feldspar-compiler-0.2: Feldspar/Compiler/Plugins/HandlePrimitives.hs
{-# LANGUAGE TypeFamilies #-}
module Feldspar.Compiler.Plugins.HandlePrimitives
( HandlePrimitives(..)
, makeAssignment
, makePrimitive,
) where
import Feldspar.Compiler.Imperative.Representation
import Feldspar.Compiler.Imperative.Semantics (SemanticInfo)
import Feldspar.Compiler.Imperative.CodeGeneration (simpleType, typeof, listprint, compToC, toLeftValue)
import Feldspar.Compiler.PluginArchitecture (TransformationPhase(..), Plugin(..), InfosFromPrimitiveParts(..))
import Feldspar.Compiler.Options
import Feldspar.Compiler.Error
handlePrimitivesError = handleError "PluginArch/HandlePrimitives" InternalError
data HandlePrimitives = HandlePrimitives
instance TransformationPhase HandlePrimitives where
type From HandlePrimitives = ()
type To HandlePrimitives = ()
type Downwards HandlePrimitives = Int
type Upwards HandlePrimitives = ()
transformPrimitive = transformPrimitive'
instance Plugin HandlePrimitives where
type ExternalInfo HandlePrimitives = (Int,DebugOption)
executePlugin _ (_,NoPrimitiveInstructionHandling) procedure = procedure
executePlugin _ (defArrSize,_) procedure = fst $ executeTransformationPhase HandlePrimitives defArrSize procedure
transformPrimitive' :: HandlePrimitives -> Int -> Primitive () -> InfosFromPrimitiveParts HandlePrimitives -> ProgramConstruction ()
transformPrimitive' _ defArrSize old modified'
= case (nameS,as) of
("(==)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "equal" "=="
("(/=)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "not_equal" "!="
("(<)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "less" "<"
("(>)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "greater" ">"
("(<=)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "less_equal" "<="
("(>=)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "greater_equal" ">="
("not", [InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive PrefixOp 1 as "not" "!"
("(&&)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "and" "&&"
("(||)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "or" "||"
("div", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "divide" "/"
("rem", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "remainder" "%"
("mod", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 2 as "mod" ""
("(^)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 2 as "pow" ""
("(.&.)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "bit_and" "&"
("(.|.)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "bit_or" "|"
("xor", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "bit_xor" "^"
("complement", [InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive PrefixOp 1 as "bit_not" "~"
("bit", [InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 1 as "bit" ""
("setBit", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 2 as "setBit" ""
("clearBit", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 2 as "clearBit" ""
("complementBit", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 2 as "complementBit" ""
("testBit", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 2 as "testBit" ""
("shiftL", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "shiftL" "<<"
("shiftR", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "shiftR" ">>"
("rotateL", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 2 as "rotateL" ""
("rotateR", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 2 as "rotateR" ""
-- ("shift", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 2 as "bit_shift" ""
-- ("rotate", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 2 as "bit_rotate" ""
("bitSize", [InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 1 as "bitSize" ""
("isSigned", [InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 1 as "isSigned" ""
("abs", [InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 1 as "abs" ""
("signum", [InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive SimpleFun 1 as "signum" ""
("(+)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "add" "+"
("(-)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "sub" "-"
("(*)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "mult" "*"
("(/)", [InputActualParameter _, InputActualParameter _, OutputActualParameter _]) -> mkPrg $ makePrimitive InfixOp 2 as "divide" "/"
("(!)", [arr@(InputActualParameter _), idx@(InputActualParameter _), out@(OutputActualParameter _)])
-> mkPrg $ makeAssignment
(LeftValueExpression $ LeftValueInExpression
(ArrayElemReferenceLeftValue $ ArrayElemReference
(ArrayElemReferenceData (toLeftValue $ aToE arr) $ aToE idx) ()
) ()
) (aToL out) defArrSize
("setIx", [original@(InputActualParameter _), idx@(InputActualParameter _), val@(InputActualParameter _), result@(OutputActualParameter _)])
-> SequenceProgram $ Sequence
[ Program (PrimitiveProgram $ Primitive (makeAssignment (aToE original) (aToL result) defArrSize) ()) ()
, Program (PrimitiveProgram $ Primitive
(makeAssignment
(aToE val)
(ArrayElemReferenceLeftValue $ ArrayElemReference (ArrayElemReferenceData (aToL result) $ aToE idx) ())
defArrSize
) ()) ()
] ()
("copy", [in1@(InputActualParameter _), out@(OutputActualParameter _)])
-> mkPrg $ makeAssignment (aToE in1) (aToL out) defArrSize
_ -> mkPrg $ modified
where
nameS = nameOfProcedureToCall $ procedureCallData $ (\(ProcedureCallInstruction x) -> x) $ primitiveInstruction old
as = actualParametersOfProcedureToCall $ procedureCallData $ (\(ProcedureCallInstruction x) -> x) modified
modified = recursivelyTransformedPrimitiveInstruction modified'
mkPrg x = PrimitiveProgram (Primitive x ())
makeAssignment :: Expression () -> LeftValue () -> Int -> Instruction ()
makeAssignment in1 out defaultArraySize
| simpleType (typeof in1) = AssignmentInstruction $ Assignment (AssignmentData out in1) ()
| otherwise = case (typeof in1) of
(ImpArrayType _ t) -> makePrimitive SimpleFun 2 [eToA in1, eToA $ arraySize (typeof in1) defaultArraySize, lToA out] "copy" ""
_ -> handlePrimitivesError $ "Unknown type in makeAssignment:\n" ++ show (typeof in1)
makePrimitive :: FunctionRole -> Int -> [ActualParameter ()] -> String -> String -> Instruction ()
makePrimitive primType parNum as cFunName cOpName
| simpleType (typeof out) = AssignmentInstruction $ Assignment (AssignmentData out (FunctionCallExpression funCall)) ()
| otherwise = ProcedureCallInstruction procCall
where
funCall = case (primType, parNum) of
(SimpleFun, 1) -> FunctionCall (FunctionCallData SimpleFun (typeof out) completeFunName [in1]) ()
(SimpleFun, 2) -> FunctionCall (FunctionCallData SimpleFun (typeof out) completeFunName [in1, in2]) ()
(PrefixOp, 1) -> FunctionCall (FunctionCallData PrefixOp (typeof out) cOpName [in1]) ()
(InfixOp, 2) -> FunctionCall (FunctionCallData InfixOp (typeof out) cOpName [in1, in2]) ()
_ -> handlePrimitivesError $ "Invalid arguments:\n" ++ show (primType, parNum)
procCall = case (primType, parNum) of
(SimpleFun, 1) -> ProcedureCall (ProcedureCallData completeProcName [in1', out']) ()
(SimpleFun, 2) -> ProcedureCall (ProcedureCallData completeProcName [in1', in2', out']) ()
(PrefixOp, 1) -> ProcedureCall (ProcedureCallData completeProcName [in1', out']) ()
(InfixOp, 2) -> ProcedureCall (ProcedureCallData completeProcName [in1', in2', out']) ()
_ -> handlePrimitivesError $ "Invalid arguments:\n" ++ show (primType, parNum)
completeFunName = cFunName ++ "_fun_" ++ toFunName (typeof in1)
completeProcName = cFunName ++ "_" ++ toFunName (typeof in1)
(in1,in1') = case (filter isInparam as) of
x:_ -> (aToE x,x)
_ -> handlePrimitivesError $ "There is not any Input parameter:\n" ++ show as
(in2,in2') = case (filter isInparam as) of
_:x:_ -> (aToE x,x)
_ -> handlePrimitivesError $ "There is not enough Input parameter:\n" ++ show as
(out,out') = case (filter (not . isInparam) as) of
x:_ -> (aToL x,x)
_ -> handlePrimitivesError $ "There is not any Output parameter:\n" ++ show as
toFunName :: Type -> String
toFunName BoolType = "bool"
toFunName FloatType = "float"
toFunName (Numeric sig siz) = listprint id "_" [compToC sig, compToC siz]
toFunName (ImpArrayType _ t@(ImpArrayType _ _)) = toFunName t
toFunName (ImpArrayType _ t) = "arrayOf_" ++ toFunName t
arraySize :: Type -> Int -> Expression ()
arraySize a@(ImpArrayType _ t) defaultArraySize
= ConstantExpression $ IntConstant $ IntConstantType (arraySize' a) ()
where
arraySize' (ImpArrayType (Norm n) t) = n * arraySize' t
arraySize' (ImpArrayType (Defined n) t) = n * arraySize' t
arraySize' (ImpArrayType Undefined t) = defaultArraySize * arraySize' t
arraySize' _ = 1
isInparam (InputActualParameter _) = True
isInparam (OutputActualParameter _) = False
aToE (InputActualParameter x) = inputActualParameterExpression x
aToL (OutputActualParameter x) = outputActualParameterLeftValue x
-- TODO create a simple wrapper interface based on these functions
eToA x = InputActualParameter $ InputActualParameterType x ()
lToA x = OutputActualParameter $ OutputActualParameterType x ()