{-# LANGUAGE BangPatterns #-}
module Data.SBV.Core.Operations
(
svTrue, svFalse, svBool
, svInteger, svFloat, svDouble, svReal, svEnumFromThenTo, svString, svChar
, svAsBool, svAsInteger, svNumerator, svDenominator
, svPlus, svTimes, svMinus, svUNeg, svAbs
, svDivide, svQuot, svRem, svQuotRem
, svEqual, svNotEqual
, svLessThan, svGreaterThan, svLessEq, svGreaterEq
, svAnd, svOr, svXOr, svNot
, svShl, svShr, svRol, svRor
, svExtract, svJoin
, svIte, svLazyIte, svSymbolicMerge
, svSelect
, svSign, svUnsign, svSetBit, svWordFromBE, svWordFromLE
, svExp, svFromIntegral
, svMkOverflow
, svToWord1, svFromWord1, svTestBit
, svShiftLeft, svShiftRight
, svRotateLeft, svRotateRight
, svBlastLE, svBlastBE
, svAddConstant, svIncrement, svDecrement
, SArr, readSArr, writeSArr, mergeSArr, newSArr, eqSArr
, SFunArr(..), readSFunArr, writeSFunArr, mergeSFunArr, newSFunArr
, mkSymOp
)
where
import Data.Bits (Bits(..))
import Data.List (genericIndex, genericLength, genericTake)
import qualified Data.IORef as R (modifyIORef', newIORef, readIORef)
import qualified Data.Map.Strict as Map (toList, fromList, lookup)
import qualified Data.IntMap.Strict as IMap (IntMap, empty, toAscList, fromAscList, lookup, size, insert)
import Data.SBV.Core.AlgReals
import Data.SBV.Core.Kind
import Data.SBV.Core.Concrete
import Data.SBV.Core.Symbolic
import Data.Ratio
svTrue :: SVal
svTrue = SVal KBool (Left trueCW)
svFalse :: SVal
svFalse = SVal KBool (Left falseCW)
svBool :: Bool -> SVal
svBool b = if b then svTrue else svFalse
svInteger :: Kind -> Integer -> SVal
svInteger k n = SVal k (Left $! mkConstCW k n)
svFloat :: Float -> SVal
svFloat f = SVal KFloat (Left $! CW KFloat (CWFloat f))
svDouble :: Double -> SVal
svDouble d = SVal KDouble (Left $! CW KDouble (CWDouble d))
svString :: String -> SVal
svString s = SVal KString (Left $! CW KString (CWString s))
svChar :: Char -> SVal
svChar c = SVal KChar (Left $! CW KChar (CWChar c))
svReal :: Rational -> SVal
svReal d = SVal KReal (Left $! CW KReal (CWAlgReal (fromRational d)))
svAsBool :: SVal -> Maybe Bool
svAsBool (SVal _ (Left cw)) = Just (cwToBool cw)
svAsBool _ = Nothing
svAsInteger :: SVal -> Maybe Integer
svAsInteger (SVal _ (Left (CW _ (CWInteger n)))) = Just n
svAsInteger _ = Nothing
svNumerator :: SVal -> Maybe Integer
svNumerator (SVal KReal (Left (CW KReal (CWAlgReal (AlgRational True r))))) = Just $ numerator r
svNumerator _ = Nothing
svDenominator :: SVal -> Maybe Integer
svDenominator (SVal KReal (Left (CW KReal (CWAlgReal (AlgRational True r))))) = Just $ denominator r
svDenominator _ = Nothing
svEnumFromThenTo :: SVal -> Maybe SVal -> SVal -> Maybe [SVal]
svEnumFromThenTo bf mbs bt
| Just bs <- mbs, Just f <- svAsInteger bf, Just s <- svAsInteger bs, Just t <- svAsInteger bt, s /= f = Just $ map (svInteger (kindOf bf)) [f, s .. t]
| Nothing <- mbs, Just f <- svAsInteger bf, Just t <- svAsInteger bt = Just $ map (svInteger (kindOf bf)) [f .. t]
| True = Nothing
svPlus :: SVal -> SVal -> SVal
svPlus x y
| isConcreteZero x = y
| isConcreteZero y = x
| True = liftSym2 (mkSymOp Plus) rationalCheck (+) (+) (+) (+) x y
svTimes :: SVal -> SVal -> SVal
svTimes x y
| isConcreteZero x = x
| isConcreteZero y = y
| isConcreteOne x = y
| isConcreteOne y = x
| True = liftSym2 (mkSymOp Times) rationalCheck (*) (*) (*) (*) x y
svMinus :: SVal -> SVal -> SVal
svMinus x y
| isConcreteZero y = x
| True = liftSym2 (mkSymOp Minus) rationalCheck (-) (-) (-) (-) x y
svUNeg :: SVal -> SVal
svUNeg = liftSym1 (mkSymOp1 UNeg) negate negate negate negate
svAbs :: SVal -> SVal
svAbs = liftSym1 (mkSymOp1 Abs) abs abs abs abs
svDivide :: SVal -> SVal -> SVal
svDivide = liftSym2 (mkSymOp Quot) rationalCheck (/) idiv (/) (/)
where idiv x 0 = x
idiv x y = x `div` y
svExp :: SVal -> SVal -> SVal
svExp b e
| Just x <- svAsInteger e
= if x >= 0 then let go n v
| n == 0 = one
| even n = go (n `div` 2) (svTimes v v)
| True = svTimes v $ go (n `div` 2) (svTimes v v)
in go x b
else error $ "svExp: exponentiation: negative exponent: " ++ show x
| not (isBounded e) || hasSign e
= error $ "svExp: exponentiation only works with unsigned bounded symbolic exponents, kind: " ++ show (kindOf e)
| True
= prod $ zipWith (\use n -> svIte use n one)
(svBlastLE e)
(iterate (\x -> svTimes x x) b)
where prod = foldr svTimes one
one = svInteger (kindOf b) 1
svBlastLE :: SVal -> [SVal]
svBlastLE x = map (svTestBit x) [0 .. intSizeOf x - 1]
svSetBit :: SVal -> Int -> SVal
svSetBit x i = x `svOr` svInteger (kindOf x) (bit i :: Integer)
svBlastBE :: SVal -> [SVal]
svBlastBE = reverse . svBlastLE
svWordFromLE :: [SVal] -> SVal
svWordFromLE bs = go zero 0 bs
where zero = svInteger (KBounded False (length bs)) 0
go !acc _ [] = acc
go !acc !i (x:xs) = go (svIte x (svSetBit acc i) acc) (i+1) xs
svWordFromBE :: [SVal] -> SVal
svWordFromBE = svWordFromLE . reverse
svAddConstant :: Integral a => SVal -> a -> SVal
svAddConstant x i = x `svPlus` svInteger (kindOf x) (fromIntegral i)
svIncrement :: SVal -> SVal
svIncrement x = svAddConstant x (1::Integer)
svDecrement :: SVal -> SVal
svDecrement x = svAddConstant x (-1 :: Integer)
svQuot :: SVal -> SVal -> SVal
svQuot x y
| isConcreteZero x = x
| isConcreteZero y = svInteger (kindOf x) 0
| isConcreteOne y = x
| True = liftSym2 (mkSymOp Quot) nonzeroCheck
(noReal "quot") quot' (noFloat "quot") (noDouble "quot") x y
where
quot' a b | kindOf x == KUnbounded = div a (abs b) * signum b
| otherwise = quot a b
svRem :: SVal -> SVal -> SVal
svRem x y
| isConcreteZero x = x
| isConcreteZero y = x
| isConcreteOne y = svInteger (kindOf x) 0
| True = liftSym2 (mkSymOp Rem) nonzeroCheck
(noReal "rem") rem' (noFloat "rem") (noDouble "rem") x y
where
rem' a b | kindOf x == KUnbounded = mod a (abs b)
| otherwise = rem a b
svQuotRem :: SVal -> SVal -> (SVal, SVal)
svQuotRem x y = (x `svQuot` y, x `svRem` y)
eqOptBool :: Op -> SW -> SW -> SW -> Maybe SW
eqOptBool op w x y
| k == KBool && op == Equal && x == trueSW = Just y
| k == KBool && op == Equal && y == trueSW = Just x
| k == KBool && op == NotEqual && x == falseSW = Just y
| k == KBool && op == NotEqual && y == falseSW = Just x
| True = eqOpt w x y
where k = swKind x
svEqual :: SVal -> SVal -> SVal
svEqual = liftSym2B (mkSymOpSC (eqOptBool Equal trueSW) Equal) rationalCheck (==) (==) (==) (==) (==) (==) (==) (==)
svNotEqual :: SVal -> SVal -> SVal
svNotEqual = liftSym2B (mkSymOpSC (eqOptBool NotEqual falseSW) NotEqual) rationalCheck (/=) (/=) (/=) (/=) (/=) (/=) (/=) (/=)
svLessThan :: SVal -> SVal -> SVal
svLessThan x y
| isConcreteMax x = svFalse
| isConcreteMin y = svFalse
| True = liftSym2B (mkSymOpSC (eqOpt falseSW) LessThan) rationalCheck (<) (<) (<) (<) (<) (<) (<) (uiLift "<" (<)) x y
svGreaterThan :: SVal -> SVal -> SVal
svGreaterThan x y
| isConcreteMin x = svFalse
| isConcreteMax y = svFalse
| True = liftSym2B (mkSymOpSC (eqOpt falseSW) GreaterThan) rationalCheck (>) (>) (>) (>) (>) (>) (>) (uiLift ">" (>)) x y
svLessEq :: SVal -> SVal -> SVal
svLessEq x y
| isConcreteMin x = svTrue
| isConcreteMax y = svTrue
| True = liftSym2B (mkSymOpSC (eqOpt trueSW) LessEq) rationalCheck (<=) (<=) (<=) (<=) (<=) (<=) (<=) (uiLift "<=" (<=)) x y
svGreaterEq :: SVal -> SVal -> SVal
svGreaterEq x y
| isConcreteMax x = svTrue
| isConcreteMin y = svTrue
| True = liftSym2B (mkSymOpSC (eqOpt trueSW) GreaterEq) rationalCheck (>=) (>=) (>=) (>=) (>=) (>=) (>=) (uiLift ">=" (>=)) x y
svAnd :: SVal -> SVal -> SVal
svAnd x y
| isConcreteZero x = x
| isConcreteOnes x = y
| isConcreteZero y = y
| isConcreteOnes y = x
| True = liftSym2 (mkSymOpSC opt And) (const (const True)) (noReal ".&.") (.&.) (noFloat ".&.") (noDouble ".&.") x y
where opt a b
| a == falseSW || b == falseSW = Just falseSW
| a == trueSW = Just b
| b == trueSW = Just a
| True = Nothing
svOr :: SVal -> SVal -> SVal
svOr x y
| isConcreteZero x = y
| isConcreteOnes x = x
| isConcreteZero y = x
| isConcreteOnes y = y
| True = liftSym2 (mkSymOpSC opt Or) (const (const True))
(noReal ".|.") (.|.) (noFloat ".|.") (noDouble ".|.") x y
where opt a b
| a == trueSW || b == trueSW = Just trueSW
| a == falseSW = Just b
| b == falseSW = Just a
| True = Nothing
svXOr :: SVal -> SVal -> SVal
svXOr x y
| isConcreteZero x = y
| isConcreteOnes x = svNot y
| isConcreteZero y = x
| isConcreteOnes y = svNot x
| True = liftSym2 (mkSymOpSC opt XOr) (const (const True))
(noReal "xor") xor (noFloat "xor") (noDouble "xor") x y
where opt a b
| a == b && swKind a == KBool = Just falseSW
| a == falseSW = Just b
| b == falseSW = Just a
| True = Nothing
svNot :: SVal -> SVal
svNot = liftSym1 (mkSymOp1SC opt Not)
(noRealUnary "complement") complement
(noFloatUnary "complement") (noDoubleUnary "complement")
where opt a
| a == falseSW = Just trueSW
| a == trueSW = Just falseSW
| True = Nothing
svShl :: SVal -> Int -> SVal
svShl x i
| i <= 0
= x
| isBounded x, i >= intSizeOf x
= svInteger k 0
| True
= x `svShiftLeft` svInteger k (fromIntegral i)
where k = kindOf x
svShr :: SVal -> Int -> SVal
svShr x i
| i <= 0
= x
| isBounded x, i >= intSizeOf x
= if not (hasSign x)
then z
else svIte (x `svLessThan` z) neg1 z
| True
= x `svShiftRight` svInteger k (fromIntegral i)
where k = kindOf x
z = svInteger k 0
neg1 = svInteger k (-1)
svRol :: SVal -> Int -> SVal
svRol x i
| i <= 0
= x
| True
= case kindOf x of
KBounded _ sz -> liftSym1 (mkSymOp1 (Rol (i `mod` sz)))
(noRealUnary "rotateL") (rot True sz i)
(noFloatUnary "rotateL") (noDoubleUnary "rotateL") x
_ -> svShl x i
svRor :: SVal -> Int -> SVal
svRor x i
| i <= 0
= x
| True
= case kindOf x of
KBounded _ sz -> liftSym1 (mkSymOp1 (Ror (i `mod` sz)))
(noRealUnary "rotateR") (rot False sz i)
(noFloatUnary "rotateR") (noDoubleUnary "rotateR") x
_ -> svShr x i
rot :: Bool -> Int -> Int -> Integer -> Integer
rot toLeft sz amt x
| sz < 2 = x
| True = norm x y' `shiftL` y .|. norm (x `shiftR` y') y
where (y, y') | toLeft = (amt `mod` sz, sz - y)
| True = (sz - y', amt `mod` sz)
norm v s = v .&. ((1 `shiftL` s) - 1)
svExtract :: Int -> Int -> SVal -> SVal
svExtract i j x@(SVal (KBounded s _) _)
| i < j
= SVal k (Left $! CW k (CWInteger 0))
| SVal _ (Left (CW _ (CWInteger v))) <- x
= SVal k (Left $! normCW (CW k (CWInteger (v `shiftR` j))))
| True
= SVal k (Right (cache y))
where k = KBounded s (i - j + 1)
y st = do sw <- svToSW st x
newExpr st k (SBVApp (Extract i j) [sw])
svExtract _ _ _ = error "extract: non-bitvector type"
svJoin :: SVal -> SVal -> SVal
svJoin x@(SVal (KBounded s i) a) y@(SVal (KBounded _ j) b)
| i == 0 = y
| j == 0 = x
| Left (CW _ (CWInteger m)) <- a, Left (CW _ (CWInteger n)) <- b
= SVal k (Left $! CW k (CWInteger (m `shiftL` j .|. n)))
| True
= SVal k (Right (cache z))
where
k = KBounded s (i + j)
z st = do xsw <- svToSW st x
ysw <- svToSW st y
newExpr st k (SBVApp Join [xsw, ysw])
svJoin _ _ = error "svJoin: non-bitvector type"
svIte :: SVal -> SVal -> SVal -> SVal
svIte t a b = svSymbolicMerge (kindOf a) True t a b
svLazyIte :: Kind -> SVal -> SVal -> SVal -> SVal
svLazyIte k t a b = svSymbolicMerge k False t a b
svSymbolicMerge :: Kind -> Bool -> SVal -> SVal -> SVal -> SVal
svSymbolicMerge k force t a b
| Just r <- svAsBool t
= if r then a else b
| force, rationalSBVCheck a b, sameResult a b
= a
| True
= SVal k $ Right $ cache c
where sameResult (SVal _ (Left c1)) (SVal _ (Left c2)) = c1 == c2
sameResult _ _ = False
c st = do swt <- svToSW st t
case () of
() | swt == trueSW -> svToSW st a
() | swt == falseSW -> svToSW st b
() -> do
let sta = st `extendSValPathCondition` svAnd t
let stb = st `extendSValPathCondition` svAnd (svNot t)
swa <- svToSW sta a
swb <- svToSW stb b
case () of
() | swa == swb -> return swa
() | swa == trueSW && swb == falseSW -> return swt
() | swa == falseSW && swb == trueSW -> newExpr st k (SBVApp Not [swt])
() -> newExpr st k (SBVApp Ite [swt, swa, swb])
svSelect :: [SVal] -> SVal -> SVal -> SVal
svSelect xs err ind
| SVal _ (Left c) <- ind =
case cwVal c of
CWInteger i -> if i < 0 || i >= genericLength xs
then err
else xs `genericIndex` i
_ -> error $ "SBV.select: unsupported " ++ show (kindOf ind) ++ " valued select/index expression"
svSelect xsOrig err ind = xs `seq` SVal kElt (Right (cache r))
where
kInd = kindOf ind
kElt = kindOf err
xs = case kInd of
KBounded False i -> genericTake ((2::Integer) ^ i) xsOrig
KBounded True i -> genericTake ((2::Integer) ^ (i-1)) xsOrig
KUnbounded -> xsOrig
_ -> error $ "SBV.select: unsupported " ++ show kInd ++ " valued select/index expression"
r st = do sws <- mapM (svToSW st) xs
swe <- svToSW st err
if all (== swe) sws
then return swe
else do idx <- getTableIndex st kInd kElt sws
swi <- svToSW st ind
let len = length xs
newExpr st kElt (SBVApp (LkUp (idx, kInd, kElt, len) swi swe) [])
svChangeSign :: Bool -> SVal -> SVal
svChangeSign s x
| Just n <- svAsInteger x = svInteger k n
| True = SVal k (Right (cache y))
where
k = KBounded s (intSizeOf x)
y st = do xsw <- svToSW st x
newExpr st k (SBVApp (Extract (intSizeOf x - 1) 0) [xsw])
svSign :: SVal -> SVal
svSign = svChangeSign True
svUnsign :: SVal -> SVal
svUnsign = svChangeSign False
svFromIntegral :: Kind -> SVal -> SVal
svFromIntegral kTo x
| Just v <- svAsInteger x
= svInteger kTo v
| True
= result
where result = SVal kTo (Right (cache y))
kFrom = kindOf x
y st = do xsw <- svToSW st x
newExpr st kTo (SBVApp (KindCast kFrom kTo) [xsw])
svToWord1 :: SVal -> SVal
svToWord1 b = svSymbolicMerge k True b (svInteger k 1) (svInteger k 0)
where k = KBounded False 1
svFromWord1 :: SVal -> SVal
svFromWord1 x = svNotEqual x (svInteger k 0)
where k = kindOf x
svTestBit :: SVal -> Int -> SVal
svTestBit x i
| i < intSizeOf x = svFromWord1 (svExtract i i x)
| True = svFalse
svShiftLeft :: SVal -> SVal -> SVal
svShiftLeft = svShift True
svShiftRight :: SVal -> SVal -> SVal
svShiftRight = svShift False
svShift :: Bool -> SVal -> SVal -> SVal
svShift toLeft x i
| Just r <- constFoldValue
= r
| cannotOverShift
= svIte (i `svLessThan` svInteger ki 0)
x
regularShiftValue
| True
= svIte (i `svLessThan` svInteger ki 0)
x
$ svIte (i `svGreaterEq` svInteger ki (fromIntegral (intSizeOf x)))
overShiftValue
regularShiftValue
where nm | toLeft = "shiftLeft"
| True = "shiftRight"
kx = kindOf x
ki = kindOf i
constFoldValue
| Just iv <- getConst i, iv == 0
= Just x
| Just xv <- getConst x, xv == 0
= Just x
| Just xv <- getConst x, Just iv <- getConst i
= Just $ SVal kx . Left $! normCW $ CW kx (CWInteger (xv `opC` shiftAmount iv))
| isInteger x || isInteger i
= bailOut $ "Not yet implemented unbounded/non-constants shifts for " ++ show (kx, ki) ++ ", please file a request!"
| not (isBounded x && isBounded i)
= bailOut $ "Unexpected kinds: " ++ show (kx, ki)
| True
= Nothing
where bailOut m = error $ "SBV." ++ nm ++ ": " ++ m
getConst (SVal _ (Left (CW _ (CWInteger val)))) = Just val
getConst _ = Nothing
opC | toLeft = shiftL
| True = shiftR
shiftAmount :: Integer -> Int
shiftAmount iv
| iv <= 0 = 0
| isInteger i, iv > fromIntegral (maxBound :: Int) = bailOut $ "Unsupported constant unbounded shift with amount: " ++ show iv
| isInteger x = fromIntegral iv
| iv >= fromIntegral ub = ub
| not (isBounded x && isBounded i) = bailOut $ "Unsupported kinds: " ++ show (kx, ki)
| True = fromIntegral iv
where ub = intSizeOf x
cannotOverShift = maxRepresentable <= fromIntegral (intSizeOf x)
where maxRepresentable :: Integer
maxRepresentable
| hasSign i = bit (intSizeOf i - 1) - 1
| True = bit (intSizeOf i ) - 1
overShiftValue | toLeft = zx
| hasSign x = svIte (x `svLessThan` zx) neg1 zx
| True = zx
where zx = svInteger kx 0
neg1 = svInteger kx (-1)
regularShiftValue = SVal kx $ Right $ cache result
where result st = do sw1 <- svToSW st x
sw2 <- svToSW st i
let op | toLeft = Shl
| True = Shr
adjustedShift <- if kx == ki
then return sw2
else newExpr st kx (SBVApp (KindCast ki kx) [sw2])
newExpr st kx (SBVApp op [sw1, adjustedShift])
svRotateLeft :: SVal -> SVal -> SVal
svRotateLeft x i
| not (isBounded x)
= svShiftLeft x i
| isBounded i && bit si <= toInteger sx
= svIte (svLessThan i zi)
(svSelect [x `svRor` k | k <- [0 .. bit si - 1]] z (svUNeg i))
(svSelect [x `svRol` k | k <- [0 .. bit si - 1]] z i)
| True
= svIte (svLessThan i zi)
(svSelect [x `svRor` k | k <- [0 .. sx - 1]] z (svUNeg i `svRem` n))
(svSelect [x `svRol` k | k <- [0 .. sx - 1]] z ( i `svRem` n))
where sx = intSizeOf x
si = intSizeOf i
z = svInteger (kindOf x) 0
zi = svInteger (kindOf i) 0
n = svInteger (kindOf i) (toInteger sx)
svRotateRight :: SVal -> SVal -> SVal
svRotateRight x i
| not (isBounded x)
= svShiftRight x i
| isBounded i && bit si <= toInteger sx
= svIte (svLessThan i zi)
(svSelect [x `svRol` k | k <- [0 .. bit si - 1]] z (svUNeg i))
(svSelect [x `svRor` k | k <- [0 .. bit si - 1]] z i)
| True
= svIte (svLessThan i zi)
(svSelect [x `svRol` k | k <- [0 .. sx - 1]] z (svUNeg i `svRem` n))
(svSelect [x `svRor` k | k <- [0 .. sx - 1]] z ( i `svRem` n))
where sx = intSizeOf x
si = intSizeOf i
z = svInteger (kindOf x) 0
zi = svInteger (kindOf i) 0
n = svInteger (kindOf i) (toInteger sx)
svMkOverflow :: OvOp -> SVal -> SVal -> SVal
svMkOverflow o x y = SVal KBool (Right (cache r))
where r st = do sx <- svToSW st x
sy <- svToSW st y
newExpr st KBool $ SBVApp (OverflowOp o) [sx, sy]
data SArr = SArr (Kind, Kind) (Cached ArrayIndex)
readSArr :: SArr -> SVal -> SVal
readSArr (SArr (_, bk) f) a = SVal bk $ Right $ cache r
where r st = do arr <- uncacheAI f st
i <- svToSW st a
newExpr st bk (SBVApp (ArrRead arr) [i])
writeSArr :: SArr -> SVal -> SVal -> SArr
writeSArr (SArr ainfo f) a b = SArr ainfo $ cache g
where g st = do arr <- uncacheAI f st
addr <- svToSW st a
val <- svToSW st b
amap <- R.readIORef (rArrayMap st)
let j = ArrayIndex $ IMap.size amap
upd = IMap.insert (unArrayIndex j) ("array_" ++ show j, ainfo, ArrayMutate arr addr val)
j `seq` modifyState st rArrayMap upd $ modifyIncState st rNewArrs upd
return j
mergeSArr :: SVal -> SArr -> SArr -> SArr
mergeSArr t (SArr ainfo a) (SArr _ b) = SArr ainfo $ cache h
where h st = do ai <- uncacheAI a st
bi <- uncacheAI b st
ts <- svToSW st t
amap <- R.readIORef (rArrayMap st)
let k = ArrayIndex $ IMap.size amap
upd = IMap.insert (unArrayIndex k) ("array_" ++ show k, ainfo, ArrayMerge ts ai bi)
k `seq` modifyState st rArrayMap upd $ modifyIncState st rNewArrs upd
return k
newSArr :: State -> (Kind, Kind) -> (Int -> String) -> Maybe SVal -> IO SArr
newSArr st ainfo mkNm mbDef = do
amap <- R.readIORef $ rArrayMap st
mbSWDef <- case mbDef of
Nothing -> return Nothing
Just sv -> Just <$> svToSW st sv
let i = ArrayIndex $ IMap.size amap
nm = mkNm (unArrayIndex i)
upd = IMap.insert (unArrayIndex i) (nm, ainfo, ArrayFree mbSWDef)
registerLabel "SArray declaration" st nm
modifyState st rArrayMap upd $ modifyIncState st rNewArrs upd
return $ SArr ainfo $ cache $ const $ return i
eqSArr :: SArr -> SArr -> SVal
eqSArr (SArr _ a) (SArr _ b) = SVal KBool $ Right $ cache c
where c st = do ai <- uncacheAI a st
bi <- uncacheAI b st
newExpr st KBool (SBVApp (ArrEq ai bi) [])
data SFunArr = SFunArr (Kind, Kind) (Cached FArrayIndex)
nodeIdToSVal :: Kind -> Int -> SVal
nodeIdToSVal k i = swToSVal $ SW k (NodeId i)
swToSVal :: SW -> SVal
swToSVal sw@(SW k _) = SVal k $ Right $ cache $ const $ return sw
svEqualWithConsts :: (SVal, Maybe CW) -> (SVal, Maybe CW) -> SVal
svEqualWithConsts sv1 sv2 = case (grabCW sv1, grabCW sv2) of
(Just cw, Just cw') | rationalCheck cw cw' -> if cw == cw' then svTrue else svFalse
_ -> fst sv1 `svEqual` fst sv2
where grabCW (_, Just cw) = Just cw
grabCW (SVal _ (Left cw), _ ) = Just cw
grabCW _ = Nothing
readSFunArr :: SFunArr -> SVal -> SVal
readSFunArr (SFunArr (ak, bk) f) address
| kindOf address /= ak
= error $ "Data.SBV.readSFunArr: Impossible happened, accesing with address type: " ++ show (kindOf address) ++ ", expected: " ++ show ak
| True
= SVal bk $ Right $ cache r
where r st = do fArrayIndex <- uncacheFAI f st
fArrMap <- R.readIORef (rFArrayMap st)
constMap <- R.readIORef (rconstMap st)
let consts = Map.fromList [(i, cw) | (cw, SW _ (NodeId i)) <- Map.toList constMap]
case unFArrayIndex fArrayIndex `IMap.lookup` fArrMap of
Nothing -> error $ "Data.SBV.readSFunArr: Impossible happened while trying to access SFunArray, can't find index: " ++ show fArrayIndex
Just (uninitializedRead, rCache) -> do
memoTable <- R.readIORef rCache
SW _ (NodeId addressNodeId) <- svToSW st address
case addressNodeId `IMap.lookup` memoTable of
Just v -> return v
Nothing ->
do let aInfo = (address, addressNodeId `Map.lookup` consts)
find :: [(Int, SW)] -> SVal
find [] = uninitializedRead address
find ((i, v) : ivs) = svIte (svEqualWithConsts (nodeIdToSVal ak i, i `Map.lookup` consts) aInfo) (swToSVal v) (find ivs)
finalValue = find (IMap.toAscList memoTable)
finalSW <- svToSW st finalValue
R.modifyIORef' rCache (IMap.insert addressNodeId finalSW)
return finalSW
writeSFunArr :: SFunArr -> SVal -> SVal -> SFunArr
writeSFunArr (SFunArr (ak, bk) f) address b
| kindOf address /= ak
= error $ "Data.SBV.writeSFunArr: Impossible happened, accesing with address type: " ++ show (kindOf address) ++ ", expected: " ++ show ak
| kindOf b /= bk
= error $ "Data.SBV.writeSFunArr: Impossible happened, accesing with address type: " ++ show (kindOf b) ++ ", expected: " ++ show bk
| True
= SFunArr (ak, bk) $ cache g
where g st = do fArrayIndex <- uncacheFAI f st
fArrMap <- R.readIORef (rFArrayMap st)
constMap <- R.readIORef (rconstMap st)
let consts = Map.fromList [(i, cw) | (cw, SW _ (NodeId i)) <- Map.toList constMap]
case unFArrayIndex fArrayIndex `IMap.lookup` fArrMap of
Nothing -> error $ "Data.SBV.writeSFunArr: Impossible happened while trying to access SFunArray, can't find index: " ++ show fArrayIndex
Just (aUi, rCache) -> do
memoTable <- R.readIORef rCache
SW _ (NodeId addressNodeId) <- svToSW st address
val <- svToSW st b
cont <- case addressNodeId `IMap.lookup` memoTable of
Just oldVal
| val == oldVal -> return $ Left fArrayIndex
| True -> return $ Right memoTable
Nothing -> do
let aInfo = (address, addressNodeId `Map.lookup` consts)
walk :: [(Int, SW)] -> [(Int, SW)] -> IO [(Int, SW)]
walk [] sofar = return $ reverse sofar
walk ((i, s):iss) sofar = modify i s >>= \s' -> walk iss ((i, s') : sofar)
modify :: Int -> SW -> IO SW
modify i s = svToSW st $ svIte (svEqualWithConsts (nodeIdToSVal ak i, i `Map.lookup` consts) aInfo) b (swToSVal s)
Right . IMap.fromAscList <$> walk (IMap.toAscList memoTable) []
case cont of
Left j -> return j
Right mt -> do
newMemoTable <- R.newIORef $ IMap.insert addressNodeId val mt
let j = FArrayIndex $ IMap.size fArrMap
upd = IMap.insert (unFArrayIndex j) (aUi, newMemoTable)
j `seq` modifyState st rFArrayMap upd (return ())
return j
mergeSFunArr :: SVal -> SFunArr -> SFunArr -> SFunArr
mergeSFunArr t array1@(SFunArr ainfo@(sourceKind, targetKind) a) array2@(SFunArr binfo b)
| ainfo /= binfo
= error $ "Data.SBV.mergeSFunArr: Impossible happened, merging incompatbile arrays: " ++ show (ainfo, binfo)
| Just test <- svAsBool t
= if test then array1 else array2
| True
= SFunArr ainfo $ cache c
where c st = do ai <- uncacheFAI a st
bi <- uncacheFAI b st
constMap <- R.readIORef (rconstMap st)
let consts = Map.fromList [(i, cw) | (cw, SW _ (NodeId i)) <- Map.toList constMap]
if unFArrayIndex ai == unFArrayIndex bi
then return ai
else do fArrMap <- R.readIORef (rFArrayMap st)
case (unFArrayIndex ai `IMap.lookup` fArrMap, unFArrayIndex bi `IMap.lookup` fArrMap) of
(Nothing, _) -> error $ "Data.SBV.mergeSFunArr: Impossible happened while trying to access SFunArray, can't find index: " ++ show ai
(_, Nothing) -> error $ "Data.SBV.mergeSFunArr: Impossible happened while trying to access SFunArray, can't find index: " ++ show bi
(Just (aUi, raCache), Just (bUi, rbCache)) -> do
aMemo <- R.readIORef raCache
bMemo <- R.readIORef rbCache
let aMemoT = IMap.toAscList aMemo
bMemoT = IMap.toAscList bMemo
gen :: (SVal -> SVal) -> Int -> [(Int, SW)] -> IO SW
gen mk k choices = svToSW st $ walk choices
where kInfo = (nodeIdToSVal sourceKind k, k `Map.lookup` consts)
walk :: [(Int, SW)] -> SVal
walk [] = mk (fst kInfo)
walk ((i, v) : ivs) = svIte (svEqualWithConsts (nodeIdToSVal sourceKind i, i `Map.lookup` consts) kInfo)
(swToSVal v)
(walk ivs)
fill :: Int -> SW -> SW -> IMap.IntMap SW -> IO (IMap.IntMap SW)
fill k (SW _ (NodeId ni1)) (SW _ (NodeId ni2)) m = do v <- svToSW st (svIte t sval1 sval2)
return $ IMap.insert k v m
where sval1 = nodeIdToSVal targetKind ni1
sval2 = nodeIdToSVal targetKind ni2
merge [] [] sofar = return sofar
merge ((k1, v1) : as) [] sofar = gen bUi k1 bMemoT >>= \v2 -> fill k1 v1 v2 sofar >>= merge as []
merge [] ((k2, v2) : bs) sofar = gen aUi k2 aMemoT >>= \v1 -> fill k2 v1 v2 sofar >>= merge [] bs
merge ass@((k1, v1) : as) bss@((k2, v2) : bs) sofar
| k1 < k2 = gen bUi k1 bMemoT >>= \nv2 -> fill k1 v1 nv2 sofar >>= merge as bss
| k1 > k2 = gen aUi k2 aMemoT >>= \nv1 -> fill k2 nv1 v2 sofar >>= merge ass bs
| True = fill k1 v1 v2 sofar >>= merge as bs
mergedMap <- merge aMemoT bMemoT IMap.empty
memoMerged <- R.newIORef mergedMap
let mkUninitialized i = svIte t (aUi i) (bUi i)
let j = FArrayIndex $ IMap.size fArrMap
upd = IMap.insert (unFArrayIndex j) (mkUninitialized, memoMerged)
j `seq` modifyState st rFArrayMap upd (return ())
return j
newSFunArr :: State -> (Kind, Kind) -> (Int -> String) -> Maybe SVal -> IO SFunArr
newSFunArr st (ak, bk) mkNm mbDef = do
fArrMap <- R.readIORef (rFArrayMap st)
memoTable <- R.newIORef IMap.empty
let j = FArrayIndex $ IMap.size fArrMap
nm = mkNm (unFArrayIndex j)
mkUninitialized i = case mbDef of
Just def -> def
_ -> svUninterpreted bk (nm ++ "_uninitializedRead") Nothing [i]
upd = IMap.insert (unFArrayIndex j) (mkUninitialized, memoTable)
registerLabel "SFunArray declaration" st nm
j `seq` modifyState st rFArrayMap upd (return ())
return $ SFunArr (ak, bk) $ cache $ const $ return j
noUnint :: (Maybe Int, String) -> a
noUnint x = error $ "Unexpected operation called on uninterpreted/enumerated value: " ++ show x
noUnint2 :: (Maybe Int, String) -> (Maybe Int, String) -> a
noUnint2 x y = error $ "Unexpected binary operation called on uninterpreted/enumerated values: " ++ show (x, y)
noCharLift :: Char -> a
noCharLift x = error $ "Unexpected operation called on char: " ++ show x
noStringLift :: String -> a
noStringLift x = error $ "Unexpected operation called on string: " ++ show x
noCharLift2 :: Char -> Char -> a
noCharLift2 x y = error $ "Unexpected binary operation called on chars: " ++ show (x, y)
noStringLift2 :: String -> String -> a
noStringLift2 x y = error $ "Unexpected binary operation called on strings: " ++ show (x, y)
liftSym1 :: (State -> Kind -> SW -> IO SW) -> (AlgReal -> AlgReal) -> (Integer -> Integer) -> (Float -> Float) -> (Double -> Double) -> SVal -> SVal
liftSym1 _ opCR opCI opCF opCD (SVal k (Left a)) = SVal k . Left $! mapCW opCR opCI opCF opCD noCharLift noStringLift noUnint a
liftSym1 opS _ _ _ _ a@(SVal k _) = SVal k $ Right $ cache c
where c st = do swa <- svToSW st a
opS st k swa
liftSW2 :: (State -> Kind -> SW -> SW -> IO SW) -> Kind -> SVal -> SVal -> Cached SW
liftSW2 opS k a b = cache c
where c st = do sw1 <- svToSW st a
sw2 <- svToSW st b
opS st k sw1 sw2
liftSym2 :: (State -> Kind -> SW -> SW -> IO SW) -> (CW -> CW -> Bool) -> (AlgReal -> AlgReal -> AlgReal) -> (Integer -> Integer -> Integer) -> (Float -> Float -> Float) -> (Double -> Double -> Double) -> SVal -> SVal -> SVal
liftSym2 _ okCW opCR opCI opCF opCD (SVal k (Left a)) (SVal _ (Left b)) | okCW a b = SVal k . Left $! mapCW2 opCR opCI opCF opCD noCharLift2 noStringLift2 noUnint2 a b
liftSym2 opS _ _ _ _ _ a@(SVal k _) b = SVal k $ Right $ liftSW2 opS k a b
liftSym2B :: (State -> Kind -> SW -> SW -> IO SW) -> (CW -> CW -> Bool) -> (AlgReal -> AlgReal -> Bool) -> (Integer -> Integer -> Bool) -> (Float -> Float -> Bool) -> (Double -> Double -> Bool) -> (Char -> Char -> Bool) -> (String -> String -> Bool) -> ([CWVal] -> [CWVal] -> Bool) -> ((Maybe Int, String) -> (Maybe Int, String) -> Bool) -> SVal -> SVal -> SVal
liftSym2B _ okCW opCR opCI opCF opCD opCC opCS opCSeq opUI (SVal _ (Left a)) (SVal _ (Left b)) | okCW a b = svBool (liftCW2 opCR opCI opCF opCD opCC opCS opCSeq opUI a b)
liftSym2B opS _ _ _ _ _ _ _ _ _ a b = SVal KBool $ Right $ liftSW2 opS KBool a b
mkSymOpSC :: (SW -> SW -> Maybe SW) -> Op -> State -> Kind -> SW -> SW -> IO SW
mkSymOpSC shortCut op st k a b = maybe (newExpr st k (SBVApp op [a, b])) return (shortCut a b)
mkSymOp :: Op -> State -> Kind -> SW -> SW -> IO SW
mkSymOp = mkSymOpSC (const (const Nothing))
mkSymOp1SC :: (SW -> Maybe SW) -> Op -> State -> Kind -> SW -> IO SW
mkSymOp1SC shortCut op st k a = maybe (newExpr st k (SBVApp op [a])) return (shortCut a)
mkSymOp1 :: Op -> State -> Kind -> SW -> IO SW
mkSymOp1 = mkSymOp1SC (const Nothing)
eqOpt :: SW -> SW -> SW -> Maybe SW
eqOpt w x y = case swKind x of
KFloat -> Nothing
KDouble -> Nothing
_ -> if x == y then Just w else Nothing
uiLift :: String -> (Int -> Int -> Bool) -> (Maybe Int, String) -> (Maybe Int, String) -> Bool
uiLift _ cmp (Just i, _) (Just j, _) = i `cmp` j
uiLift w _ a b = error $ "Data.SBV.Core.Operations: Impossible happened while trying to lift " ++ w ++ " over " ++ show (a, b)
isConcreteZero :: SVal -> Bool
isConcreteZero (SVal _ (Left (CW _ (CWInteger n)))) = n == 0
isConcreteZero (SVal KReal (Left (CW KReal (CWAlgReal v)))) = isExactRational v && v == 0
isConcreteZero _ = False
isConcreteOne :: SVal -> Bool
isConcreteOne (SVal _ (Left (CW _ (CWInteger 1)))) = True
isConcreteOne (SVal KReal (Left (CW KReal (CWAlgReal v)))) = isExactRational v && v == 1
isConcreteOne _ = False
isConcreteOnes :: SVal -> Bool
isConcreteOnes (SVal _ (Left (CW (KBounded b w) (CWInteger n)))) = n == if b then -1 else bit w - 1
isConcreteOnes (SVal _ (Left (CW KUnbounded (CWInteger n)))) = n == -1
isConcreteOnes (SVal _ (Left (CW KBool (CWInteger n)))) = n == 1
isConcreteOnes _ = False
isConcreteMax :: SVal -> Bool
isConcreteMax (SVal _ (Left (CW (KBounded False w) (CWInteger n)))) = n == bit w - 1
isConcreteMax (SVal _ (Left (CW (KBounded True w) (CWInteger n)))) = n == bit (w - 1) - 1
isConcreteMax (SVal _ (Left (CW KBool (CWInteger n)))) = n == 1
isConcreteMax _ = False
isConcreteMin :: SVal -> Bool
isConcreteMin (SVal _ (Left (CW (KBounded False _) (CWInteger n)))) = n == 0
isConcreteMin (SVal _ (Left (CW (KBounded True w) (CWInteger n)))) = n == - bit (w - 1)
isConcreteMin (SVal _ (Left (CW KBool (CWInteger n)))) = n == 0
isConcreteMin _ = False
rationalCheck :: CW -> CW -> Bool
rationalCheck a b = case (cwVal a, cwVal b) of
(CWAlgReal x, CWAlgReal y) -> isExactRational x && isExactRational y
_ -> True
nonzeroCheck :: CW -> CW -> Bool
nonzeroCheck _ b = cwVal b /= CWInteger 0
rationalSBVCheck :: SVal -> SVal -> Bool
rationalSBVCheck (SVal KReal (Left a)) (SVal KReal (Left b)) = rationalCheck a b
rationalSBVCheck _ _ = True
noReal :: String -> AlgReal -> AlgReal -> AlgReal
noReal o a b = error $ "SBV.AlgReal." ++ o ++ ": Unexpected arguments: " ++ show (a, b)
noFloat :: String -> Float -> Float -> Float
noFloat o a b = error $ "SBV.Float." ++ o ++ ": Unexpected arguments: " ++ show (a, b)
noDouble :: String -> Double -> Double -> Double
noDouble o a b = error $ "SBV.Double." ++ o ++ ": Unexpected arguments: " ++ show (a, b)
noRealUnary :: String -> AlgReal -> AlgReal
noRealUnary o a = error $ "SBV.AlgReal." ++ o ++ ": Unexpected argument: " ++ show a
noFloatUnary :: String -> Float -> Float
noFloatUnary o a = error $ "SBV.Float." ++ o ++ ": Unexpected argument: " ++ show a
noDoubleUnary :: String -> Double -> Double
noDoubleUnary o a = error $ "SBV.Double." ++ o ++ ": Unexpected argument: " ++ show a
{-# ANN svIte ("HLint: ignore Eta reduce" :: String) #-}
{-# ANN svLazyIte ("HLint: ignore Eta reduce" :: String) #-}
{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}