{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module What4.Utils.ResolveBounds.BV
( resolveSymBV
, SearchStrategy(..)
, ResolvedSymBV(..)
) where
import Data.BitVector.Sized ( BV )
import qualified Data.BitVector.Sized as BV
import qualified Data.Parameterized.NatRepr as PN
import qualified Prettyprinter as PP
import qualified What4.Expr.Builder as WEB
import qualified What4.Expr.GroundEval as WEG
import qualified What4.Interface as WI
import qualified What4.Protocol.Online as WPO
import qualified What4.Protocol.SMTWriter as WPS
import qualified What4.SatResult as WSat
import qualified What4.Utils.BVDomain.Arith as WUBA
data ResolvedSymBV w
= BVConcrete (BV w)
| BVSymbolic (WUBA.Domain w)
instance Show (ResolvedSymBV w) where
showsPrec :: Int -> ResolvedSymBV w -> ShowS
showsPrec Int
_p ResolvedSymBV w
res =
case ResolvedSymBV w
res of
BVConcrete BV w
bv ->
String -> ShowS
showString String
"BVConcrete " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> BV w -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 BV w
bv
BVSymbolic Domain w
d ->
let (Integer
lb, Integer
ub) = Domain w -> (Integer, Integer)
forall (w :: Nat). Domain w -> (Integer, Integer)
WUBA.ubounds Domain w
d in
String -> ShowS
showString String
"BVSymbolic ["
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Integer -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 Integer
lb
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ShowS
showString String
", "
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Integer -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
11 Integer
ub
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ShowS
showString String
"]"
data SearchStrategy
= ExponentialSearch
| BinarySearch
instance PP.Pretty SearchStrategy where
pretty :: forall ann. SearchStrategy -> Doc ann
pretty SearchStrategy
ExponentialSearch = String -> Doc ann
forall ann. String -> Doc ann
forall a ann. Pretty a => a -> Doc ann
PP.pretty String
"exponential search"
pretty SearchStrategy
BinarySearch = String -> Doc ann
forall ann. String -> Doc ann
forall a ann. Pretty a => a -> Doc ann
PP.pretty String
"binary search"
resolveSymBV ::
forall w sym solver scope st fs
. ( 1 PN.<= w
, sym ~ WEB.ExprBuilder scope st fs
, WPO.OnlineSolver solver
)
=> sym
-> SearchStrategy
-> PN.NatRepr w
-> WPO.SolverProcess scope solver
-> WI.SymBV sym w
-> IO (ResolvedSymBV w)
resolveSymBV :: forall (w :: Nat) sym solver scope (st :: Type -> Type) fs.
(1 <= w, sym ~ ExprBuilder scope st fs, OnlineSolver solver) =>
sym
-> SearchStrategy
-> NatRepr w
-> SolverProcess scope solver
-> SymBV sym w
-> IO (ResolvedSymBV w)
resolveSymBV sym
sym SearchStrategy
searchStrat NatRepr w
w SolverProcess scope solver
proc SymBV sym w
symBV =
case Expr scope (BaseBVType w) -> Maybe (BV w)
forall (w :: Nat). Expr scope (BaseBVType w) -> Maybe (BV w)
forall (e :: BaseType -> Type) (w :: Nat).
IsExpr e =>
e (BaseBVType w) -> Maybe (BV w)
WI.asBV SymBV sym w
Expr scope (BaseBVType w)
symBV of
Just BV w
bv -> ResolvedSymBV w -> IO (ResolvedSymBV w)
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (ResolvedSymBV w -> IO (ResolvedSymBV w))
-> ResolvedSymBV w -> IO (ResolvedSymBV w)
forall a b. (a -> b) -> a -> b
$ BV w -> ResolvedSymBV w
forall (w :: Nat). BV w -> ResolvedSymBV w
BVConcrete BV w
bv
Maybe (BV w)
Nothing -> do
BV w
modelForBV <- SolverProcess scope solver -> IO (BV w) -> IO (BV w)
forall (m :: Type -> Type) solver scope a.
(MonadIO m, MonadMask m, SMTReadWriter solver) =>
SolverProcess scope solver -> m a -> m a
WPO.inNewFrame SolverProcess scope solver
proc (IO (BV w) -> IO (BV w)) -> IO (BV w) -> IO (BV w)
forall a b. (a -> b) -> a -> b
$ do
SatResult (GroundEvalFn scope) ()
msat <- SolverProcess scope solver
-> String -> IO (SatResult (GroundEvalFn scope) ())
forall solver scope.
SMTReadWriter solver =>
SolverProcess scope solver
-> String -> IO (SatResult (GroundEvalFn scope) ())
WPO.checkAndGetModel SolverProcess scope solver
proc String
"resolveSymBV (check with initial assumptions)"
GroundEvalFn scope
model <- case SatResult (GroundEvalFn scope) ()
msat of
SatResult (GroundEvalFn scope) ()
WSat.Unknown -> IO (GroundEvalFn scope)
forall a. IO a
failUnknown
WSat.Unsat{} -> String -> IO (GroundEvalFn scope)
forall a. String -> IO a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail String
"resolveSymBV: Initial assumptions are unsatisfiable"
WSat.Sat GroundEvalFn scope
model -> GroundEvalFn scope -> IO (GroundEvalFn scope)
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure GroundEvalFn scope
model
GroundEvalFn scope
-> forall (tp :: BaseType). Expr scope tp -> IO (GroundValue tp)
forall t.
GroundEvalFn t
-> forall (tp :: BaseType). Expr t tp -> IO (GroundValue tp)
WEG.groundEval GroundEvalFn scope
model SymBV sym w
Expr scope (BaseBVType w)
symBV
Bool
isSymbolic <- SolverProcess scope solver -> IO Bool -> IO Bool
forall (m :: Type -> Type) solver scope a.
(MonadIO m, MonadMask m, SMTReadWriter solver) =>
SolverProcess scope solver -> m a -> m a
WPO.inNewFrame SolverProcess scope solver
proc (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ do
BoolExpr scope
block <- sym -> Pred sym -> IO (Pred sym)
forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
WI.notPred sym
sym (BoolExpr scope -> IO (BoolExpr scope))
-> IO (BoolExpr scope) -> IO (BoolExpr scope)
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
forall (w :: Nat).
(1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
forall sym (w :: Nat).
(IsExprBuilder sym, 1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
WI.bvEq sym
sym SymBV sym w
symBV (Expr scope (BaseBVType w) -> IO (BoolExpr scope))
-> IO (Expr scope (BaseBVType w)) -> IO (BoolExpr scope)
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< sym -> NatRepr w -> BV w -> IO (SymBV sym w)
forall (w :: Nat).
(1 <= w) =>
sym -> NatRepr w -> BV w -> IO (SymBV sym w)
forall sym (w :: Nat).
(IsExprBuilder sym, 1 <= w) =>
sym -> NatRepr w -> BV w -> IO (SymBV sym w)
WI.bvLit sym
sym NatRepr w
w BV w
modelForBV
WriterConn scope solver -> BoolExpr scope -> IO ()
forall h t. SMTWriter h => WriterConn t h -> BoolExpr t -> IO ()
WPS.assume WriterConn scope solver
conn BoolExpr scope
block
SatResult () ()
msat <- SolverProcess scope solver -> String -> IO (SatResult () ())
forall solver scope.
SMTReadWriter solver =>
SolverProcess scope solver -> String -> IO (SatResult () ())
WPO.check SolverProcess scope solver
proc String
"resolveSymBV (check under assumption that model cannot happen)"
case SatResult () ()
msat of
SatResult () ()
WSat.Unknown -> IO Bool
forall a. IO a
failUnknown
WSat.Sat{} -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Bool
True
WSat.Unsat{} -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Bool
False
if Bool
isSymbolic
then
case SearchStrategy
searchStrat of
SearchStrategy
ExponentialSearch -> do
BV w
lowerBound <- BV w -> IO (BV w)
computeLowerBoundExponential BV w
modelForBV
BV w
upperBound <- BV w -> IO (BV w)
computeUpperBoundExponential BV w
modelForBV
ResolvedSymBV w -> IO (ResolvedSymBV w)
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (ResolvedSymBV w -> IO (ResolvedSymBV w))
-> ResolvedSymBV w -> IO (ResolvedSymBV w)
forall a b. (a -> b) -> a -> b
$ Domain w -> ResolvedSymBV w
forall (w :: Nat). Domain w -> ResolvedSymBV w
BVSymbolic (Domain w -> ResolvedSymBV w) -> Domain w -> ResolvedSymBV w
forall a b. (a -> b) -> a -> b
$ NatRepr w -> Integer -> Integer -> Domain w
forall (w :: Nat). NatRepr w -> Integer -> Integer -> Domain w
WUBA.range NatRepr w
w
(BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
lowerBound) (BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
upperBound)
SearchStrategy
BinarySearch -> do
BV w
lowerBound <- BV w -> BV w -> IO (BV w)
computeLowerBoundBinary BV w
bvZero BV w
bvMaxUnsigned
BV w
upperBound <- BV w -> BV w -> IO (BV w)
computeUpperBoundBinary BV w
bvZero BV w
bvMaxUnsigned
ResolvedSymBV w -> IO (ResolvedSymBV w)
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (ResolvedSymBV w -> IO (ResolvedSymBV w))
-> ResolvedSymBV w -> IO (ResolvedSymBV w)
forall a b. (a -> b) -> a -> b
$ Domain w -> ResolvedSymBV w
forall (w :: Nat). Domain w -> ResolvedSymBV w
BVSymbolic (Domain w -> ResolvedSymBV w) -> Domain w -> ResolvedSymBV w
forall a b. (a -> b) -> a -> b
$ NatRepr w -> Integer -> Integer -> Domain w
forall (w :: Nat). NatRepr w -> Integer -> Integer -> Domain w
WUBA.range NatRepr w
w
(BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
lowerBound) (BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
upperBound)
else ResolvedSymBV w -> IO (ResolvedSymBV w)
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (ResolvedSymBV w -> IO (ResolvedSymBV w))
-> ResolvedSymBV w -> IO (ResolvedSymBV w)
forall a b. (a -> b) -> a -> b
$ BV w -> ResolvedSymBV w
forall (w :: Nat). BV w -> ResolvedSymBV w
BVConcrete BV w
modelForBV
where
conn :: WPS.WriterConn scope solver
conn :: WriterConn scope solver
conn = SolverProcess scope solver -> WriterConn scope solver
forall scope solver.
SolverProcess scope solver -> WriterConn scope solver
WPO.solverConn SolverProcess scope solver
proc
failUnknown :: forall a. IO a
failUnknown :: forall a. IO a
failUnknown = String -> IO a
forall a. String -> IO a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail String
"resolveSymBV: Resolving value yielded UNKNOWN"
bvZero :: BV w
bvZero :: BV w
bvZero = NatRepr w -> BV w
forall (w :: Nat). NatRepr w -> BV w
BV.zero NatRepr w
w
bvOne :: BV w
bvOne :: BV w
bvOne = NatRepr w -> BV w
forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
BV.one NatRepr w
w
bvTwo :: BV w
bvTwo :: BV w
bvTwo = NatRepr w -> Integer -> BV w
forall (w :: Nat). NatRepr w -> Integer -> BV w
BV.mkBV NatRepr w
w Integer
2
bvMaxUnsigned :: BV w
bvMaxUnsigned :: BV w
bvMaxUnsigned = NatRepr w -> BV w
forall (w :: Nat). NatRepr w -> BV w
BV.maxUnsigned NatRepr w
w
computeLowerBoundExponential :: BV w -> IO (BV w)
computeLowerBoundExponential :: BV w -> IO (BV w)
computeLowerBoundExponential BV w
start = BV w -> BV w -> IO (BV w)
go BV w
start BV w
bvOne
where
go :: BV w -> BV w -> IO (BV w)
go :: BV w -> BV w -> IO (BV w)
go BV w
previouslyTried BV w
diff
|
BV w
start BV w -> BV w -> Bool
forall (w :: Nat). BV w -> BV w -> Bool
`BV.ult` BV w
diff
= BV w -> BV w -> IO (BV w)
computeLowerBoundBinary BV w
bvZero BV w
previouslyTried
|
Bool
otherwise
= do let nextToTry :: BV w
nextToTry = NatRepr w -> BV w -> BV w -> BV w
forall (w :: Nat). NatRepr w -> BV w -> BV w -> BV w
BV.sub NatRepr w
w BV w
start BV w
diff
Bool
exceedsLB <- BV w -> IO Bool
checkExceedsLowerBound BV w
nextToTry
if |
Bool
exceedsLB
-> BV w -> BV w -> IO (BV w)
computeLowerBoundBinary BV w
nextToTry BV w
previouslyTried
|
BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
diff Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
2 Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
bvMaxUnsigned
-> BV w -> BV w -> IO (BV w)
computeLowerBoundBinary BV w
bvZero BV w
nextToTry
|
Bool
otherwise
-> BV w -> BV w -> IO (BV w)
go BV w
nextToTry (BV w -> IO (BV w)) -> BV w -> IO (BV w)
forall a b. (a -> b) -> a -> b
$ NatRepr w -> BV w -> BV w -> BV w
forall (w :: Nat). NatRepr w -> BV w -> BV w -> BV w
BV.mul NatRepr w
w BV w
diff BV w
bvTwo
computeLowerBoundBinary :: BV w -> BV w -> IO (BV w)
computeLowerBoundBinary :: BV w -> BV w -> IO (BV w)
computeLowerBoundBinary BV w
l BV w
r
|
BV w
l BV w -> BV w -> Bool
forall a. Eq a => a -> a -> Bool
== BV w
r
= BV w -> IO (BV w)
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure BV w
l
|
NatRepr w -> BV w -> BV w -> BV w
forall (w :: Nat). NatRepr w -> BV w -> BV w -> BV w
BV.sub NatRepr w
w BV w
r BV w
l BV w -> BV w -> Bool
forall a. Ord a => a -> a -> Bool
< BV w
bvTwo
= do Bool
lExceedsLB <- BV w -> IO Bool
checkExceedsLowerBound BV w
l
BV w -> IO (BV w)
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (BV w -> IO (BV w)) -> BV w -> IO (BV w)
forall a b. (a -> b) -> a -> b
$ if Bool
lExceedsLB then BV w
r else BV w
l
|
Bool
otherwise
= do let nextToTry :: BV w
nextToTry = NatRepr w -> Integer -> BV w
forall (w :: Nat). NatRepr w -> Integer -> BV w
BV.mkBV NatRepr w
w ((BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
l Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
r) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
2)
Bool
exceedsLB <- BV w -> IO Bool
checkExceedsLowerBound BV w
nextToTry
if Bool
exceedsLB
then BV w -> BV w -> IO (BV w)
computeLowerBoundBinary BV w
nextToTry BV w
r
else BV w -> BV w -> IO (BV w)
computeLowerBoundBinary BV w
l BV w
nextToTry
checkExceedsLowerBound :: BV w -> IO Bool
checkExceedsLowerBound :: BV w -> IO Bool
checkExceedsLowerBound BV w
bv = SolverProcess scope solver -> IO Bool -> IO Bool
forall (m :: Type -> Type) solver scope a.
(MonadIO m, MonadMask m, SMTReadWriter solver) =>
SolverProcess scope solver -> m a -> m a
WPO.inNewFrame SolverProcess scope solver
proc (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ do
BoolExpr scope
leLowerBound <- sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
forall (w :: Nat).
(1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
forall sym (w :: Nat).
(IsExprBuilder sym, 1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
WI.bvUle sym
sym SymBV sym w
symBV (Expr scope (BaseBVType w) -> IO (BoolExpr scope))
-> IO (Expr scope (BaseBVType w)) -> IO (BoolExpr scope)
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< sym -> NatRepr w -> BV w -> IO (SymBV sym w)
forall (w :: Nat).
(1 <= w) =>
sym -> NatRepr w -> BV w -> IO (SymBV sym w)
forall sym (w :: Nat).
(IsExprBuilder sym, 1 <= w) =>
sym -> NatRepr w -> BV w -> IO (SymBV sym w)
WI.bvLit sym
sym NatRepr w
w BV w
bv
WriterConn scope solver -> BoolExpr scope -> IO ()
forall h t. SMTWriter h => WriterConn t h -> BoolExpr t -> IO ()
WPS.assume WriterConn scope solver
conn BoolExpr scope
leLowerBound
SatResult () ()
msat <- SolverProcess scope solver -> String -> IO (SatResult () ())
forall solver scope.
SMTReadWriter solver =>
SolverProcess scope solver -> String -> IO (SatResult () ())
WPO.check SolverProcess scope solver
proc String
"resolveSymBV (check if lower bound has been exceeded)"
case SatResult () ()
msat of
SatResult () ()
WSat.Unknown -> IO Bool
forall a. IO a
failUnknown
WSat.Sat{} -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Bool
False
WSat.Unsat{} -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Bool
True
computeUpperBoundExponential :: BV w -> IO (BV w)
computeUpperBoundExponential :: BV w -> IO (BV w)
computeUpperBoundExponential BV w
start = BV w -> BV w -> IO (BV w)
go BV w
start BV w
bvOne
where
go :: BV w -> BV w -> IO (BV w)
go :: BV w -> BV w -> IO (BV w)
go BV w
previouslyTried BV w
diff
|
BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
start Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
diff Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
bvMaxUnsigned
= BV w -> BV w -> IO (BV w)
computeUpperBoundBinary BV w
previouslyTried BV w
bvMaxUnsigned
| Bool
otherwise
= do let nextToTry :: BV w
nextToTry = NatRepr w -> BV w -> BV w -> BV w
forall (w :: Nat). NatRepr w -> BV w -> BV w -> BV w
BV.add NatRepr w
w BV w
start BV w
diff
Bool
exceedsUB <- BV w -> IO Bool
checkExceedsUpperBound BV w
nextToTry
if |
Bool
exceedsUB
-> BV w -> BV w -> IO (BV w)
computeUpperBoundBinary BV w
previouslyTried BV w
nextToTry
|
BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
diff Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
2 Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
bvMaxUnsigned
-> BV w -> BV w -> IO (BV w)
computeUpperBoundBinary BV w
nextToTry BV w
bvMaxUnsigned
|
Bool
otherwise
-> BV w -> BV w -> IO (BV w)
go BV w
nextToTry (BV w -> IO (BV w)) -> BV w -> IO (BV w)
forall a b. (a -> b) -> a -> b
$ NatRepr w -> BV w -> BV w -> BV w
forall (w :: Nat). NatRepr w -> BV w -> BV w -> BV w
BV.mul NatRepr w
w BV w
diff BV w
bvTwo
computeUpperBoundBinary :: BV w -> BV w -> IO (BV w)
computeUpperBoundBinary :: BV w -> BV w -> IO (BV w)
computeUpperBoundBinary BV w
l BV w
r
|
BV w
l BV w -> BV w -> Bool
forall a. Eq a => a -> a -> Bool
== BV w
r
= BV w -> IO (BV w)
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure BV w
l
|
NatRepr w -> BV w -> BV w -> BV w
forall (w :: Nat). NatRepr w -> BV w -> BV w -> BV w
BV.sub NatRepr w
w BV w
r BV w
l BV w -> BV w -> Bool
forall a. Ord a => a -> a -> Bool
< BV w
bvTwo
= do Bool
rExceedsUB <- BV w -> IO Bool
checkExceedsUpperBound BV w
r
BV w -> IO (BV w)
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (BV w -> IO (BV w)) -> BV w -> IO (BV w)
forall a b. (a -> b) -> a -> b
$ if Bool
rExceedsUB then BV w
l else BV w
r
|
Bool
otherwise
= do let nextToTry :: BV w
nextToTry = NatRepr w -> Integer -> BV w
forall (w :: Nat). NatRepr w -> Integer -> BV w
BV.mkBV NatRepr w
w ((BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
l Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ BV w -> Integer
forall (w :: Nat). BV w -> Integer
BV.asUnsigned BV w
r) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
2)
Bool
exceedsUB <- BV w -> IO Bool
checkExceedsUpperBound BV w
nextToTry
if Bool
exceedsUB
then BV w -> BV w -> IO (BV w)
computeUpperBoundBinary BV w
l BV w
nextToTry
else BV w -> BV w -> IO (BV w)
computeUpperBoundBinary BV w
nextToTry BV w
r
checkExceedsUpperBound :: BV w -> IO Bool
checkExceedsUpperBound :: BV w -> IO Bool
checkExceedsUpperBound BV w
bv = SolverProcess scope solver -> IO Bool -> IO Bool
forall (m :: Type -> Type) solver scope a.
(MonadIO m, MonadMask m, SMTReadWriter solver) =>
SolverProcess scope solver -> m a -> m a
WPO.inNewFrame SolverProcess scope solver
proc (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ do
BoolExpr scope
geUpperBound <- sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
forall (w :: Nat).
(1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
forall sym (w :: Nat).
(IsExprBuilder sym, 1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
WI.bvUge sym
sym SymBV sym w
symBV (Expr scope (BaseBVType w) -> IO (BoolExpr scope))
-> IO (Expr scope (BaseBVType w)) -> IO (BoolExpr scope)
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< sym -> NatRepr w -> BV w -> IO (SymBV sym w)
forall (w :: Nat).
(1 <= w) =>
sym -> NatRepr w -> BV w -> IO (SymBV sym w)
forall sym (w :: Nat).
(IsExprBuilder sym, 1 <= w) =>
sym -> NatRepr w -> BV w -> IO (SymBV sym w)
WI.bvLit sym
sym NatRepr w
w BV w
bv
WriterConn scope solver -> BoolExpr scope -> IO ()
forall h t. SMTWriter h => WriterConn t h -> BoolExpr t -> IO ()
WPS.assume WriterConn scope solver
conn BoolExpr scope
geUpperBound
SatResult () ()
msat <- SolverProcess scope solver -> String -> IO (SatResult () ())
forall solver scope.
SMTReadWriter solver =>
SolverProcess scope solver -> String -> IO (SatResult () ())
WPO.check SolverProcess scope solver
proc String
"resolveSymBV (check if upper bound has been exceeded)"
case SatResult () ()
msat of
SatResult () ()
WSat.Unknown -> IO Bool
forall a. IO a
failUnknown
WSat.Sat{} -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Bool
False
WSat.Unsat{} -> Bool -> IO Bool
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Bool
True