packages feed

llvm-0.0.2: LLVM/ExecutionEngine.hs

{-# LANGUAGE
   DeriveDataTypeable
  , FunctionalDependencies
  , MultiParamTypeClasses
  #-}

module LLVM.ExecutionEngine
    (
    -- * Execution engines
      ExecutionEngine
    , createExecutionEngine
    , runStaticConstructors
    , runStaticDestructors
    , runFunction

    -- * Generic values
    , GenericValue
    , Generic(..)
    ) where

import Control.Applicative ((<$>))
import Control.Exception (ioError)
import Data.Int (Int8, Int16, Int32, Int64)
import Data.Typeable (Typeable)
import Data.Word (Word8, Word16, Word32, Word64)
import Foreign.ForeignPtr (FinalizerPtr, ForeignPtr, newForeignPtr,
                           withForeignPtr)
import Foreign.C.String (peekCString)
import Foreign.Marshal.Alloc (alloca, free)
import Foreign.Marshal.Array (withArrayLen)
import Foreign.Marshal.Utils (fromBool, toBool)
import Foreign.Ptr (Ptr)
import Foreign.Storable (peek)
import System.IO.Error (userError)
import System.IO.Unsafe (unsafePerformIO)

import qualified LLVM.ExecutionEngine.FFI as FFI
import qualified LLVM.Core.Type as T
import qualified LLVM.Core.Value as V

newtype ExecutionEngine = ExecutionEngine {
      fromExecutionEngine :: ForeignPtr FFI.ExecutionEngine
    }

withExecutionEngine :: ExecutionEngine -> (Ptr FFI.ExecutionEngine -> IO a)
                    -> IO a
withExecutionEngine ee = withForeignPtr (fromExecutionEngine ee)

createExecutionEngine :: T.ModuleProvider -> IO ExecutionEngine
createExecutionEngine prov =
    T.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
                    final <- h2c_ee FFI.disposeExecutionEngine
                    ExecutionEngine <$> newForeignPtr final ptr

foreign import ccall "wrapper" h2c_ee
    :: (Ptr FFI.ExecutionEngine -> IO ()) -> IO (FinalizerPtr a)

runStaticConstructors :: ExecutionEngine -> IO ()
runStaticConstructors ee = withExecutionEngine ee FFI.runStaticConstructors

runStaticDestructors :: ExecutionEngine -> IO ()
runStaticDestructors ee = withExecutionEngine ee FFI.runStaticDestructors


newtype GenericValue t = GenericValue {
      fromGenericValue :: ForeignPtr FFI.GenericValue
    }
    deriving (Typeable)

withGenericValue :: GenericValue t -> (FFI.GenericValueRef -> IO a) -> IO a
withGenericValue = withForeignPtr . fromGenericValue

createGenericValueWith :: IO FFI.GenericValueRef -> IO (GenericValue t)
createGenericValueWith f = do
  final <- h2c_genericValue FFI.disposeGenericValue
  ptr <- f
  GenericValue <$> newForeignPtr final ptr

foreign import ccall "wrapper" h2c_genericValue
    :: (FFI.GenericValueRef -> IO ()) -> IO (FinalizerPtr a)

withAll :: [GenericValue t] -> (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 :: ExecutionEngine -> V.Function r p -> [GenericValue t]
            -> IO (GenericValue r)
runFunction ee func args =
    withExecutionEngine ee $ \eePtr ->
      withAll args $ \argLen argPtr ->
        createGenericValueWith $ FFI.runFunction eePtr (V.valueRef func)
                                        (fromIntegral argLen) argPtr

class Generic a t | a -> t where
    createGeneric :: a -> IO (GenericValue t)
    fromGeneric :: GenericValue t -> a

toGenericInt :: (Integral a, T.Type t) => (b -> t) -> Bool -> a -> IO (GenericValue t)
toGenericInt typf signed val = createGenericValueWith $
    FFI.createGenericValueOfInt (T.typeRef (typf undefined))
           (fromIntegral val) (fromBool signed)

fromGenericInt :: (Integral a, T.Type t) => Bool -> GenericValue t -> a
fromGenericInt signed val = unsafePerformIO $
    withGenericValue val $ \ref ->
      return . fromIntegral $ FFI.genericValueToInt ref (fromBool signed)

instance Generic Bool T.Int1 where
    createGeneric = toGenericInt T.int1 False . fromBool
    fromGeneric = toBool . fromGenericInt False

instance Generic Int8 T.Int8 where
    createGeneric = toGenericInt T.int8 True . fromIntegral
    fromGeneric = fromIntegral . fromGenericInt True

instance Generic Int16 T.Int16 where
    createGeneric = toGenericInt T.int16 True . fromIntegral
    fromGeneric = fromIntegral . fromGenericInt True

instance Generic Int32 T.Int32 where
    createGeneric = toGenericInt T.int32 True . fromIntegral
    fromGeneric = fromIntegral . fromGenericInt True

instance Generic Int T.Int32 where
    createGeneric = toGenericInt T.int32 True . fromIntegral
    fromGeneric = fromIntegral . fromGenericInt True

instance Generic Int64 T.Int64 where
    createGeneric = toGenericInt T.int64 True . fromIntegral
    fromGeneric = fromIntegral . fromGenericInt True

instance Generic Word8 T.Int8 where
    createGeneric = toGenericInt T.int8 False . fromIntegral
    fromGeneric = fromIntegral . fromGenericInt False

instance Generic Word16 T.Int16 where
    createGeneric = toGenericInt T.int16 False . fromIntegral
    fromGeneric = fromIntegral . fromGenericInt False

instance Generic Word32 T.Int32 where
    createGeneric = toGenericInt T.int32 False . fromIntegral
    fromGeneric = fromIntegral . fromGenericInt False

instance Generic Word64 T.Int64 where
    createGeneric = toGenericInt T.int64 False . fromIntegral
    fromGeneric = fromIntegral . fromGenericInt False

toGenericReal :: (Real a, T.Type t) => t -> a -> IO (GenericValue t)
toGenericReal typ val = createGenericValueWith $
    FFI.createGenericValueOfFloat (T.typeRef typ) (realToFrac val)

fromGenericReal :: (Fractional a, T.Type t) => GenericValue t -> a
fromGenericReal val = unsafePerformIO $
    withGenericValue val $ \ref ->
      return . realToFrac $ FFI.genericValueToFloat ref

instance Generic Float T.Float where
    createGeneric = toGenericReal undefined
    fromGeneric = fromGenericReal

instance Generic Double T.Double where
    createGeneric = toGenericReal undefined
    fromGeneric = fromGenericReal