packages feed

apple-0.2.0.0: src/C.hs

{-# LANGUAGE DeriveFunctor     #-}
{-# LANGUAGE OverloadedStrings #-}

-- first IR with for loops and array accesses, inspired by C
module C ( Temp (..), FTemp (..), BTemp (..)
         , ArrAcc (..)
         , CE (..), CFE (..)
         , PE (..)
         , CS (..)
         , (=:)
         , Label, AsmData
         , LSt (..)
         , prettyCS
         , pL
         ) where

import           CF.AL
import           Data.Copointed
import           Data.Int          (Int64)
import qualified Data.IntMap       as IM
import           Data.Word         (Word64)
import           Op
import           Prettyprinter     (Doc, Pretty (..), brackets, comma, dot, hardline, indent, lbrace, parens, rbrace, tupled, (<+>))
import           Prettyprinter.Ext

type Label=Word; type AsmData = IM.IntMap [Word64]

data Temp = ITemp !Int | ATemp !Int
          | C0 | C1 | C2 | C3 | C4 | C5 | CRet deriving Eq

data BTemp = BTemp !Int | CBRet deriving Eq

data FTemp = FTemp !Int
           | F0 | F1 | F2 | F3 | F4 | F5 | FRet0 | FRet1 deriving Eq

instance Pretty BTemp where pretty (BTemp i) = "P" <> pretty i; pretty CBRet = "PRet"

instance Pretty Temp where
    pretty (ITemp i) = "T" <> pretty i
    pretty (ATemp i) = "AT" <> pretty i
    pretty C0        = "CArg0"
    pretty C1        = "CArg1"
    pretty C2        = "CArg2"
    pretty C3        = "CArg3"
    pretty C4        = "CArg4"
    pretty C5        = "CArg5"
    pretty CRet      = "CRet"

instance Pretty FTemp where
    pretty (FTemp i) = "X" <> pretty i
    pretty F0        = "FArg0"
    pretty F1        = "FArg1"
    pretty F2        = "FArg2"
    pretty F3        = "FArg3"
    pretty F4        = "FArg4"
    pretty F5        = "FArg5"
    pretty FRet0     = "FRet0"
    pretty FRet1     = "FRet1"

instance Show Temp where show=show.pretty
instance Show FTemp where show=show.pretty
instance Show BTemp where show=show.pretty

data ArrAcc = AElem Temp CE CE (Maybe AL) Int64 -- pointer, rank, elem., label for tracking liveness, elem. size (bytes)
            -- TODO: more robust way to handle rank (often statically known)
            | ARnk Temp (Maybe AL)
            | ADim Temp CE (Maybe AL) -- pointer, #, label
            | At Temp [CE] [CE] (Maybe AL) Int64 -- pointer to data, strides, indices, label, elem. size (bytes)
            | Raw Temp CE (Maybe AL) Int64 -- pointer to data, offset, label, element size
            | TupM Temp (Maybe AL)

instance Pretty ArrAcc where
    pretty (AElem t _ e _ _) = pretty t <> brackets (pretty e)
    pretty (ADim t e _)      = pretty t <> dot <> "dim" <> brackets (pretty e)
    pretty (ARnk t _)        = "rnk" <> parens (pretty t)
    pretty (At t s ix _ _)   = pretty t <> foldMap (brackets.pretty) ix <+> foldMap (parens.pretty) s
    pretty (Raw t o _ _)     = pretty t <> "@" <> pretty o
    pretty (TupM t _)        = "tup@" <> pretty t

instance Show ArrAcc where show=show.pretty

bPrec AndB=3; bPrec OrB=2; bPrec XorB=6

mPrec IPlus=Just 6;mPrec ITimes=Just 7;mPrec IMinus=Just 6;mPrec IDiv=Nothing;mPrec IRem=Nothing;mPrec IAsl=Nothing; mPrec IMax=Nothing; mPrec IMin=Nothing; mPrec IAsr=Nothing; mPrec (BI p) = Just$bPrec p
fprec FPlus=Just 6;fprec FMinus=Just 6;fprec FTimes=Just 7; fprec FDiv=Just 7; fprec FExp=Just 8; fprec FMax=Nothing; fprec FMin=Nothing

data CE = EAt ArrAcc | Bin IBin CE CE | Tmp Temp | ConstI !Int64 | CFloor CFE
        | LA !Int -- assembler data
        | DP Temp CE -- pointer, rank

instance Pretty CE where pretty=ps 0

instance PS CE where
    ps _ (Tmp t)        = pretty t
    ps _ (ConstI i)     = pretty i
    ps d (Bin op e0 e1) | Just d' <- mPrec op = parensp (d>d') (ps (d'+1) e0 <> pretty op <> ps (d'+1) e1)
                        | otherwise = parens (pretty op <+> ps 11 e0 <+> ps 11 e1)
    ps _ (EAt a)        = pretty a
    ps _ (LA n)         = "A_" <> pretty n
    ps _ (DP t _)       = "DATA" <> parens (pretty t)
    ps _ (CFloor x)     = "⌊" <> pretty x

instance Show CE where show=show.pretty

instance Num CE where
    (+) = Bin IPlus; (*) = Bin ITimes; (-) = Bin IMinus; fromInteger=ConstI . fromInteger

data CFE = FAt ArrAcc | FBin FBin CFE CFE | FUn FUn CFE | FTmp FTemp | ConstF !Double | IE CE

instance Num CFE where
    (+) = FBin FPlus; (*) = FBin FTimes; (-) = FBin FMinus; fromInteger=ConstF . fromInteger

instance Fractional CFE where
    (/) = FBin FDiv; fromRational=ConstF . fromRational

instance Pretty CFE where pretty=ps 0

data PE = IRel IRel CE CE
        | FRel FRel CFE CFE
        | Boo BBin PE PE
        | BConst Bool
        | IUn IUn CE
        | Is BTemp
        | PAt ArrAcc
        | BU BUn PE

instance Pretty PE where
    pretty (IRel rel e0 e1) = pretty e0 <+> pretty rel <+> pretty e1
    pretty (FRel rel e0 e1) = pretty e0 <+> pretty rel <+> pretty e1
    pretty (IUn p e)        = pretty p <+> pretty e
    pretty (Is t)           = "is?" <+> pretty t
    pretty (PAt a)          = "b@" <> pretty a
    pretty (BConst True)    = "true"
    pretty (BConst False)   = "false"
    pretty (Boo op e0 e1)   = pretty e0 <+> pretty op <+> pretty e1
    pretty (BU op e)        = pretty op <> pretty e

instance PS CFE where
    ps _ (FAt a)         = pretty a
    ps _ (FUn f e)       = parens (pretty f <+> pretty e)
    ps d (FBin op x0 x1) | Just d' <- fprec op = parensp (d>d') (ps (d'+1) x0 <+> pretty op <+> ps (d'+1) x1)
                         | otherwise = parens (pretty op <+> ps 11 x0 <+> ps 11 x1)
    ps _ (FTmp t)        = pretty t
    ps _ (ConstF x)      = pretty x
    ps d (IE e)          = parensp (d>10) ("itof" <+> ps 11 e)

