module LLVM.Core.Instructions(
ret,
condBr,
br,
switch,
invoke,
unwind,
unreachable,
add, sub, mul, neg,
fadd, fsub, fmul,
udiv, sdiv, fdiv, urem, srem, frem,
shl, lshr, ashr, and, or, xor, inv,
extractelement,
insertelement,
shufflevector,
extractvalue,
insertvalue,
malloc, arrayMalloc,
alloca, arrayAlloca,
free,
load,
store,
getElementPtr, getElementPtr0,
trunc, zext, sext,
fptrunc, fpext,
fptoui, fptosi,
uitofp, sitofp,
ptrtoint, inttoptr,
bitcast, bitcastUnify,
IntPredicate(..), FPPredicate(..),
CmpRet,
icmp, fcmp,
select,
phi, addPhiInputs,
call,
Terminate,
Ret, CallArgs, ABinOp, CmpOp, FunctionArgs, FunctionRet, IsConst,
AllocArg,
GetElementPtr, IsIndexArg, GetValue
) where
import Prelude hiding (and, or)
import Data.Typeable
import Control.Monad(liftM)
import Data.Int
import Data.Word
import Foreign.C(CInt, CUInt)
import Data.TypeLevel((:<:), (:>:), (:==:), D0, toNum, Succ, Nat)
import qualified LLVM.FFI.Core as FFI
import LLVM.Core.Data
import LLVM.Core.Type
import LLVM.Core.CodeGenMonad
import LLVM.Core.CodeGen
import qualified LLVM.Core.Util as U
type Terminate = ()
terminate :: Terminate
terminate = ()
class Ret a r where
ret' :: a -> CodeGenFunction r Terminate
ret :: (Ret a r) => a -> CodeGenFunction r Terminate
ret = ret'
instance (IsFirstClass a, IsConst a) => Ret a a where
ret' = ret . valueOf
instance Ret (Value a) a where
ret' (Value a) = do
withCurrentBuilder $ \ bldPtr -> FFI.buildRet bldPtr a
return terminate
instance Ret () () where
ret' _ = do
withCurrentBuilder $ FFI.buildRetVoid
return terminate
condBr :: Value Bool
-> BasicBlock
-> BasicBlock
-> CodeGenFunction r Terminate
condBr (Value b) (BasicBlock t1) (BasicBlock t2) = do
withCurrentBuilder $ \ bldPtr -> FFI.buildCondBr bldPtr b t1 t2
return terminate
br :: BasicBlock
-> CodeGenFunction r Terminate
br (BasicBlock t) = do
withCurrentBuilder $ \ bldPtr -> FFI.buildBr bldPtr t
return terminate
switch :: (IsInteger a)
=> Value a
-> BasicBlock
-> [(ConstValue a, BasicBlock)]
-> CodeGenFunction r Terminate
switch (Value val) (BasicBlock dflt) arms = do
withCurrentBuilder $ \ bldPtr -> do
inst <- FFI.buildSwitch bldPtr val dflt (fromIntegral $ length arms)
sequence_ [ FFI.addCase inst c b | (ConstValue c, BasicBlock b) <- arms ]
return terminate
unwind :: CodeGenFunction r Terminate
unwind = do
withCurrentBuilder FFI.buildUnwind
return terminate
unreachable :: CodeGenFunction r Terminate
unreachable = do
withCurrentBuilder FFI.buildUnreachable
return terminate
type FFIBinOp = FFI.BuilderRef -> FFI.ValueRef -> FFI.ValueRef -> U.CString -> IO FFI.ValueRef
type FFIConstBinOp = FFI.ValueRef -> FFI.ValueRef -> FFI.ValueRef
class ABinOp a b c | a b -> c where
abinop :: FFIConstBinOp -> FFIBinOp -> a -> b -> CodeGenFunction r c
add :: ( IsArithmetic c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
add = abinop FFI.constAdd FFI.buildAdd
sub :: ( IsArithmetic c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
sub = abinop FFI.constSub FFI.buildSub
mul :: ( IsArithmetic c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
mul = abinop FFI.constMul FFI.buildMul
udiv :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
udiv = abinop FFI.constUDiv FFI.buildUDiv
sdiv :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
sdiv = abinop FFI.constSDiv FFI.buildSDiv
urem :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
urem = abinop FFI.constURem FFI.buildURem
srem :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
srem = abinop FFI.constSRem FFI.buildSRem
fadd :: (IsFloating c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
fadd = abinop FFI.constFAdd FFI.buildFAdd
fsub :: (IsFloating c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
fsub = abinop FFI.constFSub FFI.buildFSub
fmul :: (IsFloating c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
fmul = abinop FFI.constFMul FFI.buildFMul
fdiv :: (IsFloating c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
fdiv = abinop FFI.constFDiv FFI.buildFDiv
frem :: (IsFloating c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
frem = abinop FFI.constFRem FFI.buildFRem
shl :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
shl = abinop FFI.constShl FFI.buildShl
lshr :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
lshr = abinop FFI.constLShr FFI.buildLShr
ashr :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
ashr = abinop FFI.constAShr FFI.buildAShr
and :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
and = abinop FFI.constAnd FFI.buildAnd
or :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
or = abinop FFI.constOr FFI.buildOr
xor :: (IsInteger c, ABinOp a b (v c)) => a -> b -> CodeGenFunction r (v c)
xor = abinop FFI.constXor FFI.buildXor
instance ABinOp (Value a) (Value a) (Value a) where
abinop _ op (Value a1) (Value a2) = buildBinOp op a1 a2
instance ABinOp (ConstValue a) (Value a) (Value a) where
abinop _ op (ConstValue a1) (Value a2) = buildBinOp op a1 a2
instance ABinOp (Value a) (ConstValue a) (Value a) where
abinop _ op (Value a1) (ConstValue a2) = buildBinOp op a1 a2
instance ABinOp (ConstValue a) (ConstValue a) (ConstValue a) where
abinop cop _ (ConstValue a1) (ConstValue a2) =
return $ ConstValue $ cop a1 a2
instance (IsConst a) => ABinOp (Value a) a (Value a) where
abinop cop op a1 a2 = abinop cop op a1 (constOf a2)
instance (IsConst a) => ABinOp a (Value a) (Value a) where
abinop cop op a1 a2 = abinop cop op (constOf a1) a2
buildBinOp :: FFIBinOp -> FFI.ValueRef -> FFI.ValueRef -> CodeGenFunction r (Value a)
buildBinOp op a1 a2 =
liftM Value $
withCurrentBuilder $ \ bld ->
U.withEmptyCString $ op bld a1 a2
type FFIUnOp = FFI.BuilderRef -> FFI.ValueRef -> U.CString -> IO FFI.ValueRef
buildUnOp :: FFIUnOp -> FFI.ValueRef -> CodeGenFunction r (Value a)
buildUnOp op a =
liftM Value $
withCurrentBuilder $ \ bld ->
U.withEmptyCString $ op bld a
neg :: ( IsArithmetic a) => Value a -> CodeGenFunction r (Value a)
neg (Value x) = buildUnOp FFI.buildNeg x
inv :: (IsInteger a) => Value a -> CodeGenFunction r (Value a)
inv (Value x) = buildUnOp FFI.buildNot x
extractelement :: Value (Vector n a)
-> Value Word32
-> CodeGenFunction r (Value a)
extractelement (Value vec) (Value i) =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $ FFI.buildExtractElement bldPtr vec i
insertelement :: Value (Vector n a)
-> Value a
-> Value Word32
-> CodeGenFunction r (Value (Vector n a))
insertelement (Value vec) (Value e) (Value i) =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $ FFI.buildInsertElement bldPtr vec e i
shufflevector :: Value (Vector n a)
-> Value (Vector n a)
-> ConstValue (Vector n Word32)
-> CodeGenFunction r (Value (Vector n a))
shufflevector (Value a) (Value b) (ConstValue mask) =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $ FFI.buildShuffleVector bldPtr a b mask
class GetValue agg ix el | agg ix -> el where
getIx :: agg -> ix -> CUInt
instance (GetField as i a, Nat i) => GetValue (Struct as) i a where
getIx _ n = toNum n
instance (IsFirstClass a, Nat n) => GetValue (Array n a) Word32 a where
getIx _ n = fromIntegral n
instance (IsFirstClass a, Nat n) => GetValue (Array n a) Word64 a where
getIx _ n = fromIntegral n
extractvalue :: forall r agg i a.
GetValue agg i a
=> Value agg
-> i
-> CodeGenFunction r (Value a)
extractvalue (Value agg) i =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $
FFI.buildExtractValue bldPtr agg (getIx (undefined::agg) i)
insertvalue :: forall r agg i a.
GetValue agg i a
=> Value agg
-> Value a
-> i
-> CodeGenFunction r (Value agg)
insertvalue (Value agg) (Value e) i =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $
FFI.buildInsertValue bldPtr agg e (getIx (undefined::agg) i)
trunc :: (IsInteger a, IsInteger b, IsPrimitive a, IsPrimitive b, IsSized a sa, IsSized b sb, sa :>: sb)
=> Value a -> CodeGenFunction r (Value b)
trunc = convert FFI.buildTrunc
zext :: (IsInteger a, IsInteger b, IsPrimitive a, IsPrimitive b, IsSized a sa, IsSized b sb, sa :<: sb)
=> Value a -> CodeGenFunction r (Value b)
zext = convert FFI.buildZExt
sext :: (IsInteger a, IsInteger b, IsPrimitive a, IsPrimitive b, IsSized a sa, IsSized b sb, sa :<: sb)
=> Value a -> CodeGenFunction r (Value b)
sext = convert FFI.buildSExt
fptrunc :: (IsFloating a, IsFloating b, IsPrimitive a, IsPrimitive b, IsSized a sa, IsSized b sb, sa :>: sb)
=> Value a -> CodeGenFunction r (Value b)
fptrunc = convert FFI.buildFPTrunc
fpext :: (IsFloating a, IsFloating b, IsPrimitive a, IsPrimitive b, IsSized a sa, IsSized b sb, sa :<: sb)
=> Value a -> CodeGenFunction r (Value b)
fpext = convert FFI.buildFPExt
fptoui :: (IsFloating a, IsInteger b, NumberOfElements n a, NumberOfElements n b) => Value a -> CodeGenFunction r (Value b)
fptoui = convert FFI.buildFPToUI
fptosi :: (IsFloating a, IsInteger b, NumberOfElements n a, NumberOfElements n b) => Value a -> CodeGenFunction r (Value b)
fptosi = convert FFI.buildFPToSI
uitofp :: (IsInteger a, IsFloating b, NumberOfElements n a, NumberOfElements n b) => Value a -> CodeGenFunction r (Value b)
uitofp = convert FFI.buildUIToFP
sitofp :: (IsInteger a, IsFloating b, NumberOfElements n a, NumberOfElements n b) => Value a -> CodeGenFunction r (Value b)
sitofp = convert FFI.buildSIToFP
ptrtoint :: (IsInteger b, IsPrimitive b) => Value (Ptr a) -> CodeGenFunction r (Value b)
ptrtoint = convert FFI.buildPtrToInt
inttoptr :: (IsInteger a, IsType b) => Value a -> CodeGenFunction r (Value (Ptr b))
inttoptr = convert FFI.buildIntToPtr
bitcast :: (IsFirstClass a, IsFirstClass b, IsSized a sa, IsSized b sb, sa :==: sb)
=> Value a -> CodeGenFunction r (Value b)
bitcast = convert FFI.buildBitCast
bitcastUnify :: (IsFirstClass a, IsFirstClass b, IsSized a s, IsSized b s)
=> Value a -> CodeGenFunction r (Value b)
bitcastUnify = convert FFI.buildBitCast
type FFIConvert = FFI.BuilderRef -> FFI.ValueRef -> FFI.TypeRef -> U.CString -> IO FFI.ValueRef
convert :: forall a b r . (IsType b) => FFIConvert -> Value a -> CodeGenFunction r (Value b)
convert conv (Value a) =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $ conv bldPtr a (typeRef (undefined :: b))
data IntPredicate =
IntEQ
| IntNE
| IntUGT
| IntUGE
| IntULT
| IntULE
| IntSGT
| IntSGE
| IntSLT
| IntSLE
deriving (Eq, Ord, Enum, Show, Typeable)
fromIntPredicate :: IntPredicate -> CInt
fromIntPredicate p = fromIntegral (fromEnum p + 32)
data FPPredicate =
FPFalse
| FPOEQ
| FPOGT
| FPOGE
| FPOLT
| FPOLE
| FPONE
| FPORD
| FPUNO
| FPUEQ
| FPUGT
| FPUGE
| FPULT
| FPULE
| FPUNE
| FPT
deriving (Eq, Ord, Enum, Show, Typeable)
fromFPPredicate :: FPPredicate -> CInt
fromFPPredicate p = fromIntegral (fromEnum p)
class CmpOp a b c d | a b -> c where
cmpop :: FFIBinOp -> a -> b -> CodeGenFunction r (Value d)
instance CmpOp (Value a) (Value a) a d where
cmpop op (Value a1) (Value a2) = buildBinOp op a1 a2
instance (IsConst a) => CmpOp a (Value a) a d where
cmpop op a1 a2 = cmpop op (valueOf a1) a2
instance (IsConst a) => CmpOp (Value a) a a d where
cmpop op a1 a2 = cmpop op a1 (valueOf a2)
class CmpRet a b | a -> b
instance CmpRet Float Bool
instance CmpRet Double Bool
instance CmpRet FP128 Bool
instance CmpRet Bool Bool
instance CmpRet Word8 Bool
instance CmpRet Word16 Bool
instance CmpRet Word32 Bool
instance CmpRet Word64 Bool
instance CmpRet Int8 Bool
instance CmpRet Int16 Bool
instance CmpRet Int32 Bool
instance CmpRet Int64 Bool
instance CmpRet (Ptr a) Bool
instance CmpRet (Vector n a) (Vector n Bool)
icmp :: (IsIntegerOrPointer c, CmpOp a b c d, CmpRet c d) =>
IntPredicate -> a -> b -> CodeGenFunction r (Value d)
icmp p = cmpop (flip FFI.buildICmp (fromIntPredicate p))
fcmp :: (IsFloating c, CmpOp a b c d, CmpRet c d) =>
FPPredicate -> a -> b -> CodeGenFunction r (Value d)
fcmp p = cmpop (flip FFI.buildFCmp (fromFPPredicate p))
select :: (IsFirstClass a, CmpRet a b) => Value b -> Value a -> Value a -> CodeGenFunction r (Value a)
select (Value cnd) (Value thn) (Value els) =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $
FFI.buildSelect bldPtr cnd thn els
type Caller = FFI.BuilderRef -> [FFI.ValueRef] -> IO FFI.ValueRef
class CallArgs f g | f -> g, g -> f where
doCall :: Caller -> [FFI.ValueRef] -> f -> g
instance (CallArgs b b') => CallArgs (a -> b) (Value a -> b') where
doCall mkCall args f (Value arg) = doCall mkCall (arg : args) (f (undefined :: a))
instance CallArgs (IO a) (CodeGenFunction r (Value a)) where
doCall = doCallDef
doCallDef :: Caller -> [FFI.ValueRef] -> b -> CodeGenFunction r (Value a)
doCallDef mkCall args _ =
withCurrentBuilder $ \ bld ->
liftM Value $ mkCall bld (reverse args)
call :: (CallArgs f g) => Function f -> g
call (Value f) = doCall (U.makeCall f) [] (undefined :: f)
invoke :: (CallArgs f g)
=> BasicBlock
-> BasicBlock
-> Function f
-> g
invoke (BasicBlock norm) (BasicBlock expt) (Value f) =
doCall (U.makeInvoke norm expt f) [] (undefined :: f)
phi :: forall a r . (IsFirstClass a) => [(Value a, BasicBlock)] -> CodeGenFunction r (Value a)
phi incoming =
liftM Value $
withCurrentBuilder $ \ bldPtr -> do
inst <- U.buildEmptyPhi bldPtr (typeRef (undefined :: a))
U.addPhiIns inst [ (v, b) | (Value v, BasicBlock b) <- incoming ]
return inst
addPhiInputs :: forall a r . (IsFirstClass a)
=> Value a
-> [(Value a, BasicBlock)]
-> CodeGenFunction r ()
addPhiInputs (Value inst) incoming =
liftIO $ U.addPhiIns inst [ (v, b) | (Value v, BasicBlock b) <- incoming ]
class AllocArg a where
getAllocArg :: a -> FFI.ValueRef
instance AllocArg (Value Word32) where
getAllocArg (Value v) = v
instance AllocArg (ConstValue Word32) where
getAllocArg = unConst
instance AllocArg Word32 where
getAllocArg = unConst . constOf
malloc :: forall a r s . (IsSized a s) => CodeGenFunction r (Value (Ptr a))
malloc =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $ FFI.buildMalloc bldPtr (typeRef (undefined :: a))
arrayMalloc :: forall a n r s . (IsSized a n, AllocArg s) =>
s -> CodeGenFunction r (Value (Ptr a))
arrayMalloc s =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $
FFI.buildArrayMalloc bldPtr (typeRef (undefined :: a)) (getAllocArg s)
alloca :: forall a r s . (IsSized a s) => CodeGenFunction r (Value (Ptr a))
alloca =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $ FFI.buildAlloca bldPtr (typeRef (undefined :: a))
arrayAlloca :: forall a n r s . (IsSized a n, AllocArg s) =>
s -> CodeGenFunction r (Value (Ptr a))
arrayAlloca s =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $
FFI.buildArrayAlloca bldPtr (typeRef (undefined :: a)) (getAllocArg s)
free :: Value (Ptr a) -> CodeGenFunction r (Value ())
free (Value a) =
liftM Value $
withCurrentBuilder $ \ bldPtr -> FFI.buildFree bldPtr a
load :: Value (Ptr a)
-> CodeGenFunction r (Value a)
load (Value p) =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $ FFI.buildLoad bldPtr p
store :: Value a
-> Value (Ptr a)
-> CodeGenFunction r (Value ())
store (Value v) (Value p) =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
FFI.buildStore bldPtr v p
class GetElementPtr optr ixs nptr | optr ixs -> nptr where
getIxList :: optr -> ixs -> [FFI.ValueRef]
class IsIndexArg a where
getArg :: a -> FFI.ValueRef
instance IsIndexArg (Value Word32) where
getArg (Value v) = v
instance IsIndexArg (Value Word64) where
getArg (Value v) = v
instance IsIndexArg (Value Int32) where
getArg (Value v) = v
instance IsIndexArg (Value Int64) where
getArg (Value v) = v
instance IsIndexArg (ConstValue Word32) where
getArg = unConst
instance IsIndexArg (ConstValue Word64) where
getArg = unConst
instance IsIndexArg (ConstValue Int32) where
getArg = unConst
instance IsIndexArg (ConstValue Int64) where
getArg = unConst
instance IsIndexArg Word32 where
getArg = unConst . constOf
instance IsIndexArg Word64 where
getArg = unConst . constOf
instance IsIndexArg Int32 where
getArg = unConst . constOf
instance IsIndexArg Int64 where
getArg = unConst . constOf
unConst :: ConstValue a -> FFI.ValueRef
unConst (ConstValue v) = v
instance GetElementPtr a () a where
getIxList _ () = []
instance (GetElementPtr o i n, IsIndexArg a) => GetElementPtr (Array k o) (a, i) n where
getIxList _ (v, i) = getArg v : getIxList (undefined :: o) i
instance (GetElementPtr o i n, IsIndexArg a) => GetElementPtr (Vector k o) (a, i) n where
getIxList _ (v, i) = getArg v : getIxList (undefined :: o) i
instance (GetElementPtr o i n, GetField fs a o, Nat a) => GetElementPtr (Struct fs) (a, i) n where
getIxList _ (v, i) = unConst (constOf (toNum v :: Word32)) : getIxList (undefined :: o) i
instance (GetElementPtr o i n, GetField fs a o, Nat a) => GetElementPtr (PackedStruct fs) (a, i) n where
getIxList _ (v, i) = unConst (constOf (toNum v :: Word32)) : getIxList (undefined :: o) i
class GetField as i a | as i -> a
instance GetField (a, as) D0 a
instance (GetField as i b, Succ i i') => GetField (a, as) i' b
getElementPtr :: forall a o i n r . (GetElementPtr o i n, IsIndexArg a) =>
Value (Ptr o) -> (a, i) -> CodeGenFunction r (Value (Ptr n))
getElementPtr (Value ptr) (a, ixs) =
let ixl = getArg a : getIxList (undefined :: o) ixs in
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withArrayLen ixl $ \ idxLen idxPtr ->
U.withEmptyCString $
FFI.buildGEP bldPtr ptr idxPtr (fromIntegral idxLen)
getElementPtr0 :: (GetElementPtr o i n) =>
Value (Ptr o) -> i -> CodeGenFunction r (Value (Ptr n))
getElementPtr0 p i = getElementPtr p (0::Word32, i)