packages feed

llvm-tf-9.2: private/LLVM/ExecutionEngine/Target.hs

{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE EmptyDataDecls #-}
module LLVM.ExecutionEngine.Target (
    TargetData,
    dataLayoutStr,
    abiAlignmentOfType,
    abiSizeOfType,
    littleEndian,
    callFrameAlignmentOfType,
    intPtrType,
    offsetOfElement,
    pointerSize,
    preferredAlignmentOfType,
    sizeOfTypeInBits,
    storeSizeOfType,
    getTargetData,
    targetDataFromString,
    withIntPtrType,
    ) where

import qualified LLVM.ExecutionEngine.Engine as EE
import LLVM.Core.Data (WordN)

import qualified LLVM.FFI.Core as FFI
import qualified LLVM.FFI.Target as FFI

import qualified Type.Data.Num.Decimal.Number as Dec
import Type.Base.Proxy (Proxy)

import Foreign.ForeignPtr
         (ForeignPtr,
          newForeignPtr, withForeignPtr, touchForeignPtr, castForeignPtr)
import Foreign.C.String (withCString, peekCString)

import Control.Monad (liftM2, (<=<))
import Control.Applicative ((<$>))
import Data.Maybe (fromMaybe)
import System.IO.Unsafe (unsafePerformIO)


type Type = FFI.TypeRef

data TargetDataOwner

data TargetData = TargetData (ForeignPtr TargetDataOwner) FFI.TargetDataRef

dataLayoutStr :: TargetData -> String
dataLayoutStr td = unsafeIO td $ peekCString <=< FFI.copyStringRepOfTargetData

abiAlignmentOfType :: TargetData -> Type -> Int
abiAlignmentOfType td = unsafeIntIO td . flip FFI.abiAlignmentOfType

abiSizeOfType :: TargetData -> Type -> Int
abiSizeOfType td = unsafeIntIO td . flip FFI.abiSizeOfType

littleEndian :: TargetData -> Bool
littleEndian td = FFI.bigEndian /= unsafeIO td FFI.byteOrder

callFrameAlignmentOfType :: TargetData -> Type -> Int
callFrameAlignmentOfType td = unsafeIntIO td . flip FFI.callFrameAlignmentOfType

-- elementAtOffset :: TargetData -> Type -> Word64 -> Int

intPtrType :: TargetData -> Type
intPtrType td = unsafeIO td FFI.intPtrType

offsetOfElement :: TargetData -> Type -> Int -> Int
offsetOfElement td ty k =
    unsafeIntIO td $ \r -> FFI.offsetOfElement r ty (fromIntegral k)

pointerSize :: TargetData -> Int
pointerSize td = unsafeIntIO td FFI.pointerSize

-- preferredAlignmentOfGlobal :: TargetData -> Value a -> Int

preferredAlignmentOfType :: TargetData -> Type -> Int
preferredAlignmentOfType td = unsafeIntIO td . flip FFI.preferredAlignmentOfType

sizeOfTypeInBits :: TargetData -> Type -> Int
sizeOfTypeInBits td = unsafeIntIO td . flip FFI.sizeOfTypeInBits

storeSizeOfType :: TargetData -> Type -> Int
storeSizeOfType td = unsafeIntIO td . flip FFI.storeSizeOfType


withIntPtrType :: (forall n . (Dec.Positive n) => WordN n -> a) -> a
withIntPtrType f =
    fromMaybe (error "withIntPtrType: pointer size must be non-negative") $
        Dec.reifyPositive (fromIntegral sz) (\ n -> f (g n))
  where g :: Proxy n -> WordN n
        g _ = error "withIntPtrType: argument used"
        sz = pointerSize $ unsafePerformIO getTargetData


unsafeIO :: TargetData -> (FFI.TargetDataRef -> IO a) -> a
unsafeIO (TargetData fptr td) act =
    unsafePerformIO $ do x <- act td; touchForeignPtr fptr; return x

unsafeIntIO ::
   (Integral i, Num j) => TargetData -> (FFI.TargetDataRef -> IO i) -> j
unsafeIntIO td act = fromIntegral $ unsafeIO td act

-- Normally the TargetDataRef never changes,
-- so the operation are really functions.
-- The ForeignPtr can point to TargetData or to ExecutionEngine.
makeTargetData :: ForeignPtr a -> FFI.TargetDataRef -> TargetData
makeTargetData = TargetData . castForeignPtr

-- Gets the target data for the JIT target.
getTargetData :: IO TargetData
getTargetData =
    EE.runEngineAccess $
    liftM2 makeTargetData
        (EE.fromEngine <$> EE.getEngine)
        EE.getExecutionEngineTargetData

createTargetData :: String -> IO (ForeignPtr FFI.TargetData)
createTargetData s =
    newForeignPtr FFI.ptrDisposeTargetData =<<
    withCString s FFI.createTargetData

targetDataFromString :: String -> TargetData
targetDataFromString s = unsafePerformIO $ do
    td <- createTargetData s
    withForeignPtr td $ return . makeTargetData td