module LLVM.Core.Instructions(
BinOpDesc(..), InstrDesc(..), ArgDesc(..), getInstrDesc,
ret,
condBr,
br,
switch,
invoke, invokeWithConv,
invokeFromFunction, invokeWithConvFromFunction,
unreachable,
add, sub, mul, neg,
iadd, isub, imul, ineg,
fadd, fsub, fmul, fneg,
idiv, irem,
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, ext, zadapt, sadapt, adapt,
fptrunc, fpext,
fptoui, fptosi, fptoint,
uitofp, sitofp, inttofp,
ptrtoint, inttoptr,
bitcast,
bitcastElements,
CmpPredicate(..), IntPredicate(..), FPPredicate(..),
CmpOp, CmpRet, CmpResult, CmpValueResult,
cmp, pcmp, icmp, fcmp,
select,
phi, addPhiInputs,
call, callWithConv,
callFromFunction, callWithConvFromFunction,
Call, applyCall, runCall,
Terminate,
Ret, CallArgs, AUnOp, ABinOp, ABinOpResult, IsConst,
FunctionArgs, FunctionCodeGen, FunctionResult,
AllocArg,
GetElementPtr, ElementPtrType, IsIndexArg,
GetValue, ValueType,
GetField, FieldType,
) where
import qualified LLVM.Core.Util as U
import qualified LLVM.Util.Proxy as LP
import LLVM.Core.Data
import LLVM.Core.Type
import LLVM.Core.CodeGenMonad
import LLVM.Core.CodeGen
import qualified LLVM.FFI.Core as FFI
import qualified Type.Data.Num.Decimal.Number as Dec
import Type.Data.Num.Decimal.Literal (d1)
import Type.Data.Num.Decimal.Number (Pred, (:<:), (:>:))
import Type.Base.Proxy (Proxy)
import Foreign.Ptr (Ptr, FunPtr, )
import Foreign.C (CInt, CUInt)
import Control.Monad.IO.Class (liftIO)
import Control.Monad (liftM)
import Data.Typeable (Typeable)
import Data.Int (Int8, Int16, Int32, Int64)
import Data.Word (Word8, Word16, Word32, Word64)
import Data.Map (fromList, (!))
import Prelude hiding (and, or)
data ArgDesc = AV String | AI Int | AL String | AE
instance Show ArgDesc where
show (AV s) = s
show (AI i) = show i
show (AL l) = l
show AE = "voidarg?"
data BinOpDesc = BOAdd | BOAddNuw | BOAddNsw | BOAddNuwNsw | BOFAdd
| BOSub | BOSubNuw | BOSubNsw | BOSubNuwNsw | BOFSub
| BOMul | BOMulNuw | BOMulNsw | BOMulNuwNsw | BOFMul
| BOUDiv | BOSDiv | BOSDivExact | BOFDiv | BOURem | BOSRem | BOFRem
| BOShL | BOLShR | BOAShR | BOAnd | BOOr | BOXor
deriving Show
data InstrDesc =
IDRet TypeDesc ArgDesc | IDRetVoid
| IDBrCond ArgDesc ArgDesc ArgDesc | IDBrUncond ArgDesc
| IDSwitch [(ArgDesc, ArgDesc)]
| IDIndirectBr
| IDInvoke
| IDUnwind
| IDUnreachable
| IDBinOp BinOpDesc TypeDesc ArgDesc ArgDesc
| IDAlloca TypeDesc Int Int | IDLoad TypeDesc ArgDesc | IDStore TypeDesc ArgDesc ArgDesc
| IDGetElementPtr TypeDesc [ArgDesc]
| IDTrunc TypeDesc TypeDesc ArgDesc | IDZExt TypeDesc TypeDesc ArgDesc
| IDSExt TypeDesc TypeDesc ArgDesc | IDFPtoUI TypeDesc TypeDesc ArgDesc
| IDFPtoSI TypeDesc TypeDesc ArgDesc | IDUItoFP TypeDesc TypeDesc ArgDesc
| IDSItoFP TypeDesc TypeDesc ArgDesc
| IDFPTrunc TypeDesc TypeDesc ArgDesc | IDFPExt TypeDesc TypeDesc ArgDesc
| IDPtrToInt TypeDesc TypeDesc ArgDesc | IDIntToPtr TypeDesc TypeDesc ArgDesc
| IDBitcast TypeDesc TypeDesc ArgDesc
| IDICmp IntPredicate ArgDesc ArgDesc | IDFCmp FPPredicate ArgDesc ArgDesc
| IDPhi TypeDesc [(ArgDesc, ArgDesc)] | IDCall TypeDesc ArgDesc [ArgDesc]
| IDSelect TypeDesc ArgDesc ArgDesc | IDUserOp1 | IDUserOp2 | IDVAArg
| IDExtractElement | IDInsertElement | IDShuffleVector
| IDExtractValue | IDInsertValue
| IDInvalidOp
deriving Show
getInstrDesc :: FFI.ValueRef -> IO (String, InstrDesc)
getInstrDesc v = do
valueName <- U.getValueNameU v
opcode <- FFI.instGetOpcode v
t <- FFI.typeOf v >>= typeDesc2
tsize <- return 1
os <- U.getOperands v >>= mapM getArgDesc
os0 <- if length os > 0 then return $ os !! 0 else return AE
os1 <- if length os > 1 then return $ os !! 1 else return AE
t2 <- (if not (null os) && (opcode >= 30 || opcode <= 41)
then U.getOperands v >>= return . snd . head >>= FFI.typeOf >>= typeDesc2
else return TDVoid)
p <- if opcode `elem` [42, 43] then FFI.cmpInstGetPredicate v else return 0
let instr =
(if opcode >= 8 && opcode <= 25
then IDBinOp (getBinOp opcode) t os0 os1
else if opcode >= 30 && opcode <= 41
then (getConvOp opcode) t2 t os0
else case opcode of
{ 1 -> if null os then IDRetVoid else IDRet t os0;
2 -> if length os == 1 then IDBrUncond os0 else IDBrCond os0 (os !! 2) os1;
3 -> IDSwitch $ toPairs os;
6 -> IDUnwind; 7 -> IDUnreachable;
26 -> IDAlloca (getPtrType t) tsize (getImmInt os0);
27 -> IDLoad t os0; 28 -> IDStore t os0 os1;
29 -> IDGetElementPtr t os;
42 -> IDICmp (toIntPredicate p) os0 os1;
43 -> IDFCmp (toFPPredicate p) os0 os1;
44 -> IDPhi t $ toPairs os;
45 -> IDCall t (last os) (init os);
46 -> IDSelect t os0 os1;
_ -> IDInvalidOp })
return (valueName, instr)
where getBinOp o = fromList [(8, BOAdd), (9, BOFAdd), (10, BOSub), (11, BOFSub),
(12, BOMul), (13, BOFMul), (14, BOUDiv), (15, BOSDiv),
(16, BOFDiv), (17, BOURem), (18, BOSRem), (19, BOFRem),
(20, BOShL), (21, BOLShR), (22, BOAShR), (23, BOAnd),
(24, BOOr), (25, BOXor)] ! o
getConvOp o = fromList [(30, IDTrunc), (31, IDZExt), (32, IDSExt), (33, IDFPtoUI),
(34, IDFPtoSI), (35, IDUItoFP), (36, IDSItoFP), (37, IDFPTrunc),
(38, IDFPExt), (39, IDPtrToInt), (40, IDIntToPtr), (41, IDBitcast)] ! o
toPairs xs = zip (stride 2 xs) (stride 2 (drop 1 xs))
stride _ [] = []
stride n (x:xs) = x : stride n (drop (n1) xs)
getPtrType (TDPtr t) = t
getPtrType _ = TDVoid
getImmInt (AI i) = i
getImmInt _ = 0
getArgDesc :: (String, FFI.ValueRef) -> IO ArgDesc
getArgDesc (vname, v) = do
isC <- U.isConstant v
t <- FFI.typeOf v >>= typeDesc2
if isC
then case t of
TDInt _ _ -> do
cV <- FFI.constIntGetSExtValue v
return $ AI $ fromIntegral cV
_ -> return AE
else case t of
TDLabel -> return $ AL vname
_ -> return $ AV vname
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 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
withCurrentBuilder_ :: (FFI.BuilderRef -> IO a) -> CodeGenFunction r ()
withCurrentBuilder_ p = withCurrentBuilder p >> return ()
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
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 -> IO FFI.ValueRef
withArithmeticType ::
(IsArithmetic c) =>
(ArithmeticType c -> a -> CodeGenFunction r (v c)) ->
(a -> CodeGenFunction r (v c))
withArithmeticType f = f arithmeticType
class ABinOp a b where
type ABinOpResult a b :: *
abinop :: FFIConstBinOp -> FFIBinOp -> a -> b -> CodeGenFunction r (ABinOpResult a b)
class AUnOp a where
aunop :: FFIConstUnOp -> FFIUnOp -> a -> CodeGenFunction r a
add :: (IsArithmetic c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
add =
curry $ withArithmeticType $ \typ -> uncurry $ case typ of
IntegerType -> abinop FFI.constAdd FFI.buildAdd
FloatingType -> abinop FFI.constFAdd FFI.buildFAdd
sub :: (IsArithmetic c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
sub =
curry $ withArithmeticType $ \typ -> uncurry $ case typ of
IntegerType -> abinop FFI.constSub FFI.buildSub
FloatingType -> abinop FFI.constFSub FFI.buildFSub
mul :: (IsArithmetic c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
mul =
curry $ withArithmeticType $ \typ -> uncurry $ case typ of
IntegerType -> abinop FFI.constMul FFI.buildMul
FloatingType -> abinop FFI.constFMul FFI.buildFMul
iadd :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
iadd = abinop FFI.constAdd FFI.buildAdd
isub :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
isub = abinop FFI.constSub FFI.buildSub
imul :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
imul = abinop FFI.constMul FFI.buildMul
idiv ::
forall a b c r v. (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) =>
a -> b -> CodeGenFunction r (v c)
idiv =
if isSigned (LP.Proxy :: LP.Proxy c)
then abinop FFI.constSDiv FFI.buildSDiv
else abinop FFI.constUDiv FFI.buildUDiv
irem ::
forall a b c r v. (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) =>
a -> b -> CodeGenFunction r (v c)
irem =
if isSigned (LP.Proxy :: LP.Proxy c)
then abinop FFI.constSRem FFI.buildSRem
else abinop FFI.constURem FFI.buildURem
udiv :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
udiv = abinop FFI.constUDiv FFI.buildUDiv
sdiv :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
sdiv = abinop FFI.constSDiv FFI.buildSDiv
urem :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
urem = abinop FFI.constURem FFI.buildURem
srem :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
srem = abinop FFI.constSRem FFI.buildSRem
fadd :: (IsFloating c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
fadd = abinop FFI.constFAdd FFI.buildFAdd
fsub :: (IsFloating c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
fsub = abinop FFI.constFSub FFI.buildFSub
fmul :: (IsFloating c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
fmul = abinop FFI.constFMul FFI.buildFMul
fdiv :: (IsFloating c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
fdiv = abinop FFI.constFDiv FFI.buildFDiv
frem :: (IsFloating c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
frem = abinop FFI.constFRem FFI.buildFRem
shl :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
shl = abinop FFI.constShl FFI.buildShl
lshr :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
lshr = abinop FFI.constLShr FFI.buildLShr
ashr :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
ashr = abinop FFI.constAShr FFI.buildAShr
and :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
and = abinop FFI.constAnd FFI.buildAnd
or :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
or = abinop FFI.constOr FFI.buildOr
xor :: (IsInteger c, ABinOp a b, v c ~ ABinOpResult a b) => a -> b -> CodeGenFunction r (v c)
xor = abinop FFI.constXor FFI.buildXor
instance ABinOp (Value a) (Value a) where
type ABinOpResult (Value a) (Value a) = Value a
abinop _ op (Value a1) (Value a2) = buildBinOp op a1 a2
instance ABinOp (ConstValue a) (Value a) where
type ABinOpResult (ConstValue a) (Value a) = Value a
abinop _ op (ConstValue a1) (Value a2) = buildBinOp op a1 a2
instance ABinOp (Value a) (ConstValue a) where
type ABinOpResult (Value a) (ConstValue a) = Value a
abinop _ op (Value a1) (ConstValue a2) = buildBinOp op a1 a2
instance ABinOp (ConstValue a) (ConstValue a) where
type ABinOpResult (ConstValue a) (ConstValue a) = ConstValue a
abinop cop _ (ConstValue a1) (ConstValue a2) =
liftIO $ fmap ConstValue $ cop a1 a2
instance AUnOp (Value a) where
aunop _ op (Value a) = buildUnOp op a
instance AUnOp (ConstValue a) where
aunop cop _ (ConstValue a) = liftIO $ fmap ConstValue $ cop a
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
type FFIConstUnOp = FFI.ValueRef -> 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 b, AUnOp a, a ~ v b) =>
a -> CodeGenFunction r a
neg =
withArithmeticType $ \typ -> case typ of
IntegerType -> aunop FFI.constNeg FFI.buildNeg
FloatingType -> aunop FFI.constFNeg FFI.buildFNeg
ineg ::
(IsInteger b, AUnOp a, a ~ v b) =>
a -> CodeGenFunction r a
ineg = aunop FFI.constNeg FFI.buildNeg
fneg ::
(IsFloating b, AUnOp a, a ~ v b) =>
a -> CodeGenFunction r a
fneg = aunop FFI.constFNeg FFI.buildFNeg
inv :: (IsInteger b, AUnOp a, a ~ v b) => a -> CodeGenFunction r a
inv = aunop FFI.constNot FFI.buildNot
extractelement :: (Dec.Positive n)
=> 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 :: (Dec.Positive n)
=> 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 :: (Dec.Positive n, Dec.Positive m)
=> Value (Vector n a)
-> Value (Vector n a)
-> ConstValue (Vector m Word32)
-> CodeGenFunction r (Value (Vector m a))
shufflevector (Value a) (Value b) (ConstValue mask) =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $ FFI.buildShuffleVector bldPtr a b mask
class GetValue agg ix where
type ValueType agg ix :: *
getIx :: LP.Proxy agg -> ix -> CUInt
instance (GetField as i, Dec.Natural i) => GetValue (Struct as) (Proxy i) where
type ValueType (Struct as) (Proxy i) = FieldType as i
getIx _ n = Dec.integralFromProxy n
instance (IsFirstClass a, Dec.Natural n) => GetValue (Array n a) Word32 where
type ValueType (Array n a) Word32 = a
getIx _ n = fromIntegral n
instance (IsFirstClass a, Dec.Natural n) => GetValue (Array n a) Word64 where
type ValueType (Array n a) Word64 = a
getIx _ n = fromIntegral n
instance (IsFirstClass a, Dec.Natural n, Dec.Natural i, i :<: n) => GetValue (Array n a) (Proxy i) where
type ValueType (Array n a) (Proxy i) = a
getIx _ n = Dec.integralFromProxy n
extractvalue :: forall r agg i.
GetValue agg i
=> Value agg
-> i
-> CodeGenFunction r (Value (ValueType agg i))
extractvalue (Value agg) i =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $
FFI.buildExtractValue bldPtr agg (getIx (LP.Proxy :: LP.Proxy agg) i)
insertvalue :: forall r agg i.
GetValue agg i
=> Value agg
-> Value (ValueType agg i)
-> i
-> CodeGenFunction r (Value agg)
insertvalue (Value agg) (Value e) i =
liftM Value $
withCurrentBuilder $ \ bldPtr ->
U.withEmptyCString $
FFI.buildInsertValue bldPtr agg e (getIx (LP.Proxy :: LP.Proxy agg) i)
trunc :: (IsInteger a, IsInteger b, NumberOfElements a ~ NumberOfElements b, IsSized a, IsSized b, SizeOf a :>: SizeOf b)
=> Value a -> CodeGenFunction r (Value b)
trunc = convert FFI.buildTrunc
zext :: (IsInteger a, IsInteger b, NumberOfElements a ~ NumberOfElements b, IsSized a, IsSized b, SizeOf a :<: SizeOf b)
=> Value a -> CodeGenFunction r (Value b)
zext = convert FFI.buildZExt
sext :: (IsInteger a, IsInteger b, NumberOfElements a ~ NumberOfElements b, IsSized a, IsSized b, SizeOf a :<: SizeOf b)
=> Value a -> CodeGenFunction r (Value b)
sext = convert FFI.buildSExt
ext :: forall a b r. (IsInteger a, IsInteger b, NumberOfElements a ~ NumberOfElements b, Signed a ~ Signed b, IsSized a, IsSized b, SizeOf a :<: SizeOf b)
=> Value a -> CodeGenFunction r (Value b)
ext =
if isSigned (LP.Proxy :: LP.Proxy b)
then convert FFI.buildSExt
else convert FFI.buildZExt
zadapt :: forall a b r. (IsInteger a, IsInteger b, NumberOfElements a ~ NumberOfElements b)
=> Value a -> CodeGenFunction r (Value b)
zadapt =
case compare (sizeOf (typeDesc (LP.Proxy :: LP.Proxy a)))
(sizeOf (typeDesc (LP.Proxy :: LP.Proxy b))) of
LT -> convert FFI.buildZExt
EQ -> convert FFI.buildBitCast
GT -> convert FFI.buildTrunc
sadapt :: forall a b r. (IsInteger a, IsInteger b, NumberOfElements a ~ NumberOfElements b)
=> Value a -> CodeGenFunction r (Value b)
sadapt =
case compare (sizeOf (typeDesc (LP.Proxy :: LP.Proxy a)))
(sizeOf (typeDesc (LP.Proxy :: LP.Proxy b))) of
LT -> convert FFI.buildSExt
EQ -> convert FFI.buildBitCast
GT -> convert FFI.buildTrunc
adapt :: forall a b r. (IsInteger a, IsInteger b, NumberOfElements a ~ NumberOfElements b, Signed a ~ Signed b)
=> Value a -> CodeGenFunction r (Value b)
adapt =
case compare (sizeOf (typeDesc (LP.Proxy :: LP.Proxy a)))
(sizeOf (typeDesc (LP.Proxy :: LP.Proxy b))) of
LT ->
if isSigned (LP.Proxy :: LP.Proxy b)
then convert FFI.buildSExt
else convert FFI.buildZExt
EQ -> convert FFI.buildBitCast
GT -> convert FFI.buildTrunc
fptrunc :: (IsFloating a, IsFloating b, NumberOfElements a ~ NumberOfElements b, IsSized a, IsSized b, SizeOf a :>: SizeOf b)
=> Value a -> CodeGenFunction r (Value b)
fptrunc = convert FFI.buildFPTrunc
fpext :: (IsFloating a, IsFloating b, NumberOfElements a ~ NumberOfElements b, IsSized a, IsSized b, SizeOf a :<: SizeOf b)
=> Value a -> CodeGenFunction r (Value b)
fpext = convert FFI.buildFPExt
fptoui :: (IsFloating a, IsInteger b, NumberOfElements a ~ NumberOfElements b) => Value a -> CodeGenFunction r (Value b)
fptoui = convert FFI.buildFPToUI
fptosi :: (IsFloating a, IsInteger b, NumberOfElements a ~ NumberOfElements b) => Value a -> CodeGenFunction r (Value b)
fptosi = convert FFI.buildFPToSI
fptoint :: forall r a b. (IsFloating a, IsInteger b, NumberOfElements a ~ NumberOfElements b) => Value a -> CodeGenFunction r (Value b)
fptoint =
if isSigned (LP.Proxy :: LP.Proxy b)
then convert FFI.buildFPToSI
else convert FFI.buildFPToUI
uitofp :: (IsInteger a, IsFloating b, NumberOfElements a ~ NumberOfElements b) => Value a -> CodeGenFunction r (Value b)
uitofp = convert FFI.buildUIToFP
sitofp :: (IsInteger a, IsFloating b, NumberOfElements a ~ NumberOfElements b) => Value a -> CodeGenFunction r (Value b)
sitofp = convert FFI.buildSIToFP
inttofp :: forall r a b. (IsInteger a, IsFloating b, NumberOfElements a ~ NumberOfElements b) => Value a -> CodeGenFunction r (Value b)
inttofp =
if isSigned (LP.Proxy :: LP.Proxy a)
then convert FFI.buildSIToFP
else convert FFI.buildUIToFP
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, IsSized b, SizeOf a ~ SizeOf b)
=> Value a -> CodeGenFunction r (Value b)
bitcast = convert FFI.buildBitCast
bitcastElements :: (Dec.Positive n, IsPrimitive a, IsPrimitive b, IsSized a, IsSized b, SizeOf a ~ SizeOf b)
=> Value (Vector n a) -> CodeGenFunction r (Value (Vector n b))
bitcastElements = 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 -> do
typ <- typeRef (LP.Proxy :: LP.Proxy b)
U.withEmptyCString $ conv bldPtr a typ
data CmpPredicate =
CmpEQ
| CmpNE
| CmpGT
| CmpGE
| CmpLT
| CmpLE
deriving (Eq, Ord, Enum, Show, Typeable)
uintFromCmpPredicate :: CmpPredicate -> IntPredicate
uintFromCmpPredicate p =
case p of
CmpEQ -> IntEQ
CmpNE -> IntNE
CmpGT -> IntUGT
CmpGE -> IntUGE
CmpLT -> IntULT
CmpLE -> IntULE
sintFromCmpPredicate :: CmpPredicate -> IntPredicate
sintFromCmpPredicate p =
case p of
CmpEQ -> IntEQ
CmpNE -> IntNE
CmpGT -> IntSGT
CmpGE -> IntSGE
CmpLT -> IntSLT
CmpLE -> IntSLE
fpFromCmpPredicate :: CmpPredicate -> FPPredicate
fpFromCmpPredicate p =
case p of
CmpEQ -> FPOEQ
CmpNE -> FPONE
CmpGT -> FPOGT
CmpGE -> FPOGE
CmpLT -> FPOLT
CmpLE -> FPOLE
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)
toIntPredicate :: CInt -> IntPredicate
toIntPredicate p = toEnum $ fromIntegral 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)
toFPPredicate :: CInt -> FPPredicate
toFPPredicate p = toEnum $ fromIntegral p
type CmpValueResult a b = CmpValue a b (CmpResult (CmpType a b))
class CmpRet (CmpType a b) => CmpOp a b where
type CmpType a b :: *
type CmpValue a b :: * -> *
cmpop ::
FFIConstBinOp -> FFIBinOp ->
a -> b -> CodeGenFunction r (CmpValueResult a b)
instance (CmpRet a) => CmpOp (Value a) (Value a) where
type CmpType (Value a) (Value a) = a
type CmpValue (Value a) (Value a) = Value
cmpop _ op (Value a1) (Value a2) = buildBinOp op a1 a2
instance (CmpRet a) => CmpOp (ConstValue a) (Value a) where
type CmpType (ConstValue a) (Value a) = a
type CmpValue (ConstValue a) (Value a) = Value
cmpop _ op (ConstValue a1) (Value a2) = buildBinOp op a1 a2
instance (CmpRet a) => CmpOp (Value a) (ConstValue a) where
type CmpType (Value a) (ConstValue a) = a
type CmpValue (Value a) (ConstValue a) = Value
cmpop _ op (Value a1) (ConstValue a2) = buildBinOp op a1 a2
instance (CmpRet a) => CmpOp (ConstValue a) (ConstValue a) where
type CmpType (ConstValue a) (ConstValue a) = a
type CmpValue (ConstValue a) (ConstValue a) = ConstValue
cmpop cop _ (ConstValue a1) (ConstValue a2) =
liftIO $ fmap ConstValue $ cop a1 a2
class CmpRet c where
type CmpResult c :: *
cmpBld :: LP.Proxy c -> CmpPredicate -> FFIBinOp
cmpCnst :: LP.Proxy c -> CmpPredicate -> FFIConstBinOp
instance CmpRet Float where type CmpResult Float = Bool ; cmpBld _ = fcmpBld ; cmpCnst _ = fcmpCnst
instance CmpRet Double where type CmpResult Double = Bool ; cmpBld _ = fcmpBld ; cmpCnst _ = fcmpCnst
instance CmpRet FP128 where type CmpResult FP128 = Bool ; cmpBld _ = fcmpBld ; cmpCnst _ = fcmpCnst
instance CmpRet Bool where type CmpResult Bool = Bool ; cmpBld _ = ucmpBld ; cmpCnst _ = ucmpCnst
instance CmpRet Word8 where type CmpResult Word8 = Bool ; cmpBld _ = ucmpBld ; cmpCnst _ = ucmpCnst
instance CmpRet Word16 where type CmpResult Word16 = Bool ; cmpBld _ = ucmpBld ; cmpCnst _ = ucmpCnst
instance CmpRet Word32 where type CmpResult Word32 = Bool ; cmpBld _ = ucmpBld ; cmpCnst _ = ucmpCnst
instance CmpRet Word64 where type CmpResult Word64 = Bool ; cmpBld _ = ucmpBld ; cmpCnst _ = ucmpCnst
instance CmpRet Int8 where type CmpResult Int8 = Bool ; cmpBld _ = scmpBld ; cmpCnst _ = scmpCnst
instance CmpRet Int16 where type CmpResult Int16 = Bool ; cmpBld _ = scmpBld ; cmpCnst _ = scmpCnst
instance CmpRet Int32 where type CmpResult Int32 = Bool ; cmpBld _ = scmpBld ; cmpCnst _ = scmpCnst
instance CmpRet Int64 where type CmpResult Int64 = Bool ; cmpBld _ = scmpBld ; cmpCnst _ = scmpCnst
instance CmpRet (Ptr a) where type CmpResult (Ptr a) = Bool ; cmpBld _ = ucmpBld ; cmpCnst _ = ucmpCnst
instance (Dec.Positive n) => CmpRet (WordN n) where type CmpResult (WordN n) = Bool ; cmpBld _ = ucmpBld ; cmpCnst _ = ucmpCnst
instance (Dec.Positive n) => CmpRet (IntN n) where type CmpResult (IntN n) = Bool ; cmpBld _ = ucmpBld ; cmpCnst _ = ucmpCnst
instance (CmpRet a, IsPrimitive a, Dec.Positive n) => CmpRet (Vector n a) where
type CmpResult (Vector n a) = (Vector n (CmpResult a))
cmpBld _ = cmpBld (LP.Proxy :: LP.Proxy a)
cmpCnst _ = cmpCnst (LP.Proxy :: LP.Proxy a)
cmp :: forall a b r.
(CmpOp a b) =>
CmpPredicate -> a -> b ->
CodeGenFunction r (CmpValueResult a b)
cmp p =
cmpop
(cmpCnst (LP.Proxy :: LP.Proxy (CmpType a b)) p)
(cmpBld (LP.Proxy :: LP.Proxy (CmpType a b)) p)
ucmpBld :: CmpPredicate -> FFIBinOp
ucmpBld p = flip FFI.buildICmp (fromIntPredicate (uintFromCmpPredicate p))
scmpBld :: CmpPredicate -> FFIBinOp
scmpBld p = flip FFI.buildICmp (fromIntPredicate (sintFromCmpPredicate p))
fcmpBld :: CmpPredicate -> FFIBinOp
fcmpBld p = flip FFI.buildFCmp (fromFPPredicate (fpFromCmpPredicate p))
ucmpCnst :: CmpPredicate -> FFIConstBinOp
ucmpCnst p = FFI.constICmp (fromIntPredicate (uintFromCmpPredicate p))
scmpCnst :: CmpPredicate -> FFIConstBinOp
scmpCnst p = FFI.constICmp (fromIntPredicate (sintFromCmpPredicate p))
fcmpCnst :: CmpPredicate -> FFIConstBinOp
fcmpCnst p = FFI.constFCmp (fromFPPredicate (fpFromCmpPredicate p))
_ucmp :: (IsInteger c, CmpOp a b, c ~ CmpType a b) =>
CmpPredicate -> a -> b -> CodeGenFunction r (CmpValueResult a b)
_ucmp p = cmpop (ucmpCnst p) (ucmpBld p)
_scmp :: (IsInteger c, CmpOp a b, c ~ CmpType a b) =>
CmpPredicate -> a -> b -> CodeGenFunction r (CmpValueResult a b)
_scmp p = cmpop (scmpCnst p) (scmpBld p)
pcmp :: (CmpOp a b, Ptr c ~ CmpType a b) =>
IntPredicate -> a -> b -> CodeGenFunction r (CmpValueResult a b)
pcmp p =
cmpop
(FFI.constICmp (fromIntPredicate p))
(flip FFI.buildICmp (fromIntPredicate p))
icmp :: (IsIntegerOrPointer c, CmpOp a b, c ~ CmpType a b) =>
IntPredicate -> a -> b -> CodeGenFunction r (CmpValueResult a b)
icmp p =
cmpop
(FFI.constICmp (fromIntPredicate p))
(flip FFI.buildICmp (fromIntPredicate p))
fcmp :: (IsFloating c, CmpOp a b, c ~ CmpType a b) =>
FPPredicate -> a -> b -> CodeGenFunction r (CmpValueResult a b)
fcmp p =
cmpop
(FFI.constFCmp (fromFPPredicate p))
(flip FFI.buildFCmp (fromFPPredicate p))
select :: (IsFirstClass a, CmpRet a) => Value (CmpResult a) -> 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 (f ~ CalledFunction g, r ~ CallerResult g, g ~ CallerFunction f r) =>
CallArgs f g r where
type CalledFunction g :: *
type CallerResult g :: *
type CallerFunction f r :: *
doCall :: Call f -> g
instance (CallArgs b b' r) => CallArgs (a -> b) (Value a -> b') r where
type CalledFunction (Value a -> b') = a -> CalledFunction b'
type CallerResult (Value a -> b') = CallerResult b'
type CallerFunction (a -> b) r = Value a -> CallerFunction b r
doCall f a = doCall (applyCall f a)
instance CallArgs (IO a) (CodeGenFunction r (Value a)) r where
type CalledFunction (CodeGenFunction r (Value a)) = IO a
type CallerResult (CodeGenFunction r (Value a)) = r
type CallerFunction (IO a) r = CodeGenFunction r (Value a)
doCall = runCall
doCallDef :: Caller -> [FFI.ValueRef] -> b -> CodeGenFunction r (Value a)
doCallDef mkCall args _ =
withCurrentBuilder $ \ bld ->
liftM Value $ mkCall bld (reverse args)
call :: (CallArgs f g r) => Function f -> g
call = doCall . callFromFunction
data Call a = Call Caller [FFI.ValueRef]
callFromFunction :: Function a -> Call a
callFromFunction (Value f) = Call (U.makeCall f) []
infixl 4 `applyCall`
applyCall :: Call (a -> b) -> Value a -> Call b
applyCall (Call mkCall args) (Value arg) = Call mkCall (arg:args)
runCall :: Call (IO a) -> CodeGenFunction r (Value a)
runCall (Call mkCall args) = doCallDef mkCall args ()
invokeFromFunction ::
BasicBlock
-> BasicBlock
-> Function f
-> Call f
invokeFromFunction (BasicBlock norm) (BasicBlock expt) (Value f) =
Call (U.makeInvoke norm expt f) []
invoke :: (CallArgs f g r)
=> BasicBlock
-> BasicBlock
-> Function f
-> g
invoke norm expt f = doCall $ invokeFromFunction norm expt f
callWithConvFromFunction :: FFI.CallingConvention -> Function f -> Call f
callWithConvFromFunction cc (Value f) =
Call (U.makeCallWithCc cc f) []
callWithConv :: (CallArgs f g r) => FFI.CallingConvention -> Function f -> g
callWithConv cc f = doCall $ callWithConvFromFunction cc f
invokeWithConvFromFunction ::
FFI.CallingConvention
-> BasicBlock
-> BasicBlock
-> Function f
-> Call f
invokeWithConvFromFunction cc (BasicBlock norm) (BasicBlock expt) (Value f) =
Call (U.makeInvokeWithCc cc norm expt f) []
invokeWithConv :: (CallArgs f g r)
=> FFI.CallingConvention
-> BasicBlock
-> BasicBlock
-> Function f
-> g
invokeWithConv cc norm expt f =
doCall $ invokeWithConvFromFunction cc norm expt 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 (LP.Proxy :: LP.Proxy 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 -> Value Word32
instance AllocArg (Value Word32) where
getAllocArg = id
instance AllocArg (ConstValue Word32) where
getAllocArg = value
instance AllocArg Word32 where
getAllocArg = valueOf
malloc :: forall a r . (IsSized a) => CodeGenFunction r (Value (Ptr a))
malloc = arrayMalloc (1::Word32)
foreign import ccall "&aligned_malloc_sizeptr"
alignedMalloc :: FunPtr (Ptr Word8 -> Ptr Word8 -> IO (Ptr Word8))
foreign import ccall "&aligned_free"
alignedFree :: FunPtr (Ptr Word8 -> IO ())
arrayMalloc :: forall a r s . (IsSized a, AllocArg s) =>
s -> CodeGenFunction r (Value (Ptr a))
arrayMalloc s = do
func <- staticNamedFunction "alignedMalloc" alignedMalloc
size <- sizeOfArray (LP.Proxy :: LP.Proxy a) (getAllocArg s)
alignment <- alignOf (LP.Proxy :: LP.Proxy a)
bitcast =<<
call
(func :: Function (Ptr Word8 -> Ptr Word8 -> IO (Ptr Word8)))
size
alignment
alloca :: forall a r . (IsSized a) => CodeGenFunction r (Value (Ptr a))
alloca =
liftM Value $
withCurrentBuilder $ \ bldPtr -> do
typ <- typeRef (LP.Proxy :: LP.Proxy a)
U.withEmptyCString $ FFI.buildAlloca bldPtr typ
arrayAlloca :: forall a r s . (IsSized a, AllocArg s) =>
s -> CodeGenFunction r (Value (Ptr a))
arrayAlloca s =
liftM Value $
withCurrentBuilder $ \ bldPtr -> do
typ <- typeRef (LP.Proxy :: LP.Proxy a)
U.withEmptyCString $
FFI.buildArrayAlloca bldPtr typ (case getAllocArg s of Value v -> v)
free :: (IsType a) => Value (Ptr a) -> CodeGenFunction r ()
free ptr = do
func <- staticNamedFunction "alignedFree" alignedFree
_ <- call (func :: Function (Ptr Word8 -> IO ())) =<< bitcast ptr
return ()
_sizeOf ::
forall a r.
(IsSized a) => LP.Proxy a -> CodeGenFunction r (Value Word64)
_sizeOf a =
liftIO $ liftM Value $
FFI.sizeOf =<< typeRef a
_alignOf ::
forall a r.
(IsSized a) => LP.Proxy a -> CodeGenFunction r (Value Word64)
_alignOf a =
liftIO $ liftM Value $
FFI.alignOf =<< typeRef a
sizeOfArray ::
forall a r . (IsSized a) =>
LP.Proxy a -> Value Word32 -> CodeGenFunction r (Value (Ptr Word8))
sizeOfArray _ len =
bitcast =<<
getElementPtr (value zero :: Value (Ptr a)) (len, ())
alignOf ::
forall a r . (IsSized a) =>
LP.Proxy a -> CodeGenFunction r (Value (Ptr Word8))
alignOf _ =
bitcast =<<
getElementPtr0 (value zero :: Value (Ptr (Struct (Bool, (a, ()))))) (d1, ())
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 ()
store (Value v) (Value p) = do
withCurrentBuilder_ $ \ bldPtr ->
FFI.buildStore bldPtr v p
return ()
class GetElementPtr optr ixs where
type ElementPtrType optr ixs :: *
getIxList :: LP.Proxy 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 () where
type ElementPtrType a () = a
getIxList _ () = []
instance (GetElementPtr o i, IsIndexArg a, Dec.Natural k) => GetElementPtr (Array k o) (a, i) where
type ElementPtrType (Array k o) (a, i) = ElementPtrType o i
getIxList _ (v, i) = getArg v : getIxList (LP.Proxy :: LP.Proxy o) i
instance (GetElementPtr o i, IsIndexArg a, Dec.Positive k) => GetElementPtr (Vector k o) (a, i) where
type ElementPtrType (Vector k o) (a, i) = ElementPtrType o i
getIxList _ (v, i) = getArg v : getIxList (LP.Proxy :: LP.Proxy o) i
instance (GetElementPtr (FieldType fs a) i, Dec.Natural a) => GetElementPtr (Struct fs) (Proxy a, i) where
type ElementPtrType (Struct fs) (Proxy a, i) = ElementPtrType (FieldType fs a) i
getIxList _ (v, i) = unConst (constOf (Dec.integralFromProxy v :: Word32)) : getIxList (LP.Proxy :: LP.Proxy (FieldType fs a)) i
instance (GetElementPtr (FieldType fs a) i, Dec.Natural a) => GetElementPtr (PackedStruct fs) (Proxy a, i) where
type ElementPtrType (PackedStruct fs) (Proxy a, i) = ElementPtrType (FieldType fs a) i
getIxList _ (v, i) = unConst (constOf (Dec.integralFromProxy v :: Word32)) : getIxList (LP.Proxy :: LP.Proxy (FieldType fs a)) i
class GetField as i where type FieldType as i :: *
instance GetField (a, as) Dec.Zero where type FieldType (a, as) Dec.Zero = a
instance (GetField as (Pred (Dec.Pos i0 i1))) => GetField (a, as) (Dec.Pos i0 i1) where type FieldType (a,as) (Dec.Pos i0 i1) = FieldType as (Pred (Dec.Pos i0 i1))
getElementPtr :: forall a o i r . (GetElementPtr o i, IsIndexArg a) =>
Value (Ptr o) -> (a, i) -> CodeGenFunction r (Value (Ptr (ElementPtrType o i)))
getElementPtr (Value ptr) (a, ixs) =
let ixl = getArg a : getIxList (LP.Proxy :: LP.Proxy 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) =>
Value (Ptr o) -> i -> CodeGenFunction r (Value (Ptr (ElementPtrType o i)))
getElementPtr0 p i = getElementPtr p (0::Word32, i)