Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/main/scala/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -668,9 +668,10 @@ class Config(args: Seq[String]) extends SilFrontendConfig(args, "Silicon") {
noshort = true
)

val moreJoins: ScallopOption[Boolean] = opt[Boolean]("moreJoins",
descr = "Enable more joins using a more complete implementation of state merging.",
default = Some(false),
val moreJoins: ScallopOption[Int] = opt[Int]("moreJoins",
descr = "Enable more joins using a more complete implementation of state merging. " +
"0 = off, 1 = don't branch on impure conditionals, 2 = join all branches when possible.",
default = Some(0),
Comment thread
marcoeilers marked this conversation as resolved.
noshort = true
)

Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/rules/Brancher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ object brancher extends BranchingRules {
v.decider.prover.comment(s"Bulk-declaring functions")
v.decider.declareAndRecordAsFreshFunctions(functionsOfElseBranchDecider, true)
v.decider.prover.comment(s"Bulk-declaring macros")
v.decider.declareAndRecordAsFreshMacros(macrosOfElseBranchDecider, true)
// Declare macros without duplicates; we keep only the last occurrence of every declaration to avoid errors.
v.decider.declareAndRecordAsFreshMacros(macrosOfElseBranchDecider.reverse.distinct.reverse, true)
}
res
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/rules/Consumer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ object consumer extends ConsumptionRules {
v.logger.debug("hR = " + s.reserveHeaps.map(v.stateFormatter.format).mkString("", ",\n ", ""))

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

case ite @ ast.CondExp(e0, a1, a2) if !a.isPure && s.moreJoins =>
case ite @ ast.CondExp(e0, a1, a2) if !a.isPure && s.moreJoins > 0 =>
val condExpRecord = new CondExpRecord(ite, s, v.decider.pcs, "consume")
val uidCondExp = v.symbExLog.openScope(condExpRecord)
consumeConditionalTlcMoreJoins(s, h, e0, a1, Some(a2), uidCondExp, pve, v)(Q)
Expand Down Expand Up @@ -507,7 +507,7 @@ object consumer extends ConsumptionRules {
// Asume that entry1.pcs is inverse of entry2.pcs
Ite(And(entry1.pathConditions.branchConditions), entry1.data._2, entry2.data._2)
)
(entry1.pathConditionAwareMerge(entry2, v1), mergedData)
(entry1.pathConditionAwareMergeWithoutConsolidation(entry2, v1), mergedData)
case _ =>
sys.error(s"Unexpected join data entries: $entries")
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/rules/Evaluator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ object evaluator extends EvaluationRules {
* incomplete).
*/
smDomainNeeded = true,
moreJoins = false)
moreJoins = 0)
consumes(s3, pres, _ => pvePre, v2)((s4, snap, v3) => {
val snap1 = snap.convert(sorts.Snap)
val preFApp = App(functionSupporter.preconditionVersion(v3.symbolConverter.toFunction(func)), snap1 :: tArgs)
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/rules/Executor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ object executor extends ExecutionRules {
case (Seq(), _) => Q(s, v)
case (Seq(edge), _) => follow(s, edge, v, joinPoint)(Q)
case (Seq(edge1, edge2), Some(newJoinPoint)) if
s.moreJoins &&
s.moreJoins > 1 &&
// Can't directly match type because of type erasure ...
edge1.isInstanceOf[ConditionalEdge[ast.Stmt, ast.Exp]] &&
edge2.isInstanceOf[ConditionalEdge[ast.Stmt, ast.Exp]] &&
Expand Down
4 changes: 4 additions & 0 deletions src/main/scala/rules/Joiner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ case class JoinDataEntry[D](s: State, data: D, pathConditions: RecordedPathCondi
val res = State.merge(this.s, this.pathConditions, other.s, other.pathConditions)
v.stateConsolidator.consolidate(res, v)
}

def pathConditionAwareMergeWithoutConsolidation(other: JoinDataEntry[D], v: Verifier): State = {
State.merge(this.s, this.pathConditions, other.s, other.pathConditions)
}
}

trait JoiningRules extends SymbolicExecutionRules {
Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/rules/Producer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ object producer extends ProductionRules {
continuation(if (state.exhaleExt) state.copy(reserveHeaps = state.h +: state.reserveHeaps.drop(1)) else state, verifier)

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

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

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

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/state/State.scala
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ final case class State(g: Store = Store(),
/* ast.Field, ast.Predicate, or MagicWandIdentifier */
heapDependentTriggers: InsertionOrderedSet[Any] = InsertionOrderedSet.empty,
moreCompleteExhale: Boolean = false,
moreJoins: Boolean = false)
moreJoins: Int = 0)
extends Mergeable[State] {

val isMethodVerification: Boolean = {
Expand Down
24 changes: 21 additions & 3 deletions src/main/scala/verifier/DefaultMainVerifier.scala
Original file line number Diff line number Diff line change
Expand Up @@ -323,10 +323,28 @@ class DefaultMainVerifier(config: Config,
case _ => Verifier.config.exhaleMode == ExhaleMode.MoreComplete
}
val moreJoinsAnnotated = member.info.getUniqueInfo[ast.AnnotationInfo] match {
case Some(ai) => ai.values.contains("moreJoins")
case _ => false
case Some(ai) if ai.values.contains("moreJoins") =>
ai.values("moreJoins") match {
case Seq() => Some(2)
case Seq(vl) =>
try {
Some(vl.toInt)
} catch {
case _: NumberFormatException =>
reporter report AnnotationWarning(s"Member ${member.name} has invalid moreJoins annotation value $vl. Annotation will be ignored.")
None
}
case v =>
reporter report AnnotationWarning(s"Member ${member.name} has invalid moreJoins annotation value $v. Annotation will be ignored.")
None
}
case _ => None
}
val moreJoins = if (member.isInstanceOf[ast.Method]) {
moreJoinsAnnotated.getOrElse(Verifier.config.moreJoins.getOrElse(0))
} else {
0
}
val moreJoins = (Verifier.config.moreJoins() || moreJoinsAnnotated) && member.isInstanceOf[ast.Method]

val methodPermCache = mutable.HashMap[String, InsertionOrderedSet[ast.Location]]()
val permResources: InsertionOrderedSet[ast.Location] = if (Verifier.config.unsafeWildcardOptimization()) member match {
Expand Down
2 changes: 1 addition & 1 deletion src/test/scala/SiliconTestsMoreJoins.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ class SiliconTestsMoreJoins extends SiliconTests {

override val commandLineArguments: Seq[String] = Seq(
"--timeout", "300" /* seconds */,
"--moreJoins"
"--moreJoins=2"
)
}