{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE ViewPatterns #-}
module Cryptol.Eval.SBV
( SBV(..), Value
, SBVEval(..), SBVResult(..)
, evalPrim
, forallBV_, existsBV_
, forallSBool_, existsSBool_
, forallSInteger_, existsSInteger_
) where
import qualified Control.Exception as X
import Control.Monad (join)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Bits (bit, complement, shiftL)
import Data.List (foldl')
import qualified Data.Map as Map
import qualified Data.Text as T
import Data.SBV (symbolicEnv)
import Data.SBV.Dynamic as SBV
import Cryptol.Eval.Type (TValue(..), finNat')
import Cryptol.Eval.Backend
import Cryptol.Eval.Generic
import Cryptol.Eval.Monad
( Eval(..), blackhole, delayFill, evalSpark
, EvalError(..), Unsupported(..)
)
import Cryptol.Eval.Value
import Cryptol.Eval.Concrete ( integerToChar, ppBV, BV(..) )
import Cryptol.Testing.Random( randomV )
import Cryptol.TypeCheck.Solver.InfNat (Nat'(..), widthInteger)
import Cryptol.Utils.Ident
import Cryptol.Utils.Panic (panic)
import Cryptol.Utils.PP
data SBV = SBV
fromBitsLE :: [SBit SBV] -> SWord SBV
fromBitsLE bs = foldl' f (literalSWord 0 0) bs
where f w b = svJoin (svToWord1 b) w
packSBV :: [SBit SBV] -> SWord SBV
packSBV bs = fromBitsLE (reverse bs)
unpackSBV :: SWord SBV -> [SBit SBV]
unpackSBV x = [ svTestBit x i | i <- reverse [0 .. intSizeOf x - 1] ]
literalSWord :: Int -> Integer -> SWord SBV
literalSWord w i = svInteger (KBounded False w) i
forallBV_ :: Int -> Symbolic (SWord SBV)
forallBV_ w = symbolicEnv >>= liftIO . svMkSymVar (Just ALL) (KBounded False w) Nothing
existsBV_ :: Int -> Symbolic (SWord SBV)
existsBV_ w = symbolicEnv >>= liftIO . svMkSymVar (Just EX) (KBounded False w) Nothing
forallSBool_ :: Symbolic (SBit SBV)
forallSBool_ = symbolicEnv >>= liftIO . svMkSymVar (Just ALL) KBool Nothing
existsSBool_ :: Symbolic (SBit SBV)
existsSBool_ = symbolicEnv >>= liftIO . svMkSymVar (Just EX) KBool Nothing
forallSInteger_ :: Symbolic (SBit SBV)
forallSInteger_ = symbolicEnv >>= liftIO . svMkSymVar (Just ALL) KUnbounded Nothing
existsSInteger_ :: Symbolic (SBit SBV)
existsSInteger_ = symbolicEnv >>= liftIO . svMkSymVar (Just EX) KUnbounded Nothing
type Value = GenValue SBV
data SBVResult a
= SBVError !EvalError
| SBVResult !SVal !a
instance Functor SBVResult where
fmap _ (SBVError err) = SBVError err
fmap f (SBVResult p x) = SBVResult p (f x)
instance Applicative SBVResult where
pure = SBVResult svTrue
SBVError err <*> _ = SBVError err
_ <*> SBVError err = SBVError err
SBVResult p1 f <*> SBVResult p2 x = SBVResult (svAnd p1 p2) (f x)
instance Monad SBVResult where
return = pure
SBVError err >>= _ = SBVError err
SBVResult px x >>= m =
case m x of
SBVError err -> SBVError err
SBVResult pm z -> SBVResult (svAnd px pm) z
newtype SBVEval a = SBVEval{ sbvEval :: Eval (SBVResult a) }
deriving (Functor)
instance Applicative SBVEval where
pure = SBVEval . pure . pure
f <*> x = SBVEval $
do f' <- sbvEval f
x' <- sbvEval x
pure (f' <*> x')
instance Monad SBVEval where
return = pure
x >>= f = SBVEval $
sbvEval x >>= \case
SBVError err -> pure (SBVError err)
SBVResult px x' ->
sbvEval (f x') >>= \case
SBVError err -> pure (SBVError err)
SBVResult pz z -> pure (SBVResult (svAnd px pz) z)
instance MonadIO SBVEval where
liftIO m = SBVEval $ fmap pure (liftIO m)
instance Backend SBV where
type SBit SBV = SVal
type SWord SBV = SVal
type SInteger SBV = SVal
type SFloat SBV = ()
type SEval SBV = SBVEval
raiseError _ err = SBVEval (pure (SBVError err))
assertSideCondition _ cond err
| Just False <- svAsBool cond = SBVEval (pure (SBVError err))
| otherwise = SBVEval (pure (SBVResult cond ()))
isReady _ (SBVEval (Ready _)) = True
isReady _ _ = False
sDelayFill _ m retry = SBVEval $
do m' <- delayFill (sbvEval m) (sbvEval retry)
pure (pure (SBVEval m'))
sSpark _ m = SBVEval $
do m' <- evalSpark (sbvEval m)
pure (pure (SBVEval m'))
sDeclareHole _ msg = SBVEval $
do (hole, fill) <- blackhole msg
pure (pure (SBVEval hole, \m -> SBVEval (fmap pure $ fill (sbvEval m))))
mergeEval _sym f c mx my = SBVEval $
do rx <- sbvEval mx
ry <- sbvEval my
case (rx, ry) of
(SBVError err, SBVError _) ->
pure $ SBVError err
(SBVError _, SBVResult p y) ->
pure $ SBVResult (svAnd (svNot c) p) y
(SBVResult p x, SBVError _) ->
pure $ SBVResult (svAnd c p) x
(SBVResult px x, SBVResult py y) ->
do zr <- sbvEval (f c x y)
case zr of
SBVError err -> pure $ SBVError err
SBVResult pz z ->
pure $ SBVResult (svAnd (svIte c px py) pz) z
wordLen _ v = toInteger (intSizeOf v)
wordAsChar _ v = integerToChar <$> svAsInteger v
ppBit _ v
| Just b <- svAsBool v = text $! if b then "True" else "False"
| otherwise = text "?"
ppWord _ opts v
| Just x <- svAsInteger v = ppBV opts (BV (wordLen SBV v) x)
| otherwise = text "[?]"
ppInteger _ _opts v
| Just x <- svAsInteger v = integer x
| otherwise = text "[?]"
iteBit _ b x y = pure $! svSymbolicMerge KBool True b x y
iteWord _ b x y = pure $! svSymbolicMerge (kindOf x) True b x y
iteInteger _ b x y = pure $! svSymbolicMerge KUnbounded True b x y
bitAsLit _ b = svAsBool b
wordAsLit _ w =
case svAsInteger w of
Just x -> Just (toInteger (intSizeOf w), x)
Nothing -> Nothing
integerAsLit _ v = svAsInteger v
bitLit _ b = svBool b
wordLit _ n x = pure $! literalSWord (fromInteger n) x
integerLit _ x = pure $! svInteger KUnbounded x
bitEq _ x y = pure $! svEqual x y
bitOr _ x y = pure $! svOr x y
bitAnd _ x y = pure $! svAnd x y
bitXor _ x y = pure $! svXOr x y
bitComplement _ x = pure $! svNot x
wordBit _ x idx = pure $! svTestBit x (intSizeOf x - 1 - fromInteger idx)
wordUpdate _ x idx b = pure $! svSymbolicMerge (kindOf x) False b wtrue wfalse
where
i' = intSizeOf x - 1 - fromInteger idx
wtrue = x `svOr` svInteger (kindOf x) (bit i' :: Integer)
wfalse = x `svAnd` svInteger (kindOf x) (complement (bit i' :: Integer))
packWord _ bs = pure $! packSBV bs
unpackWord _ x = pure $! unpackSBV x
wordEq _ x y = pure $! svEqual x y
wordLessThan _ x y = pure $! svLessThan x y
wordGreaterThan _ x y = pure $! svGreaterThan x y
wordSignedLessThan _ x y = pure $! svLessThan sx sy
where sx = svSign x
sy = svSign y
joinWord _ x y = pure $! svJoin x y
splitWord _ _leftW rightW w = pure
( svExtract (intSizeOf w - 1) (fromInteger rightW) w
, svExtract (fromInteger rightW - 1) 0 w
)
extractWord _ len start w =
pure $! svExtract (fromInteger start + fromInteger len - 1) (fromInteger start) w
wordAnd _ a b = pure $! svAnd a b
wordOr _ a b = pure $! svOr a b
wordXor _ a b = pure $! svXOr a b
wordComplement _ a = pure $! svNot a
wordPlus _ a b = pure $! svPlus a b
wordMinus _ a b = pure $! svMinus a b
wordMult _ a b = pure $! svTimes a b
wordNegate _ a = pure $! svUNeg a
wordDiv sym a b =
do let z = literalSWord (intSizeOf b) 0
assertSideCondition sym (svNot (svEqual b z)) DivideByZero
pure $! svQuot a b
wordMod sym a b =
do let z = literalSWord (intSizeOf b) 0
assertSideCondition sym (svNot (svEqual b z)) DivideByZero
pure $! svRem a b
wordSignedDiv sym a b =
do let z = literalSWord (intSizeOf b) 0
assertSideCondition sym (svNot (svEqual b z)) DivideByZero
pure $! signedQuot a b
wordSignedMod sym a b =
do let z = literalSWord (intSizeOf b) 0
assertSideCondition sym (svNot (svEqual b z)) DivideByZero
pure $! signedRem a b
wordLg2 _ a = sLg2 a
wordToInt _ x = pure $! svToInteger x
wordFromInt _ w i = pure $! svFromInteger w i
intEq _ a b = pure $! svEqual a b
intLessThan _ a b = pure $! svLessThan a b
intGreaterThan _ a b = pure $! svGreaterThan a b
intPlus _ a b = pure $! svPlus a b
intMinus _ a b = pure $! svMinus a b
intMult _ a b = pure $! svTimes a b
intNegate _ a = pure $! SBV.svUNeg a
intDiv sym a b =
do let z = svInteger KUnbounded 0
assertSideCondition sym (svNot (svEqual b z)) DivideByZero
let p = svLessThan z b
pure $! svSymbolicMerge KUnbounded True p (svQuot a b) (svQuot (svUNeg a) (svUNeg b))
intMod sym a b =
do let z = svInteger KUnbounded 0
assertSideCondition sym (svNot (svEqual b z)) DivideByZero
let p = svLessThan z b
pure $! svSymbolicMerge KUnbounded True p (svRem a b) (svUNeg (svRem (svUNeg a) (svUNeg b)))
intToZn _ _m a = pure a
znToInt _ 0 _ = evalPanic "znToInt" ["0 modulus not allowed"]
znToInt _ m a =
do let m' = svInteger KUnbounded m
pure $! svRem a m'
znEq _ 0 _ _ = evalPanic "znEq" ["0 modulus not allowed"]
znEq _ m a b = svDivisible m (SBV.svMinus a b)
znPlus _ m a b = sModAdd m a b
znMinus _ m a b = sModSub m a b
znMult _ m a b = sModMult m a b
znNegate _ m a = sModNegate m a
ppFloat _ _ _ = text "[?]"
fpLit _ _ _ _ = unsupported "fpLit"
fpEq _ _ _ = unsupported "fpEq"
fpLessThan _ _ _ = unsupported "fpLessThan"
fpGreaterThan _ _ _ = unsupported "fpGreaterThan"
fpPlus _ _ _ _ = unsupported "fpPlus"
fpMinus _ _ _ _ = unsupported "fpMinus"
fpMult _ _ _ _ = unsupported "fpMult"
fpDiv _ _ _ _ = unsupported "fpDiv"
fpNeg _ _ = unsupported "fpNeg"
fpFromInteger _ _ _ _ _ = unsupported "fpFromInteger"
fpToInteger _ _ _ _ = unsupported "fpToInteger"
unsupported :: String -> SEval SBV a
unsupported x = liftIO (X.throw (UnsupportedSymbolicOp x))
svToInteger :: SWord SBV -> SInteger SBV
svToInteger w =
case svAsInteger w of
Nothing -> svFromIntegral KUnbounded w
Just x -> svInteger KUnbounded x
svFromInteger :: Integer -> SInteger SBV -> SWord SBV
svFromInteger 0 _ = literalSWord 0 0
svFromInteger n i =
case svAsInteger i of
Nothing -> svFromIntegral (KBounded False (fromInteger n)) i
Just x -> literalSWord (fromInteger n) x
evalPanic :: String -> [String] -> a
evalPanic cxt = panic ("[Symbolic]" ++ cxt)
evalPrim :: PrimIdent -> Maybe Value
evalPrim prim = Map.lookup prim primTable
primTable :: Map.Map PrimIdent Value
primTable = let sym = SBV in
Map.fromList $ map (\(n, v) -> (prelPrim (T.pack n), v))
[
("True" , VBit (bitLit sym True))
, ("False" , VBit (bitLit sym False))
, ("number" , ecNumberV sym)
, ("fraction" , ecFractionV sym)
, ("ratio" , ratioV sym)
, ("zero" , VPoly (zeroV sym))
, ("&&" , binary (andV sym))
, ("||" , binary (orV sym))
, ("^" , binary (xorV sym))
, ("complement" , unary (complementV sym))
, ("fromInteger" , fromIntegerV sym)
, ("+" , binary (addV sym))
, ("-" , binary (subV sym))
, ("negate" , unary (negateV sym))
, ("*" , binary (mulV sym))
, ("toInteger" , toIntegerV sym)
, ("/" , binary (divV sym))
, ("%" , binary (modV sym))
, ("^^" , expV sym)
, ("infFrom" , infFromV sym)
, ("infFromThen" , infFromThenV sym)
, ("recip" , recipV sym)
, ("/." , fieldDivideV sym)
, ("floor" , unary (floorV sym))
, ("ceiling" , unary (ceilingV sym))
, ("trunc" , unary (truncV sym))
, ("roundAway" , unary (roundAwayV sym))
, ("roundToEven" , unary (roundToEvenV sym))
, ("/$" , sdivV sym)
, ("%$" , smodV sym)
, ("lg2" , lg2V sym)
, (">>$" , sshrV)
, ("<" , binary (lessThanV sym))
, (">" , binary (greaterThanV sym))
, ("<=" , binary (lessThanEqV sym))
, (">=" , binary (greaterThanEqV sym))
, ("==" , binary (eqV sym))
, ("!=" , binary (distinctV sym))
, ("<$" , binary (signedLessThanV sym))
, ("fromTo" , fromToV sym)
, ("fromThenTo" , fromThenToV sym)
, ("#" ,
nlam $ \ front ->
nlam $ \ back ->
tlam $ \ elty ->
lam $ \ l -> return $
lam $ \ r -> join (ccatV sym front back elty <$> l <*> r))
, ("join" ,
nlam $ \ parts ->
nlam $ \ (finNat' -> each) ->
tlam $ \ a ->
lam $ \ x ->
joinV sym parts each a =<< x)
, ("split" , ecSplitV sym)
, ("splitAt" ,
nlam $ \ front ->
nlam $ \ back ->
tlam $ \ a ->
lam $ \ x ->
splitAtV sym front back a =<< x)
, ("reverse" , nlam $ \_a ->
tlam $ \_b ->
lam $ \xs -> reverseV sym =<< xs)
, ("transpose" , nlam $ \a ->
nlam $ \b ->
tlam $ \c ->
lam $ \xs -> transposeV sym a b c =<< xs)
, ("<<" , logicShift sym "<<"
shiftShrink
(\x y -> pure (shl x y))
(\x y -> pure (lshr x y))
shiftLeftReindex shiftRightReindex)
, (">>" , logicShift sym ">>"
shiftShrink
(\x y -> pure (lshr x y))
(\x y -> pure (shl x y))
shiftRightReindex shiftLeftReindex)
, ("<<<" , logicShift sym "<<<"
rotateShrink
(\x y -> pure (SBV.svRotateLeft x y))
(\x y -> pure (SBV.svRotateRight x y))
rotateLeftReindex rotateRightReindex)
, (">>>" , logicShift sym ">>>"
rotateShrink
(\x y -> pure (SBV.svRotateRight x y))
(\x y -> pure (SBV.svRotateLeft x y))
rotateRightReindex rotateLeftReindex)
, ("@" , indexPrim sym indexFront indexFront_bits indexFront)
, ("!" , indexPrim sym indexBack indexBack_bits indexBack)
, ("update" , updatePrim sym updateFrontSym_word updateFrontSym)
, ("updateEnd" , updatePrim sym updateBackSym_word updateBackSym)
, ("fromZ" , fromZV sym)
, ("parmap" , parmapV sym)
, ("error" ,
tlam $ \a ->
nlam $ \_ ->
VFun $ \s -> errorV sym a =<< (valueToString sym =<< s))
, ("random" ,
tlam $ \a ->
wlam sym $ \x ->
case integerAsLit sym x of
Just i -> randomV sym a i
Nothing -> cryUserError sym "cannot evaluate 'random' with symbolic inputs")
, ("trace",
nlam $ \_n ->
tlam $ \_a ->
tlam $ \_b ->
lam $ \s -> return $
lam $ \x -> return $
lam $ \y -> do
_ <- s
_ <- x
y)
]
indexFront ::
Nat' ->
TValue ->
SeqMap SBV ->
TValue ->
SVal ->
SEval SBV Value
indexFront mblen a xs _ix idx
| Just i <- SBV.svAsInteger idx
= lookupSeqMap xs i
| Nat n <- mblen
, TVSeq wlen TVBit <- a
= do wvs <- traverse (fromWordVal "indexFront" =<<) (enumerateSeqMap n xs)
case asWordList wvs of
Just ws ->
do z <- wordLit SBV wlen 0
return $ VWord wlen $ pure $ WordVal $ SBV.svSelect ws z idx
Nothing -> folded
| otherwise
= folded
where
k = SBV.kindOf idx
def = zeroV SBV a
f n y = iteValue SBV (SBV.svEqual idx (SBV.svInteger k n)) (lookupSeqMap xs n) y
folded =
case k of
KBounded _ w ->
case mblen of
Nat n | n < 2^w -> foldr f def [0 .. n-1]
_ -> foldr f def [0 .. 2^w - 1]
_ ->
case mblen of
Nat n -> foldr f def [0 .. n-1]
Inf -> liftIO (X.throw (UnsupportedSymbolicOp "unbounded integer indexing"))
indexBack ::
Nat' ->
TValue ->
SeqMap SBV ->
TValue ->
SWord SBV ->
SEval SBV Value
indexBack (Nat n) a xs ix idx = indexFront (Nat n) a (reverseSeqMap n xs) ix idx
indexBack Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack"]
indexFront_bits ::
Nat' ->
TValue ->
SeqMap SBV ->
TValue ->
[SBit SBV] ->
SEval SBV Value
indexFront_bits mblen _a xs _ix bits0 = go 0 (length bits0) bits0
where
go :: Integer -> Int -> [SBit SBV] -> SEval SBV Value
go i _k []
| Nat n <- mblen
, i >= n
= raiseError SBV (InvalidIndex (Just i))
| otherwise
= lookupSeqMap xs i
go i k (b:bs)
| Nat n <- mblen
, (i `shiftL` k) >= n
= raiseError SBV (InvalidIndex Nothing)
| otherwise
= iteValue SBV b
(go ((i `shiftL` 1) + 1) (k-1) bs)
(go (i `shiftL` 1) (k-1) bs)
indexBack_bits ::
Nat' ->
TValue ->
SeqMap SBV ->
TValue ->
[SBit SBV] ->
SEval SBV Value
indexBack_bits (Nat n) a xs ix idx = indexFront_bits (Nat n) a (reverseSeqMap n xs) ix idx
indexBack_bits Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack_bits"]
wordValueEqualsInteger :: WordValue SBV -> Integer -> SEval SBV (SBit SBV)
wordValueEqualsInteger wv i
| wordValueSize SBV wv < widthInteger i = return SBV.svFalse
| otherwise =
case wv of
WordVal w -> return $ SBV.svEqual w (literalSWord (SBV.intSizeOf w) i)
_ -> bitsAre i <$> enumerateWordValueRev SBV wv
where
bitsAre :: Integer -> [SBit SBV] -> SBit SBV
bitsAre n [] = SBV.svBool (n == 0)
bitsAre n (b : bs) = SBV.svAnd (bitIs (odd n) b) (bitsAre (n `div` 2) bs)
bitIs :: Bool -> SBit SBV -> SBit SBV
bitIs b x = if b then x else SBV.svNot x
updateFrontSym ::
Nat' ->
TValue ->
SeqMap SBV ->
Either (SInteger SBV) (WordValue SBV) ->
SEval SBV (GenValue SBV) ->
SEval SBV (SeqMap SBV)
updateFrontSym _len _eltTy vs (Left idx) val =
case SBV.svAsInteger idx of
Just i -> return $ updateSeqMap vs i val
Nothing -> return $ IndexSeqMap $ \i ->
do b <- intEq SBV idx =<< integerLit SBV i
iteValue SBV b val (lookupSeqMap vs i)
updateFrontSym _len _eltTy vs (Right wv) val =
case wv of
WordVal w | Just j <- SBV.svAsInteger w ->
return $ updateSeqMap vs j val
_ ->
return $ IndexSeqMap $ \i ->
do b <- wordValueEqualsInteger wv i
iteValue SBV b val (lookupSeqMap vs i)
updateFrontSym_word ::
Nat' ->
TValue ->
WordValue SBV ->
Either (SInteger SBV) (WordValue SBV) ->
SEval SBV (GenValue SBV) ->
SEval SBV (WordValue SBV)
updateFrontSym_word Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateFrontSym_bits"]
updateFrontSym_word (Nat _) eltTy (LargeBitsVal n bv) idx val =
LargeBitsVal n <$> updateFrontSym (Nat n) eltTy bv idx val
updateFrontSym_word (Nat n) eltTy (WordVal bv) (Left idx) val =
do idx' <- wordFromInt SBV n idx
updateFrontSym_word (Nat n) eltTy (WordVal bv) (Right (WordVal idx')) val
updateFrontSym_word (Nat n) eltTy bv (Right wv) val =
case wv of
WordVal idx
| Just j <- SBV.svAsInteger idx ->
updateWordValue SBV bv j (fromVBit <$> val)
| WordVal bw <- bv ->
WordVal <$>
do b <- fromVBit <$> val
let sz = SBV.intSizeOf bw
let z = literalSWord sz 0
let znot = SBV.svNot z
let q = SBV.svSymbolicMerge (SBV.kindOf bw) True b znot z
let msk = SBV.svShiftRight (literalSWord sz (bit (sz-1))) idx
let bw' = SBV.svAnd bw (SBV.svNot msk)
return $! SBV.svXOr bw' (SBV.svAnd q msk)
_ -> LargeBitsVal n <$> updateFrontSym (Nat n) eltTy (asBitsMap SBV bv) (Right wv) val
updateBackSym ::
Nat' ->
TValue ->
SeqMap SBV ->
Either (SInteger SBV) (WordValue SBV) ->
SEval SBV (GenValue SBV) ->
SEval SBV (SeqMap SBV)
updateBackSym Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateBackSym"]
updateBackSym (Nat n) _eltTy vs (Left idx) val =
case SBV.svAsInteger idx of
Just i -> return $ updateSeqMap vs (n - 1 - i) val
Nothing -> return $ IndexSeqMap $ \i ->
do b <- intEq SBV idx =<< integerLit SBV (n - 1 - i)
iteValue SBV b val (lookupSeqMap vs i)
updateBackSym (Nat n) _eltTy vs (Right wv) val =
case wv of
WordVal w | Just j <- SBV.svAsInteger w ->
return $ updateSeqMap vs (n - 1 - j) val
_ ->
return $ IndexSeqMap $ \i ->
do b <- wordValueEqualsInteger wv (n - 1 - i)
iteValue SBV b val (lookupSeqMap vs i)
updateBackSym_word ::
Nat' ->
TValue ->
WordValue SBV ->
Either (SInteger SBV) (WordValue SBV) ->
SEval SBV (GenValue SBV) ->
SEval SBV (WordValue SBV)
updateBackSym_word Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateBackSym_bits"]
updateBackSym_word (Nat _) eltTy (LargeBitsVal n bv) idx val =
LargeBitsVal n <$> updateBackSym (Nat n) eltTy bv idx val
updateBackSym_word (Nat n) eltTy (WordVal bv) (Left idx) val =
do idx' <- wordFromInt SBV n idx
updateBackSym_word (Nat n) eltTy (WordVal bv) (Right (WordVal idx')) val
updateBackSym_word (Nat n) eltTy bv (Right wv) val = do
case wv of
WordVal idx
| Just j <- SBV.svAsInteger idx ->
updateWordValue SBV bv (n - 1 - j) (fromVBit <$> val)
| WordVal bw <- bv ->
WordVal <$>
do b <- fromVBit <$> val
let sz = SBV.intSizeOf bw
let z = literalSWord sz 0
let znot = SBV.svNot z
let q = SBV.svSymbolicMerge (SBV.kindOf bw) True b znot z
let msk = SBV.svShiftLeft (literalSWord sz 1) idx
let bw' = SBV.svAnd bw (SBV.svNot msk)
return $! SBV.svXOr bw' (SBV.svAnd q msk)
_ -> LargeBitsVal n <$> updateBackSym (Nat n) eltTy (asBitsMap SBV bv) (Right wv) val
asWordList :: [WordValue SBV] -> Maybe [SWord SBV]
asWordList = go id
where go :: ([SWord SBV] -> [SWord SBV]) -> [WordValue SBV] -> Maybe [SWord SBV]
go f [] = Just (f [])
go f (WordVal x :vs) = go (f . (x:)) vs
go _f (LargeBitsVal _ _ : _) = Nothing
sModAdd :: Integer -> SInteger SBV -> SInteger SBV -> SEval SBV (SInteger SBV)
sModAdd 0 _ _ = evalPanic "sModAdd" ["0 modulus not allowed"]
sModAdd modulus x y =
case (SBV.svAsInteger x, SBV.svAsInteger y) of
(Just i, Just j) -> integerLit SBV ((i + j) `mod` modulus)
_ -> pure $ SBV.svPlus x y
sModSub :: Integer -> SInteger SBV -> SInteger SBV -> SEval SBV (SInteger SBV)
sModSub 0 _ _ = evalPanic "sModSub" ["0 modulus not allowed"]
sModSub modulus x y =
case (SBV.svAsInteger x, SBV.svAsInteger y) of
(Just i, Just j) -> integerLit SBV ((i - j) `mod` modulus)
_ -> pure $ SBV.svMinus x y
sModNegate :: Integer -> SInteger SBV -> SEval SBV (SInteger SBV)
sModNegate 0 _ = evalPanic "sModNegate" ["0 modulus not allowed"]
sModNegate modulus x =
case SBV.svAsInteger x of
Just i -> integerLit SBV ((negate i) `mod` modulus)
_ -> pure $ SBV.svUNeg x
sModMult :: Integer -> SInteger SBV -> SInteger SBV -> SEval SBV (SInteger SBV)
sModMult 0 _ _ = evalPanic "sModMult" ["0 modulus not allowed"]
sModMult modulus x y =
case (SBV.svAsInteger x, SBV.svAsInteger y) of
(Just i, Just j) -> integerLit SBV ((i * j) `mod` modulus)
_ -> pure $ SBV.svTimes x y
sLg2 :: SWord SBV -> SEval SBV (SWord SBV)
sLg2 x = pure $ go 0
where
lit n = literalSWord (SBV.intSizeOf x) n
go i | i < SBV.intSizeOf x = SBV.svIte (SBV.svLessEq x (lit (2^i))) (lit (toInteger i)) (go (i + 1))
| otherwise = lit (toInteger i)
svDivisible :: Integer -> SInteger SBV -> SEval SBV (SBit SBV)
svDivisible m x =
do m' <- integerLit SBV m
z <- integerLit SBV 0
pure $ SBV.svEqual (SBV.svRem x m') z
signedQuot :: SWord SBV -> SWord SBV -> SWord SBV
signedQuot x y = SBV.svUnsign (SBV.svQuot (SBV.svSign x) (SBV.svSign y))
signedRem :: SWord SBV -> SWord SBV -> SWord SBV
signedRem x y = SBV.svUnsign (SBV.svRem (SBV.svSign x) (SBV.svSign y))
ashr :: SVal -> SVal -> SVal
ashr x idx =
case SBV.svAsInteger idx of
Just i -> SBV.svUnsign (SBV.svShr (SBV.svSign x) (fromInteger i))
Nothing -> SBV.svUnsign (SBV.svShiftRight (SBV.svSign x) idx)
lshr :: SVal -> SVal -> SVal
lshr x idx =
case SBV.svAsInteger idx of
Just i -> SBV.svShr x (fromInteger i)
Nothing -> SBV.svShiftRight x idx
shl :: SVal -> SVal -> SVal
shl x idx =
case SBV.svAsInteger idx of
Just i -> SBV.svShl x (fromInteger i)
Nothing -> SBV.svShiftLeft x idx
sshrV :: Value
sshrV =
nlam $ \n ->
tlam $ \ix ->
wlam SBV $ \x -> return $
lam $ \y ->
y >>= asIndex SBV ">>$" ix >>= \case
Left idx ->
do let w = toInteger (SBV.intSizeOf x)
let pneg = svLessThan idx (svInteger KUnbounded 0)
zneg <- shl x . svFromInteger w <$> shiftShrink SBV n ix (SBV.svUNeg idx)
zpos <- ashr x . svFromInteger w <$> shiftShrink SBV n ix idx
let z = svSymbolicMerge (kindOf x) True pneg zneg zpos
return . VWord w . pure . WordVal $ z
Right wv ->
do z <- ashr x <$> asWordVal SBV wv
return . VWord (toInteger (SBV.intSizeOf x)) . pure . WordVal $ z