packages feed

feldspar-compiler-0.5.0.1: Feldspar/Compiler/Imperative/Frontend.hs

--
-- Copyright (c) 2009-2011, ERICSSON AB
-- All rights reserved.
-- 
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are met:
-- 
--     * Redistributions of source code must retain the above copyright notice, 
--       this list of conditions and the following disclaimer.
--     * Redistributions in binary form must reproduce the above copyright
--       notice, this list of conditions and the following disclaimer in the
--       documentation and/or other materials provided with the distribution.
--     * Neither the name of the ERICSSON AB nor the names of its contributors
--       may be used to endorse or promote products derived from this software
--       without specific prior written permission.
-- 
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--

{-# LANGUAGE ViewPatterns #-}

module Feldspar.Compiler.Imperative.Frontend where

import Data.List

import Feldspar.Compiler.Imperative.Representation hiding (Type, UserType, Cast, In, Out, Variable, Block, Pointer, Comment)
import qualified Feldspar.Compiler.Imperative.Representation as AIR

import Feldspar.Core.Types hiding (Type)

-- * Frontend data types

data Mod = Mod [Ent]
  deriving (Show)

data Ent
    = StructD String [(String, Type)]
    | ProcDf String [Var] [Var] Prog
    | ProcDcl String [Var] [Var]
  deriving (Show)

data Type
    = Void
    | Boolean
    | Bit
    | Floating
    | I8 | I16 | I32 | I40 | I64
    | U8 | U16 | U32 | U40 | U64
    | Complex Type
    | UserType String
    | Array Type
    | SizedArray Int Type
    | Struct [(String, Type)]
  deriving Eq

data Expr
    = Var Type String
    | Ptr Type String
    | Tr
    | Fl
    | LitI Type Integer
    | LitF Double
    | LitC Expr Expr
    | Expr :!: Expr
    | Expr :.: String
    | Binop Type String [Expr]
    | Fun Type String [Expr]
    | Cast Type Expr
    | SizeofE Expr
    | SizeofT Type
  deriving (Show)

data Prog
    = Skip
    | BComment String
    | Comment String
    | Expr := Expr
    | Call String [Param]
    | Seq [Prog]
    | If Expr Prog Prog
    | While Prog Expr Prog
    | For String Expr Int Prog
    | Block [Def] Prog
  deriving (Show)

data Param
    = In Expr
    | Out Expr
  deriving (Show)

data Block
    = Bl [Def] Prog
  deriving (Show)

data Def
    = Init Type String Expr
    | Def Type String
  deriving (Show)

data Var
    = Variable Type String
    | Pointer Type String
  deriving (Show)

-- * Conversion between representation and frontend

class Interface t where
    type Repr t
    toInterface :: Repr t -> t
    fromInterface :: t -> Repr t

instance Interface Mod where
    type Repr Mod = AIR.Module ()
    toInterface (Module entities ()) = Mod $ map toInterface entities
    fromInterface (Mod entities) = AIR.Module (map fromInterface entities) ()

instance Interface Ent where
    type Repr Ent = AIR.Entity ()
    toInterface (AIR.StructDef name members () ()) =
        StructD name (map (\(StructMember mname mtyp ())->(mname,toInterface mtyp)) members)
    toInterface (AIR.ProcDef name inparams outparams body () ()) =
        ProcDf name (map toInterface inparams) (map toInterface outparams) (toProg body)
    toInterface (AIR.ProcDecl name inparams outparams () ()) =
        ProcDcl name (map toInterface inparams) (map toInterface outparams)
    fromInterface (StructD name members) =
        AIR.StructDef name (map (\(mname,mtyp)->(StructMember mname (fromInterface mtyp) ())) members) () ()
    fromInterface (ProcDf name inparams outparams body) =
        AIR.ProcDef name (map fromInterface inparams) (map fromInterface outparams) (toBlock body) () ()
    fromInterface (ProcDcl name inparams outparams) =
        AIR.ProcDecl name (map fromInterface inparams) (map fromInterface outparams) () ()


instance Interface Type where
    type Repr Type = AIR.Type
    toInterface VoidType = Void
    toInterface AIR.BoolType = Boolean
    toInterface BitType = Bit
    toInterface AIR.FloatType = Floating
    toInterface (NumType Signed S8) = I8
    toInterface (NumType Signed S16) = I16
    toInterface (NumType Signed S32) = I32
    toInterface (NumType Signed S40) = I40
    toInterface (NumType Signed S64) = I64
    toInterface (NumType Unsigned S8) = U8
    toInterface (NumType Unsigned S16) = U16
    toInterface (NumType Unsigned S32) = U32
    toInterface (NumType Unsigned S40) = U40
    toInterface (NumType Unsigned S64) = U64
    toInterface (AIR.ComplexType t) = Complex $ toInterface t
    toInterface (AIR.UserType s) = UserType s
    toInterface (AIR.ArrayType (LiteralLen l) t) = SizedArray l $ toInterface t
    toInterface (AIR.ArrayType _ t) = Array $ toInterface t
    toInterface (AIR.StructType fields) = Struct $ map (\(name,t) -> (name,toInterface t)) fields
    fromInterface Void = VoidType
    fromInterface Boolean = AIR.BoolType
    fromInterface Bit = BitType
    fromInterface Floating = AIR.FloatType
    fromInterface I8 = NumType Signed S8
    fromInterface I16 = NumType Signed S16
    fromInterface I32 = NumType Signed S32
    fromInterface I40 = NumType Signed S40
    fromInterface I64 = NumType Signed S64
    fromInterface U8 = NumType Unsigned S8
    fromInterface U16 = NumType Unsigned S16
    fromInterface U32 = NumType Unsigned S32
    fromInterface U40 = NumType Unsigned S40
    fromInterface U64 = NumType Unsigned S64
    fromInterface (Complex t) = AIR.ComplexType $ fromInterface t
    fromInterface (UserType s) = AIR.UserType s
    fromInterface (Array t) = AIR.ArrayType UndefinedLen $ fromInterface t
    fromInterface (SizedArray l t) = AIR.ArrayType (LiteralLen l) $ fromInterface t
    fromInterface (Struct fields) = AIR.StructType $ map (\(name,t) -> (name,fromInterface t)) fields

instance Interface Expr where
    type Repr Expr = Expression ()
    toInterface (VarExpr (AIR.Variable name t Value ()) ()) = Var (toInterface t) name
    toInterface (VarExpr (AIR.Variable name t AIR.Pointer ()) ()) = Ptr (toInterface t) name
    toInterface (ArrayElem arr idx () ()) = (toInterface arr) :!: (toInterface idx)
    toInterface (StructField str field () ()) = (toInterface str) :.: field
    toInterface (ConstExpr (BoolConst True () ()) ()) = Tr
    toInterface (ConstExpr (BoolConst False () ()) ()) = Fl
    toInterface (ConstExpr (IntConst x t () ()) ()) = LitI (toInterface t) x
    toInterface (ConstExpr (FloatConst x () ()) ()) = LitF x
    toInterface (ConstExpr (ComplexConst r i () ()) ()) = LitC (toInterface $ ConstExpr r ()) (toInterface $ ConstExpr i ())
    toInterface (FunctionCall (Function name t Prefix) ps () ()) = Fun (toInterface t) name $ map toInterface ps
    toInterface (FunctionCall (Function name t Infix) ps () ()) = Binop (toInterface t) name $ map toInterface ps
    toInterface (AIR.Cast t e () ()) = Cast (toInterface t) (toInterface e)
    toInterface (SizeOf (Left t) () ()) = SizeofT $ toInterface t
    toInterface (SizeOf (Right e) () ()) = SizeofE $ toInterface e
    fromInterface (Var t name) = VarExpr (AIR.Variable name (fromInterface t) Value ()) ()
    fromInterface (Ptr t name) = VarExpr (AIR.Variable name (fromInterface t) AIR.Pointer ()) ()
    fromInterface (Tr) = ConstExpr (BoolConst True () ()) ()
    fromInterface (Fl) = ConstExpr (BoolConst False () ()) ()
    fromInterface (LitI t x) = ConstExpr (IntConst x (fromInterface t) () ()) ()
    fromInterface (LitF x) = ConstExpr (FloatConst x () ()) ()
    fromInterface (LitC (fromInterface -> (ConstExpr r ())) (fromInterface -> (ConstExpr i ()))) =
        ConstExpr (ComplexConst r i () ()) ()
    fromInterface (LitC _ _) = error "Illegal LitC" -- TODO (?)
    fromInterface (Binop t name es) = FunctionCall (Function name (fromInterface t) Infix) (map fromInterface es) () ()
    fromInterface (Fun t name es) = FunctionCall (Function name (fromInterface t) Prefix) (map fromInterface es) () ()
    fromInterface (Cast t e) = AIR.Cast (fromInterface t) (fromInterface e) () ()
    fromInterface (SizeofE e) = SizeOf (Right $ fromInterface e) () ()
    fromInterface (SizeofT t) = SizeOf (Left $ fromInterface t) () ()
    fromInterface (arr :!: idx) = ArrayElem (fromInterface arr) (fromInterface idx) () ()
    fromInterface (str :.: field) = StructField (fromInterface str) field () ()

instance Interface Prog where
    type Repr Prog = AIR.Program ()
    toInterface (Empty () ()) = Skip
    toInterface (AIR.Comment True s () ()) = BComment s
    toInterface (AIR.Comment False s () ()) = Comment s
    toInterface (Assign lhs rhs () ()) = (toInterface lhs) := (toInterface rhs)
    toInterface (ProcedureCall s ps () ()) = Call s (map toInterface ps)
    toInterface (Sequence ps () ()) = Seq (map toInterface ps)
    toInterface (Branch e b1 b2 () ()) = If (toInterface e) (toProg b1) (toProg b2)
    toInterface (SeqLoop e pe b () ()) = While (toProg pe) (toInterface e) (toProg b)
    toInterface (ParLoop v e i b () ()) = For (varName v) (toInterface e) i (toProg b)
    toInterface (BlockProgram b ()) = Block (map toInterface $ locals b) (toInterface $ blockBody b)
    fromInterface (Skip) = Empty () ()
    fromInterface (BComment s) = AIR.Comment True s () ()
    fromInterface (Comment s) = AIR.Comment False s () ()
    fromInterface (lhs := rhs) = Assign (fromInterface lhs) (fromInterface rhs) () ()
    fromInterface (Call s ps) = ProcedureCall s (map fromInterface ps) () ()
    fromInterface (Seq ps) = Sequence (map fromInterface ps) () ()
    fromInterface (If e p1 p2) = Branch (fromInterface e) (toBlock p1) (toBlock p2) () ()
    fromInterface (While pe e p) = SeqLoop (fromInterface e) (toBlock pe) (toBlock p) () ()
    fromInterface (For s e i p) = ParLoop
        (AIR.Variable s (NumType Unsigned S32) Value ()) (fromInterface e) i (toBlock p) () ()
    fromInterface (Block ds p) = BlockProgram (AIR.Block (map fromInterface ds) (fromInterface p) ()) ()

instance Interface Param where
    type Repr Param = ActualParameter ()
    toInterface (AIR.In e ()) = In (toInterface e)
    toInterface (AIR.Out e ()) = Out (toInterface e)
    fromInterface (In e) = AIR.In (fromInterface e) ()
    fromInterface (Out e) = AIR.Out (fromInterface e) ()

instance Interface Def where
    type Repr Def = Declaration ()
    toInterface (Declaration v (Just e) ()) = Init (toInterface $ varType v) (varName v) (toInterface e)
    toInterface (Declaration v Nothing ()) = Def (toInterface $ varType v) (varName v)
    fromInterface (Init t s e) = Declaration (AIR.Variable s (fromInterface t) Value ()) (Just $ fromInterface e) ()
    fromInterface (Def t s) = Declaration (AIR.Variable s (fromInterface t) Value ()) Nothing ()

instance Interface Block where
    type Repr Block = AIR.Block ()
    toInterface (AIR.Block ds p ()) = Bl (map toInterface ds) (toInterface p)
    fromInterface (Bl ds p) = AIR.Block (map fromInterface ds) (fromInterface p) ()

instance Interface Var where
    type Repr Var = AIR.Variable ()
    toInterface (AIR.Variable name typ Value ()) = Variable (toInterface typ) name
    toInterface (AIR.Variable name typ AIR.Pointer ()) = Pointer (toInterface typ) name
    fromInterface (Variable typ name) = AIR.Variable name (fromInterface typ) Value ()
    fromInterface (Pointer typ name) = AIR.Variable name (fromInterface typ) AIR.Pointer ()

toBlock :: Prog -> AIR.Block ()
toBlock (Block ds p) = AIR.Block (map fromInterface ds) (fromInterface p) ()
toBlock p = AIR.Block [] (fromInterface p) ()

toProg :: AIR.Block () -> Prog
toProg (AIR.Block [] p ()) = toInterface p
toProg (AIR.Block ds p ()) = Block (map toInterface ds) (toInterface p)

boolToExpr :: Bool -> Expr
boolToExpr True = Tr
boolToExpr False = Fl

setLength :: Expr -> Expr -> Prog
setLength arr len = Call "setLength" [Out arr, In len]

increaseLength :: Expr -> Expr -> Prog
increaseLength arr len = Call "increaseLength" [Out arr, In len]

copyProg :: Expr -> Expr -> Prog
copyProg outExp inExp = Call "copy" [Out outExp, In inExp]

copyProgPos :: Expr -> Expr -> Expr -> Prog
copyProgPos outExp shift inExp = Call "copyArrayPos" [Out outExp, In shift, In inExp]

copyProgLen :: Expr -> Expr -> Expr -> Prog
copyProgLen outExp inExp len = Call "copyArrayLen" [Out outExp, In inExp, In len]

instance Show Type
  where
    show Void       = "void"
    show Boolean    = "bool"
    show Bit        = "bit"
    show Floating   = "float"
    show I8         = "int8"
    show I16        = "int16"
    show I32        = "int32"
    show I40        = "int40"
    show I64        = "int64"
    show U8         = "uint8"
    show U16        = "uint16"
    show U32        = "uint32"
    show U40        = "uint40"
    show U64        = "uint64"
    show (Complex t)    = "complexOf_" ++ show t
    show (UserType s)   = "userType_" ++ s
    show (Array t)      = "arrayOf_" ++ show t
    show (SizedArray i t)   = "arrayOfSize_" ++ show i ++ "_" ++ show t
    show (Struct fields)    = "struct_" ++ intercalate "_" (map (\(s,t) -> s ++ "_" ++ show t) fields)

instance HasType Expr
  where
    type TypeOf Expr = Type
    typeof = toInterface . typeof . fromInterface

intWidth :: Type -> Maybe Integer
intWidth I8  = Just 8
intWidth I16 = Just 16
intWidth I32 = Just 32
intWidth I40 = Just 40
intWidth I64 = Just 64
intWidth U8  = Just 8
intWidth U16 = Just 16
intWidth U32 = Just 32
intWidth U40 = Just 40
intWidth U64 = Just 64
intWidth _   = Nothing

intSigned :: Type -> Maybe Bool
intSigned I8  = Just True
intSigned I16 = Just True
intSigned I32 = Just True
intSigned I40 = Just True
intSigned I64 = Just True
intSigned U8  = Just False
intSigned U16 = Just False
intSigned U32 = Just False
intSigned U40 = Just False
intSigned U64 = Just False
intSigned _   = Nothing

litB :: Bool -> Expr
litB True = Tr
litB False = Fl

isArray :: Type -> Bool
isArray (Array _) = True
isArray (SizedArray _ _) = True
isArray _ = False