instance Show CFE where show=show.pretty

infix 9 =:

(=:) = MT ()

data CS a = For { lann :: a, ixVar :: Temp, eLow :: CE, loopCond :: IRel, eUpper :: CE, body :: [CS a] }
          | For1 { lann :: a, ixVar :: Temp, eLow :: CE, loopCond :: IRel, eUpper :: CE, body :: [CS a] }
          | While { lann :: a, iVar :: Temp, loopCond :: IRel, eDone :: CE, body :: [CS a] }
          | MT { lann :: a, tDest :: Temp, tSrc :: CE }
          | MX { lann :: a, ftDest :: FTemp, ftSrc :: CFE }
          | MB { lann :: a, bDest :: BTemp, pSrc :: PE }
          | Wr { lann :: a, addr :: ArrAcc, wrE :: CE }
          | WrF { lann :: a, addr :: ArrAcc, wrF :: CFE }
          | WrP { lann :: a, addr :: ArrAcc , wrB :: PE }
          | Ma { lann :: a, label :: AL, temp :: Temp, rank :: CE, nElem :: CE, elemSz :: !Int64 }
          | Free Temp
          | MaΠ { lann :: a, label :: AL, temp :: Temp, aBytes :: CE }
          | RA { lann :: a, label :: !AL } -- return array no-op (takes label)
          | CpyE { lann :: a, aDest, aSrc :: ArrAcc, nElem :: CE, elemSz :: !Int64 } -- copy elems
          | CpyD { lann :: a, aDest, aSrc :: ArrAcc, nDims :: CE } -- copy dims
          | Ifn't { lann :: a, scond :: PE, branch :: [CS a] }
          | If { lann :: a, scond :: PE, iBranch, eBranch :: [CS a] }
          | Sa { lann :: a, temp :: Temp, allocBytes :: CE }
          | Pop { lann :: a, aBytes :: CE }
          | Cmov { lann :: a, scond :: PE, tdest :: Temp, src :: CE }
          | Fcmov { lann :: a, scond :: PE, fdest :: FTemp, fsrc :: CFE }
          -- TODO: Fcneg?
          | Cset { lann :: a, scond :: PE, bdest :: BTemp }
          | SZ { lann :: a, szDest :: Temp, arr :: Temp, rank :: CE, mLabel :: Maybe AL }
          | PlProd { lann :: a, nDest :: Temp, pdims :: [CE] }
          | Rnd { lann :: a, rndDest :: Temp }
          | FRnd { lann :: a, frndDest :: FTemp }
          | Def { lann :: a, fLabel :: Label, body :: [CS a] }
          | G { lann :: a, gt :: Label, retLabel :: Label }
          deriving Functor
          -- TODO: PlDims cause we have diml

