Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rasi generator #1221

Merged
merged 26 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
97fb61d
Made representation of multi-intervals deterministic
PBHTasche May 27, 2024
9621b90
Merge dev to rasi_generator
PBHTasche May 29, 2024
b8800af
Fixed missed merge
PBHTasche May 29, 2024
1fbe4e7
Updated RASI generator for new types in node.scala
PBHTasche May 29, 2024
b2de439
Created infrastructure for selecting new variables on the fly
PBHTasche May 30, 2024
cf10256
Improved handling of mutually dependent variable constraints
PBHTasche May 30, 2024
4d117a3
Variable selection works in very limited manner
PBHTasche May 30, 2024
104e27a
Enabled inferrence of min_advance as required variable
PBHTasche May 30, 2024
aee6772
Filter variables based on whether they locally split the state space
PBHTasche May 31, 2024
67ebc10
Fixed VeSUV output stage; fixed output for multiple files
PBHTasche Jun 5, 2024
e435b18
Added vesuv_entry to VeSUV output
PBHTasche Jun 5, 2024
e66bcb2
Started infrastructure for finding objects for each field
PBHTasche Jun 6, 2024
55b5407
Added textual output option for RASI
PBHTasche Jun 7, 2024
596f073
Fixed variable naming for RASI output
PBHTasche Jun 7, 2024
d1da31d
Replaced 'main' method by vesuv entry point; did some cleanup
PBHTasche Jun 10, 2024
299da95
Fixed treatment of min_advance; fixed error with changing process det…
PBHTasche Jun 10, 2024
4c823fb
Add option for splitting RASI
PBHTasche Jun 23, 2024
07cf0a0
Merge dev and refactor transSubnodes
PBHTasche Jun 23, 2024
c329300
Enabled printing multiple RASIs
PBHTasche Jun 23, 2024
eca0190
Modified scheduler event update mechanism
PBHTasche Jun 24, 2024
33e12d6
Remove printing of trivial scales for predicate applications
PBHTasche Jun 24, 2024
d7d8972
Add handling for member expression
PBHTasche Jun 25, 2024
a421155
Added --dev-unsafe-optimization option to sacrifice usability for per…
PBHTasche Jun 25, 2024
806a9f9
When splitting RASI, filter by what the process associated with a spl…
PBHTasche Jun 27, 2024
fb1b432
Fixed VeSUV transformation with unused methods in the SystemC code
PBHTasche Jul 9, 2024
6892187
Merge dev into rasi_generator
PBHTasche Jul 9, 2024
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package vct.col.ast.expr.apply

import vct.col.ast.InstancePredicateApply
import vct.col.ast.{InstancePredicateApply, WritePerm}
import vct.col.print.{Ctx, Doc, Group, Precedence, Text}
import vct.col.ast.ops.InstancePredicateApplyOps

Expand Down
2 changes: 1 addition & 1 deletion src/col/vct/col/ast/expr/apply/PredicateApplyImpl.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package vct.col.ast.expr.apply

import vct.col.ast.PredicateApply
import vct.col.ast.{PredicateApply, WritePerm}
import vct.col.print.{Ctx, Doc, DocUtil, Empty, Group, Precedence, Text}
import vct.col.ast.ops.PredicateApplyOps

