Skip to content

Commit 9e3d0f8

Browse files
authored
Merge pull request #823 from viperproject/meilers_flexible_more_joins
More flexible moreJoins
2 parents d4d2816 + 2abf3f5 commit 9e3d0f8

10 files changed

Lines changed: 41 additions & 17 deletions

File tree

src/main/scala/Config.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -668,9 +668,10 @@ class Config(args: Seq[String]) extends SilFrontendConfig(args, "Silicon") {
668668
noshort = true
669669
)
670670

671-
val moreJoins: ScallopOption[Boolean] = opt[Boolean]("moreJoins",
672-
descr = "Enable more joins using a more complete implementation of state merging.",
673-
default = Some(false),
671+
val moreJoins: ScallopOption[Int] = opt[Int]("moreJoins",
672+
descr = "Enable more joins using a more complete implementation of state merging. " +
673+
"0 = off, 1 = don't branch on impure conditionals, 2 = join all branches when possible.",
674+
default = Some(0),
674675
noshort = true
675676
)
676677

src/main/scala/rules/Brancher.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ object brancher extends BranchingRules {
244244
v.decider.prover.comment(s"Bulk-declaring functions")
245245
v.decider.declareAndRecordAsFreshFunctions(functionsOfElseBranchDecider, true)
246246
v.decider.prover.comment(s"Bulk-declaring macros")
247-
v.decider.declareAndRecordAsFreshMacros(macrosOfElseBranchDecider, true)
247+
// Declare macros without duplicates; we keep only the last occurrence of every declaration to avoid errors.
248+
v.decider.declareAndRecordAsFreshMacros(macrosOfElseBranchDecider.reverse.distinct.reverse, true)
248249
}
249250
res
250251
}

src/main/scala/rules/Consumer.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ object consumer extends ConsumptionRules {
183183
v.logger.debug("hR = " + s.reserveHeaps.map(v.stateFormatter.format).mkString("", ",\n ", ""))
184184

185185
val consumed = a match {
186-
case imp @ ast.Implies(e0, a0) if !a.isPure && s.moreJoins =>
186+
case imp @ ast.Implies(e0, a0) if !a.isPure && s.moreJoins > 0 =>
187187
val impliesRecord = new ImpliesRecord(imp, s, v.decider.pcs, "consume")
188188
val uidImplies = v.symbExLog.openScope(impliesRecord)
189189
consumeConditionalTlcMoreJoins(s, h, e0, a0, None, uidImplies, pve, v)(Q)
@@ -203,7 +203,7 @@ object consumer extends ConsumptionRules {
203203
Q(s2, h, Unit, v2)
204204
}))
205205

206-
case ite @ ast.CondExp(e0, a1, a2) if !a.isPure && s.moreJoins =>
206+
case ite @ ast.CondExp(e0, a1, a2) if !a.isPure && s.moreJoins > 0 =>
207207
val condExpRecord = new CondExpRecord(ite, s, v.decider.pcs, "consume")
208208
val uidCondExp = v.symbExLog.openScope(condExpRecord)
209209
consumeConditionalTlcMoreJoins(s, h, e0, a1, Some(a2), uidCondExp, pve, v)(Q)
@@ -507,7 +507,7 @@ object consumer extends ConsumptionRules {
507507
// Asume that entry1.pcs is inverse of entry2.pcs
508508
Ite(And(entry1.pathConditions.branchConditions), entry1.data._2, entry2.data._2)
509509
)
510-
(entry1.pathConditionAwareMerge(entry2, v1), mergedData)
510+
(entry1.pathConditionAwareMergeWithoutConsolidation(entry2, v1), mergedData)
511511
case _ =>
512512
sys.error(s"Unexpected join data entries: $entries")
513513
}

