crucible-0.7: src/Lang/Crucible/Simulator/Evaluation.hs
-----------------------------------------------------------------------
-- |
-- Module : Lang.Crucible.Simulator.Evaluation
-- Description : Evaluation functions for Crucible core expressions
-- Copyright : (c) Galois, Inc 2014-2016
-- License : BSD3
-- Maintainer : Joe Hendrix <jhendrix@galois.com>
-- Stability : provisional
--
-- This module provides operations evaluating Crucible expressions.
------------------------------------------------------------------------
{-# LANGUAGE DoAndIfThenElse #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ViewPatterns #-}
module Lang.Crucible.Simulator.Evaluation
( EvalAppFunc
, evalApp
, selectedIndices
, indexSymbolic
, integerAsChar
, complexRealAsChar
, indexVectorWithSymNat
, adjustVectorWithSymNat
, updateVectorWithSymNat
) where
import Prelude hiding (pred)
import qualified Control.Exception as Ex
import Control.Lens
import Control.Monad
import qualified Data.BitVector.Sized as BV
import qualified Data.Map.Strict as Map
import Data.Maybe
import qualified Data.Text as Text
import qualified Data.Vector as V
import Data.Word
import Numeric ( showHex )
import Numeric.Natural
import GHC.Stack
import Data.Parameterized.Classes
import Data.Parameterized.Context as Ctx
import Data.Parameterized.TraversableFC
import What4.Interface
import What4.InterpretedFloatingPoint
import What4.Partial (pattern PE, pattern Unassigned, joinMaybePE)
import What4.Utils.Complex
import What4.WordMap
import Lang.Crucible.Backend
import Lang.Crucible.CFG.Expr
import Lang.Crucible.Simulator.Intrinsics
import Lang.Crucible.Simulator.RegMap
import Lang.Crucible.Simulator.SimError
import Lang.Crucible.Simulator.SymSequence
import Lang.Crucible.Types
------------------------------------------------------------------------
-- Utilities
-- | Given a list of Booleans l, @selectedIndices@ returns the indices of
-- true values in @l@.
selectedIndices :: [Bool] -> [Natural]
selectedIndices l = catMaybes $ Prelude.zipWith selectIndex l [1..]
where selectIndex True i = Just i
selectIndex False _ = Nothing
------------------------------------------------------------------------
-- Coercion functions
integerAsChar :: Integer -> Word16
integerAsChar i = fromInteger ((i `max` 0) `min` (2^(16::Int)-1))
complexRealAsChar :: (MonadFail m, IsExpr val)
=> val BaseComplexType
-> m Word16
complexRealAsChar v = do
case cplxExprAsRational v of
-- Check number is printable.
Just r | otherwise -> return (integerAsChar (floor r))
Nothing -> fail "Symbolic value cannot be interpreted as a character."
-- XXX: Should this be a panic?
-- XXX: We should move this to crucible-matlab
------------------------------------------------------------------------
-- Evaluating expressions
-- | Helper method for implementing 'indexSymbolic'
indexSymbolic' :: IsSymBackend sym bak
=> bak
-> (Pred sym -> a -> a -> IO a)
-- ^ Function for merging valeus
-> ([Natural] -> IO a) -- ^ Concrete index function.
-> [Natural] -- ^ Values of processed indices (in reverse order)
-> [(Natural,Natural)] -- ^ Bounds on remaining indices.
-> [SymNat sym] -- ^ Remaining indices.
-> IO a
indexSymbolic' _ _ f p [] _ = f (reverse p)
indexSymbolic' _ _ f p _ [] = f (reverse p)
indexSymbolic' bak iteFn f p ((l,h):nl) (si:il) = do
let subIndex idx = indexSymbolic' bak iteFn f (idx:p) nl il
case asNat si of
Just i
| l <= i && i <= h -> subIndex i
| otherwise ->
addFailedAssertion bak (AssertFailureSimError msg details)
where msg = "Index outside matrix dimensions." ++ show (l,i,h)
details = unwords ["Index", show i, "is outside of range", show (l, h)]
Nothing ->
do let sym = backendGetSym bak
ensureInRange bak l h si "Index outside matrix dimensions."
let predFn i = natEq sym si =<< natLit sym i
muxRange predFn iteFn subIndex l h
ensureInRange ::
IsSymBackend sym bak =>
bak ->
Natural ->
Natural ->
SymNat sym ->
String ->
IO ()
ensureInRange bak l h si msg =
do let sym = backendGetSym bak
l_sym <- natLit sym l
h_sym <- natLit sym h
inRange <- join $ andPred sym <$> natLe sym l_sym si <*> natLe sym si h_sym
assert bak inRange (AssertFailureSimError msg details)
where details = unwords ["Range is", show (l, h)]
-- | Lookup a value in an array that may be at a symbolic offset.
--
-- This function takes a list of symbolic indices as natural numbers
-- along with a pair of lower and upper bounds for each index.
-- It assumes that the indices are all in range.
indexSymbolic :: IsSymBackend sym bak
=> bak
-> (Pred sym -> a -> a -> IO a)
-- ^ Function for combining results together.
-> ([Natural] -> IO a) -- ^ Concrete index function.
-> [(Natural,Natural)] -- ^ High and low bounds at the indices.
-> [SymNat sym]
-> IO a
indexSymbolic sym iteFn f = indexSymbolic' sym iteFn f []
-- | Evaluate an indexTermterm to an index value.
evalBase :: IsSymInterface sym =>
sym
-> (forall utp . f utp -> IO (RegValue sym utp))
-> BaseTerm f vtp
-> IO (SymExpr sym vtp)
evalBase _ evalSub (BaseTerm _tp e) = evalSub e
-- | Get value stored in vector at a symbolic index.
indexVectorWithSymNat :: IsSymBackend sym bak
=> bak
-> (Pred sym -> a -> a -> IO a)
-- ^ Ite function
-> V.Vector a
-> SymNat sym
-> IO a
indexVectorWithSymNat bak iteFn v si =
Ex.assert (n > 0) $
case asNat si of
Just i | 0 <= i && i < n -> return (v V.! fromIntegral i)
| otherwise -> addFailedAssertion bak (AssertFailureSimError msg details)
Nothing ->
do let sym = backendGetSym bak
let predFn i = natEq sym si =<< natLit sym i
let getElt i = return (v V.! fromIntegral i)
ensureInRange bak 0 (n - 1) si msg
muxRange predFn iteFn getElt 0 (n - 1)
where
n = fromIntegral (V.length v)
msg = "Vector index out of range"
details = unwords ["Range is", show (0 :: Natural, n)]
-- | Update a vector at a given natural number index.
updateVectorWithSymNat :: IsSymBackend sym bak
=> bak
-- ^ Symbolic backend
-> (Pred sym -> a -> a -> IO a)
-- ^ Ite function
-> V.Vector a
-- ^ Vector to update
-> SymNat sym
-- ^ Index to update
-> a
-- ^ New value to assign
-> IO (V.Vector a)
updateVectorWithSymNat bak iteFn v si new_val = do
adjustVectorWithSymNat bak iteFn v si (\_ -> return new_val)
-- | Update a vector at a given natural number index.
adjustVectorWithSymNat :: IsSymBackend sym bak
=> bak
-- ^ Symbolic backend
-> (Pred sym -> a -> a -> IO a)
-- ^ Ite function
-> V.Vector a
-- ^ Vector to update
-> SymNat sym
-- ^ Index to update
-> (a -> IO a)
-- ^ Adjustment function to apply
-> IO (V.Vector a)
adjustVectorWithSymNat bak iteFn v si adj =
case asNat si of
Just i
| i < fromIntegral n ->
do new_val <- adj (v V.! fromIntegral i)
return $ v V.// [(fromIntegral i, new_val)]
| otherwise ->
addFailedAssertion bak $ AssertFailureSimError msg (details i)
Nothing ->
do ensureInRange bak 0 (fromIntegral (n-1)) si msg
V.generateM n setFn
where
setFn j =
do let sym = backendGetSym bak
-- Compare si and j.
c <- natEq sym si =<< natLit sym (fromIntegral j)
-- Select old value or new value
case asConstantPred c of
Just True -> adj (v V.! j)
Just False -> return (v V.! j)
Nothing ->
do new_val <- adj (v V.! j)
iteFn c new_val (v V.! j)
where
n = V.length v
msg = "Illegal vector index"
details i = "Illegal index " ++ show i ++ "given to updateVectorWithSymNat"
type EvalAppFunc sym app = forall f.
(forall tp. f tp -> IO (RegValue sym tp)) ->
(forall tp. app f tp -> IO (RegValue sym tp))
{-# INLINE evalApp #-}
-- | Evaluate the application.
evalApp :: forall sym bak ext.
IsSymBackend sym bak
=> bak
-> IntrinsicTypes sym
-> (Int -> String -> IO ())
-- ^ Function for logging messages.
-> EvalAppFunc sym (ExprExtension ext)
-> EvalAppFunc sym (App ext)
evalApp bak itefns _logFn evalExt (evalSub :: forall tp. f tp -> IO (RegValue sym tp)) a0 = do
let sym = backendGetSym bak
case a0 of
BaseIsEq tp xe ye -> do
x <- evalBase sym evalSub (BaseTerm tp xe)
y <- evalBase sym evalSub (BaseTerm tp ye)
isEq sym x y
BaseIte tp ce xe ye -> do
c <- evalSub ce
case asConstantPred c of
Just True -> evalSub xe
Just False -> evalSub ye
Nothing -> do
x <- evalBase sym evalSub (BaseTerm tp xe)
y <- evalBase sym evalSub (BaseTerm tp ye)
baseTypeIte sym c x y
----------------------------------------------------------------------
ExtensionApp x -> evalExt evalSub x
----------------------------------------------------------------------
-- ()
EmptyApp -> return ()
----------------------------------------------------------------------
-- Any
PackAny tp x -> do
xv <- evalSub x
return (AnyValue tp xv)
UnpackAny tp x -> do
xv <- evalSub x
case xv of
AnyValue tpv v
| Just Refl <- testEquality tp tpv ->
return $! PE (truePred sym) v
| otherwise ->
return Unassigned
----------------------------------------------------------------------
-- Bool
BoolLit b -> return $ backendPred sym b
Not x -> do
r <- evalSub x
notPred sym r
And x y -> do
xv <- evalSub x
yv <- evalSub y
andPred sym xv yv
Or x y -> do
xv <- evalSub x
yv <- evalSub y
orPred sym xv yv
BoolXor x y -> do
xv <- evalSub x
yv <- evalSub y
xorPred sym xv yv
----------------------------------------------------------------------
-- Nat
NatLit n -> natLit sym n
NatIte pe xe ye -> do
p <- evalSub pe
x <- evalSub xe
y <- evalSub ye
natIte sym p x y
NatEq xe ye -> do
x <- evalSub xe
y <- evalSub ye
natEq sym x y
NatLt xe ye -> do
x <- evalSub xe
y <- evalSub ye
natLt sym x y
NatLe xe ye -> do
x <- evalSub xe
y <- evalSub ye
natLe sym x y
NatAdd xe ye -> do
x <- evalSub xe
y <- evalSub ye
natAdd sym x y
NatSub xe ye -> do
x <- evalSub xe
y <- evalSub ye
natSub sym x y
NatMul xe ye -> do
x <- evalSub xe
y <- evalSub ye
natMul sym x y
NatDiv xe ye -> do
x <- evalSub xe
y <- evalSub ye
natDiv sym x y
NatMod xe ye -> do
x <- evalSub xe
y <- evalSub ye
natMod sym x y
----------------------------------------------------------------------
-- Int
IntLit n -> intLit sym n
IntLe xe ye -> do
x <- evalSub xe
y <- evalSub ye
intLe sym x y
IntLt xe ye -> do
x <- evalSub xe
y <- evalSub ye
intLt sym x y
IntNeg xe -> do
x <- evalSub xe
intNeg sym x
IntAbs xe -> do
x <- evalSub xe
intAbs sym x
IntAdd xe ye -> do
x <- evalSub xe
y <- evalSub ye
intAdd sym x y
IntSub xe ye -> do
x <- evalSub xe
y <- evalSub ye
intSub sym x y
IntMul xe ye -> do
x <- evalSub xe
y <- evalSub ye
intMul sym x y
IntDiv xe ye -> do
x <- evalSub xe
y <- evalSub ye
intDiv sym x y
IntMod xe ye -> do
x <- evalSub xe
y <- evalSub ye
intMod sym x y
--------------------------------------------------------------------
-- Maybe
JustValue _ e -> do
r <- evalSub e
return $! PE (truePred sym) r
NothingValue _ -> do
return Unassigned
FromJustValue _ maybe_expr msg_expr -> do
maybe_val <- evalSub maybe_expr
case maybe_val of
-- Special case to avoid forcing evaluation of msg.
PE (asConstantPred -> Just True) v -> return v
_ -> do
msg <- evalSub msg_expr
case asString msg of
Just (UnicodeLiteral msg') -> readPartExpr bak maybe_val (GenericSimError (Text.unpack msg'))
Nothing ->
addFailedAssertion bak $
Unsupported callStack "Symbolic string in fromJustValue"
----------------------------------------------------------------------
-- Recursive Types
RollRecursive _ _ e -> RolledType <$> evalSub e
UnrollRecursive _ _ e -> unroll <$> evalSub e
----------------------------------------------------------------------
-- Vector
VectorLit _ v -> traverse evalSub v
VectorReplicate _ n_expr e_expr -> do
ne <- evalSub n_expr
case asNat ne of
Nothing -> addFailedAssertion bak $
Unsupported callStack "vectors with symbolic length"
Just n -> do
e <- evalSub e_expr
return $ V.replicate (fromIntegral n) e
VectorIsEmpty r -> do
v <- evalSub r
return $ backendPred sym (V.null v)
VectorSize v_expr -> do
v <- evalSub v_expr
natLit sym (fromIntegral (V.length v))
VectorGetEntry rtp v_expr i_expr -> do
v <- evalSub v_expr
i <- evalSub i_expr
indexVectorWithSymNat bak (muxRegForType sym itefns rtp) v i
VectorSetEntry rtp v_expr i_expr n_expr -> do
v <- evalSub v_expr
i <- evalSub i_expr
n <- evalSub n_expr
updateVectorWithSymNat bak (muxRegForType sym itefns rtp) v i n
VectorCons _ e_expr v_expr -> do
e <- evalSub e_expr
v <- evalSub v_expr
return $ V.cons e v
--------------------------------------------------------------------
-- Sequence
SequenceNil _tpr -> nilSymSequence sym
SequenceCons _tpr x xs ->
join $ consSymSequence sym <$> evalSub x <*> evalSub xs
SequenceAppend _tpr xs ys ->
join $ appendSymSequence sym <$> evalSub xs <*> evalSub ys
SequenceIsNil _tpr xs ->
isNilSymSequence sym =<< evalSub xs
SequenceLength _tpr xs ->
lengthSymSequence sym =<< evalSub xs
SequenceHead tpr xs ->
headSymSequence sym (muxRegForType sym itefns tpr) =<< evalSub xs
SequenceTail _tpr xs ->
tailSymSequence sym =<< evalSub xs
SequenceUncons tpr xs ->
do xs' <- evalSub xs
mu <- unconsSymSequence sym (muxRegForType sym itefns tpr) xs'
traverse (\ (h,tl) -> pure (Ctx.Empty Ctx.:> RV h Ctx.:> RV tl)) mu
--------------------------------------------------------------------
-- Symbolic Arrays
SymArrayLookup _ a i -> do
join $ arrayLookup sym <$> evalSub a <*> traverseFC (evalBase sym evalSub) i
SymArrayUpdate _ a i v -> do
join $ arrayUpdate sym
<$> evalSub a
<*> traverseFC (evalBase sym evalSub) i
<*> evalSub v
----------------------------------------------------------------------
-- Handle
HandleLit h -> return (HandleFnVal h)
Closure _ _ h_expr tp v_expr -> do
h <- evalSub h_expr
v <- evalSub v_expr
return $! ClosureFnVal h tp v
----------------------------------------------------------------------
-- RealVal
RationalLit d -> realLit sym d
RealNeg xe -> do
x <- evalSub xe
realNeg sym x
RealAdd xe ye -> do
x <- evalSub xe
y <- evalSub ye
realAdd sym x y
RealSub xe ye -> do
x <- evalSub xe
y <- evalSub ye
realSub sym x y
RealMul xe ye -> do
x <- evalSub xe
y <- evalSub ye
realMul sym x y
RealDiv xe ye -> do
x <- evalSub xe
y <- evalSub ye
realDiv sym x y
RealMod xe ye -> do
x <- evalSub xe
y <- evalSub ye
realMod sym x y
RealLt x_expr y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
realLt sym x y
RealLe x_expr y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
realLe sym x y
RealIsInteger x_expr -> do
x <- evalSub x_expr
isInteger sym x
----------------------------------------------------------------------
-- Float
-- This is not necessarily considered correct, see crucible#366
FloatUndef f -> freshConstant sym emptySymbol (iFloatBaseTypeRepr sym f)
FloatLit f -> iFloatLitSingle sym f
DoubleLit d -> iFloatLitDouble sym d
X86_80Lit ld -> iFloatLitLongDouble sym ld
FloatNaN fi -> iFloatNaN sym fi
FloatPInf fi -> iFloatPInf sym fi
FloatNInf fi -> iFloatNInf sym fi
FloatPZero fi -> iFloatPZero sym fi
FloatNZero fi -> iFloatNZero sym fi
FloatNeg _ (x_expr :: f (FloatType fi)) ->
iFloatNeg @_ @fi sym =<< evalSub x_expr
FloatAbs _ (x_expr :: f (FloatType fi)) ->
iFloatAbs @_ @fi sym =<< evalSub x_expr
FloatSqrt _ rm (x_expr :: f (FloatType fi)) ->
iFloatSqrt @_ @fi sym rm =<< evalSub x_expr
FloatAdd _ rm (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatAdd @_ @fi sym rm x y
FloatSub _ rm (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatSub @_ @fi sym rm x y
FloatMul _ rm (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatMul @_ @fi sym rm x y
FloatDiv _ rm (x_expr :: f (FloatType fi)) y_expr -> do
-- TODO: handle division by zero
x <- evalSub x_expr
y <- evalSub y_expr
iFloatDiv @_ @fi sym rm x y
FloatRem _ (x_expr :: f (FloatType fi)) y_expr -> do
-- TODO: handle division by zero
x <- evalSub x_expr
y <- evalSub y_expr
iFloatRem @_ @fi sym x y
FloatMin _ (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatMin @_ @fi sym x y
FloatMax _ (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatMax @_ @fi sym x y
FloatFMA _ rm (x_expr :: f (FloatType fi)) y_expr z_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
z <- evalSub z_expr
iFloatFMA @_ @fi sym rm x y z
FloatEq (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatEq @_ @fi sym x y
FloatFpEq (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatFpEq @_ @fi sym x y
FloatIte _ c_expr (x_expr :: f (FloatType fi)) y_expr -> do
c <- evalSub c_expr
x <- evalSub x_expr
y <- evalSub y_expr
iFloatIte @_ @fi sym c x y
FloatLt (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatLt @_ @fi sym x y
FloatLe (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatLe @_ @fi sym x y
FloatGt (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatGt @_ @fi sym x y
FloatGe (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatGe @_ @fi sym x y
FloatNe (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatNe @_ @fi sym x y
FloatFpApart (x_expr :: f (FloatType fi)) y_expr -> do
x <- evalSub x_expr
y <- evalSub y_expr
iFloatFpApart @_ @fi sym x y
FloatCast fi rm (x_expr :: f (FloatType fi')) ->
iFloatCast @_ @_ @fi' sym fi rm =<< evalSub x_expr
FloatFromBinary fi x_expr -> iFloatFromBinary sym fi =<< evalSub x_expr
FloatToBinary fi x_expr -> iFloatToBinary sym fi =<< evalSub x_expr
FloatFromBV fi rm x_expr -> iBVToFloat sym fi rm =<< evalSub x_expr
FloatFromSBV fi rm x_expr -> iSBVToFloat sym fi rm =<< evalSub x_expr
FloatFromReal fi rm x_expr -> iRealToFloat sym fi rm =<< evalSub x_expr
FloatToBV w rm (x_expr :: f (FloatType fi)) ->
iFloatToBV @_ @_ @fi sym w rm =<< evalSub x_expr
FloatToSBV w rm (x_expr :: f (FloatType fi)) ->
iFloatToSBV @_ @_ @fi sym w rm =<< evalSub x_expr
FloatToReal (x_expr :: f (FloatType fi)) ->
iFloatToReal @_ @fi sym =<< evalSub x_expr
FloatIsNaN (x_expr :: f (FloatType fi)) ->
iFloatIsNaN @_ @fi sym =<< evalSub x_expr
FloatIsInfinite (x_expr :: f (FloatType fi)) ->
iFloatIsInf @_ @fi sym =<< evalSub x_expr
FloatIsZero (x_expr :: f (FloatType fi)) ->
iFloatIsZero @_ @fi sym =<< evalSub x_expr
FloatIsPositive (x_expr :: f (FloatType fi)) ->
iFloatIsPos @_ @fi sym =<< evalSub x_expr
FloatIsNegative (x_expr :: f (FloatType fi)) ->
iFloatIsNeg @_ @fi sym =<< evalSub x_expr
FloatIsSubnormal (x_expr :: f (FloatType fi)) ->
iFloatIsSubnorm @_ @fi sym =<< evalSub x_expr
FloatIsNormal (x_expr :: f (FloatType fi)) ->
iFloatIsNorm @_ @fi sym =<< evalSub x_expr
----------------------------------------------------------------------
-- Conversions
NatToInteger x_expr -> do
x <- evalSub x_expr
natToInteger sym x
IntegerToReal x_expr -> do
x <- evalSub x_expr
integerToReal sym x
RealToNat x_expr -> do
x <- evalSub x_expr
realToNat sym x
BvToNat _ xe -> do
bvToNat sym =<< evalSub xe
BvToInteger _ xe -> do
bvToInteger sym =<< evalSub xe
SbvToInteger _ xe -> do
sbvToInteger sym =<< evalSub xe
RealFloor xe ->
realFloor sym =<< evalSub xe
RealCeil xe ->
realCeil sym =<< evalSub xe
RealRound xe ->
realRound sym =<< evalSub xe
IntegerToBV w xe -> do
x <- evalSub xe
integerToBV sym x w
----------------------------------------------------------------------
-- ComplexReal
Complex r_expr i_expr -> do
r <- evalSub r_expr
i <- evalSub i_expr
mkComplex sym (r :+ i)
RealPart c_expr -> getRealPart sym =<< evalSub c_expr
ImagPart c_expr -> getImagPart sym =<< evalSub c_expr
--------------------------------------------------------------------
-- BVs
-- This is not necessarily considered correct, see crucible#366
BVUndef w ->
freshConstant sym emptySymbol (BaseBVRepr w)
BVLit w bv -> bvLit sym w bv
BVConcat _ _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvConcat sym x y
-- FIXME: there are probably some worthwhile special cases to exploit in "BVSelect"
BVSelect idx n _ xe -> do
x <- evalSub xe
bvSelect sym idx n x
BVTrunc w' _ xe -> do
x <- evalSub xe
bvTrunc sym w' x
BVZext w' _ xe -> do
x <- evalSub xe
bvZext sym w' x
BVSext w' _ xe -> do
x <- evalSub xe
bvSext sym w' x
BVNot _ xe ->
bvNotBits sym =<< evalSub xe
BVAnd _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvAndBits sym x y
BVOr _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvOrBits sym x y
BVXor _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvXorBits sym x y
BVAdd _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvAdd sym x y
BVNeg _ xe -> do
x <- evalSub xe
bvNeg sym x
BVSub _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvSub sym x y
BVMul _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvMul sym x y
BVUdiv _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvUdiv sym x y
BVSdiv _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvSdiv sym x y
BVUrem _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvUrem sym x y
BVSrem _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvSrem sym x y
BVUlt _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvUlt sym x y
BVSlt _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvSlt sym x y
BoolToBV w xe -> do
x <- evalSub xe
one <- bvLit sym w (BV.one w)
zro <- bvLit sym w (BV.zero w)
bvIte sym x one zro
BVNonzero _ xe -> do
x <- evalSub xe
bvIsNonzero sym x
BVShl _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvShl sym x y
BVLshr _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvLshr sym x y
BVAshr _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvAshr sym x y
BVRol _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvRol sym x y
BVRor _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvRor sym x y
BVCountTrailingZeros _ xe -> do
x <- evalSub xe
bvCountTrailingZeros sym x
BVCountLeadingZeros _ xe -> do
x <- evalSub xe
bvCountLeadingZeros sym x
BVPopcount _ xe -> do
x <- evalSub xe
bvPopcount sym x
BVCarry _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
fst <$> addUnsignedOF sym x y
BVSCarry _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
fst <$> addSignedOF sym x y
BVSBorrow _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
fst <$> subSignedOF sym x y
BVUle _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvUle sym x y
BVSle _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
bvSle sym x y
BVUMin _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
c <- bvUle sym x y
bvIte sym c x y
BVUMax _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
c <- bvUgt sym x y
bvIte sym c x y
BVSMin _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
c <- bvSle sym x y
bvIte sym c x y
BVSMax _ xe ye -> do
x <- evalSub xe
y <- evalSub ye
c <- bvSgt sym x y
bvIte sym c x y
--------------------------------------------------------------------
-- Word Maps
EmptyWordMap w tp -> do
emptyWordMap sym w tp
InsertWordMap w tp ie ve me -> do
i <- evalSub ie
v <- evalSub ve
m <- evalSub me
insertWordMap sym w tp i v m
LookupWordMap tp ie me -> do
i <- evalSub ie
m <- evalSub me
x <- lookupWordMap sym (bvWidth i) tp i m
let msg = "WordMap: read an undefined index" ++
case asBV i of
Nothing -> ""
Just (BV.BV idx) -> " 0x" ++ showHex idx ""
let ex = ReadBeforeWriteSimError msg
readPartExpr bak x ex
LookupWordMapWithDefault tp ie me de -> do
i <- evalSub ie
m <- evalSub me
d <- evalSub de
x <- lookupWordMap sym (bvWidth i) tp i m
case x of
Unassigned -> return d
PE p v -> do
muxRegForType sym itefns (baseToType tp) p v d
---------------------------------------------------------------------
-- Struct
MkStruct _ exprs -> traverseFC (\x -> RV <$> evalSub x) exprs
GetStruct st idx _ -> do
struct <- evalSub st
return $ unRV $ struct Ctx.! idx
SetStruct _ st idx x -> do
struct <- evalSub st
v <- evalSub x
return $ struct & ixF idx .~ RV v
----------------------------------------------------------------------
-- Variant
InjectVariant ctx idx ve -> do
v <- evalSub ve
return $ injectVariant sym ctx idx v
ProjectVariant _ctx idx ve -> do
v <- evalSub ve
return $ unVB $ v Ctx.! idx
----------------------------------------------------------------------
-- IdentValueMap
EmptyStringMap _ -> return Map.empty
LookupStringMapEntry _ m_expr i_expr -> do
i <- evalSub i_expr
m <- evalSub m_expr
case asString i of
Just (UnicodeLiteral i') -> return $ joinMaybePE (Map.lookup i' m)
Nothing -> addFailedAssertion bak $
Unsupported callStack "Symbolic string in lookupStringMapEntry"
InsertStringMapEntry _ m_expr i_expr v_expr -> do
m <- evalSub m_expr
i <- evalSub i_expr
v <- evalSub v_expr
case asString i of
Just (UnicodeLiteral i') -> return $ Map.insert i' v m
Nothing -> addFailedAssertion bak $
Unsupported callStack "Symbolic string in insertStringMapEntry"
--------------------------------------------------------------------
-- Strings
StringLit x -> stringLit sym x
ShowValue _bt x_expr -> do
x <- evalSub x_expr
stringLit sym (UnicodeLiteral (Text.pack (show (printSymExpr x))))
ShowFloat _fi x_expr -> do
x <- evalSub x_expr
stringLit sym (UnicodeLiteral (Text.pack (show (printSymExpr x))))
StringConcat _si x y -> do
x' <- evalSub x
y' <- evalSub y
stringConcat sym x' y'
StringEmpty si ->
stringEmpty sym si
StringLength x -> do
x' <- evalSub x
stringLength sym x'
StringContains x y -> do
x' <- evalSub x
y' <- evalSub y
stringContains sym x' y'
StringIsPrefixOf x y -> do
x' <- evalSub x
y' <- evalSub y
stringIsPrefixOf sym x' y'
StringIsSuffixOf x y -> do
x' <- evalSub x
y' <- evalSub y
stringIsSuffixOf sym x' y'
StringIndexOf x y k -> do
x' <- evalSub x
y' <- evalSub y
k' <- evalSub k
stringIndexOf sym x' y' k'
StringSubstring _si x off len -> do
x' <- evalSub x
off' <- evalSub off
len' <- evalSub len
stringSubstring sym x' off' len'
---------------------------------------------------------------------
-- Introspection
IsConcrete _ v -> do
x <- baseIsConcrete <$> evalSub v
return $! if x then truePred sym else falsePred sym
---------------------------------------------------------------------
-- References
ReferenceEq _ ref1 ref2 -> do
cell1 <- evalSub ref1
cell2 <- evalSub ref2
eqReference sym cell1 cell2