llvm-party-12.1.0: src/LLVM/AST/Typed.hs
{-# LANGUAGE RecordWildCards #-}
-- | Querying the type of LLVM expressions
module LLVM.AST.Typed (
Typed(..),
getElementType,
indexTypeByConstants,
indexTypeByOperands,
extractValueType,
) where
import LLVM.Prelude
import Control.Monad.State (gets)
import qualified Data.Map.Lazy as Map
import qualified Data.Either as Either
import GHC.Stack
import LLVM.AST
import LLVM.AST.Global
import LLVM.AST.Type
import LLVM.IRBuilder.Module
import qualified LLVM.AST.Constant as C
import qualified LLVM.AST.Float as F
class Typed a where
typeOf :: (HasCallStack, MonadModuleBuilder m) => a -> m (Either String Type)
instance Typed Operand where
typeOf (LocalReference t _) = return $ Right t
typeOf (ConstantOperand c) = typeOf c
typeOf _ = return $ Right MetadataType
instance Typed CallableOperand where
typeOf (Right op) = typeOf op
typeOf (Left _) = return $ Left "typeOf inline assembler is not defined. (Malformed AST)"
instance Typed C.Constant where
typeOf (C.Int bits _) = return $ Right $ IntegerType bits
typeOf (C.Float t) = typeOf t
typeOf (C.Null t) = return $ Right t
typeOf (C.AggregateZero t) = return $ Right t
typeOf (C.Struct {..}) = case structName of
Nothing -> do
mvtys <- mapM typeOf memberValues
case (all Either.isRight mvtys) of
True -> return $ Right $ StructureType isPacked $ Either.rights mvtys
False -> do
let (Left s) = head $ filter Either.isLeft mvtys
return $ Left $ "Could not deduce type for struct field: " ++ s
Just sn -> return $ Right $ NamedTypeReference sn
typeOf (C.Array {..}) = return $ Right $ ArrayType (fromIntegral $ length memberValues) memberType
typeOf (C.Vector {..}) = case memberValues of
[] -> return $ Left "Vectors of size zero are not allowed. (Malformed AST)"
(x:_) -> do
t <- typeOf x
case t of
(Left _) -> return t
(Right t') -> return $ Right $ VectorType (fromIntegral $ length memberValues) t'
typeOf (C.Undef t) = return $ Right t
typeOf (C.BlockAddress {}) = return $ Right $ ptr i8
typeOf (C.GlobalReference t _) = return $ Right t
typeOf (C.Add {..}) = typeOf operand0
typeOf (C.FAdd {..}) = typeOf operand0
typeOf (C.FDiv {..}) = typeOf operand0
typeOf (C.FRem {..}) = typeOf operand0
typeOf (C.Sub {..}) = typeOf operand0
typeOf (C.FSub {..}) = typeOf operand0
typeOf (C.Mul {..}) = typeOf operand0
typeOf (C.FMul {..}) = typeOf operand0
typeOf (C.UDiv {..}) = typeOf operand0
typeOf (C.SDiv {..}) = typeOf operand0
typeOf (C.URem {..}) = typeOf operand0
typeOf (C.SRem {..}) = typeOf operand0
typeOf (C.Shl {..}) = typeOf operand0
typeOf (C.LShr {..}) = typeOf operand0
typeOf (C.AShr {..}) = typeOf operand0
typeOf (C.And {..}) = typeOf operand0
typeOf (C.Or {..}) = typeOf operand0
typeOf (C.Xor {..}) = typeOf operand0
typeOf (C.GetElementPtr {..}) = do
aty <- typeOf address
case aty of
(Left _) -> return aty
(Right aty') -> indexTypeByConstants aty' indices
typeOf (C.Trunc {..}) = return $ Right type'
typeOf (C.ZExt {..}) = return $ Right type'
typeOf (C.SExt {..}) = return $ Right type'
typeOf (C.FPToUI {..}) = return $ Right type'
typeOf (C.FPToSI {..}) = return $ Right type'
typeOf (C.UIToFP {..}) = return $ Right type'
typeOf (C.SIToFP {..}) = return $ Right type'
typeOf (C.FPTrunc {..}) = return $ Right type'
typeOf (C.FPExt {..}) = return $ Right type'
typeOf (C.PtrToInt {..}) = return $ Right type'
typeOf (C.IntToPtr {..}) = return $ Right type'
typeOf (C.BitCast {..}) = return $ Right type'
typeOf (C.ICmp {..}) = do
t <- typeOf operand0
case t of
(Left _) -> return t
(Right (VectorType n _)) -> return $ Right $ VectorType n i1
(Right _) -> return $ Right i1
typeOf (C.FCmp {..}) = do
t <- typeOf operand0
case t of
(Left _) -> return t
(Right (VectorType n _)) -> return $ Right $ VectorType n i1
(Right _) -> return $ Right i1
typeOf (C.Select {..}) = typeOf trueValue
typeOf (C.ExtractElement {..}) = do
t <- typeOf vector
case t of
(Left _) -> return t
(Right (VectorType _ t')) -> return $ Right t'
(Right _) -> return $ Left "The first operand of an extractelement instruction is a value of vector type. (Malformed AST)"
typeOf (C.InsertElement {..}) = typeOf vector
typeOf (C.ShuffleVector {..}) = do
t0 <- typeOf operand0
tm <- typeOf mask
case (t0, tm) of
(Right (VectorType _ t), Right (VectorType m _)) -> return $ Right $ VectorType m t
_ -> return $ Left "The first operand of an shufflevector instruction is a value of vector type. (Malformed AST)"
typeOf (C.ExtractValue {..}) = do
t <- typeOf aggregate
case t of
(Left _) -> return t
(Right t') -> extractValueType indices' t'
typeOf (C.InsertValue {..}) = typeOf aggregate
typeOf (C.TokenNone) = return $ Right TokenType
typeOf (C.AddrSpaceCast {..}) = return $ Right type'
-- | Index into a type using a list of 'Constant' values. Returns a pointer type whose referent is the indexed type, or an error message if indexing was not possible.
indexTypeByConstants :: (HasCallStack, MonadModuleBuilder m) => Type -> [C.Constant] -> m (Either String Type)
indexTypeByConstants ty [] = return $ Right $ ptr ty
indexTypeByConstants (PointerType ty _) (_:is) = indexTypeByConstants ty is
indexTypeByConstants (StructureType _ elTys) (C.Int 32 val:is) =
indexTypeByConstants (elTys !! fromIntegral val) is
indexTypeByConstants (StructureType _ _) (i:_) =
return $ Left $ "Indices into structures should be 32-bit integer constants. (Malformed AST): " ++ show i
indexTypeByConstants (VectorType _ elTy) (_:is) = indexTypeByConstants elTy is
indexTypeByConstants (ArrayType _ elTy) (_:is) = indexTypeByConstants elTy is
indexTypeByConstants (NamedTypeReference n) is = do
mayTy <- liftModuleState (gets (Map.lookup n . builderTypeDefs))
case mayTy of
Nothing -> return $ Left $ "Couldn’t resolve typedef for: " ++ show n
Just ty -> indexTypeByConstants ty is
indexTypeByConstants ty _ = return $ Left $ "Expecting aggregate type. (Malformed AST): " ++ show ty
-- | Index into a type using a list of 'Operand' values. Returns a pointer type whose referent is the indexed type, or an error message if indexing was not possible.
indexTypeByOperands :: (HasCallStack, MonadModuleBuilder m) => Type -> [Operand] -> m (Either String Type)
indexTypeByOperands ty [] = return $ Right $ ptr ty
indexTypeByOperands (PointerType ty _) (_:is) = indexTypeByOperands ty is
indexTypeByOperands (StructureType _ elTys) (ConstantOperand (C.Int 32 val):is) =
indexTypeByOperands (elTys !! fromIntegral val) is
indexTypeByOperands (StructureType _ _) (i:_) =
return $ Left $ "Indices into structures should be 32-bit integer constants. (Malformed AST): " ++ show i
indexTypeByOperands (VectorType _ elTy) (_:is) = indexTypeByOperands elTy is
indexTypeByOperands (ArrayType _ elTy) (_:is) = indexTypeByOperands elTy is
indexTypeByOperands (NamedTypeReference n) is = do
mayTy <- liftModuleState (gets (Map.lookup n . builderTypeDefs))
case mayTy of
Nothing -> return $ Left $ "Couldn’t resolve typedef for: " ++ show n
Just ty -> indexTypeByOperands ty is
indexTypeByOperands ty _ = return $ Left $ "Expecting aggregate type. (Malformed AST): " ++ show ty
getElementType :: Type -> Either String Type
getElementType (PointerType t _) = Right t
getElementType t = Left $ "Expecting pointer type. (Malformed AST): " ++ show t
extractValueType :: (HasCallStack, MonadModuleBuilder m) => [Word32] -> Type -> m (Either String Type)
extractValueType [] ty = return $ Right ty
extractValueType (i : is) (ArrayType numEls elTy)
| fromIntegral i < numEls = extractValueType is elTy
| fromIntegral i >= numEls = return $ Left $ "Expecting valid index into array type. (Malformed AST): " ++ show i
extractValueType (i : is) (StructureType _ elTys)
| fromIntegral i < length elTys = extractValueType is (elTys !! fromIntegral i)
| otherwise = return $ Left $ "Expecting valid index into structure type. (Malformed AST): " ++ show i
extractValueType _ ty = return $ Left $ "Expecting vector type. (Malformed AST): " ++ show ty
instance Typed F.SomeFloat where
typeOf (F.Half _) = return $ Right $ FloatingPointType HalfFP
typeOf (F.Single _) = return $ Right $ FloatingPointType FloatFP
typeOf (F.Double _) = return $ Right $ FloatingPointType DoubleFP
typeOf (F.Quadruple _ _) = return $ Right $ FloatingPointType FP128FP
typeOf (F.X86_FP80 _ _) = return $ Right $ FloatingPointType X86_FP80FP
typeOf (F.PPC_FP128 _ _) = return $ Right $ FloatingPointType PPC_FP128FP
instance Typed Global where
typeOf (GlobalVariable {..}) = return $ Right $ type'
typeOf (GlobalAlias {..}) = return $ Right $ type'
typeOf (Function {..}) = do
let (params, isVarArg) = parameters
ptys <- mapM typeOf params
case (all Either.isRight ptys) of
True -> return $ Right $ FunctionType returnType (Either.rights ptys) isVarArg
False -> do
let (Left s) = head $ filter Either.isLeft ptys
return $ Left $ "Could not deduce type for function parameter: " ++ s
instance Typed Parameter where
typeOf (Parameter t _ _) = return $ Right t
instance Typed [Int32] where
typeOf mask = return $ Right $ VectorType (fromIntegral $ length mask) i32