{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Cryptol.Symbolic.Value
( SBool, SWord, SInteger
, literalSWord
, fromBitsLE
, forallBV_, existsBV_
, forallSBool_, existsSBool_
, forallSInteger_, existsSInteger_
, Value
, TValue, isTBit, tvSeq
, GenValue(..), lam, tlam, toStream, toFinSeq, toSeq
, fromVBit, fromVFun, fromVPoly, fromVTuple, fromVRecord, lookupRecord
, fromSeq, fromVWord
, evalPanic
, iteSValue, mergeValue, mergeWord, mergeBit, mergeBits, mergeSeqMap
, mergeWord'
)
where
import Data.Bits (bit, complement)
import Data.List (foldl')
import qualified Data.Sequence as Seq
import Data.SBV (symbolicEnv)
import Data.SBV.Dynamic
import Cryptol.Eval.Type (TValue(..), isTBit, tvSeq)
import Cryptol.Eval.Monad (Eval, ready)
import Cryptol.Eval.Value ( GenValue(..), BitWord(..), lam, tlam, toStream,
toFinSeq, toSeq, WordValue(..),
fromSeq, fromVBit, fromVWord, fromVFun, fromVPoly,
fromVTuple, fromVRecord, lookupRecord, SeqMap(..),
ppBV, BV(..), integerToChar, lookupSeqMap, memoMap,
wordValueSize, asBitsMap)
import Cryptol.Utils.Panic (panic)
import Cryptol.Utils.PP
import Control.Monad.Trans (liftIO)
type SBool = SVal
type SWord = SVal
type SInteger = SVal
fromBitsLE :: [SBool] -> SWord
fromBitsLE bs = foldl' f (literalSWord 0 0) bs
where f w b = svJoin (svToWord1 b) w
literalSWord :: Int -> Integer -> SWord
literalSWord w i = svInteger (KBounded False w) i
forallBV_ :: Int -> Symbolic SWord
forallBV_ w = symbolicEnv >>= liftIO . svMkSymVar (Just ALL) (KBounded False w) Nothing
existsBV_ :: Int -> Symbolic SWord
existsBV_ w = symbolicEnv >>= liftIO . svMkSymVar (Just EX) (KBounded False w) Nothing
forallSBool_ :: Symbolic SBool
forallSBool_ = symbolicEnv >>= liftIO . svMkSymVar (Just ALL) KBool Nothing
existsSBool_ :: Symbolic SBool
existsSBool_ = symbolicEnv >>= liftIO . svMkSymVar (Just EX) KBool Nothing
forallSInteger_ :: Symbolic SBool
forallSInteger_ = symbolicEnv >>= liftIO . svMkSymVar (Just ALL) KUnbounded Nothing
existsSInteger_ :: Symbolic SBool
existsSInteger_ = symbolicEnv >>= liftIO . svMkSymVar (Just EX) KUnbounded Nothing
type Value = GenValue SBool SWord SInteger
iteSValue :: SBool -> Value -> Value -> Eval Value
iteSValue c x y =
case svAsBool c of
Just True -> return x
Just False -> return y
Nothing -> mergeValue True c x y
mergeBit :: Bool
-> SBool
-> SBool
-> SBool
-> SBool
mergeBit f c b1 b2 = svSymbolicMerge KBool f c b1 b2
mergeWord :: Bool
-> SBool
-> WordValue SBool SWord SInteger
-> WordValue SBool SWord SInteger
-> WordValue SBool SWord SInteger
mergeWord f c (WordVal w1) (WordVal w2) =
WordVal $ svSymbolicMerge (kindOf w1) f c w1 w2
mergeWord f c (WordVal w1) (BitsVal ys) =
BitsVal $ mergeBits f c (Seq.fromList $ map ready $ unpackWord w1) ys
mergeWord f c (BitsVal xs) (WordVal w2) =
BitsVal $ mergeBits f c xs (Seq.fromList $ map ready $ unpackWord w2)
mergeWord f c (BitsVal xs) (BitsVal ys) =
BitsVal $ mergeBits f c xs ys
mergeWord f c w1 w2 =
LargeBitsVal (wordValueSize w1) (mergeSeqMap f c (asBitsMap w1) (asBitsMap w2))
mergeWord' :: Bool
-> SBool
-> Eval (WordValue SBool SWord SInteger)
-> Eval (WordValue SBool SWord SInteger)
-> Eval (WordValue SBool SWord SInteger)
mergeWord' f c x y = mergeWord f c <$> x <*> y
mergeBits :: Bool
-> SBool
-> Seq.Seq (Eval SBool)
-> Seq.Seq (Eval SBool)
-> Seq.Seq (Eval SBool)
mergeBits f c bs1 bs2 = Seq.zipWith mergeBit' bs1 bs2
where mergeBit' b1 b2 = mergeBit f c <$> b1 <*> b2
mergeInteger :: Bool
-> SBool
-> SInteger
-> SInteger
-> SInteger
mergeInteger f c x y = svSymbolicMerge KUnbounded f c x y
mergeValue :: Bool -> SBool -> Value -> Value -> Eval Value
mergeValue f c v1 v2 =
case (v1, v2) of
(VRecord fs1, VRecord fs2) -> pure $ VRecord $ zipWith mergeField fs1 fs2
(VTuple vs1 , VTuple vs2 ) -> pure $ VTuple $ zipWith (mergeValue' f c) vs1 vs2
(VBit b1 , VBit b2 ) -> pure $ VBit $ mergeBit f c b1 b2
(VInteger i1, VInteger i2) -> pure $ VInteger $ mergeInteger f c i1 i2
(VWord n1 w1, VWord n2 w2 ) | n1 == n2 -> pure $ VWord n1 $ mergeWord' f c w1 w2
(VSeq n1 vs1, VSeq n2 vs2 ) | n1 == n2 -> VSeq n1 <$> memoMap (mergeSeqMap f c vs1 vs2)
(VStream vs1, VStream vs2) -> VStream <$> memoMap (mergeSeqMap f c vs1 vs2)
(VFun f1 , VFun f2 ) -> pure $ VFun $ \x -> mergeValue' f c (f1 x) (f2 x)
(VPoly f1 , VPoly f2 ) -> pure $ VPoly $ \x -> mergeValue' f c (f1 x) (f2 x)
(_ , _ ) -> panic "Cryptol.Symbolic.Value"
[ "mergeValue: incompatible values" ]
where
mergeField (n1, x1) (n2, x2)
| n1 == n2 = (n1, mergeValue' f c x1 x2)
| otherwise = panic "Cryptol.Symbolic.Value"
[ "mergeValue.mergeField: incompatible values" ]
mergeValue' :: Bool -> SBool -> Eval Value -> Eval Value -> Eval Value
mergeValue' f c x1 x2 =
do v1 <- x1
v2 <- x2
mergeValue f c v1 v2
mergeSeqMap :: Bool -> SBool -> SeqMap SBool SWord SInteger -> SeqMap SBool SWord SInteger -> SeqMap SBool SWord SInteger
mergeSeqMap f c x y =
IndexSeqMap $ \i ->
do xi <- lookupSeqMap x i
yi <- lookupSeqMap y i
mergeValue f c xi yi
instance BitWord SBool SWord SInteger where
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 v) x)
| otherwise = text "[?]"
ppInteger _opts v
| Just x <- svAsInteger v = integer x
| otherwise = text "[?]"
bitLit b = svBool b
wordLit n x = svInteger (KBounded False (fromInteger n)) x
integerLit x = svInteger KUnbounded x
wordBit x idx = svTestBit x (intSizeOf x - 1 - fromInteger idx)
wordUpdate x idx b = 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 = fromBitsLE (reverse bs)
unpackWord x = [ svTestBit x i | i <- reverse [0 .. intSizeOf x - 1] ]
joinWord x y = svJoin x y
splitWord _leftW rightW w =
( svExtract (intSizeOf w - 1) (fromInteger rightW) w
, svExtract (fromInteger rightW - 1) 0 w
)
extractWord len start w =
svExtract (fromInteger start + fromInteger len - 1) (fromInteger start) w
wordPlus = svPlus
wordMinus = svMinus
wordMult = svTimes
intPlus = svPlus
intMinus = svMinus
intMult = svTimes
intModPlus _m = svPlus
intModMinus _m = svMinus
intModMult _m = svTimes
wordToInt = svToInteger
wordFromInt = svFromInteger
svToInteger :: SWord -> SInteger
svToInteger w =
case svAsInteger w of
Nothing -> svFromIntegral KUnbounded w
Just x -> svInteger KUnbounded x
svFromInteger :: Integer -> SInteger -> SWord
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)