Skip to content

Commit 63942e4

Browse files
authored
Move modifies inference immediately after resolution (#1004)
- Fix issue #1001 by moving modifies inference earlier so that type checking can use that information. - Change command-line option /doModSetAnalysis to /inferModifies. - Improve documentation of cache coherence example.
1 parent 6c21aff commit 63942e4

File tree

11 files changed

+61
-41
lines changed

11 files changed

+61
-41
lines changed

Source/Core/Analysis/ModSetCollector.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public ModSetCollector(CoreOptions options)
2626

2727
private bool moreProcessingRequired;
2828

29-
public void DoModSetAnalysis(Program program)
29+
public void CollectModifies(Program program)
3030
{
3131
Contract.Requires(program != null);
3232
var implementedProcs = new HashSet<Procedure>();
@@ -66,8 +66,11 @@ public void DoModSetAnalysis(Program program)
6666

6767
foreach (Procedure x in modSets.Keys)
6868
{
69-
x.Modifies = new List<IdentifierExpr>();
70-
foreach (Variable v in modSets[x])
69+
if (x.Modifies == null)
70+
{
71+
x.Modifies = new List<IdentifierExpr>();
72+
}
73+
foreach (Variable v in modSets[x].Except(x.Modifies.Select(y => y.Decl)))
7174
{
7275
x.Modifies.Add(new IdentifierExpr(v.tok, v));
7376
}

Source/Core/CoreOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public enum VerbosityLevel
5555
bool OverlookBoogieTypeErrors { get; }
5656
uint TimeLimit { get; }
5757
uint ResourceLimit { get; }
58-
bool DoModSetAnalysis { get; set; }
58+
bool InferModifies { get; set; }
5959
bool DebugStagedHoudini { get; }
6060
int LoopUnrollCount { get; }
6161
bool DeterministicExtractLoops { get; }

Source/Core/ResolutionContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ public class TypecheckingContext : CheckingContext
751751
public LayerRange ExpectedLayerRange;
752752
public bool GlobalAccessOnlyInOld;
753753
public int InsideOld;
754-
public bool CheckModifies => Proc != null && (!Options?.DoModSetAnalysis ?? true);
754+
public bool CheckModifies => Proc != null && (!Options?.InferModifies ?? true);
755755

756756
public TypecheckingContext(IErrorSink errorSink, CoreOptions options)
757757
: base(errorSink)

Source/ExecutionEngine/CommandLineOptions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -416,9 +416,9 @@ public bool SIBoolControlVC {
416416

417417
public bool ExpandLambdas { get; set; } = true; // not useful from command line, only to be set to false programatically
418418

419-
public bool DoModSetAnalysis {
420-
get => doModSetAnalysis;
421-
set => doModSetAnalysis = value;
419+
public bool InferModifies {
420+
get => inferModifies;
421+
set => inferModifies = value;
422422
}
423423

424424
public bool UseAbstractInterpretation { get; set; }
@@ -576,7 +576,7 @@ void ObjectInvariant5()
576576
private bool proverHelpRequested = false;
577577
private bool restartProverPerVc = false;
578578
private bool useArrayAxioms = false;
579-
private bool doModSetAnalysis = false;
579+
private bool inferModifies = false;
580580
private bool runDiagnosticsOnTimeout = false;
581581
private bool traceDiagnosticsOnTimeout = false;
582582
private bool siBoolControlVc = false;
@@ -1362,7 +1362,7 @@ protected override bool ParseOption(string name, CommandLineParseState ps)
13621362
ps.CheckBooleanFlag("reflectAdd", x => ReflectAdd = x) ||
13631363
ps.CheckBooleanFlag("useArrayAxioms", x => useArrayAxioms = x) ||
13641364
ps.CheckBooleanFlag("relaxFocus", x => RelaxFocus = x) ||
1365-
ps.CheckBooleanFlag("doModSetAnalysis", x => doModSetAnalysis = x) ||
1365+
ps.CheckBooleanFlag("inferModifies", x => inferModifies = x) ||
13661366
ps.CheckBooleanFlag("runDiagnosticsOnTimeout", x => runDiagnosticsOnTimeout = x) ||
13671367
ps.CheckBooleanFlag("traceDiagnosticsOnTimeout", x => traceDiagnosticsOnTimeout = x) ||
13681368
ps.CheckBooleanFlag("boolControlVC", x => siBoolControlVc = x, true) ||
@@ -1809,7 +1809,7 @@ extract reducible loops into recursive procedures and
18091809
inline irreducible loops using the bound supplied by /loopUnroll:<n>
18101810
/soundLoopUnrolling
18111811
sound loop unrolling
1812-
/doModSetAnalysis
1812+
/inferModifies
18131813
automatically infer modifies clauses
18141814
/printModel:<n>
18151815
0 (default) - do not print Z3's error model

Source/ExecutionEngine/ExecutionEngine.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,11 @@ public void CoalesceBlocks(Program program)
229229
}
230230

231231

232-
public void CollectModSets(Program program)
232+
public void CollectModifies(Program program)
233233
{
234-
if (Options.DoModSetAnalysis)
234+
if (Options.InferModifies)
235235
{
236-
new ModSetCollector(Options).DoModSetAnalysis(program);
236+
new ModSetCollector(Options).CollectModifies(program);
237237
}
238238
}
239239

@@ -339,7 +339,7 @@ public Program ParseBoogieProgram(IList<string> fileNames, bool suppressTraceOut
339339
if (program.TopLevelDeclarations.Any(d => d.HasCivlAttribute()))
340340
{
341341
Options.Libraries.Add("base");
342-
Options.DoModSetAnalysis = true;
342+
Options.InferModifies = true;
343343
}
344344

345345
foreach (var libraryName in Options.Libraries)
@@ -403,6 +403,8 @@ public PipelineOutcome ResolveAndTypecheck(Program program, string bplFileName,
403403
return PipelineOutcome.TypeCheckingError;
404404
}
405405

406+
CollectModifies(program);
407+
406408
errorCount = program.Typecheck(Options);
407409
if (errorCount != 0)
408410
{
@@ -443,8 +445,6 @@ public PipelineOutcome ResolveAndTypecheck(Program program, string bplFileName,
443445
return PipelineOutcome.FatalError;
444446
}
445447

446-
CollectModSets(program);
447-
448448
civlTypeChecker = new CivlTypeChecker(Options, program);
449449
civlTypeChecker.TypeCheck();
450450
if (civlTypeChecker.checkingContext.ErrorCount != 0)
@@ -728,7 +728,7 @@ public async Task<IReadOnlyList<IVerificationTask>> GetVerificationTasks(Program
728728
}
729729

730730
EliminateDeadVariables(program);
731-
CollectModSets(program);
731+
CollectModifies(program);
732732
CoalesceBlocks(program);
733733
Inline(program);
734734

Source/UnitTests/ExecutionEngineTests/ExecutionEngineTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ public Program GetProgram(ExecutionEngine engine, string code) {
516516

517517
engine.ResolveAndTypecheck(program, bplFileName, out _);
518518
engine.EliminateDeadVariables(program);
519-
engine.CollectModSets(program);
519+
engine.CollectModifies(program);
520520
engine.CoalesceBlocks(program);
521521
engine.Inline(program);
522522
return program;

Test/civl/large-samples/cache-coherence.bpl

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,22 @@ var {:layer 1,3} absMem: [MemAddr]Value;
7272
/*
7373
The proof is done in two layers.
7474
75-
At layer 1, cachePermissions and dirPermissions are introduced allowing dirBusy and cacheBusy
76-
to be hidden. At this layer, absMem is also introduced. The main purpose of this layer is to
77-
create atomic actions with suitable mover types. Specifically, we want the following:
75+
Layer 1 to layer 2:
76+
absMem is introduced to enable specification of the cache coherence property.
77+
cachePermissions and dirPermissions are introduced allowing dirBusy and cacheBusy to be hidden.
78+
The main purpose of this proof is to create atomic actions with suitable mover types.
79+
Specifically, we want the following:
7880
- Memory operations (read and write) to be both movers.
7981
- Shared invalidate request at cache to be left mover.
8082
- Response to read request at cache to be left mover.
8183
- Initiation and conclusion of cache and directory operations to be right and left movers, respectively.
8284
83-
At layer 2, we do an invariance proof to hide the directory and all the caches so that the read
84-
and write operations at cache are described as atomic operations over absMem. This specfication
85-
method naturally captures the cache coherence property. To achieve this specfication, the variables
86-
mem, dir, cache, cachePermissions, and dirPermissions are hidden. The yield invariant at this level
87-
is a global invariant connecting directory and cache states.
85+
Layer 2 to layer 3:
86+
We do an invariance proof to hide the directory and all the caches so that the read
87+
and write operations at cache are described as atomic operations over absMem.
88+
This specfication method naturally captures the cache coherence property.
89+
To achieve this specfication, the variables mem, dir, cache, cachePermissions, and dirPermissions are hidden.
90+
The yield invariant at this level is a global invariant connecting directory and cache states.
8891
*/
8992

9093
/// Yield invariants
@@ -116,21 +119,20 @@ invariant (var line := cache[i][Hash(ma)]; (line->state == Invalid() || line->st
116119

117120
/// Cache
118121
/*
119-
There are 5 top-level operations on the cache.
120-
cache_read and cache_write read and write a cache entry, respectively;
121-
they may nondeterministically choose not to do the operation.
122-
cache_evict_req initiates eviction of a cache line.
123-
cache_read_shd_req and cache_read_exc_req initiate bringing a memory address into the cache
124-
in Shared and Exclusive mode, respectively.
122+
There are 5 top-level operations on the cache:
123+
- cache_read and cache_write read and write a cache entry, respectively.
124+
- cache_evict_req initiates eviction of a cache line.
125+
- cache_read_shd_req and cache_read_exc_req initiate bringing a memory address into the cache
126+
in Shared and Exclusive mode, respectively.
125127
The last three operations make asynchronous calls to corresponding operations on the directory
126128
to achieve their goals.
127129
128-
To specify the protocol, we introduce absMem, a global variable capturing the logical view of
129-
memory at layer 1.
130-
The verification demonstrates that cache_read and cache_read do the appropriate operation
131-
on absMem.
132-
At layer 3, all operations other than cache_read and cache_write disappear by becoming "skip"
133-
since all the concrete state is hidden by layer 2.
130+
We introduce at layer 1 a global variable absMem to capture the logical view of memory.
131+
The presence of absMem allows us to specify the cache coherence property in a natural way.
132+
The verification demonstrates that at layer 3:
133+
- cache_read is abstracted by an atomic action that reads from absMem.
134+
- cache_write is abstracted by an atomic action that writes to absMem.
135+
- all other operations are abstracted by "skip".
134136
*/
135137

136138
yield procedure {:layer 2} cache_read(i: CacheId, ma: MemAddr) returns (result: Option Value)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %parallel-boogie "%s" > "%t"
2+
// RUN: %diff "%s.expect" "%t"
3+
4+
var {:layer 0,1} g: int;
5+
yield right procedure {:layer 1} P()
6+
{
7+
call A();
8+
}
9+
10+
yield procedure {:layer 0} A();
11+
refines right action {:layer 1} _ {
12+
g := 1;
13+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
modifies-bug.bpl(7,4): Error: modified variable does not appear in modifies clause of mover procedure: g
2+
1 type checking errors detected in modifies-bug.bpl

Test/smack/git-issue-203-define.bpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// generated by SMACK version 2.4.0 for boogie
22
// via /usr/local/bin/smack two_arrays.c --loop-limit=11 --unroll=11 --verifier=boogie --debug --bpl=pero.bpl
33

4-
// RUN: %parallel-boogie -doModSetAnalysis -timeLimit:1200 -errorLimit:1 -loopUnroll:15 "%s" > "%t"
4+
// RUN: %parallel-boogie -inferModifies -timeLimit:1200 -errorLimit:1 -loopUnroll:15 "%s" > "%t"
55
// RUN: %diff "%s.expect" "%t"
66

77
// Basic types

0 commit comments

Comments
 (0)