ddc-core-llvm-0.4.2.1: DDC/Core/Llvm/Convert/Exp/PrimArith.hs
module DDC.Core.Llvm.Convert.Exp.PrimArith
(convPrimArith)
where
import DDC.Llvm.Syntax
import DDC.Core.Llvm.Convert.Exp.Atom
import DDC.Core.Llvm.Convert.Context
import DDC.Core.Llvm.Convert.Type
import DDC.Core.Llvm.Convert.Base
import Data.Sequence (Seq)
import qualified DDC.Core.Exp as C
import qualified DDC.Core.Salt as A
import qualified Data.Sequence as Seq
-- | Convert a primitive call to LLVM,
-- or Nothing if this doesn't look like such an operation.
convPrimArith
:: Context -- ^ Context of the conversion.
-> Maybe Var -- ^ Assign result to this var.
-> A.PrimOp -- ^ Primitive to call.
-> [A.Arg] -- ^ Arguments to primitive.
-> Maybe (ConvertM (Seq AnnotInstr))
convPrimArith ctx mdst p xs
= let pp = contextPlatform ctx
kenv = contextKindEnv ctx
in case p of
-- Unary operators ------------
A.PrimArith op
| A.RType t : args <- xs
, Just dst <- mdst
, Just [mx1] <- sequence $ map (mconvArg ctx) args
-> Just $ do
x1' <- mx1
t' <- convertType pp kenv t
let result
| A.PrimArithNeg <- op
, isIntegralT t
= return $ IOp dst OpSub (XLit $ LitInt t' 0) x1'
| A.PrimArithNeg <- op
, isFloatingT t
= return $ IOp dst OpSub (XLit $ LitFloat t' 0) x1'
-- Cannot use primop at this type.
| otherwise
= throw $ ErrorInvalidArith op t
instr <- result
return $ Seq.singleton (annotNil instr)
-- Binary operators -----------
A.PrimArith op
| A.RType t : args <- xs
, Just dst <- mdst
, Just [mx1, mx2] <- sequence $ map (mconvArg ctx) args
-> Just $ do
x1' <- mx1
x2' <- mx2
let result
| Just op' <- convPrimArith2 op t
= return $ IOp dst op' x1' x2'
| Just icond' <- convPrimICond op t
= return $ ICmp dst (ICond icond') x1' x2'
| Just fcond' <- convPrimFCond op t
= return $ ICmp dst (FCond fcond') x1' x2'
-- Cannot use primop at this type.
| otherwise
= throw $ ErrorInvalidArith op t
instr <- result
return $ Seq.singleton (annotNil instr)
-- This doesn't look like an arithmetic primop.
_ -> Nothing
-- | Convert a binary primop from Core Sea to LLVM form.
convPrimArith2 :: A.PrimArith -> C.Type A.Name -> Maybe Op
convPrimArith2 op t
= case op of
A.PrimArithAdd
| isIntegralT t -> Just OpAdd
| isFloatingT t -> Just OpFAdd
A.PrimArithSub
| isIntegralT t -> Just OpSub
| isFloatingT t -> Just OpFSub
A.PrimArithMul
| isIntegralT t -> Just OpMul
| isFloatingT t -> Just OpFMul
A.PrimArithDiv
| isIntegralT t, isUnsignedT t -> Just OpUDiv
| isIntegralT t, isSignedT t -> Just OpSDiv
| isFloatingT t -> Just OpFDiv
A.PrimArithRem
| isIntegralT t, isUnsignedT t -> Just OpURem
| isIntegralT t, isSignedT t -> Just OpSRem
| isFloatingT t -> Just OpFRem
A.PrimArithShl
| isIntegralT t -> Just OpShl
A.PrimArithShr
| isIntegralT t, isUnsignedT t -> Just OpLShr
| isIntegralT t, isSignedT t -> Just OpAShr
A.PrimArithBAnd
| isIntegralT t -> Just OpAnd
A.PrimArithBOr
| isIntegralT t -> Just OpOr
A.PrimArithBXOr
| isIntegralT t -> Just OpXor
_ -> Nothing
-- | Convert an integer comparison from Core Sea to LLVM form.
convPrimICond :: A.PrimArith -> C.Type A.Name -> Maybe ICond
convPrimICond op t
| isIntegralT t
= case op of
A.PrimArithEq -> Just ICondEq
A.PrimArithNeq -> Just ICondNe
A.PrimArithGt -> Just ICondUgt
A.PrimArithGe -> Just ICondUge
A.PrimArithLt -> Just ICondUlt
A.PrimArithLe -> Just ICondUle
_ -> Nothing
| otherwise = Nothing
-- | Convert a floating point comparison from Core Sea to LLVM form.
convPrimFCond :: A.PrimArith -> C.Type A.Name -> Maybe FCond
convPrimFCond op t
| isIntegralT t
= case op of
A.PrimArithEq -> Just FCondOeq
A.PrimArithNeq -> Just FCondOne
A.PrimArithGt -> Just FCondOgt
A.PrimArithGe -> Just FCondOge
A.PrimArithLt -> Just FCondOlt
A.PrimArithLe -> Just FCondOle
_ -> Nothing
| otherwise = Nothing