instance Copointed CS where copoint=lann

instance Pretty (CS a) where
    pretty = pL (const"")

pL f (MT l t (Bin IPlus (Tmp t') e)) | t==t' = pretty t <+> "+=" <+> pretty e <> f l
pL f (MT l t e)             = pretty t <+> "=" <+> pretty e <> f l
pL f (MX l t (FBin FPlus (FTmp t') e)) | t==t' = pretty t <+> "+=" <+> pretty e <> f l
pL f (MX l t e)             = pretty t <+> "=" <+> pretty e <> f l
pL f (MB l t e)             = pretty t <+> "=" <+> pretty e <> f l
pL f (Wr l a e)             = pretty a <+> "=" <+> pretty e <> f l
pL f (WrF l a e)            = pretty a <+> "=" <+> pretty e <> f l
pL f (WrP l a e)            = pretty a <+> "=" <+> pretty e <> f l
pL _ (Free t)               = "free" <+> pretty t
pL f (Ma l _ t rnk e sz)    = pretty t <+> "=" <+> "malloc" <> parens ("rnk=" <> pretty rnk <> comma <+> pretty e <> "*" <> pretty sz) <> f l
pL f (MaΠ l _ t sz)         = pretty t <+> "=" <+> "malloc" <> parens (pretty sz) <> f l
pL f (For l t el rel eu ss) = "for" <> parens (pretty t <> comma <+> pretty t <> "≔" <> pretty el <> comma <+> pretty t <> pretty rel <> pretty eu) <+> lbrace <#> indent 4 (pCS f ss) <#> rbrace <> f l
pL f (For1 l t el rel eu ss) = "for-1" <> parens (pretty t <> comma <+> pretty t <> "≔" <> pretty el <> comma <+> pretty t <> pretty rel <> pretty eu) <+> lbrace <#> indent 4 (pCS f ss) <#> rbrace <> f l
pL f (While l t rel eb ss)  = "while" <> parens (pretty t <> pretty rel <> pretty eb) <+> lbrace <#> indent 4 (pCS f ss) <#> rbrace <> f l
pL f (Ifn't l p s)          = "ifn't" <+> parens (pretty p) <+> lbrace <#> indent 4 (pCS f s) <#> rbrace <> f l
pL f (If l p s0 s1)         = "if" <+> parens (pretty p) <+> lbrace <#> indent 4 (pCS f s0) <#> rbrace <+> "else" <+> lbrace <#> indent 4 (pCS f s1) <#> rbrace <> f l
pL _ RA{}                   = mempty
pL f (CpyE l a a' e n)      = "cpy" <+> pretty a <> comma <+> pretty a' <+> parens (pretty e<>"*"<>pretty n) <> f l
pL f (CpyD l a a' e)        = "cpydims" <+> pretty a <+> pretty a' <+> pretty e <> f l
pL f (Sa l t e)             = pretty t <+> "=" <+> "salloc" <> parens (pretty e) <> f l
pL f (Pop l e)              = "pop" <+> pretty e <> f l
pL f (Cmov l p t e)         = "if" <+> parens (pretty p) <+> lbrace <#> indent 4 (pretty t <+> "=" <+> pretty e) <#> rbrace <> f l
pL f (Fcmov l p t e)        = "if" <+> parens (pretty p) <+> lbrace <#> indent 4 (pretty t <+> "=" <+> pretty e) <#> rbrace <> f l
pL f (Cset l p t)           = pretty t <+> "=" <+> pretty p <> f l
pL f (SZ l td t _ _)        = pretty td <+> "=" <+> "SIZE" <> parens (pretty t) <> f l
pL f (PlProd l t ts)        = pretty t <+> "=" <+> "PRODUCT" <> tupled (pretty<$>ts) <> f l
pL f (Rnd l t)              = pretty t <+> "=" <+> "(rnd)" <> f l
pL f (FRnd l x)             = pretty x <+> "=" <+> "(frnd)" <> f l
pL f (Def la l cs)          = hardline <> pS l <> ":" <#> indent 4 (pCS f cs) <> f la
pL f (G la l _)             = "GOTO" <+> pS l <> f la

pS :: Label -> Doc ann
pS l = "fun_" <> pretty l

instance Show (CS a) where show=show.pretty

prettyCS :: (AsmData, [CS a]) -> Doc ann
prettyCS (ds,ss) = pCS (const"") ss

pCS :: (a -> Doc ann) -> [CS a] -> Doc ann
pCS f=prettyLines.fmap (pL f)

data LSt = LSt { clabel :: !Label, ctemps :: !Int }