Skip to content

Commit 176a23d

Browse files
authored
Merge pull request #784 from viperproject/meilers_proverArgs_annotation
Adding an annotation to set prover arguments per method
2 parents cef593b + f255a2b commit 176a23d

8 files changed

Lines changed: 82 additions & 5 deletions

File tree

src/main/scala/decider/Decider.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ import scala.collection.mutable
3030

3131
trait Decider {
3232
def prover: Prover
33+
def setProverOptions(options: Map[String, String]): Unit
34+
def getProverOptions(): Map[String, String]
35+
def resetProverOptions(): Unit
36+
3337
def pcs: PathConditionStack
3438

3539
def pushScope(): Unit
@@ -106,6 +110,9 @@ trait DefaultDeciderProvider extends VerifierComponent { this: Verifier =>
106110
private var _freshFunctionStack: Stack[mutable.HashSet[FunctionDecl]] = _
107111
private var _freshMacroStack: Stack[mutable.ListBuffer[MacroDecl]] = _
108112

113+
private var _proverOptions: Map[String, String] = Map.empty
114+
private var _proverResetOptions: Map[String, String] = Map.empty
115+
109116
def prover: Prover = _prover
110117

111118
def pcs: PathConditionStack = pathConditions
@@ -165,6 +172,20 @@ trait DefaultDeciderProvider extends VerifierComponent { this: Verifier =>
165172
None
166173
}
167174

175+
override def setProverOptions(options: Map[String, String]): Unit = {
176+
_proverOptions = _proverOptions ++ options
177+
val resetOptions = _proverOptions.map { case (k, v) => (k, _prover.setOption(k, v)) }
178+
_proverResetOptions = resetOptions ++ _proverResetOptions
179+
}
180+
181+
override def getProverOptions(): Map[String, String] = _proverOptions
182+
183+
override def resetProverOptions(): Unit = {
184+
_proverResetOptions.foreach { case (k, v) => _prover.setOption(k, v) }
185+
_proverResetOptions = Map.empty
186+
_proverOptions = Map.empty
187+
}
188+
168189
/* Life cycle */
169190

170191
def start(): Unit = {

src/main/scala/decider/ProverStdIO.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,15 @@ abstract class ProverStdIO(uniqueId: String,
195195
readSuccess()
196196
}
197197

198+
override def setOption(name: String, value: String): String = {
199+
writeLine(s"(get-option :${name})")
200+
val oldVal = readLine()
201+
if (oldVal == "unsupported")
202+
throw ProverInteractionFailed(uniqueId, s"Prover does not support option $name")
203+
emit(s"(set-option :$name $value)")
204+
oldVal
205+
}
206+
198207
// private val quantificationLogger = bookkeeper.logfiles("quantification-problems")
199208

200209
def assume(term: Term): Unit = {

src/main/scala/decider/Z3ProverAPI.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import java.nio.file.Path
2020
import scala.collection.mutable
2121
import com.microsoft.z3._
2222
import com.microsoft.z3.enumerations.Z3_param_kind
23-
import viper.silicon.reporting.ExternalToolError
23+
import viper.silicon.reporting.{ExternalToolError, ProverInteractionFailed}
2424

2525
import scala.jdk.CollectionConverters.MapHasAsJava
2626
import scala.util.Random
@@ -239,6 +239,10 @@ class Z3ProverAPI(uniqueId: String,
239239
}
240240
}
241241

242+
override def setOption(name: String, value: String): String = {
243+
throw new ProverInteractionFailed(uniqueId, "Dynamically setting prover options via Z3 API is currently not supported.")
244+
}
245+
242246
def assume(term: Term): Unit = {
243247
try {
244248
if (preamblePhaseOver)

src/main/scala/interfaces/decider/Prover.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ trait ProverLike {
2222
def emit(content: String): Unit
2323
def emit(contents: Iterable[String]): Unit = { contents foreach emit }
2424
def emitSettings(contents: Iterable[String]): Unit
25+
def setOption(name: String, value: String): String
2526
def assume(term: Term): Unit
2627
def declare(decl: Decl): Unit
2728
def comment(content: String): Unit

src/main/scala/rules/Brancher.scala

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,10 @@ object brancher extends BranchingRules {
8585
val uidBranchPoint = v.symbExLog.insertBranchPoint(2, Some(condition), conditionExp)
8686
var functionsOfCurrentDecider: Set[FunctionDecl] = null
8787
var macrosOfCurrentDecider: Vector[MacroDecl] = null
88+
var proverArgsOfCurrentDecider: viper.silicon.Map[String, String] = null
8889
var wasElseExecutedOnDifferentVerifier = false
8990
var functionsOfElseBranchDecider: Set[FunctionDecl] = null
91+
var proverArgsOfElseBranchDecider: viper.silicon.Map[String, String] = null
9092
var macrosOfElseBranchDecider: Seq[MacroDecl] = null
9193
var pcsForElseBranch: PathConditionStack = null
9294
var noOfErrors = 0
@@ -104,6 +106,7 @@ object brancher extends BranchingRules {
104106
if (parallelizeElseBranch){
105107
functionsOfCurrentDecider = v.decider.freshFunctions
106108
macrosOfCurrentDecider = v.decider.freshMacros
109+
proverArgsOfCurrentDecider = v.decider.getProverOptions()
107110
pcsForElseBranch = v.decider.pcs.duplicate()
108111
noOfErrors = v.errorsReportedSoFar.get()
109112
}
@@ -122,6 +125,9 @@ object brancher extends BranchingRules {
122125
val newMacros = macrosOfCurrentDecider.diff(v0.decider.freshMacros)
123126

124127
v0.decider.prover.comment(s"[Shifting execution from ${v.uniqueId} to ${v0.uniqueId}]")
128+
proverArgsOfElseBranchDecider = v0.decider.getProverOptions()
129+
v0.decider.resetProverOptions()
130+
v0.decider.setProverOptions(proverArgsOfCurrentDecider)
125131
v0.decider.prover.comment(s"Bulk-declaring functions")
126132
v0.decider.declareAndRecordAsFreshFunctions(newFunctions, false)
127133
v0.decider.prover.comment(s"Bulk-declaring macros")
@@ -141,10 +147,14 @@ object brancher extends BranchingRules {
141147
v1.decider.prover.saturate(Verifier.config.proverSaturationTimeouts.afterContract)
142148

143149
val result = fElse(v1.stateConsolidator.consolidateIfRetrying(s1, v1), v1)
144-
if (wasElseExecutedOnDifferentVerifier && s.underJoin) {
145-
val newSymbols = v1.decider.popSymbolStack()
146-
functionsOfElseBranchDecider = newSymbols._1
147-
macrosOfElseBranchDecider = newSymbols._2
150+
if (wasElseExecutedOnDifferentVerifier) {
151+
v1.decider.resetProverOptions()
152+
v1.decider.setProverOptions(proverArgsOfElseBranchDecider)
153+
if (s.underJoin) {
154+
val newSymbols = v1.decider.popSymbolStack()
155+
functionsOfElseBranchDecider = newSymbols._1
156+
macrosOfElseBranchDecider = newSymbols._2
157+
}
148158
}
149159
result
150160
})
@@ -206,6 +216,8 @@ object brancher extends BranchingRules {
206216
v.decider.setPcs(pcsAfterThenBranch)
207217
v.errorsReportedSoFar.set(noOfErrorsAfterThenBranch)
208218
v.decider.prover.saturate(Verifier.config.proverSaturationTimeouts.afterContract)
219+
v.decider.resetProverOptions()
220+
v.decider.setProverOptions(proverArgsOfCurrentDecider)
209221
}
210222
}else{
211223
rs = elseBranchFuture.get()

src/main/scala/supporters/MethodSupporter.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import viper.silicon.state.{Heap, State, Store}
1818
import viper.silicon.state.State.OldHeaps
1919
import viper.silicon.verifier.{Verifier, VerifierComponent}
2020
import viper.silicon.utils.freshSnap
21+
import viper.silver.reporter.AnnotationWarning
22+
import viper.silicon.{Map, toMap}
2123

2224
/* TODO: Consider changing the DefaultMethodVerificationUnitProvider into a SymbolicExecutionRule */
2325

@@ -44,6 +46,24 @@ trait DefaultMethodVerificationUnitProvider extends VerifierComponent { v: Verif
4446
logger.debug("\n\n" + "-" * 10 + " METHOD " + method.name + "-" * 10 + "\n")
4547
decider.prover.comment("%s %s %s".format("-" * 10, method.name, "-" * 10))
4648

49+
val proverOptions: Map[String, String] = method.info.getUniqueInfo[ast.AnnotationInfo] match {
50+
case Some(ai) if ai.values.contains("proverArgs") =>
51+
toMap(ai.values("proverArgs").flatMap(o => {
52+
val index = o.indexOf("=")
53+
if (index == -1) {
54+
reporter report AnnotationWarning(s"Invalid proverArgs annotation ${o} on method ${method.name}. " +
55+
s"Required format for each option is optionName=value.")
56+
None
57+
} else {
58+
val (name, value) = (o.take(index), o.drop(index + 1))
59+
Some((name, value))
60+
}
61+
}))
62+
case _ =>
63+
Map.empty
64+
}
65+
v.decider.setProverOptions(proverOptions)
66+
4767
openSymbExLogger(method)
4868

4969
val pres = method.pres
@@ -94,6 +114,8 @@ trait DefaultMethodVerificationUnitProvider extends VerifierComponent { v: Verif
94114
consumes(s4, posts, postViolated, v4)((_, _, _) =>
95115
Success()))}) } )})})
96116

117+
v.decider.resetProverOptions()
118+
97119
symbExLog.closeMemberScope()
98120
Seq(result)
99121
}

src/main/scala/verifier/DefaultMainVerifier.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ class DefaultMainVerifier(config: Config,
150150
decider.prover.emitSettings(contents)
151151
_verificationPoolManager.pooledVerifiers.emitSettings(contents)
152152
}
153+
154+
override def setOption(name: String, value: String): String = {
155+
decider.prover.setOption(name, value)
156+
_verificationPoolManager.pooledVerifiers.setOption(name, value)
157+
}
153158
}
154159

155160
/* Program verification */

src/main/scala/verifier/VerificationPoolManager.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class VerificationPoolManager(mainVerifier: MainVerifier) extends StatefulCompon
3737

3838
override def emitSettings(contents: Iterable[String]): Unit =
3939
workerVerifiers foreach (_.decider.prover.emitSettings(contents))
40+
41+
override def setOption(name: String, value: String): String =
42+
(workerVerifiers map (_.decider.prover.setOption(name, value))).head
4043
}
4144

4245
/* Verifier pool management */

0 commit comments

Comments
 (0)