llvm-0.6.0.2: LLVM/ExecutionEngine/Engine.hs
{-# LANGUAGE CPP, ForeignFunctionInterface, FlexibleInstances, UndecidableInstances, OverlappingInstances, ScopedTypeVariables, GeneralizedNewtypeDeriving #-}
module LLVM.ExecutionEngine.Engine(
EngineAccess,
runEngineAccess,
{-
ExecutionEngine,
-}
createExecutionEngine, addModuleProvider, addModule,
{- runStaticConstructors, runStaticDestructors, -}
getExecutionEngineTargetData,
#if HAS_GETPOINTERTOGLOBAL
getPointerToFunction,
#endif
runFunction, getRunFunction,
GenericValue, Generic(..)
) where
import Control.Monad.State
import Control.Concurrent.MVar
import Data.Int
import Data.Word
import Foreign.Marshal.Alloc (alloca, free)
import Foreign.Marshal.Array (withArrayLen)
import Foreign.ForeignPtr (ForeignPtr, newForeignPtr, withForeignPtr)
import Foreign.Marshal.Utils (fromBool)
import Foreign.C.String (peekCString)
import Foreign.Ptr (Ptr)
#if HAS_GETPOINTERTOGLOBAL
import Foreign.Ptr (FunPtr)
import LLVM.Core.CodeGen(Value(..), Function)
#endif
import Foreign.Storable (peek)
import System.IO.Unsafe (unsafePerformIO)
import LLVM.Core.Util(Module, ModuleProvider, withModuleProvider, createModule, createModuleProviderForExistingModule)
import qualified LLVM.FFI.ExecutionEngine as FFI
import qualified LLVM.FFI.Target as FFI
import qualified LLVM.Core.Util(Function)
import LLVM.Core.Type(IsFirstClass, typeRef)
{-
-- |The type of the JITer.
newtype ExecutionEngine = ExecutionEngine {
fromExecutionEngine :: ForeignPtr FFI.ExecutionEngine
}
withExecutionEngine :: ExecutionEngine -> (Ptr FFI.ExecutionEngine -> IO a)
-> IO a
withExecutionEngine = withForeignPtr . fromExecutionEngine
-- |Create an execution engine for a module provider.
-- Warning, do not call this function more than once.
createExecutionEngine :: ModuleProvider -> IO ExecutionEngine
createExecutionEngine prov =
withModuleProvider prov $ \provPtr ->
alloca $ \eePtr ->
alloca $ \errPtr -> do
ret <- FFI.createExecutionEngine eePtr provPtr errPtr
if ret == 1
then do err <- peek errPtr
errStr <- peekCString err
free err
ioError . userError $ errStr
else do ptr <- peek eePtr
liftM ExecutionEngine $ newForeignPtr FFI.ptrDisposeExecutionEngine ptr
addModuleProvider :: ExecutionEngine -> ModuleProvider -> IO ()
addModuleProvider ee prov =
withExecutionEngine ee $ \ eePtr ->
withModuleProvider prov $ \ provPtr ->
FFI.addModuleProvider eePtr provPtr
runStaticConstructors :: ExecutionEngine -> IO ()
runStaticConstructors ee = withExecutionEngine ee FFI.runStaticConstructors
runStaticDestructors :: ExecutionEngine -> IO ()
runStaticDestructors ee = withExecutionEngine ee FFI.runStaticDestructors
getExecutionEngineTargetData :: ExecutionEngine -> IO FFI.TargetDataRef
getExecutionEngineTargetData ee = withExecutionEngine ee FFI.getExecutionEngineTargetData
#if HAS_GETPOINTERTOGLOBAL
getPointerToFunction :: ExecutionEngine -> Function f -> IO (FunPtr f)
getPointerToFunction ee (Value f) =
withExecutionEngine ee $ \ eePtr ->
FFI.getPointerToGlobal eePtr f
#endif
-}
-- This global variable holds the one and only execution engine.
-- It may be missing, but it never dies.
-- XXX We could provide a destructor, what about functions obtained by runFunction?
{-# NOINLINE theEngine #-}
theEngine :: MVar (Maybe (Ptr FFI.ExecutionEngine))
theEngine = unsafePerformIO $ newMVar Nothing
createExecutionEngine :: ModuleProvider -> IO (Ptr FFI.ExecutionEngine)
createExecutionEngine prov =
withModuleProvider prov $ \provPtr ->
alloca $ \eePtr ->
alloca $ \errPtr -> do
ret <- FFI.createExecutionEngine eePtr provPtr errPtr
if ret == 1
then do err <- peek errPtr
errStr <- peekCString err
free err
ioError . userError $ errStr
else do peek eePtr
getTheEngine :: IO (Ptr FFI.ExecutionEngine)
getTheEngine = do
mee <- takeMVar theEngine
case mee of
Just ee -> do putMVar theEngine mee; return ee
Nothing -> do
m <- createModule "__empty__"
mp <- createModuleProviderForExistingModule m
ee <- createExecutionEngine mp
putMVar theEngine (Just ee)
return ee
data EAState = EAState {
ea_engine :: Ptr FFI.ExecutionEngine,
ea_providers :: [ModuleProvider]
}
newtype EngineAccess a = EA (StateT EAState IO a)
deriving (Functor, Monad, MonadState EAState, MonadIO)
-- |The LLVM execution engine is encapsulated so it cannot be accessed directly.
-- The reason is that (currently) there must only ever be one engine,
-- so access to it is wrapped ina monad.
runEngineAccess :: EngineAccess a -> IO a
runEngineAccess (EA body) = do
eePtr <- getTheEngine
let ea = EAState { ea_engine = eePtr, ea_providers = [] }
(a, _ea') <- runStateT body ea
-- XXX should remove module providers again
return a
addModuleProvider :: ModuleProvider -> EngineAccess ()
addModuleProvider prov = do
ea <- get
put ea{ ea_providers = prov : ea_providers ea }
liftIO $ withModuleProvider prov $ \ provPtr ->
FFI.addModuleProvider (ea_engine ea) provPtr
getExecutionEngineTargetData :: EngineAccess FFI.TargetDataRef
getExecutionEngineTargetData = do
eePtr <- gets ea_engine
liftIO $ FFI.getExecutionEngineTargetData eePtr
#if HAS_GETPOINTERTOGLOBAL
getPointerToFunction :: Function f -> EngineAccess (FunPtr f)
getPointerToFunction (Value f) = do
eePtr <- gets ea_engine
liftIO $ FFI.getPointerToGlobal eePtr f
#endif
addModule :: Module -> EngineAccess ()
addModule m = do
mp <- liftIO $ createModuleProviderForExistingModule m
addModuleProvider mp
--------------------------------------
newtype GenericValue = GenericValue {
fromGenericValue :: ForeignPtr FFI.GenericValue
}
withGenericValue :: GenericValue -> (FFI.GenericValueRef -> IO a) -> IO a
withGenericValue = withForeignPtr . fromGenericValue
createGenericValueWith :: IO FFI.GenericValueRef -> IO GenericValue
createGenericValueWith f = do
ptr <- f
liftM GenericValue $ newForeignPtr FFI.ptrDisposeGenericValue ptr
withAll :: [GenericValue] -> (Int -> Ptr FFI.GenericValueRef -> IO a) -> IO a
withAll ps a = go [] ps
where go ptrs (x:xs) = withGenericValue x $ \ptr -> go (ptr:ptrs) xs
go ptrs _ = withArrayLen (reverse ptrs) a
runFunction :: LLVM.Core.Util.Function -> [GenericValue] -> EngineAccess GenericValue
runFunction func args = do
eePtr <- gets ea_engine
liftIO $ withAll args $ \argLen argPtr ->
createGenericValueWith $ FFI.runFunction eePtr func
(fromIntegral argLen) argPtr
getRunFunction :: EngineAccess (LLVM.Core.Util.Function -> [GenericValue] -> IO GenericValue)
getRunFunction = do
eePtr <- gets ea_engine
return $ \ func args ->
withAll args $ \argLen argPtr ->
createGenericValueWith $ FFI.runFunction eePtr func
(fromIntegral argLen) argPtr
class Generic a where
toGeneric :: a -> GenericValue
fromGeneric :: GenericValue -> a
instance Generic () where
toGeneric _ = error "toGeneric ()"
fromGeneric _ = ()
toGenericInt :: (Integral a, IsFirstClass a) => Bool -> a -> GenericValue
toGenericInt signed val = unsafePerformIO $ createGenericValueWith $
FFI.createGenericValueOfInt (typeRef val) (fromIntegral val) (fromBool signed)
fromGenericInt :: (Integral a, IsFirstClass a) => Bool -> GenericValue -> a
fromGenericInt signed val = unsafePerformIO $
withGenericValue val $ \ref ->
return . fromIntegral $ FFI.genericValueToInt ref (fromBool signed)
--instance Generic Bool where
-- toGeneric = toGenericInt False . fromBool
-- fromGeneric = toBool . fromGenericInt False
instance Generic Int8 where
toGeneric = toGenericInt True
fromGeneric = fromGenericInt True
instance Generic Int16 where
toGeneric = toGenericInt True
fromGeneric = fromGenericInt True
instance Generic Int32 where
toGeneric = toGenericInt True
fromGeneric = fromGenericInt True
{-
instance Generic Int where
toGeneric = toGenericInt True
fromGeneric = fromGenericInt True
-}
instance Generic Int64 where
toGeneric = toGenericInt True
fromGeneric = fromGenericInt True
instance Generic Word8 where
toGeneric = toGenericInt False
fromGeneric = fromGenericInt False
instance Generic Word16 where
toGeneric = toGenericInt False
fromGeneric = fromGenericInt False
instance Generic Word32 where
toGeneric = toGenericInt False
fromGeneric = fromGenericInt False
instance Generic Word64 where
toGeneric = toGenericInt False
fromGeneric = fromGenericInt False
toGenericReal :: (Real a, IsFirstClass a) => a -> GenericValue
toGenericReal val = unsafePerformIO $ createGenericValueWith $
FFI.createGenericValueOfFloat (typeRef val) (realToFrac val)
fromGenericReal :: forall a . (Fractional a, IsFirstClass a) => GenericValue -> a
fromGenericReal val = unsafePerformIO $
withGenericValue val $ \ ref ->
return . realToFrac $ FFI.genericValueToFloat (typeRef (undefined :: a)) ref
instance Generic Float where
toGeneric = toGenericReal
fromGeneric = fromGenericReal
instance Generic Double where
toGeneric = toGenericReal
fromGeneric = fromGenericReal
instance Generic (Ptr a) where
toGeneric = unsafePerformIO . createGenericValueWith . FFI.createGenericValueOfPointer
fromGeneric val = unsafePerformIO . withGenericValue val $ FFI.genericValueToPointer