src/main/scala/rules/Evaluator.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ object evaluator extends EvaluationRules {
785785
* incomplete).
786786
*/
787787
smDomainNeeded = true,
788-
moreJoins = false)
788+
moreJoins = 0)
789789
consumes(s3, pres, _ => pvePre, v2)((s4, snap, v3) => {
790790
val snap1 = snap.convert(sorts.Snap)
791791
val preFApp = App(functionSupporter.preconditionVersion(v3.symbolConverter.toFunction(func)), snap1 :: tArgs)

src/main/scala/rules/Executor.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ object executor extends ExecutionRules {
111111
case (Seq(), _) => Q(s, v)
112112
case (Seq(edge), _) => follow(s, edge, v, joinPoint)(Q)
113113
case (Seq(edge1, edge2), Some(newJoinPoint)) if
114-
s.moreJoins &&
114+
s.moreJoins > 1 &&
115115
// Can't directly match type because of type erasure ...
116116
edge1.isInstanceOf[ConditionalEdge[ast.Stmt, ast.Exp]] &&
117117
edge2.isInstanceOf[ConditionalEdge[ast.Stmt, ast.Exp]] &&

src/main/scala/rules/Joiner.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ case class JoinDataEntry[D](s: State, data: D, pathConditions: RecordedPathCondi
2121
val res = State.merge(this.s, this.pathConditions, other.s, other.pathConditions)
2222
v.stateConsolidator.consolidate(res, v)
2323
}
24+
25+
def pathConditionAwareMergeWithoutConsolidation(other: JoinDataEntry[D], v: Verifier): State = {
26+
State.merge(this.s, this.pathConditions, other.s, other.pathConditions)
27+
}
2428
}
2529

2630
trait JoiningRules extends SymbolicExecutionRules {

src/main/scala/rules/Producer.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ object producer extends ProductionRules {
214214
continuation(if (state.exhaleExt) state.copy(reserveHeaps = state.h +: state.reserveHeaps.drop(1)) else state, verifier)
215215

216216
val produced = a match {
217-
case imp @ ast.Implies(e0, a0) if !a.isPure && s.moreJoins =>
217+
case imp @ ast.Implies(e0, a0) if !a.isPure && s.moreJoins > 0 =>
218218
val impliesRecord = new ImpliesRecord(imp, s, v.decider.pcs, "produce")
219219
val uidImplies = v.symbExLog.openScope(impliesRecord)
220220

@@ -240,7 +240,7 @@ object producer extends ProductionRules {
240240
case Seq(entry) => // One branch is dead
241241
entry.s
242242
case Seq(entry1, entry2) => // Both branches are alive
243-
entry1.pathConditionAwareMerge(entry2, v1)
243+
entry1.pathConditionAwareMergeWithoutConsolidation(entry2, v1)
244244
case _ =>
245245
sys.error(s"Unexpected join data entries: $entries")}
246246
(s2, null)
@@ -267,7 +267,7 @@ object producer extends ProductionRules {
267267
Q(s2, v2)
268268
}))
269269

270-
case ite @ ast.CondExp(e0, a1, a2) if !a.isPure && s.moreJoins =>
270+
case ite @ ast.CondExp(e0, a1, a2) if !a.isPure && s.moreJoins > 0=>
271271
val condExpRecord = new CondExpRecord(ite, s, v.decider.pcs, "produce")
272272
val uidCondExp = v.symbExLog.openScope(condExpRecord)
273273

src/main/scala/state/State.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ final case class State(g: Store = Store(),
7171
/* ast.Field, ast.Predicate, or MagicWandIdentifier */
7272
heapDependentTriggers: InsertionOrderedSet[Any] = InsertionOrderedSet.empty,
7373
moreCompleteExhale: Boolean = false,
74-
moreJoins: Boolean = false)
74+
moreJoins: Int = 0)
7575
extends Mergeable[State] {
7676

7777
val isMethodVerification: Boolean = {

src/main/scala/verifier/DefaultMainVerifier.scala

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,28 @@ class DefaultMainVerifier(config: Config,
323323
case _ => Verifier.config.exhaleMode == ExhaleMode.MoreComplete
324324
}
325325
val moreJoinsAnnotated = member.info.getUniqueInfo[ast.AnnotationInfo] match {
326-
case Some(ai) => ai.values.contains("moreJoins")
327-
case _ => false
326+
case Some(ai) if ai.values.contains("moreJoins") =>
327+
ai.values("moreJoins") match {
328+
case Seq() => Some(2)
329+
case Seq(vl) =>
330+
try {
331+
Some(vl.toInt)
332+
} catch {
333+
case _: NumberFormatException =>
334+
reporter report AnnotationWarning(s"Member ${member.name} has invalid moreJoins annotation value $vl. Annotation will be ignored.")
335+
None
336+
}
337+
case v =>
338+
reporter report AnnotationWarning(s"Member ${member.name} has invalid moreJoins annotation value $v. Annotation will be ignored.")
339+
None
340+
}
341+
case _ => None
342+
}
343+
val moreJoins = if (member.isInstanceOf[ast.Method]) {
344+
moreJoinsAnnotated.getOrElse(Verifier.config.moreJoins.getOrElse(0))
345+
} else {
346+
0
328347
}
329-
val moreJoins = (Verifier.config.moreJoins() || moreJoinsAnnotated) && member.isInstanceOf[ast.Method]
330348

331349
val methodPermCache = mutable.HashMap[String, InsertionOrderedSet[ast.Location]]()
332350
val permResources: InsertionOrderedSet[ast.Location] = if (Verifier.config.unsafeWildcardOptimization()) member match {

src/test/scala/SiliconTestsMoreJoins.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ class SiliconTestsMoreJoins extends SiliconTests {
1919

2020
override val commandLineArguments: Seq[String] = Seq(
2121
"--timeout", "300" /* seconds */,
22-
"--moreJoins"
22+
"--moreJoins=2"
2323
)
2424
}

0 commit comments

Comments
 (0)