llvm-hs-4.2.0: src/LLVM/Internal/OrcJIT/CompileOnDemandLayer.hs
{-# LANGUAGE MultiParamTypeClasses, OverloadedStrings #-}
module LLVM.Internal.OrcJIT.CompileOnDemandLayer where
import LLVM.Prelude
import Control.Exception
import Control.Monad.AnyCont
import Control.Monad.IO.Class
import Data.IORef
import Foreign.Ptr
import LLVM.Internal.Coding
import LLVM.Internal.OrcJIT
import LLVM.Internal.OrcJIT.CompileLayer
import LLVM.Internal.Target
import qualified LLVM.Internal.FFI.DataLayout as FFI
import qualified LLVM.Internal.FFI.OrcJIT as FFI
import qualified LLVM.Internal.FFI.OrcJIT.CompileOnDemandLayer as FFI
import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
type PartitioningFn = Ptr FFI.Function -> IO [Ptr FFI.Function]
-- | This is used by 'CompileOnDemandLayer' to create callback that
-- compile functions when they are called.
data JITCompileCallbackManager =
CallbackMgr !(Ptr FFI.JITCompileCallbackManager)
!(IO ())
-- | This is used by 'CompileOnDemandLayer' to manage the stubs
-- created for function definitions that have not yet been compiled.
newtype IndirectStubsManagerBuilder =
StubsMgr (Ptr FFI.IndirectStubsManagerBuilder)
-- | Adding a module to a 'CompileOnDemandLayer' creates stubs for its
-- functions definitions. When one of those stubs is called, the
-- corresponding function body is extracted and compiled.
data CompileOnDemandLayer baseLayer =
CompileOnDemandLayer {
compileLayer :: !(Ptr FFI.CompileOnDemandLayer),
dataLayout :: !(Ptr FFI.DataLayout),
cleanupActions :: !(IORef [IO ()])
}
deriving Eq
instance CompileLayer (CompileOnDemandLayer l) where
getCompileLayer = FFI.upCast . compileLayer
getDataLayout = dataLayout
getCleanups = cleanupActions
instance MonadIO m =>
EncodeM m PartitioningFn (IORef [IO ()] -> IO (FunPtr FFI.PartitioningFn)) where
encodeM partition = return $ \cleanups -> do
allocFunPtr
cleanups
(FFI.wrapPartitioningFn
(\f set -> do
fs <- partition f
traverse_ (FFI.insertFun set) fs
return ()))
instance (MonadIO m, MonadAnyCont IO m) =>
EncodeM m (Maybe (IO ())) (FFI.TargetAddress, IO ()) where
encodeM Nothing = return (FFI.TargetAddress 0, return ())
encodeM (Just f) = do
f' <- anyContToM $ bracketOnError (FFI.wrapErrorHandler f) freeHaskellFunPtr
return
( (FFI.TargetAddress . fromIntegral . ptrToWordPtr . castFunPtrToPtr) f'
, freeHaskellFunPtr f')
-- | Create a new 'IndirectStubsManagerBuilder'.
--
-- When the stubs manager is no longer needed, it should be freed
-- using 'disposeIndirectStubsManagerBuilder'.
newIndirectStubsManagerBuilder ::
ShortByteString {- ^ target triple -} ->
IO IndirectStubsManagerBuilder
newIndirectStubsManagerBuilder triple =
flip runAnyContT return $ do
triple' <- encodeM triple
stubsMgr <- liftIO (FFI.createLocalIndirectStubsManagerBuilder triple')
return (StubsMgr stubsMgr)
-- | Dispose of an 'IndirectStubsManagerBuilder'.
disposeIndirectStubsManagerBuilder :: IndirectStubsManagerBuilder -> IO ()
disposeIndirectStubsManagerBuilder (StubsMgr stubsMgr) =
FFI.disposeIndirectStubsManagerBuilder stubsMgr
-- | 'bracket'-style wrapper around 'newIndirectStubsManagerBuilder'
-- and 'disposeIndirectStubsManagerBuilder'.
withIndirectStubsManagerBuilder ::
ShortByteString {- ^ target triple -} ->
(IndirectStubsManagerBuilder -> IO a) ->
IO a
withIndirectStubsManagerBuilder triple =
bracket
(newIndirectStubsManagerBuilder triple)
disposeIndirectStubsManagerBuilder
-- | Create a new 'JITCompileCallbackManager'.
--
-- When the callback manager is no longer needed, it should be freed
-- using 'disposeJITCompileCallbackManager'.
newJITCompileCallbackManager ::
ShortByteString {- ^ target triple -} ->
Maybe (IO ()) {- ^ called on compilation errors -} ->
IO JITCompileCallbackManager
newJITCompileCallbackManager triple errorHandler = flip runAnyContT return $ do
triple' <- encodeM triple
(errorHandler', cleanup) <- encodeM errorHandler
callbackMgr <- liftIO (FFI.createLocalCompileCallbackManager triple' errorHandler')
return (CallbackMgr callbackMgr cleanup)
-- | Dispose of a 'JITCompileCallbackManager'.
disposeJITCompileCallbackManager :: JITCompileCallbackManager -> IO ()
disposeJITCompileCallbackManager (CallbackMgr mgr cleanup) =
FFI.disposeCallbackManager mgr >> cleanup
-- | Execute a computation using a new 'JITCompileCallbackManager'.
withJITCompileCallbackManager ::
ShortByteString {- ^ target triple -} ->
Maybe (IO ()) {- ^ called on compilation errors -} ->
(JITCompileCallbackManager -> IO a) ->
IO a
withJITCompileCallbackManager triple errorHandler =
bracket
(newJITCompileCallbackManager triple errorHandler)
disposeJITCompileCallbackManager
-- | Create a new 'CompileOnDemandLayer'. The partitioning function
-- specifies which functions should be compiled when a function is
-- called.
--
-- When the layer is no longer needed, it should be disposed using 'disposeCompileLayer'.
newCompileOnDemandLayer :: CompileLayer l =>
l ->
TargetMachine ->
(Ptr FFI.Function -> IO [Ptr FFI.Function]) {- ^ partitioning function -} ->
JITCompileCallbackManager ->
IndirectStubsManagerBuilder ->
Bool {- ^ clone stubs into partitions -} ->
IO (CompileOnDemandLayer l)
newCompileOnDemandLayer baseLayer tm partition (CallbackMgr callbackMgr _) (StubsMgr stubsMgr) cloneStubs =
flip runAnyContT return $ do
cleanups <- liftIO (newIORef [])
dl <- createRegisteredDataLayout tm cleanups
partitionAct <- encodeM partition
partition' <- liftIO $ partitionAct cleanups
cloneStubs' <- encodeM cloneStubs
cl <-
liftIO
(FFI.createCompileOnDemandLayer
(getCompileLayer baseLayer)
partition'
callbackMgr
stubsMgr
cloneStubs')
return (CompileOnDemandLayer cl dl cleanups)
-- | 'bracket'-style wrapper around 'newCompileOnDemandLayer' and 'disposeCompileLayer'.
withCompileOnDemandLayer ::
CompileLayer l =>
l ->
TargetMachine ->
(Ptr FFI.Function -> IO [Ptr FFI.Function]) {- ^ partitioning function -} ->
JITCompileCallbackManager ->
IndirectStubsManagerBuilder ->
Bool {- ^ clone stubs into partitions -} ->
(CompileOnDemandLayer l -> IO a) ->
IO a
withCompileOnDemandLayer l tm partition callbackMgr stubsMgr cloneStubs =
bracket
(newCompileOnDemandLayer l tm partition callbackMgr stubsMgr cloneStubs)
disposeCompileLayer