Expand Down
4 changes: 3 additions & 1 deletion src/main/vct/main/modes/VeSUV.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ case object VeSUV extends LazyLogging {
val stages = Stages
.vesuvOfOptions(options, ConstantBlameProvider(collector))
stages.run(options.inputs) match {
case Left(_: UserError) => EXIT_CODE_ERROR
case Left(err: UserError) =>
logger.error(err.text)
EXIT_CODE_ERROR
case Left(err: SystemError) => throw err
case Right(()) =>
logger.info("Transformation complete")
Expand Down
1 change: 1 addition & 0 deletions src/main/vct/main/stages/Backend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ case object Backend {
options.siliconPrintQuantifierStats.isDefined,
reportOnNoProgress = options.devSiliconReportOnNoProgress,
traceBranchConditions = options.devSiliconTraceBranchConditions,
optimizeUnsafe = options.devUnsafeOptimization,
branchConditionReportInterval =
options.devSiliconBranchConditionReportInterval,
options = options.backendFlags,
Expand Down
98 changes: 87 additions & 11 deletions src/main/vct/main/stages/GenerateRASI.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
package vct.main.stages

import com.typesafe.scalalogging.LazyLogging
import hre.io.LiteralReadable
import hre.stages.Stage
import vct.col.ast.{InstanceField, InstanceMethod, InstancePredicate, Node}
import vct.col.ast.{
Declaration,
Deref,
Expr,
InstanceField,
InstanceMethod,
InstancePredicate,
Node,
Predicate,
Procedure,
Program,
Verification,
VerificationContext,
}
import vct.col.origin.{LabelContext, Origin, PreferredName}
import vct.col.print.Ctx
import vct.col.rewrite.Generation
import vct.options.Options
import vct.rewrite.rasi.{
Expand All @@ -12,16 +29,26 @@ import vct.rewrite.rasi.{
SizeVariable,
}

import java.nio.file.Path
import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Path}

case object GenerateRASI {
def ofOptions(options: Options): Stage[Node[_ <: Generation], Unit] = {
GenerateRASI(options.vesuvRasiVariables, options.vesuvOutput)
GenerateRASI(
options.vesuvRasiVariables,
options.vesuvRasiSplitVariables,
options.vesuvOutput,
test = options.vesuvRasiTest,
)
}
}

case class GenerateRASI(vars: Option[Seq[String]], out: Path)
extends Stage[Node[_ <: Generation], Unit] {
case class GenerateRASI(
vars: Option[Seq[String]],
split: Option[Seq[String]],
out: Path,
test: Boolean,
) extends Stage[Node[_ <: Generation], Unit] with LazyLogging {

override def friendlyName: String =
"Generate reachable abstract states invariant"
Expand All @@ -31,16 +58,65 @@ case class GenerateRASI(vars: Option[Seq[String]], out: Path)
override def run(in1: Node[_ <: Generation]): Unit = {
val in = in1.asInstanceOf[Node[Generation]]
val main_method =
in.collectFirst {
case m: InstanceMethod[_]
if m.o.getPreferredName.get.snake.equals("main") =>
m
}.get
in.collectFirst { case m: Procedure[_] if m.vesuv_entry => m }.get
val variables: Set[ConcreteVariable[Generation]] =
vars.getOrElse(Seq()).map(s => resolve_variable(in, s)).toSet
val split_on_variables: Option[Set[ConcreteVariable[Generation]]] = split
.map(seq => seq.map(s => resolve_variable(in, s)).toSet)
val parameter_invariant: InstancePredicate[Generation] =
get_parameter_invariant(in)
new RASIGenerator().test(main_method, variables, parameter_invariant, out)
if (test) {
new RASIGenerator().test(main_method, variables, parameter_invariant, out)
} else {
val rasis: Seq[(String, Expr[Generation])] = new RASIGenerator().execute(
main_method,
variables,
split_on_variables,
parameter_invariant,
in,
)
val predicates: Seq[Predicate[Generation]] = rasis
.map(t => rasi_predicate(t._1, t._2))
implicit val o: Origin = Origin(Seq(LabelContext("rasi-generation")))
val verification: Verification[Generation] = Verification(
Seq(VerificationContext(Program(predicates)(o))),
Seq(),
)

val name_map: Map[Declaration[_], String] = Map
.from(predicates.flatMap(p =>
p.collect {
case Deref(_, ref) =>
ref.decl -> ref.decl.o.getPreferredName.get.snake
case p: Predicate[_] => p -> p.o.getPreferredName.get.snake
}
))
print(verification, name_map)
}
}

private def rasi_predicate(
name: String,
rasi: Expr[Generation],
): Predicate[Generation] = {
implicit val o: Origin = Origin(Seq(LabelContext("rasi-generation")))
.withContent(PreferredName(Seq(name)))
new Predicate(Seq(), Some(rasi), threadLocal = false, inline = true)
}

private def print(
in: Verification[_ <: Generation],
name_map: Map[Declaration[_], String],
): Unit = {
val ctx = Ctx(syntax = Ctx.PVL, names = name_map)

val buf = new StringBuffer()
in.write(buf)(ctx)
val path = s"invariant.pvl"
val txt = LiteralReadable(path, buf.toString)

logger.info(s"Writing ${txt.fileName} to $out")
Files.write(out, txt.data.getBytes(StandardCharsets.UTF_8))
}

private def resolve_variable(
Expand Down
32 changes: 24 additions & 8 deletions src/main/vct/main/stages/Output.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ package vct.main.stages

import com.typesafe.scalalogging.LazyLogging
import hre.io.{LiteralReadable, Readable}
import hre.stages.{Stage, Stages}
import vct.col.ast.{Declaration, Node, Program, Verification}
import vct.col.origin.DiagnosticOrigin
import hre.stages.{FunctionStage, Stage, Stages}
import vct.col.ast.{
Declaration,
Node,
Program,
Verification,
VerificationContext,
}
import vct.col.origin.{DiagnosticOrigin, Origin}
import vct.col.print.{Ctx, Namer}
import vct.col.rewrite.{Generation, InitialGeneration}
import vct.options.Options
Expand All @@ -22,9 +28,19 @@ case object Output {
def vesuvOfOptions[G <: Generation](
options: Options
): Stages[ParseResult[G], Unit] = {
// FunctionStage((pr: ParseResult[_ <: Generation]) => Program(pr.decls)(DiagnosticOrigin)(DiagnosticOrigin))
// .thenRun(??? /* Output(options.vesuvOutput, Ctx.PVL) */)
???
implicit val o: Origin = DiagnosticOrigin
FunctionStage((pr: ParseResult[_ <: Generation]) =>
Verification(
Seq(VerificationContext(Program(pr.decls)(DiagnosticOrigin))),
Seq(),
)
).thenRun(Output(
Some(options.vesuvOutput),
Ctx.PVL,
Files.isDirectory(options.vesuvOutput),
)).thenRun(FunctionStage((_: Seq[LiteralReadable]) =>
()
)) // TODO: Not the prettiest, but I have no time for this. I blame Bob.
}

def veymontOfOptions(
Expand Down Expand Up @@ -63,9 +79,9 @@ case class Output(out: Option[Path], syntax: Ctx.Syntax, splitDecls: Boolean)

val txts: Seq[LiteralReadable] =
if (splitDecls) {
in.asInstanceOf[Program[_]].declarations.zipWithIndex.map {
in.tasks.map(t => t.program).flatMap(p => p.declarations).zipWithIndex.map {
case (decl, i) =>
val name = names.getOrElse(decl.asInstanceOf, s"unknown$i")
val name = names.getOrElse(decl.asInstanceOf[Declaration[Generation]], s"unknown$i")
val fileName = s"${name}.${extension(syntax)}"
val buf = new StringBuffer()
decl.write(buf)(ctx)
Expand Down
7 changes: 3 additions & 4 deletions src/main/vct/main/stages/PrintCFG.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package vct.main.stages

import hre.stages.Stage
import vct.col.ast.{InstanceMethod, Node}
import vct.col.ast.{Node, Procedure}
import vct.col.rewrite.Generation
import vct.options.Options
import vct.rewrite.cfg.CFGPrinter
Expand All @@ -21,11 +21,10 @@ case class PrintCFG(out: Path) extends Stage[Node[_ <: Generation], Unit] {
override def progressWeight: Int = 0

override def run(in1: Node[_ <: Generation]): Unit = {
// TODO: Is there a better way to find a "main" method?
val main_method =
in1.collectFirst {
case m: InstanceMethod[_]
if m.o.getPreferredName.get.snake.equals("main") =>
case m: Procedure[_]
if m.vesuv_entry =>
m
}.get
CFGPrinter().print_ast_as_cfg(main_method, out)
Expand Down
18 changes: 13 additions & 5 deletions src/main/vct/main/stages/Transformation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ object Transformation extends LazyLogging {
bipResults = bipResults,
splitVerificationByProcedure =
options.devSplitVerificationByProcedure,
optimizeUnsafe = options.devUnsafeOptimization,
veymontGeneratePermissions = options.veymontGeneratePermissions,
)
}
Expand Down Expand Up @@ -189,10 +190,14 @@ object Transformation extends LazyLogging {
* Execute a handler before/after a pass is executed.
* @param passes
* The list of rewrite passes to execute.
* @param optimizeUnsafe
* Flag indicating to not do typechecking in-between passes to save
* performance
*/
class Transformation(
val onPassEvent: Seq[PassEventHandler],
val passes: Seq[RewriterBuilder],
val optimizeUnsafe: Boolean = false,
) extends Stage[Verification[_ <: Generation], Verification[_ <: Generation]]
with LazyLogging {
override def friendlyName: String = "Transformation"
Expand Down Expand Up @@ -236,11 +241,12 @@ class Transformation(
action(passes, Transformation.after, pass.key, result)
}

result.tasks.map(_.program)
.flatMap(program => program.check.map(program -> _)) match {
case Nil => // ok
case errors => throw TransformationCheckError(pass, errors)
}
if (!optimizeUnsafe)
result.tasks.map(_.program)
.flatMap(program => program.check.map(program -> _)) match {
case Nil => // ok
case errors => throw TransformationCheckError(pass, errors)
}

result = PrettifyBlocks().dispatch(result)
}
Expand Down Expand Up @@ -293,6 +299,7 @@ case class SilverTransformation(
bipResults: BIP.VerificationResults,
checkSat: Boolean = true,
splitVerificationByProcedure: Boolean = false,
override val optimizeUnsafe: Boolean = false,
veymontGeneratePermissions: Boolean = false,
) extends Transformation(
onPassEvent,
Expand Down Expand Up @@ -433,6 +440,7 @@ case class SilverTransformation(
PinSilverNodes,
Explode.withArg(splitVerificationByProcedure),
),
optimizeUnsafe = optimizeUnsafe,
)

case class VeyMontImplementationGeneration(
Expand Down
17 changes: 16 additions & 1 deletion src/main/vct/options/Options.scala
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ case object Options {
"Indicate, in seconds, the timeout value for the backend verification. If the verification gets stuck " +
"for longer than this timeout, the verification will timeout."
),
opt[Unit]("dev-unsafe-optimization").maybeHidden()
.action((_, c) => c.copy(devUnsafeOptimization = true))
.text("Optimizes runtime at the cost of progress logging and readability of error messages"),
opt[Path]("dev-silicon-z3-log-file").maybeHidden()
.action((p, c) => c.copy(devSiliconZ3LogFile = Some(p)))
.text("Path for z3 to write smt2 log file to"),
Expand Down Expand Up @@ -326,11 +329,20 @@ case object Options {
.action((_, c) => c.copy(vesuvGenerateRasi = true)).text(
"Instead of transforming a SystemC design to PVL, generate a global invariant for a PVL program"
).children(
opt[Unit]("rasi-graph-output")
.action((_, c) => c.copy(vesuvRasiTest = true)).text(
"Output RASI graph to test the algorithm rather than outputting the invariant"
),
opt[Seq[String]]("rasi-vars").valueName("<var1>,...")
.action((vars, c) => c.copy(vesuvRasiVariables = Some(vars)))
.text(
"[WIP] Preliminary selection mechanism for RASI variables; might be replaced later"
)
),
opt[Seq[String]]("split-rasi").valueName("<var1>,...")
.action((vars, c) => c.copy(vesuvRasiSplitVariables = Some(vars)))
.text(
"[WIP] Preliminary selection mechanism for localizing the RASI based on certain variables; might be changed later"
),
),
),
note(""),
Expand Down Expand Up @@ -433,6 +445,7 @@ case class Options(
devSiliconTraceBranchConditions: Boolean = false,
devCarbonBoogieLogFile: Option[Path] = None,
devViperProverLogFile: Option[Path] = None,
devUnsafeOptimization: Boolean = false,

// VeyMont options
veymontOutput: Option[Path] = None,
Expand All @@ -444,7 +457,9 @@ case class Options(
// VeSUV options
vesuvOutput: Path = null,
vesuvGenerateRasi: Boolean = false,
vesuvRasiTest: Boolean = false,
vesuvRasiVariables: Option[Seq[String]] = None,
vesuvRasiSplitVariables: Option[Seq[String]] = None,

// Control flow graph options
cfgOutput: Path = null,
Expand Down
Loading
Loading