module LLVM.Internal.Type where
import LLVM.Prelude
import Control.Monad.AnyCont
import Control.Monad.Catch
import Control.Monad.State
import qualified Data.Set as Set
import Foreign.Ptr
import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
import LLVM.Internal.FFI.LLVMCTypes (typeKindP)
import qualified LLVM.Internal.FFI.Type as FFI
import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
import qualified LLVM.AST as A
import qualified LLVM.AST.AddrSpace as A
import LLVM.Exception
import LLVM.Internal.Context
import LLVM.Internal.Coding
import LLVM.Internal.DecodeAST
import LLVM.Internal.EncodeAST
getStructure :: Ptr FFI.Type -> DecodeAST A.Type
getStructure t = scopeAnyCont $ do
return A.StructureType
`ap` (decodeM =<< liftIO (FFI.isPackedStruct t))
`ap` do
n <- liftIO (FFI.countStructElementTypes t)
ts <- allocaArray n
liftIO $ FFI.getStructElementTypes t ts
decodeM (n, ts)
getStructDefinitions :: DecodeAST [A.Definition]
getStructDefinitions = do
let getStructDefinition t = do
opaque <- decodeM =<< liftIO (FFI.structIsOpaque t)
if opaque then return Nothing else Just <$> getStructure t
flip fix Set.empty $ \continue done -> do
t <- takeTypeToDefine
flip (maybe (return [])) t $ \t -> do
if t `Set.member` done
then
continue done
else
return (:)
`ap` (return A.TypeDefinition `ap` getTypeName t `ap` getStructDefinition t)
`ap` (continue $ Set.insert t done)
isArrayType :: Ptr FFI.Type -> IO Bool
isArrayType t = do
k <- liftIO $ FFI.getTypeKind t
return $ k == FFI.typeKindArray
instance Monad m => EncodeM m A.AddrSpace FFI.AddrSpace where
encodeM (A.AddrSpace a) = return FFI.AddrSpace `ap` encodeM a
instance Monad m => DecodeM m A.AddrSpace FFI.AddrSpace where
decodeM (FFI.AddrSpace a) = return A.AddrSpace `ap` decodeM a
instance EncodeM EncodeAST A.Type (Ptr FFI.Type) where
encodeM f = scopeAnyCont $ do
Context context <- gets encodeStateContext
case f of
A.IntegerType bits -> do
bits <- encodeM bits
liftIO $ FFI.intTypeInContext context bits
A.FunctionType returnTypeAST argTypeASTs isVarArg -> do
returnType <- encodeM returnTypeAST
argTypes <- encodeM argTypeASTs
isVarArg <- encodeM isVarArg
liftIO $ FFI.functionType returnType argTypes isVarArg
A.PointerType elementType addressSpace -> do
e <- encodeM elementType
a <- encodeM addressSpace
liftIO $ FFI.pointerType e a
A.VoidType -> liftIO $ FFI.voidTypeInContext context
A.FloatingPointType A.HalfFP -> liftIO $ FFI.halfTypeInContext context
A.FloatingPointType A.FloatFP -> liftIO $ FFI.floatTypeInContext context
A.FloatingPointType A.DoubleFP -> liftIO $ FFI.doubleTypeInContext context
A.FloatingPointType A.X86_FP80FP -> liftIO $ FFI.x86FP80TypeInContext context
A.FloatingPointType A.FP128FP -> liftIO $ FFI.fP128TypeInContext context
A.FloatingPointType A.PPC_FP128FP -> liftIO $ FFI.ppcFP128TypeInContext context
A.VectorType sz e -> do
e <- encodeM e
sz <- encodeM sz
liftIO $ FFI.vectorType e sz
A.ArrayType sz e -> do
e <- encodeM e
sz <- encodeM sz
liftIO $ FFI.arrayType e sz
A.StructureType packed ets -> do
ets <- encodeM ets
packed <- encodeM packed
liftIO $ FFI.structTypeInContext context ets packed
A.NamedTypeReference n -> lookupNamedType n
A.MetadataType -> liftIO $ FFI.metadataTypeInContext context
A.TokenType -> liftIO $ FFI.tokenTypeInContext context
A.LabelType -> liftIO $ FFI.labelTypeInContext context
instance DecodeM DecodeAST A.Type (Ptr FFI.Type) where
decodeM t = scopeAnyCont $ do
k <- liftIO $ FFI.getTypeKind t
case k of
[typeKindP|Void|] -> return A.VoidType
[typeKindP|Integer|] -> A.IntegerType <$> (decodeM =<< liftIO (FFI.getIntTypeWidth t))
[typeKindP|Function|] ->
return A.FunctionType
`ap` (decodeM =<< liftIO (FFI.getReturnType t))
`ap` (do
n <- liftIO (FFI.countParamTypes t)
ts <- allocaArray n
liftIO $ FFI.getParamTypes t ts
decodeM (n, ts)
)
`ap` (decodeM =<< liftIO (FFI.isFunctionVarArg t))
[typeKindP|Pointer|] ->
return A.PointerType
`ap` (decodeM =<< liftIO (FFI.getElementType t))
`ap` (decodeM =<< liftIO (FFI.getPointerAddressSpace t))
[typeKindP|Half|] -> return $ A.FloatingPointType A.HalfFP
[typeKindP|Float|] -> return $ A.FloatingPointType A.FloatFP
[typeKindP|Double|] -> return $ A.FloatingPointType A.DoubleFP
[typeKindP|FP128|] -> return $ A.FloatingPointType A.FP128FP
[typeKindP|X86_FP80|] -> return $ A.FloatingPointType A.X86_FP80FP
[typeKindP|PPC_FP128|] -> return $ A.FloatingPointType A.PPC_FP128FP
[typeKindP|Vector|] ->
return A.VectorType
`ap` (decodeM =<< liftIO (FFI.getVectorSize t))
`ap` (decodeM =<< liftIO (FFI.getElementType t))
[typeKindP|Struct|] -> do
let ifM c a b = c >>= \x -> if x then a else b
ifM (decodeM =<< liftIO (FFI.structIsLiteral t))
(getStructure t)
(saveNamedType t >> return A.NamedTypeReference `ap` getTypeName t)
[typeKindP|Metadata|] -> return A.MetadataType
[typeKindP|Array|] ->
return A.ArrayType
`ap` (decodeM =<< liftIO (FFI.getArrayLength t))
`ap` (decodeM =<< liftIO (FFI.getElementType t))
[typeKindP|Token|] -> return A.TokenType
_ -> error $ "unhandled type kind " ++ show k
createNamedType :: A.Name -> EncodeAST (Ptr FFI.Type)
createNamedType n = do
Context c <- gets encodeStateContext
n <- case n of { A.Name n -> encodeM n; _ -> return nullPtr }
liftIO $ FFI.structCreateNamed c n
setNamedType :: Ptr FFI.Type -> A.Type -> EncodeAST ()
setNamedType t (A.StructureType packed ets) = do
ets <- encodeM ets
packed <- encodeM packed
liftIO $ FFI.structSetBody t ets packed
setNamedType _ ty =
throwM
(EncodeException
("A type definition requires a structure type but got: " ++ show ty))