Skip to content

Commit 701810c

Browse files
authored
Merge pull request #1313 from GaloisInc/sp/crux-mir-cryptol
Cryptol support for crux-mir-comp
2 parents 759aed0 + 717bb1a commit 701810c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1569
-211
lines changed

crux-mir-comp/crux-mir-comp.cabal

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ library
4141
template-haskell,
4242
saw-core,
4343
saw-core-what4,
44+
cryptol,
4445
cryptol-saw-core,
4546
saw-script
4647

@@ -51,6 +52,7 @@ library
5152
Mir.Compositional.Convert
5253
Mir.Compositional.MethodSpec
5354
Mir.Compositional.Override
55+
Mir.Cryptol
5456

5557
ghc-options: -Wall -Wno-name-shadowing
5658

crux-mir-comp/exe/Main.hs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
{-# LANGUAGE GADTs #-}
2+
{-# LANGUAGE RankNTypes #-}
13
module Main(main) where
24

35
import qualified Mir.Language as Mir
4-
import qualified Mir.Compositional as Mir
6+
import Mir.Compositional (compositionalOverrides)
7+
import Mir.Cryptol (cryptolOverrides)
58

69
main :: IO ()
7-
main = Mir.mainWithExtraOverrides Mir.compositionalOverrides
10+
main = Mir.mainWithExtraOverrides $
11+
compositionalOverrides `Mir.orOverride` cryptolOverrides

crux-mir-comp/src/Mir/Compositional.hs

+3-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import Lang.Crucible.Simulator
2020
import qualified What4.Expr.Builder as W4
2121

2222
import Crux
23-
import Crux.Types
2423

2524
import Mir.DefId
2625
import Mir.Generator (CollectionState)
@@ -31,13 +30,13 @@ import Mir.Compositional.Clobber (clobberGlobalsOverride)
3130

3231

3332
compositionalOverrides ::
34-
forall sym t st fs args ret blocks rtp a r .
35-
(IsSymInterface sym, sym ~ W4.ExprBuilder t st fs) =>
33+
forall sym p t st fs args ret blocks rtp a r .
34+
(IsSymInterface sym, sym ~ W4.ExprBuilder t st fs, HasModel p) =>
3635
Maybe (SomeOnlineSolver sym) ->
3736
CollectionState ->
3837
Text ->
3938
CFG MIR blocks args ret ->
40-
Maybe (OverrideSim (Model sym) sym MIR rtp a r ())
39+
Maybe (OverrideSim (p sym) sym MIR rtp a r ())
4140
compositionalOverrides _symOnline cs name cfg
4241

4342
| (normDefId "crucible::method_spec::raw::builder_new" <> "::_inst") `Text.isPrefixOf` name

crux-mir-comp/src/Mir/Compositional/Builder.hs

+156-13
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ import qualified Data.BitVector.Sized as BV
1919
import Data.Foldable
2020
import Data.Functor.Const
2121
import Data.IORef
22+
import Data.Map (Map)
2223
import qualified Data.Map as Map
2324
import Data.Parameterized.Context (pattern Empty, pattern (:>), Assignment)
2425
import Data.Parameterized.Nonce
26+
import Data.Parameterized.Pair
2527
import Data.Parameterized.Some
2628
import Data.Parameterized.TraversableFC
2729
import Data.Sequence (Seq)
@@ -41,13 +43,14 @@ import Lang.Crucible.Simulator
4143
import Lang.Crucible.Types
4244

4345
import qualified Verifier.SAW.Prelude as SAW
46+
import qualified Verifier.SAW.Recognizer as SAW (asExtCns)
4447
import qualified Verifier.SAW.SharedTerm as SAW
4548
import qualified Verifier.SAW.Simulator.What4.ReturnTrip as SAW
4649
import qualified Verifier.SAW.TypedTerm as SAW
4750

4851
import qualified SAWScript.Crucible.Common.MethodSpec as MS
4952

50-
import Crux.Types (Model)
53+
import Crux.Types (HasModel)
5154

5255
import Mir.DefId
5356
import Mir.Generator (CollectionState, collection)
@@ -72,6 +75,12 @@ data MethodSpecBuilder sym t = MethodSpecBuilder
7275
, _msbNextAlloc :: MS.AllocIndex
7376
, _msbSnapshotFrame :: FrameIdentifier
7477
, _msbVisitCache :: W4.IdxCache t (Const ())
78+
-- | Substitutions to apply to the entire `MethodSpec` after construction.
79+
-- These are generated in place of equality postconditions to improve
80+
-- performance. Variables that appear on the LHS of an entry here will be
81+
-- removed from the `MethodSpec`'s fresh variable lists. Substitutions are
82+
-- applied in the order listed.
83+
, _msbSubsts :: [(SAW.ExtCns SAW.Term, SAW.Term)]
7584
}
7685

7786
data StateExtra sym t = StateExtra
@@ -104,6 +113,7 @@ initMethodSpecBuilder cs sc eval spec snap cache = MethodSpecBuilder
104113
, _msbNextAlloc = MS.AllocIndex 0
105114
, _msbSnapshotFrame = snap
106115
, _msbVisitCache = cache
116+
, _msbSubsts = []
107117
}
108118

