llvm-extra-0.10: test/Test/Storable.hs
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE TypeFamilies #-}
module Test.Storable (tests) where
import qualified LLVM.Extra.Storable as Storable
import qualified LLVM.Extra.Tuple as Tuple
import qualified LLVM.ExecutionEngine as EE
import qualified LLVM.Core as LLVM
import qualified Type.Data.Num.Decimal as TypeNum
import qualified Foreign
import Foreign.Storable.Record.Tuple (Tuple(Tuple))
import Foreign.Ptr (FunPtr, Ptr)
import Data.Complex (Complex)
import Data.Word (Word16, Word32)
import Data.Int (Int8, Int16, Int32)
import Data.Tuple.HT (mapFst)
import qualified Test.QuickCheck.Monadic as QCMon
import qualified Test.QuickCheck as QC
type Importer func = FunPtr func -> func
generateFunction ::
EE.ExecutionFunction f =>
Importer f -> LLVM.CodeGenModule (LLVM.Function f) -> IO f
generateFunction imprt code = do
m <- LLVM.newModule
fn <- do
func <- LLVM.defineModule m $ LLVM.setTarget LLVM.hostTriple >> code
EE.runEngineAccessWithModule m $ EE.getExecutionFunction imprt func
LLVM.writeBitcodeToFile "test-storable.bc" m
return fn
foreign import ccall safe "dynamic" derefTestCasePtr ::
Importer (Ptr inp -> Ptr out -> IO ())
modul ::
(Storable.C a, Tuple.ValueOf a ~ al) =>
(Storable.C b, Tuple.ValueOf b ~ bl) =>
(al -> LLVM.CodeGenFunction () bl) ->
LLVM.CodeGenModule (LLVM.Function (Ptr a -> Ptr b -> IO ()))
modul codegen =
LLVM.createFunction LLVM.ExternalLinkage $ \aPtr bPtr -> do
flip Storable.store bPtr =<< codegen =<< Storable.load aPtr
LLVM.ret ()
run ::
(Show a) =>
(Storable.C a, Tuple.ValueOf a ~ al) =>
(Storable.C b, Tuple.ValueOf b ~ bl) =>
QC.Gen a ->
(al -> LLVM.CodeGenFunction () bl) ->
(a -> b -> Bool) ->
IO QC.Property
run qcgen codegen predicate = do
funIO <- generateFunction derefTestCasePtr $ modul codegen
return $ QC.forAll qcgen $ \a ->
QCMon.monadicIO $ do
b <-
QCMon.run $
Foreign.with a $ \aPtr ->
Foreign.alloca $ \bPtr -> do
funIO aPtr bPtr
Foreign.peek bPtr
QCMon.assert $ predicate a b
roundTrip ::
(Show a, Eq a, Storable.C a) =>
QC.Gen a -> IO QC.Property
roundTrip qcgen = run qcgen return (==)
tests :: [(String, IO QC.Property)]
tests =
map (mapFst ("RoundTrip." ++)) $
("()",
roundTrip (QC.arbitrary :: QC.Gen ())) :
("Float",
roundTrip (QC.arbitrary :: QC.Gen Float)) :
("(Word16,Float)",
roundTrip (fmap Tuple (QC.arbitrary :: QC.Gen (Word16,Float)))) :
("(Int8,Bool,Double)",
roundTrip (fmap Tuple (QC.arbitrary :: QC.Gen (Int8,Bool,Double)))) :
("Complex Float",
roundTrip (QC.arbitrary :: QC.Gen (Complex Float))) :
("Vector D3 Int32",
roundTrip (QC.arbitrary :: QC.Gen (LLVM.Vector TypeNum.D3 Int32))) :
("Vector D7 (Int16,Word32)",
roundTrip (fmap (fmap Tuple)
(QC.arbitrary :: QC.Gen (LLVM.Vector TypeNum.D7 (Int16,Word32))))) :
[]