Change the representation and caching of sequences for better performance.

There are two major changes in this patch.  The first is that sequence maps
now have special representations for point updates, of the sort produced by
the 'update' and 'updateEnd' primtives.  These updates are stored in a
finite map, rather than as a functional-update thunk using lambdas; this
reduces memory usage and improves time efficecy of sequences defined by
sequences of updates.

The second change is that the caching policy for sequences is changed
to retain all previously-calculated values.  This is a change from the
previous LRU policy, which retained only a small finite number of previous
values.  Benchmarking showed that unbounded memoization was better for
performance in essentially all cases over both an LRU and an adaptive
caching strategy.  The potential downside is that we may retain values
longer than necessary.  If this becomes a problem, we may need to revisit
this decision.
This commit is contained in:
Robert Dockins 2016-08-12 12:05:55 -07:00
parent c484a8c253
commit dae3ab11b1
8 changed files with 100 additions and 106 deletions

View File

@ -53,7 +53,6 @@ library
gitrev >= 1.0,
GraphSCC >= 1.0.4,
heredoc >= 0.2,
lrucache >= 1.2,
monad-control >= 1.0,
monadLib >= 3.7.2,
old-time >= 1.1,

View File

@ -33,14 +33,11 @@ import Cryptol.Eval.Value
import Cryptol.ModuleSystem.Name
import Cryptol.TypeCheck.AST
import Cryptol.TypeCheck.Solver.InfNat(Nat'(..))
import Cryptol.Utils.Ident (Ident)
import Cryptol.Utils.Panic (panic)
import Cryptol.Utils.PP
import Control.Monad
import Control.Monad.Fix
import qualified Data.Sequence as Seq
import Data.IORef
import Data.List
import Data.Maybe
import qualified Data.Map.Strict as Map
@ -49,7 +46,6 @@ import Prelude ()
import Prelude.Compat
type EvalEnv = GenEvalEnv Bool BV
type ReadEnv = EvalEnv
-- Expression Evaluation -------------------------------------------------------
@ -81,7 +77,7 @@ evalExpr env expr = case expr of
Just w -> WordVal w
Nothing -> BitsVal $ Seq.fromList $ map (fromVBit <$>) vs
| otherwise -> {-# SCC "evalExpr->EList" #-}
VSeq len <$> finiteSeqMap vs
return $ VSeq len $ finiteSeqMap vs
where
tyv = evalValType (envTypes env) ty
vs = map (evalExpr env) es
@ -299,11 +295,11 @@ etaDelay msg env0 Forall{ sVars = vs, sType = tp0 } = goTpVars env0 vs
VWord _ _ -> return x
VSeq n xs
| TVSeq nt el <- tp
-> return $ VSeq n $ SeqMap $ \i -> go el (lookupSeqMap xs i)
-> return $ VSeq n $ IndexSeqMap $ \i -> go el (lookupSeqMap xs i)
VStream xs
| TVSeq nt el <- tp
-> return $ VStream $ SeqMap $ \i -> go el (lookupSeqMap xs i)
-> return $ VStream $ IndexSeqMap $ \i -> go el (lookupSeqMap xs i)
VTuple xs
| TVTuple ts <- tp
@ -332,12 +328,12 @@ etaDelay msg env0 Forall{ sVars = vs, sType = tp0 } = goTpVars env0 vs
TVSeq n el ->
do x' <- delay (Just msg) (fromSeq "during eta-expansion" =<< x)
return $ VSeq n $ SeqMap $ \i -> do
return $ VSeq n $ IndexSeqMap $ \i -> do
go el (flip lookupSeqMap i =<< x')
TVStream el ->
do x' <- delay (Just msg) (fromSeq "during eta-expansion" =<< x)
return $ VStream $ SeqMap $ \i ->
return $ VStream $ IndexSeqMap $ \i ->
go el (flip lookupSeqMap i =<< x')
TVFun _t1 t2 ->
@ -503,7 +499,7 @@ evalComp :: EvalPrims b w
-> Eval (GenValue b w)
evalComp env len elty body ms =
do lenv <- mconcat <$> mapM (branchEnvs (toListEnv env)) ms
mkSeq len elty <$> memoMap (SeqMap $ \i -> do
mkSeq len elty <$> memoMap (IndexSeqMap $ \i -> do
evalExpr (evalListEnv lenv i) body)
-- | Turn a list of matches into the final environments for each iteration of
@ -527,7 +523,7 @@ evalMatch lenv m = case m of
-- Select from a sequence of finite length. This causes us to 'stutter'
-- through our previous choices `nLen` times.
Nat nLen -> do
vss <- memoMap $ SeqMap $ \i -> evalExpr (evalListEnv lenv i) expr
vss <- memoMap $ IndexSeqMap $ \i -> evalExpr (evalListEnv lenv i) expr
let stutter xs = \i -> xs (i `div` nLen)
let lenv' = lenv { leVars = fmap stutter (leVars lenv) }
let vs i = do let (q, r) = i `divMod` nLen

View File

@ -6,14 +6,13 @@
-- Stability : provisional
-- Portability : portable
{-# LANGUAGE Safe #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DoAndIfThenElse #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE Safe #-}
@ -24,9 +23,11 @@
module Cryptol.Eval.Value where
import Data.Bits
import Data.IORef
import qualified Data.Sequence as Seq
import qualified Data.Foldable as Fold
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import MonadLib
import qualified Cryptol.Eval.Arch as Arch
@ -46,9 +47,6 @@ import Numeric (showIntAtBase)
import GHC.Generics (Generic)
import Control.DeepSeq
import qualified Data.Cache.LRU.IO as LRU
-- Values ----------------------------------------------------------------------
-- | Concrete bitvector values: width, value
@ -77,21 +75,35 @@ mkBv w i = BV w (mask w i)
-- | A sequence map represents a mapping from nonnegative integer indices
-- to values. These are used to represent both finite and infinite sequences.
newtype SeqMap b w = SeqMap { lookupSeqMap :: Integer -> Eval (GenValue b w) }
data SeqMap b w
= IndexSeqMap !(Integer -> Eval (GenValue b w))
| UpdateSeqMap !(Map Integer (Eval (GenValue b w)))
!(Integer -> Eval (GenValue b w))
lookupSeqMap :: SeqMap b w -> Integer -> Eval (GenValue b w)
lookupSeqMap (IndexSeqMap f) i = f i
lookupSeqMap (UpdateSeqMap m f) i =
case Map.lookup i m of
Just x -> x
Nothing -> f i
type SeqValMap = SeqMap Bool BV
instance NFData (SeqMap b w) where
rnf x = seq x ()
-- | Generate a finite sequence map from a list of values
finiteSeqMap :: [Eval (GenValue b w)] -> Eval (SeqMap b w)
finiteSeqMap xs = do
memoMap (SeqMap $ \i -> genericIndex xs i)
finiteSeqMap :: [Eval (GenValue b w)] -> SeqMap b w
finiteSeqMap xs =
UpdateSeqMap
(Map.fromList (zip [0..] xs))
invalidIndex
-- | Generate an infinite sequence map from a stream of values
infiniteSeqMap :: [Eval (GenValue b w)] -> Eval (SeqMap b w)
infiniteSeqMap xs =
memoMap (SeqMap $ \i -> genericIndex xs i)
-- TODO: use an int-trie?
memoMap (IndexSeqMap $ \i -> genericIndex xs i)
-- | Create a finite list of length `n` of the values from [0..n-1] in
-- the given the sequence emap.
@ -106,7 +118,11 @@ streamSeqMap m = [ lookupSeqMap m i | i <- [0..] ]
reverseSeqMap :: Integer -- ^ Size of the sequence map
-> SeqMap b w
-> SeqMap b w
reverseSeqMap n vals = SeqMap $ \i -> lookupSeqMap vals (n - 1 - i)
reverseSeqMap n vals = IndexSeqMap $ \i -> lookupSeqMap vals (n - 1 - i)
updateSeqMap :: SeqMap b w -> Integer -> Eval (GenValue b w) -> SeqMap b w
updateSeqMap (UpdateSeqMap m sm) i x = UpdateSeqMap (Map.insert i x m) sm
updateSeqMap (IndexSeqMap f) i x = UpdateSeqMap (Map.singleton i x) f
-- | Given a number `n` and a sequence map, return two new sequence maps:
-- the first containing the values from `[0..n-1]` and the next containing
@ -115,33 +131,25 @@ splitSeqMap :: Integer -> SeqMap b w -> (SeqMap b w, SeqMap b w)
splitSeqMap n xs = (hd,tl)
where
hd = xs
tl = SeqMap $ \i -> lookupSeqMap xs (i+n)
tl = IndexSeqMap $ \i -> lookupSeqMap xs (i+n)
-- | Given a sequence map, return a new sequence map that is memoized using
-- fixed sized memo table. The memo table is managed using a Least-Recently-Used
-- (LRU) cache eviction policy.
--
-- Currently, the cache size is fixed at 64 elements.
-- This seems to provide a good compromize between memory useage and effective
-- memoization.
memoMap :: SeqMap b w -> Eval (SeqMap b w)
-- a finite map memo table.
memoMap x = do
-- TODO: make the size of the LRU cache a tuneable parameter...
let lruSize = 64
lru <- io $ LRU.newAtomicLRU (Just lruSize)
return $ SeqMap $ memo lru
cache <- io $ newIORef $ Map.empty
return $ IndexSeqMap (memo cache)
where
memo lru i = do
mz <- io $ LRU.lookup i lru
case mz of
Just z -> return z
Nothing -> doEval lru i
memo cache i = do
mz <- io (Map.lookup i <$> readIORef cache)
case mz of
Just z -> return z
Nothing -> doEval cache i
doEval lru i = do
v <- lookupSeqMap x i
io $ LRU.insert i v lru
return v
doEval cache i = do
v <- lookupSeqMap x i
io $ modifyIORef' cache (Map.insert i v)
return v
-- | Apply the given evaluation function pointwise to the two given
-- sequence maps.
@ -150,13 +158,13 @@ zipSeqMap :: (GenValue b w -> GenValue b w -> Eval (GenValue b w))
-> SeqMap b w
-> Eval (SeqMap b w)
zipSeqMap f x y =
memoMap (SeqMap $ \i -> join (f <$> lookupSeqMap x i <*> lookupSeqMap y i))
memoMap (IndexSeqMap $ \i -> join (f <$> lookupSeqMap x i <*> lookupSeqMap y i))
-- | Apply the given function to each value in the given sequence map
mapSeqMap :: (GenValue b w -> Eval (GenValue b w))
-> SeqMap b w -> Eval (SeqMap b w)
mapSeqMap f x =
memoMap (SeqMap $ \i -> f =<< lookupSeqMap x i)
memoMap (IndexSeqMap $ \i -> f =<< lookupSeqMap x i)
-- | For efficency reasons, we handle finite sequences of bits as special cases
-- in the evaluator. In cases where we know it is safe to do so, we prefer to
@ -224,6 +232,7 @@ forceValue v = case v of
VStream _ -> return ()
VFun _ -> return ()
VPoly _ -> return ()
VNumPoly _ -> return ()
instance (Show b, Show w) => Show (GenValue b w) where
@ -236,6 +245,7 @@ instance (Show b, Show w) => Show (GenValue b w) where
VStream _ -> "stream"
VFun _ -> "fun"
VPoly _ -> "poly"
VNumPoly _ -> "numpoly"
type Value = GenValue Bool BV
@ -282,6 +292,7 @@ ppValue opts = loop
)
VFun _ -> return $ text "<function>"
VPoly _ -> return $ text "<polymorphic value>"
VNumPoly _ -> return $ text "<polymorphic value>"
ppWordVal :: WordValue b w -> Eval Doc
ppWordVal w = ppWord opts <$> asWordVal w
@ -505,10 +516,10 @@ toStream vs =
VStream <$> infiniteSeqMap (map ready vs)
toFinSeq :: BitWord b w
=> Integer -> TValue -> [GenValue b w] -> Eval (GenValue b w)
=> Integer -> TValue -> [GenValue b w] -> GenValue b w
toFinSeq len elty vs
| isTBit elty = return $ VWord len $ ready $ WordVal $ packWord $ map fromVBit vs
| otherwise = VSeq len <$> finiteSeqMap (map ready vs)
| isTBit elty = VWord len $ ready $ WordVal $ packWord $ map fromVBit vs
| otherwise = VSeq len $ finiteSeqMap (map ready vs)
-- | This is strict!
boolToWord :: [Bool] -> Value
@ -519,7 +530,7 @@ boolToWord bs = VWord (genericLength bs) $ ready $ WordVal $ packWord bs
toSeq :: BitWord b w
=> Nat' -> TValue -> [GenValue b w] -> Eval (GenValue b w)
toSeq len elty vals = case len of
Nat n -> toFinSeq n elty vals
Nat n -> return $ toFinSeq n elty vals
Inf -> toStream vals

View File

@ -18,12 +18,11 @@
{-# LANGUAGE BangPatterns #-}
module Cryptol.Prims.Eval where
import Control.Monad (join, when, unless)
import Control.Monad (join, unless)
import Cryptol.TypeCheck.AST
import Cryptol.TypeCheck.Solver.InfNat (Nat'(..),fromNat,genLog, nMul)
import qualified Cryptol.Eval.Arch as Arch
import Cryptol.Eval.Env
import Cryptol.Eval.Monad
import Cryptol.Eval.Type
import Cryptol.Eval.Value
@ -34,9 +33,7 @@ import Cryptol.Utils.Ident (Ident,mkIdent)
import Cryptol.Utils.PP
import qualified Data.Foldable as Fold
import Data.List (sortBy, transpose, genericTake, genericDrop,
genericReplicate, genericSplitAt, genericIndex,
foldl')
import Data.List (sortBy)
import qualified Data.Sequence as Seq
import Data.Ord (comparing)
import Data.Bits (Bits(..))
@ -46,8 +43,6 @@ import qualified Data.Text as T
import System.Random.TF.Gen (seedTFGen)
import Debug.Trace(trace)
-- Primitives ------------------------------------------------------------------
instance EvalPrims Bool BV where
@ -522,10 +517,10 @@ zeroV ty = case ty of
-- sequences
TVSeq w ety
| isTBit ety -> word w 0
| otherwise -> VSeq w (SeqMap $ \_ -> ready $ zeroV ety)
| otherwise -> VSeq w (IndexSeqMap $ \_ -> ready $ zeroV ety)
TVStream ety ->
VStream (SeqMap $ \_ -> ready $ zeroV ety)
VStream (IndexSeqMap $ \_ -> ready $ zeroV ety)
-- functions
TVFun _ bty ->
@ -578,14 +573,14 @@ joinSeq (Nat parts) each TVBit xs
-- infinite sequence of words
joinSeq Inf each TVBit xs
= return $ VStream $ SeqMap $ \i -> do
= return $ VStream $ IndexSeqMap $ \i -> do
let (q,r) = divMod i each
ys <- fromWordVal "join seq" =<< lookupSeqMap xs q
VBit <$> (asBitsVal ys `Seq.index` fromInteger r)
-- finite or infinite sequence of non-words
joinSeq parts each _a xs
= return $ mkSeq $ SeqMap $ \i -> do
= return $ mkSeq $ IndexSeqMap $ \i -> do
let (q,r) = divMod i each
ys <- fromSeq "join seq" =<< lookupSeqMap xs q
lookupSeqMap ys r
@ -683,11 +678,11 @@ ecSplitV =
case (parts, each) of
(Nat p, Nat e) | isTBit a -> do
VWord _ val' <- val
return $ VSeq p $ SeqMap $ \i -> do
return $ VSeq p $ IndexSeqMap $ \i -> do
return $ VWord e (extractWordVal e ((p-i-1)*e) <$> val')
(Inf, Nat e) | isTBit a -> do
val' <- delay Nothing (fromSeq "ecSplitV" =<< val)
return $ VStream $ SeqMap $ \i ->
return $ VStream $ IndexSeqMap $ \i ->
return $ VWord e $ return $ BitsVal $ Seq.fromFunction (fromInteger e) $ \j ->
let idx = i*e + toInteger j
in idx `seq` do
@ -695,14 +690,14 @@ ecSplitV =
fromVBit <$> lookupSeqMap xs idx
(Nat p, Nat e) -> do
val' <- delay Nothing (fromSeq "ecSplitV" =<< val)
return $ VSeq p $ SeqMap $ \i ->
return $ VSeq e $ SeqMap $ \j -> do
return $ VSeq p $ IndexSeqMap $ \i ->
return $ VSeq e $ IndexSeqMap $ \j -> do
xs <- val'
lookupSeqMap xs (e * i + j)
(Inf , Nat e) -> do
val' <- delay Nothing (fromSeq "ecSplitV" =<< val)
return $ VStream $ SeqMap $ \i ->
return $ VSeq e $ SeqMap $ \j -> do
return $ VStream $ IndexSeqMap $ \i ->
return $ VSeq e $ IndexSeqMap $ \j -> do
xs <- val'
lookupSeqMap xs (e * i + j)
_ -> evalPanic "splitV" ["invalid type arguments to split"]
@ -730,7 +725,7 @@ transposeV :: BitWord b w
-> Eval (GenValue b w)
transposeV a b c xs
| isTBit c, Nat na <- a =
return $ bseq $ SeqMap $ \bi ->
return $ bseq $ IndexSeqMap $ \bi ->
return $ VWord na $ return $ BitsVal $
Seq.fromFunction (fromInteger na) $ \ai -> do
ys <- flip lookupSeqMap (toInteger ai) =<< fromSeq "transposeV" xs
@ -740,8 +735,8 @@ transposeV a b c xs
_ -> evalPanic "transpose" ["expected sequence of bits"]
| otherwise = do
return $ bseq $ SeqMap $ \bi ->
return $ aseq $ SeqMap $ \ai -> do
return $ bseq $ IndexSeqMap $ \bi ->
return $ aseq $ IndexSeqMap $ \ai -> do
ys <- flip lookupSeqMap ai =<< fromSeq "transposeV 1" xs
z <- flip lookupSeqMap bi =<< fromSeq "transposeV 2" ys
return z
@ -772,7 +767,7 @@ ccatV front back elty (VWord m l) (VWord n r) =
ccatV front back elty (VWord m l) (VStream r) = do
l' <- delay Nothing l
return $ VStream $ SeqMap $ \i ->
return $ VStream $ IndexSeqMap $ \i ->
if i < m then
VBit <$> (flip indexWordValue i =<< l')
else
@ -782,7 +777,7 @@ ccatV front back elty l r = do
l'' <- delay Nothing (fromSeq "ccatV left" l)
r'' <- delay Nothing (fromSeq "ccatV right" r)
let Nat n = front
mkSeq (evalTF TCAdd [front,back]) elty <$> return (SeqMap $ \i ->
mkSeq (evalTF TCAdd [front,back]) elty <$> return (IndexSeqMap $ \i ->
if i < n then do
ls <- l''
lookupSeqMap ls i
@ -934,7 +929,7 @@ shiftLB w bs by =
Seq.replicate (fromInteger (min w by)) (ready False)
shiftLS :: Nat' -> TValue -> SeqValMap -> Integer -> SeqValMap
shiftLS w ety vs by = SeqMap $ \i ->
shiftLS w ety vs by = IndexSeqMap $ \i ->
case w of
Nat len
| i+by < len -> lookupSeqMap vs (i+by)
@ -954,7 +949,7 @@ shiftRB w bs by =
Seq.take (fromInteger (w - min w by)) bs
shiftRS :: Nat' -> TValue -> SeqValMap -> Integer -> SeqValMap
shiftRS w ety vs by = SeqMap $ \i ->
shiftRS w ety vs by = IndexSeqMap $ \i ->
case w of
Nat len
| i >= by -> lookupSeqMap vs (i-by)
@ -977,7 +972,7 @@ rotateLB w bs by =
in tl Seq.>< hd
rotateLS :: Nat' -> TValue -> SeqValMap -> Integer -> SeqValMap
rotateLS w _ vs by = SeqMap $ \i ->
rotateLS w _ vs by = IndexSeqMap $ \i ->
case w of
Nat len -> lookupSeqMap vs ((by + i) `mod` len)
_ -> panic "Cryptol.Eval.Prim.rotateLS" [ "unexpected infinite sequence" ]
@ -994,7 +989,7 @@ rotateRB w bs by =
in tl Seq.>< hd
rotateRS :: Nat' -> TValue -> SeqValMap -> Integer -> SeqValMap
rotateRS w _ vs by = SeqMap $ \i ->
rotateRS w _ vs by = IndexSeqMap $ \i ->
case w of
Nat len -> lookupSeqMap vs ((len - by + i) `mod` len)
_ -> panic "Cryptol.Eval.Prim.rotateRS" [ "unexpected infinite sequence" ]
@ -1014,7 +1009,7 @@ indexPrimOne bits_op word_op =
lam $ \ l -> return $
lam $ \ r -> do
vs <- l >>= \case
VWord _ w -> w >>= \w' -> return $ SeqMap (\i -> VBit <$> indexWordValue w' i)
VWord _ w -> w >>= \w' -> return $ IndexSeqMap (\i -> VBit <$> indexWordValue w' i)
VSeq _ vs -> return vs
VStream vs -> return vs
_ -> evalPanic "Expected sequence value" ["indexPrimOne"]
@ -1057,12 +1052,12 @@ indexPrimMany bits_op word_op =
lam $ \ l -> return $
lam $ \ r -> do
vs <- (l >>= \case
VWord _ w -> w >>= \w' -> return $ SeqMap (\i -> VBit <$> indexWordValue w' i)
VWord _ w -> w >>= \w' -> return $ IndexSeqMap (\i -> VBit <$> indexWordValue w' i)
VSeq _ vs -> return vs
VStream vs -> return vs
_ -> evalPanic "Expected sequence value" ["indexPrimMany"])
ixs <- fromSeq "indexPrimMany idx" =<< r
mkSeq m a <$> memoMap (SeqMap $ \i -> do
mkSeq m a <$> memoMap (IndexSeqMap $ \i -> do
lookupSeqMap ixs i >>= \case
VWord _ w -> w >>= \case
WordVal w' -> word_op (fromNat n) a vs w'
@ -1082,8 +1077,7 @@ updateFront len _eltTy vs w val = do
case len of
Inf -> return ()
Nat n -> unless (idx < n) (invalidIndex idx)
return $ SeqMap $ \i ->
if i == idx then val else lookupSeqMap vs i
return $ updateSeqMap vs idx val
updateFront_bits
:: Nat'
@ -1112,9 +1106,7 @@ updateBack Inf _eltTy _vs _w _val =
updateBack (Nat n) _eltTy vs w val = do
idx <- bvVal <$> asWordVal w
unless (idx < n) (invalidIndex idx)
let idx' = n - idx - 1
return $ SeqMap $ \i ->
if i == idx' then val else lookupSeqMap vs i
return $ updateSeqMap vs (n - idx - 1) val
updateBack_bits
:: Nat'
@ -1168,7 +1160,7 @@ fromThenV =
| bits' >= Arch.maxBigIntWidth -> wordTooWide bits'
(Nat first', Nat next', Nat len', Nat bits') ->
let diff = next' - first'
in VSeq len' $ SeqMap $ \i ->
in VSeq len' $ IndexSeqMap $ \i ->
ready $ VWord bits' $ return $
WordVal $ wordLit bits' (first' + i*diff)
_ -> evalPanic "fromThenV" ["invalid arguments"]
@ -1185,7 +1177,7 @@ fromToV =
| bits' >= Arch.maxBigIntWidth -> wordTooWide bits'
(Nat first', Nat lst', Nat bits') ->
let len = 1 + (lst' - first')
in VSeq len $ SeqMap $ \i ->
in VSeq len $ IndexSeqMap $ \i ->
ready $ VWord bits' $ return $
WordVal $ wordLit bits' (first' + i)
_ -> evalPanic "fromToV" ["invalid arguments"]
@ -1204,7 +1196,7 @@ fromThenToV =
| bits' >= Arch.maxBigIntWidth -> wordTooWide bits'
(Nat first', Nat next', Nat lst', Nat len', Nat bits') ->
let diff = next' - first'
in VSeq len' $ SeqMap $ \i ->
in VSeq len' $ IndexSeqMap $ \i ->
ready $ VWord bits' $ return $
WordVal $ wordLit bits' (first' + i*diff)
_ -> evalPanic "fromThenToV" ["invalid arguments"]
@ -1215,7 +1207,7 @@ infFromV :: BitWord b w
infFromV =
nlam $ \(finNat' -> bits) ->
wlam $ \first ->
return $ VStream $ SeqMap $ \i ->
return $ VStream $ IndexSeqMap $ \i ->
ready $ VWord bits $ return $
WordVal $ wordPlus first (wordLit bits i)
@ -1226,7 +1218,7 @@ infFromThenV =
wlam $ \first -> return $
wlam $ \next -> do
let diff = wordMinus next first
return $ VStream $ SeqMap $ \i ->
return $ VStream $ IndexSeqMap $ \i ->
ready $ VWord bits $ return $
WordVal $ wordPlus first (wordMult diff (wordLit bits i))
@ -1261,10 +1253,10 @@ errorV ty msg = case ty of
TVSeq w ety
| isTBit ety -> return $ VWord w $ return $ BitsVal $
Seq.replicate (fromInteger w) (cryUserError msg)
| otherwise -> return $ VSeq w (SeqMap $ \_ -> errorV ety msg)
| otherwise -> return $ VSeq w (IndexSeqMap $ \_ -> errorV ety msg)
TVStream ety ->
return $ VStream (SeqMap $ \_ -> errorV ety msg)
return $ VStream (IndexSeqMap $ \_ -> errorV ety msg)
-- functions
TVFun _ bty ->

View File

@ -255,8 +255,7 @@ parseValue (FTSeq n FTBit) cws =
Eval.packWord (map fromVBit vs), cws')
where (vs, cws') = parseValues (replicate n FTBit) cws
parseValue (FTSeq n t) cws =
(Eval.VSeq (toInteger n) $ Eval.SeqMap $ \i ->
return $ genericIndex vs i
(Eval.VSeq (toInteger n) $ Eval.finiteSeqMap (map Eval.ready vs)
, cws'
)
where (vs, cws') = parseValues (replicate n t) cws
@ -320,8 +319,7 @@ forallFinType ty =
FTSeq 0 FTBit -> return $ Eval.word 0 0
FTSeq n FTBit -> VWord (toInteger n) . return . Eval.WordVal <$> (forallBV_ n)
FTSeq n t -> do vs <- replicateM n (forallFinType t)
return $ VSeq (toInteger n) $ Eval.SeqMap $ \i ->
return $ genericIndex vs i
return $ VSeq (toInteger n) $ Eval.finiteSeqMap (map Eval.ready vs)
FTTuple ts -> VTuple <$> mapM (fmap Eval.ready . forallFinType) ts
FTRecord fs -> VRecord <$> mapM (traverseSnd (fmap Eval.ready . forallFinType)) fs
@ -332,7 +330,6 @@ existsFinType ty =
FTSeq 0 FTBit -> return $ Eval.word 0 0
FTSeq n FTBit -> VWord (toInteger n) . return . Eval.WordVal <$> (existsBV_ n)
FTSeq n t -> do vs <- replicateM n (existsFinType t)
return $ VSeq (toInteger n) $ Eval.SeqMap $ \i ->
return $ genericIndex vs i
return $ VSeq (toInteger n) $ Eval.finiteSeqMap (map Eval.ready vs)
FTTuple ts -> VTuple <$> mapM (fmap Eval.ready . existsFinType) ts
FTRecord fs -> VRecord <$> mapM (traverseSnd (fmap Eval.ready . existsFinType)) fs

View File

@ -24,7 +24,7 @@ module Cryptol.Symbolic.Value
, fromVBit, fromVFun, fromVPoly, fromVTuple, fromVRecord, lookupRecord
, fromSeq, fromVWord
, evalPanic
, iteSValue, mergeValue, mergeWord
, iteSValue, mergeValue, mergeWord, mergeBit
)
where
@ -36,10 +36,10 @@ import Data.SBV.Dynamic
--import Cryptol.Eval.Monad
import Cryptol.Eval.Type (TValue(..), isTBit, tvSeq)
import Cryptol.Eval.Value ( GenValue(..), BitWord(..), lam, tlam, toStream,
toFinSeq, toSeq, WordValue(..), asWordVal, asBitsVal,
toFinSeq, toSeq, WordValue(..), asBitsVal,
fromSeq, fromVBit, fromVWord, fromVFun, fromVPoly,
fromVTuple, fromVRecord, lookupRecord, SeqMap(..),
ppBV,BV(..),integerToChar)
ppBV,BV(..),integerToChar, lookupSeqMap )
import Cryptol.Utils.Panic (panic)
import Cryptol.Utils.PP
@ -117,7 +117,7 @@ mergeValue f c v1 v2 =
| otherwise = panic "Cryptol.Symbolic.Value"
[ "mergeValue.mergeField: incompatible values" ]
mergeSeqMap x y =
SeqMap $ \i -> mergeValue f c <$> lookupSeqMap x i <*> lookupSeqMap y i
IndexSeqMap $ \i -> mergeValue f c <$> lookupSeqMap x i <*> lookupSeqMap y i
-- Symbolic Big-endian Words -------------------------------------------------------

View File

@ -21,7 +21,6 @@ import Data.List(genericReplicate)
import Prelude ()
import Prelude.Compat
import Data.List (genericIndex)
-- | A test result is either a pass, a failure due to evaluating to
-- @False@, or a failure due to an exception raised during evaluation
@ -121,7 +120,7 @@ typeValues ty =
[ VWord n (ready (WordVal (BV n x))) | x <- [ 0 .. 2^n - 1 ] ]
[ TCon (TC (TCNum n)) _, t ] ->
[ VSeq n (SeqMap $ \i -> return $ genericIndex xs i)
[ VSeq n (finiteSeqMap (map ready xs))
| xs <- sequence $ genericReplicate n
$ typeValues t ]
_ -> []

View File

@ -110,7 +110,7 @@ randomWord w _sz g =
randomStream :: RandomGen g => Gen g -> Gen g
randomStream mkElem sz g =
let (g1,g2) = split g
in (VStream $ SeqMap $ genericIndex (map ready (unfoldr (Just . mkElem sz) g1)), g2)
in (VStream $ IndexSeqMap $ genericIndex (map ready (unfoldr (Just . mkElem sz) g1)), g2)
{- | Generate a random sequence. This should be used for sequences
other than bits. For sequences of bits use "randomWord". -}
@ -120,7 +120,7 @@ randomSequence w mkElem sz g = do
let f g = let (x,g') = mkElem sz g
in seq x (Just (ready x, g'))
let xs = Seq.fromList $ genericTake w $ unfoldr f g1
seq xs (VSeq w $ SeqMap $ (Seq.index xs . fromInteger), g2)
seq xs (VSeq w $ IndexSeqMap $ (Seq.index xs . fromInteger), g2)
-- | Generate a random tuple value.
randomTuple :: RandomGen g => [Gen g] -> Gen g