commit ec82f0f1bb853cd503aa0aa876638244e0ee75e6
parent 781e4bd7d82c528385b43f7895efa517e27419a5
Author: Jared Tobin <jared@jtobin.io>
Date: Sun, 30 Nov 2025 10:41:43 +0400
limb: even further refinement
Diffstat:
| M | lib/Data/Word/Limb.hs | | | 110 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- |
1 file changed, 105 insertions(+), 5 deletions(-)
diff --git a/lib/Data/Word/Limb.hs b/lib/Data/Word/Limb.hs
@@ -17,10 +17,23 @@ module Data.Word.Limb (
, not#
, xor#
, bits#
+ , shl#
+ , shl1#
+ , shr#
+ , shr1#
-- * Comparison
+ , eq#
+ , ne#
+ , nonzero#
- , ct_eq#
+ -- * Selection
+ , select#
+ , cswap#
+
+ -- * Negation
+
+ , neg#
-- * Arithmetic
, add_o#
@@ -44,20 +57,60 @@ import qualified Data.Choice as C
import GHC.Exts (Word#)
import qualified GHC.Exts as Exts
+-- | A 'Limb' is the smallest component of a wider word.
newtype Limb = Limb Word#
+-- | Return a 'Limb' value as a 'String'.
render :: Limb -> String
render (Limb a) = show (Exts.W# a)
-- comparison -----------------------------------------------------------------
--- | Constant-time equality comparison.
-ct_eq#
+-- | Equality comparison.
+eq#
+ :: Limb
+ -> Limb
+ -> C.Choice
+eq# (Limb a) (Limb b) = C.ct_eq_word# a b
+{-# INLINE eq# #-}
+
+-- | Inequality comparison.
+ne#
:: Limb
-> Limb
-> C.Choice
-ct_eq# (Limb a) (Limb b) = C.ct_eq_word# a b
-{-# INLINE ct_eq# #-}
+ne# a b = C.not_c# (eq# a b)
+{-# INLINE ne# #-}
+
+-- | Comparison to zero.
+nonzero#
+ :: Limb
+ -> C.Choice
+nonzero# (Limb a) = C.from_word_nonzero# a
+{-# INLINE nonzero# #-}
+
+-- selection ------------------------------------------------------------------
+
+-- | Return a if c is truthy, otherwise return b.
+select#
+ :: Limb -- ^ a
+ -> Limb -- ^ b
+ -> C.Choice -- ^ c
+ -> Limb -- ^ result
+select# (Limb a) (Limb b) c = Limb (C.ct_select_word# a b c)
+{-# INLINE select# #-}
+
+-- | Return (# b, a #) if c is truthy, otherwise return (# a, b #).
+cswap#
+ :: Limb -- ^ a
+ -> Limb -- ^ b
+ -> C.Choice -- ^ c
+ -> (# Limb, Limb #) -- ^ result
+cswap# (Limb a) (Limb b) c =
+ let !l = C.ct_select_word# a b c
+ !r = C.ct_select_word# b a c
+ in (# Limb l, Limb r #)
+{-# INLINE cswap# #-}
-- bit manipulation -----------------------------------------------------------
@@ -102,6 +155,53 @@ bits# (Limb a) =
in _BITS - zs -- XX unbox?
{-# INLINE bits# #-}
+-- | Bit-shift left.
+shl#
+ :: Limb -- ^ limb
+ -> Exts.Int# -- ^ shift amount
+ -> Limb -- ^ result
+shl# (Limb w) s = Limb (Exts.uncheckedShiftL# w s)
+{-# INLINE shl# #-}
+
+-- | Bit-shift left by 1, returning the result and carry.
+shl1#
+ :: Limb
+ -> (# Limb, Limb #)
+shl1# (Limb w) =
+ let !s = case B.finiteBitSize (0 :: Word) of Exts.I# m -> m Exts.-# 1#
+ !r = Exts.uncheckedShiftL# w 1#
+ !c = Exts.uncheckedShiftRL# w s
+ in (# Limb r, Limb c #)
+{-# INLINE shl1# #-}
+
+-- | Bit-shift right.
+shr#
+ :: Limb -- ^ limb
+ -> Exts.Int# -- ^ shift amount
+ -> Limb -- ^ result
+shr# (Limb w) s = Limb (Exts.uncheckedShiftRL# w s)
+{-# INLINE shr# #-}
+
+-- | Bit-shift right by 1, returning the result and carry.
+shr1#
+ :: Limb
+ -> (# Limb, Limb #)
+shr1# (Limb w) =
+ let !s = case B.finiteBitSize (0 :: Word) of Exts.I# m -> m Exts.-# 1#
+ !r = Exts.uncheckedShiftRL# w 1#
+ !c = Exts.uncheckedShiftL# w s
+ in (# Limb r, Limb c #)
+{-# INLINE shr1# #-}
+
+-- negation -------------------------------------------------------------------
+
+-- | Wrapping (two's complement) negation.
+neg#
+ :: Limb
+ -> Limb
+neg# (Limb x) = Limb (Exts.plusWord# (Exts.not# x) 1##)
+{-# INLINE neg# #-}
+
-- addition -------------------------------------------------------------------
-- | Overflowing addition, computing augend + addend, returning the