mirror of
https://github.com/GaloisInc/cryptol.git
synced 2024-12-16 20:03:27 +03:00
Share more code between interpreter and symbolic simulator
Some interpreter/simulator operations are now overloaded using a newly introduced 'BitWord' type class.
This commit is contained in:
parent
6368bcbe38
commit
88983488fc
@ -9,6 +9,7 @@
|
|||||||
{-# LANGUAGE PatternGuards #-}
|
{-# LANGUAGE PatternGuards #-}
|
||||||
{-# LANGUAGE DeriveFunctor #-}
|
{-# LANGUAGE DeriveFunctor #-}
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE Safe #-}
|
{-# LANGUAGE Safe #-}
|
||||||
|
|
||||||
module Cryptol.Eval.Value where
|
module Cryptol.Eval.Value where
|
||||||
@ -188,30 +189,38 @@ ppWord opts (BV width i)
|
|||||||
|
|
||||||
-- Big-endian Words ------------------------------------------------------------
|
-- Big-endian Words ------------------------------------------------------------
|
||||||
|
|
||||||
|
class BitWord b w where
|
||||||
|
|
||||||
|
-- | NOTE this assumes that the sequence of bits is big-endian and finite, so the
|
||||||
|
-- first element of the list will be the most significant bit.
|
||||||
|
packWord :: [b] -> w
|
||||||
|
|
||||||
|
-- | NOTE this produces a list of bits that represent a big-endian word, so the
|
||||||
|
-- most significant bit is the first element of the list.
|
||||||
|
unpackWord :: w -> [b]
|
||||||
|
|
||||||
|
|
||||||
mask :: Integer -- ^ Bit-width
|
mask :: Integer -- ^ Bit-width
|
||||||
-> Integer -- ^ Value
|
-> Integer -- ^ Value
|
||||||
-> Integer -- ^ Masked result
|
-> Integer -- ^ Masked result
|
||||||
mask w i | w >= Arch.maxBigIntWidth = wordTooWide w
|
mask w i | w >= Arch.maxBigIntWidth = wordTooWide w
|
||||||
| otherwise = i .&. ((1 `shiftL` fromInteger w) - 1)
|
| otherwise = i .&. ((1 `shiftL` fromInteger w) - 1)
|
||||||
|
|
||||||
-- NOTE this assumes that the sequence of bits is big-endian and finite, so the
|
|
||||||
-- first element of the list will be the most significant bit.
|
|
||||||
packWord :: [Bool] -> BV
|
|
||||||
packWord bits = BV (toInteger w) a
|
|
||||||
where
|
|
||||||
w = case length bits of
|
|
||||||
len | toInteger len >= Arch.maxBigIntWidth -> wordTooWide (toInteger len)
|
|
||||||
| otherwise -> len
|
|
||||||
a = foldl set 0 (zip [w - 1, w - 2 .. 0] bits)
|
|
||||||
set acc (n,b) | b = setBit acc n
|
|
||||||
| otherwise = acc
|
|
||||||
|
|
||||||
-- NOTE this produces a list of bits that represent a big-endian word, so the
|
instance BitWord Bool BV where
|
||||||
-- most significant bit is the first element of the list.
|
|
||||||
unpackWord :: BV -> [Bool]
|
packWord bits = BV (toInteger w) a
|
||||||
unpackWord (BV w a) = [ testBit a n | n <- [w' - 1, w' - 2 .. 0] ]
|
where
|
||||||
where
|
w = case length bits of
|
||||||
w' = fromInteger w
|
len | toInteger len >= Arch.maxBigIntWidth -> wordTooWide (toInteger len)
|
||||||
|
| otherwise -> len
|
||||||
|
a = foldl set 0 (zip [w - 1, w - 2 .. 0] bits)
|
||||||
|
set acc (n,b) | b = setBit acc n
|
||||||
|
| otherwise = acc
|
||||||
|
|
||||||
|
unpackWord (BV w a) = [ testBit a n | n <- [w' - 1, w' - 2 .. 0] ]
|
||||||
|
where
|
||||||
|
w' = fromInteger w
|
||||||
|
|
||||||
|
|
||||||
-- Value Constructors ----------------------------------------------------------
|
-- Value Constructors ----------------------------------------------------------
|
||||||
@ -272,7 +281,7 @@ fromVBit val = case val of
|
|||||||
_ -> evalPanic "fromVBit" ["not a Bit"]
|
_ -> evalPanic "fromVBit" ["not a Bit"]
|
||||||
|
|
||||||
-- | Extract a sequence.
|
-- | Extract a sequence.
|
||||||
fromSeq :: Value -> [Value]
|
fromSeq :: BitWord b w => GenValue b w -> [GenValue b w]
|
||||||
fromSeq val = case val of
|
fromSeq val = case val of
|
||||||
VSeq _ vs -> vs
|
VSeq _ vs -> vs
|
||||||
VWord bv -> map VBit (unpackWord bv)
|
VWord bv -> map VBit (unpackWord bv)
|
||||||
@ -284,12 +293,11 @@ fromStr = map (toEnum . fromInteger . fromWord) . fromSeq
|
|||||||
|
|
||||||
-- | Extract a packed word.
|
-- | Extract a packed word.
|
||||||
-- Note that this does not clean-up any junk bits in the word.
|
-- Note that this does not clean-up any junk bits in the word.
|
||||||
fromVWord :: Value -> BV
|
fromVWord :: BitWord b w => GenValue b w -> w
|
||||||
fromVWord val = case val of
|
fromVWord val = case val of
|
||||||
VWord bv -> bv -- this should always mask
|
VWord bv -> bv -- this should always mask
|
||||||
VSeq isWord bs | isWord -> packWord (map fromVBit bs)
|
VSeq isWord bs | isWord -> packWord (map fromVBit bs)
|
||||||
_ -> evalPanic "fromVWord"
|
_ -> evalPanic "fromVWord" ["not a word"]
|
||||||
["not a word", show $ ppValue defaultPPOpts val]
|
|
||||||
|
|
||||||
vWordLen :: Value -> Maybe Integer
|
vWordLen :: Value -> Maybe Integer
|
||||||
vWordLen val = case val of
|
vWordLen val = case val of
|
||||||
|
@ -97,7 +97,7 @@ evalECon econ =
|
|||||||
VFun $ \xs ->
|
VFun $ \xs ->
|
||||||
VFun $ \y ->
|
VFun $ \y ->
|
||||||
case xs of
|
case xs of
|
||||||
VWord x -> VWord (SBV.sbvShiftLeft x (fromWord y))
|
VWord x -> VWord (SBV.sbvShiftLeft x (fromVWord y))
|
||||||
_ -> selectV shl y
|
_ -> selectV shl y
|
||||||
where
|
where
|
||||||
shl :: Integer -> Value
|
shl :: Integer -> Value
|
||||||
@ -114,7 +114,7 @@ evalECon econ =
|
|||||||
VFun $ \xs ->
|
VFun $ \xs ->
|
||||||
VFun $ \y ->
|
VFun $ \y ->
|
||||||
case xs of
|
case xs of
|
||||||
VWord x -> VWord (SBV.sbvShiftRight x (fromWord y))
|
VWord x -> VWord (SBV.sbvShiftRight x (fromVWord y))
|
||||||
_ -> selectV shr y
|
_ -> selectV shr y
|
||||||
where
|
where
|
||||||
shr :: Integer -> Value
|
shr :: Integer -> Value
|
||||||
@ -131,7 +131,7 @@ evalECon econ =
|
|||||||
VFun $ \xs ->
|
VFun $ \xs ->
|
||||||
VFun $ \y ->
|
VFun $ \y ->
|
||||||
case xs of
|
case xs of
|
||||||
VWord x -> VWord (SBV.sbvRotateLeft x (fromWord y))
|
VWord x -> VWord (SBV.sbvRotateLeft x (fromVWord y))
|
||||||
_ -> selectV rol y
|
_ -> selectV rol y
|
||||||
where
|
where
|
||||||
rol :: Integer -> Value
|
rol :: Integer -> Value
|
||||||
@ -145,7 +145,7 @@ evalECon econ =
|
|||||||
VFun $ \xs ->
|
VFun $ \xs ->
|
||||||
VFun $ \y ->
|
VFun $ \y ->
|
||||||
case xs of
|
case xs of
|
||||||
VWord x -> VWord (SBV.sbvRotateRight x (fromWord y))
|
VWord x -> VWord (SBV.sbvRotateRight x (fromVWord y))
|
||||||
_ -> selectV ror y
|
_ -> selectV ror y
|
||||||
where
|
where
|
||||||
ror :: Integer -> Value
|
ror :: Integer -> Value
|
||||||
@ -233,13 +233,13 @@ evalECon econ =
|
|||||||
|
|
||||||
ECInfFrom ->
|
ECInfFrom ->
|
||||||
tlam $ \(finTValue -> bits) ->
|
tlam $ \(finTValue -> bits) ->
|
||||||
lam $ \(fromWord -> first) ->
|
lam $ \(fromVWord -> first) ->
|
||||||
toStream [ VWord (first + SBV.literal (bv (fromInteger bits) i)) | i <- [0 ..] ]
|
toStream [ VWord (first + SBV.literal (bv (fromInteger bits) i)) | i <- [0 ..] ]
|
||||||
|
|
||||||
ECInfFromThen -> -- {a} (fin a) => [a] -> [a] -> [inf][a]
|
ECInfFromThen -> -- {a} (fin a) => [a] -> [a] -> [inf][a]
|
||||||
tlam $ \_ ->
|
tlam $ \_ ->
|
||||||
lam $ \(fromWord -> first) ->
|
lam $ \(fromVWord -> first) ->
|
||||||
lam $ \(fromWord -> next) ->
|
lam $ \(fromVWord -> next) ->
|
||||||
toStream (map VWord (iterate (+ (next - first)) first))
|
toStream (map VWord (iterate (+ (next - first)) first))
|
||||||
|
|
||||||
-- {at,len} (fin len) => [len][8] -> at
|
-- {at,len} (fin len) => [len][8] -> at
|
||||||
@ -324,8 +324,8 @@ mapV f v =
|
|||||||
|
|
||||||
catV :: Value -> Value -> Value
|
catV :: Value -> Value -> Value
|
||||||
catV xs (VStream ys) = VStream (fromSeq xs ++ ys)
|
catV xs (VStream ys) = VStream (fromSeq xs ++ ys)
|
||||||
catV (VWord x) ys = VWord (cat x (fromWord ys))
|
catV (VWord x) ys = VWord (cat x (fromVWord ys))
|
||||||
catV xs (VWord y) = VWord (cat (fromWord xs) y)
|
catV xs (VWord y) = VWord (cat (fromVWord xs) y)
|
||||||
catV (VSeq b xs) (VSeq _ ys) = VSeq b (xs ++ ys)
|
catV (VSeq b xs) (VSeq _ ys) = VSeq b (xs ++ ys)
|
||||||
catV _ _ = panic "Cryptol.Symbolic.Prims.catV" [ "non-concatenable value" ]
|
catV _ _ = panic "Cryptol.Symbolic.Prims.catV" [ "non-concatenable value" ]
|
||||||
|
|
||||||
@ -395,7 +395,7 @@ arithBinary op = loop . toTypeVal
|
|||||||
loop ty l r =
|
loop ty l r =
|
||||||
case ty of
|
case ty of
|
||||||
TVBit -> evalPanic "arithBinop" ["Invalid arguments"]
|
TVBit -> evalPanic "arithBinop" ["Invalid arguments"]
|
||||||
TVSeq _ TVBit -> VWord (op (fromWord l) (fromWord r))
|
TVSeq _ TVBit -> VWord (op (fromVWord l) (fromVWord r))
|
||||||
TVSeq _ t -> VSeq False (zipWith (loop t) (fromSeq l) (fromSeq r))
|
TVSeq _ t -> VSeq False (zipWith (loop t) (fromSeq l) (fromSeq r))
|
||||||
TVStream t -> VStream (zipWith (loop t) (fromSeq l) (fromSeq r))
|
TVStream t -> VStream (zipWith (loop t) (fromSeq l) (fromSeq r))
|
||||||
TVTuple ts -> VTuple (zipWith3 loop ts (fromVTuple l) (fromVTuple r))
|
TVTuple ts -> VTuple (zipWith3 loop ts (fromVTuple l) (fromVTuple r))
|
||||||
@ -409,7 +409,7 @@ arithUnary op = loop . toTypeVal
|
|||||||
loop ty v =
|
loop ty v =
|
||||||
case ty of
|
case ty of
|
||||||
TVBit -> evalPanic "arithUnary" ["Invalid arguments"]
|
TVBit -> evalPanic "arithUnary" ["Invalid arguments"]
|
||||||
TVSeq _ TVBit -> VWord (op (fromWord v))
|
TVSeq _ TVBit -> VWord (op (fromVWord v))
|
||||||
TVSeq _ t -> VSeq False (map (loop t) (fromSeq v))
|
TVSeq _ t -> VSeq False (map (loop t) (fromSeq v))
|
||||||
TVStream t -> VStream (map (loop t) (fromSeq v))
|
TVStream t -> VStream (map (loop t) (fromSeq v))
|
||||||
TVTuple ts -> VTuple (zipWith loop ts (fromVTuple v))
|
TVTuple ts -> VTuple (zipWith loop ts (fromVTuple v))
|
||||||
@ -451,8 +451,8 @@ cmpValue fb fw = cmp
|
|||||||
[ "Functions are not comparable" ]
|
[ "Functions are not comparable" ]
|
||||||
(VPoly {} , VPoly {} ) -> panic "Cryptol.Symbolic.Prims.cmpValue"
|
(VPoly {} , VPoly {} ) -> panic "Cryptol.Symbolic.Prims.cmpValue"
|
||||||
[ "Polymorphic values are not comparable" ]
|
[ "Polymorphic values are not comparable" ]
|
||||||
(VWord w1 , _ ) -> fw w1 (fromWord v2) k
|
(VWord w1 , _ ) -> fw w1 (fromVWord v2) k
|
||||||
(_ , VWord w2 ) -> fw (fromWord v1) w2 k
|
(_ , VWord w2 ) -> fw (fromVWord v1) w2 k
|
||||||
(_ , _ ) -> panic "Cryptol.Symbolic.Prims.cmpValue"
|
(_ , _ ) -> panic "Cryptol.Symbolic.Prims.cmpValue"
|
||||||
[ "type mismatch" ]
|
[ "type mismatch" ]
|
||||||
|
|
||||||
@ -543,7 +543,7 @@ logicBinary bop op = loop . toTypeVal
|
|||||||
loop ty l r =
|
loop ty l r =
|
||||||
case ty of
|
case ty of
|
||||||
TVBit -> VBit (bop (fromVBit l) (fromVBit r))
|
TVBit -> VBit (bop (fromVBit l) (fromVBit r))
|
||||||
TVSeq _ TVBit -> VWord (op (fromWord l) (fromWord r))
|
TVSeq _ TVBit -> VWord (op (fromVWord l) (fromVWord r))
|
||||||
TVSeq _ t -> VSeq False (zipWith (loop t) (fromSeq l) (fromSeq r))
|
TVSeq _ t -> VSeq False (zipWith (loop t) (fromSeq l) (fromSeq r))
|
||||||
TVStream t -> VStream (zipWith (loop t) (fromSeq l) (fromSeq r))
|
TVStream t -> VStream (zipWith (loop t) (fromSeq l) (fromSeq r))
|
||||||
TVTuple ts -> VTuple (zipWith3 loop ts (fromVTuple l) (fromVTuple r))
|
TVTuple ts -> VTuple (zipWith3 loop ts (fromVTuple l) (fromVTuple r))
|
||||||
@ -556,7 +556,7 @@ logicUnary bop op = loop . toTypeVal
|
|||||||
loop ty v =
|
loop ty v =
|
||||||
case ty of
|
case ty of
|
||||||
TVBit -> VBit (bop (fromVBit v))
|
TVBit -> VBit (bop (fromVBit v))
|
||||||
TVSeq _ TVBit -> VWord (op (fromWord v))
|
TVSeq _ TVBit -> VWord (op (fromVWord v))
|
||||||
TVSeq _ t -> VSeq False (map (loop t) (fromSeq v))
|
TVSeq _ t -> VSeq False (map (loop t) (fromSeq v))
|
||||||
TVStream t -> VStream (map (loop t) (fromSeq v))
|
TVStream t -> VStream (map (loop t) (fromSeq v))
|
||||||
TVTuple ts -> VTuple (zipWith loop ts (fromVTuple v))
|
TVTuple ts -> VTuple (zipWith loop ts (fromVTuple v))
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE TypeSynonymInstances #-}
|
{-# LANGUAGE TypeSynonymInstances #-}
|
||||||
|
|
||||||
module Cryptol.Symbolic.Value
|
module Cryptol.Symbolic.Value
|
||||||
@ -15,7 +16,7 @@ module Cryptol.Symbolic.Value
|
|||||||
, TValue, numTValue, toNumTValue, finTValue, isTBit, isTFun, isTSeq, isTTuple, isTRec, tvSeq
|
, TValue, numTValue, toNumTValue, finTValue, isTBit, isTFun, isTSeq, isTTuple, isTRec, tvSeq
|
||||||
, GenValue(..), lam, tlam, toStream, toFinSeq, toSeq
|
, GenValue(..), lam, tlam, toStream, toFinSeq, toSeq
|
||||||
, fromVBit, fromVFun, fromVPoly, fromVTuple, fromVRecord, lookupRecord
|
, fromVBit, fromVFun, fromVPoly, fromVTuple, fromVRecord, lookupRecord
|
||||||
, fromSeq, fromWord
|
, fromSeq, fromVWord
|
||||||
, evalPanic
|
, evalPanic
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
@ -23,8 +24,8 @@ module Cryptol.Symbolic.Value
|
|||||||
import Data.Bits (bitSize)
|
import Data.Bits (bitSize)
|
||||||
|
|
||||||
import Cryptol.Eval.Value (TValue, numTValue, toNumTValue, finTValue, isTBit, isTFun, isTSeq, isTTuple, isTRec, tvSeq,
|
import Cryptol.Eval.Value (TValue, numTValue, toNumTValue, finTValue, isTBit, isTFun, isTSeq, isTTuple, isTRec, tvSeq,
|
||||||
GenValue(..), lam, tlam, toStream, toFinSeq, toSeq,
|
GenValue(..), BitWord(..), lam, tlam, toStream, toFinSeq, toSeq, fromSeq,
|
||||||
fromVBit, fromVFun, fromVPoly, fromVTuple, fromVRecord, lookupRecord)
|
fromVBit, fromVWord, fromVFun, fromVPoly, fromVTuple, fromVRecord, lookupRecord)
|
||||||
import Cryptol.Symbolic.BitVector
|
import Cryptol.Symbolic.BitVector
|
||||||
import Cryptol.Utils.Panic (panic)
|
import Cryptol.Utils.Panic (panic)
|
||||||
|
|
||||||
@ -47,8 +48,8 @@ instance Mergeable Value where
|
|||||||
(VStream vs1, VStream vs2) -> VStream $ mergeStream vs1 vs2
|
(VStream vs1, VStream vs2) -> VStream $ mergeStream vs1 vs2
|
||||||
(VFun f1 , VFun f2 ) -> VFun $ symbolicMerge f c f1 f2
|
(VFun f1 , VFun f2 ) -> VFun $ symbolicMerge f c f1 f2
|
||||||
(VPoly f1 , VPoly f2 ) -> VPoly $ symbolicMerge f c f1 f2
|
(VPoly f1 , VPoly f2 ) -> VPoly $ symbolicMerge f c f1 f2
|
||||||
(VWord w1 , _ ) -> VWord $ symbolicMerge f c w1 (fromWord v2)
|
(VWord w1 , _ ) -> VWord $ symbolicMerge f c w1 (fromVWord v2)
|
||||||
(_ , VWord w2 ) -> VWord $ symbolicMerge f c (fromWord v1) w2
|
(_ , VWord w2 ) -> VWord $ symbolicMerge f c (fromVWord v1) w2
|
||||||
(_ , _ ) -> panic "Cryptol.Symbolic.Value"
|
(_ , _ ) -> panic "Cryptol.Symbolic.Value"
|
||||||
[ "symbolicMerge: incompatible values" ]
|
[ "symbolicMerge: incompatible values" ]
|
||||||
where
|
where
|
||||||
@ -61,22 +62,9 @@ instance Mergeable Value where
|
|||||||
|
|
||||||
-- Big-endian Words ------------------------------------------------------------
|
-- Big-endian Words ------------------------------------------------------------
|
||||||
|
|
||||||
unpackWord :: SWord -> [SBool]
|
instance BitWord SBool SWord where
|
||||||
unpackWord s = [ sbvTestBit s i | i <- reverse [0 .. bitSize s - 1] ]
|
packWord bs = Data.SBV.fromBitsBE bs
|
||||||
|
unpackWord w = [ sbvTestBit w i | i <- reverse [0 .. bitSize w - 1] ]
|
||||||
-- Constructors and Accessors --------------------------------------------------
|
|
||||||
|
|
||||||
fromWord :: Value -> SWord
|
|
||||||
fromWord (VWord s) = s
|
|
||||||
fromWord v = Data.SBV.fromBitsBE (map fromVBit (fromSeq v))
|
|
||||||
|
|
||||||
-- | Extract a sequence.
|
|
||||||
fromSeq :: Value -> [Value]
|
|
||||||
fromSeq v = case v of
|
|
||||||
VSeq _ vs -> vs
|
|
||||||
VWord s -> map VBit (unpackWord s)
|
|
||||||
VStream vs -> vs
|
|
||||||
_ -> evalPanic "fromSeq" ["not a sequence"]
|
|
||||||
|
|
||||||
-- Errors ----------------------------------------------------------------------
|
-- Errors ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user