{-# LANGUAGE TemplateHaskell, QuasiQuotes #-} {-# LANGUAGE GHCForeignImportPrim, UnliftedFFITypes, UnboxedTuples #-} import Foreign.Ptr import Test.Hspec import Test.QuickCheck import Language.Asm.Inline import Language.Asm.Inline.QQ defineAsmFun "timesTwoInt" [t| Int -> Int |] "add %rbx, %rbx" defineAsmFun "plusInt" [t| Int -> Int -> Int |] "add %r14, %rbx" defineAsmFun "swapInts" [t| Int -> Int -> (Int, Int) |] "xchg %rbx, %r14" defineAsmFun "timesTwoIntQQ" [asmTy| (a : Int) | (_ : Int) |] [asm| add ${a}, ${a} |] defineAsmFun "plusIntQQ" [asmTy| (a : Int) (b : Int) | (_ : Int) |] [asm| add ${b}, ${a} |] defineAsmFun "swap2p1QQ" [asmTy| (a : Int) (b : Int) | (a : Int) (b : Int) |] [asm| xchg ${a}, ${b} add $1, ${b} |] defineAsmFun "timesTwoFloatQQ" [asmTy| (a : Float) | (_ : Float) |] [asm| addss ${a}, ${a} |] defineAsmFun "plusFloatQQ" [asmTy| (a : Float) (b : Float) | (_ : Float) |] [asm| addss ${b}, ${a} |] defineAsmFun "timesTwoDoubleQQ" [asmTy| (a : Double) | (_ : Double) |] [asm| addsd ${a}, ${a} |] defineAsmFun "plusDoubleQQ" [asmTy| (a : Double) (b : Double) | (_ : Double) |] [asm| addsd ${b}, ${a} |] defineAsmFun "timesTwoEverything" [asmTy| (d : Double) (n : Int) (f : Float) (w : Word) | (_ : Double) (_ : Int) (_ : Float) (_ : Word) |] [asm| addsd ${d}, ${d} addss ${f}, ${f} add ${n}, ${n} add ${w}, ${w} |] defineAsmFun "addPtr" [asmTy| (ptr : Ptr Int) (shift : Int) | (_ : Ptr Int) |] [asm| add ${shift}, ${ptr} |] defineAsmFun "swapPtrs" [asmTy| (a : Ptr Int) (b : Ptr Int) | (_ : Ptr Int) (_ : Ptr Int) |] [asm| xchg ${a}, ${b} |] main :: IO () main = hspec $ do describe "Works with Ints (the non-QQ version)" $ do it "timesTwo" $ property $ \num -> timesTwoInt num `shouldBe` num * 2 it "plusWord" $ property $ \n1 n2 -> plusInt n1 n2 `shouldBe` n1 + n2 it "swap returns a tuple properly" $ property $ \n1 n2 -> swapInts n1 n2 `shouldBe` (n2, n1) describe "Works on Ints" $ do it "timesTwo" $ property $ \num -> timesTwoIntQQ num `shouldBe` num * 2 it "plusWord" $ property $ \n1 n2 -> plusIntQQ n1 n2 `shouldBe` n1 + n2 it "swap returns a tuple properly" $ property $ \n1 n2 -> swap2p1QQ n1 n2 `shouldBe` (n2, n1 + 1) describe "Works on Floats" $ do it "timesTwo" $ property $ \num -> timesTwoFloatQQ num `shouldBe` num * 2 it "plusWord" $ property $ \n1 n2 -> plusFloatQQ n1 n2 `shouldBe` n1 + n2 describe "Works on Doubles" $ do it "timesTwo" $ property $ \num -> timesTwoDoubleQQ num `shouldBe` num * 2 it "plusWord" $ property $ \n1 n2 -> plusDoubleQQ n1 n2 `shouldBe` n1 + n2 describe "Works on Ptrs" $ do it "addPtr" $ property $ \int num -> let ptr = intToPtr int in addPtr ptr num `shouldBe` (ptr `plusPtr` num) it "swap returns a tuple properly" $ property $ \n1 n2 -> let p1 = intToPtr n1 p2 = intToPtr n2 in swapPtrs p1 p2 `shouldBe` (p2, p1) describe "Works on mixed types" $ it "timesTwoEverything" $ property $ \d n f w -> timesTwoEverything d n f w `shouldBe` (d + d, n * 2, f + f, w * 2) intToPtr :: Int -> Ptr a intToPtr = intPtrToPtr . IntPtr