synthesizer-llvm-0.3: src/Synthesizer/LLVM/Execution.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
module Synthesizer.LLVM.Execution where
import qualified LLVM.ExecutionEngine as EE
import qualified LLVM.Util.Optimize as Opt
import qualified LLVM.Core as LLVM
import Foreign.Ptr (FunPtr, )
import qualified Control.Monad.Trans.Reader as R
import Control.Monad (liftM2, liftM3, )
import qualified Data.IORef as IORef
import System.IO.Unsafe (unsafePerformIO, )
import qualified Synthesizer.LLVM.Debug.Counter as Counter
type Importer f = FunPtr f -> f
class Compile externFunction llvmFunction |
externFunction -> llvmFunction,
llvmFunction -> externFunction where
compile :: llvmFunction -> EE.EngineAccess externFunction
instance Compile (FunPtr f) (LLVM.Function f) where
compile = EE.getPointerToFunction
instance (Compile efa lfa, Compile efb lfb) =>
Compile (efa,efb) (lfa,lfb) where
compile (fa,fb) =
liftM2 (,)
(compile fa)
(compile fb)
instance (Compile efa lfa, Compile efb lfb, Compile efc lfc) =>
Compile (efa,efb,efc) (lfa,lfb,lfc) where
compile (fa,fb,fc) =
liftM3 (,,)
(compile fa)
(compile fb)
(compile fc)
data BitCodeCnt = BitCodeCnt
{- |
This is only for debugging purposes
and thus I felt free to use unsafePerformIO.
-}
counter :: IORef.IORef (Counter.T BitCodeCnt)
counter =
unsafePerformIO $ Counter.new
{- |
This function also initializes LLVM.
This simplifies usage from GHCi.
The @llvm@ packages prevents multiple initialization.
-}
assembleModule ::
(llvmFunction -> EE.EngineAccess externFunction) ->
LLVM.CodeGenModule llvmFunction ->
IO externFunction
assembleModule comp bld = do
LLVM.initializeNativeTarget
m <- LLVM.newModule
(funcs, mappings) <-
LLVM.defineModule m (liftM2 (,) bld LLVM.getGlobalMappings)
Counter.with counter $ R.ReaderT $ \cnt -> do
LLVM.writeBitcodeToFile ("generator" ++ Counter.format 3 cnt ++ ".bc") m
_ <- Opt.optimizeModule 3 m
LLVM.writeBitcodeToFile ("generator" ++ Counter.format 3 cnt ++ "-opt.bc") m
EE.runEngineAccess $
EE.addModule m >>
EE.addGlobalMappings mappings >>
comp funcs
-- this compiles once and is much faster than runFunction
compileModule ::
(Compile externFunction llvmFunction) =>
LLVM.CodeGenModule llvmFunction ->
IO externFunction
compileModule =
assembleModule compile
runFunction ::
(EE.Translatable f) =>
LLVM.CodeGenModule (LLVM.Function f) -> IO f
runFunction =
assembleModule EE.generateFunction