packages feed

bv-sized 0.7.0 → 1.0.0

raw patch · 13 files changed

+1890/−1185 lines, 13 filesdep +bitwisedep +bytestringdep +hedgehogdep −QuickCheckdep −containersdep −lensdep ~basedep ~parameterized-utilsPVP ok

version bump matches the API change (PVP)

Dependencies added: bitwise, bytestring, hedgehog, panic, tasty, tasty-hedgehog, th-lift

Dependencies removed: QuickCheck, containers, lens, mtl, pretty, random

Dependency ranges changed: base, parameterized-utils

API changes (from Hackage documentation)

- Data.BitVector.Sized: (<:>) :: BitVector v -> BitVector w -> BitVector (v + w)
- Data.BitVector.Sized: bitVector :: (Integral a, KnownNat w) => a -> BitVector w
- Data.BitVector.Sized: bitVector' :: Integral a => NatRepr w -> a -> BitVector w
- Data.BitVector.Sized: bv0 :: BitVector 0
- Data.BitVector.Sized: bvAbs :: BitVector w -> BitVector w
- Data.BitVector.Sized: bvAdd :: BitVector w -> BitVector w -> BitVector w
- Data.BitVector.Sized: bvAnd :: BitVector w -> BitVector w -> BitVector w
- Data.BitVector.Sized: bvComplement :: BitVector w -> BitVector w
- Data.BitVector.Sized: bvConcat :: BitVector v -> BitVector w -> BitVector (v + w)
- Data.BitVector.Sized: bvConcatMany :: KnownNat w' => [BitVector w] -> BitVector w'
- Data.BitVector.Sized: bvConcatMany' :: NatRepr w' -> [BitVector w] -> BitVector w'
- Data.BitVector.Sized: bvExtract :: forall w w'. KnownNat w' => Int -> BitVector w -> BitVector w'
- Data.BitVector.Sized: bvExtract' :: NatRepr w' -> Int -> BitVector w -> BitVector w'
- Data.BitVector.Sized: bvGetBytesU :: Int -> BitVector w -> [BitVector 8]
- Data.BitVector.Sized: bvIntegerS :: BitVector w -> Integer
- Data.BitVector.Sized: bvIntegerU :: BitVector w -> Integer
- Data.BitVector.Sized: bvLTS :: BitVector w -> BitVector w -> Bool
- Data.BitVector.Sized: bvLTU :: BitVector w -> BitVector w -> Bool
- Data.BitVector.Sized: bvMul :: BitVector w -> BitVector w -> BitVector w
- Data.BitVector.Sized: bvNegate :: BitVector w -> BitVector w
- Data.BitVector.Sized: bvOr :: BitVector w -> BitVector w -> BitVector w
- Data.BitVector.Sized: bvPopCount :: BitVector w -> Int
- Data.BitVector.Sized: bvQuotS :: BitVector w -> BitVector w -> BitVector w
- Data.BitVector.Sized: bvQuotU :: BitVector w -> BitVector w -> BitVector w
- Data.BitVector.Sized: bvRemS :: BitVector w -> BitVector w -> BitVector w
- Data.BitVector.Sized: bvRemU :: BitVector w -> BitVector w -> BitVector w
- Data.BitVector.Sized: bvRotate :: BitVector w -> Int -> BitVector w
- Data.BitVector.Sized: bvSext :: forall w w'. KnownNat w' => BitVector w -> BitVector w'
- Data.BitVector.Sized: bvSext' :: NatRepr w' -> BitVector w -> BitVector w'
- Data.BitVector.Sized: bvShift :: BitVector w -> Int -> BitVector w
- Data.BitVector.Sized: bvShiftL :: BitVector w -> Int -> BitVector w
- Data.BitVector.Sized: bvShiftRA :: BitVector w -> Int -> BitVector w
- Data.BitVector.Sized: bvShiftRL :: BitVector w -> Int -> BitVector w
- Data.BitVector.Sized: bvSignum :: BitVector w -> BitVector w
- Data.BitVector.Sized: bvTestBit :: BitVector w -> Int -> Bool
- Data.BitVector.Sized: bvTruncBits :: BitVector w -> Int -> BitVector w
- Data.BitVector.Sized: bvWidth :: BitVector w -> Int
- Data.BitVector.Sized: bvXor :: BitVector w -> BitVector w -> BitVector w
- Data.BitVector.Sized: bvZext :: forall w w'. KnownNat w' => BitVector w -> BitVector w'
- Data.BitVector.Sized: bvZext' :: NatRepr w' -> BitVector w -> BitVector w'
- Data.BitVector.Sized: data BitVector (w :: Nat) :: *
- Data.BitVector.Sized: infixl 6 <:>
- Data.BitVector.Sized: pattern BitVector :: NatRepr w -> Integer -> BitVector w
- Data.BitVector.Sized.App: [AbsApp] :: !NatRepr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [AddApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [AndApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [ConcatApp] :: !NatRepr (w + w') -> !expr w -> !expr w' -> BVApp expr (w + w')
- Data.BitVector.Sized.App: [EqApp] :: !expr w -> !expr w -> BVApp expr 1
- Data.BitVector.Sized.App: [ExtractApp] :: NatRepr w' -> NatRepr ix -> !expr w -> BVApp expr w'
- Data.BitVector.Sized.App: [IteApp] :: !NatRepr w -> !expr 1 -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [LtsApp] :: !expr w -> !expr w -> BVApp expr 1
- Data.BitVector.Sized.App: [LtuApp] :: !expr w -> !expr w -> BVApp expr 1
- Data.BitVector.Sized.App: [MulApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [NegateApp] :: !NatRepr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [NotApp] :: !NatRepr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [OrApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [QuotSApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [QuotUApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [RemSApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [RemUApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [SExtApp] :: NatRepr w' -> !expr w -> BVApp expr w'
- Data.BitVector.Sized.App: [SignumApp] :: !NatRepr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [SllApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [SraApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [SrlApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [SubApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [XorApp] :: !NatRepr w -> !expr w -> !expr w -> BVApp expr w
- Data.BitVector.Sized.App: [ZExtApp] :: NatRepr w' -> !expr w -> BVApp expr w'
- Data.BitVector.Sized.App: absE :: BVExpr expr => expr w -> expr w
- Data.BitVector.Sized.App: addE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: andE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: appExpr :: BVExpr expr => BVApp expr w -> expr w
- Data.BitVector.Sized.App: bvAppWidth :: BVApp expr w -> NatRepr w
- Data.BitVector.Sized.App: class BVExpr (expr :: Nat -> *)
- Data.BitVector.Sized.App: concatE :: BVExpr expr => expr w -> expr w' -> expr (w + w')
- Data.BitVector.Sized.App: data BVApp (expr :: Nat -> *) (w :: Nat)
- Data.BitVector.Sized.App: eqE :: BVExpr expr => expr w -> expr w -> expr 1
- Data.BitVector.Sized.App: evalBVApp :: (forall w'. expr w' -> BitVector w') -> BVApp expr w -> BitVector w
- Data.BitVector.Sized.App: evalBVAppM :: Monad m => (forall w'. expr w' -> m (BitVector w')) -> BVApp expr w -> m (BitVector w)
- Data.BitVector.Sized.App: exprWidth :: BVExpr expr => expr w -> NatRepr w
- Data.BitVector.Sized.App: extractE :: (BVExpr expr, KnownNat w') => NatRepr ix -> expr w -> expr w'
- Data.BitVector.Sized.App: extractE' :: BVExpr expr => NatRepr w' -> NatRepr ix -> expr w -> expr w'
- Data.BitVector.Sized.App: instance Data.Parameterized.Classes.OrdF expr => Data.Parameterized.Classes.OrdF (Data.BitVector.Sized.App.BVApp expr)
- Data.BitVector.Sized.App: instance Data.Parameterized.Classes.OrdF expr => GHC.Classes.Ord (Data.BitVector.Sized.App.BVApp expr w)
- Data.BitVector.Sized.App: instance Data.Parameterized.TraversableFC.FoldableFC Data.BitVector.Sized.App.BVApp
- Data.BitVector.Sized.App: instance Data.Parameterized.TraversableFC.FunctorFC Data.BitVector.Sized.App.BVApp
- Data.BitVector.Sized.App: instance Data.Parameterized.TraversableFC.TraversableFC Data.BitVector.Sized.App.BVApp
- Data.BitVector.Sized.App: instance Data.Type.Equality.TestEquality expr => Data.Parameterized.Classes.EqF (Data.BitVector.Sized.App.BVApp expr)
- Data.BitVector.Sized.App: instance Data.Type.Equality.TestEquality expr => Data.Type.Equality.TestEquality (Data.BitVector.Sized.App.BVApp expr)
- Data.BitVector.Sized.App: instance Data.Type.Equality.TestEquality expr => GHC.Classes.Eq (Data.BitVector.Sized.App.BVApp expr w)
- Data.BitVector.Sized.App: iteE :: BVExpr expr => expr 1 -> expr w -> expr w -> expr w
- Data.BitVector.Sized.App: litBV :: BVExpr expr => BitVector w -> expr w
- Data.BitVector.Sized.App: ltsE :: BVExpr expr => expr w -> expr w -> expr 1
- Data.BitVector.Sized.App: ltuE :: BVExpr expr => expr w -> expr w -> expr 1
- Data.BitVector.Sized.App: mulE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: negateE :: BVExpr expr => expr w -> expr w
- Data.BitVector.Sized.App: notE :: BVExpr expr => expr w -> expr w
- Data.BitVector.Sized.App: orE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: quotsE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: quotuE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: remsE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: remuE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: sextE :: (BVExpr expr, KnownNat w') => expr w -> expr w'
- Data.BitVector.Sized.App: sextE' :: BVExpr expr => NatRepr w' -> expr w -> expr w'
- Data.BitVector.Sized.App: signumE :: BVExpr expr => expr w -> expr w
- Data.BitVector.Sized.App: sllE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: sraE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: srlE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: subE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: xorE :: BVExpr expr => expr w -> expr w -> expr w
- Data.BitVector.Sized.App: zextE :: (BVExpr expr, KnownNat w') => expr w -> expr w'
- Data.BitVector.Sized.App: zextE' :: BVExpr expr => NatRepr w' -> expr w -> expr w'
- Data.BitVector.Sized.BitLayout: (<:) :: Chunk r -> BitLayout t s -> BitLayout t (r + s)
- Data.BitVector.Sized.BitLayout: [Chunk] :: NatRepr w -> Int -> Chunk w
- Data.BitVector.Sized.BitLayout: bitLayoutAssignmentList :: BitLayout t s -> [Int]
- Data.BitVector.Sized.BitLayout: chunk :: KnownNat w => Int -> Chunk w
- Data.BitVector.Sized.BitLayout: data BitLayout (t :: Nat) (s :: Nat) :: *
- Data.BitVector.Sized.BitLayout: data Chunk (w :: Nat) :: *
- Data.BitVector.Sized.BitLayout: empty :: KnownNat t => BitLayout t 0
- Data.BitVector.Sized.BitLayout: extract :: BitLayout t s -> BitVector t -> BitVector s
- Data.BitVector.Sized.BitLayout: infixr 6 <:
- Data.BitVector.Sized.BitLayout: inject :: BitLayout t s -> BitVector t -> BitVector s -> BitVector t
- Data.BitVector.Sized.BitLayout: instance Data.Parameterized.Classes.ShowF Data.BitVector.Sized.BitLayout.Chunk
- Data.BitVector.Sized.BitLayout: instance GHC.Show.Show (Data.BitVector.Sized.BitLayout.BitLayout t s)
- Data.BitVector.Sized.BitLayout: instance GHC.Show.Show (Data.BitVector.Sized.BitLayout.Chunk w)
- Data.BitVector.Sized.BitLayout: instance Text.PrettyPrint.HughesPJClass.Pretty (Data.BitVector.Sized.BitLayout.BitLayout t s)
- Data.BitVector.Sized.BitLayout: instance Text.PrettyPrint.HughesPJClass.Pretty (Data.BitVector.Sized.BitLayout.Chunk w)
- Data.BitVector.Sized.BitLayout: instance Text.PrettyPrint.HughesPJClass.Pretty (Data.Parameterized.Some.Some Data.BitVector.Sized.BitLayout.Chunk)
- Data.BitVector.Sized.BitLayout: layoutLens :: BitLayout t s -> Simple Lens (BitVector t) (BitVector s)
- Data.BitVector.Sized.BitLayout: layoutsLens :: forall ws. List (BitLayout 32) ws -> Simple Lens (BitVector 32) (List BitVector ws)
- Data.BitVector.Sized.BitLayout: singleChunk :: (KnownNat w, KnownNat w') => Int -> BitLayout w w'
+ Data.BitVector.Sized: abs :: 1 <= w => NatRepr w -> BV w -> BV w
+ Data.BitVector.Sized: add :: NatRepr w -> BV w -> BV w -> BV w
+ Data.BitVector.Sized: and :: BV w -> BV w -> BV w
+ Data.BitVector.Sized: asBitsBE :: NatRepr w -> BV w -> [Bool]
+ Data.BitVector.Sized: asBitsLE :: NatRepr w -> BV w -> [Bool]
+ Data.BitVector.Sized: asBytesBE :: NatRepr w -> BV w -> Maybe [Word8]
+ Data.BitVector.Sized: asBytesLE :: NatRepr w -> BV w -> Maybe [Word8]
+ Data.BitVector.Sized: asBytestringBE :: NatRepr w -> BV w -> Maybe ByteString
+ Data.BitVector.Sized: asBytestringLE :: NatRepr w -> BV w -> Maybe ByteString
+ Data.BitVector.Sized: asNatural :: BV w -> Natural
+ Data.BitVector.Sized: asSigned :: 1 <= w => NatRepr w -> BV w -> Integer
+ Data.BitVector.Sized: asUnsigned :: BV w -> Integer
+ Data.BitVector.Sized: ashr :: 1 <= w => NatRepr w -> BV w -> Natural -> BV w
+ Data.BitVector.Sized: bit :: (ix + 1) <= w => NatRepr w -> NatRepr ix -> BV w
+ Data.BitVector.Sized: bit' :: NatRepr w -> Natural -> BV w
+ Data.BitVector.Sized: bitsBE :: [Bool] -> Pair NatRepr BV
+ Data.BitVector.Sized: bitsLE :: [Bool] -> Pair NatRepr BV
+ Data.BitVector.Sized: bool :: Bool -> BV 1
+ Data.BitVector.Sized: bytesBE :: [Word8] -> Pair NatRepr BV
+ Data.BitVector.Sized: bytesLE :: [Word8] -> Pair NatRepr BV
+ Data.BitVector.Sized: bytestringBE :: ByteString -> Pair NatRepr BV
+ Data.BitVector.Sized: bytestringLE :: ByteString -> Pair NatRepr BV
+ Data.BitVector.Sized: clearBit :: (ix + 1) <= w => NatRepr w -> NatRepr ix -> BV w -> BV w
+ Data.BitVector.Sized: clearBit' :: NatRepr w -> Natural -> BV w -> BV w
+ Data.BitVector.Sized: clz :: NatRepr w -> BV w -> BV w
+ Data.BitVector.Sized: complement :: NatRepr w -> BV w -> BV w
+ Data.BitVector.Sized: complementBit :: (ix + 1) <= w => NatRepr ix -> BV w -> BV w
+ Data.BitVector.Sized: complementBit' :: NatRepr w -> Natural -> BV w -> BV w
+ Data.BitVector.Sized: concat :: NatRepr w -> NatRepr w' -> BV w -> BV w' -> BV (w + w')
+ Data.BitVector.Sized: ctz :: NatRepr w -> BV w -> BV w
+ Data.BitVector.Sized: data BV (w :: Nat) :: Type
+ Data.BitVector.Sized: data NatRepr (n :: Nat)
+ Data.BitVector.Sized: enumFromToSigned :: 1 <= w => NatRepr w -> BV w -> BV w -> [BV w]
+ Data.BitVector.Sized: enumFromToUnsigned :: BV w -> BV w -> [BV w]
+ Data.BitVector.Sized: int16 :: Int16 -> BV 16
+ Data.BitVector.Sized: int32 :: Int32 -> BV 32
+ Data.BitVector.Sized: int64 :: Int64 -> BV 64
+ Data.BitVector.Sized: int8 :: Int8 -> BV 8
+ Data.BitVector.Sized: knownNat :: KnownNat n => NatRepr n
+ Data.BitVector.Sized: lshr :: NatRepr w -> BV w -> Natural -> BV w
+ Data.BitVector.Sized: maxSigned :: 1 <= w => NatRepr w -> BV w
+ Data.BitVector.Sized: maxUnsigned :: NatRepr w -> BV w
+ Data.BitVector.Sized: minSigned :: 1 <= w => NatRepr w -> BV w
+ Data.BitVector.Sized: minUnsigned :: NatRepr w -> BV w
+ Data.BitVector.Sized: mkBV :: NatRepr w -> Integer -> BV w
+ Data.BitVector.Sized: mkBVSigned :: 1 <= w => NatRepr w -> Integer -> Maybe (BV w)
+ Data.BitVector.Sized: mkBVUnsigned :: NatRepr w -> Integer -> Maybe (BV w)
+ Data.BitVector.Sized: mul :: NatRepr w -> BV w -> BV w -> BV w
+ Data.BitVector.Sized: mulWide :: NatRepr w -> NatRepr w' -> BV w -> BV w' -> BV (w + w')
+ Data.BitVector.Sized: negate :: NatRepr w -> BV w -> BV w
+ Data.BitVector.Sized: one :: 1 <= w => NatRepr w -> BV w
+ Data.BitVector.Sized: or :: BV w -> BV w -> BV w
+ Data.BitVector.Sized: pattern BV :: Integer -> BV w
+ Data.BitVector.Sized: popCount :: BV w -> BV w
+ Data.BitVector.Sized: ppBin :: NatRepr w -> BV w -> String
+ Data.BitVector.Sized: ppDec :: NatRepr w -> BV w -> String
+ Data.BitVector.Sized: ppHex :: NatRepr w -> BV w -> String
+ Data.BitVector.Sized: ppOct :: NatRepr w -> BV w -> String
+ Data.BitVector.Sized: predSigned :: 1 <= w => NatRepr w -> BV w -> Maybe (BV w)
+ Data.BitVector.Sized: predUnsigned :: NatRepr w -> BV w -> Maybe (BV w)
+ Data.BitVector.Sized: rotateL :: NatRepr w -> BV w -> Natural -> BV w
+ Data.BitVector.Sized: rotateR :: NatRepr w -> BV w -> Natural -> BV w
+ Data.BitVector.Sized: sdiv :: 1 <= w => NatRepr w -> BV w -> BV w -> BV w
+ Data.BitVector.Sized: sdivMod :: 1 <= w => NatRepr w -> BV w -> BV w -> (BV w, BV w)
+ Data.BitVector.Sized: select :: (ix + w') <= w => NatRepr ix -> NatRepr w' -> BV w -> BV w'
+ Data.BitVector.Sized: select' :: Natural -> NatRepr w' -> BV w -> BV w'
+ Data.BitVector.Sized: setBit :: (ix + 1) <= w => NatRepr ix -> BV w -> BV w
+ Data.BitVector.Sized: setBit' :: NatRepr w -> Natural -> BV w -> BV w
+ Data.BitVector.Sized: sext :: (1 <= w, (w + 1) <= w') => NatRepr w -> NatRepr w' -> BV w -> BV w'
+ Data.BitVector.Sized: shl :: NatRepr w -> BV w -> Natural -> BV w
+ Data.BitVector.Sized: signBit :: 1 <= w => NatRepr w -> BV w -> BV w
+ Data.BitVector.Sized: signedClamp :: 1 <= w => NatRepr w -> Integer -> BV w
+ Data.BitVector.Sized: signum :: 1 <= w => NatRepr w -> BV w -> BV w
+ Data.BitVector.Sized: sle :: 1 <= w => NatRepr w -> BV w -> BV w -> Bool
+ Data.BitVector.Sized: slt :: 1 <= w => NatRepr w -> BV w -> BV w -> Bool
+ Data.BitVector.Sized: smax :: 1 <= w => NatRepr w -> BV w -> BV w -> BV w
+ Data.BitVector.Sized: smin :: 1 <= w => NatRepr w -> BV w -> BV w -> BV w
+ Data.BitVector.Sized: smod :: 1 <= w => NatRepr w -> BV w -> BV w -> BV w
+ Data.BitVector.Sized: squot :: 1 <= w => NatRepr w -> BV w -> BV w -> BV w
+ Data.BitVector.Sized: squotRem :: 1 <= w => NatRepr w -> BV w -> BV w -> (BV w, BV w)
+ Data.BitVector.Sized: srem :: 1 <= w => NatRepr w -> BV w -> BV w -> BV w
+ Data.BitVector.Sized: sub :: NatRepr w -> BV w -> BV w -> BV w
+ Data.BitVector.Sized: succSigned :: 1 <= w => NatRepr w -> BV w -> Maybe (BV w)
+ Data.BitVector.Sized: succUnsigned :: NatRepr w -> BV w -> Maybe (BV w)
+ Data.BitVector.Sized: testBit :: (ix + 1) <= w => NatRepr ix -> BV w -> Bool
+ Data.BitVector.Sized: testBit' :: Natural -> BV w -> Bool
+ Data.BitVector.Sized: trunc :: (w' + 1) <= w => NatRepr w' -> BV w -> BV w'
+ Data.BitVector.Sized: trunc' :: NatRepr w' -> BV w -> BV w'
+ Data.BitVector.Sized: truncBits :: Natural -> BV w -> BV w
+ Data.BitVector.Sized: ule :: BV w -> BV w -> Bool
+ Data.BitVector.Sized: ult :: BV w -> BV w -> Bool
+ Data.BitVector.Sized: umax :: BV w -> BV w -> BV w
+ Data.BitVector.Sized: umin :: BV w -> BV w -> BV w
+ Data.BitVector.Sized: unsignedClamp :: NatRepr w -> Integer -> BV w
+ Data.BitVector.Sized: uquot :: BV w -> BV w -> BV w
+ Data.BitVector.Sized: uquotRem :: BV w -> BV w -> (BV w, BV w)
+ Data.BitVector.Sized: urem :: BV w -> BV w -> BV w
+ Data.BitVector.Sized: width :: NatRepr w -> BV w
+ Data.BitVector.Sized: word16 :: Word16 -> BV 16
+ Data.BitVector.Sized: word32 :: Word32 -> BV 32
+ Data.BitVector.Sized: word64 :: Word64 -> BV 64
+ Data.BitVector.Sized: word8 :: Word8 -> BV 8
+ Data.BitVector.Sized: xor :: BV w -> BV w -> BV w
+ Data.BitVector.Sized: zero :: NatRepr w -> BV w
+ Data.BitVector.Sized: zext :: (w + 1) <= w' => NatRepr w' -> BV w -> BV w'
+ Data.BitVector.Sized.Overflow: NoSignedOverflow :: SignedOverflow
+ Data.BitVector.Sized.Overflow: NoUnsignedOverflow :: UnsignedOverflow
+ Data.BitVector.Sized.Overflow: Overflow :: UnsignedOverflow -> SignedOverflow -> a -> Overflow a
+ Data.BitVector.Sized.Overflow: SignedOverflow :: SignedOverflow
+ Data.BitVector.Sized.Overflow: UnsignedOverflow :: UnsignedOverflow
+ Data.BitVector.Sized.Overflow: addOf :: 1 <= w => NatRepr w -> BV w -> BV w -> Overflow (BV w)
+ Data.BitVector.Sized.Overflow: data Overflow a
+ Data.BitVector.Sized.Overflow: data SignedOverflow
+ Data.BitVector.Sized.Overflow: data UnsignedOverflow
+ Data.BitVector.Sized.Overflow: instance Data.Foldable.Foldable Data.BitVector.Sized.Overflow.Overflow
+ Data.BitVector.Sized.Overflow: instance Data.Traversable.Traversable Data.BitVector.Sized.Overflow.Overflow
+ Data.BitVector.Sized.Overflow: instance GHC.Base.Applicative Data.BitVector.Sized.Overflow.Overflow
+ Data.BitVector.Sized.Overflow: instance GHC.Base.Functor Data.BitVector.Sized.Overflow.Overflow
+ Data.BitVector.Sized.Overflow: instance GHC.Base.Monad Data.BitVector.Sized.Overflow.Overflow
+ Data.BitVector.Sized.Overflow: instance GHC.Base.Monoid Data.BitVector.Sized.Overflow.SignedOverflow
+ Data.BitVector.Sized.Overflow: instance GHC.Base.Monoid Data.BitVector.Sized.Overflow.UnsignedOverflow
+ Data.BitVector.Sized.Overflow: instance GHC.Base.Semigroup Data.BitVector.Sized.Overflow.SignedOverflow
+ Data.BitVector.Sized.Overflow: instance GHC.Base.Semigroup Data.BitVector.Sized.Overflow.UnsignedOverflow
+ Data.BitVector.Sized.Overflow: instance GHC.Classes.Eq Data.BitVector.Sized.Overflow.SignedOverflow
+ Data.BitVector.Sized.Overflow: instance GHC.Classes.Eq Data.BitVector.Sized.Overflow.UnsignedOverflow
+ Data.BitVector.Sized.Overflow: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.BitVector.Sized.Overflow.Overflow a)
+ Data.BitVector.Sized.Overflow: instance GHC.Show.Show Data.BitVector.Sized.Overflow.SignedOverflow
+ Data.BitVector.Sized.Overflow: instance GHC.Show.Show Data.BitVector.Sized.Overflow.UnsignedOverflow
+ Data.BitVector.Sized.Overflow: instance GHC.Show.Show a => GHC.Show.Show (Data.BitVector.Sized.Overflow.Overflow a)
+ Data.BitVector.Sized.Overflow: mulOf :: 1 <= w => NatRepr w -> BV w -> BV w -> Overflow (BV w)
+ Data.BitVector.Sized.Overflow: ofResult :: Overflow a -> a
+ Data.BitVector.Sized.Overflow: ofSigned :: Overflow a -> Bool
+ Data.BitVector.Sized.Overflow: ofUnsigned :: Overflow a -> Bool
+ Data.BitVector.Sized.Overflow: sdivOf :: 1 <= w => NatRepr w -> BV w -> BV w -> Overflow (BV w)
+ Data.BitVector.Sized.Overflow: shlOf :: 1 <= w => NatRepr w -> BV w -> Natural -> Overflow (BV w)
+ Data.BitVector.Sized.Overflow: smodOf :: 1 <= w => NatRepr w -> BV w -> BV w -> Overflow (BV w)
+ Data.BitVector.Sized.Overflow: squotOf :: 1 <= w => NatRepr w -> BV w -> BV w -> Overflow (BV w)
+ Data.BitVector.Sized.Overflow: sremOf :: 1 <= w => NatRepr w -> BV w -> BV w -> Overflow (BV w)
+ Data.BitVector.Sized.Overflow: subOf :: 1 <= w => NatRepr w -> BV w -> BV w -> Overflow (BV w)
+ Data.BitVector.Sized.Signed: SignedBV :: BV w -> SignedBV w
+ Data.BitVector.Sized.Signed: instance (GHC.TypeNats.KnownNat w, 1 GHC.TypeNats.<= w) => Data.Bits.Bits (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: instance (GHC.TypeNats.KnownNat w, 1 GHC.TypeNats.<= w) => Data.Bits.FiniteBits (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: instance (GHC.TypeNats.KnownNat w, 1 GHC.TypeNats.<= w) => GHC.Arr.Ix (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: instance (GHC.TypeNats.KnownNat w, 1 GHC.TypeNats.<= w) => GHC.Classes.Ord (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: instance (GHC.TypeNats.KnownNat w, 1 GHC.TypeNats.<= w) => GHC.Enum.Bounded (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: instance (GHC.TypeNats.KnownNat w, 1 GHC.TypeNats.<= w) => GHC.Enum.Enum (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: instance (GHC.TypeNats.KnownNat w, 1 GHC.TypeNats.<= w) => GHC.Num.Num (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: instance GHC.Classes.Eq (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: instance GHC.Generics.Generic (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: instance GHC.Read.Read (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: instance GHC.Show.Show (Data.BitVector.Sized.Signed.SignedBV w)
+ Data.BitVector.Sized.Signed: mkSignedBV :: NatRepr w -> Integer -> SignedBV w
+ Data.BitVector.Sized.Signed: newtype SignedBV w
+ Data.BitVector.Sized.Unsigned: UnsignedBV :: BV w -> UnsignedBV w
+ Data.BitVector.Sized.Unsigned: [asBV] :: UnsignedBV w -> BV w
+ Data.BitVector.Sized.Unsigned: instance GHC.Classes.Eq (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: instance GHC.Classes.Ord (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: instance GHC.Generics.Generic (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: instance GHC.Read.Read (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: instance GHC.Show.Show (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: instance GHC.TypeNats.KnownNat w => Data.Bits.Bits (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: instance GHC.TypeNats.KnownNat w => Data.Bits.FiniteBits (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: instance GHC.TypeNats.KnownNat w => GHC.Arr.Ix (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: instance GHC.TypeNats.KnownNat w => GHC.Enum.Bounded (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: instance GHC.TypeNats.KnownNat w => GHC.Enum.Enum (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: instance GHC.TypeNats.KnownNat w => GHC.Num.Num (Data.BitVector.Sized.Unsigned.UnsignedBV w)
+ Data.BitVector.Sized.Unsigned: mkUnsignedBV :: NatRepr w -> Integer -> UnsignedBV w
+ Data.BitVector.Sized.Unsigned: newtype UnsignedBV w

Files

README.md view
@@ -1,39 +1,12 @@+[![Build Status](https://travis-ci.org/GaloisInc/bv-sized.svg?branch=master)](https://travis-ci.org/GaloisInc/bv-sized)+ bv-sized - A Haskell library for manipulating width-parameterized bitvectors ===  copyright (c) Ben Selfridge, Galois Inc. 2018 -This library defines a `BitVector` datatype that is parameterized by the vector-width.--Requirements-===--The following are a list of mandatory and secondary requirements for bv-sized.--Mandatory Requirements-===--- Must support integer arithmetic on bitvectors of arbitrary width, assuming a-  two's-complement representation.--- Must support the construction of symbolic expressions involving bitvectors,-  and evaluating those expressions in such a way that the "pure" bitvector-  expression language can be embedded in a larger expression language. (See-  Data.BitVector.Sized.App)--- Declarative descriptions of bit encodings within an instruction word for the-  purposes of ISA definitions and the like. (See Data.BitVector.Sized.BitLayout)--Secondary Requirements-===--None.--Current Status-===--The library is relatively stable and supports all the above requirements.+This library defines a bitvector datatype that is parameterized by the+vector width.  Other information ===
bv-sized.cabal view
@@ -1,5 +1,5 @@ name:                bv-sized-version:             0.7.0+version:             1.0.0 category:            Bit Vectors synopsis:            a BitVector datatype that is parameterized by the vector width description:@@ -16,34 +16,37 @@ cabal-version:       >=1.10 extra-source-files:  README.md +source-repository head+  type:     git+  location: https://github.com/GaloisInc/bv-sized+ library   exposed-modules:     Data.BitVector.Sized-                     , Data.BitVector.Sized.App-                     , Data.BitVector.Sized.BitLayout+                       Data.BitVector.Sized.Signed+                       Data.BitVector.Sized.Unsigned+                       Data.BitVector.Sized.Overflow   other-modules:       Data.BitVector.Sized.Internal-  build-depends:       base >= 4.7 && < 5-                     , containers >= 0.5.10 && < 0.7-                     , lens >= 4 && < 5-                     , mtl >= 2 && < 3-                     , parameterized-utils >= 2.0 && < 3-                     , pretty-                     , random >= 1.1 && < 1.2-                     , QuickCheck >= 2.11 && < 2.12+                       Data.BitVector.Sized.Panic+  build-depends:       base >= 4.10 && <5,+                       bitwise >= 1.0.0 && < 1.1,+                       bytestring >= 0.10.10 && < 0.11,+                       panic >= 0.4.0 && < 0.5,+                       parameterized-utils >= 2.0.2 && < 2.1,+                       th-lift >= 0.8.1 && < 0.9   hs-source-dirs:      src   default-language:    Haskell2010   ghc-options:         -Wall -test-suite bv-tests-  type: exitcode-stdio-1.0-  default-language: Haskell2010-  ghc-options: -Wall-  main-is: Test.hs-  other-modules:       Data.BitVector.Sized-  hs-source-dirs: test, src-  build-depends:       base >= 4.7 && < 5-                     , bv-sized-                     , lens >= 4 && < 5-                     , parameterized-utils-                     , pretty-                     , random >= 1.1 && < 1.2-                     , QuickCheck >= 2.11 && < 2.12+test-suite bv-sized-tests+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Main.hs+  build-depends:       base >= 4.7 && < 5,+                       bv-sized,+                       bytestring >= 0.10.10 && < 0.11,+                       hedgehog >= 1.0.2 && < 1.1,+                       parameterized-utils >= 2.0.2 && < 2.1,+                       tasty >= 1.2.3 && < 1.3,+                       tasty-hedgehog >= 1.0.0.2 && < 1.1+  default-language:    Haskell2010+  ghc-options:         -Wall -Wcompat
changelog.md view
@@ -1,10 +1,37 @@ # Changelog for [`bv-sized` package](http://hackage.haskell.org/package/bv-sized) +## 1.0.0 *May 2020*++This is a completely breaking change and it is completely incompatible+with any previous use for this library.++  * Bitvectors no longer track their own width. Every operations that+    relies on runtime awareness of the width (for instance,+    truncations) requires an expicit 'NatRepr' argument.+  * Bitvectors do not support any typical instances you might hope for+    (Num, Bits, etc.). This is because they are not interpreted by+    default as signed or unsigned, so any class that requires such an+    interpretation is not supported. We do provide wrapper types that+    supply those instances when the bitvector width is known+    (SignedBV/UnsignedBV).+  * Every operation has been renamed. Most are pretty straightforward+    (e.g. bvAdd ==> add).+  * Several previously unsupported operations have been added+    (e.g. count leading zeros, conversion to/from bit/bytestrings)+  * The App and BitLayout modules have been removed entirely. Both are+    potentially useful, but are out of date and probably should be in+    a different package anyway.+  * New modules+	  * Data.BitVector.Sized.{Signed,Unsigned}: wrappers for BV that+		provide many instances+	  * Data.BitVector.Sized.Overflow: wrappers for operations that+        provide overflow information as part of the output+ ## 0.7.0 *April 2019*-  * extractWithRepr now takes a NatRepr as an argument to specify the index, which it-    always should have.-  * Updated to recent parameterized-utils hackage release, which fixes the build-    failures in the previous bv-sized release.+  * extractWithRepr now takes a NatRepr as an argument to specify the+    index, which it always should have.+  * Updated to recent parameterized-utils hackage release, which fixes+    the build failures in the previous bv-sized release.  ## 0.6.0 *March 2019*   * changed WithRepr functions to '@@ -17,8 +44,9 @@   * fixed github URL  ## 0.5.0 *August 2018*-  * Added a lot of better support for the App module, including a type class for-    embedding BVApp expressions along with associated smart constructors+  * Added a lot of better support for the App module, including a type+    class for embedding BVApp expressions along with associated smart+    constructors  ## 0.4.0 *April 2018*   * Added App module for BitVector expression languages and evaluation@@ -33,8 +61,9 @@ ## 0.2.1 *March 2018*   * bvMulFSU   * bvDivU, bvDivS-  * Added Read instance, fixed Show to be compatible. Using prettyclass for-    pretty printing. (I guess this is semi-breaking, but whatever.)+  * Added Read instance, fixed Show to be compatible. Using+    prettyclass for pretty printing. (I guess this is semi-breaking,+    but whatever.)  ## 0.2 *March 2018*   * bv -> bitVector, so this is very much a breaking change@@ -45,10 +74,11 @@   * added BitLayout  ## 0.1.1.0 *March 2018*-  * added functions `bvMulFS`/`bvMulFU` for full bitvector multiplication-    without truncation+  * added functions `bvMulFS`/`bvMulFU` for full bitvector+    multiplication without truncation   * removed Internal module, now export all those functions in Data.BitVector.Sized-  * fixed the bv*WithRepr functions, which were not truncating the inputs properly+  * fixed the bv*WithRepr functions, which were not truncating the+    inputs properly  ## 0.1.0.0 *March 2018*   * First release
src/Data/BitVector/Sized.hs view
@@ -9,47 +9,106 @@ Module      : Data.BitVector.Sized Copyright   : (c) Galois Inc. 2018 License     : BSD-3-Maintainer  : benselfridge@galois.com+Maintainer  : Ben Selfridge <benselfridge@galois.com> Stability   : experimental Portability : portable -This module defines a width-parameterized 'BitVector' type and various associated-operations that assume a 2's complement representation.+This module defines a width-parameterized 'BV' type and various+associated operations. A @'BV' w@ is a newtype around an 'Integer', so+operations that require the width take an explicit @'NatRepr' w@+argument. We explicitly do not allow widths that cannot be represented+as an 'Prelude.Int', as we appeal to the underlying 'Prelude.Num' and+'Data.Bits.Bits' instances on 'Integer' for the implementation of many+of the same operations (which, in turn, require those widths to be+'Prelude.Int's).++We omit all typeclass instances that require compile-time knowledge of+bitvector width, or force a signed or unsigned intepretation. Those+instances can be recovered via the use of+'Data.BitVector.Sized.Signed.SignedBV' or+'Data.BitVector.Sized.Unsigned.UnsignedBV'.++This module should be imported qualified, as many of the names clash+with those in Prelude or other base packages. -}  module Data.BitVector.Sized-  ( -- * BitVector type-    BitVector, pattern BitVector-  , bitVector, bitVector'-  , bv0-    -- * Bitwise operations (width-preserving)-    -- | These are alternative versions of some of the 'Data.Bits' functions where we-    -- do not need to know the width at compile time. They are all width-preserving.-  , bvAnd, bvOr, bvXor-  , bvComplement-  , bvShift, bvShiftL, bvShiftRA, bvShiftRL, bvRotate-  , bvWidth-  , bvTestBit-  , bvPopCount-  , bvTruncBits+  ( -- * 'BV.BV' type+    BV.BV, pattern BV+    -- * 'NatRepr's (from parameterized-utils)+  , NatRepr+  , knownNat+    -- * Constructors+  , mkBV, mkBVUnsigned, mkBVSigned+  , unsignedClamp, signedClamp+  , minUnsigned, maxUnsigned+  , minSigned, maxSigned+    -- * Construction from fixed-width data types+  , bool+  , word8, word16, word32, word64+  , int8, int16, int32, int64+  , bitsBE, bitsLE+  , bytesBE, bytesLE+  , bytestringBE, bytestringLE+    -- * Conversions to primitive types+  , asSigned+  , asUnsigned+  , asNatural+  , asBitsBE, asBitsLE+  , asBytesBE, asBytesLE+  , asBytestringBE, asBytestringLE+    -- * Bits operations (width-preserving)+    -- | 'BV' versions of the functions in @Data.Bits@.+  , and, or, xor+  , complement+  , shl, lshr, ashr, rotateL, rotateR+  , zero, one, width+  , bit, bit'+  , setBit, setBit'+  , clearBit, clearBit'+  , complementBit, complementBit'+  , testBit, testBit'+  , popCount+  , ctz, clz+  , truncBits     -- * Arithmetic operations (width-preserving)-  , bvAdd, bvMul-  , bvQuotU, bvQuotS-  , bvRemU, bvRemS-  , bvAbs, bvNegate-  , bvSignum-  , bvLTS, bvLTU+  , add, sub, mul+  , uquot, squot, sdiv+  , urem, srem, smod+  , uquotRem, squotRem, sdivMod+  , abs, negate+  , signBit+  , signum+  , slt, sle, ult, ule+  , umin, umax+  , smin, smax     -- * Variable-width operations     -- | These are functions that involve bit vectors of different lengths.-  , bvConcat, (<:>), bvConcatMany, bvConcatMany'-  , bvExtract, bvExtract'-  , bvZext, bvZext'-  , bvSext, bvSext'-    -- * Conversions to Integer-  , bvIntegerU-  , bvIntegerS-    -- * Byte decomposition-  , bvGetBytesU+  , concat+  , select, select'+  , zext+  , sext+  , trunc, trunc'+  , mulWide+    -- * Enum operations+  , succUnsigned, succSigned+  , predUnsigned, predSigned+  , enumFromToUnsigned, enumFromToSigned+    -- * Pretty printing+  , ppHex+  , ppBin+  , ppOct+  , ppDec   ) where -import Data.BitVector.Sized.Internal+import Data.BitVector.Sized.Internal hiding (BV(..))+import qualified Data.BitVector.Sized.Internal as BV++import Data.Parameterized.NatRepr (knownNat, NatRepr)+import Prelude (Integer)++-- | Get the underlying 'Integer' representation from a 'BV'. We+-- guarantee that @(\\(BV.BV x) -> x) == BV.toUnsigned@.+pattern BV :: Integer -> BV.BV w+pattern BV x <- BV.BV x+{-# COMPLETE BV #-}
− src/Data/BitVector/Sized/App.hs
@@ -1,369 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeOperators #-}--{-|-Module      : Data.BitVector.Sized.App-Copyright   : (c) Galois Inc. 2018-License     : BSD-3-Maintainer  : benselfridge@galois.com-Stability   : experimental-Portability : portable--This module exports a type, 'BVApp', to aid in building expression languages over-'BitVector's. Let @expr :: Nat -> *@ be some ADT of /expressions/ that yield-'BitVector's when evaluated. Then, given one or more values of type @expr w@-(i.e. one or more of these evaluatable expressions), 'BVApp' provides the various-constructors necessary for creating compound expressions involving pure 'BitVector'-operations. The @expr@ type can (and often will) include a constructor of type @BVApp-expr w -> expr w@ in order to create a recursive expression language.--In addition to the 'BVApp' type, we provide an evaluator which, given a function-mapping values of type @expr w@ to 'BitVector's, will evaluate the compound-'BVApp' expressions.--}--module Data.BitVector.Sized.App-  ( BVApp(..)-  , evalBVApp-  , evalBVAppM-  , bvAppWidth-  -- * Smart constructors-  , BVExpr(..)-  -- ** Bitwise-  , andE-  , orE-  , xorE-  , notE-  -- ** Arithmetic-  , addE-  , subE-  , mulE-  , quotuE-  , quotsE-  , remuE-  , remsE-  , negateE-  , absE-  , signumE-  , sllE-  , srlE-  , sraE-  -- ** Comparison-  , eqE-  , ltuE-  , ltsE-  -- ** Width-changing-  , zextE, zextE'-  , sextE, sextE'-  , extractE, extractE'-  , concatE-  -- ** Control-  , iteE-  ) where--import Control.Monad.Identity-import Data.BitVector.Sized--- import Data.Bits-import Data.Parameterized-import Data.Parameterized.TH.GADT-import Foreign.Marshal.Utils (fromBool)-import GHC.TypeLits---- | Represents the application of a 'BitVector' operation to one or more--- subexpressions.-data BVApp (expr :: Nat -> *) (w :: Nat) where--  -- Bitwise operations-  AndApp :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  OrApp  :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  XorApp :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  NotApp :: !(NatRepr w) -> !(expr w) -> BVApp expr w--  -- Shifts-  SllApp :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  SrlApp :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  SraApp :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w--  -- Arithmetic operations-  AddApp   :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  SubApp   :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  MulApp   :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  QuotUApp :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  QuotSApp :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  RemUApp  :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  RemSApp  :: !(NatRepr w) -> !(expr w) -> !(expr w) -> BVApp expr w-  NegateApp :: !(NatRepr w) -> !(expr w) -> BVApp expr w-  AbsApp   :: !(NatRepr w) -> !(expr w) -> BVApp expr w-  SignumApp :: !(NatRepr w) -> !(expr w) -> BVApp expr w--  -- Comparisons-  EqApp  :: !(expr w) -> !(expr w) -> BVApp expr 1-  LtuApp :: !(expr w) -> !(expr w) -> BVApp expr 1-  LtsApp :: !(expr w) -> !(expr w) -> BVApp expr 1--  -- Width-changing-  ZExtApp    :: NatRepr w' -> !(expr w) -> BVApp expr w'-  SExtApp    :: NatRepr w' -> !(expr w) -> BVApp expr w'-  ExtractApp :: NatRepr w' -> NatRepr ix -> !(expr w) -> BVApp expr w'-  ConcatApp  :: !(NatRepr (w+w')) -> !(expr w) -> !(expr w') -> BVApp expr (w+w')--  -- Other operations-  IteApp :: !(NatRepr w) -> !(expr 1) -> !(expr w) -> !(expr w) -> BVApp expr w--bvAppWidth :: BVApp expr w -> NatRepr w-bvAppWidth (AndApp wRepr _ _) = wRepr-bvAppWidth (OrApp wRepr _ _) = wRepr-bvAppWidth (XorApp wRepr _ _) = wRepr-bvAppWidth (NotApp wRepr _) = wRepr--bvAppWidth (SllApp wRepr _ _) = wRepr-bvAppWidth (SrlApp wRepr _ _) = wRepr-bvAppWidth (SraApp wRepr _ _) = wRepr--bvAppWidth (AddApp wRepr _ _) = wRepr-bvAppWidth (SubApp wRepr _ _) = wRepr-bvAppWidth (MulApp wRepr _ _) = wRepr-bvAppWidth (QuotUApp wRepr _ _) = wRepr-bvAppWidth (QuotSApp wRepr _ _) = wRepr-bvAppWidth (RemUApp wRepr _ _) = wRepr-bvAppWidth (RemSApp wRepr _ _) = wRepr-bvAppWidth (NegateApp wRepr _) = wRepr-bvAppWidth (AbsApp wRepr _) = wRepr-bvAppWidth (SignumApp wRepr _) = wRepr--bvAppWidth (EqApp _ _) = knownNat-bvAppWidth (LtuApp _ _) = knownNat-bvAppWidth (LtsApp _ _) = knownNat--bvAppWidth (ZExtApp wRepr _) = wRepr-bvAppWidth (SExtApp wRepr _) = wRepr-bvAppWidth (ExtractApp wRepr _ _) = wRepr-bvAppWidth (ConcatApp wRepr _ _) = wRepr--bvAppWidth (IteApp wRepr _ _ _) = wRepr--$(return [])--instance TestEquality expr => TestEquality (BVApp expr) where-  testEquality = $(structuralTypeEquality [t|BVApp|]-                   [ (AnyType `TypeApp` AnyType, [|testEquality|]) ])--instance TestEquality expr => Eq (BVApp expr w) where-  (==) = \x y -> isJust (testEquality x y)--instance TestEquality expr => EqF (BVApp expr) where-  eqF = (==)--instance OrdF expr => OrdF (BVApp expr) where-  compareF = $(structuralTypeOrd [t|BVApp|]-                [ (AnyType `TypeApp` AnyType, [|compareF|]) ])--instance OrdF expr => Ord (BVApp expr w) where-  compare a b =-    case compareF a b of-      LTF -> LT-      EQF -> EQ-      GTF -> GT--instance FunctorFC BVApp where-  fmapFC = fmapFCDefault--instance FoldableFC BVApp where-  foldMapFC = foldMapFCDefault--instance TraversableFC BVApp where-  traverseFC = $(structuralTraversal [t|BVApp|] [])---- | Evaluate a 'BVApp' given a monadic evaluation function for the parameterized type @expr@.-evalBVAppM :: Monad m-           => (forall w' . expr w' -> m (BitVector w')) -- ^ expression evaluator-           -> BVApp expr w                              -- ^ application-           -> m (BitVector w)-evalBVAppM eval (AndApp _ e1 e2) = bvAnd <$> eval e1 <*> eval e2-evalBVAppM eval (OrApp  _ e1 e2) = bvOr  <$> eval e1 <*> eval e2-evalBVAppM eval (XorApp _ e1 e2) = bvXor <$> eval e1 <*> eval e2-evalBVAppM eval (NotApp _ e)     = bvComplement <$> eval e-evalBVAppM eval (AddApp _ e1 e2) = bvAdd <$> eval e1 <*> eval e2-evalBVAppM eval (SubApp _ e1 e2) = bvAdd <$> eval e1 <*> (bvNegate <$> eval e2)-evalBVAppM eval (SllApp _ e1 e2) = bvShiftL  <$> eval e1 <*> (fromIntegral . bvIntegerU <$> eval e2)-evalBVAppM eval (SrlApp _ e1 e2) = bvShiftRL <$> eval e1 <*> (fromIntegral . bvIntegerU <$> eval e2)-evalBVAppM eval (SraApp _ e1 e2) = bvShiftRA <$> eval e1 <*> (fromIntegral . bvIntegerU <$> eval e2)-evalBVAppM eval (MulApp _ e1 e2) = bvMul <$> eval e1 <*> eval e2-evalBVAppM eval (QuotSApp _ e1 e2) = bvQuotS  <$> eval e1 <*> eval e2-evalBVAppM eval (QuotUApp _ e1 e2) = bvQuotU  <$> eval e1 <*> eval e2-evalBVAppM eval (RemSApp  _ e1 e2) = bvRemS   <$> eval e1 <*> eval e2-evalBVAppM eval (RemUApp  _ e1 e2) = bvRemU   <$> eval e1 <*> eval e2-evalBVAppM eval (NegateApp _ e) = bvNegate <$> eval e-evalBVAppM eval (AbsApp _ e) = bvAbs <$> eval e-evalBVAppM eval (SignumApp _ e) = bvSignum <$> eval e-evalBVAppM eval (EqApp  e1 e2) = fromBool <$> ((==)  <$> eval e1 <*> eval e2)-evalBVAppM eval (LtuApp e1 e2) = fromBool <$> (bvLTU <$> eval e1 <*> eval e2)-evalBVAppM eval (LtsApp e1 e2) = fromBool <$> (bvLTS <$> eval e1 <*> eval e2)-evalBVAppM eval (ZExtApp wRepr e) = bvZext' wRepr <$> eval e-evalBVAppM eval (SExtApp wRepr e) = bvSext' wRepr <$> eval e-evalBVAppM eval (ExtractApp wRepr ixRepr e) =-  bvExtract' wRepr (fromIntegral $ intValue ixRepr) <$> eval e-evalBVAppM eval (ConcatApp _ e1 e2) = do-  e1Val <- eval e1-  e2Val <- eval e2-  return $ e1Val `bvConcat` e2Val-evalBVAppM eval (IteApp _ eTest eT eF) = do-  testVal <- eval eTest-  case testVal of-    1 -> eval eT-    _ -> eval eF---- | Evaluate a 'BVApp' given a pure evaluation function for the parameterized type @expr@.-evalBVApp :: (forall w' . expr w' -> BitVector w') -- ^ expression evaluator-          -> BVApp expr w                          -- ^ application-          -> BitVector w-evalBVApp eval bvApp = runIdentity $ evalBVAppM (return . eval) bvApp---- | Typeclass for embedding 'BVApp' constructors into larger expression types.-class BVExpr (expr :: Nat -> *) where-  litBV :: BitVector w -> expr w-  exprWidth :: expr w -> NatRepr w-  appExpr :: BVApp expr w -> expr w---- -- TODO: finish--- instance (BVExpr expr) => Num (BVApp expr w) where---   app1 + app2 = AddApp (appExpr app1) (appExpr app2)---   app1 * app2 = MulApp (appExpr app1) (appExpr app2)---   abs app = AbsApp (appExpr app)---   signum app = SignumApp (appExpr app)---   fromInteger = undefined---   negate app = NegateApp (appExpr app)---   app1 - app2 = SubApp (appExpr app1) (appExpr app2)---- -- TODO: finish--- instance (KnownNat w, BVExpr expr, TestEquality expr) => Bits (BVApp expr w) where---   app1 .&. app2 = AndApp (appExpr app1) (appExpr app2)---   app1 .|. app2 = OrApp (appExpr app1) (appExpr app2)---   app1 `xor` app2 = XorApp (appExpr app1) (appExpr app2)---   complement app = NotApp (appExpr app)---   shiftL = undefined---   shiftR = undefined---   rotate = undefined---   bitSize = undefined---   bitSizeMaybe = undefined---   isSigned = undefined---   testBit = undefined---   bit = undefined---   popCount = undefined---- | Bitwise and.-andE :: BVExpr expr => expr w -> expr w -> expr w-andE e1 e2 = appExpr (AndApp (exprWidth e1) e1 e2)---- | Bitwise or.-orE :: BVExpr expr => expr w -> expr w -> expr w-orE e1 e2 = appExpr (OrApp (exprWidth e1) e1 e2)---- | Bitwise xor.-xorE :: BVExpr expr => expr w -> expr w -> expr w-xorE e1 e2 = appExpr (XorApp (exprWidth e1) e1 e2)---- | Bitwise not.-notE :: BVExpr expr => expr w -> expr w-notE e = appExpr (NotApp (exprWidth e) e)---- | Add two expressions.-addE :: BVExpr expr => expr w -> expr w -> expr w-addE e1 e2 = appExpr (AddApp (exprWidth e1) e1 e2)---- | Subtract the second expression from the first.-subE :: BVExpr expr => expr w -> expr w -> expr w-subE e1 e2 = appExpr (SubApp (exprWidth e1) e1 e2)---- | Signed multiply two 'BitVector's, doubling the width of the result to hold all--- arithmetic overflow bits.-mulE :: BVExpr expr => expr w -> expr w -> expr w-mulE e1 e2 = appExpr (MulApp (exprWidth e1) e1 e2)---- | Signed divide two 'BitVector's, rounding to zero.-quotsE :: BVExpr expr => expr w -> expr w -> expr w-quotsE e1 e2 = appExpr (QuotSApp (exprWidth e1) e1 e2)---- | Unsigned divide two 'BitVector's, rounding to zero.-quotuE :: BVExpr expr => expr w -> expr w -> expr w-quotuE e1 e2 = appExpr (QuotUApp (exprWidth e1) e1 e2)---- | Remainder after signed division of two 'BitVector's, when rounded to zero.-remsE :: BVExpr expr => expr w -> expr w -> expr w-remsE e1 e2 = appExpr (RemSApp (exprWidth e1) e1 e2)---- | Remainder after unsigned division of two 'BitVector's, when rounded to zero.-remuE :: BVExpr expr => expr w -> expr w -> expr w-remuE e1 e2 = appExpr (RemUApp (exprWidth e1) e1 e2)--negateE :: BVExpr expr => expr w -> expr w-negateE e = appExpr (NegateApp (exprWidth e) e)--absE :: BVExpr expr => expr w -> expr w-absE e = appExpr (AbsApp (exprWidth e) e)--signumE :: BVExpr expr => expr w -> expr w-signumE e = appExpr (SignumApp (exprWidth e) e)---- | Left logical shift the first expression by the second.-sllE :: BVExpr expr => expr w -> expr w -> expr w-sllE e1 e2 = appExpr (SllApp (exprWidth e1) e1 e2)---- | Left logical shift the first expression by the second.-srlE :: BVExpr expr => expr w -> expr w -> expr w-srlE e1 e2 = appExpr (SrlApp (exprWidth e1) e1 e2)---- | Left logical shift the first expression by the second.-sraE :: BVExpr expr => expr w -> expr w -> expr w-sraE e1 e2 = appExpr (SraApp (exprWidth e1) e1 e2)---- | Test for equality of two expressions.-eqE :: BVExpr expr => expr w -> expr w -> expr 1-eqE e1 e2 = appExpr (EqApp e1 e2)---- | Signed less than-ltsE :: BVExpr expr => expr w -> expr w -> expr 1-ltsE e1 e2 = appExpr (LtsApp e1 e2)---- | Unsigned less than-ltuE :: BVExpr expr => expr w -> expr w -> expr 1-ltuE e1 e2 = appExpr (LtuApp e1 e2)---- | Zero-extension-zextE :: (BVExpr expr, KnownNat w') => expr w -> expr w'-zextE e = appExpr (ZExtApp knownNat e)---- | Zero-extension with an explicit width argument-zextE' :: BVExpr expr => NatRepr w' -> expr w -> expr w'-zextE' repr e = appExpr (ZExtApp repr e)---- | Sign-extension-sextE :: (BVExpr expr, KnownNat w') => expr w -> expr w'-sextE e = appExpr (SExtApp knownNat e)---- | Sign-extension with an explicit width argument-sextE' :: BVExpr expr => NatRepr w' -> expr w -> expr w'-sextE' repr e = appExpr (SExtApp repr e)---- | Extract bits-extractE :: (BVExpr expr, KnownNat w') => NatRepr ix -> expr w -> expr w'-extractE ixRepr e = appExpr (ExtractApp knownNat ixRepr e)---- | Extract bits with an explicit width argument-extractE' :: BVExpr expr => NatRepr w' -> NatRepr ix -> expr w -> expr w'-extractE' wRepr ixRepr e = appExpr (ExtractApp wRepr ixRepr e)---- | Concatenation-concatE :: BVExpr expr => expr w -> expr w' -> expr (w+w')-concatE e1 e2 = appExpr (ConcatApp (exprWidth e1 `addNat` exprWidth e2) e1 e2)---- | Conditional branch.-iteE :: BVExpr expr => expr 1 -> expr w -> expr w -> expr w-iteE t e1 e2 = appExpr (IteApp (exprWidth e1) t e1 e2)
− src/Data/BitVector/Sized/BitLayout.hs
@@ -1,283 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TypeOperators #-}--{-|-Module      : Data.BitVector.Sized.BitLayout-Copyright   : (c) Galois Inc. 2018-License     : BSD-3-Maintainer  : benselfridge@galois.com-Stability   : experimental-Portability : portable--This module defines a 'BitLayout' datatype which encodes a chunk-to-chunk mapping (no-overlaps) from a smaller bit vector into a larger one. 'BitLayout's are especially-useful for defining the encoding and decoding of opcodes/operands in an instruction.--}--module Data.BitVector.Sized.BitLayout-  ( -- * Chunk-    Chunk(..)-  , chunk-    -- * BitLayout-  , BitLayout-  , empty, singleChunk, (<:)-  , inject-  , extract-    -- * Lenses-  , layoutLens, layoutsLens-    -- * Utilities-  , bitLayoutAssignmentList-  ) where--import Data.BitVector.Sized.Internal-import Data.Foldable-import qualified Data.Functor.Product as P-import Control.Lens (lens, Simple, Lens)-import Data.Parameterized-import Data.Parameterized.List-import qualified Data.Sequence as S-import Data.Sequence (Seq)-import GHC.TypeLits-import Text.PrettyPrint.HughesPJClass (Pretty(..), text)---- | 'Chunk' type, parameterized by chunk width. The internal 'Int' is the--- position of the least significant bit of the chunk, and the type-level nat 'w' is--- the width of the chunk.------ >>> chunk 2 :: Chunk 5--- Chunk 5 2------ Intuitively, the above chunk index captures the notion of /embedding/ a--- 'BitVector' @5@ (bit vector of width 5) into a larger 'BitVector' at index 2,--- preserving the order of the input bits. So an 5-bit input like @10011@ would map--- to some larger bit vector containing the input starting at position 2, like--- @000001001100@.------ Multiple 'Chunk's comprise a 'BitLayout'; see below.-data Chunk (w :: Nat) :: * where-  Chunk :: NatRepr w -- width of range-        -> Int       -- index of range start-        -> Chunk w---- | Construct a 'Chunk' in a context where the chunk width is known at compile time.-chunk :: KnownNat w => Int -> Chunk w-chunk = Chunk knownNat--deriving instance Show (Chunk w)--instance ShowF Chunk where-  showF = show--instance Pretty (Chunk w) where-  pPrint (Chunk wRepr start)-    | width > 0 = text $-      "[" ++ show (start + width - 1) ++ "..." ++ show start ++ "]"-    | otherwise = text $ "[" ++ show start ++ "]"-    where width = fromIntegral (natValue wRepr)--instance Pretty (Some Chunk) where-  pPrint (Some (Chunk wRepr start))-    | width > 0 = text $-      "[" ++ show (start + width - 1) ++ "..." ++ show start ++ "]"-    | otherwise = text $ "[" ++ show start ++ "]"-    where width = fromIntegral (natValue wRepr)---- | BitLayout type, parameterized by target width and source width. @t@ is the--- target width, @s@ is the source width. @s@ should always be less than or equal to--- @t@.------ To construct a 'BitLayout', use the 'empty' constructor and the '<:' operator,--- like so:------ >>> empty :: BitLayout 32 0--- BitLayout 32 0 (fromList [])--- >>> let layout = (chunk 25 :: Chunk 7) <: (chunk 7 :: Chunk 5) <: (empty :: BitLayout 32 0)--- >>> layout--- BitLayout 32 12 (fromList [Chunk 5 7,Chunk 7 25])--- >>> :type it--- it :: BitLayout 32 12------ In the above example @bitLayout@ defines a chunk-by-chunk mapping from a bit--- vector of width 12 to one of width 32. We imagine the input vector of width 12--- listed like so:------ @--- 0bAXXXXXBCXXXD---   |-----||---|---      7     5--- @------ Here, bits @A@, @B@, @C@, and @D@ are just labeled as such to illustrate their--- place after the mapping. The @BitLayout 32 12@ defined above as the @layout@--- variable would map that 12-bit vector to the following 32-bit vector:------ @---      (Bit 25)          (Bit 5)---         |                 |---         |                 |---         v                 v--- 0bAXXXXXB0000000000000CXXXD0000000---   |-----|             |---|---      7                  5--- @------ To use a 'BitLayout' to achieve a bidirectional mapping like the one described--- above, you can either use the 'Lens' interface or the functions 'inject' and--- 'extract', which give an explicit setter and getter, respectively.------ Example use of @inject@/@extract@:------ >>> let bl = (chunk 25 :: Chunk 7) <: (chunk 7 :: Chunk 5) <: (empty :: BitLayout 32 0)--- >>> let sVec = bitVector 0b111111100001 :: BitVector 12--- >>> sVec--- 0xfe1--- >>> inject bl (bitVector 0) (bitVector 0b111111100001)--- 0xfe000080--- >>> extract bl $ inject bl (bitVector 0) (bitVector 0b111111100001)--- 0xfe1--data BitLayout (t :: Nat) (s :: Nat) :: * where-  BitLayout :: NatRepr t -> NatRepr s -> Seq (Some Chunk) -> BitLayout t s--instance Pretty (BitLayout t s) where-  pPrint (BitLayout _ _ chks) = text $ show (pPrint <$> reverse $ toList chks)--deriving instance Show (BitLayout t s)---- | Construct an empty 'BitLayout'.-empty :: KnownNat t => BitLayout t 0-empty = BitLayout knownNat knownNat S.empty---- | Construct a 'BitLayout' with one chunk.-singleChunk :: (KnownNat w, KnownNat w') => Int -> BitLayout w w'-singleChunk idx = chunk idx <: empty---- TODO: Should this be in Maybe?--- | Add a 'Chunk' to a 'BitLayout'. If the 'Chunk' does not fit, either because the--- resulting 'BitLayout' would be too long or because it would overlap with a 'Chunk'--- that is already in the 'BitLayout', we throw an error.-(<:) :: Chunk r             -- ^ chunk to add-     -> BitLayout t s       -- ^ layout we are adding the chunk to-     -> BitLayout t (r + s)-chk@(Chunk rRepr _) <: bl@(BitLayout tRepr sRepr chunks) =-  if chk `chunkFits` bl-  then BitLayout tRepr (rRepr `addNat` sRepr) (chunks S.|> Some chk)-  else error $-       "chunk " ++ show chk ++ " does not fit in layout of size " ++-       show (natValue tRepr) ++ ": " ++ show bl---- TODO: check precedence (associativity is correct)-infixr 6 <:--chunkFits :: Chunk r -> BitLayout t s -> Bool-chunkFits chk@(Chunk rRepr start) (BitLayout tRepr sRepr chunks) =-  (natValue rRepr + natValue sRepr <= natValue tRepr) && -- widths are ok-  (fromIntegral start + natValue rRepr <= natValue tRepr) && -- chunk lies within the bit vector-  (0 <= start) &&-  noOverlaps chk (toList chunks)--noOverlaps :: Chunk r -> [Some Chunk] -> Bool-noOverlaps chk = all (chunksDontOverlap (Some chk))--chunksDontOverlap :: Some Chunk -> Some Chunk -> Bool-chunksDontOverlap (Some (Chunk chunkRepr1 start1)) (Some (Chunk chunkRepr2 start2)) =-  if start1 <= start2-  then start1 + chunkWidth1 <= start2-  else start2 + chunkWidth2 <= start1-  where chunkWidth1 = fromIntegral (natValue chunkRepr1)-        chunkWidth2 = fromIntegral (natValue chunkRepr2)---- | Given a starting position, insert (via "or") a smaller 'BitVector' @s@ with a larger--- 'BitVector' @t@ at that position.-bvOrAt :: Int-       -> BitVector s-       -> BitVector t-       -> BitVector t-bvOrAt start sVec tVec@(BitVector tRepr _) =-  (bvZext' tRepr sVec `bvShift` start) `bvOr` tVec---- | Given a list of 'Chunk's, inject each chunk from a source 'BitVector' @s@ into a--- target 'BitVector' @t@.-bvOrAtAll :: NatRepr t-          -> [Some Chunk]-          -> BitVector s-          -> BitVector t-bvOrAtAll tRepr [] _ = BV tRepr 0-bvOrAtAll tRepr (Some (Chunk chunkRepr chunkStart) : chunks) sVec =-  bvOrAt chunkStart (bvTruncBits sVec chunkWidth) (bvOrAtAll tRepr chunks (sVec `bvShift` (- chunkWidth)))-  where chunkWidth = fromIntegral (natValue chunkRepr)---- | Use a 'BitLayout' to inject a smaller vector into a larger one.-inject :: BitLayout t s -- ^ The layout-       -> BitVector t   -- ^ The larger vector to inject into-       -> BitVector s   -- ^ The smaller vector to be injected-       -> BitVector t-inject (BitLayout tRepr _ chunks) tVec sVec =-  bvOrAtAll tRepr (toList chunks) sVec `bvOr` tVec---- First, extract the appropriate bits as a BitVector t, where the relevant bits--- start at the LSB of the vector (so, mask and shiftL). Then, truncate to a--- BitVector s, and shiftinto the starting position.-extractChunk :: NatRepr s     -- ^ width of output-             -> Int           -- ^ where to place the chunk in the result-             -> Some Chunk    -- ^ location/width of chunk in the input-             -> BitVector t   -- ^ input vector-             -> BitVector s-extractChunk sRepr sStart (Some (Chunk chunkRepr chunkStart)) tVec =-  bvShift extractedChunk sStart-  where extractedChunk = bvZext' sRepr (bvExtract' chunkRepr chunkStart tVec)--extractAll :: NatRepr s       -- ^ determines width of output vector-           -> Int             -- ^ current position in output vector-           -> [Some Chunk]    -- ^ list of remaining chunks to place in output vector-           -> BitVector t     -- ^ input vector-           -> BitVector s-extractAll sRepr _ [] _ = BV sRepr 0-extractAll sRepr outStart (chk@(Some (Chunk chunkRepr _)) : chunks) tVec =-  extractChunk sRepr outStart chk tVec `bvOr`-  extractAll sRepr (outStart + chunkWidth) chunks tVec-  where chunkWidth = fromInteger (intValue chunkRepr)---- | Use a 'BitLayout' to extract a smaller vector from a larger one.-extract :: BitLayout t s -- ^ The layout-        -> BitVector t   -- ^ The larger vector to extract from-        -> BitVector s-extract (BitLayout _ sRepr chunks) = extractAll sRepr 0 (toList chunks)---- | Lens for a 'BitLayout'.-layoutLens :: BitLayout t s -> Simple Lens (BitVector t) (BitVector s)-layoutLens layout = lens (extract layout) (inject layout)---- | Lens for a parameterized 'List' of 'BitLayout's.-layoutsLens :: forall ws . List (BitLayout 32) ws -> Simple Lens (BitVector 32) (List BitVector ws)-layoutsLens layouts = lens-  (\bv -> imap (const $ flip extract bv) layouts)-  (\bv bvFlds -> ifoldr (\_ (P.Pair fld layout) bv' -> inject layout bv' fld)-                 bv-                 (izipWith (const P.Pair) bvFlds layouts))---- | From a `BitLayout`, get a list representing the position of each bit from the--- source to the target. The list------ @--- [3,4,5,10,11,12,13]--- @------ means that bit 0 of the source is placed in bit 3 of the target, bit 1 of the--- source is placed in bit 4 of the target, etc.--bitLayoutAssignmentList :: BitLayout t s -> [Int]-bitLayoutAssignmentList (BitLayout _ _ someChunks) = reverse (bitLayoutAssignmentList' (toList someChunks))--bitLayoutAssignmentList' :: [Some Chunk] -> [Int]-bitLayoutAssignmentList' [] = []-bitLayoutAssignmentList' (Some (Chunk wRepr start):rst) =-  reverse [start..start+w-1] ++ bitLayoutAssignmentList' rst-  where w = fromIntegral (natValue wRepr)
src/Data/BitVector/Sized/Internal.hs view
@@ -1,420 +1,922 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeOperators #-}--{-|-Module      : Data.BitVector.Sized-Copyright   : (c) Galois Inc. 2018-License     : BSD-3-Maintainer  : benselfridge@galois.com-Stability   : experimental-Portability : portable--This module defines a width-parameterized 'BitVector' type and various associated-operations that assume a 2's complement representation.--}--module Data.BitVector.Sized.Internal where--import Data.Bits-import Data.Ix-import Data.Parameterized-import GHC.TypeLits-import Numeric-import System.Random-import Test.QuickCheck (Arbitrary(..), choose)-import Text.PrettyPrint.HughesPJClass-import Text.Printf-import Unsafe.Coerce (unsafeCoerce)--------------------------------------------- BitVector data type definitions---- | BitVector datatype, parameterized by width.-data BitVector (w :: Nat) :: * where-  BV :: NatRepr w -> Integer -> BitVector w---- | 'BitVector' can be treated as a constructor for pattern matching, but to build--- one you must use the smart constructor `bitVector`.-pattern BitVector :: NatRepr w -> Integer -> BitVector w-pattern BitVector wRepr x <- BV wRepr x-{-# COMPLETE BitVector #-}---- | Construct a bit vector with a particular width, where the width is inferrable--- from the type context. The input (an unbounded data type, hence with an--- infinite-width bit representation), whether positive or negative, is silently--- truncated to fit into the number of bits demanded by the return type.------ >>> bitVector 0xA :: BitVector 4--- 0xa--- >>> bitVector 0xA :: BitVector 2--- 0x2-bitVector :: (Integral a, KnownNat w) => a -> BitVector w-bitVector x = bitVector' knownNat x---- | Like 'bitVector', but with an explict 'NatRepr'.-bitVector' :: Integral a => NatRepr w -> a -> BitVector w-bitVector' wRepr x = BV wRepr (truncBits width (fromIntegral x))-  where width = natValue wRepr---- | The zero bitvector with width 0.-bv0 :: BitVector 0-bv0 = bitVector (0 :: Integer)--------------------------------------------- BitVector -> Integer functions---- | Unsigned interpretation of a bit vector as a (positive) Integer.-bvIntegerU :: BitVector w -> Integer-bvIntegerU (BV _ x) = x---- | Signed interpretation of a bit vector as an Integer.-bvIntegerS :: BitVector w -> Integer-bvIntegerS bv = if bvTestBit bv (width - 1)-                then bvIntegerU bv - (1 `shiftL` width)-                else bvIntegerU bv-  where width = bvWidth bv--------------------------------------------- BitVector w operations (fixed width)---- | Bitwise and.-bvAnd :: BitVector w -> BitVector w -> BitVector w-bvAnd (BV wRepr x) (BV _ y) = BV wRepr (x .&. y)---- | Bitwise or.-bvOr :: BitVector w -> BitVector w -> BitVector w-bvOr (BV wRepr x) (BV _ y) = BV wRepr (x .|. y)---- | Bitwise xor.-bvXor :: BitVector w -> BitVector w -> BitVector w-bvXor (BV wRepr x) (BV _ y) = BV wRepr (x `xor` y)---- | Bitwise complement (flip every bit).-bvComplement :: BitVector w -> BitVector w-bvComplement (BV wRepr x) = BV wRepr (truncBits width (complement x))-  where width = natValue wRepr---- | Bitwise shift. Uses an arithmetic right shift.-bvShift :: BitVector w -> Int -> BitVector w-bvShift bv@(BV wRepr _) shf = BV wRepr (truncBits width (x `shift` shf))-  where width = natValue wRepr-        x     = bvIntegerS bv -- arithmetic right shift when negative--toPos :: Int -> Int-toPos x | x < 0 = 0-toPos x = x---- | Left shift.-bvShiftL :: BitVector w -> Int -> BitVector w-bvShiftL bv shf = bvShift bv (toPos shf)---- | Right arithmetic shift.-bvShiftRA :: BitVector w -> Int -> BitVector w-bvShiftRA bv shf = bvShift bv (- (toPos shf))---- | Right logical shift.-bvShiftRL :: BitVector w -> Int -> BitVector w-bvShiftRL bv@(BV wRepr _) shf = BV wRepr (truncBits width (x `shift` (- toPos shf)))-  where width = natValue wRepr-        x     = bvIntegerU bv---- | Bitwise rotate.-bvRotate :: BitVector w -> Int -> BitVector w-bvRotate bv rot' = leftChunk `bvOr` rightChunk-  where rot = rot' `mod` bvWidth bv-        leftChunk = bvShift bv rot-        rightChunk = bvShift bv (rot - bvWidth bv)---- | Get the width of a 'BitVector'.-bvWidth :: BitVector w -> Int-bvWidth (BV wRepr _) = fromIntegral (natValue wRepr)---- | Test if a particular bit is set.-bvTestBit :: BitVector w -> Int -> Bool-bvTestBit (BV _ x) b = testBit x b---- | Get the number of 1 bits in a 'BitVector'.-bvPopCount :: BitVector w -> Int-bvPopCount (BV _ x) = popCount x---- | Truncate a bit vector to a particular width given at runtime, while keeping the--- type-level width constant.-bvTruncBits :: BitVector w -> Int -> BitVector w-bvTruncBits (BV wRepr x) b = BV wRepr (truncBits b x)--------------------------------------------- BitVector w arithmetic operations (fixed width)---- | Bitwise add.-bvAdd :: BitVector w -> BitVector w -> BitVector w-bvAdd (BV wRepr x) (BV _ y) = BV wRepr (truncBits width (x + y))-  where width = natValue wRepr---- | Bitwise multiply.-bvMul :: BitVector w -> BitVector w -> BitVector w-bvMul (BV wRepr x) (BV _ y) = BV wRepr (truncBits width (x * y))-  where width = natValue wRepr---- | Bitwise division (unsigned). Rounds to zero.-bvQuotU :: BitVector w -> BitVector w -> BitVector w-bvQuotU (BV wRepr x) (BV _ y) = BV wRepr (x `quot` y)---- | Bitwise division (signed). Rounds to zero (not negative infinity).-bvQuotS :: BitVector w -> BitVector w -> BitVector w-bvQuotS bv1@(BV wRepr _) bv2 = BV wRepr (truncBits width (x `quot` y))-  where x = bvIntegerS bv1-        y = bvIntegerS bv2-        width = natValue wRepr---- | Bitwise remainder after division (unsigned), when rounded to zero.-bvRemU :: BitVector w -> BitVector w -> BitVector w-bvRemU (BV wRepr x) (BV _ y) = BV wRepr (x `rem` y)---- | Bitwise remainder after  division (signed), when rounded to zero (not negative--- infinity).-bvRemS :: BitVector w -> BitVector w -> BitVector w-bvRemS bv1@(BV wRepr _) bv2 = BV wRepr (truncBits width (x `rem` y))-  where x = bvIntegerS bv1-        y = bvIntegerS bv2-        width = natValue wRepr---- | Bitwise absolute value.-bvAbs :: BitVector w -> BitVector w-bvAbs bv@(BV wRepr _) = BV wRepr abs_x-  where width = natValue wRepr-        x     = bvIntegerS bv-        abs_x = truncBits width (abs x) -- this is necessary---- | Bitwise negation.-bvNegate :: BitVector w -> BitVector w-bvNegate (BV wRepr x) = BV wRepr (truncBits width (-x))-  where width = fromIntegral (natValue wRepr) :: Integer---- | Get the sign bit as a 'BitVector'.-bvSignum :: BitVector w -> BitVector w-bvSignum bv@(BV wRepr _) = bvShift bv (1 - width) `bvAnd` BV wRepr 0x1-  where width = fromIntegral (natValue wRepr)---- | Signed less than.-bvLTS :: BitVector w -> BitVector w -> Bool-bvLTS bv1 bv2 = bvIntegerS bv1 < bvIntegerS bv2---- | Unsigned less than.-bvLTU :: BitVector w -> BitVector w -> Bool-bvLTU bv1 bv2 = bvIntegerU bv1 < bvIntegerU bv2--------------------------------------------- Width-changing operations---- | Concatenate two bit vectors.------ >>> (0xAA :: BitVector 8) `bvConcat` (0xBCDEF0 :: BitVector 24)--- 0xaabcdef0--- >>> :type it--- it :: BitVector 32------ Note that the first argument gets placed in the higher-order bits. The above--- example should be illustrative enough.-bvConcat :: BitVector v -> BitVector w -> BitVector (v+w)-bvConcat (BV hiWRepr hi) (BV loWRepr lo) =-  BV (hiWRepr `addNat` loWRepr) ((hi `shiftL` loWidth) .|. lo)-  where loWidth = fromIntegral (natValue loWRepr)---- | Infix 'bvConcat'.-(<:>) :: BitVector v -> BitVector w -> BitVector (v+w)-(<:>) = bvConcat--bvConcatSome :: Some BitVector -> Some BitVector -> Some BitVector-bvConcatSome (Some bv1) (Some bv2) = Some (bv2 <:> bv1)---- | Concatenate a list of 'BitVector's into a 'BitVector' of arbitrary width. The ordering is little endian:------ >>> bvConcatMany [0xAA :: BitVector 8, 0xBB] :: BitVector 16--- 0xbbaa--- >>> bvConcatMany [0xAA :: BitVector 8, 0xBB, 0xCC] :: BitVector 16--- 0xbbaa------ If the sum of the widths of the input 'BitVector's exceeds the output width, we--- ignore the tail end of the list.-bvConcatMany :: KnownNat w' => [BitVector w] -> BitVector w'-bvConcatMany = bvConcatMany' knownNat---- | 'bvConcatMany' with an explicit 'NatRepr'.-bvConcatMany' :: NatRepr w' -> [BitVector w] -> BitVector w'-bvConcatMany' wRepr bvs =-  viewSome (bvZext' wRepr) $ foldl bvConcatSome (Some bv0) (Some <$> bvs)--infixl 6 <:>---- | Slice out a smaller bit vector from a larger one. The lowest significant bit is--- given explicitly as an argument of type 'Int', and the length of the slice is--- inferred from a type-level context.------ >>> bvExtract 12 (0xAABCDEF0 :: BitVector 32) :: BitVector 8--- 0xcd------ Note that 'bvExtract' does not do any bounds checking whatsoever; if you try and--- extract bits that aren't present in the input, you will get 0's.-bvExtract :: forall w w' . (KnownNat w')-          => Int-          -> BitVector w-          -> BitVector w'-bvExtract pos bv = bitVector xShf-  where (BV _ xShf) = bvShift bv (- pos)---- | Unconstrained variant of 'bvExtract' with an explicit 'NatRepr' argument.-bvExtract' :: NatRepr w'-                  -> Int-                  -> BitVector w-                  -> BitVector w'-bvExtract' repr pos bv = BV repr (truncBits width xShf)-  where (BV _ xShf) = bvShift bv (- pos)-        width = natValue repr---- | Zero-extend a vector to one of greater length. If given an input of greater--- length than the output type, this performs a truncation.-bvZext :: forall w w' . KnownNat w'-       => BitVector w-       -> BitVector w'-bvZext (BV _ x) = bitVector x---- | Unconstrained variant of 'bvZext' with an explicit 'NatRepr' argument.-bvZext' :: NatRepr w'-               -> BitVector w-               -> BitVector w'-bvZext' repr (BV _ x) = BV repr (truncBits width x)-  where width = natValue repr---- | Sign-extend a vector to one of greater length. If given an input of greater--- length than the output type, this performs a truncation.-bvSext :: forall w w' . KnownNat w'-       => BitVector w-       -> BitVector w'-bvSext bv = bitVector (bvIntegerS bv)---- | Unconstrained variant of 'bvSext' with an explicit 'NatRepr' argument.-bvSext' :: NatRepr w'-               -> BitVector w-               -> BitVector w'-bvSext' repr bv = BV repr (truncBits width (bvIntegerS bv))-  where width = natValue repr--------------------------------------------- Byte decomposition---- | Given a 'BitVector' of arbitrary length, decompose it into a list of bytes. Uses--- an unsigned interpretation of the input vector, so if you ask for more bytes that--- the 'BitVector' contains, you get zeros. The result is little-endian, so the first--- element of the list will be the least significant byte of the input vector.-bvGetBytesU :: Int -> BitVector w -> [BitVector 8]-bvGetBytesU n _ | n <= 0 = []-bvGetBytesU n bv = bvExtract 0 bv : bvGetBytesU (n-1) (bvShiftRL bv 8)--------------------------------------------- Bits---- | Mask for a specified number of lower bits.-lowMask :: (Integral a, Bits b) => a -> b-lowMask numBits = complement (complement zeroBits `shiftL` fromIntegral numBits)---- | Truncate to a specified number of lower bits.-truncBits :: (Integral a, Bits b) => a -> b -> b-truncBits width b = b .&. lowMask width--------------------------------------------- Class instances-$(return [])--instance Show (BitVector w) where-  show (BV _ x) = "0x" ++ showHex x ""--instance KnownNat w => Read (BitVector w) where-  readsPrec s =-    (fmap . fmap) (\(a,s') -> (bitVector a, s')) (readsPrec s :: ReadS Integer)--instance ShowF BitVector--instance Eq (BitVector w) where-  (BV _ x) == (BV _ y) = x == y--instance EqF BitVector where-  (BV _ x) `eqF` (BV _ y) = x == y--instance Ord (BitVector w) where-  (BV _ x) `compare` (BV _ y) = x `compare` y--instance OrdF BitVector where-  (BV xRepr x) `compareF` (BV yRepr y) =-    case xRepr `compareF` yRepr of-      EQF -> fromOrdering (x `compare` y)-      cmp -> cmp--instance TestEquality BitVector where-  testEquality (BV wRepr x) (BV wRepr' y) =-    if natValue wRepr == natValue wRepr' && x == y-    then Just (unsafeCoerce (Refl :: a :~: a))-    else Nothing--instance KnownNat w => Bits (BitVector w) where-  (.&.)        = bvAnd-  (.|.)        = bvOr-  xor          = bvXor-  complement   = bvComplement-  shift        = bvShift-  rotate       = bvRotate-  bitSize      = bvWidth-  bitSizeMaybe = Just . bvWidth-  isSigned     = const False-  testBit      = bvTestBit-  bit          = bitVector . (bit :: Int -> Integer)-  popCount     = bvPopCount--instance KnownNat w => FiniteBits (BitVector w) where-  finiteBitSize = bvWidth--instance KnownNat w => Num (BitVector w) where-  (+)         = bvAdd-  (*)         = bvMul-  abs         = bvAbs-  signum      = bvSignum-  fromInteger = bitVector-  negate      = bvNegate--instance KnownNat w => Enum (BitVector w) where-  toEnum   = bitVector-  fromEnum = fromIntegral . bvIntegerU--instance KnownNat w => Ix (BitVector w) where-  range (lo, hi) = bitVector <$> [bvIntegerU lo .. bvIntegerU hi]-  index (lo, hi) bv = index (bvIntegerU lo, bvIntegerU hi) (bvIntegerU bv)-  inRange (lo, hi) bv = inRange (bvIntegerU lo, bvIntegerU hi) (bvIntegerU bv)--instance KnownNat w => Bounded (BitVector w) where-  minBound = bitVector (0 :: Integer)-  maxBound = bitVector ((-1) :: Integer)--instance KnownNat w => Arbitrary (BitVector w) where-  arbitrary = choose (minBound, maxBound)--instance KnownNat w => Random (BitVector w) where-  randomR (bvLo, bvHi) gen =-    let (x, gen') = randomR (bvIntegerU bvLo, bvIntegerU bvHi) gen-    in (bitVector x, gen')-  random gen =-    let (x :: Integer, gen') = random gen-    in (bitVector x, gen')--prettyHex :: (Integral a, PrintfArg a, Show a) => a -> Integer -> String-prettyHex width val = printf format val width-  where -- numDigits = (width+3) `quot` 4-        -- format = "0x%." ++ show numDigits ++ "x<%d>"-        format = "0x%x<%d>"--instance Pretty (BitVector w) where-  -- | Pretty print a bit vector (shows its width)-  pPrint (BV wRepr x) = text $ prettyHex (natValue wRepr) x+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}++{-|+Module      : Data.BitVector.Sized.Internal+Copyright   : (c) Galois Inc. 2018+License     : BSD-3+Maintainer  : benselfridge@galois.com+Stability   : experimental+Portability : portable++Internal hidden module containing all definitions for the 'BV' type.+-}++module Data.BitVector.Sized.Internal where++import Data.BitVector.Sized.Panic (panic)++-- Qualified imports+import qualified Data.Bits                  as B+import qualified Data.Bits.Bitwise          as B+import qualified Data.ByteString as BS+import qualified Numeric                    as N+import qualified Data.Parameterized.NatRepr as P+import qualified Prelude as Prelude++-- Unqualified imports+import Data.Char (intToDigit)+import Data.List (genericLength)+import Data.Int+import Data.Kind (Type)+import Data.Maybe (fromJust)+import Data.Word+import Data.Parameterized ( NatRepr+                          , mkNatRepr+                          , natValue+                          , intValue+                          , addNat+                          , ShowF+                          , EqF(..)+                          , Hashable(..)+                          , Some(..)+                          , Pair(..)+                          )+import GHC.Generics+import GHC.TypeLits+import Language.Haskell.TH.Lift (Lift)+import Numeric.Natural+import Prelude hiding (abs, or, and, negate, concat, signum)++----------------------------------------+-- Utility functions++-- | Check that a 'NatRepr' is representable as an 'Int'.+checkNatRepr :: NatRepr w -> a -> a+checkNatRepr = checkNatural . natValue++-- | Check that a 'Natural' is representable as an 'Int'.+checkNatural :: Natural -> a -> a+checkNatural n a = if n > (fromIntegral (maxBound :: Int) :: Natural)+  then panic "Data.BitVector.Sized.Internal.checkNatural"+       [show n ++ " not representable as Int"]+  else a+++-- | Unsafe coercion from @Natural@ to @Int@.  We mostly use this to+--   interact with operations from "Data.Bits".  This should only be+--   called when we already know the input @Natural@ is small enough,+--   e.g., because we previously called @checkNatural@.+fromNatural :: Natural -> Int+fromNatural = fromIntegral++----------------------------------------+-- BitVector data type definitions++-- | Bitvector datatype, parameterized by width.+data BV (w :: Nat) :: Type where+  -- | We store the value as an 'Integer' rather than a 'Natural',+  -- since many of the operations on bitvectors rely on a two's+  -- complement representation. However, an invariant on the value is+  -- that it must always be positive.+  --+  -- Secondly, we maintain the invariant that any constructed BV value+  -- has a width whose value is representable in a Haskell @Int@.+  BV :: Integer -> BV w++  deriving (Generic, Show, Read, Eq, Ord, Lift)++instance ShowF BV++instance EqF BV where+  BV bv `eqF` BV bv' = bv == bv'++instance Hashable (BV w) where+  hashWithSalt salt (BV i) = hashWithSalt salt i++----------------------------------------+-- BV construction+-- | Internal function for masking the input integer *without*+-- checking that the width is representable as an 'Int'. We use this+-- instead of 'mkBV' whenever we already have some guarantee that the+-- width is legal.+mkBV' :: NatRepr w -> Integer -> BV w+mkBV' w x = BV (P.toUnsigned w x)++-- | Construct a bitvector with a particular width, where the width is+-- provided as an explicit `NatRepr` argument. The input 'Integer',+-- whether positive or negative, is silently truncated to fit into the+-- number of bits demanded by the return type. The width cannot be+-- arbitrarily large; it must be representable as an 'Int'.+--+-- >>> mkBV (knownNat @4) 10+-- BV 10+-- >>> mkBV (knownNat @2) 10+-- BV 2+-- >>> mkBV (knownNat @4) (-2)+-- BV 14+mkBV :: NatRepr w+     -- ^ Desired bitvector width+     -> Integer+     -- ^ Integer value to truncate to bitvector width+     -> BV w+mkBV w x = checkNatRepr w $ mkBV' w x++-- | Return 'Nothing' if the unsigned 'Integer' does not fit in the+-- required number of bits, otherwise return the input.+checkUnsigned :: NatRepr w+              -> Integer+              -> Maybe Integer+checkUnsigned w i = if i < 0 || i > P.maxUnsigned w+  then Nothing+  else Just i++-- | Like 'mkBV', but returns 'Nothing' if unsigned input integer cannot be+-- represented in @w@ bits.+mkBVUnsigned :: NatRepr w+             -- ^ Desired bitvector width+             -> Integer+             -- ^ Integer value+             -> Maybe (BV w)+mkBVUnsigned w x = checkNatRepr w $ BV <$> checkUnsigned w x++-- | Return 'Nothing if the signed 'Integer' does not fit in the+-- required number of bits, otherwise return an unsigned positive+-- integer that fits in @w@ bits.+signedToUnsigned :: 1 <= w => NatRepr w+                 -- ^ Width of output+                 -> Integer+                 -> Maybe Integer+signedToUnsigned w i = if i < P.minSigned w || i > P.maxSigned w+  then Nothing+  else Just $ if i < 0 then i + P.maxUnsigned w + 1 else i++-- | Like 'mkBV', but returns 'Nothing' if signed input integer cannot+-- be represented in @w@ bits.+mkBVSigned :: 1 <= w => NatRepr w+              -- ^ Desired bitvector width+           -> Integer+           -- ^ Integer value+           -> Maybe (BV w)+mkBVSigned w x = checkNatRepr w $ BV <$> signedToUnsigned w x++-- | The minimum unsigned value for bitvector with given width (always 0).+minUnsigned :: NatRepr w -> BV w+minUnsigned w = checkNatRepr w $ BV 0++-- | The maximum unsigned value for bitvector with given width.+maxUnsigned :: NatRepr w -> BV w+maxUnsigned w = checkNatRepr w $ BV (P.maxUnsigned w)++-- | The minimum value for bitvector in two's complement with given width.+minSigned :: 1 <= w => NatRepr w -> BV w+minSigned w = mkBV w (P.minSigned w)++-- | The maximum value for bitvector in two's complement with given width.+maxSigned :: 1 <= w => NatRepr w -> BV w+maxSigned w = checkNatRepr w $ BV (P.maxSigned w)++-- | @unsignedClamp w i@ rounds @i@ to the nearest value between @0@+-- and @2^w - 1@ (inclusive).+unsignedClamp :: NatRepr w -> Integer -> BV w+unsignedClamp w x = checkNatRepr w $+  if | x < P.minUnsigned w -> BV (P.minUnsigned w)+     | x > P.maxUnsigned w -> BV (P.maxUnsigned w)+     | otherwise -> BV x++-- | @signedClamp w i@ rounds @i@ to the nearest value between+-- @-2^(w-1)@ and @2^(w-1) - 1@ (inclusive).+signedClamp :: 1 <= w => NatRepr w -> Integer -> BV w+signedClamp w x = checkNatRepr w $+  if | x < P.minSigned w -> BV (P.minSigned w)+     | x > P.maxSigned w -> BV (P.maxSigned w)+     | otherwise -> BV x++----------------------------------------+-- Construction from fixed-width data types++-- | Construct a 'BV' from a 'Bool'.+bool :: Bool -> BV 1+bool True = BV 1+bool False = BV 0++-- | Construct a 'BV' from a 'Word8'.+word8 :: Word8 -> BV 8+word8 = BV . toInteger++-- | Construct a 'BV' from a 'Word16'.+word16 :: Word16 -> BV 16+word16 = BV . toInteger++-- | Construct a 'BV' from a 'Word32'.+word32 :: Word32 -> BV 32+word32 = BV . toInteger++-- | Construct a 'BV' from a 'Word64'.+word64 :: Word64 -> BV 64+word64 = BV . toInteger++-- | Construct a 'BV' from an 'Int8'.+int8 :: Int8 -> BV 8+int8 = word8 . (fromIntegral :: Int8 -> Word8)++-- | Construct a 'BV' from an 'Int16'.+int16 :: Int16 -> BV 16+int16 = word16 . (fromIntegral :: Int16 -> Word16)++-- | Construct a 'BV' from an 'Int32'.+int32 :: Int32 -> BV 32+int32 = word32 . (fromIntegral :: Int32 -> Word32)++-- | Construct a 'BV' from an 'Int64'.+int64 :: Int64 -> BV 64+int64 = word64 . (fromIntegral :: Int64 -> Word64)++-- | Construct a 'BV' from a list of bits, in big endian order (bits+-- with lower value index in the list are mapped to higher order bits+-- in the output bitvector). Return the resulting 'BV' along with its+-- width.+--+-- >>> case bitsBE [True, False] of p -> (fstPair p, sndPair p)+-- (2,BV 2)+bitsBE :: [Bool] -> Pair NatRepr BV+bitsBE bs = case mkNatRepr (fromInteger (genericLength bs)) of+  Some w -> checkNatRepr w $ Pair w (BV (B.fromListBE bs))++-- | Construct a 'BV' from a list of bits, in little endian order+-- (bits with lower value index in the list are mapped to lower order+-- bits in the output bitvector). Return the resulting 'BV' along+-- with its width.+--+-- >>> case bitsLE [True, False] of p -> (fstPair p, sndPair p)+-- (2,BV 1)+bitsLE :: [Bool] -> Pair NatRepr BV+bitsLE bs = case mkNatRepr (fromInteger (genericLength bs)) of+  Some w -> checkNatRepr w $ Pair w (BV (B.fromListLE bs))++-- | Convert a 'ByteString' (big-endian) of length @n@ to an 'Integer'+-- with @8*n@ bits. This function uses a balanced binary fold to+-- achieve /O(n log n)/ total memory allocation and run-time, in+-- contrast to the /O(n^2)/ that would be required by a naive+-- left-fold.+bytestringToIntegerBE :: BS.ByteString -> Integer+bytestringToIntegerBE bs+  | l == 0 = 0+  | l == 1 = toInteger (BS.head bs)+  | otherwise = x1 `B.shiftL` (l2 * 8) B..|. x2+  where+    l = BS.length bs+    l1 = l `div` 2+    l2 = l - l1+    (bs1, bs2) = BS.splitAt l1 bs+    x1 = bytestringToIntegerBE bs1+    x2 = bytestringToIntegerBE bs2++bytestringToIntegerLE :: BS.ByteString -> Integer+bytestringToIntegerLE bs+  | l == 0 = 0+  | l == 1 = toInteger (BS.head bs)+  | otherwise = x2 `B.shiftL` (l1 * 8) B..|. x1+  where+    l = BS.length bs+    l1 = l `div` 2+    (bs1, bs2) = BS.splitAt l1 bs+    x1 = bytestringToIntegerLE bs1+    x2 = bytestringToIntegerLE bs2++-- | Construct a 'BV' from a big-endian bytestring.+--+-- >>> case bytestringBE (BS.pack [0, 1, 1]) of p -> (fstPair p, sndPair p)+-- (24,BV 257)+bytestringBE :: BS.ByteString -> Pair NatRepr BV+bytestringBE bs = case mkNatRepr (8*fromIntegral (BS.length bs)) of+  Some w -> checkNatRepr w $ Pair w (BV (bytestringToIntegerBE bs))++-- | Construct a 'BV' from a little-endian bytestring.+--+-- >>> case bytestringLE (BS.pack [0, 1, 1]) of p -> (fstPair p, sndPair p)+-- (24,BV 65792)+bytestringLE :: BS.ByteString -> Pair NatRepr BV+bytestringLE bs = case mkNatRepr (8*fromIntegral (BS.length bs)) of+  Some w -> checkNatRepr w $ Pair w (BV (bytestringToIntegerLE bs))++-- | Construct a 'BV' from a list of bytes, in big endian order (bytes+-- with lower value index in the list are mapped to higher order bytes+-- in the output bitvector).+--+-- >>> case bytesBE [0, 1, 1] of p -> (fstPair p, sndPair p)+-- (24,BV 257)+bytesBE :: [Word8] -> Pair NatRepr BV+bytesBE = bytestringBE . BS.pack++-- | Construct a 'BV' from a list of bytes, in little endian order+-- (bytes with lower value index in the list are mapped to lower+-- order bytes in the output bitvector).+--+-- >>> case bytesLE [0, 1, 1] of p -> (fstPair p, sndPair p)+-- (24,BV 65792)+bytesLE :: [Word8] -> Pair NatRepr BV+bytesLE = bytestringLE . BS.pack++----------------------------------------+-- BitVector -> Integer functions++-- | Unsigned interpretation of a bitvector as a positive Integer.+asUnsigned :: BV w -> Integer+asUnsigned (BV x) = x++-- | Signed interpretation of a bitvector as an Integer.+asSigned :: (1 <= w) => NatRepr w -> BV w -> Integer+asSigned w (BV x) =+  -- NB, fromNatural is OK here because we maintain the invariant that+  --  any existing BV value has a representable width+  let wInt = fromNatural (natValue w) in+  if B.testBit x (wInt - 1)+  then x - B.bit wInt+  else x++-- | Unsigned interpretation of a bitvector as a Natural.+asNatural :: BV w -> Natural+asNatural = (fromInteger :: Integer -> Natural) . asUnsigned++-- | Convert a bitvector to a list of bits, in big endian order+-- (higher order bits in the bitvector are mapped to lower indices in+-- the output list).+--+-- >>> asBitsBE (knownNat @5) (mkBV knownNat 0b1101)+-- [False,True,True,False,True]+asBitsBE :: NatRepr w -> BV w -> [Bool]+asBitsBE w bv = [ testBit' i bv | i <- fromInteger <$> [wi - 1, wi - 2 .. 0] ]+  where wi = intValue w++-- | Convert a bitvector to a list of bits, in little endian order+-- (lower order bits in the bitvector are mapped to lower indices in+-- the output list).+--+-- >>> asBitsLE (knownNat @5) (mkBV knownNat 0b1101)+-- [True,False,True,True,False]+asBitsLE :: NatRepr w -> BV w -> [Bool]+asBitsLE w bv = [ testBit' i bv | i <- fromInteger <$> [0 .. wi - 1] ]+  where wi = intValue w++integerToBytesBE :: Natural+                 -- ^ number of bytes+                 -> Integer+                 -> [Word8]+integerToBytesBE n x =+  [ fromIntegral (x `B.shiftR` (8*ix)) | ix <- [ni-1, ni-2 .. 0] ]+  where ni = fromIntegral n++integerToBytesLE :: Natural+                 -- ^ number of bytes+                 -> Integer+                 -> [Word8]+integerToBytesLE n x =+  [ fromIntegral (x `B.shiftR` (8*ix)) | ix <- [0 .. ni-1] ]+  where ni = fromIntegral n++-- | Convert a bitvector to a list of bytes, in big endian order+-- (higher order bytes in the bitvector are mapped to lower indices in+-- the output list). Return 'Nothing' if the width is not a multiple+-- of 8.+--+-- >>> asBytesBE (knownNat @32) (mkBV knownNat 0xaabbccdd)+-- Just [170,187,204,221]+asBytesBE :: NatRepr w -> BV w -> Maybe [Word8]+asBytesBE w (BV x)+  | natValue w `mod` 8 == 0 = Just $ integerToBytesBE (natValue w `div` 8) x+  | otherwise = Nothing++-- | Convert a bitvector to a list of bytes, in little endian order+-- (lower order bytes in the bitvector are mapped to lower indices in+-- the output list). Return 'Nothing' if the width is not a multiple+-- of 8.+--+-- >>> asBytesLE (knownNat @32) (mkBV knownNat 0xaabbccdd)+-- Just [221,204,187,170]+asBytesLE :: NatRepr w -> BV w -> Maybe [Word8]+asBytesLE w (BV x)+  | natValue w `mod` 8 == 0 = Just $ integerToBytesLE (natValue w `div` 8) x+  | otherwise = Nothing++-- | 'asBytesBE', but for bytestrings.+asBytestringBE :: NatRepr w -> BV w -> Maybe BS.ByteString+asBytestringBE w bv = BS.pack <$> asBytesBE w bv++-- | 'asBytesLE', but for bytestrings.+asBytestringLE :: NatRepr w -> BV w -> Maybe BS.ByteString+asBytestringLE w bv = BS.pack <$> asBytesLE w bv++----------------------------------------+-- BV w operations (fixed width)++-- | Bitwise and.+and :: BV w -> BV w -> BV w+and (BV x) (BV y) = BV (x B..&. y)++-- | Bitwise or.+or :: BV w -> BV w -> BV w+or (BV x) (BV y) = BV (x B..|. y)++-- | Bitwise xor.+xor :: BV w -> BV w -> BV w+xor (BV x) (BV y) = BV (x `B.xor` y)++-- | Bitwise complement (flip every bit).+complement :: NatRepr w -> BV w -> BV w+complement w (BV x) = mkBV' w (B.complement x)+++-- | Clamp shift amounts to the word width and+--   coerce to an @Int@+shiftAmount :: NatRepr w -> Natural -> Int+shiftAmount w shf = fromNatural (min (natValue w) shf)++-- | Left shift by positive 'Natural'.+shl :: NatRepr w -> BV w -> Natural -> BV w+shl w (BV x) shf = mkBV' w (x `B.shiftL` shiftAmount w shf)++-- | Right arithmetic shift by positive 'Natural'.+ashr :: (1 <= w) => NatRepr w -> BV w -> Natural -> BV w+ashr w bv shf = mkBV' w (asSigned w bv `B.shiftR` shiftAmount w shf)++-- | Right logical shift by positive 'Natural'.+lshr :: NatRepr w -> BV w -> Natural -> BV w+lshr w (BV x) shf =+  -- Shift right (logical by default since the value is positive). No+  -- need to truncate bits, since the result is guaranteed to occupy+  -- no more bits than the input.+  BV (x `B.shiftR` shiftAmount w shf)++-- | Bitwise rotate left.+rotateL :: NatRepr w -> BV w -> Natural -> BV w+rotateL w bv rot' = leftChunk `or` rightChunk+  where rot = rot' `mod` wNatural+        leftChunk = shl w bv rot+        rightChunk = lshr w bv (wNatural - rot)+        wNatural = natValue w++-- | Bitwise rotate right.+rotateR :: NatRepr w -> BV w -> Natural -> BV w+rotateR w bv rot' = leftChunk `or` rightChunk+  where rot = rot' `mod` wNatural+        rightChunk = lshr w bv rot+        leftChunk = shl w bv (wNatural - rot)+        wNatural = natValue w++-- | The zero bitvector of any width.+zero :: NatRepr w -> BV w+zero w = checkNatRepr w $ BV 0++-- | The bitvector with value 1, of any positive width.+one :: 1 <= w => NatRepr w -> BV w+one w = checkNatRepr w $ BV 1++-- | The bitvector whose value is its own width, of any width.+width :: NatRepr w -> BV w+width w = checkNatRepr w $ BV (intValue w)++-- | The 'BV' that has a particular bit set, and is 0 everywhere+-- else.+bit :: ix+1 <= w+    => NatRepr w+    -- ^ Desired output width+    -> NatRepr ix+    -- ^ Index of bit to set+    -> BV w+bit w ix =+  checkNatRepr w $+    -- NB fromNatural is OK here because of the (ix+1<w) constraint+    BV (B.bit (fromNatural (natValue ix)))++-- | Like 'bit', but without the requirement that the index bit refers+-- to an actual bit in the output 'BV'. If it is out of range, just+-- silently return the zero bitvector.+bit' :: NatRepr w+     -- ^ Desired output width+     -> Natural+     -- ^ Index of bit to set+     -> BV w+bit' w ix+  | ix < natValue w = checkNatRepr w $ mkBV' w (B.bit (fromNatural ix))+  | otherwise = zero w++-- | @setBit bv ix@ is the same as @or bv (bit knownNat ix)@.+setBit :: ix+1 <= w+       => NatRepr ix+       -- ^ Index of bit to set+       -> BV w+       -- ^ Original bitvector+       -> BV w+setBit ix bv =+  -- NB, fromNatural is OK because of the (ix+1 <= w) constraint+  or bv (BV (B.bit (fromNatural (natValue ix))))++-- | Like 'setBit', but without the requirement that the index bit+-- refers to an actual bit in the input 'BV'. If it is out of range,+-- just silently return the original input.+setBit' :: NatRepr w+        -- ^ Desired output width+        -> Natural+        -- ^ Index of bit to set+        -> BV w+        -- ^ Original bitvector+        -> BV w+setBit' w ix bv+  | ix < natValue w = or bv (BV (B.bit (fromNatural ix)))+  | otherwise = bv++-- | @clearBit w bv ix@ is the same as @and bv (complement (bit w ix))@.+clearBit :: ix+1 <= w+         => NatRepr w+         -- ^ Desired output width+         -> NatRepr ix+         -- ^ Index of bit to clear+         -> BV w+         -- ^ Original bitvector+         -> BV w+clearBit w ix bv =+  -- NB, fromNatural is OK because of the (ix+1<=w) constraint+  and bv (complement w (BV (B.bit (fromNatural (natValue ix)))))+++-- | Like 'clearBit', but without the requirement that the index bit+-- refers to an actual bit in the input 'BV'. If it is out of range,+-- just silently return the original input.+clearBit' :: NatRepr w+          -- ^ Desired output width+          -> Natural+          -- ^ Index of bit to clear+          -> BV w+          -- ^ Original bitvector+          -> BV w+clearBit' w ix bv+  | ix < natValue w = and bv (complement w (BV (B.bit (fromNatural ix))))+  | otherwise = bv++-- | @complementBit bv ix@ is the same as @xor bv (bit knownNat ix)@.+complementBit :: ix+1 <= w+              => NatRepr ix+              -- ^ Index of bit to flip+              -> BV w+              -- ^ Original bitvector+              -> BV w+complementBit ix bv =+  -- NB, fromNatural is OK because of (ix+1 <= w) constraint+  xor bv (BV (B.bit (fromNatural (natValue ix))))++-- | Like 'complementBit', but without the requirement that the index+-- bit refers to an actual bit in the input 'BV'. If it is out of+-- range, just silently return the original input.+complementBit' :: NatRepr w+               -- ^ Desired output width+               -> Natural+               -- ^ Index of bit to flip+               -> BV w+               -- ^ Original bitvector+               -> BV w+complementBit' w ix bv+  | ix < natValue w = xor bv (BV (B.bit (fromNatural ix)))+  | otherwise = bv++-- | Test if a particular bit is set.+testBit :: ix+1 <= w => NatRepr ix -> BV w -> Bool+testBit ix (BV x) = B.testBit x (fromNatural (natValue ix))++-- | Like 'testBit', but takes a 'Natural' for the bit index. If the+-- index is out of bounds, return 'False'.+testBit' :: Natural -> BV w -> Bool+testBit' ix (BV x)+  -- NB, If the index is larger than the maximum representable 'Int',+  -- this function should be 'False' by construction of 'BV'.+  | ix > fromIntegral (maxBound :: Int) = False+  | otherwise = B.testBit x (fromNatural ix)++-- | Get the number of 1 bits in a 'BV'.+popCount :: BV w -> BV w+popCount (BV x) = BV (toInteger (B.popCount x))++-- | Count trailing zeros in a 'BV'.+ctz :: NatRepr w -> BV w -> BV w+ctz w (BV x) = BV (go 0)+  where go !i | i < intValue w &&+                B.testBit x (fromInteger i) == False = go (i+1)+              | otherwise = i++-- | Count leading zeros in a 'BV'.+clz :: NatRepr w -> BV w -> BV w+clz w (BV x) = BV (go 0)+ where go !i | i < intValue w &&+               B.testBit x (fromInteger (intValue w - i - 1)) == False =+                 go (i+1)+             | otherwise = i++-- | Truncate a bitvector to a particular width given at runtime,+-- while keeping the type-level width constant.+truncBits :: Natural -> BV w -> BV w+truncBits b (BV x) = checkNatural b $ BV (x B..&. (B.bit (fromNatural b) - 1))++----------------------------------------+-- BV w arithmetic operations (fixed width)++-- | Bitvector add.+add :: NatRepr w -> BV w -> BV w -> BV w+add w (BV x) (BV y) = mkBV' w (x+y)++-- | Bitvector subtract.+sub :: NatRepr w -> BV w -> BV w -> BV w+sub w (BV x) (BV y) = mkBV' w (x-y)++-- | Bitvector multiply.+mul :: NatRepr w -> BV w -> BV w -> BV w+mul w (BV x) (BV y) = mkBV' w (x*y)++-- | Bitvector division (unsigned). Rounds to zero. Division by zero+-- yields a runtime error.+uquot :: BV w -> BV w -> BV w+uquot (BV x) (BV y) = BV (x `quot` y)++-- | Bitvector remainder after division (unsigned), when rounded to+-- zero. Division by zero yields a runtime error.+urem :: BV w -> BV w -> BV w+urem (BV x) (BV y) = BV (x `rem` y)++-- | 'uquot' and 'urem' returned as a pair.+uquotRem :: BV w -> BV w -> (BV w, BV w)+uquotRem bv1 bv2 = (uquot bv1 bv2, urem bv1 bv2)++-- | Bitvector division (signed). Rounds to zero. Division by zero+-- yields a runtime error.+squot :: (1 <= w) => NatRepr w -> BV w -> BV w -> BV w+squot w bv1 bv2 = mkBV' w (x `quot` y)+  where x = asSigned w bv1+        y = asSigned w bv2++-- | Bitvector remainder after division (signed), when rounded to+-- zero. Division by zero yields a runtime error.+srem :: (1 <= w) => NatRepr w -> BV w -> BV w -> BV w+srem w bv1 bv2 = mkBV' w (x `rem` y)+  where x = asSigned w bv1+        y = asSigned w bv2++-- | 'squot' and 'srem' returned as a pair.+squotRem :: (1 <= w) => NatRepr w -> BV w -> BV w -> (BV w, BV w)+squotRem w bv1 bv2 = (squot w bv1 bv2, srem w bv1 bv2)++-- | Bitvector division (signed). Rounds to negative infinity. Division+-- by zero yields a runtime error.+sdiv :: (1 <= w) => NatRepr w -> BV w -> BV w -> BV w+sdiv w bv1 bv2 = mkBV' w (x `div` y)+  where x = asSigned w bv1+        y = asSigned w bv2++-- | Bitvector remainder after division (signed), when rounded to+-- negative infinity. Division by zero yields a runtime error.+smod :: (1 <= w) => NatRepr w -> BV w -> BV w -> BV w+smod w bv1 bv2 = mkBV' w (x `mod` y)+  where x = asSigned w bv1+        y = asSigned w bv2++-- | 'sdiv' and 'smod' returned as a pair.+sdivMod :: (1 <= w) => NatRepr w -> BV w -> BV w -> (BV w, BV w)+sdivMod w bv1 bv2 = (sdiv w bv1 bv2, smod w bv1 bv2)++-- | Bitvector absolute value.  Returns the 2's complement+--   magnitude of the bitvector.+abs :: (1 <= w) => NatRepr w -> BV w -> BV w+abs w bv = mkBV' w (Prelude.abs (asSigned w bv))++-- | 2's complement bitvector negation.+negate :: NatRepr w -> BV w -> BV w+negate w (BV x) = mkBV' w (-x)++-- | Get the sign bit as a 'BV'.+signBit :: 1 <= w => NatRepr w -> BV w -> BV w+signBit w bv@(BV _) = lshr w bv (natValue w - 1) `and` BV 1++-- | Return 1 if positive, -1 if negative, and 0 if 0.+signum :: 1 <= w => NatRepr w -> BV w -> BV w+signum w bv = mkBV' w (Prelude.signum (asSigned w bv))++-- | Signed less than.+slt :: (1 <= w) => NatRepr w -> BV w -> BV w -> Bool+slt w bv1 bv2 = asSigned w bv1 < asSigned w bv2++-- | Signed less than or equal.+sle :: (1 <= w) => NatRepr w -> BV w -> BV w -> Bool+sle w bv1 bv2 = asSigned w bv1 <= asSigned w bv2++-- | Unsigned less than.+ult :: BV w -> BV w -> Bool+ult bv1 bv2 = asUnsigned bv1 < asUnsigned bv2++-- | Unsigned less than or equal.+ule :: BV w -> BV w -> Bool+ule bv1 bv2 = asUnsigned bv1 <= asUnsigned bv2++-- | Unsigned minimum of two bitvectors.+umin :: BV w -> BV w -> BV w+umin (BV x) (BV y) = if x < y then BV x else BV y++-- | Unsigned maximum of two bitvectors.+umax :: BV w -> BV w -> BV w+umax (BV x) (BV y) = if x < y then BV y else BV x++-- | Signed minimum of two bitvectors.+smin :: (1 <= w) => NatRepr w -> BV w -> BV w -> BV w+smin w bv1 bv2 = if asSigned w bv1 < asSigned w bv2 then bv1 else bv2++-- | Signed maximum of two bitvectors.+smax :: (1 <= w) => NatRepr w -> BV w -> BV w -> BV w+smax w bv1 bv2 = if asSigned w bv1 < asSigned w bv2 then bv2 else bv1++----------------------------------------+-- Width-changing operations++-- | Concatenate two bitvectors. The first argument gets placed in the+-- higher order bits.+--+-- >>> concat knownNat (mkBV (knownNat @3) 0b001) (mkBV (knownNat @2) 0b10)+-- BV 6+-- >>> :type it+-- it :: BV 5+concat :: NatRepr w+       -- ^ Width of higher-order bits+       -> NatRepr w'+       -- ^ Width of lower-order bits+       -> BV w+       -- ^ Higher-order bits+       -> BV w'+       -- ^ Lower-order bits+       -> BV (w+w')+concat w w' (BV hi) (BV lo) = checkNatRepr (w `addNat` w') $+  BV ((hi `B.shiftL` (fromNatural (natValue w'))) B..|. lo)++-- | Slice out a smaller bitvector from a larger one.+--+-- >>> select (knownNat @4) (knownNat @1) (mkBV (knownNat @12) 0b110010100110)+-- BV 3+-- >>> :type it+-- it :: BV 4+select :: ix + w' <= w+       => NatRepr ix+       -- ^ Index to start selecting from+       -> NatRepr w'+       -- ^ Desired output width+       -> BV w+       -- ^ Bitvector to select from+       -> BV w'+select ix w' (BV x) = mkBV' w' xShf+  -- NB fromNatural is OK because of (ix + w' <= w) constraint+  where xShf = x `B.shiftR` (fromNatural (natValue ix))++-- | Like 'select', but takes a 'Natural' as the index to start+-- selecting from. Neither the index nor the output width is checked+-- to ensure the resulting 'BV' lies entirely within the bounds of the+-- original bitvector. Any bits "selected" from beyond the bounds of+-- the input bitvector will be 0.+--+-- >>> select' (knownNat @4) 9 (mkBV (knownNat @12) 0b110010100110)+-- BV 6+-- >>> :type it+-- it :: BV 4+select' :: Natural+        -- ^ Index to start selecting from+        -> NatRepr w'+        -- ^ Desired output width+        -> BV w+        -- ^ Bitvector to select from+        -> BV w'+select' ix w' (BV x)+  | toInteger ix < toInteger (maxBound :: Int) = mkBV w' (x `B.shiftR` (fromNatural ix))+  | otherwise = zero w'++-- | Zero-extend a bitvector to one of strictly greater width.+--+-- >>> zext (knownNat @8) (mkBV (knownNat @4) 0b1101)+-- BV 13+-- >>> :type it+-- it :: BV 8+zext :: w + 1 <= w'+     => NatRepr w'+     -- ^ Desired output width+     -> BV w+     -- ^ Bitvector to extend+     -> BV w'+zext w (BV x) = checkNatRepr w $ BV x++-- | Sign-extend a bitvector to one of strictly greater width.+sext :: (1 <= w, w + 1 <= w')+     => NatRepr w+     -- ^ Width of input bitvector+     -> NatRepr w'+     -- ^ Desired output width+     -> BV w+     -- ^ Bitvector to extend+     -> BV w'+sext w w' bv = mkBV w' (asSigned w bv)++-- | Truncate a bitvector to one of strictly smaller width.+trunc :: w' + 1 <= w+      => NatRepr w'+      -- ^ Desired output width+      -> BV w+      -- ^ Bitvector to truncate+      -> BV w'+trunc w' (BV x) = mkBV' w' x++-- | Like 'trunc', but allows the input width to be greater than or+-- equal to the output width, in which case it just performs a zero+-- extension.+trunc' :: NatRepr w'+       -- ^ Desired output width+       -> BV w+       -- ^ Bitvector to truncate+       -> BV w'+trunc' w' (BV x) = mkBV w' x++-- | Wide multiply of two bitvectors.+mulWide :: NatRepr w -> NatRepr w' -> BV w -> BV w' -> BV (w+w')+mulWide w w' (BV x) (BV y) = checkNatRepr (w `addNat` w') $ BV (x*y)++----------------------------------------+-- Enum functions++-- | Unsigned successor. @succUnsigned w (maxUnsigned w)@ returns 'Nothing'.+succUnsigned :: NatRepr w -> BV w -> Maybe (BV w)+succUnsigned w (BV x) =+  if x == P.maxUnsigned w+  then Nothing+  else Just (BV (x+1))++-- | Signed successor. @succSigned w (maxSigned w)@ returns 'Nothing'.+succSigned :: 1 <= w => NatRepr w -> BV w -> Maybe (BV w)+succSigned w (BV x) =+  if x == P.maxSigned w+  then Nothing+  else Just (mkBV' w (x+1))++-- | Unsigned predecessor. @predUnsigned w zero@ returns 'Nothing'.+predUnsigned :: NatRepr w -> BV w -> Maybe (BV w)+predUnsigned w (BV x) =+  if x == P.minUnsigned w+  then Nothing+  else Just (BV (x-1))++-- | Signed predecessor. @predSigned w (minSigned w)@ returns 'Nothing'.+predSigned :: 1 <= w => NatRepr w -> BV w -> Maybe (BV w)+predSigned w bv@(BV x) =+  if bv == minSigned w+  then Nothing+  else Just (mkBV' w (x-1))++-- | List of all unsigned bitvectors from a lower to an upper bound,+-- inclusive.+enumFromToUnsigned :: BV w+                   -- ^ Lower bound+                   -> BV w+                   -- ^ Upper bound+                   -> [BV w]+enumFromToUnsigned bv1 bv2 = BV <$> [asUnsigned bv1 .. asUnsigned bv2]++-- | List of all signed bitvectors from a lower to an upper bound,+-- inclusive.+enumFromToSigned :: 1 <= w => NatRepr w+                 -> BV w+                 -- ^ Lower bound+                 -> BV w+                 -- ^ Upper bound+                 -> [BV w]+enumFromToSigned w bv1 bv2 = (BV . fromJust . signedToUnsigned w) <$> [asSigned w bv1 .. asSigned w bv2]++----------------------------------------+-- Pretty printing++-- | Pretty print in hex+ppHex :: NatRepr w -> BV w -> String+ppHex w (BV x) = "0x" ++ N.showHex x "" ++ ":" ++ ppWidth w++-- | Pretty print in binary+ppBin :: NatRepr w -> BV w -> String+ppBin w (BV x) = "0b" ++ N.showIntAtBase 2 intToDigit x "" ++ ":" ++ ppWidth w++-- | Pretty print in octal+ppOct :: NatRepr w -> BV w -> String+ppOct w (BV x) = "0o" ++ N.showOct x "" ++ ":" ++ ppWidth w++-- | Pretty print in decimal+ppDec :: NatRepr w -> BV w -> String+ppDec w (BV x) = show x ++ ":" ++ ppWidth w++ppWidth :: NatRepr w -> String+ppWidth w = "[" ++ show (natValue w) ++ "]"
+ src/Data/BitVector/Sized/Overflow.hs view
@@ -0,0 +1,216 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE TypeOperators #-}++{-|+Module      : Data.BitVector.Sized.Overflow+Copyright   : (c) Galois Inc. 2020+License     : BSD-3+Maintainer  : Ben Selfridge <benselfridge@galois.com>+Stability   : experimental+Portability : portable++This module provides alternative definitions of certain bitvector+functions that might produce signed or unsigned overflow. Instead of+producing a pure value, these versions produce the same value along+with overflow flags. We only provide definitions for operators that+might actually overflow.++-}++module Data.BitVector.Sized.Overflow+  ( Overflow(..)+  , UnsignedOverflow(..)+  , SignedOverflow(..)+  , ofUnsigned+  , ofSigned+  , ofResult+  -- * Overflowing bitwise operators+  , shlOf+  -- * Overflowing arithmetic operators+  , addOf+  , subOf+  , mulOf+  , squotOf+  , sremOf+  , sdivOf+  , smodOf+  ) where++import qualified Data.Bits as B+import Numeric.Natural+import GHC.TypeLits++import Data.Parameterized ( NatRepr )+import qualified Data.Parameterized.NatRepr as P++import Data.BitVector.Sized.Internal ( BV(..)+                                     , mkBV'+                                     , asUnsigned+                                     , asSigned+                                     , shiftAmount+                                     )+++----------------------------------------+-- Unsigned and signed overflow datatypes++-- | Datatype representing the possibility of unsigned overflow.+data UnsignedOverflow = UnsignedOverflow+                      | NoUnsignedOverflow+  deriving (Show, Eq)++instance Semigroup UnsignedOverflow where+  NoUnsignedOverflow <> NoUnsignedOverflow = NoUnsignedOverflow+  _ <> _ = UnsignedOverflow++instance Monoid UnsignedOverflow where+  mempty = NoUnsignedOverflow++-- | Datatype representing the possibility of signed overflow.+data SignedOverflow = SignedOverflow+                    | NoSignedOverflow+  deriving (Show, Eq)++instance Semigroup SignedOverflow where+  NoSignedOverflow <> NoSignedOverflow = NoSignedOverflow+  _ <> _ = SignedOverflow++instance Monoid SignedOverflow where+  mempty = NoSignedOverflow++----------------------------------------+-- Overflow wrapper+-- | A value annotated with overflow information.+data Overflow a =+  Overflow UnsignedOverflow SignedOverflow a+  deriving (Show, Eq)++-- | Return 'True' if a computation caused unsigned overflow.+ofUnsigned :: Overflow a -> Bool+ofUnsigned (Overflow UnsignedOverflow _ _) = True+ofUnsigned _ = False++-- | Return 'True' if a computation caused signed overflow.+ofSigned :: Overflow a -> Bool+ofSigned (Overflow _ SignedOverflow _) = True+ofSigned _ = False++-- | Return the result of a computation.+ofResult :: Overflow a -> a+ofResult (Overflow _ _ res) = res++instance Foldable Overflow where+  foldMap f (Overflow _ _ a) = f a++instance Traversable Overflow where+  sequenceA (Overflow uof sof a) = Overflow uof sof <$> a++instance Functor Overflow where+  fmap f (Overflow uof sof a) = Overflow uof sof (f a)++instance Applicative Overflow where+  pure a = Overflow mempty mempty a+  Overflow uof sof f <*> Overflow uof' sof' a =+    Overflow (uof <> uof') (sof <> sof') (f a)++-- | Monad for bitvector operations which might produce signed or+-- unsigned overflow.+instance Monad Overflow where+  Overflow uof sof a >>= k =+    let Overflow uof' sof' b = k a+    in Overflow (uof <> uof') (sof <> sof') b++getUof :: NatRepr w -> Integer -> UnsignedOverflow+getUof w x = if x < P.minUnsigned w || x > P.maxUnsigned w+             then UnsignedOverflow+             else NoUnsignedOverflow++getSof :: NatRepr w -> Integer -> SignedOverflow+getSof w x = case P.isZeroOrGT1 w of+  Left P.Refl -> NoSignedOverflow+  Right P.LeqProof ->+    if x < P.minSigned w || x > P.maxSigned w+    then SignedOverflow+    else NoSignedOverflow++-- | This only works if the operation has equivalent signed and+-- unsigned interpretations on bitvectors.+liftBinary :: (1 <= w) => (Integer -> Integer -> Integer)+           -> NatRepr w+           -> BV w -> BV w -> Overflow (BV w)+liftBinary op w xv yv =+  let ux = asUnsigned xv+      uy = asUnsigned yv+      sx = asSigned w xv+      sy = asSigned w yv++      ures = ux `op` uy+      sres = sx `op` sy++      uof = getUof w ures+      sof = getSof w sres+  in Overflow uof sof (mkBV' w ures)++-- | Bitvector add.+addOf :: (1 <= w) => NatRepr w -> BV w -> BV w -> Overflow (BV w)+addOf = liftBinary (+)++-- | Bitvector subtract.+subOf :: (1 <= w) => NatRepr w -> BV w -> BV w -> Overflow (BV w)+subOf = liftBinary (-)++-- | Bitvector multiply.+mulOf :: (1 <= w) => NatRepr w -> BV w -> BV w -> Overflow (BV w)+mulOf = liftBinary (*)++-- | Left shift by positive 'Natural'.+shlOf :: (1 <= w) => NatRepr w -> BV w -> Natural -> Overflow (BV w)+shlOf w xv shf =+  let ux = asUnsigned xv+      sx = asSigned w xv+      ures = ux `B.shiftL` shiftAmount w shf+      sres = sx `B.shiftL` shiftAmount w shf+      uof = getUof w ures+      sof = getSof w sres+  in Overflow uof sof (mkBV' w ures)++-- | Bitvector division (signed). Rounds to zero. Division by zero+-- yields a runtime error.+squotOf :: (1 <= w) => NatRepr w -> BV w -> BV w -> Overflow (BV w)+squotOf w bv1 bv2 = Overflow NoUnsignedOverflow sof (mkBV' w (x `quot` y))+  where x = asSigned w bv1+        y = asSigned w bv2+        sof = if (x == P.minSigned w && y == -1)+              then SignedOverflow+              else NoSignedOverflow++-- | Bitvector remainder after division (signed), when rounded to+-- zero. Division by zero yields a runtime error.+sremOf :: (1 <= w) => NatRepr w -> BV w -> BV w -> Overflow (BV w)+sremOf w bv1 bv2 = Overflow NoUnsignedOverflow sof (mkBV' w (x `rem` y))+  where x = asSigned w bv1+        y = asSigned w bv2+        sof = if (x == P.minSigned w && y == -1)+              then SignedOverflow+              else NoSignedOverflow++-- | Bitvector division (signed). Rounds to zero. Division by zero+-- yields a runtime error.+sdivOf :: (1 <= w) => NatRepr w -> BV w -> BV w -> Overflow (BV w)+sdivOf w bv1 bv2 = Overflow NoUnsignedOverflow sof (mkBV' w (x `div` y))+  where x = asSigned w bv1+        y = asSigned w bv2+        sof = if (x == P.minSigned w && y == -1)+              then SignedOverflow+              else NoSignedOverflow++-- | Bitvector remainder after division (signed), when rounded to+-- zero. Division by zero yields a runtime error.+smodOf :: (1 <= w) => NatRepr w -> BV w -> BV w -> Overflow (BV w)+smodOf w bv1 bv2 = Overflow NoUnsignedOverflow sof (mkBV' w (x `mod` y))+  where x = asSigned w bv1+        y = asSigned w bv2+        sof = if (x == P.minSigned w && y == -1)+              then SignedOverflow+              else NoSignedOverflow
+ src/Data/BitVector/Sized/Panic.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE TemplateHaskell #-}++module Data.BitVector.Sized.Panic+  ( panic+  ) where++import Panic hiding (panic)+import qualified Panic++data BVSized = BVSized++panic :: String -> [String] -> a+panic = Panic.panic BVSized++instance PanicComponent BVSized where+  panicComponentName _ = "bv-sized"+  panicComponentIssues _ = "https://github.com/GaloisInc/bv-sized/issues"++  {-# Noinline panicComponentRevision #-}+  panicComponentRevision = $useGitRevision
+ src/Data/BitVector/Sized/Signed.hs view
@@ -0,0 +1,128 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeApplications #-}++{-|+Module      : Data.BitVector.Sized.Signed+Copyright   : (c) Galois Inc. 2018+License     : BSD-3+Maintainer  : benselfridge@galois.com+Stability   : experimental+Portability : portable++This module defines a wrapper around the 'BV' type, 'SignedBV', with+instances not provided by 'BV'.+-}++module Data.BitVector.Sized.Signed+  ( SignedBV(..)+  , mkSignedBV+  ) where++import           Data.BitVector.Sized (BV, mkBV)+import qualified Data.BitVector.Sized.Internal as BV+import           Data.BitVector.Sized.Panic (panic)+import Data.Parameterized.NatRepr++import Data.Bits (Bits(..), FiniteBits(..))+import Data.Ix+import GHC.Generics+import GHC.TypeLits+import Numeric.Natural++-- | Signed bit vector.+newtype SignedBV w = SignedBV (BV w)+  deriving (Generic, Show, Read, Eq)++-- | Convenience wrapper for 'BV.mkBV'.+mkSignedBV :: NatRepr w -> Integer -> SignedBV w+mkSignedBV w x = SignedBV (BV.mkBV w x)++instance (KnownNat w, 1 <= w) => Ord (SignedBV w) where+  SignedBV bv1 `compare` SignedBV bv2 =+    if | bv1 == bv2              -> EQ+       | BV.slt knownNat bv1 bv2 -> LT+       | otherwise               -> GT++liftUnary :: (BV w -> BV w)+          -> SignedBV w+          -> SignedBV w+liftUnary op (SignedBV bv) = SignedBV (op bv)++liftBinary :: (BV w -> BV w -> BV w)+           -> SignedBV w+           -> SignedBV w+           -> SignedBV w+liftBinary op (SignedBV bv1) (SignedBV bv2) = SignedBV (op bv1 bv2)++liftBinaryInt :: (BV w -> Natural -> BV w)+              -> SignedBV w+              -> Int+              -> SignedBV w+liftBinaryInt op (SignedBV bv) i = SignedBV (op bv (intToNatural i))++intToNatural :: Int -> Natural+intToNatural = fromIntegral++instance (KnownNat w, 1 <= w) => Bits (SignedBV w) where+  (.&.)        = liftBinary BV.and+  (.|.)        = liftBinary BV.or+  xor          = liftBinary BV.xor+  complement   = liftUnary (BV.complement knownNat)+  shiftL       = liftBinaryInt (BV.shl knownNat)+  shiftR       = liftBinaryInt (BV.ashr knownNat)+  rotateL      = liftBinaryInt (BV.rotateL knownNat)+  rotateR      = liftBinaryInt (BV.rotateR knownNat)+  bitSize _    = widthVal (knownNat @w)+  bitSizeMaybe _ = Just (widthVal (knownNat @w))+  isSigned     = const True+  testBit (SignedBV bv) ix = BV.testBit' (intToNatural ix) bv+  bit          = SignedBV . BV.bit' knownNat . intToNatural+  popCount (SignedBV bv) = fromInteger (BV.asUnsigned (BV.popCount bv))++instance (KnownNat w, 1 <= w) => FiniteBits (SignedBV w) where+  finiteBitSize _ = widthVal (knownNat @w)+  countLeadingZeros  (SignedBV bv) = fromInteger $ BV.asUnsigned $ BV.clz knownNat bv+  countTrailingZeros (SignedBV bv) = fromInteger $ BV.asUnsigned $ BV.ctz knownNat bv++instance (KnownNat w, 1 <= w) => Num (SignedBV w) where+  (+)         = liftBinary (BV.add knownNat)+  (*)         = liftBinary (BV.mul knownNat)+  abs         = liftUnary (BV.abs knownNat)+  signum (SignedBV bv) = mkSignedBV knownNat $ signum $ BV.asSigned knownNat bv+  fromInteger = SignedBV . mkBV knownNat+  negate      = liftUnary (BV.negate knownNat)++instance (KnownNat w, 1 <= w) => Enum (SignedBV w) where+  toEnum = SignedBV . mkBV knownNat . checkInt+    where checkInt i | lo <= toInteger i && toInteger i <= hi = toInteger i+                     | otherwise = panic "Data.BitVector.Sized.Signed"+                                   ["toEnum: bad argument"]+            where lo = minSigned (knownNat @w)+                  hi = maxSigned (knownNat @w)++  fromEnum (SignedBV bv) = fromInteger (BV.asSigned (knownNat @w) bv)++instance (KnownNat w, 1 <= w) => Ix (SignedBV w) where+  range (SignedBV loBV, SignedBV hiBV) =+    (SignedBV . mkBV knownNat) <$>+    [BV.asSigned knownNat loBV .. BV.asSigned knownNat hiBV]+  index (SignedBV loBV, SignedBV hiBV) (SignedBV ixBV) =+    index ( BV.asSigned knownNat loBV+          , BV.asSigned knownNat hiBV)+    (BV.asSigned knownNat ixBV)+  inRange (SignedBV loBV, SignedBV hiBV) (SignedBV ixBV) =+    inRange ( BV.asSigned knownNat loBV+            , BV.asSigned knownNat hiBV)+    (BV.asSigned knownNat ixBV)++instance (KnownNat w, 1 <= w) => Bounded (SignedBV w) where+  minBound = SignedBV (BV.minSigned knownNat)+  maxBound = SignedBV (BV.maxSigned knownNat)
+ src/Data/BitVector/Sized/Unsigned.hs view
@@ -0,0 +1,120 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeApplications #-}++{-|+Module      : Data.BitVector.Sized.Unsigned+Copyright   : (c) Galois Inc. 2018+License     : BSD-3+Maintainer  : benselfridge@galois.com+Stability   : experimental+Portability : portable++This module defines a wrapper around the 'BV' type, 'UnsignedBV', with+instances not provided by 'BV'.+-}++module Data.BitVector.Sized.Unsigned+  ( UnsignedBV(..)+  , mkUnsignedBV+  ) where++import           Data.BitVector.Sized.Internal (BV(..), mkBV)+import qualified Data.BitVector.Sized.Internal as BV+import           Data.BitVector.Sized.Panic (panic)+import Data.Parameterized.NatRepr++import Data.Bits (Bits(..), FiniteBits(..))+import Data.Ix+import GHC.Generics+import GHC.TypeLits+import Numeric.Natural++-- | Signed bit vector.+newtype UnsignedBV w = UnsignedBV { asBV :: BV w }+  deriving (Generic, Show, Read, Eq, Ord)++-- | Convenience wrapper for 'BV.mkBV'.+mkUnsignedBV :: NatRepr w -> Integer -> UnsignedBV w+mkUnsignedBV w x = UnsignedBV (BV.mkBV w x)++liftUnary :: (BV w -> BV w)+          -> UnsignedBV w+          -> UnsignedBV w+liftUnary op (UnsignedBV bv) = UnsignedBV (op bv)++liftBinary :: (BV w -> BV w -> BV w)+           -> UnsignedBV w+           -> UnsignedBV w+           -> UnsignedBV w+liftBinary op (UnsignedBV bv1) (UnsignedBV bv2) = UnsignedBV (op bv1 bv2)++liftBinaryInt :: (BV w -> Natural -> BV w)+              -> UnsignedBV w+              -> Int+              -> UnsignedBV w+liftBinaryInt op (UnsignedBV bv) i = UnsignedBV (op bv (intToNatural i))++intToNatural :: Int -> Natural+intToNatural = fromIntegral++instance KnownNat w => Bits (UnsignedBV w) where+  (.&.)        = liftBinary BV.and+  (.|.)        = liftBinary BV.or+  xor          = liftBinary BV.xor+  complement   = liftUnary (BV.complement knownNat)+  shiftL       = liftBinaryInt (BV.shl knownNat)+  shiftR       = liftBinaryInt (BV.lshr knownNat)+  rotateL      = liftBinaryInt (BV.rotateL knownNat)+  rotateR      = liftBinaryInt (BV.rotateR knownNat)+  bitSize _    = widthVal (knownNat @w)+  bitSizeMaybe _ = Just (widthVal (knownNat @w))+  isSigned     = const False+  testBit (UnsignedBV bv) ix = BV.testBit' (intToNatural ix) bv+  bit          = UnsignedBV . BV.bit' knownNat . intToNatural+  popCount (UnsignedBV bv) = fromInteger (BV.asUnsigned (BV.popCount bv))++instance KnownNat w => FiniteBits (UnsignedBV w) where+  finiteBitSize _ = widthVal (knownNat @w)+  countLeadingZeros  (UnsignedBV bv) = fromInteger $ BV.asUnsigned $ BV.clz knownNat bv+  countTrailingZeros (UnsignedBV bv) = fromInteger $ BV.asUnsigned $ BV.ctz knownNat bv++instance KnownNat w => Num (UnsignedBV w) where+  (+)         = liftBinary (BV.add knownNat)+  (*)         = liftBinary (BV.mul knownNat)+  abs         = id+  signum (UnsignedBV bv) = UnsignedBV $ BV.BV $ signum $ BV.asUnsigned bv+  fromInteger = UnsignedBV . mkBV knownNat+  -- in this case, negate just means "additive inverse"+  negate      = liftUnary (BV.negate knownNat)++instance KnownNat w => Enum (UnsignedBV w) where+  toEnum = UnsignedBV . mkBV knownNat . checkInt+    where checkInt i | 0 <= i && toInteger i <= (maxUnsigned (knownNat @w)) = toInteger i+                     | otherwise = panic "Data.BitVector.Sized.Unsigned"+                                   ["toEnum: bad argument"]++  fromEnum (UnsignedBV bv) = fromInteger (BV.asUnsigned bv)++instance KnownNat w => Ix (UnsignedBV w) where+  range (UnsignedBV loBV, UnsignedBV hiBV) =+    (UnsignedBV . mkBV knownNat) <$>+    [BV.asUnsigned loBV .. BV.asUnsigned hiBV]+  index (UnsignedBV loBV, UnsignedBV hiBV) (UnsignedBV ixBV) =+    index ( BV.asUnsigned loBV,+            BV.asUnsigned hiBV)+    (BV.asUnsigned ixBV)+  inRange (UnsignedBV loBV, UnsignedBV hiBV) (UnsignedBV ixBV) =+    inRange ( BV.asUnsigned loBV+            , BV.asUnsigned hiBV)+    (BV.asUnsigned ixBV)++instance KnownNat w => Bounded (UnsignedBV w) where+  minBound = UnsignedBV (BV.minUnsigned knownNat)+  maxBound = UnsignedBV (BV.maxUnsigned knownNat)
+ test/Main.hs view
@@ -0,0 +1,319 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}++module Main where++-- Testing modules+import Hedgehog+import qualified Hedgehog.Gen as Gen+import qualified Hedgehog.Range as Range+import Test.Tasty+import Test.Tasty.Hedgehog++-- Modules under test+import qualified Data.BitVector.Sized as BV++-- Auxiliary modules+import qualified Data.ByteString as BS+import Data.Maybe (isJust, fromJust)+import Data.Parameterized.NatRepr+import Data.Parameterized.Some+import Data.Parameterized.Pair+import Data.Word++----------------------------------------+-- Utilities+forcePos :: (1 <= w => NatRepr w -> a)+         -> NatRepr w -> a+forcePos f w = case isZeroOrGT1 w of+  Left Refl -> error "Main.forcePos: encountered 0 nat"+  Right LeqProof -> f w++----------------------------------------+-- Homomorphisms+un :: Show a+   => Gen (Some NatRepr)+   -- ^ generator for width+   -> (forall w . NatRepr w -> a -> BV.BV w)+   -- ^ morphism+   -> (forall w . NatRepr w -> Gen a)+   -- ^ generator for arg+   -> (forall w . NatRepr w -> a -> a)+   -- ^ unary operator on domain+   -> (forall w . NatRepr w -> BV.BV w -> BV.BV w)+   -- ^ unary operator on codomain+   -> Property+un genW p gen aOp bOp = property $ do+  Some w <- forAll genW+  a <- forAll (gen w)++  p w (aOp w a) === bOp w (p w a)++bin :: Show a+    => Gen (Some NatRepr)+    -- ^ generator for width+    -> (forall w. NatRepr w -> a -> BV.BV w)+    -- ^ morphism on domains+    -> (forall w. NatRepr w -> Gen a)+    -- ^ generator for first arg+    -> (forall w. NatRepr w -> Gen a)+    -- ^ generator for second arg+    -> (forall w. NatRepr w -> a -> a -> a)+    -- ^ binary operator on domain+    -> (forall w. NatRepr w -> BV.BV w -> BV.BV w -> BV.BV w)+    -- ^ binary operator on codomain+    -> Property+bin genW p gen1 gen2 aOp bOp = property $ do+  Some w <- forAll genW+  a1 <- forAll (gen1 w)+  a2 <- forAll (gen2 w)++  -- compute f (a1 `aOp` a2)+  let a1_a2  = aOp w a1 a2+  let pa1_a2 = p w a1_a2++  -- compute f (a1) `bOp` f (a2)+  let pa1     = p w a1+  let pa2     = p w a2+  let pa1_pa2 = bOp w pa1 pa2+  +  pa1_a2 === pa1_pa2++binPred :: Show a+        => Gen (Some NatRepr)+        -- ^ generator for width+        -> (forall w. NatRepr w -> a -> BV.BV w)+        -- ^ morphism on domains+        -> (forall w . NatRepr w -> Gen a)+        -- ^ generator for first arg+        -> (forall w . NatRepr w -> Gen a)+        -- ^ generator for second arg+        -> (forall w . NatRepr w -> a -> a -> Bool)+        -- ^ binary predicate on domain+        -> (forall w . NatRepr w -> BV.BV w -> BV.BV w -> Bool)+        -- ^ binary predicate on codomain+        -> Property+binPred genW p gen1 gen2 aPred bPred = property $ do+  Some w <- forAll genW+  a1 <- forAll (gen1 w)+  a2 <- forAll (gen2 w)++  let a1_a2  = aPred w a1 a2++  let pa1     = p w a1+  let pa2     = p w a2+  let pa1_pa2 = bPred w pa1 pa2+  +  a1_a2 === pa1_pa2++----------------------------------------+-- Ranges++anyWidth :: Gen (Some NatRepr)+anyWidth = mkNatRepr <$> (Gen.integral $ Range.linear 0 128)++byteWidth :: Gen (Some NatRepr)+byteWidth = mkNatRepr <$> (8*) <$> (Gen.integral $ Range.linear 0 16)++anyPosWidth :: Gen (Some NatRepr)+anyPosWidth = mkNatRepr <$> (Gen.integral $ Range.linear 1 128)++anyWidthGT1 :: Gen (Some NatRepr)+anyWidthGT1 = mkNatRepr <$> (Gen.integral $ Range.linear 2 128)++smallPosWidth :: Gen (Some NatRepr)+smallPosWidth = mkNatRepr <$> (Gen.integral $ Range.linear 1 4)++bytes :: Gen [Word8]+bytes = Gen.list (Range.linear 0 16) $ Gen.word8 Range.linearBounded++bits :: Gen [Bool]+bits = Gen.list (Range.linear 0 128) $ Gen.bool++unsigned :: NatRepr w -> Gen Integer+unsigned w = Gen.integral $ Range.linear 0 (maxUnsigned w)++unsignedPos :: NatRepr w -> Gen Integer+unsignedPos w = Gen.integral $ Range.linear 1 (maxUnsigned w)++largeUnsigned :: NatRepr w -> Gen Integer+largeUnsigned w = Gen.integral $ Range.linear 0 (maxUnsigned w')+  where w' = incNat w++signed :: NatRepr w -> Gen Integer+signed w = case isZeroOrGT1 w of+  Left Refl -> error "Main.signed: w = 0"+  Right LeqProof -> Gen.integral $ Range.linearFrom 0 (minSigned w) (maxSigned w)++signedPos :: NatRepr w -> Gen Integer+signedPos w = case isZeroOrGT1 w of+  Left Refl -> error "Main.posBounded: w = 0"+  Right LeqProof -> Gen.integral $ Range.linear 1 (maxSigned w)++signedNeg :: NatRepr w -> Gen Integer+signedNeg w = case isZeroOrGT1 w of+  Left Refl -> error "Main.posBounded: w = 0"+  Right LeqProof -> Gen.integral $ Range.linearFrom (-1) (minSigned w) (-1)++largeSigned :: NatRepr w -> Gen Integer+largeSigned w = Gen.integral $ Range.linearFrom 0 (- maxUnsigned w') (maxUnsigned w')+  where w' = incNat w++genPair :: Gen a -> Gen a -> Gen (a, a)+genPair gen gen' = do+  a <- gen+  a' <- gen'+  return (a, a')++----------------------------------------+-- Tests++arithHomTests :: TestTree+arithHomTests = testGroup "arithmetic homomorphisms tests"+  [ testProperty "add" $ bin anyWidth BV.mkBV+    largeSigned largeSigned+    (const (+)) BV.add+  , testProperty "sub" $ bin anyWidth BV.mkBV+    largeSigned largeSigned+    (const (-)) BV.sub+  , testProperty "mul" $ bin anyWidth BV.mkBV+    largeSigned largeSigned+    (const (*)) BV.mul+  , testProperty "uquot" $ bin anyPosWidth BV.mkBV+    unsigned unsignedPos+    (const quot) (const BV.uquot)+  , testProperty "urem" $ bin anyPosWidth BV.mkBV+    unsigned unsignedPos+    (const rem) (const BV.urem)+  , testProperty "squot-pos-denom" $ bin anyWidthGT1 BV.mkBV+    signed signedPos+    (const quot) (forcePos BV.squot)+  , testProperty "squot-neg-denom" $ bin anyPosWidth BV.mkBV+    signed signedNeg+    (const quot) (forcePos BV.squot)+  , testProperty "srem-pos-denom" $ bin anyPosWidth BV.mkBV+    signed signedPos+    (const rem) (forcePos BV.srem)+  , testProperty "srem-neg-denom" $ bin anyPosWidth BV.mkBV+    signed signedNeg+    (const rem) (forcePos BV.srem)+  , testProperty "sdiv-pos-denom" $ bin anyPosWidth BV.mkBV+    signed signedPos+    (const div) (forcePos BV.sdiv)+  , testProperty "sdiv-neg-denom" $ bin anyPosWidth BV.mkBV+    signed signedNeg+    (const div) (forcePos BV.sdiv)+  , testProperty "smod-pos-denom" $ bin anyPosWidth BV.mkBV+    signed signedPos+    (const mod) (forcePos BV.smod)+  , testProperty "smod-neg-denom" $ bin anyPosWidth BV.mkBV+    signed signedNeg+    (const mod) (forcePos BV.smod)+  , testProperty "abs" $ un anyPosWidth BV.mkBV+    signed+    (const abs) (forcePos BV.abs)+  , testProperty "negate" $ un anyPosWidth BV.mkBV+    largeSigned+    (const negate) BV.negate+  , testProperty "signBit" $ un anyPosWidth BV.mkBV+    signed+    (\_ a -> if a < 0 then 1 else 0) (forcePos BV.signBit)+  , testProperty "slt" $ binPred anyPosWidth BV.mkBV+    signed signed+    (const (<)) (forcePos BV.slt)+  , testProperty "sle" $ binPred anyPosWidth BV.mkBV+    signed signed+    (const (<=)) (forcePos BV.sle)+  , testProperty "ult" $ binPred anyWidth BV.mkBV+    unsigned unsigned+    (const (<)) (const BV.ult)+  , testProperty "ule" $ binPred anyWidth BV.mkBV+    unsigned unsigned+    (const (<=)) (const BV.ule)+  , testProperty "umin" $ bin anyWidth BV.mkBV+    unsigned unsigned+    (const min) (const BV.umin)+  , testProperty "umax" $ bin anyWidth BV.mkBV+    unsigned unsigned+    (const max) (const BV.umax)+  ]++serdeTest :: Gen (Some NatRepr)+          -> (forall w . NatRepr w -> BV.BV w -> Maybe a)+          -> (a -> Pair NatRepr BV.BV)+          -> Property+serdeTest wGen ser de = property $ do+  Some w <- forAll wGen+  i <- forAll (largeUnsigned w)+  let bv = BV.mkBV w i++  let a = ser w bv+  assert (isJust a)+  Pair w' bv' <- return $ de $ fromJust a++  assert (isJust (w' `testEquality` w))+  Just Refl <- return $ w' `testEquality` w+  bv' === bv++deserTest :: (Show a, Eq a)+          => Gen a+          -> (a -> Int)+          -> (a -> Pair NatRepr BV.BV)+          -> (forall w . NatRepr w -> BV.BV w -> Maybe a)+          -> Property+deserTest genA lenA de ser = property $ do+  a <- forAll genA+  Some w' <- return $ mkNatRepr (fromIntegral (lenA a))++  Pair w bv <- return $ de $ a++  assert (isJust (w' `testEquality` w))+  Just Refl <- return $ w' `testEquality` w++  ser w bv === Just a++serdeTests :: TestTree+serdeTests = testGroup "serialization/deseriallization tests"+  [ testProperty "bitsBE" $+    serdeTest anyWidth (\w bv -> Just (BV.asBitsBE w bv)) BV.bitsBE+  , testProperty "bitsLE" $+    serdeTest anyWidth (\w bv -> Just (BV.asBitsLE w bv)) BV.bitsLE+  , testProperty "bytesBE" $+    serdeTest byteWidth BV.asBytesBE BV.bytesBE+  , testProperty "bytesLE" $+    serdeTest byteWidth BV.asBytesLE BV.bytesLE+  , testProperty "bytestringBE" $+    serdeTest byteWidth BV.asBytestringBE BV.bytestringBE+  , testProperty "bytestringLE" $+    serdeTest byteWidth BV.asBytestringLE BV.bytestringLE+  ]++deserTests :: TestTree+deserTests = testGroup "deserialization/serialization tests"+  [ testProperty "asBitsBE" $+    deserTest bits length BV.bitsBE (\w bv -> Just (BV.asBitsBE w bv))+  , testProperty "asBitsLE" $+    deserTest bits length BV.bitsLE (\w bv -> Just (BV.asBitsLE w bv))+  , testProperty "asBytesBE" $+    deserTest bytes ((*8) . length) BV.bytesBE BV.asBytesBE+  , testProperty "asBytesLE" $+    deserTest bytes ((*8) . length) BV.bytesLE BV.asBytesLE+  , testProperty "asBytesBE" $+    deserTest (BS.pack <$> bytes) ((*8) . BS.length) BV.bytestringBE BV.asBytestringBE+  , testProperty "asBytesLE" $+    deserTest (BS.pack <$> bytes) ((*8) . BS.length) BV.bytestringLE BV.asBytestringLE+  ]++tests :: TestTree+tests = testGroup "bv-sized tests"+  [ arithHomTests+  , serdeTests+  , deserTests+  ]++main :: IO ()+main = defaultMain tests
− test/Test.hs
@@ -1,13 +0,0 @@-{-# LANGUAGE DataKinds #-}--module Main where--import Test.QuickCheck--import Data.BitVector.Sized--main :: IO ()-main = quickCheck bitVectorTest--bitVectorTest :: BitVector 64 -> Bool-bitVectorTest bv = bitVector (bvIntegerS bv) == bv