packages feed

synthesizer-llvm-0.2: src/Synthesizer/LLVM/Execution.hs

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}
module Synthesizer.LLVM.Execution where

import LLVM.Core
   (CodeGenModule, newModule, defineModule, getGlobalMappings, Function,
    writeBitcodeToFile, )
import LLVM.ExecutionEngine
   (EngineAccess, runEngineAccess,
    Translatable, generateFunction,
    addModule, getPointerToFunction, addGlobalMappings, )
import LLVM.Util.Optimize (optimizeModule, )

import Foreign.Ptr (FunPtr, )

import Control.Monad (liftM2, liftM3, )

import qualified Data.List.HT as ListHT
import qualified Data.IORef as IORef
import System.IO.Unsafe (unsafePerformIO, )


type Importer f = FunPtr f -> f

class Compile externFunction llvmFunction |
                    externFunction -> llvmFunction,
                    llvmFunction -> externFunction where
   compile :: llvmFunction -> EngineAccess externFunction

instance Compile (FunPtr f) (Function f) where
   compile = 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)


{- |
This is only for debugging purposes
and thus I felt free to use unsafePerformIO.
-}
counter :: IORef.IORef Int
counter =
   unsafePerformIO $ IORef.newIORef 0


assembleModule ::
   (llvmFunction -> EngineAccess externFunction) ->
   CodeGenModule llvmFunction ->
   IO externFunction
assembleModule comp bld = do
   m <- newModule
   (funcs, mappings) <-
      defineModule m (liftM2 (,) bld getGlobalMappings)

   -- write bitcode files for debugging
   num <- fmap (ListHT.padLeft '0' 3 . show) (IORef.readIORef counter)
   IORef.modifyIORef counter succ

   writeBitcodeToFile ("generator"++num++".bc") m

   optimizeModule 3 m

   writeBitcodeToFile ("generator"++num++"-opt.bc") m

   runEngineAccess $
      addModule m >>
      addGlobalMappings mappings >>
      comp funcs


-- this compiles once and is much faster than runFunction
compileModule ::
   (Compile externFunction llvmFunction) =>
   CodeGenModule llvmFunction ->
   IO externFunction
compileModule =
   assembleModule compile

runFunction ::
   (Translatable f) =>
   CodeGenModule (Function f) -> IO f
runFunction =
   assembleModule generateFunction