@@ -12,7 +12,7 @@ public class YieldingProcDuplicator : Duplicator
1212 * Async calls are also rewritten so that the resulting copies are guaranteed not to
1313 * have any async calls. The copy of yielding procedure X shares local variables of X.
1414 * This sharing is exploited when instrumenting the duplicates in the class
15- * YieldProcInstrumentation .
15+ * YieldingProcInstrumentation .
1616 */
1717 private CivlTypeChecker civlTypeChecker ;
1818 private int layerNum ;
@@ -29,11 +29,11 @@ public YieldingProcDuplicator(CivlTypeChecker civlTypeChecker, int layerNum, boo
2929 {
3030 this . civlTypeChecker = civlTypeChecker ;
3131 this . layerNum = layerNum ;
32- this . doRefinementCheck = doRefinementCheck ;
33- this . procToDuplicate = new Dictionary < Procedure , Procedure > ( ) ;
32+ this . procToDuplicate = [ ] ;
3433 this . absyMap = new AbsyMap ( ) ;
35- this . asyncCallPreconditionCheckers = new Dictionary < string , Procedure > ( ) ;
34+ this . asyncCallPreconditionCheckers = [ ] ;
3635 this . linearRewriter = new LinearRewriter ( civlTypeChecker ) ;
36+ this . doRefinementCheck = doRefinementCheck ;
3737 }
3838
3939 #region Procedure duplication
@@ -62,15 +62,15 @@ public override Procedure VisitYieldProcedureDecl(YieldProcedureDecl node)
6262 var proc = new Procedure (
6363 node . tok ,
6464 procName ,
65- new List < TypeVariable > ( ) ,
65+ [ ] ,
6666 VisitVariableSeq ( node . InParams ) ,
6767 VisitVariableSeq ( node . OutParams ) ,
6868 false ,
6969 requires ,
70- new List < Requires > ( ) ,
70+ [ ] ,
7171 ensures ,
7272 ( node . HasMoverType && node . Layer == layerNum
73- ? node . ModifiedVars . Select ( g => Expr . Ident ( g ) )
73+ ? node . ModifiedVars . Select ( Expr . Ident )
7474 : civlTypeChecker . GlobalVariables . Select ( v => Expr . Ident ( v ) ) ) . ToList ( )
7575 ) ;
7676 procToDuplicate [ node ] = proc ;
@@ -140,6 +140,8 @@ public override Ensures VisitEnsures(Ensures node)
140140
141141 private Dictionary < CtorType , Variable > returnedPAs ;
142142
143+ private Dictionary < string , Variable > addedLocalVariables ;
144+
143145 private Variable ReturnedPAs ( CtorType pendingAsyncType )
144146 {
145147 if ( ! returnedPAs . ContainsKey ( pendingAsyncType ) )
@@ -168,11 +170,13 @@ public override Implementation VisitImplementation(Implementation impl)
168170 Debug . Assert ( layerNum <= enclosingYieldingProc . Layer ) ;
169171
170172 returnedPAs = new Dictionary < CtorType , Variable > ( ) ;
173+ addedLocalVariables = new Dictionary < string , Variable > ( ) ;
171174
172175 Implementation newImpl = base . VisitImplementation ( impl ) ;
173176 newImpl . Name = newImpl . Proc . Name ;
174177
175178 newImpl . LocVars . AddRange ( returnedPAs . Values ) ;
179+ newImpl . LocVars . AddRange ( addedLocalVariables . Values ) ;
176180
177181 if ( ! enclosingYieldingProc . HasMoverType && RefinedAction . HasPendingAsyncs && doRefinementCheck )
178182 {
@@ -259,6 +263,52 @@ public override List<Cmd> VisitCmdSeq(List<Cmd> cmdSeq)
259263 return newCmdSeq ;
260264 }
261265
266+ private void AddParallelCall ( List < CallCmd > callCmds , Absy absy )
267+ {
268+ var parCallCmd = new ParCallCmd ( absy . tok , callCmds ) ;
269+ absyMap [ parCallCmd ] = absyMap [ absy ] ;
270+ newCmdSeq . Add ( parCallCmd ) ;
271+ }
272+
273+ private bool NeedsRefinementChecking ( CallCmd callCmd )
274+ {
275+ if ( callCmd . Proc is not YieldProcedureDecl yieldingProc )
276+ {
277+ return false ;
278+ }
279+ if ( layerNum != yieldingProc . Layer )
280+ {
281+ return false ;
282+ }
283+ var visibleFormalNames = enclosingYieldingProc . VisibleFormals . Select ( v => v . Name ) ;
284+ var visibleOutFormalNames = enclosingYieldingProc . OutParams . Select ( v => v . Name ) . Intersect ( visibleFormalNames ) ;
285+ var callOutParamNames = callCmd . Outs . Select ( ie => ie . Decl . Name ) ;
286+ var isCallSkippable = yieldingProc . RefinedAction . ActionDecl == civlTypeChecker . SkipActionDecl &&
287+ ! visibleOutFormalNames . Intersect ( callOutParamNames ) . Any ( ) ;
288+ return ! isCallSkippable ;
289+ }
290+
291+ // Create a duplicate of callCmd and update the outputs of callCmd to fresh local variables.
292+ // The duplicate call, returned by this method, is rewritten to call the refined action.
293+ // The original callCmd with rewritten outputs is used as normal in the parallel call that models
294+ // the yield after the call to the refined action.
295+ // Assumes constraining each output to the corresponding fresh output are added after the parallel call.
296+ private CallCmd PrepareCallCmd ( CallCmd callCmd )
297+ {
298+ var copyCallCmd = ( CallCmd ) VisitCallCmd ( callCmd ) ;
299+ var freshOuts = new List < IdentifierExpr > ( ) ;
300+ copyCallCmd . Outs . ForEach ( ie => {
301+ if ( ! addedLocalVariables . TryGetValue ( ie . Decl . Name , out Variable copyVar ) )
302+ {
303+ copyVar = civlTypeChecker . LocalVariable ( $ "{ ie . Decl . Name } _{ callCmd . UniqueId } ", ie . Type ) ;
304+ addedLocalVariables [ ie . Decl . Name ] = copyVar ;
305+ }
306+ freshOuts . Add ( Expr . Ident ( copyVar ) ) ;
307+ } ) ;
308+ callCmd . Outs = freshOuts ;
309+ return copyCallCmd ;
310+ }
311+
262312 private void ProcessCallCmd ( CallCmd newCall )
263313 {
264314 if ( newCall . Proc . IsPure )
@@ -295,9 +345,7 @@ cmd is AssertCmd assertCmd && makeAssume
295345 {
296346 if ( layerNum == yieldInvariant . Layer )
297347 {
298- var parCallCmd = new ParCallCmd ( newCall . tok , new List < CallCmd > { newCall } ) ;
299- absyMap [ parCallCmd ] = absyMap [ newCall ] ;
300- newCmdSeq . Add ( parCallCmd ) ;
348+ AddParallelCall ( [ newCall ] , newCall ) ;
301349 }
302350 return ;
303351 }
@@ -353,15 +401,13 @@ cmd is AssertCmd assertCmd && makeAssume
353401 }
354402 else
355403 {
356- if ( doRefinementCheck && yieldingProc . RefinedAction . ActionDecl != civlTypeChecker . SkipActionDecl )
404+ if ( doRefinementCheck && NeedsRefinementChecking ( newCall ) )
357405 {
358- var parCallCmdBefore = new ParCallCmd ( newCall . tok , [ ] ) ;
359- absyMap [ parCallCmdBefore ] = absyMap [ newCall ] ;
360- newCmdSeq . Add ( parCallCmdBefore ) ;
361- AddActionCall ( newCall , yieldingProc ) ;
362- var parCallCmdAfter = new ParCallCmd ( newCall . tok , [ ] ) ;
363- absyMap [ parCallCmdAfter ] = absyMap [ newCall ] ;
364- newCmdSeq . Add ( parCallCmdAfter ) ;
406+ AddParallelCall ( [ ] , newCall ) ;
407+ var copyCall = PrepareCallCmd ( newCall ) ;
408+ AddActionCall ( copyCall , yieldingProc ) ;
409+ AddDuplicateCall ( newCall , true ) ;
410+ newCmdSeq . AddRange ( newCall . Outs . Zip ( copyCall . Outs ) . Select ( x => CmdHelper . AssumeCmd ( Expr . Eq ( x . First , x . Second ) ) ) ) ;
365411 }
366412 else
367413 {
@@ -376,11 +422,14 @@ private void ProcessParCallCmd(ParCallCmd newParCall)
376422 {
377423 var callCmds = new List < CallCmd > ( ) ;
378424
379- void AddParallelCall ( )
425+ void AddParallelCallWrapper ( )
380426 {
381- var parCallCmd = new ParCallCmd ( newParCall . tok , callCmds ) ;
382- absyMap [ parCallCmd ] = absyMap [ newParCall ] ;
383- newCmdSeq . Add ( parCallCmd ) ;
427+ callCmds . Where ( iter => iter . Proc is YieldProcedureDecl )
428+ . ForEach ( iter => {
429+ iter . Proc = procToDuplicate [ iter . Proc ] ;
430+ iter . callee = iter . Proc . Name ;
431+ } ) ;
432+ AddParallelCall ( callCmds , newParCall ) ;
384433 }
385434
386435 void ProcessPendingCallCmds ( )
@@ -389,18 +438,19 @@ void ProcessPendingCallCmds()
389438 {
390439 return ;
391440 }
392- var callCmd = callCmds . Find ( cmd =>
393- cmd . Proc is YieldProcedureDecl yieldingProc &&
394- layerNum == yieldingProc . Layer &&
395- yieldingProc . RefinedAction . ActionDecl != civlTypeChecker . SkipActionDecl ) ;
396- if ( doRefinementCheck && callCmd != null )
441+ CallCmd callCmd = doRefinementCheck ? callCmds . Find ( NeedsRefinementChecking ) : null ;
442+ if ( callCmd != null )
397443 {
398- callCmds . Remove ( callCmd ) ;
399- callCmds . ForEach ( callCmd => Debug . Assert ( callCmd . Proc is YieldInvariantDecl ) ) ;
400- AddParallelCall ( ) ;
401- AddActionCall ( callCmd , ( YieldProcedureDecl ) callCmd . Proc ) ;
444+ AddParallelCall ( [ ] , callCmd ) ;
445+ var copyCall = PrepareCallCmd ( callCmd ) ;
446+ AddActionCall ( copyCall , ( YieldProcedureDecl ) callCmd . Proc ) ;
447+ AddParallelCallWrapper ( ) ;
448+ newCmdSeq . AddRange ( callCmd . Outs . Zip ( copyCall . Outs ) . Select ( x => CmdHelper . AssumeCmd ( Expr . Eq ( x . First , x . Second ) ) ) ) ;
449+ }
450+ else
451+ {
452+ AddParallelCallWrapper ( ) ;
402453 }
403- AddParallelCall ( ) ;
404454 callCmds = [ ] ;
405455 }
406456
@@ -415,11 +465,6 @@ cmd.Proc is YieldProcedureDecl yieldingProc &&
415465 ProcessCallCmd ( callCmd ) ;
416466 continue ;
417467 }
418- }
419- if ( procToDuplicate . ContainsKey ( callCmd . Proc ) )
420- {
421- callCmd . Proc = procToDuplicate [ callCmd . Proc ] ;
422- callCmd . callee = callCmd . Proc . Name ;
423468 callCmds . Add ( callCmd ) ;
424469 }
425470 else
@@ -506,7 +551,7 @@ private void InjectGate(Action action, CallCmd callCmd, bool assume)
506551 return ;
507552 }
508553
509- Dictionary < Variable , Expr > map = new Dictionary < Variable , Expr > ( ) ;
554+ Dictionary < Variable , Expr > map = [ ] ;
510555 for ( int i = 0 ; i < action . Impl . InParams . Count ; i ++ )
511556 {
512557 // Parameters come from the implementation that defines the action
@@ -577,9 +622,7 @@ private void AddDuplicateCall(CallCmd newCall, bool makeParallel)
577622 newCall . callee = newCall . Proc . Name ;
578623 if ( makeParallel )
579624 {
580- var parCallCmd = new ParCallCmd ( newCall . tok , new List < CallCmd > { newCall } ) ;
581- absyMap [ parCallCmd ] = absyMap [ newCall ] ;
582- newCmdSeq . Add ( parCallCmd ) ;
625+ AddParallelCall ( [ newCall ] , newCall ) ;
583626 }
584627 else
585628 {
@@ -594,7 +637,7 @@ private void DesugarAsyncCall(CallCmd newCall)
594637 asyncCallPreconditionCheckers [ newCall . Proc . Name ] = DeclHelper . Procedure (
595638 civlTypeChecker . AddNamePrefix ( $ "AsyncCall_{ newCall . Proc . Name } _{ layerNum } ") ,
596639 newCall . Proc . InParams , newCall . Proc . OutParams ,
597- procToDuplicate [ newCall . Proc ] . Requires , new List < Requires > ( ) , new List < Ensures > ( ) , new List < IdentifierExpr > ( ) ) ;
640+ procToDuplicate [ newCall . Proc ] . Requires , [ ] , [ ] , [ ] ) ;
598641 }
599642
600643 var asyncCallPreconditionChecker = asyncCallPreconditionCheckers [ newCall . Proc . Name ] ;
@@ -661,7 +704,7 @@ public class AbsyMap
661704
662705 public AbsyMap ( )
663706 {
664- this . absyMap = new Dictionary < Absy , Absy > ( ) ;
707+ this . absyMap = [ ] ;
665708 }
666709
667710 public Absy this [ Absy absy ]
0 commit comments