packages feed

what4 1.4 → 1.5

raw patch · 19 files changed

+143/−28 lines, 19 filesdep −th-abstractiondep ~tasty-sugar

Dependencies removed: th-abstraction

Dependency ranges changed: tasty-sugar

Files

CHANGES.md view
@@ -1,3 +1,14 @@+# 1.5 (July 2023)++* Allow building with GHC 9.6.++* The `MonadTrans (PartialT sym)` instance now has a `IsExpr (SymExpr sym)`+  constraint in its instance context. (This is a requirement imposed by+  `MonadTrans` gaining a quantified `Monad` superclass in `mtl-2.3`.)++* Make `what4` simplify expressions of the form+  `(bvult (bvadd a c) (bvadd b c))` to `(bvult a b)` when it is sound to do so.+ # 1.4 (January 2023)  * Allow building with GHC 9.4.
doc/arithdomain.cry view
@@ -306,6 +306,20 @@ sle : {n} (fin n, n >= 1) => Dom n -> Dom n -> Bit sle a b = (sbounds a).1 <=$ (sbounds b).0 +ult_sum_common_equiv : {n} (fin n) => Dom n -> Dom n -> Dom n -> Bit+ult_sum_common_equiv a b c =+  if al == ah /\ bl == bh /\ al == bl+    then True+    else if ~(carry cl c.sz)+      then check_same_wrap_interval cl ch+      else check_same_wrap_interval cl mask`{n} /\ check_same_wrap_interval 0 ch+  where+    (cl, ch) = (c.lo, c.lo + c.sz)+    (al, ah) = ubounds a+    (bl, bh) = ubounds b+    check_same_wrap_interval lo hi =+      ~(carry ah hi) /\ ~(carry bh hi) \/ carry al lo /\ carry bl lo+ // A bitmask indicating which bits cannot be determined // given the interval information in the given domain unknowns : {n} (fin n, n >= 1) => Dom n -> [n]@@ -460,6 +474,13 @@ correct_ule a b x y =   ule a b ==> mem a x ==> mem b y ==> x <= y +correct_ult_sum_common_equiv :+  {n} (fin n, n >= 1) => Dom n -> Dom n -> Dom n -> [n] -> [n] -> [n] -> Bit+correct_ult_sum_common_equiv a b c x y z =+  ult_sum_common_equiv a b c ==>+  mem a x ==> mem b y ==> mem c z ==>+  (x + z < y + z <==> x < y)+ correct_bnot : {n} (fin n) => Dom n -> [n] -> Bit correct_bnot a x =   mem a x <==> mem (bnot a) (~ x)@@ -505,6 +526,7 @@ property o2 = correct_sle`{16} property o3 = correct_ult`{16} property o4 = correct_ule`{16}+property o5 = correct_ult_sum_common_equiv`{4}  //////////////////////////////////////////////////////////// // Operations preserve singletons
src/What4/Config.hs view
@@ -175,10 +175,10 @@ import qualified Control.Concurrent.ReadWriteVar as RWV import           Control.Lens ((&)) import qualified Control.Lens.Combinators as LC+import           Control.Monad (foldM, when) import           Control.Monad.Catch import           Control.Monad.IO.Class-import           Control.Monad.Identity-import           Control.Monad.Writer.Strict hiding ((<>))+import           Control.Monad.Writer.Strict (MonadWriter(..), WriterT, execWriterT) import           Data.Foldable (toList) import           Data.Kind import           Data.List.NonEmpty (NonEmpty(..))
src/What4/Expr/Builder.hs view
@@ -2400,6 +2400,14 @@     | x == y =       return $! falsePred sym +    | sr <- SR.SemiRingBVRepr SR.BVArithRepr (bvWidth x)+    , (z, x', y') <- WSum.extractCommon (asWeightedSum sr x) (asWeightedSum sr y)+    , not (WSum.isZero sr z)+    , BVD.isUltSumCommonEquiv (WSum.sumAbsValue x') (WSum.sumAbsValue y') (WSum.sumAbsValue z) = do+      xr <- semiRingSum sym x'+      yr <- semiRingSum sym y'+      bvUlt sym xr yr+     | otherwise = do         ut <- CFG.getOpt (sbUnaryThreshold sym)         let ?unaryThreshold = fromInteger ut
src/What4/Expr/Simplify.hs view
@@ -20,8 +20,9 @@   ) where  import           Control.Lens ((^.))+import           Control.Monad (void, when) import           Control.Monad.ST-import           Control.Monad.State+import           Control.Monad.State (MonadState(..), State, execState) import           Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import           Data.Maybe@@ -144,7 +145,7 @@ count_subterms' :: Expr t tp -> Counter () count_subterms' e0 =   case e0 of-    BoolExpr{} -> pure () +    BoolExpr{} -> pure ()     SemiRingLiteral{} -> pure ()     StringExpr{} -> pure ()     FloatExpr{} -> pure ()
src/What4/Expr/VarIdentification.hs view
@@ -42,9 +42,10 @@ #endif  import           Control.Lens-import           Control.Monad.Reader+import           Control.Monad (when)+import           Control.Monad.Reader (MonadReader(..), ReaderT(..)) import           Control.Monad.ST-import           Control.Monad.State+import           Control.Monad.State (StateT, execStateT) import           Data.Bits import qualified Data.HashTable.ST.Basic as H import           Data.List.NonEmpty (NonEmpty(..))
src/What4/Expr/WeightedSum.hs view
@@ -70,7 +70,7 @@   ) where  import           Control.Lens-import           Control.Monad.State+import           Control.Monad (unless) import qualified Data.BitVector.Sized as BV import           Data.Hashable import           Data.Kind
src/What4/Partial.hs view
@@ -266,7 +266,7 @@ instance (IsExpr (SymExpr sym), MonadFail m) => MonadFail (PartialT sym m) where   fail msg = PartialT $ \_ _ -> fail msg -instance MonadTrans (PartialT sym) where+instance IsExpr (SymExpr sym) => MonadTrans (PartialT sym) where   lift m = PartialT $ \_ p -> PE p <$> m  instance (IsExpr (SymExpr sym), MonadIO m) => MonadIO (PartialT sym m) where
src/What4/Protocol/SMTLib2.hs view
@@ -101,8 +101,10 @@  import           Control.Applicative import           Control.Exception-import           Control.Monad.Except-import           Control.Monad.Reader+import           Control.Monad (forM, forM_, replicateM_, unless, when)+import           Control.Monad.IO.Class (MonadIO(..))+import           Control.Monad.Except (MonadError(..), ExceptT, runExceptT)+import           Control.Monad.Reader (MonadReader(..), ReaderT(..), asks) import qualified Data.Bimap as Bimap import qualified Data.BitVector.Sized as BV import           Data.Char (digitToInt, isAscii)@@ -707,7 +709,7 @@   getUnsatCoreCommand _ = SMT2.getUnsatCore   getAbductCommand _ nm e = SMT2.getAbduct nm e   getAbductNextCommand _ = SMT2.getAbductNext-  +   setOptCommand _ = SMT2.setOption    declareCommand _proxy v argTypes retType =@@ -1283,7 +1285,7 @@              -> Text              -> Term              -> IO [String]-runGetAbducts s n nm p = +runGetAbducts s n nm p =   if (n > 0) then do     writeGetAbduct (sessionWriter s) nm p     let valRsp = \x -> case x of
src/What4/Protocol/SMTLib2/Parse.hs view
@@ -39,7 +39,8 @@ import qualified Control.Monad.Fail #endif -import           Control.Monad.Reader+import           Control.Monad (when)+import           Control.Monad.Reader (ReaderT(..)) import qualified Data.ByteString as BS import qualified Data.ByteString.UTF8 as UTF8 import           Data.Char
src/What4/Protocol/SMTWriter.hs view
@@ -111,11 +111,13 @@  import           Control.Exception import           Control.Lens hiding ((.>), Strict)+import           Control.Monad (forM_, unless, when) import           Control.Monad.IO.Class-import           Control.Monad.Reader+import           Control.Monad.Reader (ReaderT(..), asks) import           Control.Monad.ST-import           Control.Monad.State.Strict-import           Control.Monad.Trans.Maybe+import           Control.Monad.State.Strict (State, runState)+import           Control.Monad.Trans (MonadTrans(..))+import           Control.Monad.Trans.Maybe (MaybeT(..)) import           Data.Bimap (Bimap) import qualified Data.Bimap as Bimap import qualified Data.BitVector.Sized as BV
src/What4/Protocol/VerilogWriter/AST.hs view
@@ -19,7 +19,9 @@ import qualified Data.Set as Set import           Data.String import           Data.Word-import           Control.Monad.Except+import           Control.Monad (forM_)+import           Control.Monad.Except (ExceptT, MonadError(..))+import           Control.Monad.IO.Class (MonadIO(..)) import           Control.Monad.State (MonadState(), StateT(..), get, put, modify, gets)  import qualified What4.BaseTypes as WT
src/What4/Protocol/VerilogWriter/Backend.hs view
@@ -16,8 +16,9 @@   where  +import           Control.Monad (foldM) import           Control.Monad.State (get)-import           Control.Monad.Except+import           Control.Monad.Except (MonadError(..)) import qualified Data.BitVector.Sized as BV import           Data.List.NonEmpty ( NonEmpty(..) ) 
src/What4/Serialize/Parser.hs view
@@ -34,6 +34,7 @@   , printSExpr   ) where +import           Control.Monad ( when ) import qualified Control.Monad.Except as E import           Control.Monad.IO.Class ( liftIO ) import qualified Control.Monad.Reader as R@@ -886,7 +887,7 @@ readLetFnExpr bindings _body = E.throwError $   "invalid s-expression for let-bindings: " ++ (show bindings) -  + -- | Parse an arbitrary expression. readExpr ::   forall sym t st fs . (sym ~ W4.ExprBuilder t st fs)@@ -1030,7 +1031,7 @@                  Right solverSym -> return solverSym   argNames <- readFnArgs argVarsRaw   (argTys, _retTy) <- readFnType rawFnType-  E.when (not (length argTys == length argNames)) $+  when (not (length argTys == length argNames)) $     E.throwError $ "Function type expected "     ++ (show $ length argTys)     ++ " args but found "
src/What4/Serialize/Printer.hs view
@@ -89,7 +89,7 @@  instance Ord (SomeExprSymFn t) where   compare (SomeExprSymFn fn1) (SomeExprSymFn fn2) =-    compare (Nonce.indexValue $ W4.symFnId fn1) (Nonce.indexValue $ W4.symFnId fn2) +    compare (Nonce.indexValue $ W4.symFnId fn1) (Nonce.indexValue $ W4.symFnId fn2)   instance Show (SomeExprSymFn t) where@@ -376,7 +376,7 @@ freshFnName fn = do   idCount <- MS.gets envIdCounter   MS.modify' $ (\e -> e {envIdCounter = idCount + 1})-  let prefix = case W4.symFnInfo fn of +  let prefix = case W4.symFnInfo fn of                  W4.UninterpFnInfo{} -> "ufn"                  W4.DefinedFnInfo{} -> "dfn"                  W4.MatlabSolverFnInfo{} -> "mfn"@@ -412,7 +412,7 @@           sexp <- go initialExpr           case sexp of             S.A _ -> return sexp -- Don't memoize atomic s-expressions - that's just silly.-            _ -> do +            _ -> do               letVarName <- addLetBinding key sexp (W4.exprType initialExpr)               return $ ident letVarName   where go :: W4.Expr t tp -> Memo t SExpr@@ -448,7 +448,7 @@   bvs <- MS.gets envBoundVars   -- If this variable is not bound (in the standard syntactic sense)   -- and free variables are not explicitly permitted, raise an error.-  MS.when ((not $ Set.member (Some x) bvs) && (not fvsAllowed)) $+  M.when ((not $ Set.member (Some x) bvs) && (not fvsAllowed)) $     error $     "encountered the free What4 ExprBoundVar `"     ++ (T.unpack (W4.solverSymbolAsText (W4.bvarName x)))@@ -683,7 +683,7 @@                        ]          -- -- -- -- Helper functions! -- -- -- ---        +         goE :: forall tp' . W4.Expr t tp' -> Memo t SExpr         goE = convertExpr 
src/What4/Utils/BVDomain.hs view
@@ -51,6 +51,7 @@   , domainsOverlap   , ubounds   , sbounds+  , isUltSumCommonEquiv   , A.arithDomainData   , B.bitbounds     -- * Operations@@ -424,6 +425,11 @@  sbounds :: (1 <= w) => NatRepr w -> BVDomain w -> (Integer, Integer) sbounds w a = A.sbounds w (asArithDomain a)++-- | Check if (bvult (bvadd a c) (bvadd b c)) is equivalent to (bvult a b)+isUltSumCommonEquiv :: BVDomain w -> BVDomain w -> BVDomain w -> Bool+isUltSumCommonEquiv a b c =+  A.isUltSumCommonEquiv (asArithDomain a) (asArithDomain b) (asArithDomain c)  -------------------------------------------------------------------------------- -- Operations
src/What4/Utils/BVDomain/Arith.hs view
@@ -11,6 +11,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-}@@ -30,6 +31,7 @@   , eq   , slt   , ult+  , isUltSumCommonEquiv   , domainsOverlap   , arithDomainData   , bitbounds@@ -94,6 +96,7 @@   , correct_eq   , correct_ult   , correct_slt+  , correct_isUltSumCommonEquiv   , correct_unknowns   , correct_bitbounds   ) where@@ -276,6 +279,46 @@     (a_min, a_max) = ubounds a     (b_min, b_max) = ubounds b +-- | Check if @(bvult (bvadd a c) (bvadd b c))@ is equivalent to @(bvult a b)@.+-- +-- This is true if and only if for all natural values @i_a@, @i_b@, @i_c@ in+-- @a@, @b@, @c@, either both @i_a + i_c@ and @i_b + i_c@ are less than @2^w@,+-- or both are not. We prove this by contradiction. If @i_a = i_b@, then the+-- property is trivial. Assume that @i_a < i_b@. Then @i_a + i_c < i_b + i_c@.+-- If exactly one of the additions is less than @2^w@, it must be the case that+-- @i_a + i_c < 2^w@ and @0 <= i_b + i_c - 2^w < 2^w@. Since @i_b < 2^w@, it+-- follows that @i_b + i_c < 2^w + i_c@, that @i_b + i_c - 2^w < i_c@, and that+-- @i_b + i_c - 2^w < i_a + i_c@. Thus, for these values of @i_a@, @i_b@, @i_c@,+-- @(bvult a b)@ is true, but @(bvult (bvadd a c) (bvadd b c))@ is false, which+-- is a contradiction.+--+-- We check this property by case analysis on whether @c@ is a single+-- non-wrapping interval, or it wraps around and is a union of two non-wrapping+-- intervals. For a non-wrapping (sub)interval @c'@ of @c@, there are four+-- possible cases:+-- 1. @a@ and @b@ contain a single value.+-- 2. @(bvadd a c')@ and @(bvadd b c')@ do not wrap around for any values in+--    @a@, @b@, @c'@.+-- 3. @(bvadd a c')@ and @(bvadd b c')@ wrap around for all values in @a@, @b@,+--    @c'@.+--+-- This is used to simplify @bvult@.+isUltSumCommonEquiv :: Domain w -> Domain w -> Domain w -> Bool+isUltSumCommonEquiv a b c = if al == ah && bl == bh && al == bl+  then True+  else if cl + cw == ch+    then checkSameWrapInterval cl ch+    else checkSameWrapInterval cl mask && checkSameWrapInterval 0 ch+  where+    (mask, cl, cw) = case c of+      BVDInterval mask' cl' cw' -> (mask', cl', cw')+      BVDAny mask' -> (mask', 0, mask')+    ch = (cl + cw) .&. mask+    (al, ah) = ubounds a+    (bl, bh) = ubounds b+    checkSameWrapInterval lo hi =+      ah + hi <= mask && bh + hi <= mask || mask < al + lo && mask < bl + lo+ -------------------------------------------------------------------------------- -- Operations @@ -814,6 +857,18 @@       Just True  -> toSigned n x < toSigned n y       Just False -> toSigned n x >= toSigned n y       Nothing    -> True++correct_isUltSumCommonEquiv ::+  (1 <= n) =>+  NatRepr n ->+  (Domain n, Integer) ->+  (Domain n, Integer) ->+  (Domain n, Integer) ->+  Property+correct_isUltSumCommonEquiv n (a, x) (b, y) (c, z) =+  member a x ==> member b y ==> member c z ==>+    isUltSumCommonEquiv a b c ==>+      ((toUnsigned n (x + z) < toUnsigned n (y + z)) == (toUnsigned n x < toUnsigned n y))  correct_unknowns :: (1 <= n) => Domain n -> Integer -> Integer -> Property correct_unknowns a x y = member a x ==> member a y ==> ((x .|. u) == (y .|. u)) && (u .|. mask == mask)
test/BVDomTests.hs view
@@ -182,6 +182,9 @@   , genTest "correct_slt" $       do SW n <- genWidth          A.correct_slt n <$> A.genPair n <*> A.genPair n+  , genTest "correct_isUltSumCommonEquiv" $+      do SW n <- genWidth+         A.correct_isUltSumCommonEquiv n <$> A.genPair n <*> A.genPair n <*> A.genPair n   , genTest "correct_unknowns" $       do SW n <- genWidth          a <- A.genDomain n
what4.cabal view
@@ -1,6 +1,6 @@ Cabal-version: 2.4 Name:          what4-Version:       1.4+Version:       1.5 Author:        Galois Inc. Maintainer:    rscott@galois.com, kquick@galois.com Copyright:     (c) Galois, Inc 2014-2023@@ -127,7 +127,6 @@     temporary >= 1.2,     template-haskell,     text >= 1.2.4.0 && < 2.1,-    th-abstraction >=0.1 && <0.5,     th-lift >= 0.8.2 && < 0.9,     th-lift-instances >= 0.1 && < 0.2,     time >= 1.8 && < 1.13,@@ -422,7 +421,7 @@                , exceptions                , io-streams                , lumberjack-               , tasty-sugar >= 2.0 && < 2.1+               , tasty-sugar >= 2.0 && < 2.3                , text  test-suite what4-serialize-tests