{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
module Limb (
tests
) where
import qualified Data.Choice as C
import qualified Data.Word.Limb as L
import GHC.Exts
import Test.Tasty
import qualified Test.Tasty.HUnit as H
overflowing_add_no_carry :: H.Assertion
overflowing_add_no_carry = do
let !(# r, c #) = L.add_o# (L.Limb 0##) (L.Limb 1##)
H.assertBool mempty (L.eq_vartime# r (L.Limb 1##))
H.assertBool mempty (L.eq_vartime# c (L.Limb 0##))
overflowing_add_with_carry :: H.Assertion
overflowing_add_with_carry = do
let !(# r, c #) = L.add_o# (L.Limb (not# 0##)) (L.Limb 1##)
H.assertBool mempty (L.eq_vartime# r (L.Limb 0##))
H.assertBool mempty (L.eq_vartime# c (L.Limb 1##))
wrapping_add_no_carry :: H.Assertion
wrapping_add_no_carry = do
let !r = L.add_w# (L.Limb 0##) (L.Limb 1##)
H.assertBool mempty (L.eq_vartime# r (L.Limb 1##))
wrapping_add_with_carry :: H.Assertion
wrapping_add_with_carry = do
let !r = L.add_w# (L.Limb (not# 0##)) (L.Limb 1##)
H.assertBool mempty (L.eq_vartime# r (L.Limb 0##))
borrowing_sub_no_borrow :: H.Assertion
borrowing_sub_no_borrow = do
let !(# r, c #) = L.sub_b# (L.Limb 1##) (L.Limb 1##) (L.Limb 0##)
H.assertBool mempty (L.eq_vartime# r (L.Limb 0##))
H.assertBool mempty (L.eq_vartime# c (L.Limb 0##))
borrowing_sub_with_borrow :: H.Assertion
borrowing_sub_with_borrow = do
let !(# r, c #) = L.sub_b# (L.Limb 0##) (L.Limb 1##) (L.Limb 0##)
H.assertBool mempty (L.eq_vartime# r (L.Limb (not# 0##)))
H.assertBool mempty (L.eq_vartime# c (L.Limb (not# 0##)))
wrapping_sub_no_borrow :: H.Assertion
wrapping_sub_no_borrow = do
let !r = L.sub_w# (L.Limb 1##) (L.Limb 1##)
H.assertBool mempty (L.eq_vartime# r (L.Limb 0##))
wrapping_sub_with_borrow :: H.Assertion
wrapping_sub_with_borrow = do
let !r = L.sub_w# (L.Limb 0##) (L.Limb 1##)
H.assertBool mempty (L.eq_vartime# r (L.Limb (not# 0##)))
shl1 :: H.Assertion
shl1 = do
let !r = L.shl# (L.Limb 1##) 1#
H.assertBool mempty (L.eq_vartime# r (L.Limb 2##))
shl2 :: H.Assertion
shl2 = do
let !r = L.shl# (L.Limb 1##) 2#
H.assertBool mempty (L.eq_vartime# r (L.Limb 4##))
shr1 :: H.Assertion
shr1 = do
let !r = L.shr# (L.Limb 2##) 1#
H.assertBool mempty (L.eq_vartime# r (L.Limb 1##))
shr2 :: H.Assertion
shr2 = do
let !r = L.shr# (L.Limb 16##) 2#
H.assertBool mempty (L.eq_vartime# r (L.Limb 4##))
eq :: H.Assertion
eq = do
let !a = L.Limb 0##
!b = L.Limb (not# 0##)
H.assertBool mempty (C.decide (L.eq# a a))
H.assertBool mempty (not (C.decide (L.eq# a b)))
H.assertBool mempty (not (C.decide (L.eq# b a)))
H.assertBool mempty (C.decide (L.eq# b b))
gt :: H.Assertion
gt = do
let !a = L.Limb 0##
!b = L.Limb 1##
!c = L.Limb (not# 0##)
H.assertBool mempty (C.decide (L.gt# b a))
H.assertBool mempty (C.decide (L.gt# c a))
H.assertBool mempty (C.decide (L.gt# c b))
H.assertBool mempty (not (C.decide (L.gt# a a)))
H.assertBool mempty (not (C.decide (L.gt# b b)))
H.assertBool mempty (not (C.decide (L.gt# c c)))
H.assertBool mempty (not (C.decide (L.gt# a b)))
H.assertBool mempty (not (C.decide (L.gt# a c)))
H.assertBool mempty (not (C.decide (L.gt# b c)))
lt :: H.Assertion
lt = do
let !a = L.Limb 0##
!b = L.Limb 1##
!c = L.Limb (not# 0##)
H.assertBool mempty (C.decide (L.lt# a b))
H.assertBool mempty (C.decide (L.lt# a c))
H.assertBool mempty (C.decide (L.lt# b c))
H.assertBool mempty (not (C.decide (L.lt# a a)))
H.assertBool mempty (not (C.decide (L.lt# b b)))
H.assertBool mempty (not (C.decide (L.lt# c c)))
H.assertBool mempty (not (C.decide (L.lt# b a)))
H.assertBool mempty (not (C.decide (L.lt# c a)))
H.assertBool mempty (not (C.decide (L.lt# c b)))
cswap :: H.Assertion
cswap = do
let !a = L.Limb (not# 0##)
!b = L.Limb 0##
!(# a0, b0 #) = L.cswap# a b (C.false# ())
H.assertBool mempty (L.eq_vartime# a0 (L.Limb (not# 0##)))
H.assertBool mempty (L.eq_vartime# b0 (L.Limb 0##))
let !(# a1, b1 #) = L.cswap# a0 b0 (C.true# ())
H.assertBool mempty (L.eq_vartime# a1 (L.Limb 0##))
H.assertBool mempty (L.eq_vartime# b1 (L.Limb (not# 0##)))
tests :: TestTree
tests = testGroup "limb tests" [
H.testCase "overflowing add, no carry" overflowing_add_no_carry
, H.testCase "overflowing add, carry" overflowing_add_with_carry
, H.testCase "wrapping add, no carry" wrapping_add_no_carry
, H.testCase "wrapping add, carry" wrapping_add_with_carry
, H.testCase "borrowing sub, no borrow" borrowing_sub_no_borrow
, H.testCase "borrowing sub, borrow" borrowing_sub_with_borrow
, H.testCase "wrapping sub, no borrow" wrapping_sub_no_borrow
, H.testCase "wrapping sub, borrow" wrapping_sub_with_borrow
, H.testCase "left shift (1)" shl1
, H.testCase "left shift (2)" shl2
, H.testCase "right shift (1)" shr1
, H.testCase "right shift (2)" shr2
, H.testCase "eq" eq
, H.testCase "gt" gt
, H.testCase "lt" lt
, H.testCase "cswap" cswap
]