109119
initStateExtra :: StateExtra sym t
@@ -172,14 +182,14 @@ instance (IsSymInterface sym, sym ~ W4.ExprBuilder t st fs) =>
172182
-- MethodSpecBuilder implementation. This is the code that actually runs when
173183
-- Rust invokes `msb.add_arg(...)` or similar.
174184

175-
builderNew :: forall sym t st fs rtp.
176-
(IsSymInterface sym, sym ~ W4.ExprBuilder t st fs) =>
185+
builderNew :: forall sym p t st fs rtp.
186+
(IsSymInterface sym, sym ~ W4.ExprBuilder t st fs, HasModel p) =>
177187
CollectionState ->
178188
-- | `DefId` of the `builder_new` monomorphization. Its `Instance` should
179189
-- have one type argument, which is the `TyFnDef` of the function that the
180190
-- spec applies to.
181191
DefId ->
182-
OverrideSim (Model sym) sym MIR rtp
192+
OverrideSim (p sym) sym MIR rtp
183193
EmptyCtx MethodSpecBuilderType (MethodSpecBuilder sym t)
184194
builderNew cs defId = do
185195
sym <- getSymInterface
@@ -214,10 +224,10 @@ builderNew cs defId = do
214224
-- As a side effect, this clobbers any mutable memory reachable through the
215225
-- argument. For example, if `argRef` points to an `&mut i32`, the `i32` will
216226
-- be overwritten with a fresh symbolic variable.
217-
addArg :: forall sym t st fs rtp args ret tp.
218-
(IsSymInterface sym, sym ~ W4.ExprBuilder t st fs) =>
227+
addArg :: forall sym p t st fs rtp args ret tp.
228+
(IsSymInterface sym, sym ~ W4.ExprBuilder t st fs, HasModel p) =>
219229
TypeRepr tp -> MirReferenceMux sym tp -> MethodSpecBuilder sym t ->
220-
OverrideSim (Model sym) sym MIR rtp args ret (MethodSpecBuilder sym t)
230+
OverrideSim (p sym) sym MIR rtp args ret (MethodSpecBuilder sym t)
221231
addArg tpr argRef msb = execBuilderT msb $ do
222232
sym <- lift $ getSymInterface
223233
loc <- liftIO $ W4.getCurrentProgramLoc sym
@@ -362,21 +372,78 @@ gatherAsserts msb = do
362372
") references variable " ++ show v ++ " (" ++ show (W4.bvarName v) ++ " at " ++
363373
show (W4.bvarLoc v) ++ "), which does not appear in the function args"
364374
Right x -> map fst x
375+
newVars <- liftIO $ gatherVars sym [Some (MethodSpecValue BoolRepr pred) | pred <- asserts']
376+
let postVars' = Set.union (msb ^. msbPost . seVars) newVars
377+
let postOnlyVars = postVars' `Set.difference` (msb ^. msbPre . seVars)
378+
379+
(asserts'', substs) <- liftIO $
380+
gatherSubsts postOnlyVars vars [] [] asserts'
381+
substTerms <- forM substs $ \(Pair var expr) -> do
382+
varTerm <- liftIO $ eval $ W4.BoundVarExpr var
383+
varEc <- case SAW.asExtCns varTerm of
384+
Just ec -> return ec
385+
Nothing -> error $ "eval of BoundVarExpr produced non-ExtCns ?" ++ show varTerm
386+
exprTerm <- liftIO $ eval expr
387+
return (varEc, exprTerm)
365388

366389
let loc = msb ^. msbSpec . MS.csLoc
367-
assertConds <- liftIO $ forM asserts' $ \pred -> do
390+
assertConds <- liftIO $ forM asserts'' $ \pred -> do
368391
tt <- eval pred >>= SAW.mkTypedTerm sc
369392
return $ MS.SetupCond_Pred loc tt
370-
newVars <- liftIO $ gatherVars sym [Some (MethodSpecValue BoolRepr pred) | pred <- asserts']
371393

372394
return $ msb
373395
& msbSpec . MS.csPostState . MS.csConditions %~ (++ assertConds)
374-
& msbPost . seVars %~ Set.union newVars
396+
& msbPost . seVars .~ postVars'
397+
& msbSubsts %~ (++ substTerms)
398+
375399
where
376400
sc = msb ^. msbSharedContext
377401
eval :: forall tp. W4.Expr t tp -> IO SAW.Term
378402
eval = msb ^. msbEval
379403

404+
-- | Find assertions of the form `var == expr` that are suitable for
405+
-- performing substitutions, and separate them from the list of assertions.
406+
gatherSubsts ::
407+
Set (Some (W4.ExprBoundVar t)) ->
408+
Set (Some (W4.ExprBoundVar t)) ->
409+
[W4.Expr t BaseBoolType] ->
410+
[Pair (W4.ExprBoundVar t) (W4.Expr t)] ->
411+
[W4.Expr t BaseBoolType] ->
412+
IO ([W4.Expr t BaseBoolType], [Pair (W4.ExprBoundVar t) (W4.Expr t)])
413+
gatherSubsts _lhsOk _rhsOk accPreds accSubsts [] =
414+
return (reverse accPreds, reverse accSubsts)
415+
gatherSubsts lhsOk rhsOk accPreds accSubsts (pred : preds)
416+
| Just (Pair var expr) <- asVarEqExpr pred = do
417+
rhsSeenRef <- newIORef Set.empty
418+
cache <- W4.newIdxCache
419+
visitExprVars cache expr $ \var -> modifyIORef rhsSeenRef $ Set.insert (Some var)
420+
rhsSeen <- readIORef rhsSeenRef
421+
let lhsOk' = Set.delete (Some var) lhsOk
422+
let rhsOk' = Set.delete (Some var) rhsOk
423+
-- We can't use `pred` as a substitution if the RHS contains variables
424+
-- that were deleted by a previous substitution. Otherwise we'd end up
425+
-- re-introducing a deleted variable. We also can't do substitutions
426+
-- where the RHS expression contains the LHS variable, which is why we
427+
-- check against `rhsOk'` here instead of `rhsOk`.
428+
if rhsSeen `Set.isSubsetOf` rhsOk' then
429+
gatherSubsts lhsOk' rhsOk' accPreds (Pair var expr : accSubsts) preds
430+
else
431+
gatherSubsts lhsOk rhsOk (pred : accPreds) accSubsts preds
432+
| otherwise =
433+
gatherSubsts lhsOk rhsOk (pred : accPreds) accSubsts preds
434+
where
435+
asVarEqExpr pred
436+
| Just (W4.BaseEq _btpr x y) <- W4.asApp pred
437+
, W4.BoundVarExpr v <- x
438+
, Set.member (Some v) lhsOk
439+
= Just (Pair v y)
440+
| Just (W4.BaseEq _btpr x y) <- W4.asApp pred
441+
, W4.BoundVarExpr v <- y
442+
, Set.member (Some v) lhsOk
443+
= Just (Pair v x)
444+
| otherwise = Nothing
445+
446+
380447
-- | Collect all the symbolic variables that appear in `vals`.
381448
gatherVars ::
382449
(IsSymInterface sym, sym ~ W4.ExprBuilder t st fs) =>
@@ -461,10 +528,11 @@ finish msb = do
461528
& MS.csPreState . MS.csAllocs .~ preAllocs
462529
& MS.csPostState . MS.csFreshVars .~ postVars'
463530
& MS.csPostState . MS.csAllocs .~ postAllocs
464-
nonce <- liftIO $ freshNonce ng
531+
sm <- liftIO $ buildSubstMap (msb ^. msbSharedContext) (msb ^. msbSubsts)
532+
ms' <- liftIO $ substMethodSpec (msb ^. msbSharedContext) sm ms
465533

466-
let ms' = MethodSpec (msb ^. msbCollectionState) ms
467-
return $ M.MethodSpec ms' (indexValue nonce)
534+
nonce <- liftIO $ freshNonce ng
535+
return $ M.MethodSpec (MethodSpec (msb ^. msbCollectionState) ms') (indexValue nonce)
468536

469537
where
470538
sc = msb ^. msbSharedContext
@@ -480,6 +548,80 @@ finish msb = do
480548
Nothing -> error $ "BoundVarExpr translated to non-ExtCns term? " ++ show tt
481549

482550

551+
buildSubstMap ::
552+
SAW.SharedContext ->
553+
[(SAW.ExtCns SAW.Term, SAW.Term)] ->
554+
IO (Map SAW.VarIndex SAW.Term)
555+
buildSubstMap sc substs = go Map.empty substs
556+
where
557+
go sm [] = return sm
558+
go sm ((ec, term) : substs) = do
559+
-- Rewrite the RHSs of previous substitutions using the current one.
560+
let sm1 = Map.singleton (SAW.ecVarIndex ec) term
561+
sm' <- mapM (SAW.scInstantiateExt sc sm1) sm
562+
-- Add the current subst and continue.
563+
go (Map.insert (SAW.ecVarIndex ec) term sm') substs
564+
565+
substMethodSpec ::
566+
SAW.SharedContext ->
567+
Map SAW.VarIndex SAW.Term ->
568+
MIRMethodSpec ->
569+
IO MIRMethodSpec
570+
substMethodSpec sc sm ms = do
571+
preState' <- goState $ ms ^. MS.csPreState
572+
postState' <- goState $ ms ^. MS.csPostState
573+
argBindings' <- mapM goArg $ ms ^. MS.csArgBindings
574+
retValue' <- mapM goSetupValue $ ms ^. MS.csRetValue
575+
return $ ms
576+
& MS.csPreState .~ preState'
577+
& MS.csPostState .~ postState'
578+
& MS.csArgBindings .~ argBindings'
579+
& MS.csRetValue .~ retValue'
580+
581+
where
582+
goState ss = do
583+
pointsTos' <- mapM goPointsTo $ ss ^. MS.csPointsTos
584+
conditions' <- mapM goSetupCondition $ ss ^. MS.csConditions
585+
let freshVars' =
586+
filter (\tec -> not $ Map.member (SAW.ecVarIndex $ SAW.tecExt tec) sm) $
587+
ss ^. MS.csFreshVars
588+
return $ ss
589+
& MS.csPointsTos .~ pointsTos'
590+
& MS.csConditions .~ conditions'
591+
& MS.csFreshVars .~ freshVars'
592+
593+
goArg (ty, sv) = do
594+
sv' <- goSetupValue sv
595+
return (ty, sv')
596+
597+
goPointsTo (MirPointsTo alloc svs) = MirPointsTo alloc <$> mapM goSetupValue svs
598+
599+
goSetupValue sv = case sv of
600+
MS.SetupVar _ -> return sv
601+
MS.SetupTerm tt -> MS.SetupTerm <$> goTypedTerm tt
602+
MS.SetupNull _ -> return sv
603+
MS.SetupStruct b packed svs -> MS.SetupStruct b packed <$> mapM goSetupValue svs
604+
MS.SetupArray b svs -> MS.SetupArray b <$> mapM goSetupValue svs
605+
MS.SetupElem b sv idx -> MS.SetupElem b <$> goSetupValue sv <*> pure idx
606+
MS.SetupField b sv name -> MS.SetupField b <$> goSetupValue sv <*> pure name
607+
MS.SetupGlobal _ _ -> return sv
608+
MS.SetupGlobalInitializer _ _ -> return sv
609+
610+
goSetupCondition (MS.SetupCond_Equal loc sv1 sv2) =
611+
MS.SetupCond_Equal loc <$> goSetupValue sv1 <*> goSetupValue sv2
612+
goSetupCondition (MS.SetupCond_Pred loc tt) =
613+
MS.SetupCond_Pred loc <$> goTypedTerm tt
614+
goSetupCondition (MS.SetupCond_Ghost b loc gg tt) =
615+
MS.SetupCond_Ghost b loc gg <$> goTypedTerm tt
616+
617+
goTypedTerm tt = do
618+
term' <- goTerm $ SAW.ttTerm tt
619+
return $ tt { SAW.ttTerm = term' }
620+
621+
goTerm term = SAW.scInstantiateExt sc sm term
622+
623+
624+
483625
-- RegValue -> SetupValue conversion
484626

485627
-- | Convert a RegValue into a SetupValue pattern. Symbolic variables in the
@@ -518,6 +660,7 @@ regToSetup sym p eval shp rv = go shp rv
518660
| otherwise = error $ "regToSetup: type error: expected " ++ show shpTpr ++
519661
", but got Any wrapping " ++ show tpr
520662
where shpTpr = StructRepr $ fmapFC fieldShapeType flds
663+
go (TransparentShape _ shp) rv = go shp rv
521664
go (RefShape refTy ty' tpr) ref = do
522665
partIdxLen <- lift $ mirRef_indexAndLenSim ref
523666
optIdxLen <- liftIO $ readPartExprMaybe sym partIdxLen

0 commit comments

Comments
 (0)