summaryrefslogtreecommitdiff
path: root/Source/VCGeneration
diff options
context:
space:
mode:
authorGravatar Rustan Leino <leino@microsoft.com>2015-08-28 13:40:37 -0700
committerGravatar Rustan Leino <leino@microsoft.com>2015-08-28 13:40:37 -0700
commit35332e25e899424ee1714eea8d451c79563154aa (patch)
tree55cebc386a00a906c4feb130e6236f5dca6f98e8 /Source/VCGeneration
parent21f1cfff139759d9b9f91ed800da2158daca8ed4 (diff)
parent713e870a0dd2241869685e95bf31702a4f74cfff (diff)
Merge branch 'master' of https://github.com/boogie-org/boogie
Conflicts: Source/Core/CommandLineOptions.cs Source/ExecutionEngine/ExecutionEngine.cs Source/ExecutionEngine/VerificationResultCache.cs Source/VCGeneration/VC.cs Test/snapshots/runtest.snapshot Test/snapshots/runtest.snapshot.expect
Diffstat (limited to 'Source/VCGeneration')
-rw-r--r--Source/VCGeneration/Check.cs1377
-rw-r--r--Source/VCGeneration/ConditionGeneration.cs4018
-rw-r--r--Source/VCGeneration/Context.cs512
-rw-r--r--Source/VCGeneration/ExprExtensions.cs706
-rw-r--r--Source/VCGeneration/FixedpointVC.cs4480
-rw-r--r--Source/VCGeneration/OrderingAxioms.cs676
-rw-r--r--Source/VCGeneration/RPFP.cs1218
-rw-r--r--Source/VCGeneration/StratifiedVC.cs5809
-rw-r--r--Source/VCGeneration/VC.cs7870
-rw-r--r--Source/VCGeneration/VCGeneration.csproj446
-rw-r--r--Source/VCGeneration/Wlp.cs510
-rw-r--r--Source/VCGeneration/cce.cs210
12 files changed, 13923 insertions, 13909 deletions
diff --git a/Source/VCGeneration/Check.cs b/Source/VCGeneration/Check.cs
index 33baf798..3c3b5cae 100644
--- a/Source/VCGeneration/Check.cs
+++ b/Source/VCGeneration/Check.cs
@@ -1,688 +1,689 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Linq;
-using System.Collections;
-using System.Collections.Generic;
-using System.Threading;
-using System.IO;
-using System.Text.RegularExpressions;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie.AbstractInterpretation;
-using Microsoft.Boogie.VCExprAST;
-using Microsoft.Basetypes;
-using System.Threading.Tasks;
-
-namespace Microsoft.Boogie {
-
- enum CheckerStatus
- {
- Idle,
- Ready,
- Busy,
- Closed
- }
-
- /// <summary>
- /// Interface to the theorem prover specialized to Boogie.
- ///
- /// This class creates the appropriate background axioms. There
- /// should be one instance per BoogiePL program.
- /// </summary>
- public sealed class Checker {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(gen != null);
- Contract.Invariant(thmProver != null);
- }
-
- private readonly VCExpressionGenerator gen;
-
- private ProverInterface thmProver;
- private int timeout;
-
- // state for the async interface
- private volatile ProverInterface.Outcome outcome;
- private volatile bool hasOutput;
- private volatile UnexpectedProverOutputException outputExn;
- private DateTime proverStart;
- private TimeSpan proverRunTime;
- private volatile ProverInterface.ErrorHandler handler;
- private volatile CheckerStatus status;
- public volatile Program Program;
-
- public void GetReady()
- {
- Contract.Requires(IsIdle);
-
- status = CheckerStatus.Ready;
- }
-
- public void GoBackToIdle()
- {
- Contract.Requires(IsBusy);
-
- status = CheckerStatus.Idle;
- }
-
- public Task ProverTask { get; set; }
-
- public bool WillingToHandle(int timeout, Program prog) {
- return status == CheckerStatus.Idle && timeout == this.timeout && (prog == null || Program == prog);
- }
-
- public VCExpressionGenerator VCExprGen {
- get {
- Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
- return this.gen;
- }
- }
- public ProverInterface TheoremProver {
- get {
- Contract.Ensures(Contract.Result<ProverInterface>() != null);
- return this.thmProver;
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////////
- // We share context information for the same program between different Checkers
-
- private struct ContextCacheKey {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(program != null);
- }
-
- public readonly Program program;
-
- public ContextCacheKey(Program prog) {
- Contract.Requires(prog != null);
- this.program = prog;
- }
-
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public override bool Equals(object that) {
- if (that is ContextCacheKey) {
- ContextCacheKey thatKey = (ContextCacheKey)that;
- return this.program.Equals(thatKey.program);
- }
- return false;
- }
-
- [Pure]
- public override int GetHashCode() {
- return this.program.GetHashCode();
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////////
-
- /// <summary>
- /// Constructor. Initialize a checker with the program and log file.
- /// Optionally, use prover context provided by parameter "ctx".
- /// </summary>
- public Checker(VC.ConditionGeneration vcgen, Program prog, string/*?*/ logFilePath, bool appendLogFile, int timeout, ProverContext ctx = null) {
- Contract.Requires(vcgen != null);
- Contract.Requires(prog != null);
- this.timeout = timeout;
- this.Program = prog;
-
- ProverOptions options = cce.NonNull(CommandLineOptions.Clo.TheProverFactory).BlankProverOptions();
-
- if (logFilePath != null) {
- options.LogFilename = logFilePath;
- if (appendLogFile)
- options.AppendLogFile = appendLogFile;
- }
-
- if (timeout > 0) {
- options.TimeLimit = timeout * 1000;
- }
-
- options.Parse(CommandLineOptions.Clo.ProverOptions);
-
- ContextCacheKey key = new ContextCacheKey(prog);
- ProverInterface prover;
-
- if (vcgen.CheckerCommonState == null) {
- vcgen.CheckerCommonState = new Dictionary<ContextCacheKey, ProverContext>();
- }
- IDictionary<ContextCacheKey, ProverContext>/*!>!*/ cachedContexts = (IDictionary<ContextCacheKey, ProverContext/*!*/>)vcgen.CheckerCommonState;
-
- if (ctx == null && cachedContexts.TryGetValue(key, out ctx))
- {
- ctx = (ProverContext)cce.NonNull(ctx).Clone();
- prover = (ProverInterface)
- CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx);
- } else {
- if (ctx == null) ctx = (ProverContext)CommandLineOptions.Clo.TheProverFactory.NewProverContext(options);
-
- Setup(prog, ctx);
-
- // we first generate the prover and then store a clone of the
- // context in the cache, so that the prover can setup stuff in
- // the context to be cached
- prover = (ProverInterface)
- CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx);
- cachedContexts.Add(key, cce.NonNull((ProverContext)ctx.Clone()));
- }
-
- this.thmProver = prover;
- this.gen = prover.VCExprGen;
- }
-
- public void Retarget(Program prog, ProverContext ctx, int timeout = 0)
- {
- lock (this)
- {
- hasOutput = default(bool);
- outcome = default(ProverInterface.Outcome);
- outputExn = default(UnexpectedProverOutputException);
- handler = default(ProverInterface.ErrorHandler);
- TheoremProver.FullReset(gen);
- ctx.Reset();
- Setup(prog, ctx);
- this.timeout = timeout;
- SetTimeout();
- }
- }
-
- public void RetargetWithoutReset(Program prog, ProverContext ctx)
- {
- ctx.Clear();
- Setup(prog, ctx);
- }
-
-
- public void SetTimeout()
- {
- if (0 < timeout)
- {
- TheoremProver.SetTimeOut(timeout * 1000);
- }
- else
- {
- TheoremProver.SetTimeOut(0);
- }
- }
-
- /// <summary>
- /// Set up the context.
- /// </summary>
- private void Setup(Program prog, ProverContext ctx)
- {
- Program = prog;
- // TODO(wuestholz): Is this lock necessary?
- lock (Program.TopLevelDeclarations)
- {
- foreach (Declaration decl in Program.TopLevelDeclarations)
- {
- Contract.Assert(decl != null);
- var typeDecl = decl as TypeCtorDecl;
- var constDecl = decl as Constant;
- var funDecl = decl as Function;
- var axiomDecl = decl as Axiom;
- var glVarDecl = decl as GlobalVariable;
- if (typeDecl != null)
- {
- ctx.DeclareType(typeDecl, null);
- }
- else if (constDecl != null)
- {
- ctx.DeclareConstant(constDecl, constDecl.Unique, null);
- }
- else if (funDecl != null)
- {
- ctx.DeclareFunction(funDecl, null);
- }
- else if (axiomDecl != null)
- {
- ctx.AddAxiom(axiomDecl, null);
- }
- else if (glVarDecl != null)
- {
- ctx.DeclareGlobalVariable(glVarDecl, null);
- }
- }
- }
- }
-
- /// <summary>
- /// Clean-up.
- /// </summary>
- public void Close() {
- thmProver.Close();
- status = CheckerStatus.Closed;
- }
-
- /// <summary>
- /// Push a Verification Condition as an Axiom
- /// (Required for Doomed Program Point detection)
- /// </summary>
- public void PushVCExpr(VCExpr vc) {
- Contract.Requires(vc != null);
- //thmProver.Context.AddAxiom(vc);
- thmProver.PushVCExpression(vc);
- }
-
- public bool IsBusy {
- get {
- return status == CheckerStatus.Busy;
- }
- }
-
- public bool IsReady
- {
- get
- {
- return status == CheckerStatus.Ready;
- }
- }
-
- public bool IsClosed {
- get {
- return status == CheckerStatus.Closed;
- }
- }
-
- public bool IsIdle
- {
- get
- {
- return status == CheckerStatus.Idle;
- }
- }
-
- public bool HasOutput {
- get {
- return hasOutput;
- }
- }
-
- public TimeSpan ProverRunTime {
- get {
- return proverRunTime;
- }
- }
-
- private void WaitForOutput(object dummy) {
- lock (this)
- {
- try
- {
- outcome = thmProver.CheckOutcome(cce.NonNull(handler));
- }
- catch (UnexpectedProverOutputException e)
- {
- outputExn = e;
- }
-
- switch (outcome)
- {
- case ProverInterface.Outcome.Valid:
- thmProver.LogComment("Valid");
- break;
- case ProverInterface.Outcome.Invalid:
- thmProver.LogComment("Invalid");
- break;
- case ProverInterface.Outcome.TimeOut:
- thmProver.LogComment("Timed out");
- break;
- case ProverInterface.Outcome.OutOfMemory:
- thmProver.LogComment("Out of memory");
- break;
- case ProverInterface.Outcome.Undetermined:
- thmProver.LogComment("Undetermined");
- break;
- }
-
- hasOutput = true;
- proverRunTime = DateTime.UtcNow - proverStart;
- }
- }
-
- public void BeginCheck(string descriptiveName, VCExpr vc, ProverInterface.ErrorHandler handler) {
- Contract.Requires(descriptiveName != null);
- Contract.Requires(vc != null);
- Contract.Requires(handler != null);
- Contract.Requires(IsReady);
-
- status = CheckerStatus.Busy;
- hasOutput = false;
- outputExn = null;
- this.handler = handler;
-
- thmProver.Reset(gen);
- SetTimeout();
- proverStart = DateTime.UtcNow;
- thmProver.BeginCheck(descriptiveName, vc, handler);
- // gen.ClearSharedFormulas(); PR: don't know yet what to do with this guy
-
- ProverTask = Task.Factory.StartNew(() => { WaitForOutput(null); }, TaskCreationOptions.LongRunning);
- }
-
- public ProverInterface.Outcome ReadOutcome() {
- Contract.Requires(IsBusy);
- Contract.Requires(HasOutput);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- hasOutput = false;
-
- if (outputExn != null) {
- throw outputExn;
- }
-
- return outcome;
- }
- }
-
- // -----------------------------------------------------------------------------------------------
- // -----------------------------------------------------------------------------------------------
- // -----------------------------------------------------------------------------------------------
-
- public abstract class ProverInterface {
- public static ProverInterface CreateProver(Program prog, string/*?*/ logFilePath, bool appendLogFile, int timeout, int taskID = -1) {
- Contract.Requires(prog != null);
-
- ProverOptions options = cce.NonNull(CommandLineOptions.Clo.TheProverFactory).BlankProverOptions();
-
- if (logFilePath != null) {
- options.LogFilename = logFilePath;
- if (appendLogFile)
- options.AppendLogFile = appendLogFile;
- }
-
- if (timeout > 0) {
- options.TimeLimit = timeout * 1000;
- }
-
- if (taskID >= 0) {
- options.Parse(CommandLineOptions.Clo.Cho[taskID].ProverOptions);
- } else {
- options.Parse(CommandLineOptions.Clo.ProverOptions);
- }
-
- ProverContext ctx = (ProverContext)CommandLineOptions.Clo.TheProverFactory.NewProverContext(options);
-
- // set up the context
- foreach (Declaration decl in prog.TopLevelDeclarations) {
- Contract.Assert(decl != null);
- TypeCtorDecl t = decl as TypeCtorDecl;
- if (t != null) {
- ctx.DeclareType(t, null);
- }
- }
- foreach (Declaration decl in prog.TopLevelDeclarations) {
- Contract.Assert(decl != null);
- Constant c = decl as Constant;
- if (c != null) {
- ctx.DeclareConstant(c, c.Unique, null);
- }
- else {
- Function f = decl as Function;
- if (f != null) {
- ctx.DeclareFunction(f, null);
- }
- }
- }
- foreach (var ax in prog.Axioms) {
- ctx.AddAxiom(ax, null);
- }
- foreach (Declaration decl in prog.TopLevelDeclarations) {
- Contract.Assert(decl != null);
- GlobalVariable v = decl as GlobalVariable;
- if (v != null) {
- ctx.DeclareGlobalVariable(v, null);
- }
- }
-
- return (ProverInterface)CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx);
- }
-
- public enum Outcome {
- Valid,
- Invalid,
- TimeOut,
- OutOfMemory,
- Undetermined
- }
- public class ErrorHandler {
- // Used in CheckOutcomeCore
- public virtual int StartingProcId()
- {
- return 0;
- }
-
- public virtual void OnModel(IList<string> labels, Model model, Outcome proverOutcome) {
- Contract.Requires(cce.NonNullElements(labels));
- }
-
- public virtual void OnResourceExceeded(string message, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null) {
- Contract.Requires(message != null);
- }
-
- public virtual void OnProverWarning(string message)
- {
- Contract.Requires(message != null);
- switch (CommandLineOptions.Clo.PrintProverWarnings) {
- case CommandLineOptions.ProverWarnings.None:
- break;
- case CommandLineOptions.ProverWarnings.Stdout:
- Console.WriteLine("Prover warning: " + message);
- break;
- case CommandLineOptions.ProverWarnings.Stderr:
- Console.Error.WriteLine("Prover warning: " + message);
- break;
- default:
- Contract.Assume(false);
- throw new cce.UnreachableException(); // unexpected case
- }
- }
-
- public virtual Absy Label2Absy(string label) {
- Contract.Requires(label != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- throw new System.NotImplementedException();
- }
- }
- public abstract void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler);
-
- public virtual Outcome CheckRPFP(string descriptiveName, RPFP vc, ErrorHandler handler,
- out RPFP.Node cex,
- Dictionary<int, Dictionary<string, string>> varSubst, Dictionary<string,int> extra_bound = null)
- {
- throw new System.NotImplementedException();
- }
- [NoDefaultContract]
- public abstract Outcome CheckOutcome(ErrorHandler handler, int taskID = -1);
- public virtual string[] CalculatePath(int controlFlowConstant) {
- throw new System.NotImplementedException();
- }
- public virtual void LogComment(string comment) {
- Contract.Requires(comment != null);
- }
- public virtual void Close() {
- }
-
- public abstract void Reset(VCExpressionGenerator gen);
-
- public abstract void FullReset(VCExpressionGenerator gen);
-
- /// <summary>
- /// MSchaef: Allows to Push a VCExpression as Axiom on the prover stack (beta)
- /// for now it is only implemented by ProcessTheoremProver and still requires some
- /// testing
- /// </summary>
- public virtual void PushVCExpression(VCExpr vc) {
- Contract.Requires(vc != null);
- throw new NotImplementedException();
- }
- public virtual string VCExpressionToString(VCExpr vc) {
- Contract.Requires(vc != null);
- Contract.Ensures(Contract.Result<string>() != null);
- throw new NotImplementedException();
- }
- public virtual void Pop() {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- throw new NotImplementedException();
- }
- public virtual int NumAxiomsPushed() {
- throw new NotImplementedException();
- }
- public virtual int FlushAxiomsToTheoremProver() {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- throw new NotImplementedException();
- }
-
- // (assert vc)
- public virtual void Assert(VCExpr vc, bool polarity)
- {
- throw new NotImplementedException();
- }
-
- // (assert implicit-axioms)
- public virtual void AssertAxioms()
- {
- throw new NotImplementedException();
- }
-
- // (check-sat)
- public virtual void Check()
- {
- throw new NotImplementedException();
- }
-
- // (check-sat + get-unsat-core + checkOutcome)
- public virtual Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore, ErrorHandler handler)
- {
- throw new NotImplementedException();
- }
-
- public virtual Outcome CheckAssumptions(List<VCExpr> hardAssumptions, List<VCExpr> softAssumptions, out List<int> unsatisfiedSoftAssumptions, ErrorHandler handler) {
- throw new NotImplementedException();
- }
-
- public virtual Outcome CheckOutcomeCore(ErrorHandler handler, int taskID = -1)
- {
- throw new NotImplementedException();
- }
-
- // (push 1)
- public virtual void Push()
- {
- throw new NotImplementedException();
- }
-
- // Set theorem prover timeout for the next "check-sat"
- public virtual void SetTimeOut(int ms)
- { }
-
- public abstract ProverContext Context {
- get;
- }
-
- public abstract VCExpressionGenerator VCExprGen {
- get;
- }
-
- public virtual void DefineMacro(Macro fun, VCExpr vc) {
- throw new NotImplementedException();
- }
-
- public class VCExprEvaluationException : Exception
- {
-
- }
-
- public virtual object Evaluate(VCExpr expr)
- {
- throw new NotImplementedException();
- }
-
- //////////////////////
- // For interpolation queries
- //////////////////////
-
- // Assert vc tagged with a name
- public virtual void AssertNamed(VCExpr vc, bool polarity, string name)
- {
- throw new NotImplementedException();
- }
-
- // Returns Interpolant(A,B)
- public virtual VCExpr ComputeInterpolant(VCExpr A, VCExpr B)
- {
- throw new NotImplementedException();
- }
-
- // Returns for each l, Interpolant(root + (leaves - l), l)
- // Preconditions:
- // leaves cannot have subformulas with same variable names
- // Both root and leaves should have been previously named via AssertNamed
- public virtual List<VCExpr> GetTreeInterpolant(List<string> root, List<string> leaves)
- {
- throw new NotImplementedException();
- }
-
- }
-
- public class ProverInterfaceContracts : ProverInterface {
- public override ProverContext Context {
- get {
- Contract.Ensures(Contract.Result<ProverContext>() != null);
-
- throw new NotImplementedException();
- }
- }
- public override VCExpressionGenerator VCExprGen {
- get {
- Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
-
- throw new NotImplementedException();
- }
- }
- public override void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler) {/*Contract.Requires(descriptiveName != null);*/
- //Contract.Requires(vc != null);
- //Contract.Requires(handler != null);
- throw new NotImplementedException();
- }
- [NoDefaultContract]
- public override Outcome CheckOutcome(ErrorHandler handler, int taskID = -1) {
- //Contract.Requires(handler != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- throw new NotImplementedException();
- }
-
- public override void Reset(VCExpressionGenerator gen)
- {
- throw new NotImplementedException();
- }
-
- public override void FullReset(VCExpressionGenerator gen)
- {
- throw new NotImplementedException();
- }
- }
-
- public class ProverException : Exception {
- public ProverException(string s)
- : base(s) {
- }
- }
- public class UnexpectedProverOutputException : ProverException {
- public UnexpectedProverOutputException(string s)
- : base(s) {
- }
- }
- public class ProverDiedException : UnexpectedProverOutputException {
- public ProverDiedException()
- : base("Prover died with no further output, perhaps it ran out of memory or was killed.") {
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Linq;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using Microsoft.Boogie.AbstractInterpretation;
+using Microsoft.Boogie.VCExprAST;
+using Microsoft.Basetypes;
+using System.Threading.Tasks;
+
+namespace Microsoft.Boogie {
+
+ enum CheckerStatus
+ {
+ Idle,
+ Ready,
+ Busy,
+ Closed
+ }
+
+ /// <summary>
+ /// Interface to the theorem prover specialized to Boogie.
+ ///
+ /// This class creates the appropriate background axioms. There
+ /// should be one instance per BoogiePL program.
+ /// </summary>
+ public sealed class Checker {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(gen != null);
+ Contract.Invariant(thmProver != null);
+ }
+
+ private readonly VCExpressionGenerator gen;
+
+ private ProverInterface thmProver;
+ private int timeout;
+
+ // state for the async interface
+ private volatile ProverInterface.Outcome outcome;
+ private volatile bool hasOutput;
+ private volatile UnexpectedProverOutputException outputExn;
+ private DateTime proverStart;
+ private TimeSpan proverRunTime;
+ private volatile ProverInterface.ErrorHandler handler;
+ private volatile CheckerStatus status;
+ public volatile Program Program;
+
+ public void GetReady()
+ {
+ Contract.Requires(IsIdle);
+
+ status = CheckerStatus.Ready;
+ }
+
+ public void GoBackToIdle()
+ {
+ Contract.Requires(IsBusy);
+
+ status = CheckerStatus.Idle;
+ }
+
+ public Task ProverTask { get; set; }
+
+ public bool WillingToHandle(int timeout, Program prog) {
+ return status == CheckerStatus.Idle && timeout == this.timeout && (prog == null || Program == prog);
+ }
+
+ public VCExpressionGenerator VCExprGen {
+ get {
+ Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
+ return this.gen;
+ }
+ }
+ public ProverInterface TheoremProver {
+ get {
+ Contract.Ensures(Contract.Result<ProverInterface>() != null);
+ return this.thmProver;
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////
+ // We share context information for the same program between different Checkers
+
+ private struct ContextCacheKey {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(program != null);
+ }
+
+ public readonly Program program;
+
+ public ContextCacheKey(Program prog) {
+ Contract.Requires(prog != null);
+ this.program = prog;
+ }
+
+ [Pure]
+ [Reads(ReadsAttribute.Reads.Nothing)]
+ public override bool Equals(object that) {
+ if (that is ContextCacheKey) {
+ ContextCacheKey thatKey = (ContextCacheKey)that;
+ return this.program.Equals(thatKey.program);
+ }
+ return false;
+ }
+
+ [Pure]
+ public override int GetHashCode() {
+ return this.program.GetHashCode();
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////
+
+ /// <summary>
+ /// Constructor. Initialize a checker with the program and log file.
+ /// Optionally, use prover context provided by parameter "ctx".
+ /// </summary>
+ public Checker(VC.ConditionGeneration vcgen, Program prog, string/*?*/ logFilePath, bool appendLogFile, int timeout, ProverContext ctx = null) {
+ Contract.Requires(vcgen != null);
+ Contract.Requires(prog != null);
+ this.timeout = timeout;
+ this.Program = prog;
+
+ ProverOptions options = cce.NonNull(CommandLineOptions.Clo.TheProverFactory).BlankProverOptions();
+
+ if (logFilePath != null) {
+ options.LogFilename = logFilePath;
+ if (appendLogFile)
+ options.AppendLogFile = appendLogFile;
+ }
+
+ if (timeout > 0) {
+ options.TimeLimit = timeout * 1000;
+ }
+
+ options.Parse(CommandLineOptions.Clo.ProverOptions);
+
+ ContextCacheKey key = new ContextCacheKey(prog);
+ ProverInterface prover;
+
+ if (vcgen.CheckerCommonState == null) {
+ vcgen.CheckerCommonState = new Dictionary<ContextCacheKey, ProverContext>();
+ }
+ IDictionary<ContextCacheKey, ProverContext>/*!>!*/ cachedContexts = (IDictionary<ContextCacheKey, ProverContext/*!*/>)vcgen.CheckerCommonState;
+
+ if (ctx == null && cachedContexts.TryGetValue(key, out ctx))
+ {
+ ctx = (ProverContext)cce.NonNull(ctx).Clone();
+ prover = (ProverInterface)
+ CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx);
+ } else {
+ if (ctx == null) ctx = (ProverContext)CommandLineOptions.Clo.TheProverFactory.NewProverContext(options);
+
+ Setup(prog, ctx);
+
+ // we first generate the prover and then store a clone of the
+ // context in the cache, so that the prover can setup stuff in
+ // the context to be cached
+ prover = (ProverInterface)
+ CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx);
+ cachedContexts.Add(key, cce.NonNull((ProverContext)ctx.Clone()));
+ }
+
+ this.thmProver = prover;
+ this.gen = prover.VCExprGen;
+ }
+
+ public void Retarget(Program prog, ProverContext ctx, int timeout = 0)
+ {
+ lock (this)
+ {
+ hasOutput = default(bool);
+ outcome = default(ProverInterface.Outcome);
+ outputExn = default(UnexpectedProverOutputException);
+ handler = default(ProverInterface.ErrorHandler);
+ TheoremProver.FullReset(gen);
+ ctx.Reset();
+ Setup(prog, ctx);
+ this.timeout = timeout;
+ SetTimeout();
+ }
+ }
+
+ public void RetargetWithoutReset(Program prog, ProverContext ctx)
+ {
+ ctx.Clear();
+ Setup(prog, ctx);
+ }
+
+
+ public void SetTimeout()
+ {
+ if (0 < timeout)
+ {
+ TheoremProver.SetTimeOut(timeout * 1000);
+ }
+ else
+ {
+ TheoremProver.SetTimeOut(0);
+ }
+ }
+
+ /// <summary>
+ /// Set up the context.
+ /// </summary>
+ private void Setup(Program prog, ProverContext ctx)
+ {
+ Program = prog;
+ // TODO(wuestholz): Is this lock necessary?
+ lock (Program.TopLevelDeclarations)
+ {
+ foreach (Declaration decl in Program.TopLevelDeclarations)
+ {
+ Contract.Assert(decl != null);
+ var typeDecl = decl as TypeCtorDecl;
+ var constDecl = decl as Constant;
+ var funDecl = decl as Function;
+ var axiomDecl = decl as Axiom;
+ var glVarDecl = decl as GlobalVariable;
+ if (typeDecl != null)
+ {
+ ctx.DeclareType(typeDecl, null);
+ }
+ else if (constDecl != null)
+ {
+ ctx.DeclareConstant(constDecl, constDecl.Unique, null);
+ }
+ else if (funDecl != null)
+ {
+ ctx.DeclareFunction(funDecl, null);
+ }
+ else if (axiomDecl != null)
+ {
+ ctx.AddAxiom(axiomDecl, null);
+ }
+ else if (glVarDecl != null)
+ {
+ ctx.DeclareGlobalVariable(glVarDecl, null);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Clean-up.
+ /// </summary>
+ public void Close() {
+ thmProver.Close();
+ status = CheckerStatus.Closed;
+ }
+
+ /// <summary>
+ /// Push a Verification Condition as an Axiom
+ /// (Required for Doomed Program Point detection)
+ /// </summary>
+ public void PushVCExpr(VCExpr vc) {
+ Contract.Requires(vc != null);
+ //thmProver.Context.AddAxiom(vc);
+ thmProver.PushVCExpression(vc);
+ }
+
+ public bool IsBusy {
+ get {
+ return status == CheckerStatus.Busy;
+ }
+ }
+
+ public bool IsReady
+ {
+ get
+ {
+ return status == CheckerStatus.Ready;
+ }
+ }
+
+ public bool IsClosed {
+ get {
+ return status == CheckerStatus.Closed;
+ }
+ }
+
+ public bool IsIdle
+ {
+ get
+ {
+ return status == CheckerStatus.Idle;
+ }
+ }
+
+ public bool HasOutput {
+ get {
+ return hasOutput;
+ }
+ }
+
+ public TimeSpan ProverRunTime {
+ get {
+ return proverRunTime;
+ }
+ }
+
+ private void WaitForOutput(object dummy) {
+ lock (this)
+ {
+ try
+ {
+ outcome = thmProver.CheckOutcome(cce.NonNull(handler));
+ }
+ catch (UnexpectedProverOutputException e)
+ {
+ outputExn = e;
+ }
+
+ switch (outcome)
+ {
+ case ProverInterface.Outcome.Valid:
+ thmProver.LogComment("Valid");
+ break;
+ case ProverInterface.Outcome.Invalid:
+ thmProver.LogComment("Invalid");
+ break;
+ case ProverInterface.Outcome.TimeOut:
+ thmProver.LogComment("Timed out");
+ break;
+ case ProverInterface.Outcome.OutOfMemory:
+ thmProver.LogComment("Out of memory");
+ break;
+ case ProverInterface.Outcome.Undetermined:
+ thmProver.LogComment("Undetermined");
+ break;
+ }
+
+ hasOutput = true;
+ proverRunTime = DateTime.UtcNow - proverStart;
+ }
+ }
+
+ public void BeginCheck(string descriptiveName, VCExpr vc, ProverInterface.ErrorHandler handler) {
+ Contract.Requires(descriptiveName != null);
+ Contract.Requires(vc != null);
+ Contract.Requires(handler != null);
+ Contract.Requires(IsReady);
+
+ status = CheckerStatus.Busy;
+ hasOutput = false;
+ outputExn = null;
+ this.handler = handler;
+
+ thmProver.Reset(gen);
+ SetTimeout();
+ proverStart = DateTime.UtcNow;
+ thmProver.BeginCheck(descriptiveName, vc, handler);
+ // gen.ClearSharedFormulas(); PR: don't know yet what to do with this guy
+
+ ProverTask = Task.Factory.StartNew(() => { WaitForOutput(null); }, TaskCreationOptions.LongRunning);
+ }
+
+ public ProverInterface.Outcome ReadOutcome() {
+ Contract.Requires(IsBusy);
+ Contract.Requires(HasOutput);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+
+ hasOutput = false;
+
+ if (outputExn != null) {
+ throw outputExn;
+ }
+
+ return outcome;
+ }
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // -----------------------------------------------------------------------------------------------
+ // -----------------------------------------------------------------------------------------------
+
+ public abstract class ProverInterface {
+ public static ProverInterface CreateProver(Program prog, string/*?*/ logFilePath, bool appendLogFile, int timeout, int taskID = -1) {
+ Contract.Requires(prog != null);
+
+ ProverOptions options = cce.NonNull(CommandLineOptions.Clo.TheProverFactory).BlankProverOptions();
+
+ if (logFilePath != null) {
+ options.LogFilename = logFilePath;
+ if (appendLogFile)
+ options.AppendLogFile = appendLogFile;
+ }
+
+ if (timeout > 0) {
+ options.TimeLimit = timeout * 1000;
+ }
+
+ if (taskID >= 0) {
+ options.Parse(CommandLineOptions.Clo.Cho[taskID].ProverOptions);
+ } else {
+ options.Parse(CommandLineOptions.Clo.ProverOptions);
+ }
+
+ ProverContext ctx = (ProverContext)CommandLineOptions.Clo.TheProverFactory.NewProverContext(options);
+
+ // set up the context
+ foreach (Declaration decl in prog.TopLevelDeclarations) {
+ Contract.Assert(decl != null);
+ TypeCtorDecl t = decl as TypeCtorDecl;
+ if (t != null) {
+ ctx.DeclareType(t, null);
+ }
+ }
+ foreach (Declaration decl in prog.TopLevelDeclarations) {
+ Contract.Assert(decl != null);
+ Constant c = decl as Constant;
+ if (c != null) {
+ ctx.DeclareConstant(c, c.Unique, null);
+ }
+ else {
+ Function f = decl as Function;
+ if (f != null) {
+ ctx.DeclareFunction(f, null);
+ }
+ }
+ }
+ foreach (var ax in prog.Axioms) {
+ ctx.AddAxiom(ax, null);
+ }
+ foreach (Declaration decl in prog.TopLevelDeclarations) {
+ Contract.Assert(decl != null);
+ GlobalVariable v = decl as GlobalVariable;
+ if (v != null) {
+ ctx.DeclareGlobalVariable(v, null);
+ }
+ }
+
+ return (ProverInterface)CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx);
+ }
+
+ public enum Outcome {
+ Valid,
+ Invalid,
+ TimeOut,
+ OutOfMemory,
+ Undetermined,
+ Bounded
+ }
+ public class ErrorHandler {
+ // Used in CheckOutcomeCore
+ public virtual int StartingProcId()
+ {
+ return 0;
+ }
+
+ public virtual void OnModel(IList<string> labels, Model model, Outcome proverOutcome) {
+ Contract.Requires(cce.NonNullElements(labels));
+ }
+
+ public virtual void OnResourceExceeded(string message, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null) {
+ Contract.Requires(message != null);
+ }
+
+ public virtual void OnProverWarning(string message)
+ {
+ Contract.Requires(message != null);
+ switch (CommandLineOptions.Clo.PrintProverWarnings) {
+ case CommandLineOptions.ProverWarnings.None:
+ break;
+ case CommandLineOptions.ProverWarnings.Stdout:
+ Console.WriteLine("Prover warning: " + message);
+ break;
+ case CommandLineOptions.ProverWarnings.Stderr:
+ Console.Error.WriteLine("Prover warning: " + message);
+ break;
+ default:
+ Contract.Assume(false);
+ throw new cce.UnreachableException(); // unexpected case
+ }
+ }
+
+ public virtual Absy Label2Absy(string label) {
+ Contract.Requires(label != null);
+ Contract.Ensures(Contract.Result<Absy>() != null);
+
+ throw new System.NotImplementedException();
+ }
+ }
+ public abstract void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler);
+
+ public virtual Outcome CheckRPFP(string descriptiveName, RPFP vc, ErrorHandler handler,
+ out RPFP.Node cex,
+ Dictionary<int, Dictionary<string, string>> varSubst, Dictionary<string,int> extra_bound = null)
+ {
+ throw new System.NotImplementedException();
+ }
+ [NoDefaultContract]
+ public abstract Outcome CheckOutcome(ErrorHandler handler, int taskID = -1);
+ public virtual string[] CalculatePath(int controlFlowConstant) {
+ throw new System.NotImplementedException();
+ }
+ public virtual void LogComment(string comment) {
+ Contract.Requires(comment != null);
+ }
+ public virtual void Close() {
+ }
+
+ public abstract void Reset(VCExpressionGenerator gen);
+
+ public abstract void FullReset(VCExpressionGenerator gen);
+
+ /// <summary>
+ /// MSchaef: Allows to Push a VCExpression as Axiom on the prover stack (beta)
+ /// for now it is only implemented by ProcessTheoremProver and still requires some
+ /// testing
+ /// </summary>
+ public virtual void PushVCExpression(VCExpr vc) {
+ Contract.Requires(vc != null);
+ throw new NotImplementedException();
+ }
+ public virtual string VCExpressionToString(VCExpr vc) {
+ Contract.Requires(vc != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+ throw new NotImplementedException();
+ }
+ public virtual void Pop() {
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ throw new NotImplementedException();
+ }
+ public virtual int NumAxiomsPushed() {
+ throw new NotImplementedException();
+ }
+ public virtual int FlushAxiomsToTheoremProver() {
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ throw new NotImplementedException();
+ }
+
+ // (assert vc)
+ public virtual void Assert(VCExpr vc, bool polarity)
+ {
+ throw new NotImplementedException();
+ }
+
+ // (assert implicit-axioms)
+ public virtual void AssertAxioms()
+ {
+ throw new NotImplementedException();
+ }
+
+ // (check-sat)
+ public virtual void Check()
+ {
+ throw new NotImplementedException();
+ }
+
+ // (check-sat + get-unsat-core + checkOutcome)
+ public virtual Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore, ErrorHandler handler)
+ {
+ throw new NotImplementedException();
+ }
+
+ public virtual Outcome CheckAssumptions(List<VCExpr> hardAssumptions, List<VCExpr> softAssumptions, out List<int> unsatisfiedSoftAssumptions, ErrorHandler handler) {
+ throw new NotImplementedException();
+ }
+
+ public virtual Outcome CheckOutcomeCore(ErrorHandler handler, int taskID = -1)
+ {
+ throw new NotImplementedException();
+ }
+
+ // (push 1)
+ public virtual void Push()
+ {
+ throw new NotImplementedException();
+ }
+
+ // Set theorem prover timeout for the next "check-sat"
+ public virtual void SetTimeOut(int ms)
+ { }
+
+ public abstract ProverContext Context {
+ get;
+ }
+
+ public abstract VCExpressionGenerator VCExprGen {
+ get;
+ }
+
+ public virtual void DefineMacro(Macro fun, VCExpr vc) {
+ throw new NotImplementedException();
+ }
+
+ public class VCExprEvaluationException : Exception
+ {
+
+ }
+
+ public virtual object Evaluate(VCExpr expr)
+ {
+ throw new NotImplementedException();
+ }
+
+ //////////////////////
+ // For interpolation queries
+ //////////////////////
+
+ // Assert vc tagged with a name
+ public virtual void AssertNamed(VCExpr vc, bool polarity, string name)
+ {
+ throw new NotImplementedException();
+ }
+
+ // Returns Interpolant(A,B)
+ public virtual VCExpr ComputeInterpolant(VCExpr A, VCExpr B)
+ {
+ throw new NotImplementedException();
+ }
+
+ // Returns for each l, Interpolant(root + (leaves - l), l)
+ // Preconditions:
+ // leaves cannot have subformulas with same variable names
+ // Both root and leaves should have been previously named via AssertNamed
+ public virtual List<VCExpr> GetTreeInterpolant(List<string> root, List<string> leaves)
+ {
+ throw new NotImplementedException();
+ }
+
+ }
+
+ public class ProverInterfaceContracts : ProverInterface {
+ public override ProverContext Context {
+ get {
+ Contract.Ensures(Contract.Result<ProverContext>() != null);
+
+ throw new NotImplementedException();
+ }
+ }
+ public override VCExpressionGenerator VCExprGen {
+ get {
+ Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
+
+ throw new NotImplementedException();
+ }
+ }
+ public override void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler) {/*Contract.Requires(descriptiveName != null);*/
+ //Contract.Requires(vc != null);
+ //Contract.Requires(handler != null);
+ throw new NotImplementedException();
+ }
+ [NoDefaultContract]
+ public override Outcome CheckOutcome(ErrorHandler handler, int taskID = -1) {
+ //Contract.Requires(handler != null);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ throw new NotImplementedException();
+ }
+
+ public override void Reset(VCExpressionGenerator gen)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void FullReset(VCExpressionGenerator gen)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public class ProverException : Exception {
+ public ProverException(string s)
+ : base(s) {
+ }
+ }
+ public class UnexpectedProverOutputException : ProverException {
+ public UnexpectedProverOutputException(string s)
+ : base(s) {
+ }
+ }
+ public class ProverDiedException : UnexpectedProverOutputException {
+ public ProverDiedException()
+ : base("Prover died with no further output, perhaps it ran out of memory or was killed.") {
+ }
+ }
+}
diff --git a/Source/VCGeneration/ConditionGeneration.cs b/Source/VCGeneration/ConditionGeneration.cs
index 8d6606b6..1f010757 100644
--- a/Source/VCGeneration/ConditionGeneration.cs
+++ b/Source/VCGeneration/ConditionGeneration.cs
@@ -1,2009 +1,2009 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Linq;
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Threading;
-using System.IO;
-using Microsoft.Boogie;
-using Microsoft.Boogie.GraphUtil;
-using System.Diagnostics.Contracts;
-using Microsoft.Basetypes;
-using Microsoft.Boogie.VCExprAST;
-using Set = Microsoft.Boogie.GSet<object>;
-
-namespace Microsoft.Boogie {
-
- public class CalleeCounterexampleInfo {
- public Counterexample counterexample;
- public List<object>/*!>!*/ args;
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(args));
- }
-
- public CalleeCounterexampleInfo(Counterexample cex, List<object/*!>!*/> x)
- {
- Contract.Requires(cce.NonNullElements(x));
- counterexample = cex;
- args = x;
- }
- }
-
- public class TraceLocation : IEquatable<TraceLocation>
- {
- public int numBlock;
- public int numInstr;
-
- public TraceLocation(int numBlock, int numInstr)
- {
- this.numBlock = numBlock;
- this.numInstr = numInstr;
- }
-
- public override bool Equals(object obj)
- {
- TraceLocation that = obj as TraceLocation;
- if (that == null) return false;
- return (numBlock == that.numBlock && numInstr == that.numInstr);
- }
-
- public bool Equals(TraceLocation that)
- {
- return (numBlock == that.numBlock && numInstr == that.numInstr);
- }
-
- public override int GetHashCode()
- {
- return numBlock.GetHashCode() ^ 131 * numInstr.GetHashCode();
- }
- }
-
- public abstract class Counterexample {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Trace != null);
- Contract.Invariant(Context != null);
- Contract.Invariant(cce.NonNullElements(relatedInformation));
- Contract.Invariant(cce.NonNullDictionaryAndValues(calleeCounterexamples));
- }
-
- [Peer]
- public List<Block> Trace;
- public Model Model;
- public VC.ModelViewInfo MvInfo;
- public ProverContext Context;
- [Peer]
- public List<string>/*!>!*/ relatedInformation;
- public string OriginalRequestId;
- public string RequestId;
- public abstract byte[] Checksum { get; }
- public byte[] SugaredCmdChecksum;
-
- public Dictionary<TraceLocation, CalleeCounterexampleInfo> calleeCounterexamples;
-
- internal Counterexample(List<Block> trace, Model model, VC.ModelViewInfo mvInfo, ProverContext context) {
- Contract.Requires(trace != null);
- Contract.Requires(context != null);
- this.Trace = trace;
- this.Model = model;
- this.MvInfo = mvInfo;
- this.Context = context;
- this.relatedInformation = new List<string>();
- this.calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
- }
-
- // Create a shallow copy of the counterexample
- public abstract Counterexample Clone();
-
- public void AddCalleeCounterexample(TraceLocation loc, CalleeCounterexampleInfo cex)
- {
- Contract.Requires(cex != null);
- calleeCounterexamples[loc] = cex;
- }
-
- public void AddCalleeCounterexample(int numBlock, int numInstr, CalleeCounterexampleInfo cex)
- {
- Contract.Requires(cex != null);
- calleeCounterexamples[new TraceLocation(numBlock, numInstr)] = cex;
- }
-
- public void AddCalleeCounterexample(Dictionary<TraceLocation, CalleeCounterexampleInfo> cs)
- {
- Contract.Requires(cce.NonNullDictionaryAndValues(cs));
- foreach (TraceLocation loc in cs.Keys)
- {
- AddCalleeCounterexample(loc, cs[loc]);
- }
- }
-
- // Looks up the Cmd at a given index into the trace
- public Cmd getTraceCmd(TraceLocation loc)
- {
- Debug.Assert(loc.numBlock < Trace.Count);
- Block b = Trace[loc.numBlock];
- Debug.Assert(loc.numInstr < b.Cmds.Count);
- return b.Cmds[loc.numInstr];
- }
-
- // Looks up the name of the called procedure.
- // Asserts that the name exists
- public string getCalledProcName(Cmd cmd)
- {
- // There are two options:
- // 1. cmd is a CallCmd
- // 2. cmd is an AssumeCmd (passified version of a CallCmd)
- if(cmd is CallCmd) {
- return (cmd as CallCmd).Proc.Name;
- }
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- Debug.Assert(assumeCmd != null);
-
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- Debug.Assert(naryExpr != null);
-
- return naryExpr.Fun.FunctionName;
- }
-
- public void Print(int indent, TextWriter tw, Action<Block> blockAction = null) {
- int numBlock = -1;
- string ind = new string(' ', indent);
- foreach (Block b in Trace) {
- Contract.Assert(b != null);
- numBlock++;
- if (b.tok == null) {
- tw.WriteLine("{0}<intermediate block>", ind);
- } else {
- // for ErrorTrace == 1 restrict the output;
- // do not print tokens with -17:-4 as their location because they have been
- // introduced in the translation and do not give any useful feedback to the user
- if (!(CommandLineOptions.Clo.ErrorTrace == 1 && b.tok.line == -17 && b.tok.col == -4)) {
- if (blockAction != null)
- {
- blockAction(b);
- }
-
- tw.WriteLine("{4}{0}({1},{2}): {3}", b.tok.filename, b.tok.line, b.tok.col, b.Label, ind);
-
- for (int numInstr = 0; numInstr < b.Cmds.Count; numInstr++)
- {
- var loc = new TraceLocation(numBlock, numInstr);
- if (calleeCounterexamples.ContainsKey(loc))
- {
- var cmd = getTraceCmd(loc);
- var calleeName = getCalledProcName(cmd);
- if (calleeName.StartsWith(VC.StratifiedVCGen.recordProcName) && CommandLineOptions.Clo.StratifiedInlining > 0)
- {
- Contract.Assert(calleeCounterexamples[loc].args.Count == 1);
- var arg = calleeCounterexamples[loc].args[0];
- tw.WriteLine("{0}value = {1}", ind, arg.ToString());
- }
- else
- {
- tw.WriteLine("{1}Inlined call to procedure {0} begins", calleeName, ind);
- calleeCounterexamples[loc].counterexample.Print(indent + 4, tw);
- tw.WriteLine("{1}Inlined call to procedure {0} ends", calleeName, ind);
- }
- }
- }
- }
- }
- }
- }
-
- public static bool firstModelFile = true;
-
- public bool ModelHasStatesAlready = false;
-
- public void PrintModel(TextWriter tw)
- {
- var filename = CommandLineOptions.Clo.ModelViewFile;
- if (Model == null || filename == null || CommandLineOptions.Clo.StratifiedInlining > 0) return;
-
- if (!ModelHasStatesAlready) {
- PopulateModelWithStates();
- ModelHasStatesAlready = true;
- }
-
- if (filename == "-") {
- Model.Write(tw);
- tw.Flush();
- } else {
- using (var wr = new StreamWriter(filename, !firstModelFile)) {
- firstModelFile = false;
- Model.Write(wr);
- }
- }
- }
-
- void ApplyRedirections(Model m) {
- var mapping = new Dictionary<Model.Element, Model.Element>();
- foreach (var name in new string[] { "U_2_bool", "U_2_int" }) {
- Model.Func f = m.TryGetFunc(name);
- if (f != null && f.Arity == 1) {
- foreach (var ft in f.Apps) mapping[ft.Args[0]] = ft.Result;
- }
- }
- m.Substitute(mapping);
- }
-
- public void PopulateModelWithStates()
- {
- Contract.Requires(Model != null);
-
- Model m = Model;
- ApplyRedirections(m);
-
- var mvstates = m.TryGetFunc("$mv_state");
- if (MvInfo == null || mvstates == null || (mvstates.Arity == 1 && mvstates.Apps.Count() == 0))
- return;
-
- Contract.Assert(mvstates.Arity == 2);
-
- foreach (Variable v in MvInfo.AllVariables) {
- m.InitialState.AddBinding(v.Name, GetModelValue(m, v));
- }
-
- var states = new List<int>();
- foreach (var t in mvstates.Apps)
- states.Add(t.Args[1].AsInt());
-
- states.Sort();
-
- for (int i = 0; i < states.Count; ++i) {
- var s = states[i];
- if (0 <= s && s < MvInfo.CapturePoints.Count) {
- VC.ModelViewInfo.Mapping map = MvInfo.CapturePoints[s];
- var prevInc = i > 0 ? MvInfo.CapturePoints[states[i - 1]].IncarnationMap : new Dictionary<Variable, Expr>();
- var cs = m.MkState(map.Description);
-
- foreach (Variable v in MvInfo.AllVariables) {
- Expr e = map.IncarnationMap.ContainsKey(v) ? map.IncarnationMap[v] : null;
- if (e == null) continue;
-
- Expr prevIncV = prevInc.ContainsKey(v) ? prevInc[v] : null;
- if (prevIncV == e) continue; // skip unchanged variables
-
- Model.Element elt;
-
- if (e is IdentifierExpr) {
- IdentifierExpr ide = (IdentifierExpr)e;
- elt = GetModelValue(m, ide.Decl);
- } else if (e is LiteralExpr) {
- LiteralExpr lit = (LiteralExpr)e;
- elt = m.MkElement(lit.Val.ToString());
- } else {
- elt = m.MkFunc(e.ToString(), 0).GetConstant();
- }
-
- cs.AddBinding(v.Name, elt);
- }
-
- } else {
- Contract.Assume(false);
- }
- }
- }
-
- private Model.Element GetModelValue(Model m, Variable v) {
- Model.Element elt;
- // first, get the unique name
- string uniqueName;
- VCExprVar vvar = Context.BoogieExprTranslator.TryLookupVariable(v);
- if (vvar == null) {
- uniqueName = v.Name;
- } else {
- uniqueName = Context.Lookup(vvar);
- }
-
- var f = m.TryGetFunc(uniqueName);
- if (f == null) {
- f = m.MkFunc(uniqueName, 0);
- }
- elt = f.GetConstant();
- return elt;
- }
-
- public abstract int GetLocation();
- }
-
- public class CounterexampleComparer : IComparer<Counterexample> {
-
- private int Compare(List<Block> bs1, List<Block> bs2)
- {
- if (bs1.Count < bs2.Count)
- {
- return -1;
- }
- else if (bs2.Count < bs1.Count)
- {
- return 1;
- }
-
- for (int i = 0; i < bs1.Count; i++)
- {
- var b1 = bs1[i];
- var b2 = bs2[i];
- if (b1.tok.pos < b2.tok.pos)
- {
- return -1;
- }
- else if (b2.tok.pos < b1.tok.pos)
- {
- return 1;
- }
- }
-
- return 0;
- }
-
- public int Compare(Counterexample c1, Counterexample c2)
- {
- //Contract.Requires(c1 != null);
- //Contract.Requires(c2 != null);
- if (c1.GetLocation() == c2.GetLocation())
- {
- var c = Compare(c1.Trace, c2.Trace);
- if (c != 0)
- {
- return c;
- }
- // TODO(wuestholz): Generalize this to compare all IPotentialErrorNodes of the counterexample.
- var a1 = c1 as AssertCounterexample;
- var a2 = c2 as AssertCounterexample;
- if (a1 != null && a2 != null)
- {
- var s1 = a1.FailingAssert.ErrorData as string;
- var s2 = a2.FailingAssert.ErrorData as string;
- if (s1 != null && s2 != null)
- {
- return s1.CompareTo(s2);
- }
- }
-
- return 0;
- }
- if (c1.GetLocation() > c2.GetLocation())
- {
- return 1;
- }
- return -1;
- }
- }
-
- public class AssertCounterexample : Counterexample {
- [Peer]
- public AssertCmd FailingAssert;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(FailingAssert != null);
- }
-
-
- public AssertCounterexample(List<Block> trace, AssertCmd failingAssert, Model model, VC.ModelViewInfo mvInfo, ProverContext context)
- : base(trace, model, mvInfo, context) {
- Contract.Requires(trace != null);
- Contract.Requires(failingAssert != null);
- Contract.Requires(context != null);
- this.FailingAssert = failingAssert;
- }
-
- public override int GetLocation() {
- return FailingAssert.tok.line * 1000 + FailingAssert.tok.col;
- }
-
- public override byte[] Checksum
- {
- get { return FailingAssert.Checksum; }
- }
-
- public override Counterexample Clone()
- {
- var ret = new AssertCounterexample(Trace, FailingAssert, Model, MvInfo, Context);
- ret.calleeCounterexamples = calleeCounterexamples;
- return ret;
- }
- }
-
- public class CallCounterexample : Counterexample {
- public CallCmd FailingCall;
- public Requires FailingRequires;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(FailingCall != null);
- Contract.Invariant(FailingRequires != null);
- }
-
-
- public CallCounterexample(List<Block> trace, CallCmd failingCall, Requires failingRequires, Model model, VC.ModelViewInfo mvInfo, ProverContext context, byte[] checksum = null)
- : base(trace, model, mvInfo, context) {
- Contract.Requires(!failingRequires.Free);
- Contract.Requires(trace != null);
- Contract.Requires(context != null);
- Contract.Requires(failingCall != null);
- Contract.Requires(failingRequires != null);
- this.FailingCall = failingCall;
- this.FailingRequires = failingRequires;
- this.checksum = checksum;
- this.SugaredCmdChecksum = failingCall.Checksum;
- }
-
- public override int GetLocation() {
- return FailingCall.tok.line * 1000 + FailingCall.tok.col;
- }
-
- byte[] checksum;
- public override byte[] Checksum
- {
- get { return checksum; }
- }
-
- public override Counterexample Clone()
- {
- var ret = new CallCounterexample(Trace, FailingCall, FailingRequires, Model, MvInfo, Context, Checksum);
- ret.calleeCounterexamples = calleeCounterexamples;
- return ret;
- }
- }
-
- public class ReturnCounterexample : Counterexample {
- public TransferCmd FailingReturn;
- public Ensures FailingEnsures;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(FailingEnsures != null);
- Contract.Invariant(FailingReturn != null);
- }
-
-
- public ReturnCounterexample(List<Block> trace, TransferCmd failingReturn, Ensures failingEnsures, Model model, VC.ModelViewInfo mvInfo, ProverContext context, byte[] checksum)
- : base(trace, model, mvInfo, context) {
- Contract.Requires(trace != null);
- Contract.Requires(context != null);
- Contract.Requires(failingReturn != null);
- Contract.Requires(failingEnsures != null);
- Contract.Requires(!failingEnsures.Free);
- this.FailingReturn = failingReturn;
- this.FailingEnsures = failingEnsures;
- this.checksum = checksum;
- }
-
- public override int GetLocation() {
- return FailingReturn.tok.line * 1000 + FailingReturn.tok.col;
- }
-
- byte[] checksum;
-
- /// <summary>
- /// Returns the checksum of the corresponding assertion.
- /// </summary>
- public override byte[] Checksum
- {
- get
- {
- return checksum;
- }
- }
-
- public override Counterexample Clone()
- {
- var ret = new ReturnCounterexample(Trace, FailingReturn, FailingEnsures, Model, MvInfo, Context, checksum);
- ret.calleeCounterexamples = calleeCounterexamples;
- return ret;
- }
- }
-
- public class VerifierCallback {
- // reason == null means this is genuine counterexample returned by the prover
- // other reason means it's time out/memory out/crash
- public virtual void OnCounterexample(Counterexample ce, string/*?*/ reason) {
- Contract.Requires(ce != null);
- }
-
- // called in case resource is exceeded and we don't have counterexample
- public virtual void OnTimeout(string reason) {
- Contract.Requires(reason != null);
- }
-
- public virtual void OnOutOfMemory(string reason) {
- Contract.Requires(reason != null);
- }
-
- public virtual void OnProgress(string phase, int step, int totalSteps, double progressEstimate) {
- }
-
- public virtual void OnUnreachableCode(Implementation impl) {
- Contract.Requires(impl != null);
- }
-
- public virtual void OnWarning(string msg) {
- Contract.Requires(msg != null);
- switch (CommandLineOptions.Clo.PrintProverWarnings) {
- case CommandLineOptions.ProverWarnings.None:
- break;
- case CommandLineOptions.ProverWarnings.Stdout:
- Console.WriteLine("Prover warning: " + msg);
- break;
- case CommandLineOptions.ProverWarnings.Stderr:
- Console.Error.WriteLine("Prover warning: " + msg);
- break;
- default:
- Contract.Assume(false);
- throw new cce.UnreachableException(); // unexpected case
- }
- }
- }
-}
-
-////////////////////////////////////////////
-
-namespace VC {
- using Bpl = Microsoft.Boogie;
-
- public class VCGenException : Exception {
- public VCGenException(string s)
- : base(s) {
- }
- }
- [ContractClassFor(typeof(ConditionGeneration))]
- public abstract class ConditionGenerationContracts : ConditionGeneration {
- public override Outcome VerifyImplementation(Implementation impl, VerifierCallback callback) {
- Contract.Requires(impl != null);
- Contract.Requires(callback != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- throw new NotImplementedException();
- }
- public ConditionGenerationContracts(Program p, List<Checker> checkers)
- : base(p, checkers) {
- }
- }
-
- [ContractClass(typeof(ConditionGenerationContracts))]
- public abstract class ConditionGeneration : IDisposable {
- protected internal object CheckerCommonState;
-
- public enum Outcome {
- Correct,
- Errors,
- TimedOut,
- OutOfMemory,
- Inconclusive,
- ReachedBound
- }
-
- public static Outcome ProverInterfaceOutcomeToConditionGenerationOutcome(ProverInterface.Outcome outcome) {
- switch (outcome) {
- case ProverInterface.Outcome.Invalid:
- return Outcome.Errors;
- case ProverInterface.Outcome.OutOfMemory:
- return Outcome.OutOfMemory;
- case ProverInterface.Outcome.TimeOut:
- return Outcome.TimedOut;
- case ProverInterface.Outcome.Undetermined:
- return Outcome.Inconclusive;
- case ProverInterface.Outcome.Valid:
- return Outcome.Correct;
- }
- return Outcome.Inconclusive; // unreachable but the stupid compiler does not understand
- }
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(checkers));
- Contract.Invariant(cce.NonNullDictionaryAndValues(incarnationOriginMap));
- Contract.Invariant(program != null);
- }
-
- public int CumulativeAssertionCount; // for statistics
-
- protected readonly List<Checker>/*!>!*/ checkers;
-
- private bool _disposed;
-
- protected Implementation currentImplementation;
-
- protected List<Variable> CurrentLocalVariables = null;
-
- // shared across each implementation; created anew for each implementation
- protected Dictionary<Variable, int> variable2SequenceNumber;
- public Dictionary<Incarnation, Absy>/*!>!*/ incarnationOriginMap = new Dictionary<Incarnation, Absy>();
-
- public Program program;
- protected string/*?*/ logFilePath;
- protected bool appendLogFile;
-
- public static List<Model> errorModelList;
-
- public ConditionGeneration(Program p, List<Checker> checkers) {
- Contract.Requires(p != null && checkers != null && cce.NonNullElements(checkers));
- program = p;
- this.checkers = checkers;
- Cores = 1;
- }
-
- /// <summary>
- /// Takes an implementation and constructs a verification condition and sends
- /// it to the theorem prover.
- /// Returns null if "impl" is correct. Otherwise, returns a list of counterexamples,
- /// each counterexample consisting of an array of labels.
- /// </summary>
- /// <param name="impl"></param>
- public Outcome VerifyImplementation(Implementation impl, out List<Counterexample>/*?*/ errors, string requestId = null) {
- Contract.Requires(impl != null);
-
- Contract.Ensures(Contract.ValueAtReturn(out errors) == null || Contract.ForAll(Contract.ValueAtReturn(out errors), i => i != null));
- Contract.Ensures(Contract.Result<Outcome>() != Outcome.Errors || errors != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- Helpers.ExtraTraceInformation("Starting implementation verification");
-
- CounterexampleCollector collector = new CounterexampleCollector();
- collector.RequestId = requestId;
- Outcome outcome = VerifyImplementation(impl, collector);
- if (outcome == Outcome.Errors || outcome == Outcome.TimedOut || outcome == Outcome.OutOfMemory) {
- errors = collector.examples;
- } else {
- errors = null;
- }
-
- Helpers.ExtraTraceInformation("Finished implementation verification");
- return outcome;
- }
-
- /// <summary>
- /// Takes an implementation and constructs a verification condition and sends
- /// it to the theorem prover.
- /// Returns null if "impl" is correct. Otherwise, returns a list of counterexamples,
- /// each counterexample consisting of an array of labels.
- /// </summary>
- /// <param name="impl"></param>
- public Outcome VerifyImplementation(Implementation impl, out List<Counterexample> errors, out List<Model> errorsModel)
- {
- Contract.Ensures(Contract.Result<Outcome>() != Outcome.Errors || Contract.ValueAtReturn(out errors) != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- List<Counterexample> errorsOut;
-
- Outcome outcome;
- errorModelList = new List<Model>();
- outcome = VerifyImplementation(impl, out errorsOut);
- errors = errorsOut;
- errorsModel = errorModelList;
-
- return outcome;
- }
-
- public abstract Outcome VerifyImplementation(Implementation impl, VerifierCallback callback);
-
- /////////////////////////////////// Common Methods and Classes //////////////////////////////////////////
-
- #region Methods for injecting pre- and postconditions
- private static void
- ThreadInCodeExpr(Implementation impl,
- Block targetBlock,
- CodeExpr codeExpr,
- bool replaceWithAssert,
- TokenTextWriter debugWriter) {
- Contract.Requires(impl != null);
- Contract.Requires(codeExpr != null);
- Contract.Requires(targetBlock != null);
- // Go through codeExpr and for all blocks that have a "return e"
- // as their transfer command:
- // Replace all "return e" with "assert/assume e"
- // Change the transfer command to "goto targetBlock"
- // Then add all of the blocks in codeExpr to the implementation (at the end)
- foreach (Block b in codeExpr.Blocks) {
- Contract.Assert(b != null);
- ReturnExprCmd rec = b.TransferCmd as ReturnExprCmd;
- if (rec != null) { // otherwise it is a goto command
- if (replaceWithAssert) {
- Ensures ens = new Ensures(rec.tok, false, rec.Expr, null);
- Contract.Assert(ens != null);
- Cmd c = new AssertEnsuresCmd(ens);
- Contract.Assert(c != null);
- b.Cmds.Add(c);
- } else {
- b.Cmds.Add(new AssumeCmd(rec.tok, rec.Expr));
- }
- b.TransferCmd = new GotoCmd(Token.NoToken,
- new List<String> { targetBlock.Label },
- new List<Block> { targetBlock });
- targetBlock.Predecessors.Add(b);
- }
- impl.Blocks.Add(b);
- }
- if (debugWriter != null) {
- codeExpr.Emit(debugWriter, 1, false);
- }
- return;
- }
-
- private static void AddAsPrefix(Block b, List<Cmd> cs) {
- Contract.Requires(b != null);
- Contract.Requires(cs != null);
- List<Cmd> newCommands = new List<Cmd>();
- newCommands.AddRange(cs);
- newCommands.AddRange(b.Cmds);
- b.Cmds = newCommands;
- }
-
-
- /// <summary>
- /// Modifies an implementation by prepending it with startCmds and then, as assume
- /// statements, all preconditions. Insert new blocks as needed, and adjust impl.Blocks[0]
- /// accordingly to make it the new implementation entry block.
- /// </summary>
- /// <param name="impl"></param>
- /// <param name="startCmds"></param>
- protected static void InjectPreconditions(Implementation impl, [Captured] List<Cmd> startCmds) {
- Contract.Requires(impl != null);
- Contract.Requires(startCmds != null);
- Contract.Requires(impl.Proc != null);
-
- TokenTextWriter debugWriter = null;
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
- debugWriter.WriteLine("Effective precondition:");
- }
-
- Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
- string blockLabel = "PreconditionGeneratedEntry";
-
- Block origStartBlock = impl.Blocks[0];
- Block insertionPoint = new Block(
- new Token(-17, -4), blockLabel, startCmds,
- new GotoCmd(Token.NoToken, new List<String> { origStartBlock.Label }, new List<Block> { origStartBlock }));
-
- impl.Blocks[0] = insertionPoint; // make insertionPoint the start block
- impl.Blocks.Add(origStartBlock); // and put the previous start block at the end of the list
-
- // (free and checked) requires clauses
- foreach (Requires req in impl.Proc.Requires)
- // invariant: insertionPoint.TransferCmd is "goto origStartBlock;", but origStartBlock.Predecessors has not yet been updated
- {
- Contract.Assert(req != null);
- Expr e = Substituter.Apply(formalProcImplSubst, req.Condition);
- Cmd c = new AssumeCmd(req.tok, e);
- c.IrrelevantForChecksumComputation = true;
- insertionPoint.Cmds.Add(c);
- if (debugWriter != null) {
- c.Emit(debugWriter, 1);
- }
- }
- origStartBlock.Predecessors.Add(insertionPoint);
-
- if (impl.ExplicitAssumptionAboutCachedPrecondition != null)
- {
- insertionPoint.Cmds.Add(impl.ExplicitAssumptionAboutCachedPrecondition);
- }
-
- if (debugWriter != null) {
- debugWriter.WriteLine();
- }
- }
- /// <summary>
- /// Modifies an implementation by inserting all postconditions
- /// as assert statements at the end of the implementation
- /// Returns the possibly-new unified exit block of the implementation
- /// </summary>
- /// <param name="impl"></param>
- /// <param name="unifiedExitblock">The unified exit block that has
- /// already been constructed for the implementation (and so
- /// is already an element of impl.Blocks)
- /// </param>
- protected static void InjectPostConditions(Implementation impl, Block unifiedExitBlock, Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins) {
- Contract.Requires(impl != null);
- Contract.Requires(unifiedExitBlock != null);
- Contract.Requires(gotoCmdOrigins != null);
- Contract.Requires(impl.Proc != null);
- Contract.Requires(unifiedExitBlock.TransferCmd is ReturnCmd);
-
- TokenTextWriter debugWriter = null;
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
- debugWriter.WriteLine("Effective postcondition:");
- }
-
- Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
-
- // (free and checked) ensures clauses
- foreach (Ensures ens in impl.Proc.Ensures) {
- Contract.Assert(ens != null);
- if (!ens.Free) { // skip free ensures clauses
- Expr e = Substituter.Apply(formalProcImplSubst, ens.Condition);
- Ensures ensCopy = (Ensures)cce.NonNull(ens.Clone());
- ensCopy.Condition = e;
- AssertEnsuresCmd c = new AssertEnsuresCmd(ensCopy);
- c.ErrorDataEnhanced = ensCopy.ErrorDataEnhanced;
- unifiedExitBlock.Cmds.Add(c);
- if (debugWriter != null) {
- c.Emit(debugWriter, 1);
- }
- }
- }
-
- if (debugWriter != null) {
- debugWriter.WriteLine();
- }
- }
-
-
- /// <summary>
- /// Get the pre-condition of an implementation, including the where clauses from the in-parameters.
- /// </summary>
- /// <param name="impl"></param>
- protected static List<Cmd> GetPre(Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
-
-
- TokenTextWriter debugWriter = null;
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
- debugWriter.WriteLine("Effective precondition:");
- }
-
- Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
- List<Cmd> pre = new List<Cmd>();
-
- // (free and checked) requires clauses
- foreach (Requires req in impl.Proc.Requires) {
- Contract.Assert(req != null);
- Expr e = Substituter.Apply(formalProcImplSubst, req.Condition);
- Contract.Assert(e != null);
- Cmd c = new AssumeCmd(req.tok, e);
- Contract.Assert(c != null);
- pre.Add(c);
-
- if (debugWriter != null) {
- c.Emit(debugWriter, 1);
- }
- }
-
- if (debugWriter != null) {
- debugWriter.WriteLine();
- }
-
- return pre;
- }
-
- /// <summary>
- /// Get the post-condition of an implementation.
- /// </summary>
- /// <param name="impl"></param>
- protected static List<Cmd> GetPost(Implementation impl) {
-
-
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- Console.WriteLine("Effective postcondition:");
- }
-
- // Construct an Expr for the post-condition
- Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
- List<Cmd> post = new List<Cmd>();
- foreach (Ensures ens in impl.Proc.Ensures) {
- Contract.Assert(ens != null);
- if (!ens.Free) {
- Expr e = Substituter.Apply(formalProcImplSubst, ens.Condition);
- Contract.Assert(e != null);
- Ensures ensCopy = cce.NonNull((Ensures)ens.Clone());
- ensCopy.Condition = e;
- Cmd c = new AssertEnsuresCmd(ensCopy);
- ((AssertEnsuresCmd)c).ErrorDataEnhanced = ensCopy.ErrorDataEnhanced;
- post.Add(c);
-
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- c.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 1);
- }
- }
- }
-
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- Console.WriteLine();
- }
-
- return post;
- }
-
- /// <summary>
- /// Get the where clauses from the in- and out-parameters as
- /// a sequence of assume commands.
- /// As a side effect, this method adds these where clauses to the out parameters.
- /// </summary>
- /// <param name="impl"></param>
- protected static List<Cmd> GetParamWhereClauses(Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
- TokenTextWriter debugWriter = null;
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
- debugWriter.WriteLine("Effective precondition from where-clauses:");
- }
-
- Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
- List<Cmd> whereClauses = new List<Cmd>();
-
- // where clauses of in-parameters
- foreach (Formal f in impl.Proc.InParams) {
- Contract.Assert(f != null);
- if (f.TypedIdent.WhereExpr != null) {
- Expr e = Substituter.Apply(formalProcImplSubst, f.TypedIdent.WhereExpr);
- Cmd c = new AssumeCmd(f.tok, e);
- whereClauses.Add(c);
-
- if (debugWriter != null) {
- c.Emit(debugWriter, 1);
- }
- }
- }
-
- // where clauses of out-parameters
- Contract.Assert(impl.OutParams.Count == impl.Proc.OutParams.Count);
- for (int i = 0; i < impl.OutParams.Count; i++) {
- Variable f = cce.NonNull(impl.Proc.OutParams[i]);
- if (f.TypedIdent.WhereExpr != null) {
- Expr e = Substituter.Apply(formalProcImplSubst, f.TypedIdent.WhereExpr);
- Cmd c = new AssumeCmd(f.tok, e);
- whereClauses.Add(c);
-
- Variable fi = cce.NonNull(impl.OutParams[i]);
- Contract.Assume(fi.TypedIdent.WhereExpr == null);
- fi.TypedIdent.WhereExpr = e;
-
- if (debugWriter != null) {
- c.Emit(debugWriter, 1);
- }
- }
- }
-
- if (debugWriter != null) {
- debugWriter.WriteLine();
- }
-
- return whereClauses;
- }
-
- protected static void RestoreParamWhereClauses(Implementation impl) {
- Contract.Requires(impl != null);
- // We no longer need the where clauses on the out parameters, so we remove them to restore the situation from before VC generation
- foreach (Formal f in impl.OutParams) {
- Contract.Assert(f != null);
- f.TypedIdent.WhereExpr = null;
- }
- }
- #endregion
-
-
- protected Checker FindCheckerFor(int timeout, bool isBlocking = true, int waitTimeinMs = 50, int maxRetries = 3)
- {
- Contract.Requires(0 <= waitTimeinMs && 0 <= maxRetries);
- Contract.Ensures(!isBlocking || Contract.Result<Checker>() != null);
-
- lock (checkers)
- {
- retry:
- // Look for existing checker.
- for (int i = 0; i < checkers.Count; i++)
- {
- var c = checkers[i];
- if (Monitor.TryEnter(c))
- {
- try
- {
- if (c.WillingToHandle(timeout, program))
- {
- c.GetReady();
- return c;
- }
- else if (c.IsIdle || c.IsClosed)
- {
- if (c.IsIdle)
- {
- c.Retarget(program, c.TheoremProver.Context, timeout);
- c.GetReady();
- return c;
- }
- else
- {
- checkers.RemoveAt(i);
- i--;
- continue;
- }
- }
- }
- finally
- {
- Monitor.Exit(c);
- }
- }
- }
-
- if (Cores <= checkers.Count)
- {
- if (isBlocking || 0 < maxRetries)
- {
- if (0 < waitTimeinMs)
- {
- Monitor.Wait(checkers, waitTimeinMs);
- }
- maxRetries--;
- goto retry;
- }
- else
- {
- return null;
- }
- }
-
- // Create a new checker.
- string log = logFilePath;
- if (log != null && !log.Contains("@PROC@") && checkers.Count > 0)
- {
- log = log + "." + checkers.Count;
- }
- Checker ch = new Checker(this, program, log, appendLogFile, timeout);
- ch.GetReady();
- checkers.Add(ch);
- return ch;
- }
- }
-
-
- virtual public void Close() {
- }
-
-
- public class CounterexampleCollector : VerifierCallback {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(examples));
- }
-
- public string RequestId;
-
- public readonly List<Counterexample>/*!>!*/ examples = new List<Counterexample>();
- public override void OnCounterexample(Counterexample ce, string/*?*/ reason) {
- //Contract.Requires(ce != null);
- if (RequestId != null)
- {
- ce.RequestId = RequestId;
- }
- if (ce.OriginalRequestId == null && 1 < CommandLineOptions.Clo.VerifySnapshots)
- {
- ce.OriginalRequestId = RequestId;
- }
- examples.Add(ce);
- }
-
- public override void OnUnreachableCode(Implementation impl) {
- //Contract.Requires(impl != null);
- System.Console.WriteLine("found unreachable code:");
- EmitImpl(impl, false);
- // TODO report error about next to last in seq
- }
- }
-
- protected static void EmitImpl(Implementation impl, bool printDesugarings) {
- Contract.Requires(impl != null);
- int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured;
- CommandLineOptions.Clo.PrintUnstructured = 2; // print only the unstructured program
- bool oldPrintDesugaringSetting = CommandLineOptions.Clo.PrintDesugarings;
- CommandLineOptions.Clo.PrintDesugarings = printDesugarings;
- impl.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 0);
- CommandLineOptions.Clo.PrintDesugarings = oldPrintDesugaringSetting;
- CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured;
- }
-
-
- protected Block GenerateUnifiedExit(Implementation impl, Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins) {
- Contract.Requires(impl != null);
- Contract.Requires(gotoCmdOrigins != null);
- Contract.Ensures(Contract.Result<Block>() != null);
-
- Contract.Ensures(Contract.Result<Block>().TransferCmd is ReturnCmd);
- Block/*?*/ exitBlock = null;
- #region Create a unified exit block, if there's more than one
- {
- int returnBlocks = 0;
- foreach (Block b in impl.Blocks) {
- if (b.TransferCmd is ReturnCmd) {
- exitBlock = b;
- returnBlocks++;
- }
- }
- if (returnBlocks > 1) {
- string unifiedExitLabel = "GeneratedUnifiedExit";
- Block unifiedExit = new Block(new Token(-17, -4), unifiedExitLabel, new List<Cmd>(), new ReturnCmd(Token.NoToken));
- Contract.Assert(unifiedExit != null);
- foreach (Block b in impl.Blocks) {
- if (b.TransferCmd is ReturnCmd) {
- List<String> labels = new List<String>();
- labels.Add(unifiedExitLabel);
- List<Block> bs = new List<Block>();
- bs.Add(unifiedExit);
- GotoCmd go = new GotoCmd(Token.NoToken, labels, bs);
- gotoCmdOrigins[go] = (ReturnCmd)b.TransferCmd;
- b.TransferCmd = go;
- unifiedExit.Predecessors.Add(b);
- }
- }
-
- exitBlock = unifiedExit;
- impl.Blocks.Add(unifiedExit);
- }
- Contract.Assert(exitBlock != null);
- }
- return exitBlock;
- #endregion
- }
-
- protected static void ResetPredecessors(List<Block> blocks) {
- Contract.Requires(blocks != null);
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- b.Predecessors = new List<Block>();
- }
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- foreach (Block ch in Exits(b)) {
- Contract.Assert(ch != null);
- ch.Predecessors.Add(b);
- }
- }
- }
-
- protected static IEnumerable Exits(Block b) {
- Contract.Requires(b != null);
- GotoCmd g = b.TransferCmd as GotoCmd;
- if (g != null) {
- return cce.NonNull(g.labelTargets);
- }
- return new List<Block>();
- }
-
- protected Variable CreateIncarnation(Variable x, Absy a) {
- Contract.Requires(this.variable2SequenceNumber != null);
- Contract.Requires(this.CurrentLocalVariables != null);
- Contract.Requires(a is Block || a is AssignCmd || a is HavocCmd);
-
- Contract.Requires(x != null);
- Contract.Ensures(Contract.Result<Variable>() != null);
-
- int currentIncarnationNumber =
- variable2SequenceNumber.ContainsKey(x)
- ?
- variable2SequenceNumber[x]
- :
- -1;
- Variable v = new Incarnation(x, currentIncarnationNumber + 1);
- variable2SequenceNumber[x] = currentIncarnationNumber + 1;
- CurrentLocalVariables.Add(v);
- incarnationOriginMap.Add((Incarnation)v, a);
- return v;
- }
-
- /// <summary>
- /// Compute the incarnation map at the beginning of block "b" from the incarnation blocks of the
- /// predecessors of "b".
- ///
- /// The predecessor map b.map for block "b" is defined as follows:
- /// b.map.Domain == Union{Block p in b.predecessors; p.map.Domain}
- /// Forall{Variable v in b.map.Domain;
- /// b.map[v] == (v in Intersection{Block p in b.predecessors; p.map}.Domain
- /// ? b.predecessors[0].map[v]
- /// : new Variable())}
- /// Every variable that b.map maps to a fresh variable requires a fixup in all predecessor blocks.
- /// </summary>
- /// <param name="b"></param>
- /// <param name="block2Incarnation">Gives incarnation maps for b's predecessors.</param>
- /// <returns></returns>
- protected Dictionary<Variable, Expr> ComputeIncarnationMap(Block b, Dictionary<Block, Dictionary<Variable, Expr>> block2Incarnation) {
- Contract.Requires(b != null);
- Contract.Requires(block2Incarnation != null);
- Contract.Ensures(Contract.Result<Dictionary<Variable, Expr>>() != null);
-
- if (b.Predecessors.Count == 0) {
- return new Dictionary<Variable, Expr>();
- }
-
- Dictionary<Variable, Expr> incarnationMap = null;
- Set /*Variable*/ fixUps = new Set /*Variable*/ ();
- foreach (Block pred in b.Predecessors) {
- Contract.Assert(pred != null);
- Contract.Assert(block2Incarnation.ContainsKey(pred)); // otherwise, Passive Transformation found a block whose predecessors have not been processed yet
- Dictionary<Variable, Expr> predMap = (Dictionary<Variable, Expr>)block2Incarnation[pred];
- Contract.Assert(predMap != null);
- if (incarnationMap == null) {
- incarnationMap = new Dictionary<Variable, Expr>(predMap);
- continue;
- }
-
- ArrayList /*Variable*/ conflicts = new ArrayList /*Variable*/ ();
- foreach (Variable v in incarnationMap.Keys) {
- Contract.Assert(v != null);
- if (!predMap.ContainsKey(v)) {
- // conflict!!
- conflicts.Add(v);
- fixUps.Add(v);
- }
- }
- // Now that we're done with enumeration, we'll do all the removes
- foreach (Variable v in conflicts) {
- Contract.Assert(v != null);
- incarnationMap.Remove(v);
- }
- foreach (Variable v in predMap.Keys) {
- Contract.Assert(v != null);
- if (!incarnationMap.ContainsKey(v)) {
- // v was not in the domain of the predecessors seen so far, so it needs to be fixed up
- fixUps.Add(v);
- } else {
- // v in incarnationMap ==> all pred blocks (up to now) all agree on its incarnation
- if (predMap[v] != incarnationMap[v]) {
- // conflict!!
- incarnationMap.Remove(v);
- fixUps.Add(v);
- }
- }
- }
- }
-
- #region Second, for all variables in the fixups list, introduce a new incarnation and push it back into the preds.
- foreach (Variable v in fixUps) {
- Contract.Assert(v != null);
- if (!b.IsLive(v))
- continue;
- Variable v_prime = CreateIncarnation(v, b);
- IdentifierExpr ie = new IdentifierExpr(v_prime.tok, v_prime);
- Contract.Assert(incarnationMap != null);
- incarnationMap[v] = ie;
- foreach (Block pred in b.Predecessors) {
- Contract.Assert(pred != null);
- #region Create an assume command equating v_prime with its last incarnation in pred
- #region Create an identifier expression for the last incarnation in pred
- Dictionary<Variable, Expr> predMap = (Dictionary<Variable, Expr>)cce.NonNull(block2Incarnation[pred]);
-
- Expr pred_incarnation_exp;
- Expr o = predMap.ContainsKey(v) ? predMap[v] : null;
- if (o == null) {
- Variable predIncarnation = v;
- IdentifierExpr ie2 = new IdentifierExpr(predIncarnation.tok, predIncarnation);
- pred_incarnation_exp = ie2;
- } else {
- pred_incarnation_exp = o;
- }
- #endregion
- #region Create an identifier expression for the new incarnation
- IdentifierExpr v_prime_exp = new IdentifierExpr(v_prime.tok, v_prime);
- #endregion
- #region Create the assume command itself
- AssumeCmd ac = new AssumeCmd(v.tok, TypedExprEq(v_prime_exp, pred_incarnation_exp, v_prime.Name.Contains("a##cached##")));
- pred.Cmds.Add(ac);
- #endregion
- #endregion
- }
- }
- #endregion
-
- Contract.Assert(incarnationMap != null);
- return incarnationMap;
- }
-
- Dictionary<Variable, Expr> preHavocIncarnationMap = null; // null = the previous command was not an HashCmd. Otherwise, a *copy* of the map before the havoc statement
-
- protected void TurnIntoPassiveBlock(Block b, Dictionary<Variable, Expr> incarnationMap, ModelViewInfo mvInfo, Substitution oldFrameSubst, MutableVariableCollector variableCollector, byte[] currentChecksum = null) {
- Contract.Requires(b != null);
- Contract.Requires(incarnationMap != null);
- Contract.Requires(mvInfo != null);
- Contract.Requires(oldFrameSubst != null);
- #region Walk forward over the commands in this block and convert them to passive commands
-
- List<Cmd> passiveCmds = new List<Cmd>();
- foreach (Cmd c in b.Cmds) {
- Contract.Assert(c != null); // walk forward over the commands because the map gets modified in a forward direction
- ChecksumHelper.ComputeChecksums(c, currentImplementation, variableCollector.UsedVariables, currentChecksum);
- variableCollector.Visit(c);
- currentChecksum = c.Checksum;
- TurnIntoPassiveCmd(c, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, b);
- }
- b.Checksum = currentChecksum;
- b.Cmds = passiveCmds;
-
- if (b.TransferCmd is ReturnExprCmd) {
- ReturnExprCmd rec = (ReturnExprCmd)b.TransferCmd.Clone();
- Substitution incarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
- rec.Expr = Substituter.ApplyReplacingOldExprs(incarnationSubst, oldFrameSubst, rec.Expr);
- b.TransferCmd = rec;
- }
- #endregion
- }
-
- protected Dictionary<Variable, Expr> Convert2PassiveCmd(Implementation impl, ModelViewInfo mvInfo) {
- Contract.Requires(impl != null);
- Contract.Requires(mvInfo != null);
-
- currentImplementation = impl;
-
- var start = DateTime.UtcNow;
-
- Dictionary<Variable, Expr> r = ConvertBlocks2PassiveCmd(impl.Blocks, impl.Proc.Modifies, mvInfo);
-
- var end = DateTime.UtcNow;
-
- if (CommandLineOptions.Clo.TraceCachingForDebugging)
- {
- Console.Out.WriteLine("Turned implementation into passive commands within {0:F0} ms.\n", end.Subtract(start).TotalMilliseconds);
- }
-
- if (CommandLineOptions.Clo.TraceCachingForDebugging)
- {
- using (var tokTxtWr = new TokenTextWriter("<console>", Console.Out, false, false))
- {
- var pd = CommandLineOptions.Clo.PrintDesugarings;
- var pu = CommandLineOptions.Clo.PrintUnstructured;
- CommandLineOptions.Clo.PrintDesugarings = true;
- CommandLineOptions.Clo.PrintUnstructured = 1;
- impl.Emit(tokTxtWr, 0);
- CommandLineOptions.Clo.PrintDesugarings = pd;
- CommandLineOptions.Clo.PrintUnstructured = pu;
- }
- }
-
- currentImplementation = null;
-
- RestoreParamWhereClauses(impl);
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify) {
- Console.WriteLine("after conversion to passive commands");
- EmitImpl(impl, true);
- }
- #endregion
-
- return r;
- }
-
- protected Dictionary<Variable, Expr> ConvertBlocks2PassiveCmd(List<Block> blocks, List<IdentifierExpr> modifies, ModelViewInfo mvInfo) {
- Contract.Requires(blocks != null);
- Contract.Requires(modifies != null);
- Contract.Requires(mvInfo != null);
- #region Convert to Passive Commands
-
- #region Topological sort -- need to process in a linearization of the partial order
- Graph<Block> dag = new Graph<Block>();
- dag.AddSource(cce.NonNull(blocks[0])); // there is always at least one node in the graph
- foreach (Block b in blocks) {
- GotoCmd gtc = b.TransferCmd as GotoCmd;
- if (gtc != null) {
- Contract.Assume(gtc.labelTargets != null);
- foreach (Block dest in gtc.labelTargets) {
- Contract.Assert(dest != null);
- dag.AddEdge(b, dest);
- }
- }
- }
-
- IEnumerable sortedNodes;
- if (CommandLineOptions.Clo.ModifyTopologicalSorting) {
- sortedNodes = dag.TopologicalSort(true);
- } else {
- sortedNodes = dag.TopologicalSort();
- }
-
- Contract.Assert(sortedNodes != null);
- #endregion
-
- Substitution oldFrameSubst = ComputeOldExpressionSubstitution(modifies);
-
- // Now we can process the nodes in an order so that we're guaranteed to have
- // processed all of a node's predecessors before we process the node.
- Dictionary<Block, Dictionary<Variable, Expr>> block2Incarnation = new Dictionary<Block, Dictionary<Variable, Expr>>();
- Block exitBlock = null;
- Dictionary<Variable, Expr> exitIncarnationMap = null;
- var variableCollectors = new Dictionary<Block, MutableVariableCollector>();
- foreach (Block b in sortedNodes) {
- Contract.Assert(b != null);
- Contract.Assert(!block2Incarnation.ContainsKey(b));
- Dictionary<Variable, Expr> incarnationMap = ComputeIncarnationMap(b, block2Incarnation);
-
- // b.liveVarsBefore has served its purpose in the just-finished call to ComputeIncarnationMap; null it out.
- b.liveVarsBefore = null;
-
- // Decrement the succCount field in each predecessor. Once the field reaches zero in any block,
- // all its successors have been passified. Consequently, its entry in block2Incarnation can be removed.
- byte[] currentChecksum = null;
- var mvc = new MutableVariableCollector();
- variableCollectors[b] = mvc;
- foreach (Block p in b.Predecessors) {
- p.succCount--;
- if (p.Checksum != null)
- {
- // Compute the checksum based on the checksums of the predecessor. The order should not matter.
- currentChecksum = ChecksumHelper.CombineChecksums(p.Checksum, currentChecksum, true);
- }
- mvc.AddUsedVariables(variableCollectors[p].UsedVariables);
- if (p.succCount == 0)
- block2Incarnation.Remove(p);
- }
-
- #region Each block's map needs to be available to successor blocks
- GotoCmd gotoCmd = b.TransferCmd as GotoCmd;
- if (gotoCmd == null) {
- b.succCount = 0;
- }
- else {
- // incarnationMap needs to be added only if there is some successor of b
- b.succCount = gotoCmd.labelNames.Count;
- block2Incarnation.Add(b, incarnationMap);
- }
- #endregion Each block's map needs to be available to successor blocks
-
- TurnIntoPassiveBlock(b, incarnationMap, mvInfo, oldFrameSubst, mvc, currentChecksum);
- exitBlock = b;
- exitIncarnationMap = incarnationMap;
- }
-
- variableCollectors.Clear();
-
- // Verify that exitBlock is indeed the unique exit block
- Contract.Assert(exitBlock != null);
- Contract.Assert(exitBlock.TransferCmd is ReturnCmd);
- #endregion Convert to Passive Commands
-
- return exitIncarnationMap;
- }
-
- /// <summary>
- /// Compute the substitution for old expressions.
- /// </summary>
- protected static Substitution ComputeOldExpressionSubstitution(List<IdentifierExpr> modifies)
- {
- Dictionary<Variable, Expr> oldFrameMap = new Dictionary<Variable, Expr>();
- foreach (IdentifierExpr ie in modifies)
- {
- Contract.Assert(ie != null);
- if (!oldFrameMap.ContainsKey(cce.NonNull(ie.Decl)))
- oldFrameMap.Add(ie.Decl, ie);
- }
- return Substituter.SubstitutionFromHashtable(oldFrameMap);
- }
-
- public enum CachingAction : byte
- {
- DoNothingToAssert,
- MarkAsPartiallyVerified,
- MarkAsFullyVerified,
- RecycleError,
- AssumeNegationOfAssumptionVariable,
- DropAssume
- }
-
- public long[] CachingActionCounts;
-
- void TraceCachingAction(Cmd cmd, CachingAction action)
- {
- if (CommandLineOptions.Clo.TraceCachingForTesting)
- {
- using (var tokTxtWr = new TokenTextWriter("<console>", Console.Out, false, false))
- {
- var loc = cmd.tok != null && cmd.tok != Token.NoToken ? string.Format("{0}({1},{2})", cmd.tok.filename, cmd.tok.line, cmd.tok.col) : "<unknown location>";
- Console.Write("Processing command (at {0}) ", loc);
- cmd.Emit(tokTxtWr, 0);
- Console.Out.WriteLine(" >>> {0}", action);
- }
- }
-
- if (CommandLineOptions.Clo.TraceCachingForBenchmarking && CachingActionCounts != null)
- {
- Interlocked.Increment(ref CachingActionCounts[(int)action]);
- }
- }
-
- /// <summary>
- /// Turn a command into a passive command, and it remembers the previous step, to see if it is a havoc or not. In the case, it remembers the incarnation map BEFORE the havoc
- /// Meanwhile, record any information needed to later reconstruct a model view.
- /// </summary>
- protected void TurnIntoPassiveCmd(Cmd c, Dictionary<Variable, Expr> incarnationMap, Substitution oldFrameSubst, List<Cmd> passiveCmds, ModelViewInfo mvInfo, Block containingBlock) {
- Contract.Requires(c != null);
- Contract.Requires(incarnationMap != null);
- Contract.Requires(oldFrameSubst != null);
- Contract.Requires(passiveCmds != null);
- Contract.Requires(mvInfo != null);
- Contract.Requires(containingBlock != null);
-
- Substitution incarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
- #region assert/assume P |--> assert/assume P[x := in(x)], out := in
- if (c is PredicateCmd) {
- Contract.Assert(c is AssertCmd || c is AssumeCmd); // otherwise, unexpected PredicateCmd type
-
- PredicateCmd pc = (PredicateCmd)c.Clone();
- Contract.Assert(pc != null);
-
- Expr copy = Substituter.ApplyReplacingOldExprs(incarnationSubst, oldFrameSubst, pc.Expr);
- if (CommandLineOptions.Clo.ModelViewFile != null && pc is AssumeCmd) {
- string description = QKeyValue.FindStringAttribute(pc.Attributes, "captureState");
- if (description != null) {
- Expr mv = new NAryExpr(pc.tok, new FunctionCall(ModelViewInfo.MVState_FunctionDef), new List<Expr> { Bpl.Expr.Ident(ModelViewInfo.MVState_ConstantDef), Bpl.Expr.Literal(mvInfo.CapturePoints.Count) });
- copy = Bpl.Expr.And(mv, copy);
- mvInfo.CapturePoints.Add(new ModelViewInfo.Mapping(description, new Dictionary<Variable, Expr>(incarnationMap)));
- }
- }
- Contract.Assert(copy != null);
- var dropCmd = false;
- var relevantAssumpVars = currentImplementation != null ? currentImplementation.RelevantInjectedAssumptionVariables(incarnationMap) : new List<LocalVariable>();
- var relevantDoomedAssumpVars = currentImplementation != null ? currentImplementation.RelevantDoomedInjectedAssumptionVariables(incarnationMap) : new List<LocalVariable>();
- var checksum = pc.Checksum;
- if (pc is AssertCmd) {
- var ac = (AssertCmd)pc;
- ac.OrigExpr = ac.Expr;
- Contract.Assert(ac.IncarnationMap == null);
- ac.IncarnationMap = (Dictionary<Variable, Expr>)cce.NonNull(new Dictionary<Variable, Expr>(incarnationMap));
-
- var subsumption = Wlp.Subsumption(ac);
- if (relevantDoomedAssumpVars.Any())
- {
- TraceCachingAction(pc, CachingAction.DoNothingToAssert);
- }
- else if (currentImplementation != null
- && currentImplementation.HasCachedSnapshot
- && checksum != null
- && currentImplementation.IsAssertionChecksumInCachedSnapshot(checksum)
- && !currentImplementation.IsErrorChecksumInCachedSnapshot(checksum))
- {
- if (!currentImplementation.AnyErrorsInCachedSnapshot
- && currentImplementation.InjectedAssumptionVariables.Count == 1
- && relevantAssumpVars.Count == 1)
- {
- TraceCachingAction(pc, CachingAction.MarkAsPartiallyVerified);
- }
- else
- {
- bool isTrue;
- var assmVars = currentImplementation.ConjunctionOfInjectedAssumptionVariables(incarnationMap, out isTrue);
- TraceCachingAction(pc, !isTrue ? CachingAction.MarkAsPartiallyVerified : CachingAction.MarkAsFullyVerified);
- var litExpr = ac.Expr as LiteralExpr;
- if (litExpr == null || !litExpr.IsTrue)
- {
- ac.MarkAsVerifiedUnder(assmVars);
- }
- else
- {
- dropCmd = true;
- }
- }
- }
- else if (currentImplementation != null
- && currentImplementation.HasCachedSnapshot
- && relevantAssumpVars.Count == 0
- && checksum != null
- && currentImplementation.IsAssertionChecksumInCachedSnapshot(checksum)
- && currentImplementation.IsErrorChecksumInCachedSnapshot(checksum))
- {
- TraceCachingAction(pc, CachingAction.RecycleError);
- ac.MarkAsVerifiedUnder(Expr.True);
- currentImplementation.AddRecycledFailingAssertion(ac);
- pc.Attributes = new QKeyValue(Token.NoToken, "recycled_failing_assertion", new List<object>(), pc.Attributes);
- }
- else
- {
- TraceCachingAction(pc, CachingAction.DoNothingToAssert);
- }
- }
- else if (pc is AssumeCmd
- && QKeyValue.FindBoolAttribute(pc.Attributes, "precondition_previous_snapshot")
- && pc.SugaredCmdChecksum != null)
- {
- if (!relevantDoomedAssumpVars.Any()
- && currentImplementation.HasCachedSnapshot
- && currentImplementation.IsAssertionChecksumInCachedSnapshot(pc.SugaredCmdChecksum)
- && !currentImplementation.IsErrorChecksumInCachedSnapshot(pc.SugaredCmdChecksum))
- {
- bool isTrue;
- var assmVars = currentImplementation.ConjunctionOfInjectedAssumptionVariables(incarnationMap, out isTrue);
- if (!isTrue)
- {
- copy = LiteralExpr.Imp(assmVars, copy);
- TraceCachingAction(pc, CachingAction.MarkAsPartiallyVerified);
- }
- else
- {
- TraceCachingAction(pc, CachingAction.MarkAsFullyVerified);
- }
- }
- else
- {
- TraceCachingAction(pc, CachingAction.DropAssume);
- dropCmd = true;
- }
- }
- else if (pc is AssumeCmd && QKeyValue.FindBoolAttribute(pc.Attributes, "assumption_variable_initialization"))
- {
- var identExpr = pc.Expr as IdentifierExpr;
- if (identExpr != null && identExpr.Decl != null && !incarnationMap.ContainsKey(identExpr.Decl))
- {
- incarnationMap[identExpr.Decl] = LiteralExpr.True;
- dropCmd = true;
- }
- }
- pc.Expr = copy;
- if (!dropCmd)
- {
- passiveCmds.Add(pc);
- }
- }
- #endregion
- #region x1 := E1, x2 := E2, ... |--> assume x1' = E1[in] & x2' = E2[in], out := in( x |-> x' ) [except as noted below]
- else if (c is AssignCmd) {
- AssignCmd assign = ((AssignCmd)c).AsSimpleAssignCmd; // first remove map assignments
- Contract.Assert(assign != null);
- #region Substitute all variables in E with the current map
- List<Expr> copies = new List<Expr>();
- foreach (Expr e in assign.Rhss) {
- Contract.Assert(e != null);
- copies.Add(Substituter.ApplyReplacingOldExprs(incarnationSubst,
- oldFrameSubst,
- e));
- }
- #endregion
-
- List<Expr/*!>!*/> assumptions = new List<Expr>();
- // it might be too slow to create a new dictionary each time ...
- IDictionary<Variable, Expr> newIncarnationMappings =
- new Dictionary<Variable, Expr>();
-
- for (int i = 0; i < assign.Lhss.Count; ++i) {
- IdentifierExpr lhsIdExpr =
- cce.NonNull((SimpleAssignLhs)assign.Lhss[i]).AssignedVariable;
- Variable lhs = cce.NonNull(lhsIdExpr.Decl);
- Contract.Assert(lhs != null);
- Expr rhs = assign.Rhss[i];
- Contract.Assert(rhs != null);
-
- // don't create incarnations for assignments of literals or single variables.
- if (rhs is LiteralExpr) {
- incarnationMap[lhs] = rhs;
- } else if (rhs is IdentifierExpr) {
- IdentifierExpr ie = (IdentifierExpr)rhs;
- if (incarnationMap.ContainsKey(cce.NonNull(ie.Decl)))
- newIncarnationMappings[lhs] = cce.NonNull((Expr)incarnationMap[ie.Decl]);
- else
- newIncarnationMappings[lhs] = ie;
- } else {
- IdentifierExpr x_prime_exp = null;
- #region Make a new incarnation, x', for variable x, but only if x is *not* already an incarnation
- if (lhs is Incarnation) {
- // incarnations are already written only once, no need to make an incarnation of an incarnation
- x_prime_exp = lhsIdExpr;
- } else {
- Variable v = CreateIncarnation(lhs, c);
- x_prime_exp = new IdentifierExpr(lhsIdExpr.tok, v);
- newIncarnationMappings[lhs] = x_prime_exp;
- }
- #endregion
-
- var nAryExpr = copies[i] as NAryExpr;
- if (nAryExpr != null)
- {
- var binOp = nAryExpr.Fun as BinaryOperator;
- if (binOp != null
- && binOp.Op == BinaryOperator.Opcode.And)
- {
- var arg0 = nAryExpr.Args[0] as LiteralExpr;
- var arg1 = nAryExpr.Args[1] as LiteralExpr;
- if ((arg0 != null && arg0.IsTrue) || (arg1 != null && arg1.IsFalse))
- {
- // Replace the expressions "true && arg1" or "arg0 && false" by "arg1".
- copies[i] = nAryExpr.Args[1];
- }
- }
- }
-
- #region Create an assume command with the new variable
- assumptions.Add(TypedExprEq(x_prime_exp, copies[i], x_prime_exp.Decl != null && x_prime_exp.Decl.Name.Contains("a##cached##")));
- #endregion
- }
- }
-
- foreach (KeyValuePair<Variable, Expr> pair in newIncarnationMappings) {
- Contract.Assert(pair.Key != null && pair.Value != null);
- incarnationMap[pair.Key] = pair.Value;
- }
-
- if (assumptions.Count > 0) {
- Expr assumption = assumptions[0];
-
- for (int i = 1; i < assumptions.Count; ++i) {
- Contract.Assert(assumption != null);
- assumption = Expr.And(assumption, assumptions[i]);
- }
- passiveCmds.Add(new AssumeCmd(c.tok, assumption));
- }
-
- if (currentImplementation != null
- && currentImplementation.HasCachedSnapshot
- && !currentImplementation.AnyErrorsInCachedSnapshot
- && currentImplementation.DoomedInjectedAssumptionVariables.Count == 0
- && currentImplementation.InjectedAssumptionVariables.Count == 1
- && assign.Lhss.Count == 1)
- {
- var identExpr = assign.Lhss[0].AsExpr as IdentifierExpr;
- Expr incarnation;
- if (identExpr != null && identExpr.Decl != null && QKeyValue.FindBoolAttribute(identExpr.Decl.Attributes, "assumption") && incarnationMap.TryGetValue(identExpr.Decl, out incarnation))
- {
- TraceCachingAction(assign, CachingAction.AssumeNegationOfAssumptionVariable);
- passiveCmds.Add(new AssumeCmd(c.tok, Expr.Not(incarnation)));
- }
- }
- }
- #endregion
- #region havoc w |--> assume whereClauses, out := in( w |-> w' )
- else if (c is HavocCmd) {
- if (this.preHavocIncarnationMap == null) // Save a copy of the incarnation map (at the top of a sequence of havoc statements)
- this.preHavocIncarnationMap = new Dictionary<Variable, Expr>(incarnationMap);
-
- HavocCmd hc = (HavocCmd)c;
- Contract.Assert(c != null);
- // If an assumption variable for postconditions is included here, it must have been assigned within a loop.
- // We do not need to havoc it if we have performed a modular proof of the loop (i.e., using only the loop
- // invariant) in the previous snapshot and, consequently, the corresponding assumption did not affect the
- // anything after the loop. We can achieve this by simply not updating/adding it in the incarnation map.
- List<IdentifierExpr> havocVars = hc.Vars.Where(v => !(QKeyValue.FindBoolAttribute(v.Decl.Attributes, "assumption") && v.Decl.Name.StartsWith("a##cached##"))).ToList();
- // First, compute the new incarnations
- foreach (IdentifierExpr ie in havocVars) {
- Contract.Assert(ie != null);
- if (!(ie.Decl is Incarnation)) {
- Variable x = cce.NonNull(ie.Decl);
- Variable x_prime = CreateIncarnation(x, c);
- incarnationMap[x] = new IdentifierExpr(x_prime.tok, x_prime);
- }
- }
- // Then, perform the assume of the where clauses, using the updated incarnations
- Substitution updatedIncarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
- foreach (IdentifierExpr ie in havocVars) {
- Contract.Assert(ie != null);
- if (!(ie.Decl is Incarnation)) {
- Variable x = cce.NonNull(ie.Decl);
- Bpl.Expr w = x.TypedIdent.WhereExpr;
- if (w != null) {
- Expr copy = Substituter.ApplyReplacingOldExprs(updatedIncarnationSubst, oldFrameSubst, w);
- passiveCmds.Add(new AssumeCmd(c.tok, copy));
- }
- }
- }
-
- // Add the following assume-statement for each assumption variable 'v', where 'v_post' is the new incarnation and 'v_pre' is the old one:
- // assume v_post ==> v_pre;
- foreach (IdentifierExpr ie in havocVars)
- {
- if (QKeyValue.FindBoolAttribute(ie.Decl.Attributes, "assumption"))
- {
- var preInc = (Expr)(preHavocIncarnationMap[ie.Decl].Clone());
- var postInc = (Expr)(incarnationMap[ie.Decl].Clone());
- passiveCmds.Add(new AssumeCmd(c.tok, Expr.Imp(postInc, preInc)));
- }
- }
- }
- #endregion
- else if (c is CommentCmd) {
- // comments are just for debugging and don't affect verification
- } else if (c is SugaredCmd) {
- SugaredCmd sug = (SugaredCmd)c;
- Contract.Assert(sug != null);
- Cmd cmd = sug.Desugaring;
- Contract.Assert(cmd != null);
- TurnIntoPassiveCmd(cmd, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, containingBlock);
- } else if (c is StateCmd) {
- this.preHavocIncarnationMap = null; // we do not need to remeber the previous incarnations
- StateCmd st = (StateCmd)c;
- Contract.Assert(st != null);
- // account for any where clauses among the local variables
- foreach (Variable v in st.Locals) {
- Contract.Assert(v != null);
- Expr w = v.TypedIdent.WhereExpr;
- if (w != null) {
- passiveCmds.Add(new AssumeCmd(v.tok, w));
- }
- }
- // do the sub-commands
- foreach (Cmd s in st.Cmds) {
- Contract.Assert(s != null);
- TurnIntoPassiveCmd(s, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, containingBlock);
- }
- // remove the local variables from the incarnation map
- foreach (Variable v in st.Locals) {
- Contract.Assert(v != null);
- incarnationMap.Remove(v);
- }
- }
- #region There shouldn't be any other types of commands at this point
- else {
- Debug.Fail("Internal Error: Passive transformation handed a command that is not one of assert,assume,havoc,assign.");
- }
- #endregion
-
-
- #region We remember if we have put an havoc statement into a passive form
-
- if (!(c is HavocCmd))
- this.preHavocIncarnationMap = null;
- // else: it has already been set by the case for the HavocCmd
- #endregion
- }
-
- NAryExpr TypedExprEq(Expr e0, Expr e1, bool doNotResolveOverloading = false) {
- Contract.Requires(e0 != null);
- Contract.Requires(e1 != null);
- NAryExpr e = Expr.Eq(e0, e1);
- var fun = e.Fun as IOverloadedAppliable;
- if (fun != null)
- {
- fun.DoNotResolveOverloading = doNotResolveOverloading;
- }
- e.Type = Bpl.Type.Bool;
- e.TypeParameters = SimpleTypeParamInstantiation.EMPTY;
- return e;
- }
-
- /// <summary>
- /// Creates a new block to add to impl.Blocks, where impl is the implementation that contains
- /// succ. Caller must do the add to impl.Blocks.
- /// </summary>
- protected Block CreateBlockBetween(int predIndex, Block succ) {
- Contract.Requires(0 <= predIndex && predIndex < succ.Predecessors.Count);
-
-
- Contract.Requires(succ != null);
- Contract.Ensures(Contract.Result<Block>() != null);
-
- Block pred = cce.NonNull(succ.Predecessors[predIndex]);
-
- string newBlockLabel = pred.Label + "_@2_" + succ.Label;
-
- // successor of newBlock list
- List<String> ls = new List<String>();
- ls.Add(succ.Label);
- List<Block> bs = new List<Block>();
- bs.Add(succ);
-
- Block newBlock = new Block(
- new Token(-17, -4),
- newBlockLabel,
- new List<Cmd>(),
- new GotoCmd(Token.NoToken, ls, bs)
- );
-
- // predecessors of newBlock
- List<Block> ps = new List<Block>();
- ps.Add(pred);
- newBlock.Predecessors = ps;
-
- // fix successors of pred
- #region Change the edge "pred->succ" to "pred->newBlock"
- GotoCmd gtc = (GotoCmd)cce.NonNull(pred.TransferCmd);
- Contract.Assume(gtc.labelTargets != null);
- Contract.Assume(gtc.labelNames != null);
- for (int i = 0, n = gtc.labelTargets.Count; i < n; i++) {
- if (gtc.labelTargets[i] == succ) {
- gtc.labelTargets[i] = newBlock;
- gtc.labelNames[i] = newBlockLabel;
- break;
- }
- }
- #endregion Change the edge "pred->succ" to "pred->newBlock"
-
- // fix predecessors of succ
- succ.Predecessors[predIndex] = newBlock;
-
- return newBlock;
- }
-
- protected void AddBlocksBetween(List<Block> blocks) {
- Contract.Requires(blocks != null);
- #region Introduce empty blocks between join points and their multi-successor predecessors
- List<Block> tweens = new List<Block>();
- foreach (Block b in blocks) {
- int nPreds = b.Predecessors.Count;
- if (nPreds > 1) {
- // b is a join point (i.e., it has more than one predecessor)
- for (int i = 0; i < nPreds; i++) {
- GotoCmd gotocmd = (GotoCmd)(cce.NonNull(b.Predecessors[i]).TransferCmd);
- if (gotocmd.labelNames != null && gotocmd.labelNames.Count > 1) {
- tweens.Add(CreateBlockBetween(i, b));
- }
- }
- }
- }
- blocks.AddRange(tweens); // must wait until iteration is done before changing the list
- #endregion
- }
-
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposed)
- {
- if (disposing)
- {
- Close();
- }
- _disposed = true;
- }
- }
-
- public int Cores { get; set; }
- }
-
- public class ModelViewInfo
- {
- public readonly List<Variable> AllVariables = new List<Variable>();
- public readonly List<Mapping> CapturePoints = new List<Mapping>();
- public static readonly Function MVState_FunctionDef = new Function(Token.NoToken, "$mv_state",
- new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Int), true),
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Int), true) },
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Bool), false));
- public static readonly Constant MVState_ConstantDef = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "$mv_state_const", Bpl.Type.Int));
-
- public ModelViewInfo(Program program, Implementation impl) {
- Contract.Requires(program != null);
- Contract.Requires(impl != null);
-
- // global variables
- lock (program.TopLevelDeclarations)
- {
- foreach (var v in program.Variables)
- {
- if (!(v is Constant))
- {
- AllVariables.Add(v);
- }
- }
- }
- // implementation parameters
- foreach (Variable p in impl.InParams) {
- AllVariables.Add(p);
- }
- foreach (Variable p in impl.OutParams) {
- AllVariables.Add(p);
- }
- // implementation locals
- foreach (Variable v in impl.LocVars) {
- AllVariables.Add(v);
- }
- }
-
- public ModelViewInfo(CodeExpr codeExpr) {
- Contract.Requires(codeExpr != null);
- // TODO: also need all variables of enclosing scopes (the global variables of the program, the parameters
- // and perhaps locals of the implementation (if any), any enclosing code expressions).
-
- foreach (Variable v in codeExpr.LocVars) {
- AllVariables.Add(v);
- }
- }
-
- public class Mapping
- {
- public readonly string Description;
- public readonly Dictionary<Variable, Expr> IncarnationMap;
- public Mapping(string description, Dictionary<Variable, Expr> incarnationMap) {
- Description = description;
- IncarnationMap = incarnationMap;
- }
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Linq;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+using System.IO;
+using Microsoft.Boogie;
+using Microsoft.Boogie.GraphUtil;
+using System.Diagnostics.Contracts;
+using Microsoft.Basetypes;
+using Microsoft.Boogie.VCExprAST;
+using Set = Microsoft.Boogie.GSet<object>;
+
+namespace Microsoft.Boogie {
+
+ public class CalleeCounterexampleInfo {
+ public Counterexample counterexample;
+ public List<object>/*!>!*/ args;
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(args));
+ }
+
+ public CalleeCounterexampleInfo(Counterexample cex, List<object/*!>!*/> x)
+ {
+ Contract.Requires(cce.NonNullElements(x));
+ counterexample = cex;
+ args = x;
+ }
+ }
+
+ public class TraceLocation : IEquatable<TraceLocation>
+ {
+ public int numBlock;
+ public int numInstr;
+
+ public TraceLocation(int numBlock, int numInstr)
+ {
+ this.numBlock = numBlock;
+ this.numInstr = numInstr;
+ }
+
+ public override bool Equals(object obj)
+ {
+ TraceLocation that = obj as TraceLocation;
+ if (that == null) return false;
+ return (numBlock == that.numBlock && numInstr == that.numInstr);
+ }
+
+ public bool Equals(TraceLocation that)
+ {
+ return (numBlock == that.numBlock && numInstr == that.numInstr);
+ }
+
+ public override int GetHashCode()
+ {
+ return numBlock.GetHashCode() ^ 131 * numInstr.GetHashCode();
+ }
+ }
+
+ public abstract class Counterexample {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Trace != null);
+ Contract.Invariant(Context != null);
+ Contract.Invariant(cce.NonNullElements(relatedInformation));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(calleeCounterexamples));
+ }
+
+ [Peer]
+ public List<Block> Trace;
+ public Model Model;
+ public VC.ModelViewInfo MvInfo;
+ public ProverContext Context;
+ [Peer]
+ public List<string>/*!>!*/ relatedInformation;
+ public string OriginalRequestId;
+ public string RequestId;
+ public abstract byte[] Checksum { get; }
+ public byte[] SugaredCmdChecksum;
+
+ public Dictionary<TraceLocation, CalleeCounterexampleInfo> calleeCounterexamples;
+
+ internal Counterexample(List<Block> trace, Model model, VC.ModelViewInfo mvInfo, ProverContext context) {
+ Contract.Requires(trace != null);
+ Contract.Requires(context != null);
+ this.Trace = trace;
+ this.Model = model;
+ this.MvInfo = mvInfo;
+ this.Context = context;
+ this.relatedInformation = new List<string>();
+ this.calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
+ }
+
+ // Create a shallow copy of the counterexample
+ public abstract Counterexample Clone();
+
+ public void AddCalleeCounterexample(TraceLocation loc, CalleeCounterexampleInfo cex)
+ {
+ Contract.Requires(cex != null);
+ calleeCounterexamples[loc] = cex;
+ }
+
+ public void AddCalleeCounterexample(int numBlock, int numInstr, CalleeCounterexampleInfo cex)
+ {
+ Contract.Requires(cex != null);
+ calleeCounterexamples[new TraceLocation(numBlock, numInstr)] = cex;
+ }
+
+ public void AddCalleeCounterexample(Dictionary<TraceLocation, CalleeCounterexampleInfo> cs)
+ {
+ Contract.Requires(cce.NonNullDictionaryAndValues(cs));
+ foreach (TraceLocation loc in cs.Keys)
+ {
+ AddCalleeCounterexample(loc, cs[loc]);
+ }
+ }
+
+ // Looks up the Cmd at a given index into the trace
+ public Cmd getTraceCmd(TraceLocation loc)
+ {
+ Debug.Assert(loc.numBlock < Trace.Count);
+ Block b = Trace[loc.numBlock];
+ Debug.Assert(loc.numInstr < b.Cmds.Count);
+ return b.Cmds[loc.numInstr];
+ }
+
+ // Looks up the name of the called procedure.
+ // Asserts that the name exists
+ public string getCalledProcName(Cmd cmd)
+ {
+ // There are two options:
+ // 1. cmd is a CallCmd
+ // 2. cmd is an AssumeCmd (passified version of a CallCmd)
+ if(cmd is CallCmd) {
+ return (cmd as CallCmd).Proc.Name;
+ }
+ AssumeCmd assumeCmd = cmd as AssumeCmd;
+ Debug.Assert(assumeCmd != null);
+
+ NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
+ Debug.Assert(naryExpr != null);
+
+ return naryExpr.Fun.FunctionName;
+ }
+
+ public void Print(int indent, TextWriter tw, Action<Block> blockAction = null) {
+ int numBlock = -1;
+ string ind = new string(' ', indent);
+ foreach (Block b in Trace) {
+ Contract.Assert(b != null);
+ numBlock++;
+ if (b.tok == null) {
+ tw.WriteLine("{0}<intermediate block>", ind);
+ } else {
+ // for ErrorTrace == 1 restrict the output;
+ // do not print tokens with -17:-4 as their location because they have been
+ // introduced in the translation and do not give any useful feedback to the user
+ if (!(CommandLineOptions.Clo.ErrorTrace == 1 && b.tok.line == -17 && b.tok.col == -4)) {
+ if (blockAction != null)
+ {
+ blockAction(b);
+ }
+
+ tw.WriteLine("{4}{0}({1},{2}): {3}", b.tok.filename, b.tok.line, b.tok.col, b.Label, ind);
+
+ for (int numInstr = 0; numInstr < b.Cmds.Count; numInstr++)
+ {
+ var loc = new TraceLocation(numBlock, numInstr);
+ if (calleeCounterexamples.ContainsKey(loc))
+ {
+ var cmd = getTraceCmd(loc);
+ var calleeName = getCalledProcName(cmd);
+ if (calleeName.StartsWith(VC.StratifiedVCGen.recordProcName) && CommandLineOptions.Clo.StratifiedInlining > 0)
+ {
+ Contract.Assert(calleeCounterexamples[loc].args.Count == 1);
+ var arg = calleeCounterexamples[loc].args[0];
+ tw.WriteLine("{0}value = {1}", ind, arg.ToString());
+ }
+ else
+ {
+ tw.WriteLine("{1}Inlined call to procedure {0} begins", calleeName, ind);
+ calleeCounterexamples[loc].counterexample.Print(indent + 4, tw);
+ tw.WriteLine("{1}Inlined call to procedure {0} ends", calleeName, ind);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static bool firstModelFile = true;
+
+ public bool ModelHasStatesAlready = false;
+
+ public void PrintModel(TextWriter tw)
+ {
+ var filename = CommandLineOptions.Clo.ModelViewFile;
+ if (Model == null || filename == null || CommandLineOptions.Clo.StratifiedInlining > 0) return;
+
+ if (!ModelHasStatesAlready) {
+ PopulateModelWithStates();
+ ModelHasStatesAlready = true;
+ }
+
+ if (filename == "-") {
+ Model.Write(tw);
+ tw.Flush();
+ } else {
+ using (var wr = new StreamWriter(filename, !firstModelFile)) {
+ firstModelFile = false;
+ Model.Write(wr);
+ }
+ }
+ }
+
+ void ApplyRedirections(Model m) {
+ var mapping = new Dictionary<Model.Element, Model.Element>();
+ foreach (var name in new string[] { "U_2_bool", "U_2_int" }) {
+ Model.Func f = m.TryGetFunc(name);
+ if (f != null && f.Arity == 1) {
+ foreach (var ft in f.Apps) mapping[ft.Args[0]] = ft.Result;
+ }
+ }
+ m.Substitute(mapping);
+ }
+
+ public void PopulateModelWithStates()
+ {
+ Contract.Requires(Model != null);
+
+ Model m = Model;
+ ApplyRedirections(m);
+
+ var mvstates = m.TryGetFunc("$mv_state");
+ if (MvInfo == null || mvstates == null || (mvstates.Arity == 1 && mvstates.Apps.Count() == 0))
+ return;
+
+ Contract.Assert(mvstates.Arity == 2);
+
+ foreach (Variable v in MvInfo.AllVariables) {
+ m.InitialState.AddBinding(v.Name, GetModelValue(m, v));
+ }
+
+ var states = new List<int>();
+ foreach (var t in mvstates.Apps)
+ states.Add(t.Args[1].AsInt());
+
+ states.Sort();
+
+ for (int i = 0; i < states.Count; ++i) {
+ var s = states[i];
+ if (0 <= s && s < MvInfo.CapturePoints.Count) {
+ VC.ModelViewInfo.Mapping map = MvInfo.CapturePoints[s];
+ var prevInc = i > 0 ? MvInfo.CapturePoints[states[i - 1]].IncarnationMap : new Dictionary<Variable, Expr>();
+ var cs = m.MkState(map.Description);
+
+ foreach (Variable v in MvInfo.AllVariables) {
+ Expr e = map.IncarnationMap.ContainsKey(v) ? map.IncarnationMap[v] : null;
+ if (e == null) continue;
+
+ Expr prevIncV = prevInc.ContainsKey(v) ? prevInc[v] : null;
+ if (prevIncV == e) continue; // skip unchanged variables
+
+ Model.Element elt;
+
+ if (e is IdentifierExpr) {
+ IdentifierExpr ide = (IdentifierExpr)e;
+ elt = GetModelValue(m, ide.Decl);
+ } else if (e is LiteralExpr) {
+ LiteralExpr lit = (LiteralExpr)e;
+ elt = m.MkElement(lit.Val.ToString());
+ } else {
+ elt = m.MkFunc(e.ToString(), 0).GetConstant();
+ }
+
+ cs.AddBinding(v.Name, elt);
+ }
+
+ } else {
+ Contract.Assume(false);
+ }
+ }
+ }
+
+ private Model.Element GetModelValue(Model m, Variable v) {
+ Model.Element elt;
+ // first, get the unique name
+ string uniqueName;
+ VCExprVar vvar = Context.BoogieExprTranslator.TryLookupVariable(v);
+ if (vvar == null) {
+ uniqueName = v.Name;
+ } else {
+ uniqueName = Context.Lookup(vvar);
+ }
+
+ var f = m.TryGetFunc(uniqueName);
+ if (f == null) {
+ f = m.MkFunc(uniqueName, 0);
+ }
+ elt = f.GetConstant();
+ return elt;
+ }
+
+ public abstract int GetLocation();
+ }
+
+ public class CounterexampleComparer : IComparer<Counterexample> {
+
+ private int Compare(List<Block> bs1, List<Block> bs2)
+ {
+ if (bs1.Count < bs2.Count)
+ {
+ return -1;
+ }
+ else if (bs2.Count < bs1.Count)
+ {
+ return 1;
+ }
+
+ for (int i = 0; i < bs1.Count; i++)
+ {
+ var b1 = bs1[i];
+ var b2 = bs2[i];
+ if (b1.tok.pos < b2.tok.pos)
+ {
+ return -1;
+ }
+ else if (b2.tok.pos < b1.tok.pos)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ public int Compare(Counterexample c1, Counterexample c2)
+ {
+ //Contract.Requires(c1 != null);
+ //Contract.Requires(c2 != null);
+ if (c1.GetLocation() == c2.GetLocation())
+ {
+ var c = Compare(c1.Trace, c2.Trace);
+ if (c != 0)
+ {
+ return c;
+ }
+ // TODO(wuestholz): Generalize this to compare all IPotentialErrorNodes of the counterexample.
+ var a1 = c1 as AssertCounterexample;
+ var a2 = c2 as AssertCounterexample;
+ if (a1 != null && a2 != null)
+ {
+ var s1 = a1.FailingAssert.ErrorData as string;
+ var s2 = a2.FailingAssert.ErrorData as string;
+ if (s1 != null && s2 != null)
+ {
+ return s1.CompareTo(s2);
+ }
+ }
+
+ return 0;
+ }
+ if (c1.GetLocation() > c2.GetLocation())
+ {
+ return 1;
+ }
+ return -1;
+ }
+ }
+
+ public class AssertCounterexample : Counterexample {
+ [Peer]
+ public AssertCmd FailingAssert;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(FailingAssert != null);
+ }
+
+
+ public AssertCounterexample(List<Block> trace, AssertCmd failingAssert, Model model, VC.ModelViewInfo mvInfo, ProverContext context)
+ : base(trace, model, mvInfo, context) {
+ Contract.Requires(trace != null);
+ Contract.Requires(failingAssert != null);
+ Contract.Requires(context != null);
+ this.FailingAssert = failingAssert;
+ }
+
+ public override int GetLocation() {
+ return FailingAssert.tok.line * 1000 + FailingAssert.tok.col;
+ }
+
+ public override byte[] Checksum
+ {
+ get { return FailingAssert.Checksum; }
+ }
+
+ public override Counterexample Clone()
+ {
+ var ret = new AssertCounterexample(Trace, FailingAssert, Model, MvInfo, Context);
+ ret.calleeCounterexamples = calleeCounterexamples;
+ return ret;
+ }
+ }
+
+ public class CallCounterexample : Counterexample {
+ public CallCmd FailingCall;
+ public Requires FailingRequires;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(FailingCall != null);
+ Contract.Invariant(FailingRequires != null);
+ }
+
+
+ public CallCounterexample(List<Block> trace, CallCmd failingCall, Requires failingRequires, Model model, VC.ModelViewInfo mvInfo, ProverContext context, byte[] checksum = null)
+ : base(trace, model, mvInfo, context) {
+ Contract.Requires(!failingRequires.Free);
+ Contract.Requires(trace != null);
+ Contract.Requires(context != null);
+ Contract.Requires(failingCall != null);
+ Contract.Requires(failingRequires != null);
+ this.FailingCall = failingCall;
+ this.FailingRequires = failingRequires;
+ this.checksum = checksum;
+ this.SugaredCmdChecksum = failingCall.Checksum;
+ }
+
+ public override int GetLocation() {
+ return FailingCall.tok.line * 1000 + FailingCall.tok.col;
+ }
+
+ byte[] checksum;
+ public override byte[] Checksum
+ {
+ get { return checksum; }
+ }
+
+ public override Counterexample Clone()
+ {
+ var ret = new CallCounterexample(Trace, FailingCall, FailingRequires, Model, MvInfo, Context, Checksum);
+ ret.calleeCounterexamples = calleeCounterexamples;
+ return ret;
+ }
+ }
+
+ public class ReturnCounterexample : Counterexample {
+ public TransferCmd FailingReturn;
+ public Ensures FailingEnsures;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(FailingEnsures != null);
+ Contract.Invariant(FailingReturn != null);
+ }
+
+
+ public ReturnCounterexample(List<Block> trace, TransferCmd failingReturn, Ensures failingEnsures, Model model, VC.ModelViewInfo mvInfo, ProverContext context, byte[] checksum)
+ : base(trace, model, mvInfo, context) {
+ Contract.Requires(trace != null);
+ Contract.Requires(context != null);
+ Contract.Requires(failingReturn != null);
+ Contract.Requires(failingEnsures != null);
+ Contract.Requires(!failingEnsures.Free);
+ this.FailingReturn = failingReturn;
+ this.FailingEnsures = failingEnsures;
+ this.checksum = checksum;
+ }
+
+ public override int GetLocation() {
+ return FailingReturn.tok.line * 1000 + FailingReturn.tok.col;
+ }
+
+ byte[] checksum;
+
+ /// <summary>
+ /// Returns the checksum of the corresponding assertion.
+ /// </summary>
+ public override byte[] Checksum
+ {
+ get
+ {
+ return checksum;
+ }
+ }
+
+ public override Counterexample Clone()
+ {
+ var ret = new ReturnCounterexample(Trace, FailingReturn, FailingEnsures, Model, MvInfo, Context, checksum);
+ ret.calleeCounterexamples = calleeCounterexamples;
+ return ret;
+ }
+ }
+
+ public class VerifierCallback {
+ // reason == null means this is genuine counterexample returned by the prover
+ // other reason means it's time out/memory out/crash
+ public virtual void OnCounterexample(Counterexample ce, string/*?*/ reason) {
+ Contract.Requires(ce != null);
+ }
+
+ // called in case resource is exceeded and we don't have counterexample
+ public virtual void OnTimeout(string reason) {
+ Contract.Requires(reason != null);
+ }
+
+ public virtual void OnOutOfMemory(string reason) {
+ Contract.Requires(reason != null);
+ }
+
+ public virtual void OnProgress(string phase, int step, int totalSteps, double progressEstimate) {
+ }
+
+ public virtual void OnUnreachableCode(Implementation impl) {
+ Contract.Requires(impl != null);
+ }
+
+ public virtual void OnWarning(string msg) {
+ Contract.Requires(msg != null);
+ switch (CommandLineOptions.Clo.PrintProverWarnings) {
+ case CommandLineOptions.ProverWarnings.None:
+ break;
+ case CommandLineOptions.ProverWarnings.Stdout:
+ Console.WriteLine("Prover warning: " + msg);
+ break;
+ case CommandLineOptions.ProverWarnings.Stderr:
+ Console.Error.WriteLine("Prover warning: " + msg);
+ break;
+ default:
+ Contract.Assume(false);
+ throw new cce.UnreachableException(); // unexpected case
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////
+
+namespace VC {
+ using Bpl = Microsoft.Boogie;
+
+ public class VCGenException : Exception {
+ public VCGenException(string s)
+ : base(s) {
+ }
+ }
+ [ContractClassFor(typeof(ConditionGeneration))]
+ public abstract class ConditionGenerationContracts : ConditionGeneration {
+ public override Outcome VerifyImplementation(Implementation impl, VerifierCallback callback) {
+ Contract.Requires(impl != null);
+ Contract.Requires(callback != null);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ throw new NotImplementedException();
+ }
+ public ConditionGenerationContracts(Program p, List<Checker> checkers)
+ : base(p, checkers) {
+ }
+ }
+
+ [ContractClass(typeof(ConditionGenerationContracts))]
+ public abstract class ConditionGeneration : IDisposable {
+ protected internal object CheckerCommonState;
+
+ public enum Outcome {
+ Correct,
+ Errors,
+ TimedOut,
+ OutOfMemory,
+ Inconclusive,
+ ReachedBound
+ }
+
+ public static Outcome ProverInterfaceOutcomeToConditionGenerationOutcome(ProverInterface.Outcome outcome) {
+ switch (outcome) {
+ case ProverInterface.Outcome.Invalid:
+ return Outcome.Errors;
+ case ProverInterface.Outcome.OutOfMemory:
+ return Outcome.OutOfMemory;
+ case ProverInterface.Outcome.TimeOut:
+ return Outcome.TimedOut;
+ case ProverInterface.Outcome.Undetermined:
+ return Outcome.Inconclusive;
+ case ProverInterface.Outcome.Valid:
+ return Outcome.Correct;
+ }
+ return Outcome.Inconclusive; // unreachable but the stupid compiler does not understand
+ }
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(checkers));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(incarnationOriginMap));
+ Contract.Invariant(program != null);
+ }
+
+ public int CumulativeAssertionCount; // for statistics
+
+ protected readonly List<Checker>/*!>!*/ checkers;
+
+ private bool _disposed;
+
+ protected Implementation currentImplementation;
+
+ protected List<Variable> CurrentLocalVariables = null;
+
+ // shared across each implementation; created anew for each implementation
+ protected Dictionary<Variable, int> variable2SequenceNumber;
+ public Dictionary<Incarnation, Absy>/*!>!*/ incarnationOriginMap = new Dictionary<Incarnation, Absy>();
+
+ public Program program;
+ protected string/*?*/ logFilePath;
+ protected bool appendLogFile;
+
+ public static List<Model> errorModelList;
+
+ public ConditionGeneration(Program p, List<Checker> checkers) {
+ Contract.Requires(p != null && checkers != null && cce.NonNullElements(checkers));
+ program = p;
+ this.checkers = checkers;
+ Cores = 1;
+ }
+
+ /// <summary>
+ /// Takes an implementation and constructs a verification condition and sends
+ /// it to the theorem prover.
+ /// Returns null if "impl" is correct. Otherwise, returns a list of counterexamples,
+ /// each counterexample consisting of an array of labels.
+ /// </summary>
+ /// <param name="impl"></param>
+ public Outcome VerifyImplementation(Implementation impl, out List<Counterexample>/*?*/ errors, string requestId = null) {
+ Contract.Requires(impl != null);
+
+ Contract.Ensures(Contract.ValueAtReturn(out errors) == null || Contract.ForAll(Contract.ValueAtReturn(out errors), i => i != null));
+ Contract.Ensures(Contract.Result<Outcome>() != Outcome.Errors || errors != null);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ Helpers.ExtraTraceInformation("Starting implementation verification");
+
+ CounterexampleCollector collector = new CounterexampleCollector();
+ collector.RequestId = requestId;
+ Outcome outcome = VerifyImplementation(impl, collector);
+ if (outcome == Outcome.Errors || outcome == Outcome.TimedOut || outcome == Outcome.OutOfMemory) {
+ errors = collector.examples;
+ } else {
+ errors = null;
+ }
+
+ Helpers.ExtraTraceInformation("Finished implementation verification");
+ return outcome;
+ }
+
+ /// <summary>
+ /// Takes an implementation and constructs a verification condition and sends
+ /// it to the theorem prover.
+ /// Returns null if "impl" is correct. Otherwise, returns a list of counterexamples,
+ /// each counterexample consisting of an array of labels.
+ /// </summary>
+ /// <param name="impl"></param>
+ public Outcome VerifyImplementation(Implementation impl, out List<Counterexample> errors, out List<Model> errorsModel)
+ {
+ Contract.Ensures(Contract.Result<Outcome>() != Outcome.Errors || Contract.ValueAtReturn(out errors) != null);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ List<Counterexample> errorsOut;
+
+ Outcome outcome;
+ errorModelList = new List<Model>();
+ outcome = VerifyImplementation(impl, out errorsOut);
+ errors = errorsOut;
+ errorsModel = errorModelList;
+
+ return outcome;
+ }
+
+ public abstract Outcome VerifyImplementation(Implementation impl, VerifierCallback callback);
+
+ /////////////////////////////////// Common Methods and Classes //////////////////////////////////////////
+
+ #region Methods for injecting pre- and postconditions
+ private static void
+ ThreadInCodeExpr(Implementation impl,
+ Block targetBlock,
+ CodeExpr codeExpr,
+ bool replaceWithAssert,
+ TokenTextWriter debugWriter) {
+ Contract.Requires(impl != null);
+ Contract.Requires(codeExpr != null);
+ Contract.Requires(targetBlock != null);
+ // Go through codeExpr and for all blocks that have a "return e"
+ // as their transfer command:
+ // Replace all "return e" with "assert/assume e"
+ // Change the transfer command to "goto targetBlock"
+ // Then add all of the blocks in codeExpr to the implementation (at the end)
+ foreach (Block b in codeExpr.Blocks) {
+ Contract.Assert(b != null);
+ ReturnExprCmd rec = b.TransferCmd as ReturnExprCmd;
+ if (rec != null) { // otherwise it is a goto command
+ if (replaceWithAssert) {
+ Ensures ens = new Ensures(rec.tok, false, rec.Expr, null);
+ Contract.Assert(ens != null);
+ Cmd c = new AssertEnsuresCmd(ens);
+ Contract.Assert(c != null);
+ b.Cmds.Add(c);
+ } else {
+ b.Cmds.Add(new AssumeCmd(rec.tok, rec.Expr));
+ }
+ b.TransferCmd = new GotoCmd(Token.NoToken,
+ new List<String> { targetBlock.Label },
+ new List<Block> { targetBlock });
+ targetBlock.Predecessors.Add(b);
+ }
+ impl.Blocks.Add(b);
+ }
+ if (debugWriter != null) {
+ codeExpr.Emit(debugWriter, 1, false);
+ }
+ return;
+ }
+
+ private static void AddAsPrefix(Block b, List<Cmd> cs) {
+ Contract.Requires(b != null);
+ Contract.Requires(cs != null);
+ List<Cmd> newCommands = new List<Cmd>();
+ newCommands.AddRange(cs);
+ newCommands.AddRange(b.Cmds);
+ b.Cmds = newCommands;
+ }
+
+
+ /// <summary>
+ /// Modifies an implementation by prepending it with startCmds and then, as assume
+ /// statements, all preconditions. Insert new blocks as needed, and adjust impl.Blocks[0]
+ /// accordingly to make it the new implementation entry block.
+ /// </summary>
+ /// <param name="impl"></param>
+ /// <param name="startCmds"></param>
+ protected static void InjectPreconditions(Implementation impl, [Captured] List<Cmd> startCmds) {
+ Contract.Requires(impl != null);
+ Contract.Requires(startCmds != null);
+ Contract.Requires(impl.Proc != null);
+
+ TokenTextWriter debugWriter = null;
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
+ debugWriter.WriteLine("Effective precondition:");
+ }
+
+ Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
+ string blockLabel = "PreconditionGeneratedEntry";
+
+ Block origStartBlock = impl.Blocks[0];
+ Block insertionPoint = new Block(
+ new Token(-17, -4), blockLabel, startCmds,
+ new GotoCmd(Token.NoToken, new List<String> { origStartBlock.Label }, new List<Block> { origStartBlock }));
+
+ impl.Blocks[0] = insertionPoint; // make insertionPoint the start block
+ impl.Blocks.Add(origStartBlock); // and put the previous start block at the end of the list
+
+ // (free and checked) requires clauses
+ foreach (Requires req in impl.Proc.Requires)
+ // invariant: insertionPoint.TransferCmd is "goto origStartBlock;", but origStartBlock.Predecessors has not yet been updated
+ {
+ Contract.Assert(req != null);
+ Expr e = Substituter.Apply(formalProcImplSubst, req.Condition);
+ Cmd c = new AssumeCmd(req.tok, e);
+ c.IrrelevantForChecksumComputation = true;
+ insertionPoint.Cmds.Add(c);
+ if (debugWriter != null) {
+ c.Emit(debugWriter, 1);
+ }
+ }
+ origStartBlock.Predecessors.Add(insertionPoint);
+
+ if (impl.ExplicitAssumptionAboutCachedPrecondition != null)
+ {
+ insertionPoint.Cmds.Add(impl.ExplicitAssumptionAboutCachedPrecondition);
+ }
+
+ if (debugWriter != null) {
+ debugWriter.WriteLine();
+ }
+ }
+ /// <summary>
+ /// Modifies an implementation by inserting all postconditions
+ /// as assert statements at the end of the implementation
+ /// Returns the possibly-new unified exit block of the implementation
+ /// </summary>
+ /// <param name="impl"></param>
+ /// <param name="unifiedExitblock">The unified exit block that has
+ /// already been constructed for the implementation (and so
+ /// is already an element of impl.Blocks)
+ /// </param>
+ protected static void InjectPostConditions(Implementation impl, Block unifiedExitBlock, Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins) {
+ Contract.Requires(impl != null);
+ Contract.Requires(unifiedExitBlock != null);
+ Contract.Requires(gotoCmdOrigins != null);
+ Contract.Requires(impl.Proc != null);
+ Contract.Requires(unifiedExitBlock.TransferCmd is ReturnCmd);
+
+ TokenTextWriter debugWriter = null;
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
+ debugWriter.WriteLine("Effective postcondition:");
+ }
+
+ Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
+
+ // (free and checked) ensures clauses
+ foreach (Ensures ens in impl.Proc.Ensures) {
+ Contract.Assert(ens != null);
+ if (!ens.Free) { // skip free ensures clauses
+ Expr e = Substituter.Apply(formalProcImplSubst, ens.Condition);
+ Ensures ensCopy = (Ensures)cce.NonNull(ens.Clone());
+ ensCopy.Condition = e;
+ AssertEnsuresCmd c = new AssertEnsuresCmd(ensCopy);
+ c.ErrorDataEnhanced = ensCopy.ErrorDataEnhanced;
+ unifiedExitBlock.Cmds.Add(c);
+ if (debugWriter != null) {
+ c.Emit(debugWriter, 1);
+ }
+ }
+ }
+
+ if (debugWriter != null) {
+ debugWriter.WriteLine();
+ }
+ }
+
+
+ /// <summary>
+ /// Get the pre-condition of an implementation, including the where clauses from the in-parameters.
+ /// </summary>
+ /// <param name="impl"></param>
+ protected static List<Cmd> GetPre(Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+
+
+ TokenTextWriter debugWriter = null;
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
+ debugWriter.WriteLine("Effective precondition:");
+ }
+
+ Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
+ List<Cmd> pre = new List<Cmd>();
+
+ // (free and checked) requires clauses
+ foreach (Requires req in impl.Proc.Requires) {
+ Contract.Assert(req != null);
+ Expr e = Substituter.Apply(formalProcImplSubst, req.Condition);
+ Contract.Assert(e != null);
+ Cmd c = new AssumeCmd(req.tok, e);
+ Contract.Assert(c != null);
+ pre.Add(c);
+
+ if (debugWriter != null) {
+ c.Emit(debugWriter, 1);
+ }
+ }
+
+ if (debugWriter != null) {
+ debugWriter.WriteLine();
+ }
+
+ return pre;
+ }
+
+ /// <summary>
+ /// Get the post-condition of an implementation.
+ /// </summary>
+ /// <param name="impl"></param>
+ protected static List<Cmd> GetPost(Implementation impl) {
+
+
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ Console.WriteLine("Effective postcondition:");
+ }
+
+ // Construct an Expr for the post-condition
+ Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
+ List<Cmd> post = new List<Cmd>();
+ foreach (Ensures ens in impl.Proc.Ensures) {
+ Contract.Assert(ens != null);
+ if (!ens.Free) {
+ Expr e = Substituter.Apply(formalProcImplSubst, ens.Condition);
+ Contract.Assert(e != null);
+ Ensures ensCopy = cce.NonNull((Ensures)ens.Clone());
+ ensCopy.Condition = e;
+ Cmd c = new AssertEnsuresCmd(ensCopy);
+ ((AssertEnsuresCmd)c).ErrorDataEnhanced = ensCopy.ErrorDataEnhanced;
+ post.Add(c);
+
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ c.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 1);
+ }
+ }
+ }
+
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ Console.WriteLine();
+ }
+
+ return post;
+ }
+
+ /// <summary>
+ /// Get the where clauses from the in- and out-parameters as
+ /// a sequence of assume commands.
+ /// As a side effect, this method adds these where clauses to the out parameters.
+ /// </summary>
+ /// <param name="impl"></param>
+ protected static List<Cmd> GetParamWhereClauses(Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+ TokenTextWriter debugWriter = null;
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
+ debugWriter.WriteLine("Effective precondition from where-clauses:");
+ }
+
+ Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
+ List<Cmd> whereClauses = new List<Cmd>();
+
+ // where clauses of in-parameters
+ foreach (Formal f in impl.Proc.InParams) {
+ Contract.Assert(f != null);
+ if (f.TypedIdent.WhereExpr != null) {
+ Expr e = Substituter.Apply(formalProcImplSubst, f.TypedIdent.WhereExpr);
+ Cmd c = new AssumeCmd(f.tok, e);
+ whereClauses.Add(c);
+
+ if (debugWriter != null) {
+ c.Emit(debugWriter, 1);
+ }
+ }
+ }
+
+ // where clauses of out-parameters
+ Contract.Assert(impl.OutParams.Count == impl.Proc.OutParams.Count);
+ for (int i = 0; i < impl.OutParams.Count; i++) {
+ Variable f = cce.NonNull(impl.Proc.OutParams[i]);
+ if (f.TypedIdent.WhereExpr != null) {
+ Expr e = Substituter.Apply(formalProcImplSubst, f.TypedIdent.WhereExpr);
+ Cmd c = new AssumeCmd(f.tok, e);
+ whereClauses.Add(c);
+
+ Variable fi = cce.NonNull(impl.OutParams[i]);
+ Contract.Assume(fi.TypedIdent.WhereExpr == null);
+ fi.TypedIdent.WhereExpr = e;
+
+ if (debugWriter != null) {
+ c.Emit(debugWriter, 1);
+ }
+ }
+ }
+
+ if (debugWriter != null) {
+ debugWriter.WriteLine();
+ }
+
+ return whereClauses;
+ }
+
+ protected static void RestoreParamWhereClauses(Implementation impl) {
+ Contract.Requires(impl != null);
+ // We no longer need the where clauses on the out parameters, so we remove them to restore the situation from before VC generation
+ foreach (Formal f in impl.OutParams) {
+ Contract.Assert(f != null);
+ f.TypedIdent.WhereExpr = null;
+ }
+ }
+ #endregion
+
+
+ protected Checker FindCheckerFor(int timeout, bool isBlocking = true, int waitTimeinMs = 50, int maxRetries = 3)
+ {
+ Contract.Requires(0 <= waitTimeinMs && 0 <= maxRetries);
+ Contract.Ensures(!isBlocking || Contract.Result<Checker>() != null);
+
+ lock (checkers)
+ {
+ retry:
+ // Look for existing checker.
+ for (int i = 0; i < checkers.Count; i++)
+ {
+ var c = checkers[i];
+ if (Monitor.TryEnter(c))
+ {
+ try
+ {
+ if (c.WillingToHandle(timeout, program))
+ {
+ c.GetReady();
+ return c;
+ }
+ else if (c.IsIdle || c.IsClosed)
+ {
+ if (c.IsIdle)
+ {
+ c.Retarget(program, c.TheoremProver.Context, timeout);
+ c.GetReady();
+ return c;
+ }
+ else
+ {
+ checkers.RemoveAt(i);
+ i--;
+ continue;
+ }
+ }
+ }
+ finally
+ {
+ Monitor.Exit(c);
+ }
+ }
+ }
+
+ if (Cores <= checkers.Count)
+ {
+ if (isBlocking || 0 < maxRetries)
+ {
+ if (0 < waitTimeinMs)
+ {
+ Monitor.Wait(checkers, waitTimeinMs);
+ }
+ maxRetries--;
+ goto retry;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ // Create a new checker.
+ string log = logFilePath;
+ if (log != null && !log.Contains("@PROC@") && checkers.Count > 0)
+ {
+ log = log + "." + checkers.Count;
+ }
+ Checker ch = new Checker(this, program, log, appendLogFile, timeout);
+ ch.GetReady();
+ checkers.Add(ch);
+ return ch;
+ }
+ }
+
+
+ virtual public void Close() {
+ }
+
+
+ public class CounterexampleCollector : VerifierCallback {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(examples));
+ }
+
+ public string RequestId;
+
+ public readonly List<Counterexample>/*!>!*/ examples = new List<Counterexample>();
+ public override void OnCounterexample(Counterexample ce, string/*?*/ reason) {
+ //Contract.Requires(ce != null);
+ if (RequestId != null)
+ {
+ ce.RequestId = RequestId;
+ }
+ if (ce.OriginalRequestId == null && 1 < CommandLineOptions.Clo.VerifySnapshots)
+ {
+ ce.OriginalRequestId = RequestId;
+ }
+ examples.Add(ce);
+ }
+
+ public override void OnUnreachableCode(Implementation impl) {
+ //Contract.Requires(impl != null);
+ System.Console.WriteLine("found unreachable code:");
+ EmitImpl(impl, false);
+ // TODO report error about next to last in seq
+ }
+ }
+
+ protected static void EmitImpl(Implementation impl, bool printDesugarings) {
+ Contract.Requires(impl != null);
+ int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured;
+ CommandLineOptions.Clo.PrintUnstructured = 2; // print only the unstructured program
+ bool oldPrintDesugaringSetting = CommandLineOptions.Clo.PrintDesugarings;
+ CommandLineOptions.Clo.PrintDesugarings = printDesugarings;
+ impl.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 0);
+ CommandLineOptions.Clo.PrintDesugarings = oldPrintDesugaringSetting;
+ CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured;
+ }
+
+
+ protected Block GenerateUnifiedExit(Implementation impl, Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins) {
+ Contract.Requires(impl != null);
+ Contract.Requires(gotoCmdOrigins != null);
+ Contract.Ensures(Contract.Result<Block>() != null);
+
+ Contract.Ensures(Contract.Result<Block>().TransferCmd is ReturnCmd);
+ Block/*?*/ exitBlock = null;
+ #region Create a unified exit block, if there's more than one
+ {
+ int returnBlocks = 0;
+ foreach (Block b in impl.Blocks) {
+ if (b.TransferCmd is ReturnCmd) {
+ exitBlock = b;
+ returnBlocks++;
+ }
+ }
+ if (returnBlocks > 1) {
+ string unifiedExitLabel = "GeneratedUnifiedExit";
+ Block unifiedExit = new Block(new Token(-17, -4), unifiedExitLabel, new List<Cmd>(), new ReturnCmd(Token.NoToken));
+ Contract.Assert(unifiedExit != null);
+ foreach (Block b in impl.Blocks) {
+ if (b.TransferCmd is ReturnCmd) {
+ List<String> labels = new List<String>();
+ labels.Add(unifiedExitLabel);
+ List<Block> bs = new List<Block>();
+ bs.Add(unifiedExit);
+ GotoCmd go = new GotoCmd(Token.NoToken, labels, bs);
+ gotoCmdOrigins[go] = (ReturnCmd)b.TransferCmd;
+ b.TransferCmd = go;
+ unifiedExit.Predecessors.Add(b);
+ }
+ }
+
+ exitBlock = unifiedExit;
+ impl.Blocks.Add(unifiedExit);
+ }
+ Contract.Assert(exitBlock != null);
+ }
+ return exitBlock;
+ #endregion
+ }
+
+ protected static void ResetPredecessors(List<Block> blocks) {
+ Contract.Requires(blocks != null);
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ b.Predecessors = new List<Block>();
+ }
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ foreach (Block ch in Exits(b)) {
+ Contract.Assert(ch != null);
+ ch.Predecessors.Add(b);
+ }
+ }
+ }
+
+ protected static IEnumerable Exits(Block b) {
+ Contract.Requires(b != null);
+ GotoCmd g = b.TransferCmd as GotoCmd;
+ if (g != null) {
+ return cce.NonNull(g.labelTargets);
+ }
+ return new List<Block>();
+ }
+
+ protected Variable CreateIncarnation(Variable x, Absy a) {
+ Contract.Requires(this.variable2SequenceNumber != null);
+ Contract.Requires(this.CurrentLocalVariables != null);
+ Contract.Requires(a is Block || a is AssignCmd || a is HavocCmd);
+
+ Contract.Requires(x != null);
+ Contract.Ensures(Contract.Result<Variable>() != null);
+
+ int currentIncarnationNumber =
+ variable2SequenceNumber.ContainsKey(x)
+ ?
+ variable2SequenceNumber[x]
+ :
+ -1;
+ Variable v = new Incarnation(x, currentIncarnationNumber + 1);
+ variable2SequenceNumber[x] = currentIncarnationNumber + 1;
+ CurrentLocalVariables.Add(v);
+ incarnationOriginMap.Add((Incarnation)v, a);
+ return v;
+ }
+
+ /// <summary>
+ /// Compute the incarnation map at the beginning of block "b" from the incarnation blocks of the
+ /// predecessors of "b".
+ ///
+ /// The predecessor map b.map for block "b" is defined as follows:
+ /// b.map.Domain == Union{Block p in b.predecessors; p.map.Domain}
+ /// Forall{Variable v in b.map.Domain;
+ /// b.map[v] == (v in Intersection{Block p in b.predecessors; p.map}.Domain
+ /// ? b.predecessors[0].map[v]
+ /// : new Variable())}
+ /// Every variable that b.map maps to a fresh variable requires a fixup in all predecessor blocks.
+ /// </summary>
+ /// <param name="b"></param>
+ /// <param name="block2Incarnation">Gives incarnation maps for b's predecessors.</param>
+ /// <returns></returns>
+ protected Dictionary<Variable, Expr> ComputeIncarnationMap(Block b, Dictionary<Block, Dictionary<Variable, Expr>> block2Incarnation) {
+ Contract.Requires(b != null);
+ Contract.Requires(block2Incarnation != null);
+ Contract.Ensures(Contract.Result<Dictionary<Variable, Expr>>() != null);
+
+ if (b.Predecessors.Count == 0) {
+ return new Dictionary<Variable, Expr>();
+ }
+
+ Dictionary<Variable, Expr> incarnationMap = null;
+ Set /*Variable*/ fixUps = new Set /*Variable*/ ();
+ foreach (Block pred in b.Predecessors) {
+ Contract.Assert(pred != null);
+ Contract.Assert(block2Incarnation.ContainsKey(pred)); // otherwise, Passive Transformation found a block whose predecessors have not been processed yet
+ Dictionary<Variable, Expr> predMap = (Dictionary<Variable, Expr>)block2Incarnation[pred];
+ Contract.Assert(predMap != null);
+ if (incarnationMap == null) {
+ incarnationMap = new Dictionary<Variable, Expr>(predMap);
+ continue;
+ }
+
+ ArrayList /*Variable*/ conflicts = new ArrayList /*Variable*/ ();
+ foreach (Variable v in incarnationMap.Keys) {
+ Contract.Assert(v != null);
+ if (!predMap.ContainsKey(v)) {
+ // conflict!!
+ conflicts.Add(v);
+ fixUps.Add(v);
+ }
+ }
+ // Now that we're done with enumeration, we'll do all the removes
+ foreach (Variable v in conflicts) {
+ Contract.Assert(v != null);
+ incarnationMap.Remove(v);
+ }
+ foreach (Variable v in predMap.Keys) {
+ Contract.Assert(v != null);
+ if (!incarnationMap.ContainsKey(v)) {
+ // v was not in the domain of the predecessors seen so far, so it needs to be fixed up
+ fixUps.Add(v);
+ } else {
+ // v in incarnationMap ==> all pred blocks (up to now) all agree on its incarnation
+ if (predMap[v] != incarnationMap[v]) {
+ // conflict!!
+ incarnationMap.Remove(v);
+ fixUps.Add(v);
+ }
+ }
+ }
+ }
+
+ #region Second, for all variables in the fixups list, introduce a new incarnation and push it back into the preds.
+ foreach (Variable v in fixUps) {
+ Contract.Assert(v != null);
+ if (!b.IsLive(v))
+ continue;
+ Variable v_prime = CreateIncarnation(v, b);
+ IdentifierExpr ie = new IdentifierExpr(v_prime.tok, v_prime);
+ Contract.Assert(incarnationMap != null);
+ incarnationMap[v] = ie;
+ foreach (Block pred in b.Predecessors) {
+ Contract.Assert(pred != null);
+ #region Create an assume command equating v_prime with its last incarnation in pred
+ #region Create an identifier expression for the last incarnation in pred
+ Dictionary<Variable, Expr> predMap = (Dictionary<Variable, Expr>)cce.NonNull(block2Incarnation[pred]);
+
+ Expr pred_incarnation_exp;
+ Expr o = predMap.ContainsKey(v) ? predMap[v] : null;
+ if (o == null) {
+ Variable predIncarnation = v;
+ IdentifierExpr ie2 = new IdentifierExpr(predIncarnation.tok, predIncarnation);
+ pred_incarnation_exp = ie2;
+ } else {
+ pred_incarnation_exp = o;
+ }
+ #endregion
+ #region Create an identifier expression for the new incarnation
+ IdentifierExpr v_prime_exp = new IdentifierExpr(v_prime.tok, v_prime);
+ #endregion
+ #region Create the assume command itself
+ AssumeCmd ac = new AssumeCmd(v.tok, TypedExprEq(v_prime_exp, pred_incarnation_exp, v_prime.Name.Contains("a##cached##")));
+ pred.Cmds.Add(ac);
+ #endregion
+ #endregion
+ }
+ }
+ #endregion
+
+ Contract.Assert(incarnationMap != null);
+ return incarnationMap;
+ }
+
+ Dictionary<Variable, Expr> preHavocIncarnationMap = null; // null = the previous command was not an HashCmd. Otherwise, a *copy* of the map before the havoc statement
+
+ protected void TurnIntoPassiveBlock(Block b, Dictionary<Variable, Expr> incarnationMap, ModelViewInfo mvInfo, Substitution oldFrameSubst, MutableVariableCollector variableCollector, byte[] currentChecksum = null) {
+ Contract.Requires(b != null);
+ Contract.Requires(incarnationMap != null);
+ Contract.Requires(mvInfo != null);
+ Contract.Requires(oldFrameSubst != null);
+ #region Walk forward over the commands in this block and convert them to passive commands
+
+ List<Cmd> passiveCmds = new List<Cmd>();
+ foreach (Cmd c in b.Cmds) {
+ Contract.Assert(c != null); // walk forward over the commands because the map gets modified in a forward direction
+ ChecksumHelper.ComputeChecksums(c, currentImplementation, variableCollector.UsedVariables, currentChecksum);
+ variableCollector.Visit(c);
+ currentChecksum = c.Checksum;
+ TurnIntoPassiveCmd(c, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, b);
+ }
+ b.Checksum = currentChecksum;
+ b.Cmds = passiveCmds;
+
+ if (b.TransferCmd is ReturnExprCmd) {
+ ReturnExprCmd rec = (ReturnExprCmd)b.TransferCmd.Clone();
+ Substitution incarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
+ rec.Expr = Substituter.ApplyReplacingOldExprs(incarnationSubst, oldFrameSubst, rec.Expr);
+ b.TransferCmd = rec;
+ }
+ #endregion
+ }
+
+ protected Dictionary<Variable, Expr> Convert2PassiveCmd(Implementation impl, ModelViewInfo mvInfo) {
+ Contract.Requires(impl != null);
+ Contract.Requires(mvInfo != null);
+
+ currentImplementation = impl;
+
+ var start = DateTime.UtcNow;
+
+ Dictionary<Variable, Expr> r = ConvertBlocks2PassiveCmd(impl.Blocks, impl.Proc.Modifies, mvInfo);
+
+ var end = DateTime.UtcNow;
+
+ if (CommandLineOptions.Clo.TraceCachingForDebugging)
+ {
+ Console.Out.WriteLine("Turned implementation into passive commands within {0:F0} ms.\n", end.Subtract(start).TotalMilliseconds);
+ }
+
+ if (CommandLineOptions.Clo.TraceCachingForDebugging)
+ {
+ using (var tokTxtWr = new TokenTextWriter("<console>", Console.Out, false, false))
+ {
+ var pd = CommandLineOptions.Clo.PrintDesugarings;
+ var pu = CommandLineOptions.Clo.PrintUnstructured;
+ CommandLineOptions.Clo.PrintDesugarings = true;
+ CommandLineOptions.Clo.PrintUnstructured = 1;
+ impl.Emit(tokTxtWr, 0);
+ CommandLineOptions.Clo.PrintDesugarings = pd;
+ CommandLineOptions.Clo.PrintUnstructured = pu;
+ }
+ }
+
+ currentImplementation = null;
+
+ RestoreParamWhereClauses(impl);
+
+ #region Debug Tracing
+ if (CommandLineOptions.Clo.TraceVerify) {
+ Console.WriteLine("after conversion to passive commands");
+ EmitImpl(impl, true);
+ }
+ #endregion
+
+ return r;
+ }
+
+ protected Dictionary<Variable, Expr> ConvertBlocks2PassiveCmd(List<Block> blocks, List<IdentifierExpr> modifies, ModelViewInfo mvInfo) {
+ Contract.Requires(blocks != null);
+ Contract.Requires(modifies != null);
+ Contract.Requires(mvInfo != null);
+ #region Convert to Passive Commands
+
+ #region Topological sort -- need to process in a linearization of the partial order
+ Graph<Block> dag = new Graph<Block>();
+ dag.AddSource(cce.NonNull(blocks[0])); // there is always at least one node in the graph
+ foreach (Block b in blocks) {
+ GotoCmd gtc = b.TransferCmd as GotoCmd;
+ if (gtc != null) {
+ Contract.Assume(gtc.labelTargets != null);
+ foreach (Block dest in gtc.labelTargets) {
+ Contract.Assert(dest != null);
+ dag.AddEdge(b, dest);
+ }
+ }
+ }
+
+ IEnumerable sortedNodes;
+ if (CommandLineOptions.Clo.ModifyTopologicalSorting) {
+ sortedNodes = dag.TopologicalSort(true);
+ } else {
+ sortedNodes = dag.TopologicalSort();
+ }
+
+ Contract.Assert(sortedNodes != null);
+ #endregion
+
+ Substitution oldFrameSubst = ComputeOldExpressionSubstitution(modifies);
+
+ // Now we can process the nodes in an order so that we're guaranteed to have
+ // processed all of a node's predecessors before we process the node.
+ Dictionary<Block, Dictionary<Variable, Expr>> block2Incarnation = new Dictionary<Block, Dictionary<Variable, Expr>>();
+ Block exitBlock = null;
+ Dictionary<Variable, Expr> exitIncarnationMap = null;
+ var variableCollectors = new Dictionary<Block, MutableVariableCollector>();
+ foreach (Block b in sortedNodes) {
+ Contract.Assert(b != null);
+ Contract.Assert(!block2Incarnation.ContainsKey(b));
+ Dictionary<Variable, Expr> incarnationMap = ComputeIncarnationMap(b, block2Incarnation);
+
+ // b.liveVarsBefore has served its purpose in the just-finished call to ComputeIncarnationMap; null it out.
+ b.liveVarsBefore = null;
+
+ // Decrement the succCount field in each predecessor. Once the field reaches zero in any block,
+ // all its successors have been passified. Consequently, its entry in block2Incarnation can be removed.
+ byte[] currentChecksum = null;
+ var mvc = new MutableVariableCollector();
+ variableCollectors[b] = mvc;
+ foreach (Block p in b.Predecessors) {
+ p.succCount--;
+ if (p.Checksum != null)
+ {
+ // Compute the checksum based on the checksums of the predecessor. The order should not matter.
+ currentChecksum = ChecksumHelper.CombineChecksums(p.Checksum, currentChecksum, true);
+ }
+ mvc.AddUsedVariables(variableCollectors[p].UsedVariables);
+ if (p.succCount == 0)
+ block2Incarnation.Remove(p);
+ }
+
+ #region Each block's map needs to be available to successor blocks
+ GotoCmd gotoCmd = b.TransferCmd as GotoCmd;
+ if (gotoCmd == null) {
+ b.succCount = 0;
+ }
+ else {
+ // incarnationMap needs to be added only if there is some successor of b
+ b.succCount = gotoCmd.labelNames.Count;
+ block2Incarnation.Add(b, incarnationMap);
+ }
+ #endregion Each block's map needs to be available to successor blocks
+
+ TurnIntoPassiveBlock(b, incarnationMap, mvInfo, oldFrameSubst, mvc, currentChecksum);
+ exitBlock = b;
+ exitIncarnationMap = incarnationMap;
+ }
+
+ variableCollectors.Clear();
+
+ // Verify that exitBlock is indeed the unique exit block
+ Contract.Assert(exitBlock != null);
+ Contract.Assert(exitBlock.TransferCmd is ReturnCmd);
+ #endregion Convert to Passive Commands
+
+ return exitIncarnationMap;
+ }
+
+ /// <summary>
+ /// Compute the substitution for old expressions.
+ /// </summary>
+ protected static Substitution ComputeOldExpressionSubstitution(List<IdentifierExpr> modifies)
+ {
+ Dictionary<Variable, Expr> oldFrameMap = new Dictionary<Variable, Expr>();
+ foreach (IdentifierExpr ie in modifies)
+ {
+ Contract.Assert(ie != null);
+ if (!oldFrameMap.ContainsKey(cce.NonNull(ie.Decl)))
+ oldFrameMap.Add(ie.Decl, ie);
+ }
+ return Substituter.SubstitutionFromHashtable(oldFrameMap);
+ }
+
+ public enum CachingAction : byte
+ {
+ DoNothingToAssert,
+ MarkAsPartiallyVerified,
+ MarkAsFullyVerified,
+ RecycleError,
+ AssumeNegationOfAssumptionVariable,
+ DropAssume
+ }
+
+ public long[] CachingActionCounts;
+
+ void TraceCachingAction(Cmd cmd, CachingAction action)
+ {
+ if (CommandLineOptions.Clo.TraceCachingForTesting)
+ {
+ using (var tokTxtWr = new TokenTextWriter("<console>", Console.Out, false, false))
+ {
+ var loc = cmd.tok != null && cmd.tok != Token.NoToken ? string.Format("{0}({1},{2})", cmd.tok.filename, cmd.tok.line, cmd.tok.col) : "<unknown location>";
+ Console.Write("Processing command (at {0}) ", loc);
+ cmd.Emit(tokTxtWr, 0);
+ Console.Out.WriteLine(" >>> {0}", action);
+ }
+ }
+
+ if (CommandLineOptions.Clo.TraceCachingForBenchmarking && CachingActionCounts != null)
+ {
+ Interlocked.Increment(ref CachingActionCounts[(int)action]);
+ }
+ }
+
+ /// <summary>
+ /// Turn a command into a passive command, and it remembers the previous step, to see if it is a havoc or not. In the case, it remembers the incarnation map BEFORE the havoc
+ /// Meanwhile, record any information needed to later reconstruct a model view.
+ /// </summary>
+ protected void TurnIntoPassiveCmd(Cmd c, Dictionary<Variable, Expr> incarnationMap, Substitution oldFrameSubst, List<Cmd> passiveCmds, ModelViewInfo mvInfo, Block containingBlock) {
+ Contract.Requires(c != null);
+ Contract.Requires(incarnationMap != null);
+ Contract.Requires(oldFrameSubst != null);
+ Contract.Requires(passiveCmds != null);
+ Contract.Requires(mvInfo != null);
+ Contract.Requires(containingBlock != null);
+
+ Substitution incarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
+ #region assert/assume P |--> assert/assume P[x := in(x)], out := in
+ if (c is PredicateCmd) {
+ Contract.Assert(c is AssertCmd || c is AssumeCmd); // otherwise, unexpected PredicateCmd type
+
+ PredicateCmd pc = (PredicateCmd)c.Clone();
+ Contract.Assert(pc != null);
+
+ Expr copy = Substituter.ApplyReplacingOldExprs(incarnationSubst, oldFrameSubst, pc.Expr);
+ if (CommandLineOptions.Clo.ModelViewFile != null && pc is AssumeCmd) {
+ string description = QKeyValue.FindStringAttribute(pc.Attributes, "captureState");
+ if (description != null) {
+ Expr mv = new NAryExpr(pc.tok, new FunctionCall(ModelViewInfo.MVState_FunctionDef), new List<Expr> { Bpl.Expr.Ident(ModelViewInfo.MVState_ConstantDef), Bpl.Expr.Literal(mvInfo.CapturePoints.Count) });
+ copy = Bpl.Expr.And(mv, copy);
+ mvInfo.CapturePoints.Add(new ModelViewInfo.Mapping(description, new Dictionary<Variable, Expr>(incarnationMap)));
+ }
+ }
+ Contract.Assert(copy != null);
+ var dropCmd = false;
+ var relevantAssumpVars = currentImplementation != null ? currentImplementation.RelevantInjectedAssumptionVariables(incarnationMap) : new List<LocalVariable>();
+ var relevantDoomedAssumpVars = currentImplementation != null ? currentImplementation.RelevantDoomedInjectedAssumptionVariables(incarnationMap) : new List<LocalVariable>();
+ var checksum = pc.Checksum;
+ if (pc is AssertCmd) {
+ var ac = (AssertCmd)pc;
+ ac.OrigExpr = ac.Expr;
+ Contract.Assert(ac.IncarnationMap == null);
+ ac.IncarnationMap = (Dictionary<Variable, Expr>)cce.NonNull(new Dictionary<Variable, Expr>(incarnationMap));
+
+ var subsumption = Wlp.Subsumption(ac);
+ if (relevantDoomedAssumpVars.Any())
+ {
+ TraceCachingAction(pc, CachingAction.DoNothingToAssert);
+ }
+ else if (currentImplementation != null
+ && currentImplementation.HasCachedSnapshot
+ && checksum != null
+ && currentImplementation.IsAssertionChecksumInCachedSnapshot(checksum)
+ && !currentImplementation.IsErrorChecksumInCachedSnapshot(checksum))
+ {
+ if (!currentImplementation.AnyErrorsInCachedSnapshot
+ && currentImplementation.InjectedAssumptionVariables.Count == 1
+ && relevantAssumpVars.Count == 1)
+ {
+ TraceCachingAction(pc, CachingAction.MarkAsPartiallyVerified);
+ }
+ else
+ {
+ bool isTrue;
+ var assmVars = currentImplementation.ConjunctionOfInjectedAssumptionVariables(incarnationMap, out isTrue);
+ TraceCachingAction(pc, !isTrue ? CachingAction.MarkAsPartiallyVerified : CachingAction.MarkAsFullyVerified);
+ var litExpr = ac.Expr as LiteralExpr;
+ if (litExpr == null || !litExpr.IsTrue)
+ {
+ ac.MarkAsVerifiedUnder(assmVars);
+ }
+ else
+ {
+ dropCmd = true;
+ }
+ }
+ }
+ else if (currentImplementation != null
+ && currentImplementation.HasCachedSnapshot
+ && relevantAssumpVars.Count == 0
+ && checksum != null
+ && currentImplementation.IsAssertionChecksumInCachedSnapshot(checksum)
+ && currentImplementation.IsErrorChecksumInCachedSnapshot(checksum))
+ {
+ TraceCachingAction(pc, CachingAction.RecycleError);
+ ac.MarkAsVerifiedUnder(Expr.True);
+ currentImplementation.AddRecycledFailingAssertion(ac);
+ pc.Attributes = new QKeyValue(Token.NoToken, "recycled_failing_assertion", new List<object>(), pc.Attributes);
+ }
+ else
+ {
+ TraceCachingAction(pc, CachingAction.DoNothingToAssert);
+ }
+ }
+ else if (pc is AssumeCmd
+ && QKeyValue.FindBoolAttribute(pc.Attributes, "precondition_previous_snapshot")
+ && pc.SugaredCmdChecksum != null)
+ {
+ if (!relevantDoomedAssumpVars.Any()
+ && currentImplementation.HasCachedSnapshot
+ && currentImplementation.IsAssertionChecksumInCachedSnapshot(pc.SugaredCmdChecksum)
+ && !currentImplementation.IsErrorChecksumInCachedSnapshot(pc.SugaredCmdChecksum))
+ {
+ bool isTrue;
+ var assmVars = currentImplementation.ConjunctionOfInjectedAssumptionVariables(incarnationMap, out isTrue);
+ if (!isTrue)
+ {
+ copy = LiteralExpr.Imp(assmVars, copy);
+ TraceCachingAction(pc, CachingAction.MarkAsPartiallyVerified);
+ }
+ else
+ {
+ TraceCachingAction(pc, CachingAction.MarkAsFullyVerified);
+ }
+ }
+ else
+ {
+ TraceCachingAction(pc, CachingAction.DropAssume);
+ dropCmd = true;
+ }
+ }
+ else if (pc is AssumeCmd && QKeyValue.FindBoolAttribute(pc.Attributes, "assumption_variable_initialization"))
+ {
+ var identExpr = pc.Expr as IdentifierExpr;
+ if (identExpr != null && identExpr.Decl != null && !incarnationMap.ContainsKey(identExpr.Decl))
+ {
+ incarnationMap[identExpr.Decl] = LiteralExpr.True;
+ dropCmd = true;
+ }
+ }
+ pc.Expr = copy;
+ if (!dropCmd)
+ {
+ passiveCmds.Add(pc);
+ }
+ }
+ #endregion
+ #region x1 := E1, x2 := E2, ... |--> assume x1' = E1[in] & x2' = E2[in], out := in( x |-> x' ) [except as noted below]
+ else if (c is AssignCmd) {
+ AssignCmd assign = ((AssignCmd)c).AsSimpleAssignCmd; // first remove map assignments
+ Contract.Assert(assign != null);
+ #region Substitute all variables in E with the current map
+ List<Expr> copies = new List<Expr>();
+ foreach (Expr e in assign.Rhss) {
+ Contract.Assert(e != null);
+ copies.Add(Substituter.ApplyReplacingOldExprs(incarnationSubst,
+ oldFrameSubst,
+ e));
+ }
+ #endregion
+
+ List<Expr/*!>!*/> assumptions = new List<Expr>();
+ // it might be too slow to create a new dictionary each time ...
+ IDictionary<Variable, Expr> newIncarnationMappings =
+ new Dictionary<Variable, Expr>();
+
+ for (int i = 0; i < assign.Lhss.Count; ++i) {
+ IdentifierExpr lhsIdExpr =
+ cce.NonNull((SimpleAssignLhs)assign.Lhss[i]).AssignedVariable;
+ Variable lhs = cce.NonNull(lhsIdExpr.Decl);
+ Contract.Assert(lhs != null);
+ Expr rhs = assign.Rhss[i];
+ Contract.Assert(rhs != null);
+
+ // don't create incarnations for assignments of literals or single variables.
+ if (rhs is LiteralExpr) {
+ incarnationMap[lhs] = rhs;
+ } else if (rhs is IdentifierExpr) {
+ IdentifierExpr ie = (IdentifierExpr)rhs;
+ if (incarnationMap.ContainsKey(cce.NonNull(ie.Decl)))
+ newIncarnationMappings[lhs] = cce.NonNull((Expr)incarnationMap[ie.Decl]);
+ else
+ newIncarnationMappings[lhs] = ie;
+ } else {
+ IdentifierExpr x_prime_exp = null;
+ #region Make a new incarnation, x', for variable x, but only if x is *not* already an incarnation
+ if (lhs is Incarnation) {
+ // incarnations are already written only once, no need to make an incarnation of an incarnation
+ x_prime_exp = lhsIdExpr;
+ } else {
+ Variable v = CreateIncarnation(lhs, c);
+ x_prime_exp = new IdentifierExpr(lhsIdExpr.tok, v);
+ newIncarnationMappings[lhs] = x_prime_exp;
+ }
+ #endregion
+
+ var nAryExpr = copies[i] as NAryExpr;
+ if (nAryExpr != null)
+ {
+ var binOp = nAryExpr.Fun as BinaryOperator;
+ if (binOp != null
+ && binOp.Op == BinaryOperator.Opcode.And)
+ {
+ var arg0 = nAryExpr.Args[0] as LiteralExpr;
+ var arg1 = nAryExpr.Args[1] as LiteralExpr;
+ if ((arg0 != null && arg0.IsTrue) || (arg1 != null && arg1.IsFalse))
+ {
+ // Replace the expressions "true && arg1" or "arg0 && false" by "arg1".
+ copies[i] = nAryExpr.Args[1];
+ }
+ }
+ }
+
+ #region Create an assume command with the new variable
+ assumptions.Add(TypedExprEq(x_prime_exp, copies[i], x_prime_exp.Decl != null && x_prime_exp.Decl.Name.Contains("a##cached##")));
+ #endregion
+ }
+ }
+
+ foreach (KeyValuePair<Variable, Expr> pair in newIncarnationMappings) {
+ Contract.Assert(pair.Key != null && pair.Value != null);
+ incarnationMap[pair.Key] = pair.Value;
+ }
+
+ if (assumptions.Count > 0) {
+ Expr assumption = assumptions[0];
+
+ for (int i = 1; i < assumptions.Count; ++i) {
+ Contract.Assert(assumption != null);
+ assumption = Expr.And(assumption, assumptions[i]);
+ }
+ passiveCmds.Add(new AssumeCmd(c.tok, assumption));
+ }
+
+ if (currentImplementation != null
+ && currentImplementation.HasCachedSnapshot
+ && !currentImplementation.AnyErrorsInCachedSnapshot
+ && currentImplementation.DoomedInjectedAssumptionVariables.Count == 0
+ && currentImplementation.InjectedAssumptionVariables.Count == 1
+ && assign.Lhss.Count == 1)
+ {
+ var identExpr = assign.Lhss[0].AsExpr as IdentifierExpr;
+ Expr incarnation;
+ if (identExpr != null && identExpr.Decl != null && QKeyValue.FindBoolAttribute(identExpr.Decl.Attributes, "assumption") && incarnationMap.TryGetValue(identExpr.Decl, out incarnation))
+ {
+ TraceCachingAction(assign, CachingAction.AssumeNegationOfAssumptionVariable);
+ passiveCmds.Add(new AssumeCmd(c.tok, Expr.Not(incarnation)));
+ }
+ }
+ }
+ #endregion
+ #region havoc w |--> assume whereClauses, out := in( w |-> w' )
+ else if (c is HavocCmd) {
+ if (this.preHavocIncarnationMap == null) // Save a copy of the incarnation map (at the top of a sequence of havoc statements)
+ this.preHavocIncarnationMap = new Dictionary<Variable, Expr>(incarnationMap);
+
+ HavocCmd hc = (HavocCmd)c;
+ Contract.Assert(c != null);
+ // If an assumption variable for postconditions is included here, it must have been assigned within a loop.
+ // We do not need to havoc it if we have performed a modular proof of the loop (i.e., using only the loop
+ // invariant) in the previous snapshot and, consequently, the corresponding assumption did not affect the
+ // anything after the loop. We can achieve this by simply not updating/adding it in the incarnation map.
+ List<IdentifierExpr> havocVars = hc.Vars.Where(v => !(QKeyValue.FindBoolAttribute(v.Decl.Attributes, "assumption") && v.Decl.Name.StartsWith("a##cached##"))).ToList();
+ // First, compute the new incarnations
+ foreach (IdentifierExpr ie in havocVars) {
+ Contract.Assert(ie != null);
+ if (!(ie.Decl is Incarnation)) {
+ Variable x = cce.NonNull(ie.Decl);
+ Variable x_prime = CreateIncarnation(x, c);
+ incarnationMap[x] = new IdentifierExpr(x_prime.tok, x_prime);
+ }
+ }
+ // Then, perform the assume of the where clauses, using the updated incarnations
+ Substitution updatedIncarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
+ foreach (IdentifierExpr ie in havocVars) {
+ Contract.Assert(ie != null);
+ if (!(ie.Decl is Incarnation)) {
+ Variable x = cce.NonNull(ie.Decl);
+ Bpl.Expr w = x.TypedIdent.WhereExpr;
+ if (w != null) {
+ Expr copy = Substituter.ApplyReplacingOldExprs(updatedIncarnationSubst, oldFrameSubst, w);
+ passiveCmds.Add(new AssumeCmd(c.tok, copy));
+ }
+ }
+ }
+
+ // Add the following assume-statement for each assumption variable 'v', where 'v_post' is the new incarnation and 'v_pre' is the old one:
+ // assume v_post ==> v_pre;
+ foreach (IdentifierExpr ie in havocVars)
+ {
+ if (QKeyValue.FindBoolAttribute(ie.Decl.Attributes, "assumption"))
+ {
+ var preInc = (Expr)(preHavocIncarnationMap[ie.Decl].Clone());
+ var postInc = (Expr)(incarnationMap[ie.Decl].Clone());
+ passiveCmds.Add(new AssumeCmd(c.tok, Expr.Imp(postInc, preInc)));
+ }
+ }
+ }
+ #endregion
+ else if (c is CommentCmd) {
+ // comments are just for debugging and don't affect verification
+ } else if (c is SugaredCmd) {
+ SugaredCmd sug = (SugaredCmd)c;
+ Contract.Assert(sug != null);
+ Cmd cmd = sug.Desugaring;
+ Contract.Assert(cmd != null);
+ TurnIntoPassiveCmd(cmd, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, containingBlock);
+ } else if (c is StateCmd) {
+ this.preHavocIncarnationMap = null; // we do not need to remeber the previous incarnations
+ StateCmd st = (StateCmd)c;
+ Contract.Assert(st != null);
+ // account for any where clauses among the local variables
+ foreach (Variable v in st.Locals) {
+ Contract.Assert(v != null);
+ Expr w = v.TypedIdent.WhereExpr;
+ if (w != null) {
+ passiveCmds.Add(new AssumeCmd(v.tok, w));
+ }
+ }
+ // do the sub-commands
+ foreach (Cmd s in st.Cmds) {
+ Contract.Assert(s != null);
+ TurnIntoPassiveCmd(s, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, containingBlock);
+ }
+ // remove the local variables from the incarnation map
+ foreach (Variable v in st.Locals) {
+ Contract.Assert(v != null);
+ incarnationMap.Remove(v);
+ }
+ }
+ #region There shouldn't be any other types of commands at this point
+ else {
+ Debug.Fail("Internal Error: Passive transformation handed a command that is not one of assert,assume,havoc,assign.");
+ }
+ #endregion
+
+
+ #region We remember if we have put an havoc statement into a passive form
+
+ if (!(c is HavocCmd))
+ this.preHavocIncarnationMap = null;
+ // else: it has already been set by the case for the HavocCmd
+ #endregion
+ }
+
+ NAryExpr TypedExprEq(Expr e0, Expr e1, bool doNotResolveOverloading = false) {
+ Contract.Requires(e0 != null);
+ Contract.Requires(e1 != null);
+ NAryExpr e = Expr.Eq(e0, e1);
+ var fun = e.Fun as IOverloadedAppliable;
+ if (fun != null)
+ {
+ fun.DoNotResolveOverloading = doNotResolveOverloading;
+ }
+ e.Type = Bpl.Type.Bool;
+ e.TypeParameters = SimpleTypeParamInstantiation.EMPTY;
+ return e;
+ }
+
+ /// <summary>
+ /// Creates a new block to add to impl.Blocks, where impl is the implementation that contains
+ /// succ. Caller must do the add to impl.Blocks.
+ /// </summary>
+ protected Block CreateBlockBetween(int predIndex, Block succ) {
+ Contract.Requires(0 <= predIndex && predIndex < succ.Predecessors.Count);
+
+
+ Contract.Requires(succ != null);
+ Contract.Ensures(Contract.Result<Block>() != null);
+
+ Block pred = cce.NonNull(succ.Predecessors[predIndex]);
+
+ string newBlockLabel = pred.Label + "_@2_" + succ.Label;
+
+ // successor of newBlock list
+ List<String> ls = new List<String>();
+ ls.Add(succ.Label);
+ List<Block> bs = new List<Block>();
+ bs.Add(succ);
+
+ Block newBlock = new Block(
+ new Token(-17, -4),
+ newBlockLabel,
+ new List<Cmd>(),
+ new GotoCmd(Token.NoToken, ls, bs)
+ );
+
+ // predecessors of newBlock
+ List<Block> ps = new List<Block>();
+ ps.Add(pred);
+ newBlock.Predecessors = ps;
+
+ // fix successors of pred
+ #region Change the edge "pred->succ" to "pred->newBlock"
+ GotoCmd gtc = (GotoCmd)cce.NonNull(pred.TransferCmd);
+ Contract.Assume(gtc.labelTargets != null);
+ Contract.Assume(gtc.labelNames != null);
+ for (int i = 0, n = gtc.labelTargets.Count; i < n; i++) {
+ if (gtc.labelTargets[i] == succ) {
+ gtc.labelTargets[i] = newBlock;
+ gtc.labelNames[i] = newBlockLabel;
+ break;
+ }
+ }
+ #endregion Change the edge "pred->succ" to "pred->newBlock"
+
+ // fix predecessors of succ
+ succ.Predecessors[predIndex] = newBlock;
+
+ return newBlock;
+ }
+
+ protected void AddBlocksBetween(List<Block> blocks) {
+ Contract.Requires(blocks != null);
+ #region Introduce empty blocks between join points and their multi-successor predecessors
+ List<Block> tweens = new List<Block>();
+ foreach (Block b in blocks) {
+ int nPreds = b.Predecessors.Count;
+ if (nPreds > 1) {
+ // b is a join point (i.e., it has more than one predecessor)
+ for (int i = 0; i < nPreds; i++) {
+ GotoCmd gotocmd = (GotoCmd)(cce.NonNull(b.Predecessors[i]).TransferCmd);
+ if (gotocmd.labelNames != null && gotocmd.labelNames.Count > 1) {
+ tweens.Add(CreateBlockBetween(i, b));
+ }
+ }
+ }
+ }
+ blocks.AddRange(tweens); // must wait until iteration is done before changing the list
+ #endregion
+ }
+
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ Close();
+ }
+ _disposed = true;
+ }
+ }
+
+ public int Cores { get; set; }
+ }
+
+ public class ModelViewInfo
+ {
+ public readonly List<Variable> AllVariables = new List<Variable>();
+ public readonly List<Mapping> CapturePoints = new List<Mapping>();
+ public static readonly Function MVState_FunctionDef = new Function(Token.NoToken, "$mv_state",
+ new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Int), true),
+ new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Int), true) },
+ new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Bool), false));
+ public static readonly Constant MVState_ConstantDef = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "$mv_state_const", Bpl.Type.Int));
+
+ public ModelViewInfo(Program program, Implementation impl) {
+ Contract.Requires(program != null);
+ Contract.Requires(impl != null);
+
+ // global variables
+ lock (program.TopLevelDeclarations)
+ {
+ foreach (var v in program.Variables)
+ {
+ if (!(v is Constant))
+ {
+ AllVariables.Add(v);
+ }
+ }
+ }
+ // implementation parameters
+ foreach (Variable p in impl.InParams) {
+ AllVariables.Add(p);
+ }
+ foreach (Variable p in impl.OutParams) {
+ AllVariables.Add(p);
+ }
+ // implementation locals
+ foreach (Variable v in impl.LocVars) {
+ AllVariables.Add(v);
+ }
+ }
+
+ public ModelViewInfo(CodeExpr codeExpr) {
+ Contract.Requires(codeExpr != null);
+ // TODO: also need all variables of enclosing scopes (the global variables of the program, the parameters
+ // and perhaps locals of the implementation (if any), any enclosing code expressions).
+
+ foreach (Variable v in codeExpr.LocVars) {
+ AllVariables.Add(v);
+ }
+ }
+
+ public class Mapping
+ {
+ public readonly string Description;
+ public readonly Dictionary<Variable, Expr> IncarnationMap;
+ public Mapping(string description, Dictionary<Variable, Expr> incarnationMap) {
+ Description = description;
+ IncarnationMap = incarnationMap;
+ }
+ }
+ }
+}
diff --git a/Source/VCGeneration/Context.cs b/Source/VCGeneration/Context.cs
index ddc34976..3bd14e6b 100644
--- a/Source/VCGeneration/Context.cs
+++ b/Source/VCGeneration/Context.cs
@@ -1,256 +1,256 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie.VCExprAST;
-
-namespace Microsoft.Boogie
-{
- /// <summary>
- /// The methods of this class are called in the following order:
- /// DeclareType*
- /// (DeclareConstant DeclareFunction)*
- /// AddAxiom*
- /// DeclareGlobalVariable*
- /// At this time, all "attributes" are passed in as null.
- /// </summary>
- [ContractClass(typeof(ProverContextContracts))]
- public abstract class ProverContext : ICloneable {
- public int TimoutDiagnosticsCount { get; set; }
- public readonly Dictionary<int, Tuple<AssertCmd, TransferCmd>> TimeoutDiagnosticIDToAssertion = new Dictionary<int, Tuple<AssertCmd, TransferCmd>>();
- protected virtual void ProcessDeclaration(Declaration decl) {Contract.Requires(decl != null);}
- public virtual void DeclareType(TypeCtorDecl t, string attributes) {Contract.Requires(t != null); ProcessDeclaration(t); }
- public virtual void DeclareConstant(Constant c, bool uniq, string attributes) {Contract.Requires(c != null); ProcessDeclaration(c); }
- public virtual void DeclareFunction(Function f, string attributes) {Contract.Requires(f != null); ProcessDeclaration(f); }
- public virtual void AddAxiom(Axiom a, string attributes) {Contract.Requires(a != null); ProcessDeclaration(a); }
- public virtual void DeclareGlobalVariable(GlobalVariable v, string attributes) {Contract.Requires(v != null); ProcessDeclaration(v); }
- public abstract void AddAxiom(VCExpr vc);
- public abstract string Lookup(VCExprVar var);
- public abstract VCExpressionGenerator ExprGen { get; }
- public abstract Boogie2VCExprTranslator BoogieExprTranslator { get; }
- public abstract VCGenerationOptions VCGenOptions { get; }
- public abstract object Clone();
- public abstract void Reset();
- public abstract void Clear();
- }
-
-[ContractClassFor(typeof(ProverContext))]
-public abstract class ProverContextContracts:ProverContext{
- public override void AddAxiom(VCExpr vc) {
- }
- public override void AddAxiom(Axiom a, string attributes)
-{
-}
- public override VCExpressionGenerator ExprGen
-{
- get { Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
- throw new NotImplementedException(); }
-}
- public override Boogie2VCExprTranslator BoogieExprTranslator
-{
- get { Contract.Ensures(Contract.Result<Boogie2VCExprTranslator>() != null);
- throw new NotImplementedException(); }
-}
- public override VCGenerationOptions VCGenOptions
-{
- get {Contract.Ensures(Contract.Result<VCGenerationOptions>() != null);
- throw new NotImplementedException(); }
-}
- public override object Clone()
-{
- Contract.Ensures(Contract.Result<object>() != null);
- throw new NotImplementedException();
-}
-}
-
- // -----------------------------------------------------------------------------------------------
- // -----------------------------------------------------------------------------------------------
- // -----------------------------------------------------------------------------------------------
-
- /// <summary>
- /// This ProverContext subclass is intended for use with untyped provers that do not require names
- /// to be declared before use. It constructs its context from unique constants and given axioms.
- /// </summary>
- public class DeclFreeProverContext : ProverContext {
- protected VCExpressionGenerator gen;
- protected VCGenerationOptions genOptions;
- protected Boogie2VCExprTranslator translator;
-
- protected OrderingAxiomBuilder orderingAxiomBuilder;
-
- protected List<Variable> distincts;
- protected List<VCExpr> axiomConjuncts;
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(gen != null);
- Contract.Invariant(genOptions != null);
- Contract.Invariant(translator != null);
- Contract.Invariant(orderingAxiomBuilder != null);
- Contract.Invariant(cce.NonNullElements(distincts));
- Contract.Invariant(cce.NonNullElements(axiomConjuncts));
- }
-
- public VCExprTranslator/*?*/ exprTranslator;
-
- public DeclFreeProverContext(VCExpressionGenerator gen,
- VCGenerationOptions genOptions) {
- Contract.Requires(gen != null);
- Contract.Requires(genOptions != null);
- this.gen = gen;
- this.genOptions = genOptions;
- Boogie2VCExprTranslator t = new Boogie2VCExprTranslator (gen, genOptions);
- this.translator = t;
-
- SetupOrderingAxiomBuilder(gen, t);
-
- distincts = new List<Variable>();
- axiomConjuncts = new List<VCExpr>();
-
- exprTranslator = null;
- }
-
- private void SetupOrderingAxiomBuilder(VCExpressionGenerator gen, Boogie2VCExprTranslator t)
- {
- OrderingAxiomBuilder oab = new OrderingAxiomBuilder(gen, t);
- Contract.Assert(oab != null);
- oab.Setup();
- this.orderingAxiomBuilder = oab;
- }
-
- public override void Reset()
- {
- SetupOrderingAxiomBuilder(gen, translator);
- distincts = new List<Variable>();
- axiomConjuncts = new List<VCExpr>();
- }
-
- public override void Clear()
- {
- distincts = new List<Variable>();
- axiomConjuncts = new List<VCExpr>();
- }
-
- protected DeclFreeProverContext(DeclFreeProverContext ctxt) {
- Contract.Requires(ctxt != null);
- this.gen = ctxt.gen;
- this.genOptions = ctxt.genOptions;
- Boogie2VCExprTranslator t = (Boogie2VCExprTranslator)ctxt.translator.Clone();
- Contract.Assert(t != null);
- this.translator = t;
- this.orderingAxiomBuilder = new OrderingAxiomBuilder(ctxt.gen, t, ctxt.orderingAxiomBuilder);
-
- StringBuilder cmds = new StringBuilder ();
-
- distincts = new List<Variable>(ctxt.distincts);
- axiomConjuncts = new List<VCExpr>(ctxt.axiomConjuncts);
-
- if (ctxt.exprTranslator == null)
- exprTranslator = null;
- else
- exprTranslator = (VCExprTranslator)cce.NonNull(ctxt.exprTranslator.Clone());
- }
-
- public override object Clone() {
- Contract.Ensures(Contract.Result<object>() != null);
-
- return new DeclFreeProverContext(this);
- }
-
- public override void DeclareFunction(Function f, string attributes) {//Contract.Requires(f != null);
- base.ProcessDeclaration(f);
- }
-
- public override void DeclareConstant(Constant c, bool uniq, string attributes) {//Contract.Requires(c != null);
- base.DeclareConstant(c, uniq, attributes);
- orderingAxiomBuilder.AddConstant(c);
-
- // TODO: make separate distinct lists for names coming from different types
- // e.g., one for strings, one for ints, one for program types.
- if (uniq){
- distincts.Add(c);
- }
- }
-
- public override void AddAxiom(Axiom ax, string attributes) {//Contract.Requires(ax != null);
- base.AddAxiom(ax, attributes);
-
- axiomConjuncts.Add(translator.Translate(ax.Expr));
- }
-
- public override void AddAxiom(VCExpr vc)
- {//Contract.Requires(vc != null);
- axiomConjuncts.Add(vc);
- }
-
- public VCExpr Axioms {
- get {Contract.Ensures(Contract.Result<VCExpr>() != null);
- VCExpr axioms = gen.NAry(VCExpressionGenerator.AndOp, axiomConjuncts);
- List<VCExpr>/*!>!*/ distinctVars = new List<VCExpr> ();
- foreach (Variable v in distincts){
- Contract.Assert(v != null);
- distinctVars.Add(translator.LookupVariable(v));}
- axioms = gen.AndSimp(gen.Distinct(distinctVars), axioms);
- if (CommandLineOptions.Clo.TypeEncodingMethod != CommandLineOptions.TypeEncoding.Monomorphic)
- axioms = gen.AndSimp(orderingAxiomBuilder.Axioms, axioms);
- return axioms;
- }
- }
-
- public override string Lookup(VCExprVar var)
- {
- return exprTranslator.Lookup(var);
- }
-
- public override VCExpressionGenerator ExprGen { get {Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
-
- return gen;
- } }
- public override Boogie2VCExprTranslator BoogieExprTranslator { get {Contract.Ensures(Contract.Result<Boogie2VCExprTranslator>() != null);
-
- return translator;
- } }
- public override VCGenerationOptions VCGenOptions { get {Contract.Ensures(Contract.Result<VCGenerationOptions>() != null);
-
- return genOptions;
- } }
- }
-
- // Translator from VCExpressions to strings, which are implemented
- // by the various provers
- [ContractClass(typeof(VCExprTranslatorContracts))]
- public abstract class VCExprTranslator : ICloneable {
- public abstract string translate(VCExpr expr, int polarity);
- public abstract string Lookup(VCExprVar var);
- public abstract Object Clone();
- }
-
- [ContractClassFor(typeof(VCExprTranslator))]
-
- public abstract class VCExprTranslatorContracts : VCExprTranslator {
- public override object Clone() {
- Contract.Ensures(Contract.Result<object>() != null);
- throw new NotImplementedException();
- }
- public override string Lookup(VCExprVar var) {
- Contract.Requires(var != null);
- Contract.Ensures(Contract.Result<string>() != null);
-
- throw new NotImplementedException();
- }
- public override string translate(VCExpr expr, int polarity) {
-
- Contract.Requires(expr != null);
-
- Contract.Ensures(Contract.Result<string>() != null);
-
- throw new NotImplementedException();
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Diagnostics.Contracts;
+using Microsoft.Boogie.VCExprAST;
+
+namespace Microsoft.Boogie
+{
+ /// <summary>
+ /// The methods of this class are called in the following order:
+ /// DeclareType*
+ /// (DeclareConstant DeclareFunction)*
+ /// AddAxiom*
+ /// DeclareGlobalVariable*
+ /// At this time, all "attributes" are passed in as null.
+ /// </summary>
+ [ContractClass(typeof(ProverContextContracts))]
+ public abstract class ProverContext : ICloneable {
+ public int TimoutDiagnosticsCount { get; set; }
+ public readonly Dictionary<int, Tuple<AssertCmd, TransferCmd>> TimeoutDiagnosticIDToAssertion = new Dictionary<int, Tuple<AssertCmd, TransferCmd>>();
+ protected virtual void ProcessDeclaration(Declaration decl) {Contract.Requires(decl != null);}
+ public virtual void DeclareType(TypeCtorDecl t, string attributes) {Contract.Requires(t != null); ProcessDeclaration(t); }
+ public virtual void DeclareConstant(Constant c, bool uniq, string attributes) {Contract.Requires(c != null); ProcessDeclaration(c); }
+ public virtual void DeclareFunction(Function f, string attributes) {Contract.Requires(f != null); ProcessDeclaration(f); }
+ public virtual void AddAxiom(Axiom a, string attributes) {Contract.Requires(a != null); ProcessDeclaration(a); }
+ public virtual void DeclareGlobalVariable(GlobalVariable v, string attributes) {Contract.Requires(v != null); ProcessDeclaration(v); }
+ public abstract void AddAxiom(VCExpr vc);
+ public abstract string Lookup(VCExprVar var);
+ public abstract VCExpressionGenerator ExprGen { get; }
+ public abstract Boogie2VCExprTranslator BoogieExprTranslator { get; }
+ public abstract VCGenerationOptions VCGenOptions { get; }
+ public abstract object Clone();
+ public abstract void Reset();
+ public abstract void Clear();
+ }
+
+[ContractClassFor(typeof(ProverContext))]
+public abstract class ProverContextContracts:ProverContext{
+ public override void AddAxiom(VCExpr vc) {
+ }
+ public override void AddAxiom(Axiom a, string attributes)
+{
+}
+ public override VCExpressionGenerator ExprGen
+{
+ get { Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
+ throw new NotImplementedException(); }
+}
+ public override Boogie2VCExprTranslator BoogieExprTranslator
+{
+ get { Contract.Ensures(Contract.Result<Boogie2VCExprTranslator>() != null);
+ throw new NotImplementedException(); }
+}
+ public override VCGenerationOptions VCGenOptions
+{
+ get {Contract.Ensures(Contract.Result<VCGenerationOptions>() != null);
+ throw new NotImplementedException(); }
+}
+ public override object Clone()
+{
+ Contract.Ensures(Contract.Result<object>() != null);
+ throw new NotImplementedException();
+}
+}
+
+ // -----------------------------------------------------------------------------------------------
+ // -----------------------------------------------------------------------------------------------
+ // -----------------------------------------------------------------------------------------------
+
+ /// <summary>
+ /// This ProverContext subclass is intended for use with untyped provers that do not require names
+ /// to be declared before use. It constructs its context from unique constants and given axioms.
+ /// </summary>
+ public class DeclFreeProverContext : ProverContext {
+ protected VCExpressionGenerator gen;
+ protected VCGenerationOptions genOptions;
+ protected Boogie2VCExprTranslator translator;
+
+ protected OrderingAxiomBuilder orderingAxiomBuilder;
+
+ protected List<Variable> distincts;
+ protected List<VCExpr> axiomConjuncts;
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(gen != null);
+ Contract.Invariant(genOptions != null);
+ Contract.Invariant(translator != null);
+ Contract.Invariant(orderingAxiomBuilder != null);
+ Contract.Invariant(cce.NonNullElements(distincts));
+ Contract.Invariant(cce.NonNullElements(axiomConjuncts));
+ }
+
+ public VCExprTranslator/*?*/ exprTranslator;
+
+ public DeclFreeProverContext(VCExpressionGenerator gen,
+ VCGenerationOptions genOptions) {
+ Contract.Requires(gen != null);
+ Contract.Requires(genOptions != null);
+ this.gen = gen;
+ this.genOptions = genOptions;
+ Boogie2VCExprTranslator t = new Boogie2VCExprTranslator (gen, genOptions);
+ this.translator = t;
+
+ SetupOrderingAxiomBuilder(gen, t);
+
+ distincts = new List<Variable>();
+ axiomConjuncts = new List<VCExpr>();
+
+ exprTranslator = null;
+ }
+
+ private void SetupOrderingAxiomBuilder(VCExpressionGenerator gen, Boogie2VCExprTranslator t)
+ {
+ OrderingAxiomBuilder oab = new OrderingAxiomBuilder(gen, t);
+ Contract.Assert(oab != null);
+ oab.Setup();
+ this.orderingAxiomBuilder = oab;
+ }
+
+ public override void Reset()
+ {
+ SetupOrderingAxiomBuilder(gen, translator);
+ distincts = new List<Variable>();
+ axiomConjuncts = new List<VCExpr>();
+ }
+
+ public override void Clear()
+ {
+ distincts = new List<Variable>();
+ axiomConjuncts = new List<VCExpr>();
+ }
+
+ protected DeclFreeProverContext(DeclFreeProverContext ctxt) {
+ Contract.Requires(ctxt != null);
+ this.gen = ctxt.gen;
+ this.genOptions = ctxt.genOptions;
+ Boogie2VCExprTranslator t = (Boogie2VCExprTranslator)ctxt.translator.Clone();
+ Contract.Assert(t != null);
+ this.translator = t;
+ this.orderingAxiomBuilder = new OrderingAxiomBuilder(ctxt.gen, t, ctxt.orderingAxiomBuilder);
+
+ StringBuilder cmds = new StringBuilder ();
+
+ distincts = new List<Variable>(ctxt.distincts);
+ axiomConjuncts = new List<VCExpr>(ctxt.axiomConjuncts);
+
+ if (ctxt.exprTranslator == null)
+ exprTranslator = null;
+ else
+ exprTranslator = (VCExprTranslator)cce.NonNull(ctxt.exprTranslator.Clone());
+ }
+
+ public override object Clone() {
+ Contract.Ensures(Contract.Result<object>() != null);
+
+ return new DeclFreeProverContext(this);
+ }
+
+ public override void DeclareFunction(Function f, string attributes) {//Contract.Requires(f != null);
+ base.ProcessDeclaration(f);
+ }
+
+ public override void DeclareConstant(Constant c, bool uniq, string attributes) {//Contract.Requires(c != null);
+ base.DeclareConstant(c, uniq, attributes);
+ orderingAxiomBuilder.AddConstant(c);
+
+ // TODO: make separate distinct lists for names coming from different types
+ // e.g., one for strings, one for ints, one for program types.
+ if (uniq){
+ distincts.Add(c);
+ }
+ }
+
+ public override void AddAxiom(Axiom ax, string attributes) {//Contract.Requires(ax != null);
+ base.AddAxiom(ax, attributes);
+
+ axiomConjuncts.Add(translator.Translate(ax.Expr));
+ }
+
+ public override void AddAxiom(VCExpr vc)
+ {//Contract.Requires(vc != null);
+ axiomConjuncts.Add(vc);
+ }
+
+ public VCExpr Axioms {
+ get {Contract.Ensures(Contract.Result<VCExpr>() != null);
+ VCExpr axioms = gen.NAry(VCExpressionGenerator.AndOp, axiomConjuncts);
+ List<VCExpr>/*!>!*/ distinctVars = new List<VCExpr> ();
+ foreach (Variable v in distincts){
+ Contract.Assert(v != null);
+ distinctVars.Add(translator.LookupVariable(v));}
+ axioms = gen.AndSimp(gen.Distinct(distinctVars), axioms);
+ if (CommandLineOptions.Clo.TypeEncodingMethod != CommandLineOptions.TypeEncoding.Monomorphic)
+ axioms = gen.AndSimp(orderingAxiomBuilder.Axioms, axioms);
+ return axioms;
+ }
+ }
+
+ public override string Lookup(VCExprVar var)
+ {
+ return exprTranslator.Lookup(var);
+ }
+
+ public override VCExpressionGenerator ExprGen { get {Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
+
+ return gen;
+ } }
+ public override Boogie2VCExprTranslator BoogieExprTranslator { get {Contract.Ensures(Contract.Result<Boogie2VCExprTranslator>() != null);
+
+ return translator;
+ } }
+ public override VCGenerationOptions VCGenOptions { get {Contract.Ensures(Contract.Result<VCGenerationOptions>() != null);
+
+ return genOptions;
+ } }
+ }
+
+ // Translator from VCExpressions to strings, which are implemented
+ // by the various provers
+ [ContractClass(typeof(VCExprTranslatorContracts))]
+ public abstract class VCExprTranslator : ICloneable {
+ public abstract string translate(VCExpr expr, int polarity);
+ public abstract string Lookup(VCExprVar var);
+ public abstract Object Clone();
+ }
+
+ [ContractClassFor(typeof(VCExprTranslator))]
+
+ public abstract class VCExprTranslatorContracts : VCExprTranslator {
+ public override object Clone() {
+ Contract.Ensures(Contract.Result<object>() != null);
+ throw new NotImplementedException();
+ }
+ public override string Lookup(VCExprVar var) {
+ Contract.Requires(var != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+
+ throw new NotImplementedException();
+ }
+ public override string translate(VCExpr expr, int polarity) {
+
+ Contract.Requires(expr != null);
+
+ Contract.Ensures(Contract.Result<string>() != null);
+
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Source/VCGeneration/ExprExtensions.cs b/Source/VCGeneration/ExprExtensions.cs
index 2bdb4af7..5e0dcf8e 100644
--- a/Source/VCGeneration/ExprExtensions.cs
+++ b/Source/VCGeneration/ExprExtensions.cs
@@ -1,353 +1,353 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using Term = Microsoft.Boogie.VCExprAST.VCExpr;
-using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp;
-using Sort = Microsoft.Boogie.Type;
-using Microsoft.Boogie.VCExprAST;
-
-
-/** This namespace contains some extensions to allow VCExpr to provide the
- * interface needed by RPFP and FixedpointVC. */
-
-namespace Microsoft.Boogie.ExprExtensions
-{
- class ReferenceComparer<T> : IEqualityComparer<T> where T : class
- {
- private static ReferenceComparer<T> m_instance;
-
- public static ReferenceComparer<T> Instance
- {
- get
- {
- return m_instance ?? (m_instance = new ReferenceComparer<T>());
- }
- }
-
- public bool Equals(T x, T y)
- {
- return ReferenceEquals(x, y);
- }
-
- public int GetHashCode(T obj)
- {
- return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
- }
- }
-
- public class TermDict<T> : Dictionary<Term, T>
- {
- public TermDict() : base(ReferenceComparer<Term>.Instance) { }
- }
-
-
-
- public enum TermKind { App, Other };
-
- public enum DeclKind { Uninterpreted, And, Implies, Label, Other };
-
- public static class MyExtensions
- {
- public static Term[] GetAppArgs(this Term t)
- {
- Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry;
- return tn.ToArray();
- }
-
- public static FuncDecl GetAppDecl(this Term t)
- {
- Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry;
- return tn.Op;
- }
-
- public static string GetDeclName(this FuncDecl f)
- {
- return (f as VCExprBoogieFunctionOp).Func.Name; //TODO
- }
-
- public static DeclKind GetKind(this FuncDecl f)
- {
- if (f is VCExprBoogieFunctionOp)
- return DeclKind.Uninterpreted;
- if (f == VCExpressionGenerator.AndOp)
- return DeclKind.And;
- if (f == VCExpressionGenerator.ImpliesOp)
- return DeclKind.Implies;
- if (f is VCExprLabelOp)
- return DeclKind.Label;
- return DeclKind.Other;
- }
-
- public static bool IsLabel(this Term t)
- {
- return (t is VCExprNAry) && (GetAppDecl(t) is VCExprLabelOp);
- }
-
- public static string LabelName(this Term t)
- {
- return (GetAppDecl(t) as VCExprLabelOp).label;
- }
-
- public static Sort GetSort(this Term t)
- {
- return t.Type;
- }
-
- public static TermKind GetKind(this Term t)
- {
- if (t is Microsoft.Boogie.VCExprAST.VCExprNAry)
- return TermKind.App;
- return TermKind.Other;
- }
-
- public static bool IsFunctionApp(this Term t)
- {
- return t.GetKind() == TermKind.App && t.GetAppDecl().GetKind() == DeclKind.Uninterpreted;
- }
-
- public static bool IsFalse(this Term t)
- {
- return t == VCExpressionGenerator.False;
- }
-
- public static Term VCExprToTerm(this Microsoft.Boogie.ProverContext ctx, VCExpr e, LineariserOptions lin){
- return e;
- }
-
- }
-
- public class Context : Microsoft.Boogie.VCExpressionGenerator
- {
- public Term MkTrue()
- {
- return VCExpressionGenerator.True;
- }
-
- public Term MkFalse()
- {
- return VCExpressionGenerator.False;
- }
-
-
- public List<Term> axioms = new List<Term>();
-
- public void AddAxiom(Term ax)
- {
- axioms.Add(ax);
- }
-
- public void RemoveAxiom(Term ax)
- {
- axioms.Remove(ax);
- }
-
- public FuncDecl MkFuncDecl(string name, FuncDecl f)
- {
- Function h = (f as VCExprBoogieFunctionOp).Func;
- Function g = new Function(Token.NoToken, name, h.InParams, h.OutParams[0]);
- return BoogieFunctionOp(g);
- }
-
- public FuncDecl MkFuncDecl(string name, Sort rng)
- {
- Function g = new Function(Token.NoToken, name, new List<Variable>(), new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "dummy",rng)));
- return BoogieFunctionOp(g);
- }
-
- public Term MkApp(FuncDecl f, Term[] args)
- {
- return Function(f, args);
- }
-
- public Term MkApp(FuncDecl f, Term[] args, Type[]/*!*/ typeArguments)
- {
- return Function(f, args, typeArguments);
- }
-
- public Term MkApp(FuncDecl f, Term arg)
- {
- return Function(f, arg);
- }
-
- public Term CloneApp(Term t, Term[] args)
- {
- var f = t.GetAppDecl();
- var typeArgs = (t as VCExprNAry).TypeArguments;
- if (typeArgs != null && typeArgs.Count > 0)
- {
- return MkApp(f, args, typeArgs.ToArray());
- }
- else
- {
- return MkApp(f, args);
- }
- }
-
- public Term MkAnd(Term[] args)
- {
- if (args.Length == 0) return True;
- Term res = args[0];
- for (int i = 1; i < args.Length; i++)
- res = And(res, args[i]);
- return res;
- }
-
- public Term MkAnd(Term arg1, Term arg2)
- {
- return And(arg1, arg2);
- }
-
-
- public Term MkNot(Term arg1)
- {
- return Not(arg1);
- }
-
- public Term MkImplies(Term arg1, Term arg2)
- {
- return Implies(arg1, arg2);
- }
-
- public Term MkEq(Term arg1, Term arg2)
- {
- return Eq(arg1, arg2);
- }
-
- public Sort MkBoolSort()
- {
- return Type.Bool;
- }
-
- public Term MkConst(string name, Sort sort)
- {
- return Variable(name, sort);
- }
-
- public Term MkForall(Term[] bounds, Term body)
- {
- if (bounds.Length == 0)
- return body;
- List<VCExprVar> vbs = new List<VCExprVar>();
- foreach(var v in bounds)
- vbs.Add(v as VCExprVar);
- return Forall(vbs,new List<VCTrigger>(), body);
- }
-
- public Term MkExists(Term[] bounds, Term body)
- {
- if (bounds.Length == 0)
- return body;
- List<VCExprVar> vbs = new List<VCExprVar>();
- foreach (var v in bounds)
- vbs.Add(v as VCExprVar);
- return Exists(vbs, new List<VCTrigger>(), body);
- }
-
- private class Letifier
- {
- private class counter
- {
- public int cnt = 0;
- }
- TermDict<counter> refcnt = new TermDict<counter>();
- List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
- TermDict< VCExprVar> bindingMap = new TermDict< VCExprVar>();
- int letcnt = 0;
- Context ctx;
-
- public Letifier(Context _ctx) { ctx = _ctx; }
-
- private void RefCnt(Term t)
- {
- counter cnt;
- if (!refcnt.TryGetValue(t, out cnt))
- {
- cnt = new counter();
- refcnt.Add(t, cnt);
- }
- cnt.cnt++;
- if (cnt.cnt == 1)
- {
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var args = t.GetAppArgs();
- foreach (var arg in args)
- RefCnt(arg);
- }
- else if (t is VCExprQuantifier)
- {
- RefCnt((t as VCExprQuantifier).Body);
- }
- }
- }
-
- private Term Doit(Term t)
- {
- VCExprVar v;
- if (bindingMap.TryGetValue(t, out v))
- {
- return v;
- }
- Term res = null;
- var kind = t.GetKind();
- bool letok = false;
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- var args = t.GetAppArgs();
- args = args.Select(x => Doit(x)).ToArray();
- res = ctx.MkApp(f, args);
- letok = true;
- }
- else if (t is VCExprQuantifier)
- {
- var q = t as VCExprQuantifier;
- var newbody = ctx.Letify(q.Body);
- if (q.Quan == Quantifier.ALL)
- res = ctx.Forall(q.BoundVars, q.Triggers, newbody);
- else
- res = ctx.Exists(q.BoundVars, q.Triggers, newbody);
- letok = true;
- }
- else res = t;
- if (letok && refcnt[t].cnt > 1)
- {
- VCExprVar lv = ctx.MkConst("fpvc$" + Convert.ToString(letcnt), t.GetSort()) as VCExprVar;
- VCExprLetBinding b = ctx.LetBinding(lv, res);
- bindings.Add(b);
- bindingMap.Add(t, lv);
- res = lv;
- letcnt++;
- }
- return res;
- }
-
- public Term Letify(Term t)
- {
- RefCnt(t);
- Term res = Doit(t);
- if (bindings.Count > 0)
- res = ctx.Let(bindings, res);
- return res;
- }
-
- }
-
- public Term Letify(Term t)
- {
- var thing = new Letifier(this);
- return thing.Letify(t);
- }
-
- };
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Term = Microsoft.Boogie.VCExprAST.VCExpr;
+using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp;
+using Sort = Microsoft.Boogie.Type;
+using Microsoft.Boogie.VCExprAST;
+
+
+/** This namespace contains some extensions to allow VCExpr to provide the
+ * interface needed by RPFP and FixedpointVC. */
+
+namespace Microsoft.Boogie.ExprExtensions
+{
+ class ReferenceComparer<T> : IEqualityComparer<T> where T : class
+ {
+ private static ReferenceComparer<T> m_instance;
+
+ public static ReferenceComparer<T> Instance
+ {
+ get
+ {
+ return m_instance ?? (m_instance = new ReferenceComparer<T>());
+ }
+ }
+
+ public bool Equals(T x, T y)
+ {
+ return ReferenceEquals(x, y);
+ }
+
+ public int GetHashCode(T obj)
+ {
+ return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
+ }
+ }
+
+ public class TermDict<T> : Dictionary<Term, T>
+ {
+ public TermDict() : base(ReferenceComparer<Term>.Instance) { }
+ }
+
+
+
+ public enum TermKind { App, Other };
+
+ public enum DeclKind { Uninterpreted, And, Implies, Label, Other };
+
+ public static class MyExtensions
+ {
+ public static Term[] GetAppArgs(this Term t)
+ {
+ Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry;
+ return tn.ToArray();
+ }
+
+ public static FuncDecl GetAppDecl(this Term t)
+ {
+ Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry;
+ return tn.Op;
+ }
+
+ public static string GetDeclName(this FuncDecl f)
+ {
+ return (f as VCExprBoogieFunctionOp).Func.Name; //TODO
+ }
+
+ public static DeclKind GetKind(this FuncDecl f)
+ {
+ if (f is VCExprBoogieFunctionOp)
+ return DeclKind.Uninterpreted;
+ if (f == VCExpressionGenerator.AndOp)
+ return DeclKind.And;
+ if (f == VCExpressionGenerator.ImpliesOp)
+ return DeclKind.Implies;
+ if (f is VCExprLabelOp)
+ return DeclKind.Label;
+ return DeclKind.Other;
+ }
+
+ public static bool IsLabel(this Term t)
+ {
+ return (t is VCExprNAry) && (GetAppDecl(t) is VCExprLabelOp);
+ }
+
+ public static string LabelName(this Term t)
+ {
+ return (GetAppDecl(t) as VCExprLabelOp).label;
+ }
+
+ public static Sort GetSort(this Term t)
+ {
+ return t.Type;
+ }
+
+ public static TermKind GetKind(this Term t)
+ {
+ if (t is Microsoft.Boogie.VCExprAST.VCExprNAry)
+ return TermKind.App;
+ return TermKind.Other;
+ }
+
+ public static bool IsFunctionApp(this Term t)
+ {
+ return t.GetKind() == TermKind.App && t.GetAppDecl().GetKind() == DeclKind.Uninterpreted;
+ }
+
+ public static bool IsFalse(this Term t)
+ {
+ return t == VCExpressionGenerator.False;
+ }
+
+ public static Term VCExprToTerm(this Microsoft.Boogie.ProverContext ctx, VCExpr e, LineariserOptions lin){
+ return e;
+ }
+
+ }
+
+ public class Context : Microsoft.Boogie.VCExpressionGenerator
+ {
+ public Term MkTrue()
+ {
+ return VCExpressionGenerator.True;
+ }
+
+ public Term MkFalse()
+ {
+ return VCExpressionGenerator.False;
+ }
+
+
+ public List<Term> axioms = new List<Term>();
+
+ public void AddAxiom(Term ax)
+ {
+ axioms.Add(ax);
+ }
+
+ public void RemoveAxiom(Term ax)
+ {
+ axioms.Remove(ax);
+ }
+
+ public FuncDecl MkFuncDecl(string name, FuncDecl f)
+ {
+ Function h = (f as VCExprBoogieFunctionOp).Func;
+ Function g = new Function(Token.NoToken, name, h.InParams, h.OutParams[0]);
+ return BoogieFunctionOp(g);
+ }
+
+ public FuncDecl MkFuncDecl(string name, Sort rng)
+ {
+ Function g = new Function(Token.NoToken, name, new List<Variable>(), new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "dummy",rng)));
+ return BoogieFunctionOp(g);
+ }
+
+ public Term MkApp(FuncDecl f, Term[] args)
+ {
+ return Function(f, args);
+ }
+
+ public Term MkApp(FuncDecl f, Term[] args, Type[]/*!*/ typeArguments)
+ {
+ return Function(f, args, typeArguments);
+ }
+
+ public Term MkApp(FuncDecl f, Term arg)
+ {
+ return Function(f, arg);
+ }
+
+ public Term CloneApp(Term t, Term[] args)
+ {
+ var f = t.GetAppDecl();
+ var typeArgs = (t as VCExprNAry).TypeArguments;
+ if (typeArgs != null && typeArgs.Count > 0)
+ {
+ return MkApp(f, args, typeArgs.ToArray());
+ }
+ else
+ {
+ return MkApp(f, args);
+ }
+ }
+
+ public Term MkAnd(Term[] args)
+ {
+ if (args.Length == 0) return True;
+ Term res = args[0];
+ for (int i = 1; i < args.Length; i++)
+ res = And(res, args[i]);
+ return res;
+ }
+
+ public Term MkAnd(Term arg1, Term arg2)
+ {
+ return And(arg1, arg2);
+ }
+
+
+ public Term MkNot(Term arg1)
+ {
+ return Not(arg1);
+ }
+
+ public Term MkImplies(Term arg1, Term arg2)
+ {
+ return Implies(arg1, arg2);
+ }
+
+ public Term MkEq(Term arg1, Term arg2)
+ {
+ return Eq(arg1, arg2);
+ }
+
+ public Sort MkBoolSort()
+ {
+ return Type.Bool;
+ }
+
+ public Term MkConst(string name, Sort sort)
+ {
+ return Variable(name, sort);
+ }
+
+ public Term MkForall(Term[] bounds, Term body)
+ {
+ if (bounds.Length == 0)
+ return body;
+ List<VCExprVar> vbs = new List<VCExprVar>();
+ foreach(var v in bounds)
+ vbs.Add(v as VCExprVar);
+ return Forall(vbs,new List<VCTrigger>(), body);
+ }
+
+ public Term MkExists(Term[] bounds, Term body)
+ {
+ if (bounds.Length == 0)
+ return body;
+ List<VCExprVar> vbs = new List<VCExprVar>();
+ foreach (var v in bounds)
+ vbs.Add(v as VCExprVar);
+ return Exists(vbs, new List<VCTrigger>(), body);
+ }
+
+ private class Letifier
+ {
+ private class counter
+ {
+ public int cnt = 0;
+ }
+ TermDict<counter> refcnt = new TermDict<counter>();
+ List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
+ TermDict< VCExprVar> bindingMap = new TermDict< VCExprVar>();
+ int letcnt = 0;
+ Context ctx;
+
+ public Letifier(Context _ctx) { ctx = _ctx; }
+
+ private void RefCnt(Term t)
+ {
+ counter cnt;
+ if (!refcnt.TryGetValue(t, out cnt))
+ {
+ cnt = new counter();
+ refcnt.Add(t, cnt);
+ }
+ cnt.cnt++;
+ if (cnt.cnt == 1)
+ {
+ var kind = t.GetKind();
+ if (kind == TermKind.App)
+ {
+ var args = t.GetAppArgs();
+ foreach (var arg in args)
+ RefCnt(arg);
+ }
+ else if (t is VCExprQuantifier)
+ {
+ RefCnt((t as VCExprQuantifier).Body);
+ }
+ }
+ }
+
+ private Term Doit(Term t)
+ {
+ VCExprVar v;
+ if (bindingMap.TryGetValue(t, out v))
+ {
+ return v;
+ }
+ Term res = null;
+ var kind = t.GetKind();
+ bool letok = false;
+ if (kind == TermKind.App)
+ {
+ var f = t.GetAppDecl();
+ var args = t.GetAppArgs();
+ args = args.Select(x => Doit(x)).ToArray();
+ res = ctx.MkApp(f, args);
+ letok = true;
+ }
+ else if (t is VCExprQuantifier)
+ {
+ var q = t as VCExprQuantifier;
+ var newbody = ctx.Letify(q.Body);
+ if (q.Quan == Quantifier.ALL)
+ res = ctx.Forall(q.BoundVars, q.Triggers, newbody);
+ else
+ res = ctx.Exists(q.BoundVars, q.Triggers, newbody);
+ letok = true;
+ }
+ else res = t;
+ if (letok && refcnt[t].cnt > 1)
+ {
+ VCExprVar lv = ctx.MkConst("fpvc$" + Convert.ToString(letcnt), t.GetSort()) as VCExprVar;
+ VCExprLetBinding b = ctx.LetBinding(lv, res);
+ bindings.Add(b);
+ bindingMap.Add(t, lv);
+ res = lv;
+ letcnt++;
+ }
+ return res;
+ }
+
+ public Term Letify(Term t)
+ {
+ RefCnt(t);
+ Term res = Doit(t);
+ if (bindings.Count > 0)
+ res = ctx.Let(bindings, res);
+ return res;
+ }
+
+ }
+
+ public Term Letify(Term t)
+ {
+ var thing = new Letifier(this);
+ return thing.Letify(t);
+ }
+
+ };
+}
diff --git a/Source/VCGeneration/FixedpointVC.cs b/Source/VCGeneration/FixedpointVC.cs
index 5c698633..c636ea2b 100644
--- a/Source/VCGeneration/FixedpointVC.cs
+++ b/Source/VCGeneration/FixedpointVC.cs
@@ -1,2235 +1,2245 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.IO;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie;
-using Microsoft.Boogie.VCExprAST;
-
-
-using Term = Microsoft.Boogie.VCExprAST.VCExpr;
-using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp;
-using Sort = Microsoft.Boogie.Type;
-using Microsoft.Boogie.ExprExtensions;
-
-
-namespace Microsoft.Boogie
-{
- public class FixedpointVC : VC.VCGen
- {
-
- public class AnnotationInfo
- {
- public enum AnnotationType { LoopInvariant, ProcedureSummary };
- public string filename;
- public int lineno;
- public string[] argnames;
- public AnnotationType type;
- };
-
- static bool NoLabels = false;
-
- // options
- bool largeblock = false;
-
- public bool SetOption(string option, string value)
- {
- if (option == "LargeBlock")
- {
- largeblock = true;
- return true;
- }
- return false;
- }
-
- Context ctx;
- RPFP rpfp;
- // Program program;
- Microsoft.Boogie.ProverContext boogieContext;
- Microsoft.Boogie.VCExpressionGenerator gen;
- public readonly static string recordProcName = "boogie_si_record"; // TODO: this really needed?
- private Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo
- = new Dictionary<string, StratifiedInliningInfo>();
- Checker checker;
- // Microsoft.Boogie.Z3.Z3InstanceOptions options = new Microsoft.Boogie.Z3.Z3InstanceOptions(); // TODO: what?
- LineariserOptions linOptions;
- Dictionary<FuncDecl, StratifiedInliningInfo> relationToProc = new Dictionary<FuncDecl, StratifiedInliningInfo>();
- Dictionary<string, Term> labels = new Dictionary<string, Term> ();
- List<Term> DualityVCs = new List<Term>();
- Dictionary<string, bool> summaries = new Dictionary<string, bool>();
- Dictionary<Block, List<Block>> edgesCut = new Dictionary<Block, List<Block>>();
- string main_proc_name = "main";
- Dictionary<string, int> extraRecBound = null;
-
-
- public enum Mode { Corral, OldCorral, Boogie};
- public enum AnnotationStyle { Flat, Procedure, Call };
-
- Mode mode;
- AnnotationStyle style;
-
- private static Checker old_checker = null;
-
- public static void CleanUp()
- {
- if (old_checker != null)
- {
- old_checker.Close();
- old_checker = null;
- }
- }
-
- public FixedpointVC( Program _program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers, Dictionary<string,int> _extraRecBound = null)
- : base(_program, logFilePath, appendLogFile, checkers)
- {
- switch (CommandLineOptions.Clo.FixedPointMode)
- {
- case CommandLineOptions.FixedPointInferenceMode.Corral:
- mode = Mode.Corral;
- style = AnnotationStyle.Procedure;
- break;
- case CommandLineOptions.FixedPointInferenceMode.OldCorral:
- mode = Mode.OldCorral;
- style = AnnotationStyle.Procedure;
- break;
- case CommandLineOptions.FixedPointInferenceMode.Flat:
- mode = Mode.Boogie;
- style = AnnotationStyle.Flat;
- break;
- case CommandLineOptions.FixedPointInferenceMode.Procedure:
- mode = Mode.Boogie;
- style = AnnotationStyle.Procedure;
- break;
- case CommandLineOptions.FixedPointInferenceMode.Call:
- mode = Mode.Boogie;
- style = AnnotationStyle.Call;
- break;
- }
- ctx = new Context(); // TODO is this right?
- rpfp = new RPFP(RPFP.CreateLogicSolver(ctx));
- program = _program;
- gen = ctx;
- if(old_checker == null)
- checker = new Checker(this, program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime, null);
- else {
- checker = old_checker;
- checker.RetargetWithoutReset(program,checker.TheoremProver.Context);
- }
- old_checker = checker;
- boogieContext = checker.TheoremProver.Context;
- linOptions = null; // new Microsoft.Boogie.Z3.Z3LineariserOptions(false, options, new List<VCExprVar>());
- extraRecBound = _extraRecBound;
- }
-
- Dictionary<string, AnnotationInfo> annotationInfo = new Dictionary<string, AnnotationInfo>();
-
- public void AnnotateLoops(Implementation impl, ProverContext ctxt)
- {
- Contract.Requires(impl != null);
-
- CurrentLocalVariables = impl.LocVars;
- variable2SequenceNumber = new Dictionary<Variable, int>();
- incarnationOriginMap = new Dictionary<Incarnation, Absy>();
-
- ResetPredecessors(impl.Blocks);
-
- #region Create the graph by adding the source node and each edge
- GraphUtil.Graph<Block> g = Program.GraphFromImpl(impl);
- #endregion
-
- //Graph<Block> g = program.ProcessLoops(impl);
-
- g.ComputeLoops(); // this is the call that does all of the processing
- if (!g.Reducible)
- {
- throw new System.Exception("Irreducible flow graphs are unsupported.");
- }
-
- #region add a symbolic annoation to every loop head
- foreach (Block header in cce.NonNull(g.Headers))
- AnnotateBlock(impl, ctxt, header);
- #endregion
- }
-
- private void AnnotateCallSites(Implementation impl, ProverContext ctxt, Dictionary<string, bool> impls){
- foreach (var b in impl.Blocks)
- {
- foreach (var cmd in b.Cmds)
- {
- if (cmd is CallCmd)
- {
- string name = (cmd as CallCmd).callee;
- if(impls.ContainsKey(name))
- goto annotate;
- }
- }
- continue;
- annotate:
- AnnotateBlock(impl, ctxt, b);
- }
- }
-
-
- private void AnnotateBlock(Implementation impl, ProverContext ctxt, Block header)
- {
- Contract.Assert(header != null);
-
- string name = impl.Name + "_" + header.Label + "_invar";
- if (annotationInfo.ContainsKey(name))
- return;
-
- // collect the variables needed in the invariant
- List<Expr> exprs = new List<Expr>();
- List<Variable> vars = new List<Variable>();
- List<string> names = new List<string>();
-
- if (style == AnnotationStyle.Flat)
- {
- // in flat mode, all live globals should be in live set
-#if false
- foreach (Variable v in program.GlobalVariables)
- {
- vars.Add(v);
- names.Add(v.ToString());
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
-#endif
- foreach (Variable v in /* impl.LocVars */ header.liveVarsBefore)
- {
- if (!(v is BoundVariable))
- {
- vars.Add(v);
- names.Add(v.ToString());
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- }
- }
- else
- {
- foreach (Variable v in program.GlobalVariables)
- {
- vars.Add(v);
- names.Add("@old_" + v.ToString());
- exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
- }
- foreach (IdentifierExpr ie in impl.Proc.Modifies)
- {
- if (ie.Decl == null)
- continue;
- vars.Add(ie.Decl);
- names.Add(ie.Decl.ToString());
- exprs.Add(ie);
- }
- foreach (Variable v in impl.Proc.InParams)
- {
- Contract.Assert(v != null);
- vars.Add(v);
- names.Add("@old_" + v.ToString());
- exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
- }
- foreach (Variable v in impl.LocVars)
- {
- vars.Add(v);
- names.Add(v.ToString());
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- }
-
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
- var function = new Function(Token.NoToken, name, vars, returnVar);
- ctxt.DeclareFunction(function, "");
-
- Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
- var invarAssertion = new AssertCmd(Token.NoToken, invarExpr);
- List<Cmd> newCmds = new List<Cmd>();
- newCmds.Add(invarAssertion);
-
- // make a record in annotationInfo;
- var info = new AnnotationInfo();
- info.filename = header.tok.filename;
- info.lineno = header.Line;
- info.argnames = names.ToArray();
- info.type = AnnotationInfo.AnnotationType.LoopInvariant;
- annotationInfo.Add(name, info);
- // get file and line info from havoc, if there is...
- if (header.Cmds.Count > 0)
- {
- PredicateCmd bif = header.Cmds[0] as PredicateCmd;
- if (bif != null)
- {
- string foo = QKeyValue.FindStringAttribute(bif.Attributes, "sourcefile");
- if (foo != null)
- info.filename = foo;
- int bar = QKeyValue.FindIntAttribute(bif.Attributes, "sourceline", -1);
- if (bar != -1)
- info.lineno = bar;
- }
- }
- var thing = header;
- foreach (Cmd c in header.Cmds)
- {
- newCmds.Add(c);
- }
- header.Cmds = newCmds;
- }
-
-#if true
- public void AnnotateProcRequires(Procedure proc, Implementation impl, ProverContext ctxt)
- {
- Contract.Requires(impl != null);
-
- CurrentLocalVariables = impl.LocVars;
-
- // collect the variables needed in the invariant
- List<Expr> exprs = new List<Expr>();
- List<Variable> vars = new List<Variable>();
- List<string> names = new List<string>();
-
- foreach (Variable v in program.GlobalVariables)
- {
- vars.Add(v);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- names.Add(v.Name);
- }
- foreach (Variable v in proc.InParams)
- {
- Contract.Assert(v != null);
- vars.Add(v);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- names.Add(v.Name);
- }
- string name = impl.Name + "_precond";
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
- var function = new Function(Token.NoToken, name, vars, returnVar);
- ctxt.DeclareFunction(function, "");
-
- Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
-
- proc.Requires.Add(new Requires(Token.NoToken, false, invarExpr, "", null));
-
- var info = new AnnotationInfo();
- info.filename = proc.tok.filename;
- info.lineno = proc.Line;
- info.argnames = names.ToArray();
- info.type = AnnotationInfo.AnnotationType.LoopInvariant;
- annotationInfo.Add(name, info);
- }
-
- public void AnnotateProcEnsures(Procedure proc, Implementation impl, ProverContext ctxt)
- {
- Contract.Requires(impl != null);
-
- CurrentLocalVariables = impl.LocVars;
-
- // collect the variables needed in the invariant
- List<Expr> exprs = new List<Expr>();
- List<Variable> vars = new List<Variable>();
- List<string> names = new List<string>();
-
- foreach (Variable v in program.GlobalVariables)
- {
- vars.Add(v);
- exprs.Add(new OldExpr(Token.NoToken,new IdentifierExpr(Token.NoToken, v)));
- names.Add(v.Name);
- }
- foreach (Variable v in proc.InParams)
- {
- Contract.Assert(v != null);
- vars.Add(v);
- exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
- names.Add(v.Name);
- }
- foreach (IdentifierExpr ie in proc.Modifies)
- {
- if (ie.Decl == null)
- continue;
- vars.Add(ie.Decl);
- exprs.Add(ie);
- names.Add(ie.Decl.Name + "_out");
- }
- foreach (Variable v in proc.OutParams)
- {
- Contract.Assert(v != null);
- vars.Add(v);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- names.Add(v.Name);
- }
- string name = impl.Name + "_summary";
- summaries.Add(name, true);
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
- var function = new Function(Token.NoToken, name, vars, returnVar);
- ctxt.DeclareFunction(function, "");
-
- Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
-
- proc.Ensures.Add(new Ensures(Token.NoToken, false, invarExpr, "", null));
-
- var info = new AnnotationInfo();
- info.filename = proc.tok.filename;
- info.lineno = proc.Line;
- info.argnames = names.ToArray();
- info.type = AnnotationInfo.AnnotationType.ProcedureSummary;
- annotationInfo.Add(name, info);
- }
-#endif
-
- void MarkAllFunctionImplementationsInline()
- {
- foreach (var func in program.Functions)
- {
- if (func.Body == null && func.DefinitionAxiom != null)
- {
- var def = func.DefinitionAxiom.Expr as QuantifierExpr;
- var bod = def.Body as NAryExpr;
- func.Body = bod.Args[1];
- func.DefinitionAxiom = null;
- }
- if (func.Body != null)
- if (func.FindExprAttribute("inline") == null)
- func.AddAttribute("inline", Expr.Literal(100));
- }
- }
-
- void InlineAll()
- {
- foreach (var impl in program.Implementations)
- {
- impl.OriginalBlocks = impl.Blocks;
- impl.OriginalLocVars = impl.LocVars;
- if(impl.Name != main_proc_name)
- if(impl.FindExprAttribute("inline") == null)
- impl.AddAttribute("inline", Expr.Literal(100));
- }
- foreach (var impl in program.Implementations)
- {
- if (!impl.SkipVerification)
- {
- Inliner.ProcessImplementation(program, impl);
- }
- }
- foreach (var impl in program.Implementations)
- {
- impl.OriginalBlocks = null;
- impl.OriginalLocVars = null;
- }
- }
-
- public class LazyInliningInfo
- {
- [ContractInvariantMethod]
- void ObjectInvariant()
- {
- Contract.Invariant(impl != null);
- Contract.Invariant(function != null);
- Contract.Invariant(controlFlowVariable != null);
- Contract.Invariant(assertExpr != null);
- Contract.Invariant(cce.NonNullElements(interfaceVars));
- Contract.Invariant(incarnationOriginMap == null || cce.NonNullDictionaryAndValues(incarnationOriginMap));
- }
-
- public Implementation impl;
- public int uniqueId;
- public Function function;
- public Variable controlFlowVariable;
- public List<Variable> interfaceVars;
- public List<List<Variable>> interfaceVarCopies;
- public Expr assertExpr;
- public VCExpr vcexpr;
- public List<VCExprVar> privateVars;
- public Dictionary<Incarnation, Absy> incarnationOriginMap;
- public Hashtable /*Variable->Expr*/ exitIncarnationMap;
- public Hashtable /*GotoCmd->returnCmd*/ gotoCmdOrigins;
- public Dictionary<int, Absy> label2absy;
- public VC.ModelViewInfo mvInfo;
-
- public Dictionary<Block, VCExprVar> reachVars;
- public List<VCExprLetBinding> reachVarBindings;
- public Variable inputErrorVariable;
- public Variable outputErrorVariable;
-
-
-
- public LazyInliningInfo(Implementation impl, Program program, ProverContext ctxt, int uniqueId, GlobalVariable errorVariable)
- {
- Contract.Requires(impl != null);
- Contract.Requires(program != null);
- Procedure proc = cce.NonNull(impl.Proc);
-
- this.impl = impl;
- this.uniqueId = uniqueId;
- this.controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "cfc", Microsoft.Boogie.Type.Int));
- impl.LocVars.Add(controlFlowVariable);
-
- List<Variable> interfaceVars = new List<Variable>();
- Expr assertExpr = new LiteralExpr(Token.NoToken, true);
- Contract.Assert(assertExpr != null);
- foreach (Variable v in program.GlobalVariables)
- {
- Contract.Assert(v != null);
- interfaceVars.Add(v);
- if (v.Name == "error")
- inputErrorVariable = v;
- }
- // InParams must be obtained from impl and not proc
- foreach (Variable v in impl.InParams)
- {
- Contract.Assert(v != null);
- interfaceVars.Add(v);
- }
- // OutParams must be obtained from impl and not proc
- foreach (Variable v in impl.OutParams)
- {
- Contract.Assert(v != null);
- Constant c = new Constant(Token.NoToken,
- new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- interfaceVars.Add(c);
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertExpr = Expr.And(assertExpr, eqExpr);
- }
- if (errorVariable != null)
- {
- proc.Modifies.Add(new IdentifierExpr(Token.NoToken, errorVariable));
- }
- foreach (IdentifierExpr e in proc.Modifies)
- {
- Contract.Assert(e != null);
- if (e.Decl == null)
- continue;
- Variable v = e.Decl;
- Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- interfaceVars.Add(c);
- if (v.Name == "error")
- {
- outputErrorVariable = c;
- continue;
- }
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertExpr = Expr.And(assertExpr, eqExpr);
- }
-
- this.interfaceVars = interfaceVars;
- this.assertExpr = Expr.Not(assertExpr);
- List<Variable> functionInterfaceVars = new List<Variable>();
- foreach (Variable v in interfaceVars)
- {
- Contract.Assert(v != null);
- functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, v.Name, v.TypedIdent.Type), true));
- }
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
- this.function = new Function(Token.NoToken, proc.Name, functionInterfaceVars, returnVar);
- ctxt.DeclareFunction(this.function, "");
-
- interfaceVarCopies = new List<List<Variable>>();
- int temp = 0;
- for (int i = 0; i < /* CommandLineOptions.Clo.ProcedureCopyBound */ 0; i++)
- {
- interfaceVarCopies.Add(new List<Variable>());
- foreach (Variable v in interfaceVars)
- {
- Constant constant = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, v.Name + temp++, v.TypedIdent.Type));
- interfaceVarCopies[i].Add(constant);
- //program.AddTopLevelDeclaration(constant);
- }
- }
- }
- }
-
- public class StratifiedInliningInfo : LazyInliningInfo
- {
- [ContractInvariantMethod]
- void ObjectInvariant()
- {
- Contract.Invariant(cce.NonNullElements(privateVars));
- Contract.Invariant(cce.NonNullElements(interfaceExprVars));
- Contract.Invariant(cce.NonNullElements(interfaceExprVars));
- }
-
- // public StratifiedVCGenBase vcgen;
- //public Implementation impl;
- //public Program program;
- //public ProverContext ctxt;
- //public int uniqueid;
- //public Function function;
- //public Variable controlFlowVariable;
- //public Expr assertExpr;
- //public VCExpr vcexpr;
- //public List<VCExprVar> interfaceExprVars;
- //public List<VCExprVar> privateExprVars;
- //public Dictionary<int, Absy> label2absy;
- //public VC.ModelViewInfo mvInfo;
- //public Dictionary<Block, List<CallSite>> callSites;
- //public Dictionary<Block, List<CallSite>> recordProcCallSites;
- //public IEnumerable<Block> sortedBlocks;
- //public bool initialized { get; private set; }
-
-
- public List<VCExprVar> interfaceExprVars;
- // public List<VCExprVar> privateVars;
- public VCExpr funcExpr;
- public VCExpr falseExpr;
- public RPFP.Transformer F;
- public RPFP.Node node;
- public RPFP.Edge edge;
- public bool isMain = false;
- public Dictionary<Absy, string> label2absyInv;
- public ProverContext ctxt;
- public Hashtable/*<Block, LetVariable!>*/ blockVariables = new Hashtable/*<Block, LetVariable!!>*/();
- public List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
-
- public StratifiedInliningInfo(Implementation _impl, Program _program, ProverContext _ctxt, int _uniqueid)
- : base(_impl,_program,_ctxt,_uniqueid,null){
- Contract.Requires(_impl != null);
- Contract.Requires(_program != null);
- privateVars = new List<VCExprVar>();
- interfaceExprVars = new List<VCExprVar>();
- ctxt = _ctxt;
- }
-
- }
-
- protected override void addExitAssert(string implName, Block exitBlock)
- {
- if (implName2StratifiedInliningInfo != null
- && implName2StratifiedInliningInfo.ContainsKey(implName)
- && !implName2StratifiedInliningInfo[implName].isMain)
- {
- if (mode == Mode.Boogie) return;
- Expr assertExpr = implName2StratifiedInliningInfo[implName].assertExpr;
- Contract.Assert(assertExpr != null);
- exitBlock.Cmds.Add(new AssertCmd(Token.NoToken, assertExpr));
- }
- }
-
-#if false
- protected override void storeIncarnationMaps(string implName, Hashtable exitIncarnationMap)
- {
- if (implName2StratifiedInliningInfo != null && implName2StratifiedInliningInfo.ContainsKey(implName))
- {
- StratifiedInliningInfo info = implName2StratifiedInliningInfo[implName];
- Contract.Assert(info != null);
- info.exitIncarnationMap = exitIncarnationMap;
- info.incarnationOriginMap = this.incarnationOriginMap;
- }
- }
-#endif
-
- public void GenerateVCsForStratifiedInlining()
- {
- Contract.Requires(program != null);
- foreach (var impl in program.Implementations)
- {
- Contract.Assert(!impl.Name.StartsWith(recordProcName), "Not allowed to have an implementation for this guy");
-
- Procedure proc = cce.NonNull(impl.Proc);
-
- {
- StratifiedInliningInfo info = new StratifiedInliningInfo(impl, program, boogieContext, QuantifierExpr.GetNextSkolemId());
- implName2StratifiedInliningInfo[impl.Name] = info;
- // We don't need controlFlowVariable for stratified Inlining
- //impl.LocVars.Add(info.controlFlowVariable);
- List<Expr> exprs = new List<Expr>();
-
- if (mode != Mode.Boogie && QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
- {
- proc.Ensures.Add(new Ensures(Token.NoToken, true, Microsoft.Boogie.Expr.False, "", null));
- info.assertExpr = Microsoft.Boogie.Expr.False;
- // info.isMain = true;
- }
- else if (mode == Mode.Corral || proc.FindExprAttribute("inline") != null || proc is LoopProcedure)
- {
- foreach (Variable v in program.GlobalVariables)
- {
- Contract.Assert(v != null);
- exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
- }
- foreach (Variable v in proc.InParams)
- {
- Contract.Assert(v != null);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- foreach (Variable v in proc.OutParams)
- {
- Contract.Assert(v != null);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- foreach (IdentifierExpr ie in proc.Modifies)
- {
- Contract.Assert(ie != null);
- if (ie.Decl == null)
- continue;
- exprs.Add(ie);
- }
- Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(info.function), exprs);
-#if true
- if(mode == Mode.Corral || mode == Mode.OldCorral)
- proc.Ensures.Add(new Ensures(Token.NoToken, true, freePostExpr, "", new QKeyValue(Token.NoToken, "si_fcall", new List<object>(), null)));
-#endif
- }
- else // not marked "inline" must be main
- {
- Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(info.function), exprs);
- info.isMain = true;
- }
- }
- }
-
- if (mode == Mode.Boogie) return;
-
- foreach (var proc in program.Procedures)
- {
- if (!proc.Name.StartsWith(recordProcName)) continue;
- Contract.Assert(proc.InParams.Count == 1);
-
- // Make a new function
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
-
- // Get record type
- var argtype = proc.InParams[0].TypedIdent.Type;
-
- var ins = new List<Variable>();
- ins.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "x", argtype), true));
-
- var recordFunc = new Function(Token.NoToken, proc.Name, ins, returnVar);
- boogieContext.DeclareFunction(recordFunc, "");
-
- var exprs = new List<Expr>();
- exprs.Add(new IdentifierExpr(Token.NoToken, proc.InParams[0]));
-
- Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(recordFunc), exprs);
- proc.Ensures.Add(new Ensures(true, freePostExpr));
- }
- }
-
- private void FixedPointToSpecs(){
-
- if(mode != Mode.Corral || CommandLineOptions.Clo.PrintFixedPoint == null)
- return; // not implemented for other annotation modes yet
-
- var twr = new TokenTextWriter(CommandLineOptions.Clo.PrintFixedPoint, /*pretty=*/ false);
- Dictionary<string, RPFP.Node> pmap = new Dictionary<string,RPFP.Node> ();
-
- foreach (var node in rpfp.nodes)
- pmap.Add ((node.Name as VCExprBoogieFunctionOp).Func.Name, node);
-
- foreach (var impl in program.Implementations)
- {
- Contract.Assert(!impl.Name.StartsWith(recordProcName), "Not allowed to have an implementation for this guy");
-
- Procedure proc = cce.NonNull(impl.Proc);
-
- {
- StratifiedInliningInfo info = new StratifiedInliningInfo(impl, program, boogieContext, QuantifierExpr.GetNextSkolemId());
- implName2StratifiedInliningInfo[impl.Name] = info;
- // We don't need controlFlowVariable for stratified Inlining
- //impl.LocVars.Add(info.controlFlowVariable);
- List<Expr> exprs = new List<Expr>();
-
- {
- if (pmap.ContainsKey(impl.Name))
- {
- RPFP.Node node = pmap[impl.Name];
- var annot = node.Annotation;
- EmitProcSpec(twr, proc, info, annot);
- }
- }
- }
- }
- twr.Close ();
- }
-
- private void EmitProcSpec(TokenTextWriter twr, Procedure proc, StratifiedInliningInfo info, RPFP.Transformer annot)
- {
- // last ensures clause will be the symbolic one
- if (!info.isMain)
- {
- var ens = proc.Ensures[proc.Ensures.Count - 1];
- if (ens.Condition != Expr.False) // this is main
- {
- var postExpr = ens.Condition as NAryExpr;
- var args = postExpr.Args;
-
- var ind = annot.IndParams;
- var bound = new Dictionary<VCExpr, Expr>();
- for (int i = 0; i < args.Count; i++)
- {
- bound[ind[i]] = args[i];
- }
- var new_ens_cond = VCExprToExpr(annot.Formula, bound);
- if (new_ens_cond != Expr.True)
- {
- var new_ens = new Ensures(false, new_ens_cond);
- var enslist = new List<Ensures>();
- enslist.Add(new_ens);
- var new_proc = new Procedure(proc.tok, proc.Name, proc.TypeParameters, proc.InParams,
- proc.OutParams, new List<Requires>(), new List<IdentifierExpr>(), enslist);
- new_proc.Emit(twr, 0);
- }
- }
- }
- }
-
- static int ConjectureFileCounter = 0;
-
- private void ConjecturesToSpecs()
- {
-
- if (mode != Mode.Corral || CommandLineOptions.Clo.PrintConjectures == null)
- return; // not implemented for other annotation modes yet
-
- var twr = new TokenTextWriter(CommandLineOptions.Clo.PrintConjectures + "." + ConjectureFileCounter.ToString(), /*pretty=*/ false);
- ConjectureFileCounter++;
-
- foreach (var c in rpfp.conjectures)
- {
- var name = c.node.Name.GetDeclName();
- if (implName2StratifiedInliningInfo.ContainsKey(name))
- {
- StratifiedInliningInfo info = implName2StratifiedInliningInfo[c.node.Name.GetDeclName()];
- Implementation impl = info.impl;
- Procedure proc = impl.Proc;
- EmitProcSpec(twr, proc, info, c.bound);
- }
- }
-
- twr.Close ();
- }
-
- private Term ExtractSmallerVCsRec(TermDict< Term> memo, Term t, List<Term> small, Term lbl = null)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- if (f.GetKind() == DeclKind.Implies){
- var lhs = t.GetAppArgs()[0];
- if(lhs.GetKind() == TermKind.App){
- var r = lhs.GetAppDecl();
- if (r.GetKind() == DeclKind.And)
- {
- Term q = t.GetAppArgs()[1];
- var lhsargs = lhs.GetAppArgs();
- for (int i = lhsargs.Length-1; i >= 0; --i)
- {
- q = ctx.MkImplies(lhsargs[i], q);
- }
- res = ExtractSmallerVCsRec(memo, q, small,lbl);
- goto done;
- }
- if (r.GetKind() == DeclKind.Label)
- {
- var arg = lhs;
- arg = lhs.GetAppArgs()[0];
- if (!(arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted))
- goto normal;
- if (!(annotationInfo.ContainsKey(arg.GetAppDecl().GetDeclName()) && annotationInfo[arg.GetAppDecl().GetDeclName()].type == AnnotationInfo.AnnotationType.LoopInvariant))
- goto normal;
- var sm = ctx.MkImplies(lhs, ExtractSmallerVCsRec(memo, t.GetAppArgs()[1], small));
- if (lbl != null)
- sm = ctx.MkImplies(lbl, sm);
- small.Add(sm);
- res = ctx.MkTrue();
- goto done;
- }
- if (r.GetKind() == DeclKind.Uninterpreted)
- {
- var arg = lhs;
- if (!(annotationInfo.ContainsKey(arg.GetAppDecl().GetDeclName()) && annotationInfo[arg.GetAppDecl().GetDeclName()].type == AnnotationInfo.AnnotationType.LoopInvariant))
- goto normal;
- var sm = ctx.MkImplies(lhs,ExtractSmallerVCsRec(memo,t.GetAppArgs()[1],small));
- if (lbl != null)
- sm = ctx.MkImplies(lbl, sm);
- small.Add(sm);
- res = ctx.MkTrue();
- goto done;
- }
- }
- normal:
- Term newlbl = null;
- if (lhs.IsLabel() && lhs.GetAppArgs()[0] == ctx.MkTrue())
- newlbl = lhs;
- res = ctx.MkImplies(lhs,ExtractSmallerVCsRec(memo,t.GetAppArgs()[1],small,newlbl));
- }
- else if (f.GetKind() == DeclKind.And)
- {
- res = ctx.MkApp(f,t.GetAppArgs().Select(x => ExtractSmallerVCsRec(memo, x, small)).ToArray());
- }
- else
- res = t;
- }
- else
- res = t;
- done:
- memo.Add(t, res);
- return res;
- }
-
- private void ExtractSmallerVCs(Term t, List<Term> small){
- TermDict< Term> memo = new TermDict< Term>();
- Term top = ExtractSmallerVCsRec(memo, t, small);
- small.Add(top);
- }
-
- private Dictionary<FuncDecl, int> goalNumbering = new Dictionary<FuncDecl, int>();
-
- private Term NormalizeGoal(Term goal, FuncDecl label)
- {
- var f = goal.GetAppDecl();
- var args = goal.GetAppArgs();
- int number;
- if (!goalNumbering.TryGetValue(f, out number))
- {
- number = goalNumbering.Count;
- goalNumbering.Add(f, number);
- }
- Term[] tvars = new Term[args.Length];
- Term[] eqns = new Term[args.Length];
- AnnotationInfo info = null;
- annotationInfo.TryGetValue(f.GetDeclName(), out info);
- for (int i = 0; i < args.Length; i++)
- {
- string pname = (info == null) ? i.ToString() : info.argnames[i];
- tvars[i] = ctx.MkConst("@a" + number.ToString() + "_" + pname, args[i].GetSort());
- eqns[i] = ctx.MkEq(tvars[i], args[i]);
- }
- return ctx.MkImplies(ctx.MkAnd(eqns), ctx.MkApp(label, ctx.MkApp(f, tvars)));
- }
-
- private Term MergeGoalsRec(TermDict< Term> memo, Term t)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- var args = t.GetAppArgs();
- if (f.GetKind() == DeclKind.Implies)
- {
- res = ctx.MkImplies(args[0], MergeGoalsRec(memo, args[1]));
- goto done;
- }
- else if (f.GetKind() == DeclKind.And)
- {
- args = args.Select(x => MergeGoalsRec(memo, x)).ToArray();
- res = ctx.MkApp(f, args);
- goto done;
- }
- else if (f.GetKind() == DeclKind.Label)
- {
- var arg = t.GetAppArgs()[0];
- var r = arg.GetAppDecl();
- if (r.GetKind() == DeclKind.Uninterpreted)
- {
- res = NormalizeGoal(arg, f);
- goto done;
- }
- }
- }
- res = t;
- done:
- memo.Add(t, res);
- return res;
- }
-
- private Term MergeGoals(Term t)
- {
- TermDict< Term> memo = new TermDict< Term>();
- return MergeGoalsRec(memo, t);
- }
-
- private Term CollectGoalsRec(TermDict< Term> memo, Term t, List<Term> goals, List<Term> cruft)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- if (f.GetKind() == DeclKind.Implies)
- {
- CollectGoalsRec(memo, t.GetAppArgs()[1], goals, cruft);
- goto done;
- }
- else if (f.GetKind() == DeclKind.And)
- {
- foreach (var arg in t.GetAppArgs())
- {
- CollectGoalsRec(memo, arg, goals, cruft);
- }
- goto done;
- }
- else if (f.GetKind() == DeclKind.Label)
- {
- var arg = t.GetAppArgs()[0];
- if (arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted)
- {
- var r = arg.GetAppDecl();
- if (memo.TryGetValue(arg, out res))
- goto done;
- if (!annotationInfo.ContainsKey(r.GetDeclName()) && !arg.GetAppDecl().GetDeclName().StartsWith("_solve_"))
- goto done;
- goals.Add(arg);
- memo.Add(arg, arg);
- goto done;
- }
- else
- return CollectGoalsRec(memo, arg, goals, cruft);
- }
- else if (f.GetKind() == DeclKind.Uninterpreted)
- {
- string name = f.GetDeclName();
- if (name.StartsWith("_solve_"))
- {
- if (memo.TryGetValue(t, out res))
- goto done;
- goals.Add(t);
- memo.Add(t, t);
- return t;
- }
- }
- }
- // else the goal must be cruft
- cruft.Add(t);
- done:
- res = t; // just to return something
- memo.Add(t, res);
- return res;
- }
-
- private void CollectGoals(Term t, List<Term> goals, List<Term> cruft)
- {
- TermDict< Term> memo = new TermDict< Term>();
- CollectGoalsRec(memo, t.GetAppArgs()[1], goals, cruft);
- }
-
- private Term SubstRec(TermDict< Term> memo, Term t)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- // var f = t.GetAppDecl();
- var args = t.GetAppArgs().Select(x => SubstRec(memo, x)).ToArray();
- res = ctx.CloneApp(t, args);
- }
- else res = t;
- memo.Add(t, res);
- return res;
- }
-
- private Term SubstRecGoals(TermDict< Term> memo, Term t)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- var args = t.GetAppArgs();
- if (f.GetKind() == DeclKind.Implies){
- res = SubstRecGoals(memo, args[1]);
- if (res != ctx.MkTrue())
- res = ctx.MkImplies(args[0],res);
- goto done;
- }
- else if (f.GetKind() == DeclKind.And)
- {
- args = args.Select(x => SubstRecGoals(memo, x)).ToArray();
- args = args.Where(x => x != ctx.MkTrue()).ToArray();
- res = ctx.MkAnd(args);
- goto done;
- }
- else if (f.GetKind() == DeclKind.Label)
- {
- var arg = t.GetAppArgs()[0];
- if (arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted)
- {
- var r = arg.GetAppDecl();
- if (memo.TryGetValue(arg, out res))
- {
- if(res != ctx.MkTrue())
- res = ctx.MkApp(f, res);
- goto done;
- }
- }
- else
- {
- res = ctx.MkApp(f, SubstRecGoals(memo, arg));
- goto done;
- }
-
- }
- // what's left could be cruft!
- if (memo.TryGetValue(t, out res))
- {
- goto done;
- }
- }
- res = t;
- done:
- memo.Add(t, res);
- return res;
- }
-
- private void FactorVCs(Term t, List<Term> vcs)
- {
- List<Term> small = new List<Term>();
- ExtractSmallerVCs(t, small);
- foreach (var smm in small)
- {
- List<Term> goals = new List<Term>();
- List<Term> cruft = new List<Term>();
- var sm = largeblock ? MergeGoals(smm) : smm;
- CollectGoals(sm, goals,cruft);
- foreach (var goal in goals)
- {
- TermDict< Term> memo = new TermDict< Term>();
- foreach (var othergoal in goals)
- memo.Add(othergoal, othergoal.Equals(goal) ? ctx.MkFalse() : ctx.MkTrue());
- foreach (var thing in cruft)
- memo.Add(thing, ctx.MkTrue());
- var vc = SubstRecGoals(memo, sm);
- vc = ctx.MkImplies(ctx.MkNot(vc), goal);
- vcs.Add(vc);
- }
- {
- TermDict< Term> memo = new TermDict< Term>();
- foreach (var othergoal in goals)
- memo.Add(othergoal, ctx.MkTrue());
- var vc = SubstRecGoals(memo, sm);
- if (vc != ctx.MkTrue())
- {
- vc = ctx.MkImplies(ctx.MkNot(vc), ctx.MkFalse());
- vcs.Add(vc);
- }
- }
- }
- }
-
-
-
- private void GenerateVCForStratifiedInlining(Program program, StratifiedInliningInfo info, Checker checker)
- {
- Contract.Requires(program != null);
- Contract.Requires(info != null);
- Contract.Requires(checker != null);
- Contract.Requires(info.impl != null);
- Contract.Requires(info.impl.Proc != null);
-
-
-
- Implementation impl = info.impl;
- if (mode == Mode.Boogie && style == AnnotationStyle.Flat && impl.Name != main_proc_name)
- return;
- Contract.Assert(impl != null);
- ConvertCFG2DAG(impl,edgesCut);
- VC.ModelViewInfo mvInfo;
- PassifyImpl(impl, out mvInfo);
- Dictionary<int, Absy> label2absy = null;
- VCExpressionGenerator gen = checker.VCExprGen;
- Contract.Assert(gen != null);
- VCExpr vcexpr;
- if(NoLabels){
- // int assertionCount = 0;
- VCExpr startCorrect = null; /* VC.VCGen.LetVC(cce.NonNull(impl.Blocks[0]), null, null, info.blockVariables, info.bindings,
- info.ctxt, out assertionCount); */
- vcexpr = gen.Let(info.bindings, startCorrect);
- }
- else vcexpr = GenerateVC(impl, null /* info.controlFlowVariable */, out label2absy, info.ctxt);
- if(mode != Mode.Boogie)
- vcexpr = gen.Not(vcexpr);
- Contract.Assert(vcexpr != null);
- info.label2absy = label2absy;
- info.mvInfo = mvInfo;
- List<VCExpr> interfaceExprs = new List<VCExpr>();
-
- if (true /* was: !info.isMain */)
- {
- Boogie2VCExprTranslator translator = checker.TheoremProver.Context.BoogieExprTranslator;
- Contract.Assert(translator != null);
- info.privateVars = new List<VCExprVar>();
- foreach (Variable v in impl.LocVars)
- {
- Contract.Assert(v != null);
- info.privateVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in impl.OutParams)
- {
- Contract.Assert(v != null);
- info.privateVars.Add(translator.LookupVariable(v));
- }
-
- info.interfaceExprVars = new List<VCExprVar>();
-
- foreach (Variable v in info.interfaceVars)
- {
- Contract.Assert(v != null);
- VCExprVar ev = translator.LookupVariable(v);
- Contract.Assert(ev != null);
- info.interfaceExprVars.Add(ev);
- interfaceExprs.Add(ev);
- }
- }
-
- Function function = cce.NonNull(info.function);
- Contract.Assert(function != null);
- info.funcExpr = gen.Function(function, interfaceExprs);
- info.vcexpr = vcexpr;
-
- if (mode == Mode.Boogie)
- {
- Term z3vc = boogieContext.VCExprToTerm(vcexpr, linOptions);
- FactorVCs(z3vc, DualityVCs);
- }
- else
- {
- // Index the procedures by relational variable
- FuncDecl R = boogieContext.VCExprToTerm(info.funcExpr, linOptions).GetAppDecl();
- relationToProc.Add(R, info);
- info.node = rpfp.CreateNode(boogieContext.VCExprToTerm(info.funcExpr, linOptions));
- rpfp.nodes.Add(info.node);
- if (info.isMain || QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
- info.node.Bound.Formula = ctx.MkFalse();
- }
- }
-
- // This returns a new FuncDel with same sort as top-level function
- // of term t, but with numeric suffix appended to name.
-
- private FuncDecl SuffixFuncDecl(Term t, int n)
- {
- var name = t.GetAppDecl().GetDeclName() + "_" + n.ToString();
- return ctx.MkFuncDecl(name, t.GetAppDecl());
- }
-
- // Collect the relational paremeters
-
- private Term CollectParamsRec(TermDict<Term> memo, Term t, List<FuncDecl> parms, List<RPFP.Node> nodes, Dictionary<Term,Term> done)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- var args = t.GetAppArgs();
- args = args.Select(x => CollectParamsRec(memo, x, parms, nodes, done)).ToArray();
- StratifiedInliningInfo info;
- if (relationToProc.TryGetValue(f, out info))
- {
- if (done.ContainsKey(t))
- res = done[t];
- else
- {
- f = SuffixFuncDecl(t, parms.Count);
- parms.Add(f);
- nodes.Add(info.node);
- res = ctx.MkApp(f, args);
- done.Add(t,res); // don't count same expression twice!
- }
- }
- else
- res = ctx.CloneApp(t, args);
- } // TODO: handle quantifiers
- else res = t;
- memo.Add(t, res);
- return res;
- }
-
- public void GetTransformer(StratifiedInliningInfo info)
- {
- Term vcTerm = boogieContext.VCExprToTerm(info.vcexpr, linOptions);
- Term[] paramTerms = info.interfaceExprVars.Select(x => boogieContext.VCExprToTerm(x, linOptions)).ToArray();
- var relParams = new List<FuncDecl>();
- var nodeParams = new List<RPFP.Node>();
- var memo = new TermDict< Term>();
- var done = new Dictionary<Term,Term>(); // note this hashes on equality, not reference!
- vcTerm = CollectParamsRec(memo, vcTerm, relParams, nodeParams,done);
- // var ops = new Util.ContextOps(ctx);
- // var foo = ops.simplify_lhs(vcTerm);
- // vcTerm = foo.Item1;
- info.F = rpfp.CreateTransformer(relParams.ToArray(), paramTerms, vcTerm);
- info.edge = rpfp.CreateEdge(info.node, info.F, nodeParams.ToArray());
- rpfp.edges.Add(info.edge);
- // TODO labels[info.edge.number] = foo.Item2;
- }
-
- public RPFP.Node GetNodeOfImpl(Implementation/*!*/ impl)
- {
- return implName2StratifiedInliningInfo[impl.Name].node;
- }
-
- public class CyclicLiveVariableAnalysis : Microsoft.Boogie.LiveVariableAnalysis
- {
- public new static void ComputeLiveVariables(Implementation impl)
- {
-
- bool some_change = true;
- List<Block> sortedNodes = new List<Block>();
- foreach (var block in impl.Blocks)
- {
- sortedNodes.Add(block);
- }
- sortedNodes.Reverse();
-
- while (some_change)
- {
- some_change = false;
- foreach (Block/*!*/ block in sortedNodes)
- {
- Contract.Assert(block != null);
- HashSet<Variable/*!*/>/*!*/ liveVarsAfter = new HashSet<Variable/*!*/>();
- if (block.TransferCmd is GotoCmd)
- {
- GotoCmd gotoCmd = (GotoCmd)block.TransferCmd;
- if (gotoCmd.labelTargets != null)
- {
- foreach (Block/*!*/ succ in gotoCmd.labelTargets)
- {
- Contract.Assert(succ != null);
- if (succ.liveVarsBefore != null)
- liveVarsAfter.UnionWith(succ.liveVarsBefore);
- }
- }
- }
-
- List<Cmd> cmds = block.Cmds;
- int len = cmds.Count;
- for (int i = len - 1; i >= 0; i--)
- {
- if (cmds[i] is CallCmd)
- {
- Procedure/*!*/ proc = cce.NonNull(cce.NonNull((CallCmd/*!*/)cmds[i]).Proc);
- if (InterProcGenKill.HasSummary(proc.Name))
- {
- liveVarsAfter =
- InterProcGenKill.PropagateLiveVarsAcrossCall(cce.NonNull((CallCmd/*!*/)cmds[i]), liveVarsAfter);
- continue;
- }
- }
- Propagate(cmds[i], liveVarsAfter);
- }
-
- if (block.liveVarsBefore == null)
- block.liveVarsBefore = new HashSet<Variable>();
- if (!liveVarsAfter.IsSubsetOf(block.liveVarsBefore))
- {
- block.liveVarsBefore = liveVarsAfter;
- some_change = true;
- }
- }
- }
- }
- }
-
- public void Generate()
- {
-
- var oldDagOption = CommandLineOptions.Clo.vcVariety;
- CommandLineOptions.Clo.vcVariety = CommandLineOptions.VCVariety.Dag;
-
- // MarkAllFunctionImplementationsInline(); // This is for SMACK, which goes crazy with functions
-
- // Run live variable analysis (TODO: should this be here?)
-#if false
- if (CommandLineOptions.Clo.LiveVariableAnalysis == 2)
- {
- Microsoft.Boogie.InterProcGenKill.ComputeLiveVars(impl, program);
- }
-#endif
-
- #region In Boogie mode, annotate the program
- if (mode == Mode.Boogie)
- {
-
- // find the name of the main procedure
- main_proc_name = null; // default in case no entry point defined
- foreach (var impl in program.Implementations)
- {
- if (QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
- main_proc_name = impl.Proc.Name;
- }
- if (main_proc_name == null)
- {
- foreach (var impl in program.Implementations)
- {
- if (impl.Proc.Name == "main" || impl.Proc.Name.EndsWith(".main"))
- main_proc_name = impl.Proc.Name;
- }
- }
- if (main_proc_name == null)
- main_proc_name = "main";
-
- if (style == AnnotationStyle.Flat)
- {
- InlineAll();
- Microsoft.Boogie.BlockCoalescer.CoalesceBlocks(program);
- foreach (var impl in program.Implementations)
- {
- if (main_proc_name == impl.Proc.Name)
- {
- Microsoft.Boogie.LiveVariableAnalysis.ClearLiveVariables(impl);
- CyclicLiveVariableAnalysis.ComputeLiveVariables(impl);
- AnnotateLoops(impl, boogieContext);
- }
- }
- }
- else
- {
-
- if (style == AnnotationStyle.Procedure || style == AnnotationStyle.Call)
- {
- foreach (var impl in program.Implementations)
- {
- if (!QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
- AnnotateProcRequires(impl.Proc, impl, boogieContext);
- AnnotateProcEnsures(impl.Proc, impl, boogieContext);
- }
- if (style == AnnotationStyle.Call)
- {
-
- }
- }
-
- // must do this after annotating procedures, else calls
- // will be prematurely desugared
-
- foreach (var impl in program.Implementations)
- {
- Microsoft.Boogie.LiveVariableAnalysis.ClearLiveVariables(impl);
- CyclicLiveVariableAnalysis.ComputeLiveVariables(impl);
- }
-
-
- if (style == AnnotationStyle.Flat || style == AnnotationStyle.Call)
- {
- foreach (var impl in program.Implementations)
- {
- AnnotateLoops(impl, boogieContext);
- }
- }
- if (style == AnnotationStyle.Call)
- {
- Dictionary<string, bool> impls = new Dictionary<string, bool>();
- foreach (var impl in program.Implementations)
- {
- impls.Add(impl.Proc.Name, true);
- }
- foreach (var impl in program.Implementations)
- {
- AnnotateCallSites(impl, boogieContext, impls);
- }
- }
- if (style == AnnotationStyle.Flat)
- InlineAll();
- }
- }
- #endregion
-
- /* Generate the VC's */
- GenerateVCsForStratifiedInlining();
-
- /* Generate the background axioms */
- Term background = ctx.MkTrue(); // TODO boogieContext.VCExprToTerm(boogieContext.Axioms, linOptions);
- rpfp.AssertAxiom(background);
-
- int save_option = CommandLineOptions.Clo.StratifiedInlining; // need this to get funcall labels
- CommandLineOptions.Clo.StratifiedInlining = 1;
-
- /* Create the nodes, indexing procedures by their relational symbols. */
- foreach (StratifiedInliningInfo info in implName2StratifiedInliningInfo.Values)
- GenerateVCForStratifiedInlining(program, info, checker);
-
- CommandLineOptions.Clo.StratifiedInlining = save_option;
-
- if (mode == Mode.Boogie)
- {
- // var ops = new Util.ContextOps(ctx);
- var vcs = DualityVCs;
- DualityVCs = new List<Term>();
- foreach (var vc in vcs)
- {
- // var foo = ops.simplify_lhs(vc.GetAppArgs()[0]);
- var foo = vc.GetAppArgs()[0];
- if (!foo.IsFalse())
- DualityVCs.Add(ctx.MkImplies(foo, vc.GetAppArgs()[1]));
- }
-
- rpfp.FromClauses(DualityVCs.ToArray());
- // TODO rpfp.HornClauses = style == AnnotationStyle.Flat;
- }
- else
- {
- /* Generate the edges. */
- foreach (StratifiedInliningInfo info in implName2StratifiedInliningInfo.Values)
- GetTransformer(info);
- }
-
- // save some information for debugging purposes
- // TODO rpfp.ls.SetAnnotationInfo(annotationInfo);
-
- CommandLineOptions.Clo.vcVariety = oldDagOption;
- }
-
-
- private class ErrorHandler : ProverInterface.ErrorHandler
- {
- //TODO: anything we need to handle?
- }
-
- Dictionary<int, Dictionary<string, string>> varSubst = null;
-
- /** Check the RPFP, and return a counterexample if there is one. */
-
- public RPFP.LBool Check(ref RPFP.Node cexroot)
- {
- var start = DateTime.Now;
-
- ErrorHandler handler = new ErrorHandler();
- RPFP.Node cex;
- varSubst = new Dictionary<int,Dictionary<string,string>>();
-
-#if false
- int origRecursionBound = CommandLineOptions.Clo.RecursionBound;
- if (CommandLineOptions.Clo.RecursionBound > 0 && extraRecBound != null)
- {
- int maxExtra = 0;
- foreach (string s in extraRecBound.Keys)
- {
- int extra = extraRecBound[s];
- if (extra > maxExtra) maxExtra = extra;
- }
- CommandLineOptions.Clo.RecursionBound += maxExtra;
- }
-#endif
-
- ProverInterface.Outcome outcome =
- checker.TheoremProver.CheckRPFP("name", rpfp, handler, out cex, varSubst, extraRecBound);
- cexroot = cex;
-
-#if false
- CommandLineOptions.Clo.RecursionBound = origRecursionBound;
-#endif
-
- Console.WriteLine("solve: {0}s", (DateTime.Now - start).TotalSeconds);
-
- switch(outcome)
- {
- case ProverInterface.Outcome.Valid:
- return RPFP.LBool.False;
- case ProverInterface.Outcome.Invalid:
- return RPFP.LBool.True;
- default:
- return RPFP.LBool.Undef;
- }
- }
-
- private bool generated = false;
-
- static private Object thisLock = new Object();
-
- public override VC.VCGen.Outcome VerifyImplementation(Implementation impl, VerifierCallback collector)
- {
-
- lock (thisLock)
- {
- Procedure proc = impl.Proc;
-
- // we verify all the impls at once, so we need to execute only once
- // TODO: make sure needToCheck is true only once
- bool needToCheck = false;
- if (mode == Mode.OldCorral)
- needToCheck = proc.FindExprAttribute("inline") == null && !(proc is LoopProcedure);
- else if (mode == Mode.Corral || mode == Mode.Boogie)
- needToCheck = QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint") && !(proc is LoopProcedure);
- else
- needToCheck = impl.Name == main_proc_name;
-
- if (needToCheck)
- {
-
- var start = DateTime.Now;
-
- if (!generated)
- {
- Generate();
- Console.WriteLine("generate: {0}s", (DateTime.Now - start).TotalSeconds);
- generated = true;
- }
-
-
- Console.WriteLine("Verifying {0}...", impl.Name);
-
- RPFP.Node cexroot = null;
- // start = DateTime.Now;
- var checkres = Check(ref cexroot);
- Console.WriteLine("check: {0}s", (DateTime.Now - start).TotalSeconds);
- switch (checkres)
- {
- case RPFP.LBool.True:
- Console.WriteLine("Counterexample found.\n");
- // start = DateTime.Now;
- Counterexample cex = CreateBoogieCounterExample(cexroot.owner, cexroot, impl);
- // cexroot.owner.DisposeDualModel();
- // cex.Print(0); // just for testing
- collector.OnCounterexample(cex, "assertion failure");
- Console.WriteLine("cex: {0}s", (DateTime.Now - start).TotalSeconds);
- ConjecturesToSpecs();
- return VC.ConditionGeneration.Outcome.Errors;
- case RPFP.LBool.False:
- Console.WriteLine("Procedure is correct.");
- FixedPointToSpecs();
- ConjecturesToSpecs();
- return Outcome.Correct;
- case RPFP.LBool.Undef:
- Console.WriteLine("Inconclusive result.");
- ConjecturesToSpecs();
- return Outcome.ReachedBound;
- }
-
- }
-
- return Outcome.Inconclusive;
- }
- }
-
- public void FindLabelsRec(HashSet<Term> memo, Term t, Dictionary<string, Term> res)
- {
- if (memo.Contains(t))
- return;
- if (t.IsLabel())
- {
- string l = t.LabelName();
- if (!res.ContainsKey(l))
- res.Add(l, t.GetAppArgs()[0]);
- }
- if (t.GetKind() == TermKind.App)
- {
- var args = t.GetAppArgs();
- foreach (var a in args)
- FindLabelsRec(memo, a, res);
- } // TODO: handle quantifiers
-
- memo.Add(t);
- }
-
- public void FindLabels()
- {
- labels = new Dictionary<string, Term>();
- foreach(var e in rpfp.edges){
- int id = e.number;
- HashSet<Term> memo = new HashSet<Term>(ReferenceComparer<Term>.Instance);
- FindLabelsRec(memo, e.F.Formula, labels);
- }
- }
-
- public string CodeLabel(Absy code, StratifiedInliningInfo info, string prefix)
- {
- if (info.label2absyInv == null)
- {
- info.label2absyInv = new Dictionary<Absy, string>();
- foreach (int foo in info.label2absy.Keys)
- {
- Absy bar = info.label2absy[foo] as Absy;
- string lbl = foo.ToString();
- info.label2absyInv.Add(bar, lbl);
- }
- }
- if (info.label2absyInv.ContainsKey(code))
- {
- string label = info.label2absyInv[code];
- return prefix+label;
- }
- return null;
- }
-
- public Term CodeLabeledExpr(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix)
- {
- string label = CodeLabel(code, info, prefix);
-
- if (label != null)
- {
- var res = labels[label];
- return res;
- }
- else return null;
- }
-
- public class LabelNotFound : Exception { };
-
- public bool CodeLabelTrue(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix)
- {
- string label = CodeLabel(code, info, prefix);
-
- if (label == null)
- throw new LabelNotFound();
- return root.Outgoing.labels.Contains(label);
- }
-
- public bool CodeLabelFalse(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix)
- {
- return CodeLabelTrue(rpfp, root, code, info, prefix);
- }
-
-
- private class StateId
- {
- public RPFP.Edge edge;
- public int capturePoint;
- public StratifiedInliningInfo info;
- public StateId(RPFP.Edge e, int c, StratifiedInliningInfo i)
- {
- edge = e;
- capturePoint = c;
- info = i;
- }
- }
-
-
- public Counterexample CreateBoogieCounterExample(RPFP rpfp, RPFP.Node root, Implementation mainImpl)
- {
- FindLabels();
- var orderedStateIds = new List<StateId>();
- Counterexample newCounterexample =
- GenerateTrace(rpfp, root, orderedStateIds, mainImpl,true);
- if (CommandLineOptions.Clo.ModelViewFile != null)
- {
- Model m = root.owner.GetBackgroundModel();
- GetModelWithStates(m, root, implName2StratifiedInliningInfo[mainImpl.Name],
- orderedStateIds, varSubst);
- newCounterexample.Model = m;
- newCounterexample.ModelHasStatesAlready = true;
- }
- return newCounterexample;
- }
-
-
-
- private Counterexample GenerateTrace(RPFP rpfp, RPFP.Node root,
- List<StateId> orderedStateIds, Implementation procImpl, bool toplevel)
- {
- Contract.Requires(procImpl != null);
-
- Contract.Assert(!rpfp.Empty(root));
-
-
- var info = implName2StratifiedInliningInfo[procImpl.Name];
- Block entryBlock = cce.NonNull(procImpl.Blocks[0]);
- Contract.Assert(entryBlock != null);
-
- List<Block> trace = new List<Block>();
- trace.Add(entryBlock);
-
- var calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
-
- Counterexample newCounterexample =
- GenerateTraceRec(rpfp, root, orderedStateIds, entryBlock, trace, calleeCounterexamples, info, toplevel);
-
- return newCounterexample;
- }
-
- // TODO: this is a bit cheesy. Rather than finding the argument position
- // of a relational term in a transformer by linear search, better to index this
- // somewhere, but where?
- private int TransformerArgPosition(RPFP rpfp, RPFP.Node root, Term expr)
- {
- FuncDecl rel = expr.GetAppDecl();
- string relname = rel.GetDeclName();
- var rps = root.Outgoing.F.RelParams;
- for (int i = 0; i < rps.Length; i++)
- {
- string thisname = rps[i].GetDeclName();
- if (thisname == relname)
- return i;
- }
- return -1;
- }
-
- private bool EvalToFalse(RPFP rpfp, RPFP.Node root, Term expr,StratifiedInliningInfo info){
- Term res = rpfp.Eval(root.Outgoing,expr);
- return res.Equals(ctx.MkTrue());
- }
-
- private Counterexample GenerateTraceRec(
- RPFP rpfp, RPFP.Node root,
- List<StateId> orderedStateIds,
- Block/*!*/ b, List<Block>/*!*/ trace,
- Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples,
- StratifiedInliningInfo info,
- bool toplevel)
- {
- Contract.Requires(b != null);
- Contract.Requires(trace != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples));
-
- Stack<RPFP.Node> continuation_stack = new Stack<RPFP.Node>();
-
- // If our block is not present, try diving into precondition
- // and push a continuation.
- // TODO: is the precondition always the first child?
- while (!CodeLabelFalse(rpfp, root, b, info, "+"))
- {
- if (root.Outgoing != null && root.Outgoing.Children.Length > 0)
- {
- continuation_stack.Push(root);
- root = root.Outgoing.Children[0];
- }
- else
- {
- // can't find our block
- Contract.Assert(false);
- return null;
- }
- }
-
- // After translation, all potential errors come from asserts.
- while (true)
- {
-
-
- List<Cmd> cmds = b.Cmds;
- TransferCmd transferCmd = cce.NonNull(b.TransferCmd);
- for (int i = 0; i < cmds.Count; i++)
- {
- Cmd cmd = cce.NonNull(cmds[i]);
-
- // Skip if 'cmd' not contained in the trace or not an assert
- if (cmd is AssertCmd)
- {
- bool is_failed_assertion = false;
- if (NoLabels)
- is_failed_assertion = true; // we assume only assertions on
- else
- is_failed_assertion = CodeLabelTrue(rpfp, root, cmd, info, "@");
-
- if (is_failed_assertion)
- {
- if (continuation_stack.Count == 0)
- {
- Counterexample newCounterexample =
- AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, new Microsoft.Boogie.Model(), info.mvInfo,
- boogieContext);
- newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
- return newCounterexample;
- }
- root = continuation_stack.Pop();
- }
- continue;
- }
-
- // Counterexample generation for inlined procedures
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- if (assumeCmd == null)
- continue;
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- if (naryExpr == null)
- continue;
- string calleeName = naryExpr.Fun.FunctionName;
- Contract.Assert(calleeName != null);
-
- // what is this crap???
- BinaryOperator binOp = naryExpr.Fun as BinaryOperator;
- if (binOp != null && binOp.Op == BinaryOperator.Opcode.And)
- {
- Expr expr = naryExpr.Args[0];
- NAryExpr mvStateExpr = expr as NAryExpr;
- if (mvStateExpr != null && mvStateExpr.Fun.FunctionName == VC.ModelViewInfo.MVState_FunctionDef.Name)
- {
- LiteralExpr x = mvStateExpr.Args[1] as LiteralExpr;
- // Debug.Assert(x != null);
- int foo = x.asBigNum.ToInt;
- orderedStateIds.Add(new StateId(root.Outgoing,foo,info));
- }
- }
-
- if (calleeName.EndsWith("_summary"))
- calleeName = calleeName.Substring(0, calleeName.Length - 8);
-
- if (!implName2StratifiedInliningInfo.ContainsKey(calleeName) && !calleeName.EndsWith("_summary"))
- continue;
-
- {
- Term code = CodeLabeledExpr(rpfp, root, cmd, info, "+si_fcall_");
- int pos = TransformerArgPosition(rpfp, root, code);
- if (pos >= 0)
- {
- RPFP.Node callee = root.Outgoing.Children[pos];
- orderedStateIds.Add(new StateId(callee.Outgoing, CALL,info));
- calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] =
- new CalleeCounterexampleInfo(
- cce.NonNull(GenerateTrace(rpfp, callee, orderedStateIds,
- implName2StratifiedInliningInfo[calleeName].impl, false)),
- new List<object>());
- orderedStateIds.Add(new StateId(root.Outgoing, RETURN,info));
- }
- }
- }
-
- GotoCmd gotoCmd = transferCmd as GotoCmd;
- List<Block> cuts = null;
- if (edgesCut.ContainsKey(b))
- cuts = edgesCut[b];
- b = null;
-
- if (gotoCmd != null)
- {
-
- foreach (Block bb in cce.NonNull(gotoCmd.labelTargets))
- {
- Contract.Assert(bb != null);
- if (CodeLabelFalse(rpfp, root, bb, info, "+"))
- {
- trace.Add(bb);
- b = bb;
- break;
- }
- }
- if (b != null) continue;
- }
- // HACK: we have to try edges that were cut in generating the VC
-
- if (cuts != null)
- foreach (var bb in cuts)
- {
- if (CodeLabelFalse(rpfp, root, bb, info, "+"))
- {
- trace.Add(bb);
- b = bb;
- break;
- }
- }
- if (b != null) continue;
-
- return null;
- }
-
-
- }
-
- public override Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
- {
- // Construct the set of inlined procs in the original program
- var inlinedProcs = new HashSet<string>();
- foreach (var decl in program.TopLevelDeclarations)
- {
- // Implementations
- if (decl is Implementation)
- {
- var impl = decl as Implementation;
- if (!(impl.Proc is LoopProcedure))
- {
- inlinedProcs.Add(impl.Name);
- }
- }
-
- // And recording procedures
- if (decl is Procedure)
- {
- var proc = decl as Procedure;
- if (proc.Name.StartsWith(recordProcName))
- {
- // Debug.Assert(!(decl is LoopProcedure));
- inlinedProcs.Add(proc.Name);
- }
- }
- }
- return extractLoopTraceRec(
- new CalleeCounterexampleInfo(cex, new List<object>()),
- mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample;
- }
-
- protected override bool elIsLoop(string procname)
- {
- StratifiedInliningInfo info = null;
- if (implName2StratifiedInliningInfo.ContainsKey(procname))
- {
- info = implName2StratifiedInliningInfo[procname];
- }
-
- if (info == null) return false;
-
- var lp = info.impl.Proc as LoopProcedure;
-
- if (lp == null) return false;
- return true;
- }
-
- private void NumberCexEdges(RPFP.Node node, Dictionary<int,RPFP.Edge> map)
- {
- if (node.Outgoing == null)
- return; // shouldn't happen
- RPFP.Edge edge = node.Outgoing;
- map[edge.number] = edge;
- foreach (var c in edge.Children)
- NumberCexEdges(c, map);
- }
-
- private void GetModelWithStates(Model m, RPFP.Node cex, StratifiedInliningInfo mainInfo,
- List<StateId> orderedStateIds,
- Dictionary<int,Dictionary<string,string>> varSubst)
- {
- if (m == null) return;
- var mvInfo = mainInfo.mvInfo;
-
-
- foreach (Variable v in mvInfo.AllVariables)
- {
- m.InitialState.AddBinding(v.Name, GetModelValue(m, v, varSubst[cex.Outgoing.number]));
- }
-
- Dictionary<int, RPFP.Edge> edgeNumbering = new Dictionary<int,RPFP.Edge>();
- NumberCexEdges(cex, edgeNumbering);
-
- int lastCandidate = 0;
- int lastCapturePoint = CALL;
- for (int i = 0; i < orderedStateIds.Count; ++i)
- {
- var s = orderedStateIds[i];
- RPFP.Edge edge = s.edge;
- int candidate = edge.number;
- int capturePoint = s.capturePoint;
- Dictionary<string, string> subst = varSubst[candidate];
-
- string implName = edge.Parent.Name.GetDeclName();
- var info = s.info.mvInfo;
-
- if (capturePoint == CALL || capturePoint == RETURN)
- {
- lastCandidate = candidate;
- lastCapturePoint = capturePoint;
- continue;
- }
-
- Contract.Assume(0 <= capturePoint && capturePoint < info.CapturePoints.Count);
- VC.ModelViewInfo.Mapping map = info.CapturePoints[capturePoint];
- var prevInc = (lastCapturePoint != CALL && lastCapturePoint != RETURN && candidate == lastCandidate)
- ? info.CapturePoints[lastCapturePoint].IncarnationMap : new Dictionary<Variable, Expr>();
- var cs = m.MkState(map.Description);
-
- foreach (Variable v in info.AllVariables)
- {
- var e = (Expr)map.IncarnationMap[v];
-
- if (e == null)
- {
- if (lastCapturePoint == CALL || lastCapturePoint == RETURN)
- {
- cs.AddBinding(v.Name, GetModelValue(m, v, subst));
- }
- continue;
- }
-
- if (lastCapturePoint != CALL && lastCapturePoint != RETURN && prevInc[v] == e) continue; // skip unchanged variables
-
- Model.Element elt;
- if (e is IdentifierExpr)
- {
- IdentifierExpr ide = (IdentifierExpr)e;
- elt = GetModelValue(m, ide.Decl, subst);
- }
- else if (e is LiteralExpr)
- {
- LiteralExpr lit = (LiteralExpr)e;
- elt = m.MkElement(lit.Val.ToString());
- }
- else
- {
- Contract.Assume(false);
- elt = m.MkFunc(e.ToString(), 0).GetConstant();
- }
- cs.AddBinding(v.Name, elt);
- }
-
- lastCandidate = candidate;
- lastCapturePoint = capturePoint;
- }
-
- return;
- }
-
-
- public readonly static int CALL = -1;
- public readonly static int RETURN = -2;
-
- private Model.Element GetModelValue(Model m, Variable v, Dictionary<string,string> subst)
- {
- // first, get the unique name
- string uniqueName;
-
- VCExprVar vvar = boogieContext.BoogieExprTranslator.TryLookupVariable(v);
-
- uniqueName = v.Name;
-
- if(subst.ContainsKey(uniqueName))
- return m.MkElement(subst[uniqueName]);
- return m.MkFunc("@undefined", 0).GetConstant();
- }
-
- class InternalError : Exception {
- }
-
-
- private BinaryOperator.Opcode VCOpToOp (VCExprOp op)
- {
- if (op == VCExpressionGenerator.AddIOp)
- return BinaryOperator.Opcode.Add;
- if (op == VCExpressionGenerator.SubIOp)
- return BinaryOperator.Opcode.Sub;
- if (op == VCExpressionGenerator.MulIOp)
- return BinaryOperator.Opcode.Mul;
- if (op == VCExpressionGenerator.DivIOp)
- return BinaryOperator.Opcode.Div;
- if (op == VCExpressionGenerator.EqOp)
- return BinaryOperator.Opcode.Eq;
- if (op == VCExpressionGenerator.LeOp)
- return BinaryOperator.Opcode.Le;
- if (op == VCExpressionGenerator.LtOp)
- return BinaryOperator.Opcode.Lt;
- if (op == VCExpressionGenerator.GeOp)
- return BinaryOperator.Opcode.Ge;
- if (op == VCExpressionGenerator.GtOp)
- return BinaryOperator.Opcode.Gt;
- if (op == VCExpressionGenerator.AndOp)
- return BinaryOperator.Opcode.And;
- if (op == VCExpressionGenerator.OrOp)
- return BinaryOperator.Opcode.Or;
- throw new InternalError();
- }
-
- private Expr MakeBinary (BinaryOperator.Opcode op, List<Expr> args)
- {
- if(args.Count == 0){
- // with zero args we need the identity of the op
- switch(op){
- case BinaryOperator.Opcode.And:
- return Expr.True;
- case BinaryOperator.Opcode.Or:
- return Expr.False;
- case BinaryOperator.Opcode.Add:
- return new LiteralExpr(Token.NoToken,Microsoft.Basetypes.BigNum.ZERO);
- default:
- throw new InternalError();
- }
- }
- var temp = args[0];
- for(int i = 1; i < args.Count; i++)
- temp = Expr.Binary(Token.NoToken,op,temp,args[i]);
- return temp;
- }
-
- private Variable MakeVar(VCExprVar v){
- var foo = new TypedIdent(Token.NoToken,v.Name.ToString(),v.Type);
- return new BoundVariable(Token.NoToken,foo);
- }
-
- private Expr VCExprToExpr (VCExpr e, Dictionary<VCExpr,Expr> bound)
- {
- if (e is VCExprVar) {
- if(bound.ContainsKey(e))
- return bound[e];
- return Expr.Ident(MakeVar(e as VCExprVar)); // TODO: this isn't right
- }
- if (e is VCExprIntLit) {
- var n = e as VCExprIntLit;
- return new LiteralExpr(Token.NoToken,n.Val);
- }
- if (e is VCExprNAry) {
- var f = e as VCExprNAry;
- var args = new List<Expr>();
- for(int i = 0; i < f.Arity; i++){
- args.Add (VCExprToExpr (f[i],bound));
- }
-
- if(f.Op == VCExpressionGenerator.NotOp)
- return Expr.Unary(Token.NoToken, UnaryOperator.Opcode.Not, args[0]);
-
- if(f.Op == VCExpressionGenerator.IfThenElseOp)
- return new NAryExpr(Token.NoToken,new IfThenElse(Token.NoToken),args);
-
- if(f.Op is VCExprSelectOp){
- var idx = new List<Expr>();
- idx.Add(args[1]);
- return Expr.Select(args[0],idx);
- }
-
- if(f.Op is VCExprStoreOp){
- var idx = new List<Expr>();
- idx.Add(args[1]);
- return Expr.Store(args[0],idx,args[2]);
- }
-
- if (f.Op is VCExprBoogieFunctionOp)
- {
- return new NAryExpr(Token.NoToken,
- new FunctionCall((f.Op as VCExprBoogieFunctionOp).Func), args);
- }
-
- var op = VCOpToOp (f.Op);
- return MakeBinary(op,args);
- }
-
- if(e is VCExprQuantifier) {
- var f = e as VCExprQuantifier;
- var vs = new List<Variable>();
- var new_bound = new Dictionary<VCExpr,Expr>(bound);
- foreach(var v in f.BoundVars){
- var ve = MakeVar(v);
- vs.Add(ve);
- new_bound.Add (v,Expr.Ident (ve));
- }
- var bd = VCExprToExpr(f.Body,new_bound);
- if(f.Quan == Quantifier.EX)
- return new ExistsExpr(Token.NoToken,vs,bd);
- else
- return new ForallExpr(Token.NoToken,vs,bd);
- }
- if (e == VCExpressionGenerator.True) {
- return Expr.True;
- }
- if (e == VCExpressionGenerator.False) {
- return Expr.False;
- }
- if (e is VCExprLet) {
-
- }
-
- throw new InternalError();
- }
-
-
- }
-
-
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Diagnostics.Contracts;
+using Microsoft.Boogie;
+using Microsoft.Boogie.VCExprAST;
+
+
+using Term = Microsoft.Boogie.VCExprAST.VCExpr;
+using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp;
+using Sort = Microsoft.Boogie.Type;
+using Microsoft.Boogie.ExprExtensions;
+
+
+namespace Microsoft.Boogie
+{
+ public class FixedpointVC : VC.VCGen
+ {
+
+ public class AnnotationInfo
+ {
+ public enum AnnotationType { LoopInvariant, ProcedureSummary };
+ public string filename;
+ public int lineno;
+ public string[] argnames;
+ public AnnotationType type;
+ };
+
+ static bool NoLabels = false;
+
+ // options
+ bool largeblock = false;
+
+ public bool SetOption(string option, string value)
+ {
+ if (option == "LargeBlock")
+ {
+ largeblock = true;
+ return true;
+ }
+ return false;
+ }
+
+ Context ctx;
+ RPFP rpfp;
+ // Program program;
+ Microsoft.Boogie.ProverContext boogieContext;
+ Microsoft.Boogie.VCExpressionGenerator gen;
+ public readonly static string recordProcName = "boogie_si_record"; // TODO: this really needed?
+ private Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo
+ = new Dictionary<string, StratifiedInliningInfo>();
+ Checker checker;
+ // Microsoft.Boogie.Z3.Z3InstanceOptions options = new Microsoft.Boogie.Z3.Z3InstanceOptions(); // TODO: what?
+ LineariserOptions linOptions;
+ Dictionary<FuncDecl, StratifiedInliningInfo> relationToProc = new Dictionary<FuncDecl, StratifiedInliningInfo>();
+ Dictionary<string, Term> labels = new Dictionary<string, Term> ();
+ List<Term> DualityVCs = new List<Term>();
+ Dictionary<string, bool> summaries = new Dictionary<string, bool>();
+ Dictionary<Block, List<Block>> edgesCut = new Dictionary<Block, List<Block>>();
+ string main_proc_name = "main";
+ Dictionary<string, int> extraRecBound = null;
+
+
+ public enum Mode { Corral, OldCorral, Boogie};
+ public enum AnnotationStyle { Flat, Procedure, Call };
+
+ Mode mode;
+ AnnotationStyle style;
+
+ private static Checker old_checker = null;
+
+ public static void CleanUp()
+ {
+ if (old_checker != null)
+ {
+ old_checker.Close();
+ old_checker = null;
+ }
+ }
+
+ public FixedpointVC( Program _program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers, Dictionary<string,int> _extraRecBound = null)
+ : base(_program, logFilePath, appendLogFile, checkers)
+ {
+ switch (CommandLineOptions.Clo.FixedPointMode)
+ {
+ case CommandLineOptions.FixedPointInferenceMode.Corral:
+ mode = Mode.Corral;
+ style = AnnotationStyle.Procedure;
+ break;
+ case CommandLineOptions.FixedPointInferenceMode.OldCorral:
+ mode = Mode.OldCorral;
+ style = AnnotationStyle.Procedure;
+ break;
+ case CommandLineOptions.FixedPointInferenceMode.Flat:
+ mode = Mode.Boogie;
+ style = AnnotationStyle.Flat;
+ break;
+ case CommandLineOptions.FixedPointInferenceMode.Procedure:
+ mode = Mode.Boogie;
+ style = AnnotationStyle.Procedure;
+ break;
+ case CommandLineOptions.FixedPointInferenceMode.Call:
+ mode = Mode.Boogie;
+ style = AnnotationStyle.Call;
+ break;
+ }
+ ctx = new Context(); // TODO is this right?
+ rpfp = new RPFP(RPFP.CreateLogicSolver(ctx));
+ program = _program;
+ gen = ctx;
+ if(old_checker == null)
+ checker = new Checker(this, program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime, null);
+ else {
+ checker = old_checker;
+ checker.RetargetWithoutReset(program,checker.TheoremProver.Context);
+ }
+ old_checker = checker;
+ boogieContext = checker.TheoremProver.Context;
+ linOptions = null; // new Microsoft.Boogie.Z3.Z3LineariserOptions(false, options, new List<VCExprVar>());
+ extraRecBound = _extraRecBound;
+ }
+
+ Dictionary<string, AnnotationInfo> annotationInfo = new Dictionary<string, AnnotationInfo>();
+
+ public void AnnotateLoops(Implementation impl, ProverContext ctxt)
+ {
+ Contract.Requires(impl != null);
+
+ CurrentLocalVariables = impl.LocVars;
+ variable2SequenceNumber = new Dictionary<Variable, int>();
+ incarnationOriginMap = new Dictionary<Incarnation, Absy>();
+
+ ResetPredecessors(impl.Blocks);
+
+ #region Create the graph by adding the source node and each edge
+ GraphUtil.Graph<Block> g = Program.GraphFromImpl(impl);
+ #endregion
+
+ //Graph<Block> g = program.ProcessLoops(impl);
+
+ g.ComputeLoops(); // this is the call that does all of the processing
+ if (!g.Reducible)
+ {
+ throw new System.Exception("Irreducible flow graphs are unsupported.");
+ }
+
+ #region add a symbolic annoation to every loop head
+ foreach (Block header in cce.NonNull(g.Headers))
+ AnnotateBlock(impl, ctxt, header);
+ #endregion
+ }
+
+ private void AnnotateCallSites(Implementation impl, ProverContext ctxt, Dictionary<string, bool> impls){
+ foreach (var b in impl.Blocks)
+ {
+ foreach (var cmd in b.Cmds)
+ {
+ if (cmd is CallCmd)
+ {
+ string name = (cmd as CallCmd).callee;
+ if(impls.ContainsKey(name))
+ goto annotate;
+ }
+ }
+ continue;
+ annotate:
+ AnnotateBlock(impl, ctxt, b);
+ }
+ }
+
+
+ private void AnnotateBlock(Implementation impl, ProverContext ctxt, Block header)
+ {
+ Contract.Assert(header != null);
+
+ string name = impl.Name + "_" + header.Label + "_invar";
+ if (annotationInfo.ContainsKey(name))
+ return;
+
+ // collect the variables needed in the invariant
+ List<Expr> exprs = new List<Expr>();
+ List<Variable> vars = new List<Variable>();
+ List<string> names = new List<string>();
+
+ if (style == AnnotationStyle.Flat)
+ {
+ // in flat mode, all live globals should be in live set
+#if false
+ foreach (Variable v in program.GlobalVariables)
+ {
+ vars.Add(v);
+ names.Add(v.ToString());
+ exprs.Add(new IdentifierExpr(Token.NoToken, v));
+ }
+#endif
+ foreach (Variable v in /* impl.LocVars */ header.liveVarsBefore)
+ {
+ if (!(v is BoundVariable))
+ {
+ vars.Add(v);
+ names.Add(v.ToString());
+ exprs.Add(new IdentifierExpr(Token.NoToken, v));
+ }
+ }
+ }
+ else
+ {
+ foreach (Variable v in program.GlobalVariables)
+ {
+ vars.Add(v);
+ names.Add("@old_" + v.ToString());
+ exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
+ }
+ foreach (IdentifierExpr ie in impl.Proc.Modifies)
+ {
+ if (ie.Decl == null)
+ continue;
+ vars.Add(ie.Decl);
+ names.Add(ie.Decl.ToString());
+ exprs.Add(ie);
+ }
+ foreach (Variable v in impl.Proc.InParams)
+ {
+ Contract.Assert(v != null);
+ vars.Add(v);
+ names.Add("@old_" + v.ToString());
+ exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
+ }
+ foreach (Variable v in impl.LocVars)
+ {
+ vars.Add(v);
+ names.Add(v.ToString());
+ exprs.Add(new IdentifierExpr(Token.NoToken, v));
+ }
+ }
+
+ TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
+ Contract.Assert(ti != null);
+ Formal returnVar = new Formal(Token.NoToken, ti, false);
+ Contract.Assert(returnVar != null);
+ var function = new Function(Token.NoToken, name, vars, returnVar);
+ ctxt.DeclareFunction(function, "");
+
+ Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
+ var invarAssertion = new AssertCmd(Token.NoToken, invarExpr);
+ List<Cmd> newCmds = new List<Cmd>();
+ newCmds.Add(invarAssertion);
+
+ // make a record in annotationInfo;
+ var info = new AnnotationInfo();
+ info.filename = header.tok.filename;
+ info.lineno = header.Line;
+ info.argnames = names.ToArray();
+ info.type = AnnotationInfo.AnnotationType.LoopInvariant;
+ annotationInfo.Add(name, info);
+ // get file and line info from havoc, if there is...
+ if (header.Cmds.Count > 0)
+ {
+ PredicateCmd bif = header.Cmds[0] as PredicateCmd;
+ if (bif != null)
+ {
+ string foo = QKeyValue.FindStringAttribute(bif.Attributes, "sourcefile");
+ if (foo != null)
+ info.filename = foo;
+ int bar = QKeyValue.FindIntAttribute(bif.Attributes, "sourceline", -1);
+ if (bar != -1)
+ info.lineno = bar;
+ }
+ }
+ var thing = header;
+ foreach (Cmd c in header.Cmds)
+ {
+ newCmds.Add(c);
+ }
+ header.Cmds = newCmds;
+ }
+
+#if true
+ public void AnnotateProcRequires(Procedure proc, Implementation impl, ProverContext ctxt)
+ {
+ Contract.Requires(impl != null);
+
+ CurrentLocalVariables = impl.LocVars;
+
+ // collect the variables needed in the invariant
+ List<Expr> exprs = new List<Expr>();
+ List<Variable> vars = new List<Variable>();
+ List<string> names = new List<string>();
+
+ foreach (Variable v in program.GlobalVariables)
+ {
+ vars.Add(v);
+ exprs.Add(new IdentifierExpr(Token.NoToken, v));
+ names.Add(v.Name);
+ }
+ foreach (Variable v in proc.InParams)
+ {
+ Contract.Assert(v != null);
+ vars.Add(v);
+ exprs.Add(new IdentifierExpr(Token.NoToken, v));
+ names.Add(v.Name);
+ }
+ string name = impl.Name + "_precond";
+ TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
+ Contract.Assert(ti != null);
+ Formal returnVar = new Formal(Token.NoToken, ti, false);
+ Contract.Assert(returnVar != null);
+ var function = new Function(Token.NoToken, name, vars, returnVar);
+ ctxt.DeclareFunction(function, "");
+
+ Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
+
+ proc.Requires.Add(new Requires(Token.NoToken, false, invarExpr, "", null));
+
+ var info = new AnnotationInfo();
+ info.filename = proc.tok.filename;
+ info.lineno = proc.Line;
+ info.argnames = names.ToArray();
+ info.type = AnnotationInfo.AnnotationType.LoopInvariant;
+ annotationInfo.Add(name, info);
+ }
+
+ public void AnnotateProcEnsures(Procedure proc, Implementation impl, ProverContext ctxt)
+ {
+ Contract.Requires(impl != null);
+
+ CurrentLocalVariables = impl.LocVars;
+
+ // collect the variables needed in the invariant
+ List<Expr> exprs = new List<Expr>();
+ List<Variable> vars = new List<Variable>();
+ List<string> names = new List<string>();
+
+ foreach (Variable v in program.GlobalVariables)
+ {
+ vars.Add(v);
+ exprs.Add(new OldExpr(Token.NoToken,new IdentifierExpr(Token.NoToken, v)));
+ names.Add(v.Name);
+ }
+ foreach (Variable v in proc.InParams)
+ {
+ Contract.Assert(v != null);
+ vars.Add(v);
+ exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
+ names.Add(v.Name);
+ }
+ foreach (IdentifierExpr ie in proc.Modifies)
+ {
+ if (ie.Decl == null)
+ continue;
+ vars.Add(ie.Decl);
+ exprs.Add(ie);
+ names.Add(ie.Decl.Name + "_out");
+ }
+ foreach (Variable v in proc.OutParams)
+ {
+ Contract.Assert(v != null);
+ vars.Add(v);
+ exprs.Add(new IdentifierExpr(Token.NoToken, v));
+ names.Add(v.Name);
+ }
+ string name = impl.Name + "_summary";
+ summaries.Add(name, true);
+ TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
+ Contract.Assert(ti != null);
+ Formal returnVar = new Formal(Token.NoToken, ti, false);
+ Contract.Assert(returnVar != null);
+ var function = new Function(Token.NoToken, name, vars, returnVar);
+ ctxt.DeclareFunction(function, "");
+
+ Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
+
+ proc.Ensures.Add(new Ensures(Token.NoToken, false, invarExpr, "", null));
+
+ var info = new AnnotationInfo();
+ info.filename = proc.tok.filename;
+ info.lineno = proc.Line;
+ info.argnames = names.ToArray();
+ info.type = AnnotationInfo.AnnotationType.ProcedureSummary;
+ annotationInfo.Add(name, info);
+ }
+#endif
+
+ void MarkAllFunctionImplementationsInline()
+ {
+ foreach (var func in program.Functions)
+ {
+ if (func.Body == null && func.DefinitionAxiom != null)
+ {
+ var def = func.DefinitionAxiom.Expr as QuantifierExpr;
+ var bod = def.Body as NAryExpr;
+ func.Body = bod.Args[1];
+ func.DefinitionAxiom = null;
+ }
+ if (func.Body != null)
+ if (func.FindExprAttribute("inline") == null)
+ func.AddAttribute("inline", Expr.Literal(100));
+ }
+ }
+
+ void InlineAll()
+ {
+ foreach (var impl in program.Implementations)
+ {
+ impl.OriginalBlocks = impl.Blocks;
+ impl.OriginalLocVars = impl.LocVars;
+ if(impl.Name != main_proc_name)
+ if(impl.FindExprAttribute("inline") == null)
+ impl.AddAttribute("inline", Expr.Literal(100));
+ }
+ foreach (var impl in program.Implementations)
+ {
+ if (!impl.SkipVerification)
+ {
+ Inliner.ProcessImplementation(program, impl);
+ }
+ }
+ foreach (var impl in program.Implementations)
+ {
+ impl.OriginalBlocks = null;
+ impl.OriginalLocVars = null;
+ }
+ }
+
+ public class LazyInliningInfo
+ {
+ [ContractInvariantMethod]
+ void ObjectInvariant()
+ {
+ Contract.Invariant(impl != null);
+ Contract.Invariant(function != null);
+ Contract.Invariant(controlFlowVariable != null);
+ Contract.Invariant(assertExpr != null);
+ Contract.Invariant(cce.NonNullElements(interfaceVars));
+ Contract.Invariant(incarnationOriginMap == null || cce.NonNullDictionaryAndValues(incarnationOriginMap));
+ }
+
+ public Implementation impl;
+ public int uniqueId;
+ public Function function;
+ public Variable controlFlowVariable;
+ public List<Variable> interfaceVars;
+ public List<List<Variable>> interfaceVarCopies;
+ public Expr assertExpr;
+ public VCExpr vcexpr;
+ public List<VCExprVar> privateVars;
+ public Dictionary<Incarnation, Absy> incarnationOriginMap;
+ public Hashtable /*Variable->Expr*/ exitIncarnationMap;
+ public Hashtable /*GotoCmd->returnCmd*/ gotoCmdOrigins;
+ public Dictionary<int, Absy> label2absy;
+ public VC.ModelViewInfo mvInfo;
+
+ public Dictionary<Block, VCExprVar> reachVars;
+ public List<VCExprLetBinding> reachVarBindings;
+ public Variable inputErrorVariable;
+ public Variable outputErrorVariable;
+
+
+
+ public LazyInliningInfo(Implementation impl, Program program, ProverContext ctxt, int uniqueId, GlobalVariable errorVariable)
+ {
+ Contract.Requires(impl != null);
+ Contract.Requires(program != null);
+ Procedure proc = cce.NonNull(impl.Proc);
+
+ this.impl = impl;
+ this.uniqueId = uniqueId;
+ this.controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "cfc", Microsoft.Boogie.Type.Int));
+ impl.LocVars.Add(controlFlowVariable);
+
+ List<Variable> interfaceVars = new List<Variable>();
+ Expr assertExpr = new LiteralExpr(Token.NoToken, true);
+ Contract.Assert(assertExpr != null);
+ // InParams must be obtained from impl and not proc
+ foreach (Variable v in impl.InParams)
+ {
+ Contract.Assert(v != null);
+ interfaceVars.Add(v);
+ }
+ // OutParams must be obtained from impl and not proc
+ foreach (Variable v in impl.OutParams)
+ {
+ Contract.Assert(v != null);
+ Constant c = new Constant(Token.NoToken,
+ new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
+ interfaceVars.Add(c);
+ Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
+ assertExpr = Expr.And(assertExpr, eqExpr);
+ }
+ foreach (Variable v in program.GlobalVariables)
+ {
+ Contract.Assert(v != null);
+ interfaceVars.Add(v);
+ if (v.Name == "error")
+ inputErrorVariable = v;
+ }
+ if (errorVariable != null)
+ {
+ proc.Modifies.Add(new IdentifierExpr(Token.NoToken, errorVariable));
+ }
+ foreach (IdentifierExpr e in proc.Modifies)
+ {
+ Contract.Assert(e != null);
+ if (e.Decl == null)
+ continue;
+ Variable v = e.Decl;
+ Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
+ interfaceVars.Add(c);
+ if (v.Name == "error")
+ {
+ outputErrorVariable = c;
+ continue;
+ }
+ Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
+ assertExpr = Expr.And(assertExpr, eqExpr);
+ }
+
+ this.interfaceVars = interfaceVars;
+ this.assertExpr = Expr.Not(assertExpr);
+ List<Variable> functionInterfaceVars = new List<Variable>();
+ foreach (Variable v in interfaceVars)
+ {
+ Contract.Assert(v != null);
+ functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, v.Name, v.TypedIdent.Type), true));
+ }
+ TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
+ Contract.Assert(ti != null);
+ Formal returnVar = new Formal(Token.NoToken, ti, false);
+ Contract.Assert(returnVar != null);
+ this.function = new Function(Token.NoToken, proc.Name, functionInterfaceVars, returnVar);
+ ctxt.DeclareFunction(this.function, "");
+
+ interfaceVarCopies = new List<List<Variable>>();
+ int temp = 0;
+ for (int i = 0; i < /* CommandLineOptions.Clo.ProcedureCopyBound */ 0; i++)
+ {
+ interfaceVarCopies.Add(new List<Variable>());
+ foreach (Variable v in interfaceVars)
+ {
+ Constant constant = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, v.Name + temp++, v.TypedIdent.Type));
+ interfaceVarCopies[i].Add(constant);
+ //program.AddTopLevelDeclaration(constant);
+ }
+ }
+ }
+ }
+
+ public class StratifiedInliningInfo : LazyInliningInfo
+ {
+ [ContractInvariantMethod]
+ void ObjectInvariant()
+ {
+ Contract.Invariant(cce.NonNullElements(privateVars));
+ Contract.Invariant(cce.NonNullElements(interfaceExprVars));
+ Contract.Invariant(cce.NonNullElements(interfaceExprVars));
+ }
+
+ // public StratifiedVCGenBase vcgen;
+ //public Implementation impl;
+ //public Program program;
+ //public ProverContext ctxt;
+ //public int uniqueid;
+ //public Function function;
+ //public Variable controlFlowVariable;
+ //public Expr assertExpr;
+ //public VCExpr vcexpr;
+ //public List<VCExprVar> interfaceExprVars;
+ //public List<VCExprVar> privateExprVars;
+ //public Dictionary<int, Absy> label2absy;
+ //public VC.ModelViewInfo mvInfo;
+ //public Dictionary<Block, List<CallSite>> callSites;
+ //public Dictionary<Block, List<CallSite>> recordProcCallSites;
+ //public IEnumerable<Block> sortedBlocks;
+ //public bool initialized { get; private set; }
+
+
+ public List<VCExprVar> interfaceExprVars;
+ // public List<VCExprVar> privateVars;
+ public VCExpr funcExpr;
+ public VCExpr falseExpr;
+ public RPFP.Transformer F;
+ public RPFP.Node node;
+ public RPFP.Edge edge;
+ public bool isMain = false;
+ public Dictionary<Absy, string> label2absyInv;
+ public ProverContext ctxt;
+ public Hashtable/*<Block, LetVariable!>*/ blockVariables = new Hashtable/*<Block, LetVariable!!>*/();
+ public List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
+
+ public StratifiedInliningInfo(Implementation _impl, Program _program, ProverContext _ctxt, int _uniqueid)
+ : base(_impl,_program,_ctxt,_uniqueid,null){
+ Contract.Requires(_impl != null);
+ Contract.Requires(_program != null);
+ privateVars = new List<VCExprVar>();
+ interfaceExprVars = new List<VCExprVar>();
+ ctxt = _ctxt;
+ }
+
+ }
+
+ protected override void addExitAssert(string implName, Block exitBlock)
+ {
+ if (implName2StratifiedInliningInfo != null
+ && implName2StratifiedInliningInfo.ContainsKey(implName)
+ && !implName2StratifiedInliningInfo[implName].isMain)
+ {
+ if (mode == Mode.Boogie) return;
+ Expr assertExpr = implName2StratifiedInliningInfo[implName].assertExpr;
+ Contract.Assert(assertExpr != null);
+ exitBlock.Cmds.Add(new AssertCmd(Token.NoToken, assertExpr));
+ }
+ }
+
+#if false
+ protected override void storeIncarnationMaps(string implName, Hashtable exitIncarnationMap)
+ {
+ if (implName2StratifiedInliningInfo != null && implName2StratifiedInliningInfo.ContainsKey(implName))
+ {
+ StratifiedInliningInfo info = implName2StratifiedInliningInfo[implName];
+ Contract.Assert(info != null);
+ info.exitIncarnationMap = exitIncarnationMap;
+ info.incarnationOriginMap = this.incarnationOriginMap;
+ }
+ }
+#endif
+
+ public void GenerateVCsForStratifiedInlining()
+ {
+ Contract.Requires(program != null);
+ foreach (var impl in program.Implementations)
+ {
+ Contract.Assert(!impl.Name.StartsWith(recordProcName), "Not allowed to have an implementation for this guy");
+
+ Procedure proc = cce.NonNull(impl.Proc);
+
+ {
+ StratifiedInliningInfo info = new StratifiedInliningInfo(impl, program, boogieContext, QuantifierExpr.GetNextSkolemId());
+ implName2StratifiedInliningInfo[impl.Name] = info;
+ // We don't need controlFlowVariable for stratified Inlining
+ //impl.LocVars.Add(info.controlFlowVariable);
+ List<Expr> exprs = new List<Expr>();
+
+ if (mode != Mode.Boogie && QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
+ {
+ proc.Ensures.Add(new Ensures(Token.NoToken, true, Microsoft.Boogie.Expr.False, "", null));
+ info.assertExpr = Microsoft.Boogie.Expr.False;
+ // info.isMain = true;
+ }
+ else if (mode == Mode.Corral || proc.FindExprAttribute("inline") != null || proc is LoopProcedure)
+ {
+ foreach (Variable v in proc.InParams)
+ {
+ Contract.Assert(v != null);
+ exprs.Add(new IdentifierExpr(Token.NoToken, v));
+ }
+ foreach (Variable v in proc.OutParams)
+ {
+ Contract.Assert(v != null);
+ exprs.Add(new IdentifierExpr(Token.NoToken, v));
+ }
+ foreach (Variable v in program.GlobalVariables)
+ {
+ Contract.Assert(v != null);
+ exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
+ }
+ foreach (IdentifierExpr ie in proc.Modifies)
+ {
+ Contract.Assert(ie != null);
+ if (ie.Decl == null)
+ continue;
+ exprs.Add(ie);
+ }
+ Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(info.function), exprs);
+#if true
+ if(mode == Mode.Corral || mode == Mode.OldCorral)
+ proc.Ensures.Add(new Ensures(Token.NoToken, true, freePostExpr, "", new QKeyValue(Token.NoToken, "si_fcall", new List<object>(), null)));
+#endif
+ }
+ else // not marked "inline" must be main
+ {
+ Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(info.function), exprs);
+ info.isMain = true;
+ }
+ }
+ }
+
+ if (mode == Mode.Boogie) return;
+
+ foreach (var proc in program.Procedures)
+ {
+ if (!proc.Name.StartsWith(recordProcName)) continue;
+ Contract.Assert(proc.InParams.Count == 1);
+
+ // Make a new function
+ TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
+ Contract.Assert(ti != null);
+ Formal returnVar = new Formal(Token.NoToken, ti, false);
+ Contract.Assert(returnVar != null);
+
+ // Get record type
+ var argtype = proc.InParams[0].TypedIdent.Type;
+
+ var ins = new List<Variable>();
+ ins.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "x", argtype), true));
+
+ var recordFunc = new Function(Token.NoToken, proc.Name, ins, returnVar);
+ boogieContext.DeclareFunction(recordFunc, "");
+
+ var exprs = new List<Expr>();
+ exprs.Add(new IdentifierExpr(Token.NoToken, proc.InParams[0]));
+
+ Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(recordFunc), exprs);
+ proc.Ensures.Add(new Ensures(true, freePostExpr));
+ }
+ }
+
+ private void FixedPointToSpecs(){
+
+ if(mode != Mode.Corral || CommandLineOptions.Clo.PrintFixedPoint == null)
+ return; // not implemented for other annotation modes yet
+
+ var twr = new TokenTextWriter(CommandLineOptions.Clo.PrintFixedPoint, /*pretty=*/ false);
+ Dictionary<string, RPFP.Node> pmap = new Dictionary<string,RPFP.Node> ();
+
+ foreach (var node in rpfp.nodes)
+ pmap.Add ((node.Name as VCExprBoogieFunctionOp).Func.Name, node);
+
+ foreach (var impl in program.Implementations)
+ {
+ Contract.Assert(!impl.Name.StartsWith(recordProcName), "Not allowed to have an implementation for this guy");
+
+ Procedure proc = cce.NonNull(impl.Proc);
+
+ {
+ StratifiedInliningInfo info = new StratifiedInliningInfo(impl, program, boogieContext, QuantifierExpr.GetNextSkolemId());
+ implName2StratifiedInliningInfo[impl.Name] = info;
+ // We don't need controlFlowVariable for stratified Inlining
+ //impl.LocVars.Add(info.controlFlowVariable);
+ List<Expr> exprs = new List<Expr>();
+
+ {
+ if (pmap.ContainsKey(impl.Name))
+ {
+ RPFP.Node node = pmap[impl.Name];
+ var annot = node.Annotation;
+ EmitProcSpec(twr, proc, info, annot);
+ }
+ }
+ }
+ }
+ twr.Close ();
+ }
+
+ private void EmitProcSpec(TokenTextWriter twr, Procedure proc, StratifiedInliningInfo info, RPFP.Transformer annot)
+ {
+ // last ensures clause will be the symbolic one
+ if (!info.isMain)
+ {
+ var ens = proc.Ensures[proc.Ensures.Count - 1];
+ if (ens.Condition != Expr.False) // this is main
+ {
+ var postExpr = ens.Condition as NAryExpr;
+ var args = postExpr.Args;
+
+ var ind = annot.IndParams;
+ var bound = new Dictionary<VCExpr, Expr>();
+ for (int i = 0; i < args.Count; i++)
+ {
+ bound[ind[i]] = args[i];
+ }
+ var new_ens_cond = VCExprToExpr(annot.Formula, bound);
+ if (new_ens_cond != Expr.True)
+ {
+ var new_ens = new Ensures(false, new_ens_cond);
+ var enslist = new List<Ensures>();
+ enslist.Add(new_ens);
+ var new_proc = new Procedure(proc.tok, proc.Name, proc.TypeParameters, proc.InParams,
+ proc.OutParams, new List<Requires>(), new List<IdentifierExpr>(), enslist);
+ new_proc.Emit(twr, 0);
+ }
+ }
+ }
+ }
+
+ static int ConjectureFileCounter = 0;
+
+ private void ConjecturesToSpecs()
+ {
+
+ if (mode != Mode.Corral || CommandLineOptions.Clo.PrintConjectures == null)
+ return; // not implemented for other annotation modes yet
+
+ var twr = new TokenTextWriter(CommandLineOptions.Clo.PrintConjectures + "." + ConjectureFileCounter.ToString(), /*pretty=*/ false);
+ ConjectureFileCounter++;
+
+ foreach (var c in rpfp.conjectures)
+ {
+ var name = c.node.Name.GetDeclName();
+ if (implName2StratifiedInliningInfo.ContainsKey(name))
+ {
+ StratifiedInliningInfo info = implName2StratifiedInliningInfo[c.node.Name.GetDeclName()];
+ Implementation impl = info.impl;
+ Procedure proc = impl.Proc;
+ EmitProcSpec(twr, proc, info, c.bound);
+ }
+ }
+
+ twr.Close ();
+ }
+
+ private Term ExtractSmallerVCsRec(TermDict< Term> memo, Term t, List<Term> small, Term lbl = null)
+ {
+ Term res;
+ if (memo.TryGetValue(t, out res))
+ return res;
+ var kind = t.GetKind();
+ if (kind == TermKind.App)
+ {
+ var f = t.GetAppDecl();
+ if (f.GetKind() == DeclKind.Implies){
+ var lhs = t.GetAppArgs()[0];
+ if(lhs.GetKind() == TermKind.App){
+ var r = lhs.GetAppDecl();
+ if (r.GetKind() == DeclKind.And)
+ {
+ Term q = t.GetAppArgs()[1];
+ var lhsargs = lhs.GetAppArgs();
+ for (int i = lhsargs.Length-1; i >= 0; --i)
+ {
+ q = ctx.MkImplies(lhsargs[i], q);
+ }
+ res = ExtractSmallerVCsRec(memo, q, small,lbl);
+ goto done;
+ }
+ if (r.GetKind() == DeclKind.Label)
+ {
+ var arg = lhs;
+ arg = lhs.GetAppArgs()[0];
+ if (!(arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted))
+ goto normal;
+ if (!(annotationInfo.ContainsKey(arg.GetAppDecl().GetDeclName()) && annotationInfo[arg.GetAppDecl().GetDeclName()].type == AnnotationInfo.AnnotationType.LoopInvariant))
+ goto normal;
+ var sm = ctx.MkImplies(lhs, ExtractSmallerVCsRec(memo, t.GetAppArgs()[1], small));
+ if (lbl != null)
+ sm = ctx.MkImplies(lbl, sm);
+ small.Add(sm);
+ res = ctx.MkTrue();
+ goto done;
+ }
+ if (r.GetKind() == DeclKind.Uninterpreted)
+ {
+ var arg = lhs;
+ if (!(annotationInfo.ContainsKey(arg.GetAppDecl().GetDeclName()) && annotationInfo[arg.GetAppDecl().GetDeclName()].type == AnnotationInfo.AnnotationType.LoopInvariant))
+ goto normal;
+ var sm = ctx.MkImplies(lhs,ExtractSmallerVCsRec(memo,t.GetAppArgs()[1],small));
+ if (lbl != null)
+ sm = ctx.MkImplies(lbl, sm);
+ small.Add(sm);
+ res = ctx.MkTrue();
+ goto done;
+ }
+ }
+ normal:
+ Term newlbl = null;
+ if (lhs.IsLabel() && lhs.GetAppArgs()[0] == ctx.MkTrue())
+ newlbl = lhs;
+ res = ctx.MkImplies(lhs,ExtractSmallerVCsRec(memo,t.GetAppArgs()[1],small,newlbl));
+ }
+ else if (f.GetKind() == DeclKind.And)
+ {
+ res = ctx.MkApp(f,t.GetAppArgs().Select(x => ExtractSmallerVCsRec(memo, x, small)).ToArray());
+ }
+ else
+ res = t;
+ }
+ else
+ res = t;
+ done:
+ memo.Add(t, res);
+ return res;
+ }
+
+ private void ExtractSmallerVCs(Term t, List<Term> small){
+ TermDict< Term> memo = new TermDict< Term>();
+ Term top = ExtractSmallerVCsRec(memo, t, small);
+ small.Add(top);
+ }
+
+ private Dictionary<FuncDecl, int> goalNumbering = new Dictionary<FuncDecl, int>();
+
+ private Term NormalizeGoal(Term goal, FuncDecl label)
+ {
+ var f = goal.GetAppDecl();
+ var args = goal.GetAppArgs();
+ int number;
+ if (!goalNumbering.TryGetValue(f, out number))
+ {
+ number = goalNumbering.Count;
+ goalNumbering.Add(f, number);
+ }
+ Term[] tvars = new Term[args.Length];
+ Term[] eqns = new Term[args.Length];
+ AnnotationInfo info = null;
+ annotationInfo.TryGetValue(f.GetDeclName(), out info);
+ for (int i = 0; i < args.Length; i++)
+ {
+ string pname = (info == null) ? i.ToString() : info.argnames[i];
+ tvars[i] = ctx.MkConst("@a" + number.ToString() + "_" + pname, args[i].GetSort());
+ eqns[i] = ctx.MkEq(tvars[i], args[i]);
+ }
+ return ctx.MkImplies(ctx.MkAnd(eqns), ctx.MkApp(label, ctx.MkApp(f, tvars)));
+ }
+
+ private Term MergeGoalsRec(TermDict< Term> memo, Term t)
+ {
+ Term res;
+ if (memo.TryGetValue(t, out res))
+ return res;
+ var kind = t.GetKind();
+ if (kind == TermKind.App)
+ {
+ var f = t.GetAppDecl();
+ var args = t.GetAppArgs();
+ if (f.GetKind() == DeclKind.Implies)
+ {
+ res = ctx.MkImplies(args[0], MergeGoalsRec(memo, args[1]));
+ goto done;
+ }
+ else if (f.GetKind() == DeclKind.And)
+ {
+ args = args.Select(x => MergeGoalsRec(memo, x)).ToArray();
+ res = ctx.MkApp(f, args);
+ goto done;
+ }
+ else if (f.GetKind() == DeclKind.Label)
+ {
+ var arg = t.GetAppArgs()[0];
+ var r = arg.GetAppDecl();
+ if (r.GetKind() == DeclKind.Uninterpreted)
+ {
+ res = NormalizeGoal(arg, f);
+ goto done;
+ }
+ }
+ }
+ res = t;
+ done:
+ memo.Add(t, res);
+ return res;
+ }
+
+ private Term MergeGoals(Term t)
+ {
+ TermDict< Term> memo = new TermDict< Term>();
+ return MergeGoalsRec(memo, t);
+ }
+
+ private Term CollectGoalsRec(TermDict< Term> memo, Term t, List<Term> goals, List<Term> cruft)
+ {
+ Term res;
+ if (memo.TryGetValue(t, out res))
+ return res;
+ var kind = t.GetKind();
+ if (kind == TermKind.App)
+ {
+ var f = t.GetAppDecl();
+ if (f.GetKind() == DeclKind.Implies)
+ {
+ CollectGoalsRec(memo, t.GetAppArgs()[1], goals, cruft);
+ goto done;
+ }
+ else if (f.GetKind() == DeclKind.And)
+ {
+ foreach (var arg in t.GetAppArgs())
+ {
+ CollectGoalsRec(memo, arg, goals, cruft);
+ }
+ goto done;
+ }
+ else if (f.GetKind() == DeclKind.Label)
+ {
+ var arg = t.GetAppArgs()[0];
+ if (arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted)
+ {
+ var r = arg.GetAppDecl();
+ if (memo.TryGetValue(arg, out res))
+ goto done;
+ if (!annotationInfo.ContainsKey(r.GetDeclName()) && !arg.GetAppDecl().GetDeclName().StartsWith("_solve_"))
+ goto done;
+ goals.Add(arg);
+ memo.Add(arg, arg);
+ goto done;
+ }
+ else
+ return CollectGoalsRec(memo, arg, goals, cruft);
+ }
+ else if (f.GetKind() == DeclKind.Uninterpreted)
+ {
+ string name = f.GetDeclName();
+ if (name.StartsWith("_solve_"))
+ {
+ if (memo.TryGetValue(t, out res))
+ goto done;
+ goals.Add(t);
+ memo.Add(t, t);
+ return t;
+ }
+ }
+ }
+ // else the goal must be cruft
+ cruft.Add(t);
+ done:
+ res = t; // just to return something
+ memo.Add(t, res);
+ return res;
+ }
+
+ private void CollectGoals(Term t, List<Term> goals, List<Term> cruft)
+ {
+ TermDict< Term> memo = new TermDict< Term>();
+ CollectGoalsRec(memo, t.GetAppArgs()[1], goals, cruft);
+ }
+
+ private Term SubstRec(TermDict< Term> memo, Term t)
+ {
+ Term res;
+ if (memo.TryGetValue(t, out res))
+ return res;
+ var kind = t.GetKind();
+ if (kind == TermKind.App)
+ {
+ // var f = t.GetAppDecl();
+ var args = t.GetAppArgs().Select(x => SubstRec(memo, x)).ToArray();
+ res = ctx.CloneApp(t, args);
+ }
+ else res = t;
+ memo.Add(t, res);
+ return res;
+ }
+
+ private Term SubstRecGoals(TermDict< Term> memo, Term t)
+ {
+ Term res;
+ if (memo.TryGetValue(t, out res))
+ return res;
+ var kind = t.GetKind();
+ if (kind == TermKind.App)
+ {
+ var f = t.GetAppDecl();
+ var args = t.GetAppArgs();
+ if (f.GetKind() == DeclKind.Implies){
+ res = SubstRecGoals(memo, args[1]);
+ if (res != ctx.MkTrue())
+ res = ctx.MkImplies(args[0],res);
+ goto done;
+ }
+ else if (f.GetKind() == DeclKind.And)
+ {
+ args = args.Select(x => SubstRecGoals(memo, x)).ToArray();
+ args = args.Where(x => x != ctx.MkTrue()).ToArray();
+ res = ctx.MkAnd(args);
+ goto done;
+ }
+ else if (f.GetKind() == DeclKind.Label)
+ {
+ var arg = t.GetAppArgs()[0];
+ if (arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted)
+ {
+ var r = arg.GetAppDecl();
+ if (memo.TryGetValue(arg, out res))
+ {
+ if(res != ctx.MkTrue())
+ res = ctx.MkApp(f, res);
+ goto done;
+ }
+ }
+ else
+ {
+ res = ctx.MkApp(f, SubstRecGoals(memo, arg));
+ goto done;
+ }
+
+ }
+ // what's left could be cruft!
+ if (memo.TryGetValue(t, out res))
+ {
+ goto done;
+ }
+ }
+ res = t;
+ done:
+ memo.Add(t, res);
+ return res;
+ }
+
+ private void FactorVCs(Term t, List<Term> vcs)
+ {
+ List<Term> small = new List<Term>();
+ ExtractSmallerVCs(t, small);
+ foreach (var smm in small)
+ {
+ List<Term> goals = new List<Term>();
+ List<Term> cruft = new List<Term>();
+ var sm = largeblock ? MergeGoals(smm) : smm;
+ CollectGoals(sm, goals,cruft);
+ foreach (var goal in goals)
+ {
+ TermDict< Term> memo = new TermDict< Term>();
+ foreach (var othergoal in goals)
+ memo.Add(othergoal, othergoal.Equals(goal) ? ctx.MkFalse() : ctx.MkTrue());
+ foreach (var thing in cruft)
+ memo.Add(thing, ctx.MkTrue());
+ var vc = SubstRecGoals(memo, sm);
+ vc = ctx.MkImplies(ctx.MkNot(vc), goal);
+ vcs.Add(vc);
+ }
+ {
+ TermDict< Term> memo = new TermDict< Term>();
+ foreach (var othergoal in goals)
+ memo.Add(othergoal, ctx.MkTrue());
+ var vc = SubstRecGoals(memo, sm);
+ if (vc != ctx.MkTrue())
+ {
+ vc = ctx.MkImplies(ctx.MkNot(vc), ctx.MkFalse());
+ vcs.Add(vc);
+ }
+ }
+ }
+ }
+
+
+
+ private void GenerateVCForStratifiedInlining(Program program, StratifiedInliningInfo info, Checker checker)
+ {
+ Contract.Requires(program != null);
+ Contract.Requires(info != null);
+ Contract.Requires(checker != null);
+ Contract.Requires(info.impl != null);
+ Contract.Requires(info.impl.Proc != null);
+
+
+
+ Implementation impl = info.impl;
+ if (mode == Mode.Boogie && style == AnnotationStyle.Flat && impl.Name != main_proc_name)
+ return;
+ Contract.Assert(impl != null);
+ ConvertCFG2DAG(impl,edgesCut);
+ VC.ModelViewInfo mvInfo;
+ PassifyImpl(impl, out mvInfo);
+ Dictionary<int, Absy> label2absy = null;
+ VCExpressionGenerator gen = checker.VCExprGen;
+ Contract.Assert(gen != null);
+ VCExpr vcexpr;
+ if(NoLabels){
+ // int assertionCount = 0;
+ VCExpr startCorrect = null; /* VC.VCGen.LetVC(cce.NonNull(impl.Blocks[0]), null, null, info.blockVariables, info.bindings,
+ info.ctxt, out assertionCount); */
+ vcexpr = gen.Let(info.bindings, startCorrect);
+ }
+ else vcexpr = GenerateVC(impl, null /* info.controlFlowVariable */, out label2absy, info.ctxt);
+ if(mode != Mode.Boogie)
+ vcexpr = gen.Not(vcexpr);
+ Contract.Assert(vcexpr != null);
+ info.label2absy = label2absy;
+ info.mvInfo = mvInfo;
+ List<VCExpr> interfaceExprs = new List<VCExpr>();
+
+ if (true /* was: !info.isMain */)
+ {
+ Boogie2VCExprTranslator translator = checker.TheoremProver.Context.BoogieExprTranslator;
+ Contract.Assert(translator != null);
+ info.privateVars = new List<VCExprVar>();
+ foreach (Variable v in impl.LocVars)
+ {
+ Contract.Assert(v != null);
+ info.privateVars.Add(translator.LookupVariable(v));
+ }
+ foreach (Variable v in impl.OutParams)
+ {
+ Contract.Assert(v != null);
+ info.privateVars.Add(translator.LookupVariable(v));
+ }
+
+ info.interfaceExprVars = new List<VCExprVar>();
+
+ foreach (Variable v in info.interfaceVars)
+ {
+ Contract.Assert(v != null);
+ VCExprVar ev = translator.LookupVariable(v);
+ Contract.Assert(ev != null);
+ info.interfaceExprVars.Add(ev);
+ interfaceExprs.Add(ev);
+ }
+ }
+
+ Function function = cce.NonNull(info.function);
+ Contract.Assert(function != null);
+ info.funcExpr = gen.Function(function, interfaceExprs);
+ info.vcexpr = vcexpr;
+
+ if (mode == Mode.Boogie)
+ {
+ Term z3vc = boogieContext.VCExprToTerm(vcexpr, linOptions);
+ FactorVCs(z3vc, DualityVCs);
+ }
+ else
+ {
+ // Index the procedures by relational variable
+ FuncDecl R = boogieContext.VCExprToTerm(info.funcExpr, linOptions).GetAppDecl();
+ relationToProc.Add(R, info);
+ info.node = rpfp.CreateNode(boogieContext.VCExprToTerm(info.funcExpr, linOptions));
+ rpfp.nodes.Add(info.node);
+ if (info.isMain || QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
+ info.node.Bound.Formula = ctx.MkFalse();
+ }
+ }
+
+ // This returns a new FuncDel with same sort as top-level function
+ // of term t, but with numeric suffix appended to name.
+
+ private FuncDecl SuffixFuncDecl(Term t, int n)
+ {
+ var name = t.GetAppDecl().GetDeclName() + "_" + n.ToString();
+ return ctx.MkFuncDecl(name, t.GetAppDecl());
+ }
+
+ // Collect the relational paremeters
+
+ private Term CollectParamsRec(TermDict<Term> memo, Term t, List<FuncDecl> parms, List<RPFP.Node> nodes, Dictionary<Term,Term> done)
+ {
+ Term res;
+ if (memo.TryGetValue(t, out res))
+ return res;
+ var kind = t.GetKind();
+ if (kind == TermKind.App)
+ {
+ var f = t.GetAppDecl();
+ var args = t.GetAppArgs();
+ args = args.Select(x => CollectParamsRec(memo, x, parms, nodes, done)).ToArray();
+ StratifiedInliningInfo info;
+ if (relationToProc.TryGetValue(f, out info))
+ {
+ if (done.ContainsKey(t))
+ res = done[t];
+ else
+ {
+ f = SuffixFuncDecl(t, parms.Count);
+ parms.Add(f);
+ nodes.Add(info.node);
+ res = ctx.MkApp(f, args);
+ done.Add(t,res); // don't count same expression twice!
+ }
+ }
+ else
+ res = ctx.CloneApp(t, args);
+ } // TODO: handle quantifiers
+ else res = t;
+ memo.Add(t, res);
+ return res;
+ }
+
+ public void GetTransformer(StratifiedInliningInfo info)
+ {
+ Term vcTerm = boogieContext.VCExprToTerm(info.vcexpr, linOptions);
+ Term[] paramTerms = info.interfaceExprVars.Select(x => boogieContext.VCExprToTerm(x, linOptions)).ToArray();
+ var relParams = new List<FuncDecl>();
+ var nodeParams = new List<RPFP.Node>();
+ var memo = new TermDict< Term>();
+ var done = new Dictionary<Term,Term>(); // note this hashes on equality, not reference!
+ vcTerm = CollectParamsRec(memo, vcTerm, relParams, nodeParams,done);
+ // var ops = new Util.ContextOps(ctx);
+ // var foo = ops.simplify_lhs(vcTerm);
+ // vcTerm = foo.Item1;
+ info.F = rpfp.CreateTransformer(relParams.ToArray(), paramTerms, vcTerm);
+ info.edge = rpfp.CreateEdge(info.node, info.F, nodeParams.ToArray());
+ rpfp.edges.Add(info.edge);
+ // TODO labels[info.edge.number] = foo.Item2;
+ }
+
+ public RPFP.Node GetNodeOfImpl(Implementation/*!*/ impl)
+ {
+ return implName2StratifiedInliningInfo[impl.Name].node;
+ }
+
+ public class CyclicLiveVariableAnalysis : Microsoft.Boogie.LiveVariableAnalysis
+ {
+ public new static void ComputeLiveVariables(Implementation impl)
+ {
+
+ bool some_change = true;
+ List<Block> sortedNodes = new List<Block>();
+ foreach (var block in impl.Blocks)
+ {
+ sortedNodes.Add(block);
+ }
+ sortedNodes.Reverse();
+
+ while (some_change)
+ {
+ some_change = false;
+ foreach (Block/*!*/ block in sortedNodes)
+ {
+ Contract.Assert(block != null);
+ HashSet<Variable/*!*/>/*!*/ liveVarsAfter = new HashSet<Variable/*!*/>();
+ if (block.TransferCmd is GotoCmd)
+ {
+ GotoCmd gotoCmd = (GotoCmd)block.TransferCmd;
+ if (gotoCmd.labelTargets != null)
+ {
+ foreach (Block/*!*/ succ in gotoCmd.labelTargets)
+ {
+ Contract.Assert(succ != null);
+ if (succ.liveVarsBefore != null)
+ liveVarsAfter.UnionWith(succ.liveVarsBefore);
+ }
+ }
+ }
+
+ List<Cmd> cmds = block.Cmds;
+ int len = cmds.Count;
+ for (int i = len - 1; i >= 0; i--)
+ {
+ if (cmds[i] is CallCmd)
+ {
+ Procedure/*!*/ proc = cce.NonNull(cce.NonNull((CallCmd/*!*/)cmds[i]).Proc);
+ if (InterProcGenKill.HasSummary(proc.Name))
+ {
+ liveVarsAfter =
+ InterProcGenKill.PropagateLiveVarsAcrossCall(cce.NonNull((CallCmd/*!*/)cmds[i]), liveVarsAfter);
+ continue;
+ }
+ }
+ Propagate(cmds[i], liveVarsAfter);
+ }
+
+ if (block.liveVarsBefore == null)
+ block.liveVarsBefore = new HashSet<Variable>();
+ if (!liveVarsAfter.IsSubsetOf(block.liveVarsBefore))
+ {
+ block.liveVarsBefore = liveVarsAfter;
+ some_change = true;
+ }
+ }
+ }
+ }
+ }
+
+ public void Generate()
+ {
+
+ var oldDagOption = CommandLineOptions.Clo.vcVariety;
+ CommandLineOptions.Clo.vcVariety = CommandLineOptions.VCVariety.Dag;
+
+ // MarkAllFunctionImplementationsInline(); // This is for SMACK, which goes crazy with functions
+
+ // Run live variable analysis (TODO: should this be here?)
+#if false
+ if (CommandLineOptions.Clo.LiveVariableAnalysis == 2)
+ {
+ Microsoft.Boogie.InterProcGenKill.ComputeLiveVars(impl, program);
+ }
+#endif
+
+ #region In Boogie mode, annotate the program
+ if (mode == Mode.Boogie)
+ {
+
+ // find the name of the main procedure
+ main_proc_name = null; // default in case no entry point defined
+ foreach (var impl in program.Implementations)
+ {
+ if (QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
+ main_proc_name = impl.Proc.Name;
+ }
+ if (main_proc_name == null)
+ {
+ foreach (var impl in program.Implementations)
+ {
+ if (impl.Proc.Name == "main" || impl.Proc.Name.EndsWith(".main"))
+ main_proc_name = impl.Proc.Name;
+ }
+ }
+ if (main_proc_name == null)
+ main_proc_name = "main";
+
+ if (style == AnnotationStyle.Flat)
+ {
+ InlineAll();
+ Microsoft.Boogie.BlockCoalescer.CoalesceBlocks(program);
+ foreach (var impl in program.Implementations)
+ {
+ if (main_proc_name == impl.Proc.Name)
+ {
+ Microsoft.Boogie.LiveVariableAnalysis.ClearLiveVariables(impl);
+ CyclicLiveVariableAnalysis.ComputeLiveVariables(impl);
+ AnnotateLoops(impl, boogieContext);
+ }
+ }
+ }
+ else
+ {
+
+ if (style == AnnotationStyle.Procedure || style == AnnotationStyle.Call)
+ {
+ foreach (var impl in program.Implementations)
+ {
+ if (!QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
+ AnnotateProcRequires(impl.Proc, impl, boogieContext);
+ AnnotateProcEnsures(impl.Proc, impl, boogieContext);
+ }
+ if (style == AnnotationStyle.Call)
+ {
+
+ }
+ }
+
+ // must do this after annotating procedures, else calls
+ // will be prematurely desugared
+
+ foreach (var impl in program.Implementations)
+ {
+ Microsoft.Boogie.LiveVariableAnalysis.ClearLiveVariables(impl);
+ CyclicLiveVariableAnalysis.ComputeLiveVariables(impl);
+ }
+
+
+ if (style == AnnotationStyle.Flat || style == AnnotationStyle.Call)
+ {
+ foreach (var impl in program.Implementations)
+ {
+ AnnotateLoops(impl, boogieContext);
+ }
+ }
+ if (style == AnnotationStyle.Call)
+ {
+ Dictionary<string, bool> impls = new Dictionary<string, bool>();
+ foreach (var impl in program.Implementations)
+ {
+ impls.Add(impl.Proc.Name, true);
+ }
+ foreach (var impl in program.Implementations)
+ {
+ AnnotateCallSites(impl, boogieContext, impls);
+ }
+ }
+ if (style == AnnotationStyle.Flat)
+ InlineAll();
+ }
+ }
+ #endregion
+
+ /* Generate the VC's */
+ GenerateVCsForStratifiedInlining();
+
+ /* Generate the background axioms */
+ Term background = ctx.MkTrue(); // TODO boogieContext.VCExprToTerm(boogieContext.Axioms, linOptions);
+ rpfp.AssertAxiom(background);
+
+ int save_option = CommandLineOptions.Clo.StratifiedInlining; // need this to get funcall labels
+ CommandLineOptions.Clo.StratifiedInlining = 1;
+
+ /* Create the nodes, indexing procedures by their relational symbols. */
+ foreach (StratifiedInliningInfo info in implName2StratifiedInliningInfo.Values)
+ GenerateVCForStratifiedInlining(program, info, checker);
+
+ CommandLineOptions.Clo.StratifiedInlining = save_option;
+
+ if (mode == Mode.Boogie)
+ {
+ // var ops = new Util.ContextOps(ctx);
+ var vcs = DualityVCs;
+ DualityVCs = new List<Term>();
+ foreach (var vc in vcs)
+ {
+ // var foo = ops.simplify_lhs(vc.GetAppArgs()[0]);
+ var foo = vc.GetAppArgs()[0];
+ if (!foo.IsFalse())
+ DualityVCs.Add(ctx.MkImplies(foo, vc.GetAppArgs()[1]));
+ }
+
+ rpfp.FromClauses(DualityVCs.ToArray());
+ // TODO rpfp.HornClauses = style == AnnotationStyle.Flat;
+ }
+ else
+ {
+ /* Generate the edges. */
+ foreach (StratifiedInliningInfo info in implName2StratifiedInliningInfo.Values)
+ GetTransformer(info);
+ }
+
+ // save some information for debugging purposes
+ // TODO rpfp.ls.SetAnnotationInfo(annotationInfo);
+
+ CommandLineOptions.Clo.vcVariety = oldDagOption;
+ }
+
+
+ private class ErrorHandler : ProverInterface.ErrorHandler
+ {
+ //TODO: anything we need to handle?
+ }
+
+ Dictionary<int, Dictionary<string, string>> varSubst = null;
+
+ /** Check the RPFP, and return a counterexample if there is one. */
+
+ public VC.ConditionGeneration.Outcome Check(ref RPFP.Node cexroot)
+ {
+ var start = DateTime.Now;
+
+ ErrorHandler handler = new ErrorHandler();
+ RPFP.Node cex;
+ varSubst = new Dictionary<int,Dictionary<string,string>>();
+
+#if false
+ int origRecursionBound = CommandLineOptions.Clo.RecursionBound;
+ if (CommandLineOptions.Clo.RecursionBound > 0 && extraRecBound != null)
+ {
+ int maxExtra = 0;
+ foreach (string s in extraRecBound.Keys)
+ {
+ int extra = extraRecBound[s];
+ if (extra > maxExtra) maxExtra = extra;
+ }
+ CommandLineOptions.Clo.RecursionBound += maxExtra;
+ }
+#endif
+
+ ProverInterface.Outcome outcome =
+ checker.TheoremProver.CheckRPFP("name", rpfp, handler, out cex, varSubst, extraRecBound);
+ cexroot = cex;
+
+#if false
+ CommandLineOptions.Clo.RecursionBound = origRecursionBound;
+#endif
+
+ Console.WriteLine("solve: {0}s", (DateTime.Now - start).TotalSeconds);
+
+ switch(outcome)
+ {
+ case ProverInterface.Outcome.Valid:
+ return VC.ConditionGeneration.Outcome.Correct;
+ case ProverInterface.Outcome.Bounded:
+ return VC.ConditionGeneration.Outcome.ReachedBound;
+ case ProverInterface.Outcome.Invalid:
+ return VC.ConditionGeneration.Outcome.Errors;
+ case ProverInterface.Outcome.TimeOut:
+ return VC.ConditionGeneration.Outcome.TimedOut;
+ default:
+ return VC.ConditionGeneration.Outcome.Inconclusive;
+ }
+ }
+
+ private bool generated = false;
+
+ static private Object thisLock = new Object();
+
+ public override VC.VCGen.Outcome VerifyImplementation(Implementation impl, VerifierCallback collector)
+ {
+
+ lock (thisLock)
+ {
+ Procedure proc = impl.Proc;
+
+ // we verify all the impls at once, so we need to execute only once
+ // TODO: make sure needToCheck is true only once
+ bool needToCheck = false;
+ if (mode == Mode.OldCorral)
+ needToCheck = proc.FindExprAttribute("inline") == null && !(proc is LoopProcedure);
+ else if (mode == Mode.Corral || mode == Mode.Boogie)
+ needToCheck = QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint") && !(proc is LoopProcedure);
+ else
+ needToCheck = impl.Name == main_proc_name;
+
+ if (needToCheck)
+ {
+
+ var start = DateTime.Now;
+
+ if (!generated)
+ {
+ Generate();
+ Console.WriteLine("generate: {0}s", (DateTime.Now - start).TotalSeconds);
+ generated = true;
+ }
+
+
+ Console.WriteLine("Verifying {0}...", impl.Name);
+
+ RPFP.Node cexroot = null;
+ // start = DateTime.Now;
+ var checkres = Check(ref cexroot);
+ Console.WriteLine("check: {0}s", (DateTime.Now - start).TotalSeconds);
+ switch (checkres)
+ {
+ case Outcome.Errors:
+ Console.WriteLine("Counterexample found.\n");
+ // start = DateTime.Now;
+ Counterexample cex = CreateBoogieCounterExample(cexroot.owner, cexroot, impl);
+ // cexroot.owner.DisposeDualModel();
+ // cex.Print(0); // just for testing
+ collector.OnCounterexample(cex, "assertion failure");
+ Console.WriteLine("cex: {0}s", (DateTime.Now - start).TotalSeconds);
+ ConjecturesToSpecs();
+ break;
+ case Outcome.Correct:
+ Console.WriteLine("Procedure is correct. (fixed point reached)");
+ FixedPointToSpecs();
+ ConjecturesToSpecs();
+ break;
+ case Outcome.ReachedBound:
+ Console.WriteLine("Procedure is correct. (recursion bound reached)");
+ FixedPointToSpecs();
+ ConjecturesToSpecs();
+ break;
+ default:
+ Console.WriteLine("Inconclusive result.");
+ ConjecturesToSpecs();
+ break;
+ }
+ return checkres;
+
+ }
+
+ return Outcome.Inconclusive;
+ }
+ }
+
+ public void FindLabelsRec(HashSet<Term> memo, Term t, Dictionary<string, Term> res)
+ {
+ if (memo.Contains(t))
+ return;
+ if (t.IsLabel())
+ {
+ string l = t.LabelName();
+ if (!res.ContainsKey(l))
+ res.Add(l, t.GetAppArgs()[0]);
+ }
+ if (t.GetKind() == TermKind.App)
+ {
+ var args = t.GetAppArgs();
+ foreach (var a in args)
+ FindLabelsRec(memo, a, res);
+ } // TODO: handle quantifiers
+
+ memo.Add(t);
+ }
+
+ public void FindLabels()
+ {
+ labels = new Dictionary<string, Term>();
+ foreach(var e in rpfp.edges){
+ int id = e.number;
+ HashSet<Term> memo = new HashSet<Term>(ReferenceComparer<Term>.Instance);
+ FindLabelsRec(memo, e.F.Formula, labels);
+ }
+ }
+
+ public string CodeLabel(Absy code, StratifiedInliningInfo info, string prefix)
+ {
+ if (info.label2absyInv == null)
+ {
+ info.label2absyInv = new Dictionary<Absy, string>();
+ foreach (int foo in info.label2absy.Keys)
+ {
+ Absy bar = info.label2absy[foo] as Absy;
+ string lbl = foo.ToString();
+ info.label2absyInv.Add(bar, lbl);
+ }
+ }
+ if (info.label2absyInv.ContainsKey(code))
+ {
+ string label = info.label2absyInv[code];
+ return prefix+label;
+ }
+ return null;
+ }
+
+ public Term CodeLabeledExpr(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix)
+ {
+ string label = CodeLabel(code, info, prefix);
+
+ if (label != null)
+ {
+ var res = labels[label];
+ return res;
+ }
+ else return null;
+ }
+
+ public class LabelNotFound : Exception { };
+
+ public bool CodeLabelTrue(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix)
+ {
+ string label = CodeLabel(code, info, prefix);
+
+ if (label == null)
+ throw new LabelNotFound();
+ return root.Outgoing.labels.Contains(label);
+ }
+
+ public bool CodeLabelFalse(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix)
+ {
+ return CodeLabelTrue(rpfp, root, code, info, prefix);
+ }
+
+
+ private class StateId
+ {
+ public RPFP.Edge edge;
+ public int capturePoint;
+ public StratifiedInliningInfo info;
+ public StateId(RPFP.Edge e, int c, StratifiedInliningInfo i)
+ {
+ edge = e;
+ capturePoint = c;
+ info = i;
+ }
+ }
+
+
+ public Counterexample CreateBoogieCounterExample(RPFP rpfp, RPFP.Node root, Implementation mainImpl)
+ {
+ FindLabels();
+ var orderedStateIds = new List<StateId>();
+ Counterexample newCounterexample =
+ GenerateTrace(rpfp, root, orderedStateIds, mainImpl,true);
+ if (CommandLineOptions.Clo.ModelViewFile != null)
+ {
+ Model m = root.owner.GetBackgroundModel();
+ GetModelWithStates(m, root, implName2StratifiedInliningInfo[mainImpl.Name],
+ orderedStateIds, varSubst);
+ newCounterexample.Model = m;
+ newCounterexample.ModelHasStatesAlready = true;
+ }
+ return newCounterexample;
+ }
+
+
+
+ private Counterexample GenerateTrace(RPFP rpfp, RPFP.Node root,
+ List<StateId> orderedStateIds, Implementation procImpl, bool toplevel)
+ {
+ Contract.Requires(procImpl != null);
+
+ Contract.Assert(!rpfp.Empty(root));
+
+
+ var info = implName2StratifiedInliningInfo[procImpl.Name];
+ Block entryBlock = cce.NonNull(procImpl.Blocks[0]);
+ Contract.Assert(entryBlock != null);
+
+ List<Block> trace = new List<Block>();
+ trace.Add(entryBlock);
+
+ var calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
+
+ Counterexample newCounterexample =
+ GenerateTraceRec(rpfp, root, orderedStateIds, entryBlock, trace, calleeCounterexamples, info, toplevel);
+
+ return newCounterexample;
+ }
+
+ // TODO: this is a bit cheesy. Rather than finding the argument position
+ // of a relational term in a transformer by linear search, better to index this
+ // somewhere, but where?
+ private int TransformerArgPosition(RPFP rpfp, RPFP.Node root, Term expr)
+ {
+ FuncDecl rel = expr.GetAppDecl();
+ string relname = rel.GetDeclName();
+ var rps = root.Outgoing.F.RelParams;
+ for (int i = 0; i < rps.Length; i++)
+ {
+ string thisname = rps[i].GetDeclName();
+ if (thisname == relname)
+ return i;
+ }
+ return -1;
+ }
+
+ private bool EvalToFalse(RPFP rpfp, RPFP.Node root, Term expr,StratifiedInliningInfo info){
+ Term res = rpfp.Eval(root.Outgoing,expr);
+ return res.Equals(ctx.MkTrue());
+ }
+
+ private Counterexample GenerateTraceRec(
+ RPFP rpfp, RPFP.Node root,
+ List<StateId> orderedStateIds,
+ Block/*!*/ b, List<Block>/*!*/ trace,
+ Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples,
+ StratifiedInliningInfo info,
+ bool toplevel)
+ {
+ Contract.Requires(b != null);
+ Contract.Requires(trace != null);
+ Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples));
+
+ Stack<RPFP.Node> continuation_stack = new Stack<RPFP.Node>();
+
+ // If our block is not present, try diving into precondition
+ // and push a continuation.
+ // TODO: is the precondition always the first child?
+ while (!CodeLabelFalse(rpfp, root, b, info, "+"))
+ {
+ if (root.Outgoing != null && root.Outgoing.Children.Length > 0)
+ {
+ continuation_stack.Push(root);
+ root = root.Outgoing.Children[0];
+ }
+ else
+ {
+ // can't find our block
+ Contract.Assert(false);
+ return null;
+ }
+ }
+
+ // After translation, all potential errors come from asserts.
+ while (true)
+ {
+
+
+ List<Cmd> cmds = b.Cmds;
+ TransferCmd transferCmd = cce.NonNull(b.TransferCmd);
+ for (int i = 0; i < cmds.Count; i++)
+ {
+ Cmd cmd = cce.NonNull(cmds[i]);
+
+ // Skip if 'cmd' not contained in the trace or not an assert
+ if (cmd is AssertCmd)
+ {
+ bool is_failed_assertion = false;
+ if (NoLabels)
+ is_failed_assertion = true; // we assume only assertions on
+ else
+ is_failed_assertion = CodeLabelTrue(rpfp, root, cmd, info, "@");
+
+ if (is_failed_assertion)
+ {
+ if (continuation_stack.Count == 0)
+ {
+ Counterexample newCounterexample =
+ AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, new Microsoft.Boogie.Model(), info.mvInfo,
+ boogieContext);
+ newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
+ return newCounterexample;
+ }
+ root = continuation_stack.Pop();
+ }
+ continue;
+ }
+
+ // Counterexample generation for inlined procedures
+ AssumeCmd assumeCmd = cmd as AssumeCmd;
+ if (assumeCmd == null)
+ continue;
+ NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
+ if (naryExpr == null)
+ continue;
+ string calleeName = naryExpr.Fun.FunctionName;
+ Contract.Assert(calleeName != null);
+
+ // what is this crap???
+ BinaryOperator binOp = naryExpr.Fun as BinaryOperator;
+ if (binOp != null && binOp.Op == BinaryOperator.Opcode.And)
+ {
+ Expr expr = naryExpr.Args[0];
+ NAryExpr mvStateExpr = expr as NAryExpr;
+ if (mvStateExpr != null && mvStateExpr.Fun.FunctionName == VC.ModelViewInfo.MVState_FunctionDef.Name)
+ {
+ LiteralExpr x = mvStateExpr.Args[1] as LiteralExpr;
+ // Debug.Assert(x != null);
+ int foo = x.asBigNum.ToInt;
+ orderedStateIds.Add(new StateId(root.Outgoing,foo,info));
+ }
+ }
+
+ if (calleeName.EndsWith("_summary"))
+ calleeName = calleeName.Substring(0, calleeName.Length - 8);
+
+ if (!implName2StratifiedInliningInfo.ContainsKey(calleeName) && !calleeName.EndsWith("_summary"))
+ continue;
+
+ {
+ Term code = CodeLabeledExpr(rpfp, root, cmd, info, "+si_fcall_");
+ int pos = TransformerArgPosition(rpfp, root, code);
+ if (pos >= 0)
+ {
+ RPFP.Node callee = root.Outgoing.Children[pos];
+ orderedStateIds.Add(new StateId(callee.Outgoing, CALL,info));
+ calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] =
+ new CalleeCounterexampleInfo(
+ cce.NonNull(GenerateTrace(rpfp, callee, orderedStateIds,
+ implName2StratifiedInliningInfo[calleeName].impl, false)),
+ new List<object>());
+ orderedStateIds.Add(new StateId(root.Outgoing, RETURN,info));
+ }
+ }
+ }
+
+ GotoCmd gotoCmd = transferCmd as GotoCmd;
+ List<Block> cuts = null;
+ if (edgesCut.ContainsKey(b))
+ cuts = edgesCut[b];
+ b = null;
+
+ if (gotoCmd != null)
+ {
+
+ foreach (Block bb in cce.NonNull(gotoCmd.labelTargets))
+ {
+ Contract.Assert(bb != null);
+ if (CodeLabelFalse(rpfp, root, bb, info, "+"))
+ {
+ trace.Add(bb);
+ b = bb;
+ break;
+ }
+ }
+ if (b != null) continue;
+ }
+ // HACK: we have to try edges that were cut in generating the VC
+
+ if (cuts != null)
+ foreach (var bb in cuts)
+ {
+ if (CodeLabelFalse(rpfp, root, bb, info, "+"))
+ {
+ trace.Add(bb);
+ b = bb;
+ break;
+ }
+ }
+ if (b != null) continue;
+
+ return null;
+ }
+
+
+ }
+
+ public override Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
+ {
+ // Construct the set of inlined procs in the original program
+ var inlinedProcs = new HashSet<string>();
+ foreach (var decl in program.TopLevelDeclarations)
+ {
+ // Implementations
+ if (decl is Implementation)
+ {
+ var impl = decl as Implementation;
+ if (!(impl.Proc is LoopProcedure))
+ {
+ inlinedProcs.Add(impl.Name);
+ }
+ }
+
+ // And recording procedures
+ if (decl is Procedure)
+ {
+ var proc = decl as Procedure;
+ if (proc.Name.StartsWith(recordProcName))
+ {
+ // Debug.Assert(!(decl is LoopProcedure));
+ inlinedProcs.Add(proc.Name);
+ }
+ }
+ }
+ return extractLoopTraceRec(
+ new CalleeCounterexampleInfo(cex, new List<object>()),
+ mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample;
+ }
+
+ protected override bool elIsLoop(string procname)
+ {
+ StratifiedInliningInfo info = null;
+ if (implName2StratifiedInliningInfo.ContainsKey(procname))
+ {
+ info = implName2StratifiedInliningInfo[procname];
+ }
+
+ if (info == null) return false;
+
+ var lp = info.impl.Proc as LoopProcedure;
+
+ if (lp == null) return false;
+ return true;
+ }
+
+ private void NumberCexEdges(RPFP.Node node, Dictionary<int,RPFP.Edge> map)
+ {
+ if (node.Outgoing == null)
+ return; // shouldn't happen
+ RPFP.Edge edge = node.Outgoing;
+ map[edge.number] = edge;
+ foreach (var c in edge.Children)
+ NumberCexEdges(c, map);
+ }
+
+ private void GetModelWithStates(Model m, RPFP.Node cex, StratifiedInliningInfo mainInfo,
+ List<StateId> orderedStateIds,
+ Dictionary<int,Dictionary<string,string>> varSubst)
+ {
+ if (m == null) return;
+ var mvInfo = mainInfo.mvInfo;
+
+
+ foreach (Variable v in mvInfo.AllVariables)
+ {
+ m.InitialState.AddBinding(v.Name, GetModelValue(m, v, varSubst[cex.Outgoing.number]));
+ }
+
+ Dictionary<int, RPFP.Edge> edgeNumbering = new Dictionary<int,RPFP.Edge>();
+ NumberCexEdges(cex, edgeNumbering);
+
+ int lastCandidate = 0;
+ int lastCapturePoint = CALL;
+ for (int i = 0; i < orderedStateIds.Count; ++i)
+ {
+ var s = orderedStateIds[i];
+ RPFP.Edge edge = s.edge;
+ int candidate = edge.number;
+ int capturePoint = s.capturePoint;
+ Dictionary<string, string> subst = varSubst[candidate];
+
+ string implName = edge.Parent.Name.GetDeclName();
+ var info = s.info.mvInfo;
+
+ if (capturePoint == CALL || capturePoint == RETURN)
+ {
+ lastCandidate = candidate;
+ lastCapturePoint = capturePoint;
+ continue;
+ }
+
+ Contract.Assume(0 <= capturePoint && capturePoint < info.CapturePoints.Count);
+ VC.ModelViewInfo.Mapping map = info.CapturePoints[capturePoint];
+ var prevInc = (lastCapturePoint != CALL && lastCapturePoint != RETURN && candidate == lastCandidate)
+ ? info.CapturePoints[lastCapturePoint].IncarnationMap : new Dictionary<Variable, Expr>();
+ var cs = m.MkState(map.Description);
+
+ foreach (Variable v in info.AllVariables)
+ {
+ var e = (Expr)map.IncarnationMap[v];
+
+ if (e == null)
+ {
+ if (lastCapturePoint == CALL || lastCapturePoint == RETURN)
+ {
+ cs.AddBinding(v.Name, GetModelValue(m, v, subst));
+ }
+ continue;
+ }
+
+ if (lastCapturePoint != CALL && lastCapturePoint != RETURN && prevInc[v] == e) continue; // skip unchanged variables
+
+ Model.Element elt;
+ if (e is IdentifierExpr)
+ {
+ IdentifierExpr ide = (IdentifierExpr)e;
+ elt = GetModelValue(m, ide.Decl, subst);
+ }
+ else if (e is LiteralExpr)
+ {
+ LiteralExpr lit = (LiteralExpr)e;
+ elt = m.MkElement(lit.Val.ToString());
+ }
+ else
+ {
+ Contract.Assume(false);
+ elt = m.MkFunc(e.ToString(), 0).GetConstant();
+ }
+ cs.AddBinding(v.Name, elt);
+ }
+
+ lastCandidate = candidate;
+ lastCapturePoint = capturePoint;
+ }
+
+ return;
+ }
+
+
+ public readonly static int CALL = -1;
+ public readonly static int RETURN = -2;
+
+ private Model.Element GetModelValue(Model m, Variable v, Dictionary<string,string> subst)
+ {
+ // first, get the unique name
+ string uniqueName;
+
+ VCExprVar vvar = boogieContext.BoogieExprTranslator.TryLookupVariable(v);
+
+ uniqueName = v.Name;
+
+ if(subst.ContainsKey(uniqueName))
+ return m.MkElement(subst[uniqueName]);
+ return m.MkFunc("@undefined", 0).GetConstant();
+ }
+
+ class InternalError : Exception {
+ }
+
+
+ private BinaryOperator.Opcode VCOpToOp (VCExprOp op)
+ {
+ if (op == VCExpressionGenerator.AddIOp)
+ return BinaryOperator.Opcode.Add;
+ if (op == VCExpressionGenerator.SubIOp)
+ return BinaryOperator.Opcode.Sub;
+ if (op == VCExpressionGenerator.MulIOp)
+ return BinaryOperator.Opcode.Mul;
+ if (op == VCExpressionGenerator.DivIOp)
+ return BinaryOperator.Opcode.Div;
+ if (op == VCExpressionGenerator.EqOp)
+ return BinaryOperator.Opcode.Eq;
+ if (op == VCExpressionGenerator.LeOp)
+ return BinaryOperator.Opcode.Le;
+ if (op == VCExpressionGenerator.LtOp)
+ return BinaryOperator.Opcode.Lt;
+ if (op == VCExpressionGenerator.GeOp)
+ return BinaryOperator.Opcode.Ge;
+ if (op == VCExpressionGenerator.GtOp)
+ return BinaryOperator.Opcode.Gt;
+ if (op == VCExpressionGenerator.AndOp)
+ return BinaryOperator.Opcode.And;
+ if (op == VCExpressionGenerator.OrOp)
+ return BinaryOperator.Opcode.Or;
+ throw new InternalError();
+ }
+
+ private Expr MakeBinary (BinaryOperator.Opcode op, List<Expr> args)
+ {
+ if(args.Count == 0){
+ // with zero args we need the identity of the op
+ switch(op){
+ case BinaryOperator.Opcode.And:
+ return Expr.True;
+ case BinaryOperator.Opcode.Or:
+ return Expr.False;
+ case BinaryOperator.Opcode.Add:
+ return new LiteralExpr(Token.NoToken,Microsoft.Basetypes.BigNum.ZERO);
+ default:
+ throw new InternalError();
+ }
+ }
+ var temp = args[0];
+ for(int i = 1; i < args.Count; i++)
+ temp = Expr.Binary(Token.NoToken,op,temp,args[i]);
+ return temp;
+ }
+
+ private Variable MakeVar(VCExprVar v){
+ var foo = new TypedIdent(Token.NoToken,v.Name.ToString(),v.Type);
+ return new BoundVariable(Token.NoToken,foo);
+ }
+
+ private Expr VCExprToExpr (VCExpr e, Dictionary<VCExpr,Expr> bound)
+ {
+ if (e is VCExprVar) {
+ if(bound.ContainsKey(e))
+ return bound[e];
+ return Expr.Ident(MakeVar(e as VCExprVar)); // TODO: this isn't right
+ }
+ if (e is VCExprIntLit) {
+ var n = e as VCExprIntLit;
+ return new LiteralExpr(Token.NoToken,n.Val);
+ }
+ if (e is VCExprNAry) {
+ var f = e as VCExprNAry;
+ var args = new List<Expr>();
+ for(int i = 0; i < f.Arity; i++){
+ args.Add (VCExprToExpr (f[i],bound));
+ }
+
+ if(f.Op == VCExpressionGenerator.NotOp)
+ return Expr.Unary(Token.NoToken, UnaryOperator.Opcode.Not, args[0]);
+
+ if(f.Op == VCExpressionGenerator.IfThenElseOp)
+ return new NAryExpr(Token.NoToken,new IfThenElse(Token.NoToken),args);
+
+ if(f.Op is VCExprSelectOp){
+ var idx = new List<Expr>();
+ idx.Add(args[1]);
+ return Expr.Select(args[0],idx);
+ }
+
+ if(f.Op is VCExprStoreOp){
+ var idx = new List<Expr>();
+ idx.Add(args[1]);
+ return Expr.Store(args[0],idx,args[2]);
+ }
+
+ if (f.Op is VCExprBoogieFunctionOp)
+ {
+ return new NAryExpr(Token.NoToken,
+ new FunctionCall((f.Op as VCExprBoogieFunctionOp).Func), args);
+ }
+
+ var op = VCOpToOp (f.Op);
+ return MakeBinary(op,args);
+ }
+
+ if(e is VCExprQuantifier) {
+ var f = e as VCExprQuantifier;
+ var vs = new List<Variable>();
+ var new_bound = new Dictionary<VCExpr,Expr>(bound);
+ foreach(var v in f.BoundVars){
+ var ve = MakeVar(v);
+ vs.Add(ve);
+ new_bound.Add (v,Expr.Ident (ve));
+ }
+ var bd = VCExprToExpr(f.Body,new_bound);
+ if(f.Quan == Quantifier.EX)
+ return new ExistsExpr(Token.NoToken,vs,bd);
+ else
+ return new ForallExpr(Token.NoToken,vs,bd);
+ }
+ if (e == VCExpressionGenerator.True) {
+ return Expr.True;
+ }
+ if (e == VCExpressionGenerator.False) {
+ return Expr.False;
+ }
+ if (e is VCExprLet) {
+
+ }
+
+ throw new InternalError();
+ }
+
+
+ }
+
+
+}
diff --git a/Source/VCGeneration/OrderingAxioms.cs b/Source/VCGeneration/OrderingAxioms.cs
index dbb97764..9284601f 100644
--- a/Source/VCGeneration/OrderingAxioms.cs
+++ b/Source/VCGeneration/OrderingAxioms.cs
@@ -1,338 +1,338 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using System.Linq;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie.VCExprAST;
-
-// Class for constructing and collecting the axioms of the partial
-// order <:. The class also manages "unique" attributes of constants
-// and generated the necessary assumptions for the theorem prover.
-
-// TODO: there should be an interface so that different ways to handle
-// ordering relations can be accessed uniformly
-
-namespace Microsoft.Boogie {
-
- public class OrderingAxiomBuilder {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Gen != null);
- Contract.Invariant(Translator != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(OneStepFuns));
- Contract.Invariant(cce.NonNullElements(Constants));
- Contract.Invariant(cce.NonNullElements(CompleteConstantsOpen));
- Contract.Invariant(cce.NonNullElements(AllAxioms));
- Contract.Invariant(cce.NonNullElements(IncAxioms));
- }
-
-
- private readonly VCExpressionGenerator Gen;
- private readonly Boogie2VCExprTranslator Translator;
- private readonly IDictionary<Type, Function> OneStepFuns;
- private readonly List<Constant> Constants = new List<Constant>();
-
- // A list to handle constants whose direct children are fully
- // specified (the "complete" keyword). Constants are removed from
- // the list as soon as the corresponding axiom has been generated,
- // which means that from this point on no further children can be
- // added
- private readonly List<Constant> CompleteConstantsOpen = new List<Constant>();
-
- // list in which all axioms are collected
- private readonly List<VCExpr> AllAxioms = new List<VCExpr>();
-
- // list in which axioms are incrementally collected
- private readonly List<VCExpr> IncAxioms = new List<VCExpr>();
-
-
- public OrderingAxiomBuilder(VCExpressionGenerator gen,
- Boogie2VCExprTranslator translator) {
- Contract.Requires(gen != null);
- Contract.Requires(translator != null);
- this.Gen = gen;
- this.Translator = translator;
- OneStepFuns = new Dictionary<Type, Function>();
- Constants = new List<Constant>();
- CompleteConstantsOpen = new List<Constant>();
- AllAxioms = new List<VCExpr>();
- IncAxioms = new List<VCExpr>();
- }
-
- public OrderingAxiomBuilder(VCExpressionGenerator gen,
- Boogie2VCExprTranslator translator,
- OrderingAxiomBuilder builder) {
- Contract.Requires(gen != null);
- Contract.Requires(translator != null);
- Contract.Requires(builder != null);
- this.Gen = gen;
- this.Translator = translator;
- OneStepFuns = new Dictionary<Type, Function>(builder.OneStepFuns);
- Constants = new List<Constant>(builder.Constants);
- CompleteConstantsOpen = new List<Constant>(builder.CompleteConstantsOpen);
- AllAxioms = new List<VCExpr>(builder.AllAxioms);
- IncAxioms = new List<VCExpr>(builder.IncAxioms);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- // Used to axiomatise the disjoint-sub-dag specs that are
- // described by parents with the "unique" flag
-
-
- private Function OneStepFunFor(Type t) {
- Contract.Requires(t != null);
- Contract.Ensures(Contract.Result<Function>() != null);
-
- Function res;
- if (!OneStepFuns.TryGetValue(t, out res)) {
- List<Variable> args = new List<Variable>();
- args.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "arg0", t), true));
- args.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "arg1", t), true));
- Formal result = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "res", t), false);
- res = new Function(Token.NoToken, "oneStep", new List<TypeVariable>(), args, result);
- OneStepFuns.Add(t, res);
- }
- return cce.NonNull(res);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
-
- private void AddAxiom(VCExpr axiom) {
- Contract.Requires(axiom != null);
- if (axiom.Equals(VCExpressionGenerator.True))
- return;
- AllAxioms.Add(axiom);
- IncAxioms.Add(axiom);
- }
-
- // Return all axioms that were added since the last time NewAxioms
- // was called
- public VCExpr GetNewAxioms() {
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- CloseChildrenCompleteConstants();
- VCExpr res = Gen.NAry(VCExpressionGenerator.AndOp, IncAxioms);
- IncAxioms.Clear();
- return res;
- }
-
- // return all axioms
- public VCExpr Axioms {
- get {
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- CloseChildrenCompleteConstants();
- return Gen.NAry(VCExpressionGenerator.AndOp, AllAxioms);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- // Generate the normal axioms for a partial order relation
- public void Setup() {
- TypeVariable alpha = new TypeVariable(Token.NoToken, "alpha");
- Contract.Assert(alpha != null);
- List<TypeVariable> typeParams = new List<TypeVariable>();
- typeParams.Add(alpha);
-
- List<VCTrigger> triggers = new List<VCTrigger>();
-
- VCExprVar x = Gen.Variable("x", alpha);
- Contract.Assert(x != null);
- VCExprVar y = Gen.Variable("y", alpha);
- Contract.Assert(y != null);
- VCExprVar z = Gen.Variable("z", alpha);
- Contract.Assert(z != null);
-
- List<VCExprVar> boundVars = new List<VCExprVar>();
-
- // reflexivity
- boundVars.Add(x);
- AddAxiom(Gen.Forall(typeParams, boundVars, triggers,
- new VCQuantifierInfos("bg:subtype-refl", -1, false, null),
- Gen.AtMost(x, x)));
-
- // transitivity
- boundVars = new List<VCExprVar>();
- boundVars.Add(x);
- boundVars.Add(y);
- boundVars.Add(z);
- triggers = new List<VCTrigger>();
- triggers.Add(Gen.Trigger(true, Gen.AtMost(x, y), Gen.AtMost(y, z)));
- VCExpr body = Gen.Implies(Gen.And(Gen.AtMost(x, y), Gen.AtMost(y, z)),
- Gen.AtMost(x, z));
- Contract.Assert(body != null);
- AddAxiom(Gen.Forall(typeParams, boundVars, triggers,
- new VCQuantifierInfos("bg:subtype-trans", -1, false, null),
- body));
-
- // anti-symmetry
- boundVars = new List<VCExprVar>();
- boundVars.Add(x);
- boundVars.Add(y);
- triggers = new List<VCTrigger>();
- triggers.Add(Gen.Trigger(true, Gen.AtMost(x, y), Gen.AtMost(y, x)));
- body = Gen.Implies(Gen.And(Gen.AtMost(x, y), Gen.AtMost(y, x)),
- Gen.Eq(x, y));
- AddAxiom(Gen.Forall(typeParams, boundVars, triggers,
- new VCQuantifierInfos("bg:subtype-antisymm", -1, false, null),
- body));
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- public void AddConstant(Constant c) {
- Contract.Requires(c != null);
- AddAxiom(GenParentConstraints(c));
- Constants.Add(c);
- if (c.ChildrenComplete)
- CompleteConstantsOpen.Add(c);
-
- // ensure that no further children are added to closed
- // children-complete constants
- Contract.Assert(!(c.Parents != null && Contract.Exists(c.Parents, p => cce.NonNull((Constant)p.Parent.Decl).ChildrenComplete && !CompleteConstantsOpen.Contains((Constant)p.Parent.Decl))));
- }
-
- // Generate the constraints telling that parents of a constant are
- // strictly greater than the constant itself, and are the minimal
- // elements with this property
- private VCExpr GenParentConstraints(Constant c) {
- Contract.Requires(c != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr res = VCExpressionGenerator.True;
-
- if (c.Parents == null)
- return res;
-
- VCExprVar cAsVar = Translator.LookupVariable(c);
- VCExprVar w = Gen.Variable("w", c.TypedIdent.Type);
-
- // Parents of c are proper ancestors of c
- foreach (ConstantParent p in c.Parents) {
- Contract.Assert(p != null);
- VCExprVar par = Translator.LookupVariable(cce.NonNull(p.Parent.Decl));
- res = Gen.AndSimp(res, Gen.Neq(cAsVar, par));
- res = Gen.AndSimp(res, Gen.AtMost(cAsVar, par));
- }
-
- // Parents are direct ancestors of c (no other elements are in
- // between c and a parent)
- foreach (ConstantParent p in c.Parents) {
- Contract.Assert(p != null);
- VCExprVar par = Translator.LookupVariable(cce.NonNull(p.Parent.Decl));
- Contract.Assert(par != null);
- VCExpr antecedent1 = Gen.AtMost(cAsVar, w);
- Contract.Assert(antecedent1 != null);
- VCExpr antecedent2 = Gen.AtMost(w, par);
- Contract.Assert(antecedent2 != null);
- VCExpr body = Gen.Implies(Gen.And(antecedent1, antecedent2),
- Gen.Or(Gen.Eq(cAsVar, w), Gen.Eq(par, w)));
- Contract.Assert(body != null);
- res = Gen.AndSimp(res,
- Gen.Forall(w,
- Gen.Trigger(true, antecedent1, antecedent2),
- body));
- }
-
- // Ancestors of c are only c itself and the ancestors of the
- // parents of c
- VCExpr minAncestors = Gen.Eq(cAsVar, w);
- Contract.Assert(minAncestors != null);
- foreach (ConstantParent p in c.Parents) {
- Contract.Assert(p != null);
- minAncestors =
- Gen.Or(minAncestors,
- Gen.AtMost(Translator.LookupVariable(cce.NonNull(p.Parent.Decl)), w));
- }
- VCExpr antecedent = Gen.AtMost(cAsVar, w);
- Contract.Assert(antecedent != null);
- res = Gen.AndSimp(res,
- Gen.Forall(w,
- Gen.Trigger(true, antecedent),
- Gen.Implies(antecedent, minAncestors)));
-
- // Constraints for unique child-parent edges
- foreach (ConstantParent p in c.Parents) {
- Contract.Assert(p != null);
- if (p.Unique)
- res =
- Gen.AndSimp(res,
- GenUniqueParentConstraint(c, cce.NonNull((Constant)p.Parent.Decl)));
- }
-
- return res;
- }
-
- // Generate axioms that state that all direct children of c are
- // specified; this is the dual of the axiom stating that all direct
- // ancestors of a constant are known
- private VCExpr GenCompleteChildrenConstraints(Constant c) {
- Contract.Requires(c != null);
- Contract.Requires(c.ChildrenComplete);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
-
- VCExprVar cAsVar = Translator.LookupVariable(c);
- VCExprVar w = Gen.Variable("w", c.TypedIdent.Type);
-
- VCExpr maxDescendants = Gen.Eq(cAsVar, w);
- foreach (Constant d in Constants) {
- Contract.Assert(d != null);
- if (d.Parents != null && d.Parents.Any(p => c.Equals(p.Parent.Decl)))
- maxDescendants = Gen.Or(maxDescendants,
- Gen.AtMost(w, Translator.LookupVariable(d)));
- }
-
- VCExpr antecedent = Gen.AtMost(w, cAsVar);
- Contract.Assert(antecedent != null);
- return Gen.Forall(w,
- Gen.Trigger(true, antecedent),
- Gen.Implies(antecedent, maxDescendants));
- }
-
- private void CloseChildrenCompleteConstants() {
- foreach (Constant c in CompleteConstantsOpen) {
- Contract.Assert(c != null);
- AddAxiom(GenCompleteChildrenConstraints(c));
- }
- CompleteConstantsOpen.Clear();
- }
-
- // Generate the axiom ensuring that the sub-dags underneath unique
- // child-parent edges are all disjoint
- private VCExpr GenUniqueParentConstraint(Constant child, Constant parent) {
- Contract.Requires(child != null);
- Contract.Requires(parent != null);
- Contract.Requires(child.TypedIdent.Type.Equals(parent.TypedIdent.Type));
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
-
-
- VCExprVar w = Gen.Variable("w", child.TypedIdent.Type);
- Contract.Assert(w != null);
- VCExpr antecedent =
- Gen.AtMost(w, Translator.LookupVariable(child));
- Contract.Assert(antecedent != null);
- VCExpr succedent =
- Gen.Eq(Gen.Function(OneStepFunFor(child.TypedIdent.Type),
- Translator.LookupVariable(parent), w),
- Translator.LookupVariable(child));
- Contract.Assert(succedent != null);
-
- return Gen.Forall(w,
- Gen.Trigger(true, antecedent),
- Gen.Implies(antecedent, succedent));
- }
-
- }
-
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Linq;
+using System.Diagnostics.Contracts;
+using Microsoft.Boogie.VCExprAST;
+
+// Class for constructing and collecting the axioms of the partial
+// order <:. The class also manages "unique" attributes of constants
+// and generated the necessary assumptions for the theorem prover.
+
+// TODO: there should be an interface so that different ways to handle
+// ordering relations can be accessed uniformly
+
+namespace Microsoft.Boogie {
+
+ public class OrderingAxiomBuilder {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Gen != null);
+ Contract.Invariant(Translator != null);
+ Contract.Invariant(cce.NonNullDictionaryAndValues(OneStepFuns));
+ Contract.Invariant(cce.NonNullElements(Constants));
+ Contract.Invariant(cce.NonNullElements(CompleteConstantsOpen));
+ Contract.Invariant(cce.NonNullElements(AllAxioms));
+ Contract.Invariant(cce.NonNullElements(IncAxioms));
+ }
+
+
+ private readonly VCExpressionGenerator Gen;
+ private readonly Boogie2VCExprTranslator Translator;
+ private readonly IDictionary<Type, Function> OneStepFuns;
+ private readonly List<Constant> Constants = new List<Constant>();
+
+ // A list to handle constants whose direct children are fully
+ // specified (the "complete" keyword). Constants are removed from
+ // the list as soon as the corresponding axiom has been generated,
+ // which means that from this point on no further children can be
+ // added
+ private readonly List<Constant> CompleteConstantsOpen = new List<Constant>();
+
+ // list in which all axioms are collected
+ private readonly List<VCExpr> AllAxioms = new List<VCExpr>();
+
+ // list in which axioms are incrementally collected
+ private readonly List<VCExpr> IncAxioms = new List<VCExpr>();
+
+
+ public OrderingAxiomBuilder(VCExpressionGenerator gen,
+ Boogie2VCExprTranslator translator) {
+ Contract.Requires(gen != null);
+ Contract.Requires(translator != null);
+ this.Gen = gen;
+ this.Translator = translator;
+ OneStepFuns = new Dictionary<Type, Function>();
+ Constants = new List<Constant>();
+ CompleteConstantsOpen = new List<Constant>();
+ AllAxioms = new List<VCExpr>();
+ IncAxioms = new List<VCExpr>();
+ }
+
+ public OrderingAxiomBuilder(VCExpressionGenerator gen,
+ Boogie2VCExprTranslator translator,
+ OrderingAxiomBuilder builder) {
+ Contract.Requires(gen != null);
+ Contract.Requires(translator != null);
+ Contract.Requires(builder != null);
+ this.Gen = gen;
+ this.Translator = translator;
+ OneStepFuns = new Dictionary<Type, Function>(builder.OneStepFuns);
+ Constants = new List<Constant>(builder.Constants);
+ CompleteConstantsOpen = new List<Constant>(builder.CompleteConstantsOpen);
+ AllAxioms = new List<VCExpr>(builder.AllAxioms);
+ IncAxioms = new List<VCExpr>(builder.IncAxioms);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ // Used to axiomatise the disjoint-sub-dag specs that are
+ // described by parents with the "unique" flag
+
+
+ private Function OneStepFunFor(Type t) {
+ Contract.Requires(t != null);
+ Contract.Ensures(Contract.Result<Function>() != null);
+
+ Function res;
+ if (!OneStepFuns.TryGetValue(t, out res)) {
+ List<Variable> args = new List<Variable>();
+ args.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "arg0", t), true));
+ args.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "arg1", t), true));
+ Formal result = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "res", t), false);
+ res = new Function(Token.NoToken, "oneStep", new List<TypeVariable>(), args, result);
+ OneStepFuns.Add(t, res);
+ }
+ return cce.NonNull(res);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+
+ private void AddAxiom(VCExpr axiom) {
+ Contract.Requires(axiom != null);
+ if (axiom.Equals(VCExpressionGenerator.True))
+ return;
+ AllAxioms.Add(axiom);
+ IncAxioms.Add(axiom);
+ }
+
+ // Return all axioms that were added since the last time NewAxioms
+ // was called
+ public VCExpr GetNewAxioms() {
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ CloseChildrenCompleteConstants();
+ VCExpr res = Gen.NAry(VCExpressionGenerator.AndOp, IncAxioms);
+ IncAxioms.Clear();
+ return res;
+ }
+
+ // return all axioms
+ public VCExpr Axioms {
+ get {
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ CloseChildrenCompleteConstants();
+ return Gen.NAry(VCExpressionGenerator.AndOp, AllAxioms);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ // Generate the normal axioms for a partial order relation
+ public void Setup() {
+ TypeVariable alpha = new TypeVariable(Token.NoToken, "alpha");
+ Contract.Assert(alpha != null);
+ List<TypeVariable> typeParams = new List<TypeVariable>();
+ typeParams.Add(alpha);
+
+ List<VCTrigger> triggers = new List<VCTrigger>();
+
+ VCExprVar x = Gen.Variable("x", alpha);
+ Contract.Assert(x != null);
+ VCExprVar y = Gen.Variable("y", alpha);
+ Contract.Assert(y != null);
+ VCExprVar z = Gen.Variable("z", alpha);
+ Contract.Assert(z != null);
+
+ List<VCExprVar> boundVars = new List<VCExprVar>();
+
+ // reflexivity
+ boundVars.Add(x);
+ AddAxiom(Gen.Forall(typeParams, boundVars, triggers,
+ new VCQuantifierInfos("bg:subtype-refl", -1, false, null),
+ Gen.AtMost(x, x)));
+
+ // transitivity
+ boundVars = new List<VCExprVar>();
+ boundVars.Add(x);
+ boundVars.Add(y);
+ boundVars.Add(z);
+ triggers = new List<VCTrigger>();
+ triggers.Add(Gen.Trigger(true, Gen.AtMost(x, y), Gen.AtMost(y, z)));
+ VCExpr body = Gen.Implies(Gen.And(Gen.AtMost(x, y), Gen.AtMost(y, z)),
+ Gen.AtMost(x, z));
+ Contract.Assert(body != null);
+ AddAxiom(Gen.Forall(typeParams, boundVars, triggers,
+ new VCQuantifierInfos("bg:subtype-trans", -1, false, null),
+ body));
+
+ // anti-symmetry
+ boundVars = new List<VCExprVar>();
+ boundVars.Add(x);
+ boundVars.Add(y);
+ triggers = new List<VCTrigger>();
+ triggers.Add(Gen.Trigger(true, Gen.AtMost(x, y), Gen.AtMost(y, x)));
+ body = Gen.Implies(Gen.And(Gen.AtMost(x, y), Gen.AtMost(y, x)),
+ Gen.Eq(x, y));
+ AddAxiom(Gen.Forall(typeParams, boundVars, triggers,
+ new VCQuantifierInfos("bg:subtype-antisymm", -1, false, null),
+ body));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ public void AddConstant(Constant c) {
+ Contract.Requires(c != null);
+ AddAxiom(GenParentConstraints(c));
+ Constants.Add(c);
+ if (c.ChildrenComplete)
+ CompleteConstantsOpen.Add(c);
+
+ // ensure that no further children are added to closed
+ // children-complete constants
+ Contract.Assert(!(c.Parents != null && Contract.Exists(c.Parents, p => cce.NonNull((Constant)p.Parent.Decl).ChildrenComplete && !CompleteConstantsOpen.Contains((Constant)p.Parent.Decl))));
+ }
+
+ // Generate the constraints telling that parents of a constant are
+ // strictly greater than the constant itself, and are the minimal
+ // elements with this property
+ private VCExpr GenParentConstraints(Constant c) {
+ Contract.Requires(c != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ VCExpr res = VCExpressionGenerator.True;
+
+ if (c.Parents == null)
+ return res;
+
+ VCExprVar cAsVar = Translator.LookupVariable(c);
+ VCExprVar w = Gen.Variable("w", c.TypedIdent.Type);
+
+ // Parents of c are proper ancestors of c
+ foreach (ConstantParent p in c.Parents) {
+ Contract.Assert(p != null);
+ VCExprVar par = Translator.LookupVariable(cce.NonNull(p.Parent.Decl));
+ res = Gen.AndSimp(res, Gen.Neq(cAsVar, par));
+ res = Gen.AndSimp(res, Gen.AtMost(cAsVar, par));
+ }
+
+ // Parents are direct ancestors of c (no other elements are in
+ // between c and a parent)
+ foreach (ConstantParent p in c.Parents) {
+ Contract.Assert(p != null);
+ VCExprVar par = Translator.LookupVariable(cce.NonNull(p.Parent.Decl));
+ Contract.Assert(par != null);
+ VCExpr antecedent1 = Gen.AtMost(cAsVar, w);
+ Contract.Assert(antecedent1 != null);
+ VCExpr antecedent2 = Gen.AtMost(w, par);
+ Contract.Assert(antecedent2 != null);
+ VCExpr body = Gen.Implies(Gen.And(antecedent1, antecedent2),
+ Gen.Or(Gen.Eq(cAsVar, w), Gen.Eq(par, w)));
+ Contract.Assert(body != null);
+ res = Gen.AndSimp(res,
+ Gen.Forall(w,
+ Gen.Trigger(true, antecedent1, antecedent2),
+ body));
+ }
+
+ // Ancestors of c are only c itself and the ancestors of the
+ // parents of c
+ VCExpr minAncestors = Gen.Eq(cAsVar, w);
+ Contract.Assert(minAncestors != null);
+ foreach (ConstantParent p in c.Parents) {
+ Contract.Assert(p != null);
+ minAncestors =
+ Gen.Or(minAncestors,
+ Gen.AtMost(Translator.LookupVariable(cce.NonNull(p.Parent.Decl)), w));
+ }
+ VCExpr antecedent = Gen.AtMost(cAsVar, w);
+ Contract.Assert(antecedent != null);
+ res = Gen.AndSimp(res,
+ Gen.Forall(w,
+ Gen.Trigger(true, antecedent),
+ Gen.Implies(antecedent, minAncestors)));
+
+ // Constraints for unique child-parent edges
+ foreach (ConstantParent p in c.Parents) {
+ Contract.Assert(p != null);
+ if (p.Unique)
+ res =
+ Gen.AndSimp(res,
+ GenUniqueParentConstraint(c, cce.NonNull((Constant)p.Parent.Decl)));
+ }
+
+ return res;
+ }
+
+ // Generate axioms that state that all direct children of c are
+ // specified; this is the dual of the axiom stating that all direct
+ // ancestors of a constant are known
+ private VCExpr GenCompleteChildrenConstraints(Constant c) {
+ Contract.Requires(c != null);
+ Contract.Requires(c.ChildrenComplete);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+
+ VCExprVar cAsVar = Translator.LookupVariable(c);
+ VCExprVar w = Gen.Variable("w", c.TypedIdent.Type);
+
+ VCExpr maxDescendants = Gen.Eq(cAsVar, w);
+ foreach (Constant d in Constants) {
+ Contract.Assert(d != null);
+ if (d.Parents != null && d.Parents.Any(p => c.Equals(p.Parent.Decl)))
+ maxDescendants = Gen.Or(maxDescendants,
+ Gen.AtMost(w, Translator.LookupVariable(d)));
+ }
+
+ VCExpr antecedent = Gen.AtMost(w, cAsVar);
+ Contract.Assert(antecedent != null);
+ return Gen.Forall(w,
+ Gen.Trigger(true, antecedent),
+ Gen.Implies(antecedent, maxDescendants));
+ }
+
+ private void CloseChildrenCompleteConstants() {
+ foreach (Constant c in CompleteConstantsOpen) {
+ Contract.Assert(c != null);
+ AddAxiom(GenCompleteChildrenConstraints(c));
+ }
+ CompleteConstantsOpen.Clear();
+ }
+
+ // Generate the axiom ensuring that the sub-dags underneath unique
+ // child-parent edges are all disjoint
+ private VCExpr GenUniqueParentConstraint(Constant child, Constant parent) {
+ Contract.Requires(child != null);
+ Contract.Requires(parent != null);
+ Contract.Requires(child.TypedIdent.Type.Equals(parent.TypedIdent.Type));
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+
+
+ VCExprVar w = Gen.Variable("w", child.TypedIdent.Type);
+ Contract.Assert(w != null);
+ VCExpr antecedent =
+ Gen.AtMost(w, Translator.LookupVariable(child));
+ Contract.Assert(antecedent != null);
+ VCExpr succedent =
+ Gen.Eq(Gen.Function(OneStepFunFor(child.TypedIdent.Type),
+ Translator.LookupVariable(parent), w),
+ Translator.LookupVariable(child));
+ Contract.Assert(succedent != null);
+
+ return Gen.Forall(w,
+ Gen.Trigger(true, antecedent),
+ Gen.Implies(antecedent, succedent));
+ }
+
+ }
+
+}
diff --git a/Source/VCGeneration/RPFP.cs b/Source/VCGeneration/RPFP.cs
index ed3842d5..9d38eb47 100644
--- a/Source/VCGeneration/RPFP.cs
+++ b/Source/VCGeneration/RPFP.cs
@@ -1,609 +1,609 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using Term = Microsoft.Boogie.VCExprAST.VCExpr;
-using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp;
-using Sort = Microsoft.Boogie.Type;
-using Microsoft.Boogie.VCExprAST;
-
-
-using Microsoft.Boogie.ExprExtensions;
-
-
-namespace Microsoft.Boogie
-{
-
-
-
-
- /** This class represents a relation post-fixed point (RPFP) problem as
- * a "problem graph". The graph consists of Nodes and hyper-edges.
- *
- * A node consists of
- * - Annotation, a symbolic relation
- * - Bound, a symbolic relation giving an upper bound on Annotation
- *
- *
- * A hyper-edge consists of:
- * - Children, a sequence of children Nodes,
- * - F, a symbolic relational transformer,
- * - Parent, a single parent Node.
- *
- * The graph is "solved" when:
- * - For every Node n, n.Annotation subseteq n.Bound
- * - For every hyperedge e, e.F(e.Children.Annotation) subseteq e.Parent.Annotation
- *
- * where, if x is a sequence of Nodes, x.Annotation is the sequences
- * of Annotations of the nodes in the sequence.
- *
- * A symbolic Transformer consists of
- * - RelParams, a sequence of relational symbols
- * - IndParams, a sequence of individual symbols
- * - Formula, a formula over RelParams and IndParams
- *
- * A Transformer t represents a function that takes sequence R of relations
- * and yields the relation lambda (t.Indparams). Formula(R/RelParams).
- *
- * As a special case, a nullary Transformer (where RelParams is the empty sequence)
- * represents a fixed relation.
- *
- * An RPFP consists of
- * - Nodes, a set of Nodes
- * - Edges, a set of hyper-edges
- * - Context, a prover context that contains formula AST's
- *
- * Multiple RPFP's can use the same Context, but you should be careful
- * that only one RPFP asserts constraints in the context at any time.
- *
- * */
- public class RPFP
- {
- /** Symbolic representation of a relational transformer */
- public class Transformer
- {
- public FuncDecl[] RelParams;
- public Term[] IndParams;
- public Term Formula;
- public RPFP owner;
-
- public Transformer Clone()
- {
- return (Transformer)this.MemberwiseClone();
- }
- }
-
- /** Create a symbolic transformer. */
- public Transformer CreateTransformer(FuncDecl[] _RelParams, Term[] _IndParams, Term _Formula)
- {
- Transformer t = new Transformer();
- t.RelParams = _RelParams;
- t.IndParams = _IndParams;
- t.Formula = _Formula;
- t.owner = this;
- return t;
- }
-
- /** Create a relation (nullary relational transformer) */
- public Transformer CreateRelation(Term[] _IndParams, Term _Formula)
- {
- return CreateTransformer(new FuncDecl[0], _IndParams, _Formula);
- }
-
- /** A node in the RPFP graph */
- public class Node
- {
- public FuncDecl Name;
- public Transformer Annotation;
- public Transformer Bound;
- public RPFP owner;
- public int number;
- public Edge Outgoing;
- public List<Edge> Incoming;
- public Term dual;
- public Node map;
- }
-
- /** Create a node in the graph. The input is a term R(v_1...v_n)
- * where R is an arbitrary relational symbol and v_1...v_n are
- * arbitary distinct variables. The names are only of mnemonic value,
- * however, the number and type of arguments determine the type
- * of the relation at this node. */
-
- public Node CreateNode(Term t)
- {
- Node n = new Node();
- // Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry;
- // Term[] _IndParams = tn.ToArray();
- Term[] _IndParams = t.GetAppArgs();
- FuncDecl Name = t.GetAppDecl();
- n.Annotation = CreateRelation(_IndParams,ctx.MkTrue());
- n.Bound = CreateRelation(_IndParams, ctx.MkTrue());
- n.owner = this;
- n.number = ++nodeCount;
- n.Name = Name; // just to have a unique name
- n.Incoming = new List<Edge>();
- return n;
- }
-
- /** Clone a node (can be from another graph). */
-
- public Node CloneNode(Node old)
- {
- Node n = new Node();
- n.Annotation = old.Annotation.Clone();
- n.Bound = old.Bound.Clone();
- n.owner = this;
- n.number = ++nodeCount;
- n.Name = old.Name; // just to have a unique name
- n.Incoming = new List<Edge>();
- return n;
- }
-
- /** This class represents a hyper-edge in the RPFP graph */
-
- public class Edge
- {
- public Transformer F;
- public Node Parent;
- public Node[] Children;
- public RPFP owner;
- public int number;
- public Edge map;
- public HashSet<string> labels;
- internal Term dual;
- internal TermDict<Term> valuation;
- }
-
-
- /** Create a hyper-edge. */
- public Edge CreateEdge(Node _Parent, Transformer _F, Node[] _Children)
- {
- Edge e = new Edge();
- e.Parent = _Parent;
- e.F = _F;
- e.Children = _Children;
- e.owner = this;
- e.number = ++edgeCount;
- _Parent.Outgoing = e;
- foreach (var c in _Children)
- if(c != null)
- c.Incoming.Add(e);
- return e;
- }
-
- /** Create an edge that lower-bounds its parent. */
- public Edge CreateLowerBoundEdge(Node _Parent)
- {
- return CreateEdge(_Parent, _Parent.Annotation, new RPFP.Node[0]);
- }
-
-
-
-
- /** Assert a background axiom. Background axioms can be used to provide the
- * theory of auxilliary functions or relations. All symbols appearing in
- * background axioms are considered global, and may appear in both transformer
- * and relational solutions. Semantically, a solution to the RPFP gives
- * an interpretation of the unknown relations for each interpretation of the
- * auxilliary symbols that is consistent with the axioms. Axioms should be
- * asserted before any calls to Push. They cannot be de-asserted by Pop. */
-
- public void AssertAxiom(Term t)
- {
- ctx.AddAxiom(t);
- }
-
- /** Do not call this. */
-
- public void RemoveAxiom(Term t)
- {
- ctx.RemoveAxiom(t);
- }
-
- /** Type of solve results */
- public enum LBool { False, True, Undef };
-
-
- /** Solve an RPFP graph. This means either strengthen the annotation
- * so that the bound at the given root node is satisfied, or
- * show that this cannot be done by giving a dual solution
- * (i.e., a counterexample).
- *
- * In the current implementation, this only works for graphs that
- * are:
- * - tree-like
- *
- * - closed.
- *
- * In a tree-like graph, every nod has out most one incoming and one out-going edge,
- * and there are no cycles. In a closed graph, every node has exactly one out-going
- * edge. This means that the leaves of the tree are all hyper-edges with no
- * children. Such an edge represents a relation (nullary transformer) and thus
- * a lower bound on its parent. The parameter root must be the root of this tree.
- *
- * If Solve returns LBool.False, this indicates success. The annotation of the tree
- * has been updated to satisfy the upper bound at the root.
- *
- * If Solve returns LBool.True, this indicates a counterexample. For each edge,
- * you can then call Eval to determine the values of symbols in the transformer formula.
- * You can also call Empty on a node to determine if its value in the counterexample
- * is the empty relation.
- *
- * \param root The root of the tree
- * \param persist Number of context pops through which result should persist
- *
- *
- */
-
- public LBool Solve(Node root, int persist)
- {
- return LBool.False; // TODO
- }
-
-
- /** Dispose of the dual model (counterexample) if there is one. */
-
- public void DisposeDualModel()
- {
- // TODO dualModel = null;
- }
-
-
- /** Determines the value in the counterexample of a symbol occuring in the transformer formula of
- * a given edge. */
-
- public Term Eval(Edge e, Term t)
- {
- if (e.valuation == null)
- e.valuation = new TermDict< Term>();
- if (e.valuation.ContainsKey(t))
- return e.valuation[t];
- return null; // TODO
- }
-
- /** Sets the value in the counterexample of a symbol occuring in the transformer formula of
- * a given edge. */
-
- public void SetValue(Edge e, Term variable, Term value)
- {
- if (e.valuation == null)
- e.valuation = new TermDict< Term>();
- e.valuation.Add(variable, value);
- }
-
-
- /** Returns true if the given node is empty in the primal solution. For proecudure summaries,
- this means that the procedure is not called in the current counter-model. */
-
- public bool Empty(Node p)
- {
- return false; // TODO
- }
-
- /** Push a scope. Assertions made after Push can be undone by Pop. */
-
- public void Push()
- {
- stack.Push(new stack_entry());
- // TODO: do we need push/pop?
- }
-
- /** Pop a scope (see Push). Note, you cannot pop axioms. */
-
- public void Pop(int num_scopes)
- {
- //TODO ctx.Pop((uint)num_scopes);
- for (uint i = 0; i < num_scopes; i++)
- {
- stack_entry back = stack.Pop();
- foreach (var e in back.edges)
- e.dual = null;
- foreach (var n in back.nodes)
- n.dual = null;
- }
- }
-
- public Context ctx;
-
- public class LogicSolver {
- public Context ctx;
- };
-
- public LogicSolver solver;
-
- static public LogicSolver CreateLogicSolver(Context _ctx){
- LogicSolver res = new LogicSolver();
- res.ctx = _ctx;
- return res;
- }
-
- /** This represents a conjecture that a given node is upper-boudned
- by bound. */
- public class Conjecture
- {
- public Node node;
- public Transformer bound;
- }
-
- /** This is a list of conjectures generated during solving. */
-
- public List<Conjecture> conjectures = new List<Conjecture>();
-
- /** Construct an RPFP graph with a given interpolating prover context. It is allowed to
- have multiple RPFP's use the same context, but you should never have teo RPFP's
- with the same conext asserting nodes or edges at the same time. Note, if you create
- axioms in one RPFP, them create a second RPFP with the same context, the second will
- inherit the axioms.
- */
-
- public RPFP(LogicSolver slvr)
- {
- solver = slvr;
- ctx = slvr.ctx;
- stack = new Stack<stack_entry>();
- stack.Push(new stack_entry());
- }
-
-
- /** Convert an array of clauses to an RPFP.
- */
-
- public void FromClauses(Term[] clauses){
- FuncDecl failName = ctx.MkFuncDecl("@Fail", ctx.MkBoolSort());
- foreach(var clause in clauses){
- Node foo = GetNodeFromClause(clause,failName);
- if(foo != null)
- nodes.Add(foo);
- }
- foreach (var clause in clauses)
- edges.Add(GetEdgeFromClause(clause,failName));
- }
-
-
- // This returns a new FuncDel with same sort as top-level function
- // of term t, but with numeric suffix appended to name.
-
- private FuncDecl SuffixFuncDecl(Term t, int n)
- {
- var name = t.GetAppDecl().GetDeclName() + "_" + n.ToString();
- return ctx.MkFuncDecl(name, t.GetAppDecl());
- }
-
- // Collect the relational paremeters
-
- Dictionary<FuncDecl, Node> relationToNode = new Dictionary<FuncDecl, Node>();
-
- private Term CollectParamsRec(TermDict<Term> memo, Term t, List<FuncDecl> parms, List<RPFP.Node> nodes, Dictionary<Term, Term> done)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- if (t.GetKind() == TermKind.App)
- {
- var f = t.GetAppDecl();
- Node node;
- if (relationToNode.TryGetValue(f, out node))
- {
- if (done.ContainsKey(t))
- res = done[t];
- else
- {
- f = SuffixFuncDecl(t, parms.Count);
- parms.Add(f);
- nodes.Add(node);
- done.Add(t,res); // don't count same expression twice!
- }
- }
- var args = t.GetAppArgs();
- args = args.Select(x => CollectParamsRec(memo, x, parms, nodes, done)).ToArray();
- res = ctx.CloneApp(t, args);
- } // TODO: handle quantifiers
- else
- res = t;
- memo.Add(t, res);
- return res;
- }
-
- private bool IsVariable(Term t)
- {
- // TODO: is this right?
- // return t.IsFunctionApp() && t.GetAppArgs().Length == 0;
- return t is VCExprVar && !(t is VCExprConstant);
- }
-
- private Edge GetEdgeFromClause(Term t, FuncDecl failName)
- {
- Term[] args = t.GetAppArgs();
- Term body = args[0];
- Term head = args[1];
- Term[] _IndParams;
- FuncDecl Name;
- if (head.IsFalse())
- {
- Name = failName;
- _IndParams = new Term[0];
- }
- else
- {
- _IndParams = head.GetAppArgs();
- Name = head.GetAppDecl();
- }
- for(int i = 0; i < _IndParams.Length; i++)
- if (!IsVariable(_IndParams[i]))
- {
- Term v = ctx.MkConst("@a" + i.ToString(), _IndParams[i].GetSort());
- body = ctx.MkAnd(body, ctx.MkEq(v, _IndParams[i]));
- _IndParams[i] = v;
- }
- var relParams = new List<FuncDecl>();
- var nodeParams = new List<RPFP.Node>();
- var memo = new TermDict< Term>();
- var done = new Dictionary<Term, Term>(); // note this hashes on equality, not reference!
- body = CollectParamsRec(memo, body, relParams, nodeParams,done);
- Transformer F = CreateTransformer(relParams.ToArray(), _IndParams, body);
- Node parent = relationToNode[Name];
- return CreateEdge(parent, F, nodeParams.ToArray());
- }
-
- private Node GetNodeFromClause(Term t, FuncDecl failName)
- {
- Term[] args = t.GetAppArgs();
- Term body = args[0];
- Term head = args[1];
- FuncDecl Name;
- Term[] _IndParams;
- bool is_query = false;
- if (head.Equals(ctx.MkFalse()))
- {
- Name = failName;
- is_query = true;
- _IndParams = new Term[0];
- }
- else
- {
- Name = head.GetAppDecl();
- _IndParams = head.GetAppArgs();
- }
- if (relationToNode.ContainsKey(Name))
- return null;
- for (int i = 0; i < _IndParams.Length; i++)
- if (!IsVariable(_IndParams[i]))
- {
- Term v = ctx.MkConst("@a" + i.ToString(), _IndParams[i].GetSort());
- _IndParams[i] = v;
- }
- Term foo = ctx.MkApp(Name, _IndParams);
- Node node = CreateNode(foo);
- relationToNode[Name] = node;
- if (is_query)
- node.Bound = CreateRelation(new Term[0], ctx.MkFalse());
- return node;
- }
-
- /////////////////////////////////////////////////////////////////////////////////////////
- // Convert RPFP to Z3 rules
- /////////////////////////////////////////////////////////////////////////////////////////
-
- /** Get the Z3 rule corresponding to an edge */
-
- public Term GetRule(Edge edge)
- {
- Dictionary<FuncDecl, FuncDecl> predSubst = new Dictionary<FuncDecl, FuncDecl>();
- for (int i = 0; i < edge.Children.Length; i++)
- predSubst.Add(edge.F.RelParams[i], edge.Children[i].Name);
- Term body = SubstPreds(predSubst, edge.F.Formula);
- Term head = ctx.MkApp(edge.Parent.Name, edge.F.IndParams);
- var rule = BindVariables(ctx.MkImplies(body, head));
- rule = ctx.Letify(rule); // put in let bindings for theorem prover
- return rule;
- }
-
- /** Get the Z3 query corresponding to the conjunction of the node bounds. */
-
- public Term GetQuery()
- {
- List<Term> conjuncts = new List<Term>();
- foreach (var node in nodes)
- {
- if (node.Bound.Formula != ctx.MkTrue())
- conjuncts.Add(ctx.MkImplies(ctx.MkApp(node.Name, node.Bound.IndParams), node.Bound.Formula));
- }
- Term query = ctx.MkNot(ctx.MkAnd(conjuncts.ToArray()));
- query = BindVariables(query,false); // bind variables existentially
- query = ctx.Letify(query); // put in let bindings for theorem prover
- return query;
- }
-
- private void CollectVariables(TermDict< bool> memo, Term t, List<Term> vars)
- {
- if (memo.ContainsKey(t))
- return;
- if (IsVariable(t))
- vars.Add(t);
- if (t.GetKind() == TermKind.App)
- {
- foreach (var s in t.GetAppArgs())
- CollectVariables(memo, s, vars);
- }
- memo.Add(t, true);
- }
-
- private Term BindVariables(Term t, bool universal = true)
- {
- TermDict< bool> memo = new TermDict<bool>();
- List<Term> vars = new List<Term>();
- CollectVariables(memo,t,vars);
- return universal ? ctx.MkForall(vars.ToArray(), t) : ctx.MkExists(vars.ToArray(), t);
- }
-
- private Term SubstPredsRec(TermDict< Term> memo, Dictionary<FuncDecl,FuncDecl> subst, Term t)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- if (t.GetKind() == TermKind.App)
- {
- var args = t.GetAppArgs();
- args = args.Select(x => SubstPredsRec(memo,subst,x)).ToArray();
- FuncDecl nf = null;
- var f = t.GetAppDecl();
- if (subst.TryGetValue(f, out nf))
- {
- res = ctx.MkApp(nf, args);
- }
- else
- {
- res = ctx.CloneApp(t, args);
- }
- } // TODO: handle quantifiers
- else
- res = t;
- memo.Add(t, res);
- return res;
- }
-
- private Term SubstPreds(Dictionary<FuncDecl, FuncDecl> subst, Term t)
- {
- TermDict< Term> memo = new TermDict< Term>();
- return SubstPredsRec(memo, subst, t);
- }
-
- /* Everything after here is private. */
-
- private class stack_entry
- {
- public List<Edge> edges = new List<Edge>();
- public List<Node> nodes = new List<Node>();
- };
-
- /** Set the model of the background theory used in a counterexample. */
- public void SetBackgroundModel(Model m)
- {
- dualModel = m;
- }
-
- /** Set the model of the background theory used in a counterexample. */
- public Model GetBackgroundModel()
- {
- return dualModel;
- }
-
- private int nodeCount = 0;
- private int edgeCount = 0;
- private Model dualModel;
- // private LabeledLiterals dualLabels;
- private Stack<stack_entry> stack;
- public List<Node> nodes = new List<Node>();
- public List<Edge> edges = new List<Edge>();
-
-
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Term = Microsoft.Boogie.VCExprAST.VCExpr;
+using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp;
+using Sort = Microsoft.Boogie.Type;
+using Microsoft.Boogie.VCExprAST;
+
+
+using Microsoft.Boogie.ExprExtensions;
+
+
+namespace Microsoft.Boogie
+{
+
+
+
+
+ /** This class represents a relation post-fixed point (RPFP) problem as
+ * a "problem graph". The graph consists of Nodes and hyper-edges.
+ *
+ * A node consists of
+ * - Annotation, a symbolic relation
+ * - Bound, a symbolic relation giving an upper bound on Annotation
+ *
+ *
+ * A hyper-edge consists of:
+ * - Children, a sequence of children Nodes,
+ * - F, a symbolic relational transformer,
+ * - Parent, a single parent Node.
+ *
+ * The graph is "solved" when:
+ * - For every Node n, n.Annotation subseteq n.Bound
+ * - For every hyperedge e, e.F(e.Children.Annotation) subseteq e.Parent.Annotation
+ *
+ * where, if x is a sequence of Nodes, x.Annotation is the sequences
+ * of Annotations of the nodes in the sequence.
+ *
+ * A symbolic Transformer consists of
+ * - RelParams, a sequence of relational symbols
+ * - IndParams, a sequence of individual symbols
+ * - Formula, a formula over RelParams and IndParams
+ *
+ * A Transformer t represents a function that takes sequence R of relations
+ * and yields the relation lambda (t.Indparams). Formula(R/RelParams).
+ *
+ * As a special case, a nullary Transformer (where RelParams is the empty sequence)
+ * represents a fixed relation.
+ *
+ * An RPFP consists of
+ * - Nodes, a set of Nodes
+ * - Edges, a set of hyper-edges
+ * - Context, a prover context that contains formula AST's
+ *
+ * Multiple RPFP's can use the same Context, but you should be careful
+ * that only one RPFP asserts constraints in the context at any time.
+ *
+ * */
+ public class RPFP
+ {
+ /** Symbolic representation of a relational transformer */
+ public class Transformer
+ {
+ public FuncDecl[] RelParams;
+ public Term[] IndParams;
+ public Term Formula;
+ public RPFP owner;
+
+ public Transformer Clone()
+ {
+ return (Transformer)this.MemberwiseClone();
+ }
+ }
+
+ /** Create a symbolic transformer. */
+ public Transformer CreateTransformer(FuncDecl[] _RelParams, Term[] _IndParams, Term _Formula)
+ {
+ Transformer t = new Transformer();
+ t.RelParams = _RelParams;
+ t.IndParams = _IndParams;
+ t.Formula = _Formula;
+ t.owner = this;
+ return t;
+ }
+
+ /** Create a relation (nullary relational transformer) */
+ public Transformer CreateRelation(Term[] _IndParams, Term _Formula)
+ {
+ return CreateTransformer(new FuncDecl[0], _IndParams, _Formula);
+ }
+
+ /** A node in the RPFP graph */
+ public class Node
+ {
+ public FuncDecl Name;
+ public Transformer Annotation;
+ public Transformer Bound;
+ public RPFP owner;
+ public int number;
+ public Edge Outgoing;
+ public List<Edge> Incoming;
+ public Term dual;
+ public Node map;
+ }
+
+ /** Create a node in the graph. The input is a term R(v_1...v_n)
+ * where R is an arbitrary relational symbol and v_1...v_n are
+ * arbitary distinct variables. The names are only of mnemonic value,
+ * however, the number and type of arguments determine the type
+ * of the relation at this node. */
+
+ public Node CreateNode(Term t)
+ {
+ Node n = new Node();
+ // Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry;
+ // Term[] _IndParams = tn.ToArray();
+ Term[] _IndParams = t.GetAppArgs();
+ FuncDecl Name = t.GetAppDecl();
+ n.Annotation = CreateRelation(_IndParams,ctx.MkTrue());
+ n.Bound = CreateRelation(_IndParams, ctx.MkTrue());
+ n.owner = this;
+ n.number = ++nodeCount;
+ n.Name = Name; // just to have a unique name
+ n.Incoming = new List<Edge>();
+ return n;
+ }
+
+ /** Clone a node (can be from another graph). */
+
+ public Node CloneNode(Node old)
+ {
+ Node n = new Node();
+ n.Annotation = old.Annotation.Clone();
+ n.Bound = old.Bound.Clone();
+ n.owner = this;
+ n.number = ++nodeCount;
+ n.Name = old.Name; // just to have a unique name
+ n.Incoming = new List<Edge>();
+ return n;
+ }
+
+ /** This class represents a hyper-edge in the RPFP graph */
+
+ public class Edge
+ {
+ public Transformer F;
+ public Node Parent;
+ public Node[] Children;
+ public RPFP owner;
+ public int number;
+ public Edge map;
+ public HashSet<string> labels;
+ internal Term dual;
+ internal TermDict<Term> valuation;
+ }
+
+
+ /** Create a hyper-edge. */
+ public Edge CreateEdge(Node _Parent, Transformer _F, Node[] _Children)
+ {
+ Edge e = new Edge();
+ e.Parent = _Parent;
+ e.F = _F;
+ e.Children = _Children;
+ e.owner = this;
+ e.number = ++edgeCount;
+ _Parent.Outgoing = e;
+ foreach (var c in _Children)
+ if(c != null)
+ c.Incoming.Add(e);
+ return e;
+ }
+
+ /** Create an edge that lower-bounds its parent. */
+ public Edge CreateLowerBoundEdge(Node _Parent)
+ {
+ return CreateEdge(_Parent, _Parent.Annotation, new RPFP.Node[0]);
+ }
+
+
+
+
+ /** Assert a background axiom. Background axioms can be used to provide the
+ * theory of auxilliary functions or relations. All symbols appearing in
+ * background axioms are considered global, and may appear in both transformer
+ * and relational solutions. Semantically, a solution to the RPFP gives
+ * an interpretation of the unknown relations for each interpretation of the
+ * auxilliary symbols that is consistent with the axioms. Axioms should be
+ * asserted before any calls to Push. They cannot be de-asserted by Pop. */
+
+ public void AssertAxiom(Term t)
+ {
+ ctx.AddAxiom(t);
+ }
+
+ /** Do not call this. */
+
+ public void RemoveAxiom(Term t)
+ {
+ ctx.RemoveAxiom(t);
+ }
+
+ /** Type of solve results */
+ public enum LBool { False, True, Undef };
+
+
+ /** Solve an RPFP graph. This means either strengthen the annotation
+ * so that the bound at the given root node is satisfied, or
+ * show that this cannot be done by giving a dual solution
+ * (i.e., a counterexample).
+ *
+ * In the current implementation, this only works for graphs that
+ * are:
+ * - tree-like
+ *
+ * - closed.
+ *
+ * In a tree-like graph, every nod has out most one incoming and one out-going edge,
+ * and there are no cycles. In a closed graph, every node has exactly one out-going
+ * edge. This means that the leaves of the tree are all hyper-edges with no
+ * children. Such an edge represents a relation (nullary transformer) and thus
+ * a lower bound on its parent. The parameter root must be the root of this tree.
+ *
+ * If Solve returns LBool.False, this indicates success. The annotation of the tree
+ * has been updated to satisfy the upper bound at the root.
+ *
+ * If Solve returns LBool.True, this indicates a counterexample. For each edge,
+ * you can then call Eval to determine the values of symbols in the transformer formula.
+ * You can also call Empty on a node to determine if its value in the counterexample
+ * is the empty relation.
+ *
+ * \param root The root of the tree
+ * \param persist Number of context pops through which result should persist
+ *
+ *
+ */
+
+ public LBool Solve(Node root, int persist)
+ {
+ return LBool.False; // TODO
+ }
+
+
+ /** Dispose of the dual model (counterexample) if there is one. */
+
+ public void DisposeDualModel()
+ {
+ // TODO dualModel = null;
+ }
+
+
+ /** Determines the value in the counterexample of a symbol occuring in the transformer formula of
+ * a given edge. */
+
+ public Term Eval(Edge e, Term t)
+ {
+ if (e.valuation == null)
+ e.valuation = new TermDict< Term>();
+ if (e.valuation.ContainsKey(t))
+ return e.valuation[t];
+ return null; // TODO
+ }
+
+ /** Sets the value in the counterexample of a symbol occuring in the transformer formula of
+ * a given edge. */
+
+ public void SetValue(Edge e, Term variable, Term value)
+ {
+ if (e.valuation == null)
+ e.valuation = new TermDict< Term>();
+ e.valuation.Add(variable, value);
+ }
+
+
+ /** Returns true if the given node is empty in the primal solution. For proecudure summaries,
+ this means that the procedure is not called in the current counter-model. */
+
+ public bool Empty(Node p)
+ {
+ return false; // TODO
+ }
+
+ /** Push a scope. Assertions made after Push can be undone by Pop. */
+
+ public void Push()
+ {
+ stack.Push(new stack_entry());
+ // TODO: do we need push/pop?
+ }
+
+ /** Pop a scope (see Push). Note, you cannot pop axioms. */
+
+ public void Pop(int num_scopes)
+ {
+ //TODO ctx.Pop((uint)num_scopes);
+ for (uint i = 0; i < num_scopes; i++)
+ {
+ stack_entry back = stack.Pop();
+ foreach (var e in back.edges)
+ e.dual = null;
+ foreach (var n in back.nodes)
+ n.dual = null;
+ }
+ }
+
+ public Context ctx;
+
+ public class LogicSolver {
+ public Context ctx;
+ };
+
+ public LogicSolver solver;
+
+ static public LogicSolver CreateLogicSolver(Context _ctx){
+ LogicSolver res = new LogicSolver();
+ res.ctx = _ctx;
+ return res;
+ }
+
+ /** This represents a conjecture that a given node is upper-boudned
+ by bound. */
+ public class Conjecture
+ {
+ public Node node;
+ public Transformer bound;
+ }
+
+ /** This is a list of conjectures generated during solving. */
+
+ public List<Conjecture> conjectures = new List<Conjecture>();
+
+ /** Construct an RPFP graph with a given interpolating prover context. It is allowed to
+ have multiple RPFP's use the same context, but you should never have teo RPFP's
+ with the same conext asserting nodes or edges at the same time. Note, if you create
+ axioms in one RPFP, them create a second RPFP with the same context, the second will
+ inherit the axioms.
+ */
+
+ public RPFP(LogicSolver slvr)
+ {
+ solver = slvr;
+ ctx = slvr.ctx;
+ stack = new Stack<stack_entry>();
+ stack.Push(new stack_entry());
+ }
+
+
+ /** Convert an array of clauses to an RPFP.
+ */
+
+ public void FromClauses(Term[] clauses){
+ FuncDecl failName = ctx.MkFuncDecl("@Fail", ctx.MkBoolSort());
+ foreach(var clause in clauses){
+ Node foo = GetNodeFromClause(clause,failName);
+ if(foo != null)
+ nodes.Add(foo);
+ }
+ foreach (var clause in clauses)
+ edges.Add(GetEdgeFromClause(clause,failName));
+ }
+
+
+ // This returns a new FuncDel with same sort as top-level function
+ // of term t, but with numeric suffix appended to name.
+
+ private FuncDecl SuffixFuncDecl(Term t, int n)
+ {
+ var name = t.GetAppDecl().GetDeclName() + "_" + n.ToString();
+ return ctx.MkFuncDecl(name, t.GetAppDecl());
+ }
+
+ // Collect the relational paremeters
+
+ Dictionary<FuncDecl, Node> relationToNode = new Dictionary<FuncDecl, Node>();
+
+ private Term CollectParamsRec(TermDict<Term> memo, Term t, List<FuncDecl> parms, List<RPFP.Node> nodes, Dictionary<Term, Term> done)
+ {
+ Term res;
+ if (memo.TryGetValue(t, out res))
+ return res;
+ if (t.GetKind() == TermKind.App)
+ {
+ var f = t.GetAppDecl();
+ Node node;
+ if (relationToNode.TryGetValue(f, out node))
+ {
+ if (done.ContainsKey(t))
+ res = done[t];
+ else
+ {
+ f = SuffixFuncDecl(t, parms.Count);
+ parms.Add(f);
+ nodes.Add(node);
+ done.Add(t,res); // don't count same expression twice!
+ }
+ }
+ var args = t.GetAppArgs();
+ args = args.Select(x => CollectParamsRec(memo, x, parms, nodes, done)).ToArray();
+ res = ctx.CloneApp(t, args);
+ } // TODO: handle quantifiers
+ else
+ res = t;
+ memo.Add(t, res);
+ return res;
+ }
+
+ private bool IsVariable(Term t)
+ {
+ // TODO: is this right?
+ // return t.IsFunctionApp() && t.GetAppArgs().Length == 0;
+ return t is VCExprVar && !(t is VCExprConstant);
+ }
+
+ private Edge GetEdgeFromClause(Term t, FuncDecl failName)
+ {
+ Term[] args = t.GetAppArgs();
+ Term body = args[0];
+ Term head = args[1];
+ Term[] _IndParams;
+ FuncDecl Name;
+ if (head.IsFalse())
+ {
+ Name = failName;
+ _IndParams = new Term[0];
+ }
+ else
+ {
+ _IndParams = head.GetAppArgs();
+ Name = head.GetAppDecl();
+ }
+ for(int i = 0; i < _IndParams.Length; i++)
+ if (!IsVariable(_IndParams[i]))
+ {
+ Term v = ctx.MkConst("@a" + i.ToString(), _IndParams[i].GetSort());
+ body = ctx.MkAnd(body, ctx.MkEq(v, _IndParams[i]));
+ _IndParams[i] = v;
+ }
+ var relParams = new List<FuncDecl>();
+ var nodeParams = new List<RPFP.Node>();
+ var memo = new TermDict< Term>();
+ var done = new Dictionary<Term, Term>(); // note this hashes on equality, not reference!
+ body = CollectParamsRec(memo, body, relParams, nodeParams,done);
+ Transformer F = CreateTransformer(relParams.ToArray(), _IndParams, body);
+ Node parent = relationToNode[Name];
+ return CreateEdge(parent, F, nodeParams.ToArray());
+ }
+
+ private Node GetNodeFromClause(Term t, FuncDecl failName)
+ {
+ Term[] args = t.GetAppArgs();
+ Term body = args[0];
+ Term head = args[1];
+ FuncDecl Name;
+ Term[] _IndParams;
+ bool is_query = false;
+ if (head.Equals(ctx.MkFalse()))
+ {
+ Name = failName;
+ is_query = true;
+ _IndParams = new Term[0];
+ }
+ else
+ {
+ Name = head.GetAppDecl();
+ _IndParams = head.GetAppArgs();
+ }
+ if (relationToNode.ContainsKey(Name))
+ return null;
+ for (int i = 0; i < _IndParams.Length; i++)
+ if (!IsVariable(_IndParams[i]))
+ {
+ Term v = ctx.MkConst("@a" + i.ToString(), _IndParams[i].GetSort());
+ _IndParams[i] = v;
+ }
+ Term foo = ctx.MkApp(Name, _IndParams);
+ Node node = CreateNode(foo);
+ relationToNode[Name] = node;
+ if (is_query)
+ node.Bound = CreateRelation(new Term[0], ctx.MkFalse());
+ return node;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+ // Convert RPFP to Z3 rules
+ /////////////////////////////////////////////////////////////////////////////////////////
+
+ /** Get the Z3 rule corresponding to an edge */
+
+ public Term GetRule(Edge edge)
+ {
+ Dictionary<FuncDecl, FuncDecl> predSubst = new Dictionary<FuncDecl, FuncDecl>();
+ for (int i = 0; i < edge.Children.Length; i++)
+ predSubst.Add(edge.F.RelParams[i], edge.Children[i].Name);
+ Term body = SubstPreds(predSubst, edge.F.Formula);
+ Term head = ctx.MkApp(edge.Parent.Name, edge.F.IndParams);
+ var rule = BindVariables(ctx.MkImplies(body, head));
+ rule = ctx.Letify(rule); // put in let bindings for theorem prover
+ return rule;
+ }
+
+ /** Get the Z3 query corresponding to the conjunction of the node bounds. */
+
+ public Term GetQuery()
+ {
+ List<Term> conjuncts = new List<Term>();
+ foreach (var node in nodes)
+ {
+ if (node.Bound.Formula != ctx.MkTrue())
+ conjuncts.Add(ctx.MkImplies(ctx.MkApp(node.Name, node.Bound.IndParams), node.Bound.Formula));
+ }
+ Term query = ctx.MkNot(ctx.MkAnd(conjuncts.ToArray()));
+ query = BindVariables(query,false); // bind variables existentially
+ query = ctx.Letify(query); // put in let bindings for theorem prover
+ return query;
+ }
+
+ private void CollectVariables(TermDict< bool> memo, Term t, List<Term> vars)
+ {
+ if (memo.ContainsKey(t))
+ return;
+ if (IsVariable(t))
+ vars.Add(t);
+ if (t.GetKind() == TermKind.App)
+ {
+ foreach (var s in t.GetAppArgs())
+ CollectVariables(memo, s, vars);
+ }
+ memo.Add(t, true);
+ }
+
+ private Term BindVariables(Term t, bool universal = true)
+ {
+ TermDict< bool> memo = new TermDict<bool>();
+ List<Term> vars = new List<Term>();
+ CollectVariables(memo,t,vars);
+ return universal ? ctx.MkForall(vars.ToArray(), t) : ctx.MkExists(vars.ToArray(), t);
+ }
+
+ private Term SubstPredsRec(TermDict< Term> memo, Dictionary<FuncDecl,FuncDecl> subst, Term t)
+ {
+ Term res;
+ if (memo.TryGetValue(t, out res))
+ return res;
+ if (t.GetKind() == TermKind.App)
+ {
+ var args = t.GetAppArgs();
+ args = args.Select(x => SubstPredsRec(memo,subst,x)).ToArray();
+ FuncDecl nf = null;
+ var f = t.GetAppDecl();
+ if (subst.TryGetValue(f, out nf))
+ {
+ res = ctx.MkApp(nf, args);
+ }
+ else
+ {
+ res = ctx.CloneApp(t, args);
+ }
+ } // TODO: handle quantifiers
+ else
+ res = t;
+ memo.Add(t, res);
+ return res;
+ }
+
+ private Term SubstPreds(Dictionary<FuncDecl, FuncDecl> subst, Term t)
+ {
+ TermDict< Term> memo = new TermDict< Term>();
+ return SubstPredsRec(memo, subst, t);
+ }
+
+ /* Everything after here is private. */
+
+ private class stack_entry
+ {
+ public List<Edge> edges = new List<Edge>();
+ public List<Node> nodes = new List<Node>();
+ };
+
+ /** Set the model of the background theory used in a counterexample. */
+ public void SetBackgroundModel(Model m)
+ {
+ dualModel = m;
+ }
+
+ /** Set the model of the background theory used in a counterexample. */
+ public Model GetBackgroundModel()
+ {
+ return dualModel;
+ }
+
+ private int nodeCount = 0;
+ private int edgeCount = 0;
+ private Model dualModel;
+ // private LabeledLiterals dualLabels;
+ private Stack<stack_entry> stack;
+ public List<Node> nodes = new List<Node>();
+ public List<Edge> edges = new List<Edge>();
+
+
+ }
+}
diff --git a/Source/VCGeneration/StratifiedVC.cs b/Source/VCGeneration/StratifiedVC.cs
index 037fa2be..789f86f5 100644
--- a/Source/VCGeneration/StratifiedVC.cs
+++ b/Source/VCGeneration/StratifiedVC.cs
@@ -1,2903 +1,2906 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Threading;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.IO;
-using Microsoft.Boogie;
-using Microsoft.Boogie.GraphUtil;
-using System.Diagnostics.Contracts;
-using Microsoft.Basetypes;
-using Microsoft.Boogie.VCExprAST;
-
-namespace VC {
- using Bpl = Microsoft.Boogie;
-
- public class StratifiedVC {
- public StratifiedInliningInfo info;
- public int id;
- public List<VCExprVar> interfaceExprVars;
-
- // boolControlVC (block -> its bool variable)
- public Dictionary<Block, VCExpr> blockToControlVar;
- // While using labels (block -> its label)
- public Dictionary<Absy, string> block2label;
-
- public Dictionary<Block, List<StratifiedCallSite>> callSites;
- public Dictionary<Block, List<StratifiedCallSite>> recordProcCallSites;
- public VCExpr vcexpr;
-
- // Must-Reach Information
- Dictionary<Block, VCExprVar> mustReachVar;
- List<VCExprLetBinding> mustReachBindings;
-
- public StratifiedVC(StratifiedInliningInfo siInfo, HashSet<string> procCalls) {
- info = siInfo;
- info.GenerateVC();
- var vcgen = info.vcgen;
- var prover = vcgen.prover;
- VCExpressionGenerator gen = prover.VCExprGen;
- var bet = prover.Context.BoogieExprTranslator;
-
- vcexpr = info.vcexpr;
- id = vcgen.CreateNewId();
- interfaceExprVars = new List<VCExprVar>();
- Dictionary<VCExprVar, VCExpr> substDict = new Dictionary<VCExprVar, VCExpr>();
- foreach (VCExprVar v in info.interfaceExprVars) {
- VCExprVar newVar = vcgen.CreateNewVar(v.Type);
- interfaceExprVars.Add(newVar);
- substDict.Add(v, newVar);
- }
- foreach (VCExprVar v in info.privateExprVars) {
- substDict.Add(v, vcgen.CreateNewVar(v.Type));
- }
- if(info.controlFlowVariable != null)
- substDict.Add(bet.LookupVariable(info.controlFlowVariable), gen.Integer(BigNum.FromInt(id)));
- VCExprSubstitution subst = new VCExprSubstitution(substDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
- SubstitutingVCExprVisitor substVisitor = new SubstitutingVCExprVisitor(prover.VCExprGen);
- vcexpr = substVisitor.Mutate(vcexpr, subst);
-
- // For BoolControlVC generation
- if (info.blockToControlVar != null)
- {
- blockToControlVar = new Dictionary<Block, VCExpr>();
- foreach (var tup in info.blockToControlVar)
- blockToControlVar.Add(tup.Key, substDict[tup.Value]);
- }
-
- // labels
- if (info.label2absy != null)
- {
- block2label = new Dictionary<Absy, string>();
- vcexpr = RenameVCExprLabels.Apply(vcexpr, info.vcgen.prover.VCExprGen, info.label2absy, block2label);
- }
-
- if(procCalls != null)
- vcexpr = RemoveProcedureCalls.Apply(vcexpr, info.vcgen.prover.VCExprGen, procCalls);
-
- callSites = new Dictionary<Block, List<StratifiedCallSite>>();
- foreach (Block b in info.callSites.Keys) {
- callSites[b] = new List<StratifiedCallSite>();
- foreach (CallSite cs in info.callSites[b]) {
- callSites[b].Add(new StratifiedCallSite(cs, substVisitor, subst));
- }
- }
-
- recordProcCallSites = new Dictionary<Block, List<StratifiedCallSite>>();
- foreach (Block b in info.recordProcCallSites.Keys) {
- recordProcCallSites[b] = new List<StratifiedCallSite>();
- foreach (CallSite cs in info.recordProcCallSites[b]) {
- recordProcCallSites[b].Add(new StratifiedCallSite(cs, substVisitor, subst));
- }
- }
- }
-
- public VCExpr MustReach(Block block)
- {
- Contract.Assert(!CommandLineOptions.Clo.UseLabels);
-
- // This information is computed lazily
- if (mustReachBindings == null)
- {
- var vcgen = info.vcgen;
- var gen = vcgen.prover.VCExprGen;
- var impl = info.impl;
- mustReachVar = new Dictionary<Block, VCExprVar>();
- mustReachBindings = new List<VCExprLetBinding>();
- foreach (Block b in impl.Blocks)
- mustReachVar[b] = vcgen.CreateNewVar(Bpl.Type.Bool);
-
- var dag = new Graph<Block>();
- dag.AddSource(impl.Blocks[0]);
- foreach (Block b in impl.Blocks)
- {
- var gtc = b.TransferCmd as GotoCmd;
- if (gtc != null)
- foreach (Block dest in gtc.labelTargets)
- dag.AddEdge(dest, b);
- }
- IEnumerable sortedNodes = dag.TopologicalSort();
-
- foreach (Block currBlock in dag.TopologicalSort())
- {
- if (currBlock == impl.Blocks[0])
- {
- mustReachBindings.Add(gen.LetBinding(mustReachVar[currBlock], VCExpressionGenerator.True));
- continue;
- }
-
- VCExpr expr = VCExpressionGenerator.False;
- foreach (var pred in dag.Successors(currBlock))
- {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(gen.Integer(BigNum.FromInt(id)), gen.Integer(BigNum.FromInt(pred.UniqueId)));
- VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(currBlock.UniqueId)));
- expr = gen.Or(expr, gen.And(mustReachVar[pred], controlTransferExpr));
- }
- mustReachBindings.Add(gen.LetBinding(mustReachVar[currBlock], expr));
- }
- }
-
- Contract.Assert(mustReachVar.ContainsKey(block));
- return info.vcgen.prover.VCExprGen.Let(mustReachBindings, mustReachVar[block]);
- }
-
- public List<StratifiedCallSite> CallSites {
- get {
- var ret = new List<StratifiedCallSite>();
- foreach (var b in callSites.Keys) {
- foreach (var cs in callSites[b]) {
- ret.Add(cs);
- }
- }
- return ret;
- }
- }
-
- public List<StratifiedCallSite> RecordProcCallSites {
- get {
- var ret = new List<StratifiedCallSite>();
- foreach (var b in recordProcCallSites.Keys) {
- foreach (var cs in recordProcCallSites[b]) {
- ret.Add(cs);
- }
- }
- return ret;
- }
- }
-
- public override string ToString()
- {
- return info.impl.Name;
- }
- }
-
- // Rename all labels in a VC to (globally) fresh labels
- class RenameVCExprLabels : MutatingVCExprVisitor<bool>
- {
- Dictionary<int, Absy> label2absy;
- Dictionary<Absy, string> absy2newlabel;
- static int counter = 11;
-
- RenameVCExprLabels(VCExpressionGenerator gen, Dictionary<int, Absy> label2absy, Dictionary<Absy, string> absy2newlabel)
- : base(gen)
- {
- this.label2absy = label2absy;
- this.absy2newlabel = absy2newlabel;
- }
-
- public static VCExpr Apply(VCExpr expr, VCExpressionGenerator gen, Dictionary<int, Absy> label2absy, Dictionary<Absy, string> absy2newlabel)
- {
- return (new RenameVCExprLabels(gen, label2absy, absy2newlabel)).Mutate(expr, true);
- }
-
- // Finds labels and changes them to a globally unique label:
- protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
- List<VCExpr/*!*/>/*!*/ newSubExprs,
- bool changed,
- bool arg)
- {
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr ret;
- if (changed)
- ret = Gen.Function(originalNode.Op,
- newSubExprs, originalNode.TypeArguments);
- else
- ret = originalNode;
-
- VCExprLabelOp lop = originalNode.Op as VCExprLabelOp;
- if (lop == null) return ret;
- if (!(ret is VCExprNAry)) return ret;
- VCExprNAry retnary = (VCExprNAry)ret;
-
- // remove the sign
- var nosign = 0;
- if (!Int32.TryParse(lop.label.Substring(1), out nosign))
- return ret;
-
- if (!label2absy.ContainsKey(nosign))
- return ret;
-
- string newLabel = "SI" + counter.ToString();
- counter++;
- absy2newlabel[label2absy[nosign]] = newLabel;
-
- if (lop.pos)
- {
- return Gen.LabelPos(newLabel, retnary[0]);
- }
- else
- {
- return Gen.LabelNeg(newLabel, retnary[0]);
- }
-
- }
- }
-
- // Remove the uninterpreted function calls that substitute procedure calls
- class RemoveProcedureCalls : MutatingVCExprVisitor<bool>
- {
- HashSet<string> procNames;
-
- RemoveProcedureCalls(VCExpressionGenerator gen, HashSet<string> procNames)
- : base(gen)
- {
- this.procNames = procNames;
- }
-
- public static VCExpr Apply(VCExpr expr, VCExpressionGenerator gen, HashSet<string> procNames)
- {
- return (new RemoveProcedureCalls(gen, procNames)).Mutate(expr, true);
- }
-
- // Finds labels and changes them to a globally unique label:
- protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
- List<VCExpr/*!*/>/*!*/ newSubExprs,
- bool changed,
- bool arg)
- {
- //Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr ret;
- if (changed)
- ret = Gen.Function(originalNode.Op,
- newSubExprs, originalNode.TypeArguments);
- else
- ret = originalNode;
-
- if (!(ret is VCExprNAry)) return ret;
- VCExprNAry retnary = (VCExprNAry)ret;
- if (!(retnary.Op is VCExprBoogieFunctionOp))
- return ret;
-
- var fcall = (retnary.Op as VCExprBoogieFunctionOp).Func.Name;
- if (procNames.Contains(fcall))
- return VCExpressionGenerator.True;
- return ret;
- }
- }
-
-
- public class CallSite {
- public string calleeName;
- public List<VCExpr> interfaceExprs;
- public Block block;
- public int numInstr; // for TraceLocation
- public VCExprVar callSiteVar;
- public QKeyValue Attributes; // attributes on the call cmd
- public CallSite(string callee, List<VCExpr> interfaceExprs, VCExprVar callSiteVar, Block block, int numInstr, QKeyValue Attributes)
- {
- this.calleeName = callee;
- this.interfaceExprs = interfaceExprs;
- this.callSiteVar = callSiteVar;
- this.block = block;
- this.numInstr = numInstr;
- this.Attributes = Attributes;
- }
- }
-
- public class StratifiedCallSite {
- public CallSite callSite;
- public List<VCExpr> interfaceExprs;
- public VCExpr callSiteExpr;
-
- public StratifiedCallSite(CallSite cs, SubstitutingVCExprVisitor substVisitor, VCExprSubstitution subst) {
- callSite = cs;
- interfaceExprs = new List<VCExpr>();
- foreach (VCExpr v in cs.interfaceExprs) {
- interfaceExprs.Add(substVisitor.Mutate(v, subst));
- }
- if (callSite.callSiteVar != null)
- callSiteExpr = substVisitor.Mutate(callSite.callSiteVar, subst);
- }
-
- public VCExpr Attach(StratifiedVC svc) {
- Contract.Assert(interfaceExprs.Count == svc.interfaceExprVars.Count);
- StratifiedInliningInfo info = svc.info;
- ProverInterface prover = info.vcgen.prover;
- VCExpressionGenerator gen = prover.VCExprGen;
-
- Dictionary<VCExprVar, VCExpr> substDict = new Dictionary<VCExprVar, VCExpr>();
- for (int i = 0; i < svc.interfaceExprVars.Count; i++) {
- VCExprVar v = svc.interfaceExprVars[i];
- substDict.Add(v, interfaceExprs[i]);
- }
- VCExprSubstitution subst = new VCExprSubstitution(substDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
- SubstitutingVCExprVisitor substVisitor = new SubstitutingVCExprVisitor(prover.VCExprGen);
- svc.vcexpr = substVisitor.Mutate(svc.vcexpr, subst);
- foreach (StratifiedCallSite scs in svc.CallSites) {
- List<VCExpr> newInterfaceExprs = new List<VCExpr>();
- foreach (VCExpr expr in scs.interfaceExprs) {
- newInterfaceExprs.Add(substVisitor.Mutate(expr, subst));
- }
- scs.interfaceExprs = newInterfaceExprs;
- }
- foreach (StratifiedCallSite scs in svc.RecordProcCallSites) {
- List<VCExpr> newInterfaceExprs = new List<VCExpr>();
- foreach (VCExpr expr in scs.interfaceExprs) {
- newInterfaceExprs.Add(substVisitor.Mutate(expr, subst));
- }
- scs.interfaceExprs = newInterfaceExprs;
- }
- //return gen.Implies(callSiteExpr, svc.vcexpr);
- return svc.vcexpr;
- }
-
- public override string ToString()
- {
- return callSite.calleeName;
- }
- }
-
- public class StratifiedInliningInfo {
- public StratifiedVCGenBase vcgen;
- public Implementation impl;
- public Function function;
- public Variable controlFlowVariable;
- public Cmd exitAssertCmd;
- public VCExpr vcexpr;
- public List<VCExprVar> interfaceExprVars;
- public List<VCExprVar> privateExprVars;
- public Dictionary<int, Absy> label2absy;
- public ModelViewInfo mvInfo;
- public Dictionary<Block, List<CallSite>> callSites;
- public Dictionary<Block, List<CallSite>> recordProcCallSites;
- public bool initialized { get; private set; }
- // Instrumentation to apply after PassiveImpl, but before VCGen
- Action<Implementation> PassiveImplInstrumentation;
-
- // boolControlVC (block -> its Bool variable)
- public Dictionary<Block, VCExprVar> blockToControlVar;
-
- public StratifiedInliningInfo(Implementation implementation, StratifiedVCGenBase stratifiedVcGen, Action<Implementation> PassiveImplInstrumentation) {
- vcgen = stratifiedVcGen;
- impl = implementation;
- this.PassiveImplInstrumentation = PassiveImplInstrumentation;
-
- List<Variable> functionInterfaceVars = new List<Variable>();
- foreach (Variable v in vcgen.program.GlobalVariables) {
- functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
- }
- foreach (Variable v in impl.InParams) {
- functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
- }
- foreach (Variable v in impl.OutParams) {
- functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
- }
- foreach (IdentifierExpr e in impl.Proc.Modifies) {
- if (e.Decl == null) continue;
- functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", e.Decl.TypedIdent.Type), true));
- }
- Formal returnVar = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Bpl.Type.Bool), false);
- function = new Function(Token.NoToken, impl.Name, functionInterfaceVars, returnVar);
- vcgen.prover.Context.DeclareFunction(function, "");
-
- List<Expr> exprs = new List<Expr>();
- foreach (Variable v in vcgen.program.GlobalVariables) {
- Contract.Assert(v != null);
- exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
- }
- foreach (Variable v in impl.Proc.InParams) {
- Contract.Assert(v != null);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- foreach (Variable v in impl.Proc.OutParams) {
- Contract.Assert(v != null);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- foreach (IdentifierExpr ie in impl.Proc.Modifies) {
- Contract.Assert(ie != null);
- if (ie.Decl == null)
- continue;
- exprs.Add(ie);
- }
- Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
- impl.Proc.Ensures.Add(new Ensures(Token.NoToken, true, freePostExpr, "", new QKeyValue(Token.NoToken, "si_fcall", new List<object>(), null)));
-
- initialized = false;
- }
-
- public void GenerateVCBoolControl()
- {
- Debug.Assert(!initialized);
- Debug.Assert(CommandLineOptions.Clo.SIBoolControlVC);
-
- // fix names for exit variables
- var outputVariables = new List<Variable>();
- var assertConjuncts = new List<Expr>();
- foreach (Variable v in impl.OutParams)
- {
- Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- outputVariables.Add(c);
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertConjuncts.Add(eqExpr);
- }
- foreach (IdentifierExpr e in impl.Proc.Modifies)
- {
- if (e.Decl == null) continue;
- Variable v = e.Decl;
- Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- outputVariables.Add(c);
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertConjuncts.Add(eqExpr);
- }
- exitAssertCmd = new AssumeCmd(Token.NoToken, Expr.BinaryTreeAnd(assertConjuncts));
- (exitAssertCmd as AssumeCmd).Attributes = new QKeyValue(Token.NoToken, "exitAssert", new List<object>(), null);
-
- // no need for label2absy
- label2absy = new Dictionary<int, Absy>();
-
- // Passify
- Program program = vcgen.program;
- ProverInterface proverInterface = vcgen.prover;
- vcgen.ConvertCFG2DAG(impl);
- vcgen.PassifyImpl(impl, out mvInfo);
-
- VCExpressionGenerator gen = proverInterface.VCExprGen;
- var exprGen = proverInterface.Context.ExprGen;
- var translator = proverInterface.Context.BoogieExprTranslator;
-
- // add a boolean variable at each call site
- vcgen.InstrumentCallSites(impl);
-
- // typecheck
- var tc = new TypecheckingContext(null);
- impl.Typecheck(tc);
-
- ///////////////////
- // Generate the VC
- ///////////////////
-
- // block -> bool variable
- blockToControlVar = new Dictionary<Block, VCExprVar>();
- foreach (var b in impl.Blocks)
- blockToControlVar.Add(b, gen.Variable(b.Label + "_holds", Bpl.Type.Bool));
-
- vcexpr = VCExpressionGenerator.True;
- foreach (var b in impl.Blocks)
- {
- // conjoin all assume cmds
- VCExpr c = VCExpressionGenerator.True;
- foreach (var cmd in b.Cmds)
- {
- var acmd = cmd as AssumeCmd;
- if (acmd == null)
- {
- Debug.Assert(cmd is AssertCmd && (cmd as AssertCmd).Expr is LiteralExpr &&
- ((cmd as AssertCmd).Expr as LiteralExpr).IsTrue);
- continue;
- }
- var expr = translator.Translate(acmd.Expr);
- // Label the assume if it is a procedure call
- NAryExpr naryExpr = acmd.Expr as NAryExpr;
- if (naryExpr != null && naryExpr.Fun is FunctionCall)
- {
- var id = acmd.UniqueId;
- label2absy[id] = acmd;
- expr = gen.LabelPos(cce.NonNull("si_fcall_" + id.ToString()), expr);
- }
-
- c = gen.AndSimp(c, expr);
- }
-
- // block implies a disjunction of successors
- Debug.Assert(!(b.TransferCmd is ReturnExprCmd), "Not supported");
- var gc = b.TransferCmd as GotoCmd;
- if (gc != null)
- {
- VCExpr succ = VCExpressionGenerator.False;
- foreach (var sb in gc.labelTargets)
- succ = gen.OrSimp(succ, blockToControlVar[sb]);
- c = gen.AndSimp(c, succ);
- }
- else
- {
- // nothing to do
- }
- vcexpr = gen.AndSimp(vcexpr, gen.Eq(blockToControlVar[b], c));
- }
- // assert start block
- vcexpr = gen.AndSimp(vcexpr, blockToControlVar[impl.Blocks[0]]);
-
- //Console.WriteLine("VC of {0}: {1}", impl.Name, vcexpr);
- // Collect other information
- callSites = vcgen.CollectCallSites(impl);
- recordProcCallSites = vcgen.CollectRecordProcedureCallSites(impl);
-
- // record interface variables
- privateExprVars = new List<VCExprVar>();
- foreach (Variable v in impl.LocVars)
- {
- privateExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in impl.OutParams)
- {
- privateExprVars.Add(translator.LookupVariable(v));
- }
- privateExprVars.AddRange(blockToControlVar.Values);
-
- interfaceExprVars = new List<VCExprVar>();
- foreach (Variable v in program.GlobalVariables)
- {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in impl.InParams)
- {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in outputVariables)
- {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
- }
-
- public void GenerateVC() {
- if (initialized) return;
- if (CommandLineOptions.Clo.SIBoolControlVC)
- {
- GenerateVCBoolControl();
- initialized = true;
- return;
- }
- List<Variable> outputVariables = new List<Variable>();
- List<Expr> assertConjuncts = new List<Expr>();
- foreach (Variable v in impl.OutParams) {
- Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- outputVariables.Add(c);
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertConjuncts.Add(eqExpr);
- }
- foreach (IdentifierExpr e in impl.Proc.Modifies) {
- if (e.Decl == null) continue;
- Variable v = e.Decl;
- Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- outputVariables.Add(c);
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertConjuncts.Add(eqExpr);
- }
- exitAssertCmd = new AssertCmd(Token.NoToken, Expr.Not(Expr.BinaryTreeAnd(assertConjuncts)));
-
- Program program = vcgen.program;
- ProverInterface proverInterface = vcgen.prover;
- vcgen.ConvertCFG2DAG(impl);
- vcgen.PassifyImpl(impl, out mvInfo);
-
- if (PassiveImplInstrumentation != null)
- PassiveImplInstrumentation(impl);
-
- VCExpressionGenerator gen = proverInterface.VCExprGen;
- var exprGen = proverInterface.Context.ExprGen;
- var translator = proverInterface.Context.BoogieExprTranslator;
-
- VCExpr controlFlowVariableExpr = null;
- if (!CommandLineOptions.Clo.UseLabels) {
- controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "@cfc", Microsoft.Boogie.Type.Int));
- controlFlowVariableExpr = translator.LookupVariable(controlFlowVariable);
- }
-
- vcgen.InstrumentCallSites(impl);
-
- label2absy = new Dictionary<int, Absy>();
- VCGen.CodeExprConversionClosure cc = new VCGen.CodeExprConversionClosure(label2absy, proverInterface.Context);
- translator.SetCodeExprConverter(cc.CodeExprToVerificationCondition);
- vcexpr = gen.Not(vcgen.GenerateVCAux(impl, controlFlowVariableExpr, label2absy, proverInterface.Context));
-
- if (controlFlowVariableExpr != null)
- {
- VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(controlFlowVariableExpr, exprGen.Integer(BigNum.ZERO));
- VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
- vcexpr = exprGen.And(eqExpr, vcexpr);
- }
-
- callSites = vcgen.CollectCallSites(impl);
- recordProcCallSites = vcgen.CollectRecordProcedureCallSites(impl);
-
- privateExprVars = new List<VCExprVar>();
- foreach (Variable v in impl.LocVars) {
- privateExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in impl.OutParams) {
- privateExprVars.Add(translator.LookupVariable(v));
- }
-
- interfaceExprVars = new List<VCExprVar>();
- foreach (Variable v in program.GlobalVariables) {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in impl.InParams) {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in outputVariables) {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
-
- initialized = true;
- }
- }
-
- public abstract class StratifiedVCGenBase : VCGen {
- public readonly static string recordProcName = "boogie_si_record";
- public Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo;
- public ProverInterface prover;
-
- public StratifiedVCGenBase(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers, Action<Implementation> PassiveImplInstrumentation)
- : base(program, logFilePath, appendLogFile, checkers) {
- implName2StratifiedInliningInfo = new Dictionary<string, StratifiedInliningInfo>();
- prover = ProverInterface.CreateProver(program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime);
- foreach (var impl in program.Implementations) {
- implName2StratifiedInliningInfo[impl.Name] = new StratifiedInliningInfo(impl, this, PassiveImplInstrumentation);
- }
- GenerateRecordFunctions();
- }
-
- private void GenerateRecordFunctions() {
- foreach (var proc in program.Procedures) {
- if (!proc.Name.StartsWith(recordProcName)) continue;
- Contract.Assert(proc.InParams.Count == 1);
-
- // Make a new function
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Bpl.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
-
- // Get record type
- var argtype = proc.InParams[0].TypedIdent.Type;
-
- var ins = new List<Variable>();
- ins.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "x", argtype), true));
-
- var recordFunc = new Function(Token.NoToken, proc.Name, ins, returnVar);
- prover.Context.DeclareFunction(recordFunc, "");
-
- var exprs = new List<Expr>();
- exprs.Add(new IdentifierExpr(Token.NoToken, proc.InParams[0]));
-
- Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(recordFunc), exprs);
- proc.Ensures.Add(new Ensures(true, freePostExpr));
- }
- }
-
- public override void Close() {
- prover.Close();
- base.Close();
- }
-
- public void InstrumentCallSites(Implementation implementation) {
- var callSiteId = 0;
- foreach (Block block in implementation.Blocks) {
- List<Cmd> newCmds = new List<Cmd>();
- for (int i = 0; i < block.Cmds.Count; i++) {
- Cmd cmd = block.Cmds[i];
- newCmds.Add(cmd);
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- if (assumeCmd == null) continue;
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- if (naryExpr == null) continue;
- if (!implName2StratifiedInliningInfo.ContainsKey(naryExpr.Fun.FunctionName)) continue;
- Variable callSiteVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "SICS" + callSiteId, Microsoft.Boogie.Type.Bool));
- implementation.LocVars.Add(callSiteVar);
- newCmds.Add(new AssumeCmd(Token.NoToken, new IdentifierExpr(Token.NoToken, callSiteVar)));
- callSiteId++;
- }
- block.Cmds = newCmds;
- }
- }
-
- public Dictionary<Block, List<CallSite>> CollectCallSites(Implementation implementation) {
- var callSites = new Dictionary<Block, List<CallSite>>();
- foreach (Block block in implementation.Blocks) {
- for (int i = 0; i < block.Cmds.Count; i++) {
- Cmd cmd = block.Cmds[i];
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- if (assumeCmd == null) continue;
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- if (naryExpr == null) continue;
- if (!implName2StratifiedInliningInfo.ContainsKey(naryExpr.Fun.FunctionName)) continue;
- List<VCExpr> interfaceExprs = new List<VCExpr>();
- foreach (Expr e in naryExpr.Args) {
- interfaceExprs.Add(prover.Context.BoogieExprTranslator.Translate(e));
- }
- int instr = i;
- i++;
- AssumeCmd callSiteAssumeCmd = (AssumeCmd)block.Cmds[i];
- IdentifierExpr iexpr = (IdentifierExpr) callSiteAssumeCmd.Expr;
- CallSite cs = new CallSite(naryExpr.Fun.FunctionName, interfaceExprs, prover.Context.BoogieExprTranslator.LookupVariable(iexpr.Decl), block, instr, assumeCmd.Attributes);
- if (!callSites.ContainsKey(block))
- callSites[block] = new List<CallSite>();
- callSites[block].Add(cs);
- }
- }
- return callSites;
- }
-
- public Dictionary<Block, List<CallSite>> CollectRecordProcedureCallSites(Implementation implementation) {
- var callSites = new Dictionary<Block, List<CallSite>>();
- foreach (Block block in implementation.Blocks) {
- for (int i = 0; i < block.Cmds.Count; i++) {
- AssumeCmd assumeCmd = block.Cmds[i] as AssumeCmd;
- if (assumeCmd == null) continue;
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- if (naryExpr == null) continue;
- if (!naryExpr.Fun.FunctionName.StartsWith(recordProcName)) continue;
- List<VCExpr> interfaceExprs = new List<VCExpr>();
- foreach (Expr e in naryExpr.Args) {
- interfaceExprs.Add(prover.Context.BoogieExprTranslator.Translate(e));
- }
- CallSite cs = new CallSite(naryExpr.Fun.FunctionName, interfaceExprs, null, block, i, assumeCmd.Attributes);
- if (!callSites.ContainsKey(block))
- callSites[block] = new List<CallSite>();
- callSites[block].Add(cs);
- }
- }
- return callSites;
- }
-
- private int macroCountForStratifiedInlining = 0;
- public Macro CreateNewMacro() {
- string newName = "SIMacro@" + macroCountForStratifiedInlining.ToString();
- macroCountForStratifiedInlining++;
- return new Macro(Token.NoToken, newName, new List<Variable>(), new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool), false));
- }
- private int varCountForStratifiedInlining = 0;
- public VCExprVar CreateNewVar(Microsoft.Boogie.Type type) {
- string newName = "SIV@" + varCountForStratifiedInlining.ToString();
- varCountForStratifiedInlining++;
- Constant newVar = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, newName, type));
- prover.Context.DeclareConstant(newVar, false, null);
- return prover.VCExprGen.Variable(newVar.Name, type);
- }
- private int idCountForStratifiedInlining = 0;
- public int CreateNewId() {
- return idCountForStratifiedInlining++;
- }
-
- // Used inside PassifyImpl
- protected override void addExitAssert(string implName, Block exitBlock) {
- if (implName2StratifiedInliningInfo != null && implName2StratifiedInliningInfo.ContainsKey(implName)) {
- var exitAssertCmd = implName2StratifiedInliningInfo[implName].exitAssertCmd;
- if(exitAssertCmd != null) exitBlock.Cmds.Add(exitAssertCmd);
- }
- }
-
- public override Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo) {
- // Construct the set of inlined procs in the original program
- var inlinedProcs = new HashSet<string>();
- foreach (var decl in program.TopLevelDeclarations) {
- // Implementations
- if (decl is Implementation) {
- var impl = decl as Implementation;
- if (!(impl.Proc is LoopProcedure)) {
- inlinedProcs.Add(impl.Name);
- }
- }
-
- // And recording procedures
- if (decl is Procedure) {
- var proc = decl as Procedure;
- if (proc.Name.StartsWith(recordProcName)) {
- Debug.Assert(!(decl is LoopProcedure));
- inlinedProcs.Add(proc.Name);
- }
- }
- }
-
- return extractLoopTraceRec(
- new CalleeCounterexampleInfo(cex, new List<object>()),
- mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample;
- }
-
- protected override bool elIsLoop(string procname) {
- StratifiedInliningInfo info = null;
- if (implName2StratifiedInliningInfo.ContainsKey(procname)) {
- info = implName2StratifiedInliningInfo[procname];
- }
-
- if (info == null) return false;
-
- var lp = info.impl.Proc as LoopProcedure;
-
- if (lp == null) return false;
- return true;
- }
-
- public abstract Outcome FindLeastToVerify(Implementation impl, ref HashSet<string> allBoolVars);
- }
-
- public class StratifiedVCGen : StratifiedVCGenBase {
- public bool PersistCallTree;
- public static HashSet<string> callTree = null;
- public int numInlined = 0;
- public int vcsize = 0;
- private HashSet<string> procsThatReachedRecBound;
- private Dictionary<string, int> extraRecBound;
-
- public StratifiedVCGen(bool usePrevCallTree, HashSet<string> prevCallTree,
- Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
- : this(program, logFilePath, appendLogFile, checkers)
- {
- if (usePrevCallTree) {
- callTree = prevCallTree;
- PersistCallTree = true;
- }
- else {
- PersistCallTree = false;
- }
- }
-
- public StratifiedVCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
- : base(program, logFilePath, appendLogFile, checkers, null) {
- PersistCallTree = false;
- procsThatReachedRecBound = new HashSet<string>();
-
- extraRecBound = new Dictionary<string, int>();
- program.TopLevelDeclarations.OfType<Implementation>()
- .Iter(impl =>
- {
- var b = QKeyValue.FindIntAttribute(impl.Attributes, "SIextraRecBound", -1);
- if (b != -1) extraRecBound.Add(impl.Name, b);
- });
- }
-
- // Extra rec bound for procedures
- public int GetExtraRecBound(string procName) {
- if (!extraRecBound.ContainsKey(procName))
- return 0;
- else return extraRecBound[procName];
- }
-
- public class ApiChecker {
- public ProverInterface prover;
- public ProverInterface.ErrorHandler reporter;
-
- public ApiChecker(ProverInterface prover, ProverInterface.ErrorHandler reporter) {
- this.reporter = reporter;
- this.prover = prover;
- }
-
- private Outcome CheckVC() {
- prover.Check();
- ProverInterface.Outcome outcome = prover.CheckOutcomeCore(reporter);
-
- return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
- }
-
- public Outcome CheckAssumptions(List<VCExpr> assumptions) {
- if (assumptions.Count == 0) {
- return CheckVC();
- }
-
- prover.Push();
- foreach (var a in assumptions) {
- prover.Assert(a, true);
- }
- Outcome ret = CheckVC();
- prover.Pop();
- return ret;
- }
-
- public Outcome CheckAssumptions(List<VCExpr> hardAssumptions, List<VCExpr> softAssumptions) {
- List<int> unsatisfiedSoftAssumptions;
- ProverInterface.Outcome outcome = prover.CheckAssumptions(hardAssumptions, softAssumptions, out unsatisfiedSoftAssumptions, reporter);
- return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
- }
-
- public Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore) {
- ProverInterface.Outcome outcome = prover.CheckAssumptions(assumptions, out unsatCore, reporter);
- return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
- }
- }
-
- // Store important information related to a single VerifyImplementation query
- public class VerificationState {
- // The call tree
- public FCallHandler calls;
- public ApiChecker checker;
- // For statistics
- public int vcSize;
- public int expansionCount;
-
- public VerificationState(VCExpr vcMain, FCallHandler calls, ProverInterface prover, ProverInterface.ErrorHandler reporter) {
- prover.Assert(vcMain, true);
- this.calls = calls;
- this.checker = new ApiChecker(prover, reporter);
- vcSize = 0;
- expansionCount = 0;
- }
- }
-
- class FindLeastOORException : Exception
- {
- public Outcome outcome;
-
- public FindLeastOORException(string msg, Outcome outcome)
- : base(msg)
- {
- this.outcome = outcome;
- }
- }
-
- public override Outcome FindLeastToVerify(Implementation impl, ref HashSet<string> allBoolVars) {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- // Record current time
- var startTime = DateTime.UtcNow;
-
- // No Max: avoids theorem prover restarts
- CommandLineOptions.Clo.MaxProverMemory = 0;
-
- // Initialize cache
- satQueryCache = new Dictionary<int, List<HashSet<string>>>();
- unsatQueryCache = new Dictionary<int, List<HashSet<string>>>();
-
- Contract.Assert(implName2StratifiedInliningInfo != null);
-
- // Build VCs for all procedures
- implName2StratifiedInliningInfo.Values
- .Iter(info => info.GenerateVC());
-
- // Get the VC of the current procedure
- VCExpr vcMain = implName2StratifiedInliningInfo[impl.Name].vcexpr;
- Dictionary<int, Absy> mainLabel2absy = implName2StratifiedInliningInfo[impl.Name].label2absy;
-
- // Find all procedure calls in vc and put labels on them
- FCallHandler calls = new FCallHandler(prover.VCExprGen, implName2StratifiedInliningInfo, impl.Name, mainLabel2absy);
- calls.setCurrProcAsMain();
- vcMain = calls.Mutate(vcMain, true);
-
- try
- {
-
- // Put all of the necessary state into one object
- var vState = new VerificationState(vcMain, calls, prover, new EmptyErrorHandler());
-
- // We'll restore the original state of the theorem prover at the end
- // of this procedure
- vState.checker.prover.Push();
-
- // Do eager inlining
- while (calls.currCandidates.Count > 0)
- {
- List<int> toExpand = new List<int>();
-
- foreach (int id in calls.currCandidates)
- {
- Debug.Assert(calls.getRecursionBound(id) <= 1, "Recursion not supported");
- toExpand.Add(id);
- }
- DoExpansion(toExpand, vState);
- }
-
- // Find all the boolean constants
- var allConsts = new HashSet<VCExprVar>();
- foreach (var constant in program.Constants)
- {
- if (!allBoolVars.Contains(constant.Name)) continue;
- var v = prover.Context.BoogieExprTranslator.LookupVariable(constant);
- allConsts.Add(v);
- }
-
- // Now, lets start the algo
- var min = refinementLoop(vState.checker, new HashSet<VCExprVar>(), allConsts, allConsts);
-
- var ret = new HashSet<string>();
- foreach (var v in min)
- {
- //Console.WriteLine(v.Name);
- ret.Add(v.Name);
- }
- allBoolVars = ret;
-
- vState.checker.prover.Pop();
-
- return Outcome.Correct;
- }
- catch (FindLeastOORException e)
- {
- Console.WriteLine("Exception in FindLeastToVerify: {0}, {1}", e.Message, e.outcome);
- return e.outcome;
- }
- }
-
- private HashSet<VCExprVar> refinementLoop(ApiChecker apiChecker, HashSet<VCExprVar> trackedVars, HashSet<VCExprVar> trackedVarsUpperBound, HashSet<VCExprVar> allVars) {
- Debug.Assert(trackedVars.IsSubsetOf(trackedVarsUpperBound));
-
- // If we already know the fate of all vars, then we're done.
- if (trackedVars.Count == trackedVarsUpperBound.Count)
- return new HashSet<VCExprVar>(trackedVars);
-
- // See if we already have enough variables tracked
- var success = refinementLoopCheckPath(apiChecker, trackedVars, allVars);
- if (success) {
- // We have enough
- return new HashSet<VCExprVar>(trackedVars);
- }
-
- // If all that remains is 1 variable, then we know that we must track it
- if (trackedVars.Count + 1 == trackedVarsUpperBound.Count)
- return new HashSet<VCExprVar>(trackedVarsUpperBound);
-
- // Partition the remaining set of variables
- HashSet<VCExprVar> part1, part2;
- var temp = new HashSet<VCExprVar>(trackedVarsUpperBound);
- temp.ExceptWith(trackedVars);
- Partition<VCExprVar>(temp, out part1, out part2);
-
- // First half
- var fh = new HashSet<VCExprVar>(trackedVars); fh.UnionWith(part2);
- var s1 = refinementLoop(apiChecker, fh, trackedVarsUpperBound, allVars);
-
- var a = new HashSet<VCExprVar>(part1); a.IntersectWith(s1);
- var b = new HashSet<VCExprVar>(part1); b.ExceptWith(s1);
- var c = new HashSet<VCExprVar>(trackedVarsUpperBound); c.ExceptWith(b);
- a.UnionWith(trackedVars);
-
- // Second half
- return refinementLoop(apiChecker, a, c, allVars);
- }
-
- Dictionary<int, List<HashSet<string>>> satQueryCache;
- Dictionary<int, List<HashSet<string>>> unsatQueryCache;
-
- private bool refinementLoopCheckPath(ApiChecker apiChecker, HashSet<VCExprVar> varsToSet, HashSet<VCExprVar> allVars) {
- var assumptions = new List<VCExpr>();
- var prover = apiChecker.prover;
- var query = new HashSet<string>();
- varsToSet.Iter(v => query.Add(v.Name));
-
- if (checkCache(query, unsatQueryCache)) {
- prover.LogComment("FindLeast: Query Cache Hit");
- return true;
- }
- if (checkCache(query, satQueryCache)) {
- prover.LogComment("FindLeast: Query Cache Hit");
- return false;
- }
-
- prover.LogComment("FindLeast: Query Begin");
-
- foreach (var c in allVars) {
- if (varsToSet.Contains(c)) {
- assumptions.Add(c);
- }
- else {
- assumptions.Add(prover.VCExprGen.Not(c));
- }
- }
-
- var o = apiChecker.CheckAssumptions(assumptions);
- if (o != Outcome.Correct && o != Outcome.Errors)
- {
- throw new FindLeastOORException("OOR", o);
- }
- //Console.WriteLine("Result = " + o.ToString());
- prover.LogComment("FindLeast: Query End");
-
- if (o == Outcome.Correct) {
- insertCache(query, unsatQueryCache);
- return true;
- }
-
- insertCache(query, satQueryCache);
- return false;
- }
-
- private bool checkCache(HashSet<string> q, Dictionary<int, List<HashSet<string>>> cache) {
- if (!cache.ContainsKey(q.Count)) return false;
- foreach (var s in cache[q.Count]) {
- if (q.SetEquals(s)) return true;
- }
- return false;
- }
-
- private void insertCache(HashSet<string> q, Dictionary<int, List<HashSet<string>>> cache) {
- if (!cache.ContainsKey(q.Count)) {
- cache.Add(q.Count, new List<HashSet<string>>());
- }
- cache[q.Count].Add(q);
- }
-
- public static void Partition<T>(HashSet<T> values, out HashSet<T> part1, out HashSet<T> part2) {
- part1 = new HashSet<T>();
- part2 = new HashSet<T>();
- var size = values.Count;
- var crossed = false;
- var curr = 0;
- foreach (var s in values) {
- if (crossed) part2.Add(s);
- else part1.Add(s);
- curr++;
- if (!crossed && curr >= size / 2) crossed = true;
- }
- }
-
- public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback) {
- Debug.Assert(QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"));
- Debug.Assert(this.program == program);
-
- // Record current time
- var startTime = DateTime.UtcNow;
-
- // Flush any axioms that came with the program before we start SI on this implementation
- prover.AssertAxioms();
-
- // Run live variable analysis
- if (CommandLineOptions.Clo.LiveVariableAnalysis == 2) {
- Microsoft.Boogie.InterProcGenKill.ComputeLiveVars(impl, program);
- }
-
- // Get the VC of the current procedure
- StratifiedInliningInfo info = implName2StratifiedInliningInfo[impl.Name];
- info.GenerateVC();
- VCExpr vc = info.vcexpr;
- Dictionary<int, Absy> mainLabel2absy = info.label2absy;
- var reporter = new StratifiedInliningErrorReporter(implName2StratifiedInliningInfo, prover, callback, info);
-
- // Find all procedure calls in vc and put labels on them
- FCallHandler calls = new FCallHandler(prover.VCExprGen, implName2StratifiedInliningInfo, impl.Name, mainLabel2absy);
- calls.setCurrProcAsMain();
- vc = calls.Mutate(vc, true);
- reporter.SetCandidateHandler(calls);
- calls.id2VC.Add(0, vc);
- calls.extraRecursion = extraRecBound;
- if (CommandLineOptions.Clo.SIBoolControlVC)
- {
- calls.candiate2block2controlVar.Add(0, new Dictionary<Block, VCExpr>());
- implName2StratifiedInliningInfo[impl.Name].blockToControlVar.Iter(tup =>
- calls.candiate2block2controlVar[0].Add(tup.Key, tup.Value));
- }
-
- // We'll restore the original state of the theorem prover at the end
- // of this procedure
- prover.Push();
-
- // Put all of the necessary state into one object
- var vState = new VerificationState(vc, calls, prover, reporter);
- vState.vcSize += SizeComputingVisitor.ComputeSize(vc);
-
- Outcome ret = Outcome.ReachedBound;
-
- #region eager inlining
- for (int i = 1; i < CommandLineOptions.Clo.StratifiedInlining && calls.currCandidates.Count > 0; i++) {
- List<int> toExpand = new List<int>();
-
- foreach (int id in calls.currCandidates) {
- if (calls.getRecursionBound(id) <= CommandLineOptions.Clo.RecursionBound) {
- toExpand.Add(id);
- }
- }
- DoExpansion(toExpand, vState);
- }
- #endregion
-
- #region Repopulate call tree, if there is one
- if (PersistCallTree && callTree != null) {
- bool expand = true;
- while (expand) {
- List<int> toExpand = new List<int>();
- foreach (int id in calls.currCandidates) {
- if (callTree.Contains(calls.getPersistentId(id))) {
- toExpand.Add(id);
- }
- }
- if (toExpand.Count == 0) expand = false;
- else {
- DoExpansion(toExpand, vState);
- }
- }
- }
- #endregion
-
- if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1) {
- Console.WriteLine(">> SI: Size of VC after eager inlining: {0}", vState.vcSize);
- }
-
- // Under-approx query is only needed if something was inlined since
- // the last time an under-approx query was made
- // TODO: introduce this
- // bool underApproxNeeded = true;
-
- // The recursion bound for stratified search
- int bound = CommandLineOptions.Clo.NonUniformUnfolding ? CommandLineOptions.Clo.RecursionBound : 1;
-
- int done = 0;
-
- int iters = 0;
-
- // for blocking candidates (and focusing on a counterexample)
- var block = new HashSet<int>();
-
- // Process tasks while not done. We're done when:
- // case 1: (correct) We didn't find a bug (either an over-approx query was valid
- // or we reached the recursion bound) and the task is "step"
- // case 2: (bug) We find a bug
- // case 3: (internal error) The theorem prover TimesOut of runs OutOfMemory
- while (true)
- {
- // Check timeout
- if (CommandLineOptions.Clo.ProverKillTime != -1)
- {
- if ((DateTime.UtcNow - startTime).TotalSeconds > CommandLineOptions.Clo.ProverKillTime)
- {
- ret = Outcome.TimedOut;
- break;
- }
- }
-
- if (done > 0)
- {
- break;
- }
-
- // Stratified Step
- ret = stratifiedStep(bound, vState, block);
- iters++;
-
- // Sorry, out of luck (time/memory)
- if (ret == Outcome.Inconclusive || ret == Outcome.OutOfMemory || ret == Outcome.TimedOut)
- {
- done = 3;
- continue;
- }
-
- if (ret == Outcome.Errors && reporter.underapproximationMode)
- {
- // Found a bug
- done = 2;
- }
- else if (ret == Outcome.Correct)
- {
- if (block.Count == 0)
- {
- // Correct
- done = 1;
- }
- else
- {
- // reset blocked and continue loop
- block.Clear();
- }
- }
- else if (ret == Outcome.ReachedBound)
- {
- if (block.Count == 0)
- {
- if (CommandLineOptions.Clo.StratifiedInliningVerbose > 0)
- Console.WriteLine(">> SI: Exhausted Bound {0}", bound);
-
- // Increment bound
- bound++;
-
- if (bound > CommandLineOptions.Clo.RecursionBound)
- {
- // Correct under bound
- done = 1;
- }
- }
- else
- {
- // reset blocked and continue loop
- block.Clear();
- }
- }
- else
- {
- // Do inlining
- Debug.Assert(ret == Outcome.Errors && !reporter.underapproximationMode);
- Contract.Assert(reporter.candidatesToExpand.Count != 0);
-
- #region expand call tree
- if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1)
- {
- Console.Write(">> SI Inlining: ");
- reporter.candidatesToExpand
- .Select(c => calls.getProc(c))
- .Iter(c => Console.Write("{0} ", c));
-
- Console.WriteLine();
- }
-
- // Expand and try again
- vState.checker.prover.LogComment(";;;;;;;;;;;; Expansion begin ;;;;;;;;;;");
- DoExpansion(reporter.candidatesToExpand, vState);
- vState.checker.prover.LogComment(";;;;;;;;;;;; Expansion end ;;;;;;;;;;");
-
- #endregion
- }
- }
-
- // Pop off everything that we pushed so that there are no side effects from
- // this call to VerifyImplementation
- vState.checker.prover.Pop();
-
- if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1) {
- Console.WriteLine(">> SI: Expansions performed: {0}", vState.expansionCount);
- Console.WriteLine(">> SI: Candidates left: {0}", calls.currCandidates.Count);
- Console.WriteLine(">> SI: VC Size: {0}", vState.vcSize);
- }
-
- vcsize = vState.vcSize;
- numInlined = (calls.candidateParent.Keys.Count + 1) - (calls.currCandidates.Count);
-
- var rbound = "Procs that reached bound: ";
- foreach (var s in procsThatReachedRecBound) rbound += " " + s;
- if (ret == Outcome.ReachedBound) Helpers.ExtraTraceInformation(rbound);
- if (CommandLineOptions.Clo.StackDepthBound > 0 && ret == Outcome.Correct) ret = Outcome.ReachedBound;
-
- // Store current call tree
- if (PersistCallTree && (ret == Outcome.Correct || ret == Outcome.Errors || ret == Outcome.ReachedBound)) {
- callTree = new HashSet<string>();
- //var persistentNodes = new HashSet<int>(calls.candidateParent.Values);
- var persistentNodes = new HashSet<int>(calls.candidateParent.Keys);
- persistentNodes.Add(0);
- persistentNodes.ExceptWith(calls.currCandidates);
-
- foreach (var id in persistentNodes) {
- var pid = calls.getPersistentId(id);
- Debug.Assert(!callTree.Contains(pid));
- callTree.Add(pid);
- }
- }
- return ret;
- }
-
- // A step of the stratified inlining algorithm: both under-approx and over-approx queries
- private Outcome stratifiedStep(int bound, VerificationState vState, HashSet<int> block) {
- var calls = vState.calls;
- var checker = vState.checker;
- var prover = checker.prover;
- var reporter = checker.reporter as StratifiedInliningErrorReporter;
-
- reporter.underapproximationMode = true;
- prover.LogComment(";;;;;;;;;;;; Underapprox mode begin ;;;;;;;;;;");
- List<VCExpr> assumptions = new List<VCExpr>();
-
- foreach (int id in calls.currCandidates) {
- assumptions.Add(calls.getFalseExpr(id));
- }
- Outcome ret = checker.CheckAssumptions(assumptions);
- prover.LogComment(";;;;;;;;;;;; Underapprox mode end ;;;;;;;;;;");
-
- if (ret != Outcome.Correct) {
- // Either the query returned an error or it ran out of memory or time.
- // In all cases, we are done.
- return ret;
- }
-
- if (calls.currCandidates.Count == 0) {
- // If we didn't underapproximate, then we're done
- return ret;
- }
-
- prover.LogComment(";;;;;;;;;;;; Overapprox mode begin ;;;;;;;;;;");
-
- // Over-approx query
- reporter.underapproximationMode = false;
-
- // Push "true" for all, except:
- // push "false" for all candidates that have reached
- // the recursion bounds
-
- bool allTrue = true;
- bool allFalse = true;
- List<VCExpr> softAssumptions = new List<VCExpr>();
-
- assumptions = new List<VCExpr>();
- procsThatReachedRecBound.Clear();
-
- foreach (int id in calls.currCandidates) {
-
- int idBound = calls.getRecursionBound(id);
- int sd = calls.getStackDepth(id);
- if (idBound <= bound && (CommandLineOptions.Clo.StackDepthBound == 0 || sd <= CommandLineOptions.Clo.StackDepthBound)) {
- if (idBound > 1)
- softAssumptions.Add(calls.getFalseExpr(id));
-
- if (block.Contains(id)) {
- assumptions.Add(calls.getFalseExpr(id));
- allTrue = false;
- }
- else {
- allFalse = false;
- }
- }
- else {
- procsThatReachedRecBound.Add(calls.getProc(id));
- assumptions.Add(calls.getFalseExpr(id));
- allTrue = false;
- }
- }
-
- if (allFalse) {
- // If we made all candidates false, then this is the same
- // as the underapprox query. We already know the answer.
- ret = Outcome.Correct;
- }
- else {
- ret = CommandLineOptions.Clo.NonUniformUnfolding
- ? checker.CheckAssumptions(assumptions, softAssumptions)
- : checker.CheckAssumptions(assumptions);
- }
-
- if (ret != Outcome.Correct && ret != Outcome.Errors) {
- // The query ran out of memory or time, that's it,
- // we cannot do better. Give up!
- return ret;
- }
-
- if (ret == Outcome.Correct) {
- // If nothing was made false, then the program is correct
- if (allTrue) {
- return ret;
- }
-
- // Nothing more can be done with current recursion bound.
- return Outcome.ReachedBound;
- }
-
- Contract.Assert(ret == Outcome.Errors);
-
- prover.LogComment(";;;;;;;;;;;; Overapprox mode end ;;;;;;;;;;");
-
- return ret;
- }
-
- // A counter for adding new variables
- static int newVarCnt = 0;
-
- // Does on-demand inlining -- pushes procedure bodies on the theorem prover stack.
- private void DoExpansion(List<int>/*!*/ candidates, VerificationState vState) {
- Contract.Requires(candidates != null);
- Contract.Requires(vState.calls != null);
- Contract.Requires(vState.checker.prover != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- vState.expansionCount += candidates.Count;
-
- var prover = vState.checker.prover;
- var calls = vState.calls;
-
- VCExpr exprToPush = VCExpressionGenerator.True;
- Contract.Assert(exprToPush != null);
- foreach (int id in candidates) {
- VCExprNAry expr = calls.id2Candidate[id];
- Contract.Assert(expr != null);
- string procName = cce.NonNull(expr.Op as VCExprBoogieFunctionOp).Func.Name;
- if (!implName2StratifiedInliningInfo.ContainsKey(procName)) continue;
-
- StratifiedInliningInfo info = implName2StratifiedInliningInfo[procName];
- info.GenerateVC();
- //Console.WriteLine("Inlining {0}", procName);
- VCExpr expansion = cce.NonNull(info.vcexpr);
-
- // Instantiate the "forall" variables
- Dictionary<VCExprVar, VCExpr> substForallDict = new Dictionary<VCExprVar, VCExpr>();
- Contract.Assert(info.interfaceExprVars.Count == expr.Length);
- for (int i = 0; i < info.interfaceExprVars.Count; i++) {
- substForallDict.Add(info.interfaceExprVars[i], expr[i]);
- }
- VCExprSubstitution substForall = new VCExprSubstitution(substForallDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
-
- SubstitutingVCExprVisitor subst = new SubstitutingVCExprVisitor(prover.VCExprGen);
- Contract.Assert(subst != null);
- expansion = subst.Mutate(expansion, substForall);
-
- // Instantiate and declare the "exists" variables
- Dictionary<VCExprVar, VCExpr> substExistsDict = new Dictionary<VCExprVar, VCExpr>();
- foreach (VCExprVar v in info.privateExprVars) {
- Contract.Assert(v != null);
- string newName = v.Name + "_si_" + newVarCnt.ToString();
- newVarCnt++;
- prover.Context.DeclareConstant(new Constant(Token.NoToken, new TypedIdent(Token.NoToken, newName, v.Type)), false, null);
- substExistsDict.Add(v, prover.VCExprGen.Variable(newName, v.Type));
- }
- if (CommandLineOptions.Clo.SIBoolControlVC)
- {
- // record the mapping for control booleans (for tracing the path later)
- calls.candiate2block2controlVar[id] = new Dictionary<Block, VCExpr>();
- foreach (var tup in info.blockToControlVar)
- {
- calls.candiate2block2controlVar[id].Add(tup.Key,
- substExistsDict[tup.Value]);
- }
- }
- if (CommandLineOptions.Clo.ModelViewFile != null) {
- SaveSubstitution(vState, id, substForallDict, substExistsDict);
- }
- VCExprSubstitution substExists = new VCExprSubstitution(substExistsDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
-
- subst = new SubstitutingVCExprVisitor(prover.VCExprGen);
- expansion = subst.Mutate(expansion, substExists);
-
- if (!calls.currCandidates.Contains(id)) {
- Console.WriteLine("Don't know what we just expanded");
- }
-
- calls.currCandidates.Remove(id);
-
- // Record the new set of candidates and rename absy labels
- calls.currInlineCount = id;
- calls.setCurrProc(procName);
- expansion = calls.Mutate(expansion, true);
-
- //expansion = checker.VCExprGen.Eq(calls.id2ControlVar[id], expansion);
- expansion = prover.VCExprGen.Implies(calls.id2ControlVar[id], expansion);
- calls.id2VC.Add(id, expansion);
-
- exprToPush = prover.VCExprGen.And(exprToPush, expansion);
- }
- vState.checker.prover.Assert(exprToPush, true);
- vState.vcSize += SizeComputingVisitor.ComputeSize(exprToPush);
- }
-
- private void SaveSubstitution(VerificationState vState, int id,
- Dictionary<VCExprVar, VCExpr> substForallDict, Dictionary<VCExprVar, VCExpr> substExistsDict) {
- var prover = vState.checker.prover;
- var calls = vState.calls;
- Boogie2VCExprTranslator translator = prover.Context.BoogieExprTranslator;
- VCExprVar mvStateConstant = translator.LookupVariable(ModelViewInfo.MVState_ConstantDef);
- substExistsDict.Add(mvStateConstant, prover.VCExprGen.Integer(BigNum.FromInt(id)));
- Dictionary<VCExprVar, VCExpr> mapping = new Dictionary<VCExprVar, VCExpr>();
- foreach (var key in substForallDict.Keys)
- mapping[key] = substForallDict[key];
- foreach (var key in substExistsDict.Keys)
- mapping[key] = substExistsDict[key];
- calls.id2Vars[id] = mapping;
- }
-
- // Uniquely identifies a procedure call (the call expr, instance)
- public class BoogieCallExpr : IEquatable<BoogieCallExpr> {
- public NAryExpr expr;
- public int inlineCnt;
-
- public BoogieCallExpr(NAryExpr expr, int inlineCnt) {
- this.expr = expr;
- this.inlineCnt = inlineCnt;
- }
-
- public override int GetHashCode() {
- return expr.GetHashCode() + 131 * inlineCnt.GetHashCode();
- }
-
- public override bool Equals(object obj) {
- BoogieCallExpr that = obj as BoogieCallExpr;
- return (expr == that.expr && inlineCnt == that.inlineCnt);
- }
-
- public bool Equals(BoogieCallExpr that) {
- return (expr == that.expr && inlineCnt == that.inlineCnt);
- }
- }
-
- // This class is used to traverse VCs and do the following:
- // -- collect the set of FunctionCall nodes and label them with a unique string
- // -- Rename all other labels (so that calling this on the same VC results in
- // VCs with different labels each time)
- public class FCallHandler : MutatingVCExprVisitor<bool> {
- Dictionary<string/*!*/, StratifiedInliningInfo/*!*/>/*!*/ implName2StratifiedInliningInfo;
- public readonly Dictionary<int, Absy>/*!*/ mainLabel2absy;
- public Dictionary<BoogieCallExpr/*!*/, int>/*!*/ boogieExpr2Id;
- public Dictionary<BoogieCallExpr/*!*/, VCExpr>/*!*/ recordExpr2Var;
- public Dictionary<int, VCExprNAry/*!*/>/*!*/ id2Candidate;
- public Dictionary<int, VCExprVar/*!*/>/*!*/ id2ControlVar;
- public Dictionary<int, VCExpr> id2VC;
- public Dictionary<string/*!*/, int>/*!*/ label2Id;
- // candidate to block to Bool Control variable
- public Dictionary<int, Dictionary<Block, VCExpr>> candiate2block2controlVar;
- // Stores the candidate from which this one originated
- public Dictionary<int, int> candidateParent;
- // Mapping from candidate Id to the "si_unique_call" id that led to
- // this candidate. This is useful for getting persistent names for
- // candidates
- public Dictionary<int, int> candidate2callId;
- // A cache for candidate id to its persistent name
- public Dictionary<int, string> persistentNameCache;
- // Inverse of the above map
- public Dictionary<string, int> persistentNameInv;
- // Used to record candidates recently added
- public HashSet<int> recentlyAddedCandidates;
- // Name of main procedure
- private string mainProcName;
- // A map from candidate id to the VCExpr that represents its
- // first argument (used for obtaining concrete values in error trace)
- public Dictionary<int, VCExpr> argExprMap;
-
- // map from candidate to summary candidates
- public Dictionary<int, List<Tuple<VCExprVar, VCExpr>>> summaryCandidates;
- private Dictionary<string, List<Tuple<VCExprVar, VCExpr>>> summaryTemp;
- // set of all boolean guards of summaries
- public HashSet<VCExprVar> allSummaryConst;
-
- public HashSet<int> forcedCandidates;
-
- // User info -- to decrease/increase calculation of recursion bound
- public Dictionary<int, int> recursionIncrement;
- public Dictionary<string, int> extraRecursion;
-
- public HashSet<int> currCandidates;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
- Contract.Invariant(mainLabel2absy != null);
- Contract.Invariant(boogieExpr2Id != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(id2Candidate));
- Contract.Invariant(cce.NonNullDictionaryAndValues(id2ControlVar));
- Contract.Invariant(label2Id != null);
- }
-
- // Name of the procedure whose VC we're mutating
- string currProc;
-
- // The 0^th candidate is main
- static int candidateCount = 1;
- public int currInlineCount;
-
- public Dictionary<int, Dictionary<VCExprVar, VCExpr>> id2Vars;
-
- public FCallHandler(VCExpressionGenerator/*!*/ gen,
- Dictionary<string/*!*/, StratifiedInliningInfo/*!*/>/*!*/ implName2StratifiedInliningInfo,
- string mainProcName, Dictionary<int, Absy>/*!*/ mainLabel2absy)
- : base(gen) {
- Contract.Requires(gen != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
- Contract.Requires(mainLabel2absy != null);
- this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo;
- this.mainProcName = mainProcName;
- this.mainLabel2absy = mainLabel2absy;
- id2Candidate = new Dictionary<int, VCExprNAry>();
- id2ControlVar = new Dictionary<int, VCExprVar>();
- boogieExpr2Id = new Dictionary<BoogieCallExpr, int>();
- label2Id = new Dictionary<string, int>();
- currCandidates = new HashSet<int>();
- currInlineCount = 0;
- currProc = null;
- labelRenamer = new Dictionary<string, int>();
- labelRenamerInv = new Dictionary<string, string>();
- candidateParent = new Dictionary<int, int>();
- //callGraphMapping = new Dictionary<int, int>();
- recursionIncrement = new Dictionary<int, int>();
- candidate2callId = new Dictionary<int, int>();
- persistentNameCache = new Dictionary<int, string>();
- persistentNameInv = new Dictionary<string, int>();
- persistentNameCache[0] = "0";
- persistentNameInv["0"] = 0;
- recentlyAddedCandidates = new HashSet<int>();
- argExprMap = new Dictionary<int, VCExpr>();
- recordExpr2Var = new Dictionary<BoogieCallExpr, VCExpr>();
- candiate2block2controlVar = new Dictionary<int, Dictionary<Block, VCExpr>>();
-
- forcedCandidates = new HashSet<int>();
- extraRecursion = new Dictionary<string, int>();
-
- id2Vars = new Dictionary<int, Dictionary<VCExprVar, VCExpr>>();
- summaryCandidates = new Dictionary<int, List<Tuple<VCExprVar, VCExpr>>>();
- summaryTemp = new Dictionary<string, List<Tuple<VCExprVar, VCExpr>>>();
- allSummaryConst = new HashSet<VCExprVar>();
- id2VC = new Dictionary<int, VCExpr>();
- }
-
- public void Clear() {
- currCandidates = new HashSet<int>();
- }
-
- // Return the set of all candidates
- public HashSet<int> getAllCandidates() {
- var ret = new HashSet<int>(candidateParent.Keys);
- ret.Add(0);
- return ret;
- }
-
- // Given a candidate "id", let proc(id) be the
- // procedure corresponding to id. This procedure returns
- // the number of times proc(id) appears as an ancestor
- // of id. This is the same as the number of times we've
- // recursed on proc(id)
- public int getRecursionBound(int id) {
- int ret = 1;
- var str = getProc(id);
-
- while (candidateParent.ContainsKey(id)) {
- if (recursionIncrement.ContainsKey(id)) ret += recursionIncrement[id];
- id = candidateParent[id];
- if (getProc(id) == str && !forcedCandidates.Contains(id)) ret++;
- }
-
- // Usual
- if (!extraRecursion.ContainsKey(str))
- return ret;
-
- // Usual
- if (ret <= CommandLineOptions.Clo.RecursionBound - 1)
- return ret;
-
- // Special
- if (ret >= CommandLineOptions.Clo.RecursionBound &&
- ret <= CommandLineOptions.Clo.RecursionBound + extraRecursion[str] - 1)
- return CommandLineOptions.Clo.RecursionBound - 1;
-
- // Special
- return ret - extraRecursion[str];
- }
-
- // This procedure returns the stack depth of the candidate
- // (distance from main)
- public int getStackDepth(int id)
- {
- int ret = 1;
-
- while (candidateParent.ContainsKey(id))
- {
- ret++;
- id = candidateParent[id];
- }
-
- return ret;
- }
-
- // Set user-define increment/decrement to recursionBound
- public void setRecursionIncrement(int id, int incr) {
- if (recursionIncrement.ContainsKey(id))
- recursionIncrement[id] = incr;
- else
- recursionIncrement.Add(id, incr);
- }
-
- // Returns the name of the procedure corresponding to candidate id
- public string getProc(int id) {
- if (id == 0) return mainProcName;
-
- return (id2Candidate[id].Op as VCExprBoogieFunctionOp).Func.Name;
- }
-
- // Get a unique id for this candidate (dependent only on the Call
- // graph of the program). The persistent id is:
- // 0: for main
- // a_b_c: where a is the persistent id of parent, and b is the procedure name
- // and c is the unique call id (if any)
- public string getPersistentId(int top_id) {
- if (top_id == 0) return "0";
- Debug.Assert(candidateParent.ContainsKey(top_id));
- if (persistentNameCache.ContainsKey(top_id))
- return persistentNameCache[top_id];
-
- var parent_id = getPersistentId(candidateParent[top_id]);
- var call_id = candidate2callId.ContainsKey(top_id) ? candidate2callId[top_id] : -1;
- var ret = string.Format("{0}_131_{1}_131_{2}", parent_id, getProc(top_id), call_id);
- persistentNameCache[top_id] = ret;
- persistentNameInv[ret] = top_id;
- return ret;
- }
-
- public int getCandidateFromGraphNode(string n) {
- if (!persistentNameInv.ContainsKey(n)) {
- return -1;
- }
- return persistentNameInv[n];
- }
-
- private int GetNewId(VCExprNAry vc) {
- Contract.Requires(vc != null);
- int id = candidateCount;
-
- id2Candidate[id] = vc;
- id2ControlVar[id] = Gen.Variable("si_control_var_bool_" + id.ToString(), Microsoft.Boogie.Type.Bool);
-
- candidateCount++;
- currCandidates.Add(id);
- recentlyAddedCandidates.Add(id);
-
- return id;
- }
-
- private string GetLabel(int id) {
- Contract.Ensures(Contract.Result<string>() != null);
-
- string ret = "si_fcall_" + id.ToString();
- if (!label2Id.ContainsKey(ret))
- label2Id[ret] = id;
-
- return ret;
- }
-
- public int GetId(string label) {
- Contract.Requires(label != null);
- if (!label2Id.ContainsKey(label))
- return -1;
- return label2Id[label];
- }
-
- Dictionary<string, int> labelRenamer;
- Dictionary<string, string> labelRenamerInv;
-
- public string RenameAbsyLabel(string label) {
- Contract.Requires(label != null);
- Contract.Requires(label.Length >= 1);
- Contract.Ensures(Contract.Result<string>() != null);
-
- // Remove the sign from the label
- string nosign = label.Substring(1);
- var ret = "si_inline_" + currInlineCount.ToString() + "_" + nosign;
-
- if (!labelRenamer.ContainsKey(ret)) {
- var c = labelRenamer.Count + 11; // two digit labels only
- labelRenamer.Add(ret, c);
- labelRenamerInv.Add(c.ToString(), ret);
- }
- return labelRenamer[ret].ToString();
- }
-
- public string ParseRenamedAbsyLabel(string label, int cnt) {
- Contract.Requires(label != null);
- if (!labelRenamerInv.ContainsKey(label)) {
- return null;
- }
- var str = labelRenamerInv[label];
- var prefix = "si_inline_" + cnt.ToString() + "_";
- if (!str.StartsWith(prefix)) return null;
- return str.Substring(prefix.Length);
- }
-
- public void setCurrProc(string name) {
- Contract.Requires(name != null);
- currProc = name;
- Contract.Assert(implName2StratifiedInliningInfo.ContainsKey(name));
- }
-
- public void setCurrProcAsMain() {
- currProc = "";
- }
-
- // Return the formula (candidate IFF false)
- public VCExpr getFalseExpr(int candidateId) {
- //return Gen.Eq(VCExpressionGenerator.False, id2ControlVar[candidateId]);
- return Gen.Not(id2ControlVar[candidateId]);
- }
-
- // Return the formula (candidate IFF true)
- public VCExpr getTrueExpr(int candidateId) {
- return Gen.Eq(VCExpressionGenerator.True, id2ControlVar[candidateId]);
- }
-
- public Dictionary<int, Absy> getLabel2absy() {
- Contract.Ensures(Contract.Result<Dictionary<int, Absy>>() != null);
-
- Contract.Assert(currProc != null);
- if (currProc == "") {
- return mainLabel2absy;
- }
- return cce.NonNull(implName2StratifiedInliningInfo[currProc].label2absy);
- }
-
- // Finds labels and changes them:
- // si_fcall_id: if "id" corresponds to a tracked procedure call, then
- // si_control_var_candidateId
- // si_fcall_id: if "id" does not corresponds to a tracked procedure call, then
- // delete
- // num: si_inline_num
- //
- protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
- List<VCExpr/*!*/>/*!*/ newSubExprs,
- // has any of the subexpressions changed?
- bool changed,
- bool arg) {
- //Contract.Requires(originalNode != null);
- //Contract.Requires(cce.NonNullElements(newSubExprs));
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr ret;
- if (changed)
- ret = Gen.Function(originalNode.Op,
- newSubExprs, originalNode.TypeArguments);
- else
- ret = originalNode;
-
- VCExprLabelOp lop = originalNode.Op as VCExprLabelOp;
- if (lop == null) return ret;
- if (!(ret is VCExprNAry)) return ret;
-
- VCExprNAry retnary = (VCExprNAry)ret;
- Contract.Assert(retnary != null);
- string prefix = "si_fcall_"; // from Wlp.ssc::Cmd(...)
- if (lop.label.Substring(1).StartsWith(prefix)) {
- int id = Int32.Parse(lop.label.Substring(prefix.Length + 1));
- Dictionary<int, Absy> label2absy = getLabel2absy();
- Absy cmd = label2absy[id] as Absy;
- //label2absy.Remove(id);
-
- Contract.Assert(cmd != null);
- AssumeCmd acmd = cmd as AssumeCmd;
- Contract.Assert(acmd != null);
- NAryExpr naryExpr = acmd.Expr as NAryExpr;
- Contract.Assert(naryExpr != null);
-
- string calleeName = naryExpr.Fun.FunctionName;
-
- VCExprNAry callExpr = retnary[0] as VCExprNAry;
-
- if (implName2StratifiedInliningInfo.ContainsKey(calleeName)) {
- Contract.Assert(callExpr != null);
- int candidateId = GetNewId(callExpr);
- boogieExpr2Id[new BoogieCallExpr(naryExpr, currInlineCount)] = candidateId;
- candidateParent[candidateId] = currInlineCount;
- candiate2block2controlVar[candidateId] = new Dictionary<Block, VCExpr>();
-
- string label = GetLabel(candidateId);
- var unique_call_id = QKeyValue.FindIntAttribute(acmd.Attributes, "si_unique_call", -1);
- if (unique_call_id != -1)
- candidate2callId[candidateId] = unique_call_id;
-
- //return Gen.LabelPos(label, callExpr);
- return Gen.LabelPos(label, id2ControlVar[candidateId]);
- }
- else if (calleeName.StartsWith(recordProcName)) {
- Contract.Assert(callExpr != null);
- Debug.Assert(callExpr.Length == 1);
- Debug.Assert(callExpr[0] != null);
- recordExpr2Var[new BoogieCallExpr(naryExpr, currInlineCount)] = callExpr[0];
- return callExpr;
- }
- else {
- // callExpr can be null; this happens when the FunctionCall was on a
- // pure function (not procedure) and the function got inlined
- return retnary[0];
- }
- }
-
- // Else, rename label
- string newLabel = RenameAbsyLabel(lop.label);
- if (lop.pos) {
- return Gen.LabelPos(newLabel, retnary[0]);
- }
- else {
- return Gen.LabelNeg(newLabel, retnary[0]);
- }
-
- }
-
- // Upgrades summaryTemp to summaryCandidates by matching ensure clauses with
- // the appropriate candidate they came from
- public void matchSummaries() {
- var id2Set = new Dictionary<string, List<Tuple<int, HashSet<VCExprVar>>>>();
- foreach (var id in recentlyAddedCandidates) {
- var collect = new CollectVCVars();
- var proc = getProc(id);
- if (!id2Set.ContainsKey(proc)) id2Set.Add(proc, new List<Tuple<int, HashSet<VCExprVar>>>());
- id2Set[proc].Add(Tuple.Create(id, collect.Collect(id2Candidate[id], true)));
- }
-
- foreach (var kvp in summaryTemp) {
- Contract.Assert(id2Set.ContainsKey(kvp.Key));
- var ls = id2Set[kvp.Key];
- foreach (var tup in kvp.Value) {
- var collect = new CollectVCVars();
- var s1 = collect.Collect(tup.Item2, true);
- var found = false;
- foreach (var t in ls) {
- var s2 = t.Item2;
- if (s1.IsSubsetOf(s2)) {
- if (!summaryCandidates.ContainsKey(t.Item1))
- summaryCandidates.Add(t.Item1, new List<Tuple<VCExprVar, VCExpr>>());
- summaryCandidates[t.Item1].Add(tup);
- allSummaryConst.Add(tup.Item1);
- found = true;
- break;
- }
- }
- Contract.Assert(found);
- }
- }
- summaryTemp.Clear();
- }
-
- public IEnumerable<int> getInlinedCandidates() {
- return candidateParent.Keys.Except(currCandidates).Union(new int[] { 0 });
- }
-
- } // end FCallHandler
-
- // Collects the set of all VCExprVar in a given VCExpr
- class CollectVCVars : CollectingVCExprVisitor<HashSet<VCExprVar>, bool> {
- public override HashSet<VCExprVar> Visit(VCExprVar node, bool arg) {
- var ret = new HashSet<VCExprVar>();
- ret.Add(node);
- return ret;
- }
-
- protected override HashSet<VCExprVar> CombineResults(List<HashSet<VCExprVar>> results, bool arg) {
- var ret = new HashSet<VCExprVar>();
- results.Iter(s => ret.UnionWith(s));
- return ret;
- }
- }
-
- public class FCallInliner : MutatingVCExprVisitor<bool> {
- public Dictionary<int, VCExpr/*!*/>/*!*/ subst;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullDictionaryAndValues(subst));
- }
-
-
- public FCallInliner(VCExpressionGenerator gen)
- : base(gen) {
- Contract.Requires(gen != null);
- subst = new Dictionary<int, VCExpr>();
- }
-
- public void Clear() {
- subst = new Dictionary<int, VCExpr>();
- }
-
- protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
- List<VCExpr/*!*/>/*!*/ newSubExprs,
- // has any of the subexpressions changed?
- bool changed,
- bool arg) {
- //Contract.Requires(originalNode != null);Contract.Requires(newSubExprs != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr ret;
- if (changed)
- ret = Gen.Function(originalNode.Op, newSubExprs, originalNode.TypeArguments);
- else
- ret = originalNode;
-
- VCExprLabelOp lop = originalNode.Op as VCExprLabelOp;
- if (lop == null) return ret;
- if (!(ret is VCExprNAry)) return ret;
-
- string prefix = "si_fcall_"; // from FCallHandler::GetLabel
- if (lop.label.Substring(1).StartsWith(prefix)) {
- int id = Int32.Parse(lop.label.Substring(prefix.Length + 1));
- if (subst.ContainsKey(id)) {
- return subst[id];
- }
- }
- return ret;
- }
-
- } // end FCallInliner
-
-
-
- public class StratifiedInliningErrorReporter : ProverInterface.ErrorHandler {
- Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo;
- ProverInterface theoremProver;
- VerifierCallback callback;
- FCallHandler calls;
- StratifiedInliningInfo mainInfo;
- StratifiedVC mainVC;
-
- public bool underapproximationMode;
- public List<int> candidatesToExpand;
- public List<StratifiedCallSite> callSitesToExpand;
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(candidatesToExpand != null);
- Contract.Invariant(mainInfo != null);
- Contract.Invariant(callback != null);
- Contract.Invariant(theoremProver != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
- }
-
-
- public StratifiedInliningErrorReporter(Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo,
- ProverInterface theoremProver, VerifierCallback callback,
- StratifiedInliningInfo mainInfo) {
- Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
- Contract.Requires(theoremProver != null);
- Contract.Requires(callback != null);
- Contract.Requires(mainInfo != null);
- this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo;
- this.theoremProver = theoremProver;
- this.callback = callback;
- this.mainInfo = mainInfo;
- this.underapproximationMode = false;
- this.calls = null;
- this.candidatesToExpand = new List<int>();
- }
-
- public StratifiedInliningErrorReporter(Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo,
- ProverInterface theoremProver, VerifierCallback callback,
- StratifiedVC mainVC) {
- Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
- Contract.Requires(theoremProver != null);
- Contract.Requires(callback != null);
- Contract.Requires(mainVC != null);
- this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo;
- this.theoremProver = theoremProver;
- this.callback = callback;
- this.mainVC = mainVC;
- this.underapproximationMode = false;
- this.candidatesToExpand = new List<int>();
- }
-
- public void SetCandidateHandler(FCallHandler calls) {
- Contract.Requires(calls != null);
- this.calls = calls;
- }
-
- List<Tuple<int, int>> orderedStateIds;
-
- private Model.Element GetModelValue(Model m, Variable v, int candidateId) {
- // first, get the unique name
- string uniqueName;
-
- VCExprVar vvar = theoremProver.Context.BoogieExprTranslator.TryLookupVariable(v);
- if (vvar == null) {
- uniqueName = v.Name;
- }
- else {
- if (candidateId != 0) {
- Dictionary<VCExprVar, VCExpr> mapping = calls.id2Vars[candidateId];
- if (mapping.ContainsKey(vvar)) {
- VCExpr e = mapping[vvar];
- if (e is VCExprLiteral) {
- VCExprLiteral lit = (VCExprLiteral)e;
- return m.MkElement(lit.ToString());
- }
- vvar = (VCExprVar)mapping[vvar];
- }
- }
- uniqueName = theoremProver.Context.Lookup(vvar);
- }
-
- var f = m.TryGetFunc(uniqueName);
- if (f == null)
- return m.MkFunc("@undefined", 0).GetConstant();
- return f.GetConstant();
- }
-
- public readonly static int CALL = -1;
- public readonly static int RETURN = -2;
-
- public void PrintModel(Model model) {
- var filename = CommandLineOptions.Clo.ModelViewFile;
- if (model == null || filename == null) return;
-
- if (filename == "-") {
- model.Write(Console.Out);
- Console.Out.Flush();
- }
- else {
- using (var wr = new StreamWriter(filename, !Counterexample.firstModelFile)) {
- Counterexample.firstModelFile = false;
- model.Write(wr);
- }
- }
- }
-
- private void GetModelWithStates(Model m) {
- if (m == null) return;
- var mvInfo = mainInfo.mvInfo;
- var mvstates = m.TryGetFunc("$mv_state");
- if (mvstates == null)
- return;
-
- Contract.Assert(mvstates.Arity == 2);
-
- foreach (Variable v in mvInfo.AllVariables) {
- m.InitialState.AddBinding(v.Name, GetModelValue(m, v, 0));
- }
-
- int lastCandidate = 0;
- int lastCapturePoint = CALL;
- for (int i = 0; i < this.orderedStateIds.Count; ++i) {
- var s = orderedStateIds[i];
- int candidate = s.Item1;
- int capturePoint = s.Item2;
- string implName = calls.getProc(candidate);
- ModelViewInfo info = candidate == 0 ? mvInfo : implName2StratifiedInliningInfo[implName].mvInfo;
-
- if (capturePoint == CALL || capturePoint == RETURN) {
- lastCandidate = candidate;
- lastCapturePoint = capturePoint;
- continue;
- }
-
- Contract.Assume(0 <= capturePoint && capturePoint < info.CapturePoints.Count);
- VC.ModelViewInfo.Mapping map = info.CapturePoints[capturePoint];
- var prevInc = (lastCapturePoint != CALL && lastCapturePoint != RETURN && candidate == lastCandidate)
- ? info.CapturePoints[lastCapturePoint].IncarnationMap : new Dictionary<Variable, Expr>();
- var cs = m.MkState(map.Description);
-
- foreach (Variable v in info.AllVariables) {
- var e = (Expr)map.IncarnationMap[v];
-
- if (e == null) {
- if (lastCapturePoint == CALL || lastCapturePoint == RETURN) {
- cs.AddBinding(v.Name, GetModelValue(m, v, candidate));
- }
- continue;
- }
-
- if (lastCapturePoint != CALL && lastCapturePoint != RETURN && prevInc[v] == e) continue; // skip unchanged variables
-
- Model.Element elt;
- if (e is IdentifierExpr) {
- IdentifierExpr ide = (IdentifierExpr)e;
- elt = GetModelValue(m, ide.Decl, candidate);
- }
- else if (e is LiteralExpr) {
- LiteralExpr lit = (LiteralExpr)e;
- elt = m.MkElement(lit.Val.ToString());
- }
- else {
- Contract.Assume(false);
- elt = m.MkFunc(e.ToString(), 0).GetConstant();
- }
- cs.AddBinding(v.Name, elt);
- }
-
- lastCandidate = candidate;
- lastCapturePoint = capturePoint;
- }
-
- return;
- }
-
- public override void OnResourceExceeded(string message, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null)
- {
- //Contract.Requires(message != null);
- }
-
- public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) {
- if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) {
- model.Write(ErrorReporter.ModelWriter);
- ErrorReporter.ModelWriter.Flush();
- }
-
- // Timeout?
- if (proverOutcome != ProverInterface.Outcome.Invalid)
- return;
-
- candidatesToExpand = new List<int>();
- orderedStateIds = new List<Tuple<int, int>>();
- var cex = GenerateTrace(labels, model, 0, mainInfo.impl, mainInfo.mvInfo);
-
- if (underapproximationMode && cex != null) {
- //Debug.Assert(candidatesToExpand.All(calls.isSkipped));
- GetModelWithStates(model);
- callback.OnCounterexample(cex, null);
- this.PrintModel(model);
- }
- }
-
- private Counterexample GenerateTrace(IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel,
- int candidateId, Implementation procImpl, ModelViewInfo mvInfo) {
- Contract.Requires(cce.NonNullElements(labels));
- Contract.Requires(procImpl != null);
-
- Hashtable traceNodes = new Hashtable();
-
- if (!CommandLineOptions.Clo.SIBoolControlVC)
- {
- foreach (string s in labels)
- {
- Contract.Assert(s != null);
- var absylabel = calls.ParseRenamedAbsyLabel(s, candidateId);
-
- if (absylabel == null) continue;
-
- Absy absy;
-
- if (candidateId == 0)
- {
- absy = Label2Absy(absylabel);
- }
- else
- {
- absy = Label2Absy(procImpl.Name, absylabel);
- }
-
- if (traceNodes.ContainsKey(absy))
- System.Console.WriteLine("Warning: duplicate label: " + s + " read while tracing nodes");
- else
- traceNodes.Add(absy, null);
- }
- }
- else
- {
- Debug.Assert(CommandLineOptions.Clo.UseProverEvaluate, "Must use prover evaluate option with boolControlVC");
- var block = procImpl.Blocks[0];
- traceNodes.Add(block, null);
- while (true)
- {
- var gc = block.TransferCmd as GotoCmd;
- if (gc == null) break;
- Block next = null;
- foreach (var succ in gc.labelTargets)
- {
- var succtaken = (bool) theoremProver.Evaluate(calls.candiate2block2controlVar[candidateId][succ]);
- if (succtaken)
- {
- next = succ;
- traceNodes.Add(succ, null);
- break;
- }
- }
- Debug.Assert(next != null, "Must find a successor");
- Debug.Assert(traceNodes.ContainsKey(next), "CFG cannot be cyclic");
- block = next;
- }
- }
-
- List<Block> trace = new List<Block>();
- Block entryBlock = cce.NonNull(procImpl.Blocks[0]);
- Contract.Assert(entryBlock != null);
- Contract.Assert(traceNodes.Contains(entryBlock));
- trace.Add(entryBlock);
-
- var calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
- Counterexample newCounterexample = GenerateTraceRec(labels, errModel, mvInfo, candidateId, entryBlock, traceNodes, trace, calleeCounterexamples);
-
- return newCounterexample;
- }
-
- private Counterexample GenerateTraceRec(
- IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel, ModelViewInfo mvInfo,
- int candidateId,
- Block/*!*/ b, Hashtable/*!*/ traceNodes, List<Block>/*!*/ trace,
- Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples) {
- Contract.Requires(cce.NonNullElements(labels));
- Contract.Requires(b != null);
- Contract.Requires(traceNodes != null);
- Contract.Requires(trace != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples));
- // After translation, all potential errors come from asserts.
- while (true) {
- List<Cmd> cmds = b.Cmds;
- TransferCmd transferCmd = cce.NonNull(b.TransferCmd);
- for (int i = 0; i < cmds.Count; i++) {
- Cmd cmd = cce.NonNull(cmds[i]);
-
- // Skip if 'cmd' not contained in the trace or not an assert
- if ((cmd is AssertCmd && traceNodes.Contains(cmd)) ||
- (cmd is AssumeCmd && QKeyValue.FindBoolAttribute((cmd as AssumeCmd).Attributes, "exitAssert")))
- {
- var acmd = cmd as AssertCmd;
- if (acmd == null) { acmd = new AssertCmd(Token.NoToken, Expr.True); }
- Counterexample newCounterexample = AssertCmdToCounterexample(acmd, transferCmd, trace, errModel, mvInfo, theoremProver.Context);
- newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
- return newCounterexample;
- }
-
- // Counterexample generation for inlined procedures
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- if (assumeCmd == null)
- continue;
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- if (naryExpr == null)
- continue;
- string calleeName = naryExpr.Fun.FunctionName;
- Contract.Assert(calleeName != null);
-
- BinaryOperator binOp = naryExpr.Fun as BinaryOperator;
- if (binOp != null && binOp.Op == BinaryOperator.Opcode.And) {
- Expr expr = naryExpr.Args[0];
- NAryExpr mvStateExpr = expr as NAryExpr;
- if (mvStateExpr != null && mvStateExpr.Fun.FunctionName == ModelViewInfo.MVState_FunctionDef.Name) {
- LiteralExpr x = mvStateExpr.Args[1] as LiteralExpr;
- orderedStateIds.Add(new Tuple<int, int>(candidateId, x.asBigNum.ToInt));
- }
- }
-
- if (calleeName.StartsWith(recordProcName) && (errModel != null || CommandLineOptions.Clo.UseProverEvaluate)) {
- var expr = calls.recordExpr2Var[new BoogieCallExpr(naryExpr, candidateId)];
-
- // Record concrete value of the argument to this procedure
- var args = new List<object>();
- if (errModel == null && CommandLineOptions.Clo.UseProverEvaluate)
- {
- object exprv;
- try
- {
- exprv = theoremProver.Evaluate(expr);
- }
- catch (Exception)
- {
- exprv = null;
- }
- args.Add(exprv);
- }
- else
- {
- if (expr is VCExprIntLit)
- {
- args.Add(errModel.MkElement((expr as VCExprIntLit).Val.ToString()));
- }
- else if (expr == VCExpressionGenerator.True)
- {
- args.Add(errModel.MkElement("true"));
- }
- else if (expr == VCExpressionGenerator.False)
- {
- args.Add(errModel.MkElement("false"));
- }
- else if (expr is VCExprVar)
- {
- var idExpr = expr as VCExprVar;
- string name = theoremProver.Context.Lookup(idExpr);
- Contract.Assert(name != null);
- Model.Func f = errModel.TryGetFunc(name);
- if (f != null)
- {
- args.Add(f.GetConstant());
- }
- }
- else
- {
- Contract.Assert(false);
- }
- }
- calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] =
- new CalleeCounterexampleInfo(null, args);
- continue;
- }
-
- if (!implName2StratifiedInliningInfo.ContainsKey(calleeName))
- continue;
-
- Contract.Assert(calls != null);
-
- int calleeId = calls.boogieExpr2Id[new BoogieCallExpr(naryExpr, candidateId)];
-
- if (calls.currCandidates.Contains(calleeId)) {
- candidatesToExpand.Add(calleeId);
- }
- else {
- orderedStateIds.Add(new Tuple<int, int>(calleeId, StratifiedInliningErrorReporter.CALL));
- var calleeInfo = implName2StratifiedInliningInfo[calleeName];
- calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] =
- new CalleeCounterexampleInfo(GenerateTrace(labels, errModel, calleeId, calleeInfo.impl, calleeInfo.mvInfo), new List<object>());
- orderedStateIds.Add(new Tuple<int, int>(candidateId, StratifiedInliningErrorReporter.RETURN));
- }
- }
-
- GotoCmd gotoCmd = transferCmd as GotoCmd;
- if (gotoCmd != null) {
- b = null;
- foreach (Block bb in cce.NonNull(gotoCmd.labelTargets)) {
- Contract.Assert(bb != null);
- if (traceNodes.Contains(bb)) {
- trace.Add(bb);
- b = bb;
- break;
- }
- }
- if (b != null) continue;
- }
- return null;
- }
- }
-
- public override Absy Label2Absy(string label) {
- //Contract.Requires(label != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- int id = int.Parse(label);
- Contract.Assert(calls != null);
- return cce.NonNull((Absy)calls.mainLabel2absy[id]);
- }
-
- public Absy Label2Absy(string procName, string label) {
- Contract.Requires(label != null);
- Contract.Requires(procName != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- int id = int.Parse(label);
- Dictionary<int, Absy> l2a = cce.NonNull(implName2StratifiedInliningInfo[procName]).label2absy;
- return cce.NonNull((Absy)l2a[id]);
- }
-
- public override void OnProverWarning(string msg) {
- //Contract.Requires(msg != null);
- callback.OnWarning(msg);
- }
- }
-
- } // class StratifiedVCGen
-
- public class EmptyErrorHandler : ProverInterface.ErrorHandler
- {
- public override void OnModel(IList<string> labels, Model model, ProverInterface.Outcome proverOutcome)
- { }
- }
-
- public class InvalidProgramForSecureVc : Exception
- {
- public InvalidProgramForSecureVc(string msg) :
- base(msg) { }
- }
-
- public class SecureVCGen : VCGen
- {
- // Z3
- ProverInterface prover;
- // Handler
- ErrorReporter handler;
- // dump file
- public static TokenTextWriter outfile = null;
-
-
- public SecureVCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
- : base(program, logFilePath, appendLogFile, checkers)
- {
- prover = null;
- handler = null;
- if (CommandLineOptions.Clo.SecureVcGen != "" && outfile == null)
- {
- outfile = new TokenTextWriter(new StreamWriter(CommandLineOptions.Clo.SecureVcGen));
- CommandLineOptions.Clo.PrintInstrumented = true;
- var implsToVerify = new HashSet<string>(
- program.TopLevelDeclarations.OfType<Implementation>()
- .Where(impl => !impl.SkipVerification)
- .Select(impl => impl.Name));
-
- foreach (var decl in program.TopLevelDeclarations)
- {
- if (decl is NamedDeclaration && implsToVerify.Contains((decl as NamedDeclaration).Name))
- continue;
- decl.Emit(outfile, 0);
- }
- }
- }
-
- private Block GetExitBlock(Implementation impl)
- {
- var exitblocks = impl.Blocks.Where(blk => blk.TransferCmd is ReturnCmd);
- if (exitblocks.Count() == 1)
- return exitblocks.First();
- // create a new exit block
- var eb = new Block(Token.NoToken, "SVCeb", new List<Cmd>(), new ReturnCmd(Token.NoToken));
- foreach (var b in exitblocks)
- {
- b.TransferCmd = new GotoCmd(Token.NoToken, new List<Block> { eb });
- }
- impl.Blocks.Add(eb);
- return eb;
- }
-
- //static int LocalVarCounter = 0;
- private LocalVariable GetNewLocal(Variable v, string suffix)
- {
- return new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken,
- string.Format("svc_{0}_{1}", v.Name, suffix), v.TypedIdent.Type));
- }
-
- private void GenVc(Implementation impl, VerifierCallback collector)
- {
- if (impl.Proc.Requires.Any())
- throw new InvalidProgramForSecureVc("SecureVc: Requires not supported");
- if(impl.LocVars.Any(v => isVisible(v)))
- throw new InvalidProgramForSecureVc("SecureVc: Visible Local variables not allowed");
-
- // Desugar procedure calls
- DesugarCalls(impl);
-
- // Gather spec, remove existing ensures
- var secureAsserts = new List<AssertCmd>();
- var logicalAsserts = new List<AssertCmd>();
-
- foreach (var ens in impl.Proc.Ensures)
- {
- if(ens.Free)
- throw new InvalidProgramForSecureVc("SecureVc: Free Ensures not supported");
- var dd = new Duplicator();
- secureAsserts.Add(new AssertCmd(ens.tok, Expr.Not(ens.Condition)));
- logicalAsserts.Add(dd.VisitAssertCmd(new AssertCmd(ens.tok, ens.Condition)) as AssertCmd);
- }
- impl.Proc.Ensures.Clear();
-
- // Make a copy of the impl
- var dup = new Duplicator();
- var implDup = dup.VisitImplementation(impl);
-
- // Get exit block
- var eb = GetExitBlock(impl);
-
- // Create two blocks: one for secureAsserts, one for logical asserts
- var ebSecure = new Block(Token.NoToken, "svc_secure_asserts", new List<Cmd>(), new ReturnCmd(Token.NoToken));
- var ebLogical = new Block(Token.NoToken, "svc_logical_asserts", new List<Cmd>(), new ReturnCmd(Token.NoToken));
-
- eb.TransferCmd = new GotoCmd(eb.TransferCmd.tok, new List<Block> { ebSecure, ebLogical });
- impl.Blocks.Add(ebSecure);
- impl.Blocks.Add(ebLogical);
-
- // Rename spec, while create copies of the hidden variables
- var substOld = new Dictionary<Variable, Expr>();
- var substVarSpec = new Dictionary<Variable, Expr>();
- var substVarPath = new Dictionary<Variable, Expr>();
- foreach (var g in program.GlobalVariables)
- {
- if (!isHidden(g)) continue;
- var lv = GetNewLocal(g, "In");
- impl.LocVars.Add(lv);
- substOld.Add(g, Expr.Ident(lv));
- }
-
- for(int i = 0; i < impl.InParams.Count; i++)
- {
- var v = impl.Proc.InParams[i];
- if (!isHidden(v))
- {
- substVarSpec.Add(impl.Proc.InParams[i], Expr.Ident(impl.InParams[i]));
- continue;
- }
-
- var lv = GetNewLocal(v, "In");
- impl.LocVars.Add(lv);
- substVarSpec.Add(v, Expr.Ident(lv));
- substVarPath.Add(impl.InParams[i], Expr.Ident(lv));
- }
-
- for (int i = 0; i < impl.OutParams.Count; i++)
- {
- var v = impl.Proc.OutParams[i];
- if (!isHidden(v))
- {
- substVarSpec.Add(impl.Proc.OutParams[i], Expr.Ident(impl.OutParams[i]));
- continue;
- }
-
- var lv = GetNewLocal(v, "Out");
- impl.LocVars.Add(lv);
- substVarSpec.Add(v, Expr.Ident(lv));
- substVarPath.Add(impl.OutParams[i], Expr.Ident(lv));
- }
-
- foreach (var g in program.GlobalVariables)
- {
- if (!isHidden(g)) continue;
- if (!impl.Proc.Modifies.Any(ie => ie.Name == g.Name)) continue;
-
- var lv = GetNewLocal(g, "Out");
- impl.LocVars.Add(lv);
- substVarSpec.Add(g, Expr.Ident(lv));
- substVarPath.Add(g, Expr.Ident(lv));
- }
-
- secureAsserts = secureAsserts.ConvertAll(ac =>
- Substituter.ApplyReplacingOldExprs(
- Substituter.SubstitutionFromHashtable(substVarSpec),
- Substituter.SubstitutionFromHashtable(substOld),
- ac) as AssertCmd);
-
- var substVarProcToImpl = new Dictionary<Variable, Expr>();
- for (int i = 0; i < impl.InParams.Count; i++)
- substVarProcToImpl.Add(impl.Proc.InParams[i], Expr.Ident(impl.InParams[i]));
-
- for (int i = 0; i < impl.OutParams.Count; i++)
- substVarProcToImpl.Add(impl.Proc.OutParams[i], Expr.Ident(impl.OutParams[i]));
-
- logicalAsserts = logicalAsserts.ConvertAll(ac =>
- Substituter.Apply(Substituter.SubstitutionFromHashtable(substVarProcToImpl), ac)
- as AssertCmd);
-
- // Paths
- foreach (var path in GetAllPaths(implDup))
- {
- var wp = ComputeWP(implDup, path);
-
- // replace hidden variables to match those used in the spec
- wp = Substituter.ApplyReplacingOldExprs(
- Substituter.SubstitutionFromHashtable(substVarPath),
- Substituter.SubstitutionFromHashtable(substOld),
- wp);
-
- ebSecure.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.Not(wp)));
- }
-
- ebSecure.Cmds.AddRange(secureAsserts);
- ebLogical.Cmds.AddRange(logicalAsserts);
-
- if (outfile != null)
- {
- impl.Proc.Emit(outfile, 0);
- impl.Emit(outfile, 0);
- }
-
- ModelViewInfo mvInfo;
- ConvertCFG2DAG(impl);
- var gotoCmdOrigins = PassifyImpl(impl, out mvInfo);
-
- var gen = prover.VCExprGen;
- var exprGen = prover.Context.ExprGen;
- var translator = prover.Context.BoogieExprTranslator;
-
- var label2absy = new Dictionary<int, Absy>();
- VCGen.CodeExprConversionClosure cc = new VCGen.CodeExprConversionClosure(label2absy, prover.Context);
- translator.SetCodeExprConverter(cc.CodeExprToVerificationCondition);
- var implVc = gen.Not(GenerateVCAux(impl, null, label2absy, prover.Context));
-
- handler = new VCGen.ErrorReporter(gotoCmdOrigins, label2absy, impl.Blocks, incarnationOriginMap, collector, mvInfo, prover.Context, program);
-
- prover.Assert(implVc, true);
- }
-
- Expr ComputeWP(Implementation impl, List<Cmd> path)
- {
- Expr expr = Expr.True;
-
- // create constants for out varibles
- var subst = new Dictionary<Variable, Expr>();
- foreach (var g in impl.Proc.Modifies)
- {
- var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken,
- "svc_out_const_" + g.Name, g.Decl.TypedIdent.Type));
- subst.Add(c, g);
- expr = Expr.And(expr, Expr.Eq(Expr.Ident(c), g));
- }
-
- foreach (var v in impl.OutParams)
- {
- var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken,
- "svc_out_const_" + v.Name, v.TypedIdent.Type));
- subst.Add(c, Expr.Ident(v));
- expr = Expr.And(expr, Expr.Eq(Expr.Ident(c), Expr.Ident(v)));
- }
-
- // we need this technicality
- var subst1 = new Dictionary<Variable, Expr>();
- foreach (var g in program.GlobalVariables)
- {
- subst1.Add(g, new OldExpr(Token.NoToken, Expr.Ident(g)));
- }
-
- // Implicitly close with havoc of all the locals and OutParams
- path.Insert(0, new HavocCmd(Token.NoToken, new List<IdentifierExpr>(
- impl.LocVars.Select(v => Expr.Ident(v)).Concat(
- impl.OutParams.Select(v => Expr.Ident(v))))));
-
- for (int i = path.Count - 1; i >= 0; i--)
- {
- var cmd = path[i];
- if (cmd is AssumeCmd)
- {
- expr = Expr.And(expr, (cmd as AssumeCmd).Expr);
- }
- else if (cmd is AssignCmd)
- {
- var h = new Dictionary<Variable, Expr>();
- var acmd = cmd as AssignCmd;
- for (int j = 0; j < acmd.Lhss.Count; j++)
- {
- h.Add(acmd.Lhss[j].DeepAssignedVariable, acmd.Rhss[j]);
- }
- var s = Substituter.SubstitutionFromHashtable(h);
- expr = Substituter.Apply(s, expr);
- }
- else if (cmd is HavocCmd)
- {
- var h = new Dictionary<Variable, Expr>();
- var formals = new List<Variable>();
-
- var vc = new VariableCollector();
- vc.VisitExpr(expr);
-
- foreach (var ie in (cmd as HavocCmd).Vars)
- {
- if (!vc.usedVars.Contains(ie.Decl)) continue;
- var f = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken,
- ie.Decl.Name + "_formal", ie.Decl.TypedIdent.Type));
- h.Add(ie.Decl, Expr.Ident(f));
- formals.Add(f);
- }
- if (!formals.Any())
- continue;
- var s = Substituter.SubstitutionFromHashtable(h);
- expr = Substituter.Apply(s, expr);
- expr = new ExistsExpr(Token.NoToken, formals, expr);
- }
- else
- {
- throw new InvalidProgramForSecureVc(string.Format("Unhandled cmd: {0}", cmd));
- }
- }
-
- // Implicitly close with havoc of all the locals and OutParams
-
-
-
- expr = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst1), expr);
- expr = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst),
- Substituter.SubstitutionFromHashtable(new Dictionary<Variable,Expr>()), expr);
- expr.Typecheck(new TypecheckingContext(null));
- return expr;
- }
-
- // Generate all paths in the impl
- IEnumerable<List<Cmd>> GetAllPaths(Implementation impl)
- {
- var stk = new Stack<Tuple<Block, int>>();
- stk.Push(Tuple.Create(impl.Blocks[0], 0));
-
- while (stk.Any())
- {
- var tup = stk.Peek();
- if (tup.Item1.TransferCmd is ReturnCmd)
- {
- var ret = new List<Cmd>();
- var ls = stk.ToList();
- ls.Iter(t => ret.AddRange(t.Item1.Cmds));
- yield return ret;
-
- stk.Pop();
- continue;
- }
-
- stk.Pop();
-
- var gc = tup.Item1.TransferCmd as GotoCmd;
- if (gc.labelTargets.Count <= tup.Item2)
- continue;
-
- stk.Push(Tuple.Create(tup.Item1, tup.Item2 + 1));
- stk.Push(Tuple.Create(gc.labelTargets[tup.Item2], 0));
- }
- yield break;
- }
-
- bool isHidden(Variable v)
- {
- return QKeyValue.FindBoolAttribute(v.Attributes, "hidden");
- }
-
- bool isVisible(Variable v)
- {
- return !isHidden(v);
- }
-
- public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback)
- {
- Debug.Assert(this.program == program);
-
- // Record current time
- var startTime = DateTime.UtcNow;
-
- CommandLineOptions.Clo.ProverCCLimit = 1;
- prover = ProverInterface.CreateProver(program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime);
-
- // Flush any axioms that came with the program before we start SI on this implementation
- prover.AssertAxioms();
-
- GenVc(impl, callback);
-
- prover.Check();
- var outcome = prover.CheckOutcomeCore(handler);
- //var outcome = ProverInterface.Outcome.Valid;
-
- prover.Close();
-
-
-
- //Console.WriteLine("Answer = {0}", outcome);
-
- return ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
- }
- }
-
-} // namespace VC
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.IO;
+using Microsoft.Boogie;
+using Microsoft.Boogie.GraphUtil;
+using System.Diagnostics.Contracts;
+using Microsoft.Basetypes;
+using Microsoft.Boogie.VCExprAST;
+
+namespace VC {
+ using Bpl = Microsoft.Boogie;
+
+ public class StratifiedVC {
+ public StratifiedInliningInfo info;
+ public int id;
+ public List<VCExprVar> interfaceExprVars;
+
+ // boolControlVC (block -> its bool variable)
+ public Dictionary<Block, VCExpr> blockToControlVar;
+ // While using labels (block -> its label)
+ public Dictionary<Absy, string> block2label;
+
+ public Dictionary<Block, List<StratifiedCallSite>> callSites;
+ public Dictionary<Block, List<StratifiedCallSite>> recordProcCallSites;
+ public VCExpr vcexpr;
+
+ // Must-Reach Information
+ Dictionary<Block, VCExprVar> mustReachVar;
+ List<VCExprLetBinding> mustReachBindings;
+
+ public StratifiedVC(StratifiedInliningInfo siInfo, HashSet<string> procCalls) {
+ info = siInfo;
+ info.GenerateVC();
+ var vcgen = info.vcgen;
+ var prover = vcgen.prover;
+ VCExpressionGenerator gen = prover.VCExprGen;
+ var bet = prover.Context.BoogieExprTranslator;
+
+ vcexpr = info.vcexpr;
+ id = vcgen.CreateNewId();
+ interfaceExprVars = new List<VCExprVar>();
+ Dictionary<VCExprVar, VCExpr> substDict = new Dictionary<VCExprVar, VCExpr>();
+ foreach (VCExprVar v in info.interfaceExprVars) {
+ VCExprVar newVar = vcgen.CreateNewVar(v.Type);
+ interfaceExprVars.Add(newVar);
+ substDict.Add(v, newVar);
+ }
+ foreach (VCExprVar v in info.privateExprVars) {
+ substDict.Add(v, vcgen.CreateNewVar(v.Type));
+ }
+ if(info.controlFlowVariable != null)
+ substDict.Add(bet.LookupVariable(info.controlFlowVariable), gen.Integer(BigNum.FromInt(id)));
+ VCExprSubstitution subst = new VCExprSubstitution(substDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
+ SubstitutingVCExprVisitor substVisitor = new SubstitutingVCExprVisitor(prover.VCExprGen);
+ vcexpr = substVisitor.Mutate(vcexpr, subst);
+
+ // For BoolControlVC generation
+ if (info.blockToControlVar != null)
+ {
+ blockToControlVar = new Dictionary<Block, VCExpr>();
+ foreach (var tup in info.blockToControlVar)
+ blockToControlVar.Add(tup.Key, substDict[tup.Value]);
+ }
+
+ // labels
+ if (info.label2absy != null)
+ {
+ block2label = new Dictionary<Absy, string>();
+ vcexpr = RenameVCExprLabels.Apply(vcexpr, info.vcgen.prover.VCExprGen, info.label2absy, block2label);
+ }
+
+ if(procCalls != null)
+ vcexpr = RemoveProcedureCalls.Apply(vcexpr, info.vcgen.prover.VCExprGen, procCalls);
+
+ callSites = new Dictionary<Block, List<StratifiedCallSite>>();
+ foreach (Block b in info.callSites.Keys) {
+ callSites[b] = new List<StratifiedCallSite>();
+ foreach (CallSite cs in info.callSites[b]) {
+ callSites[b].Add(new StratifiedCallSite(cs, substVisitor, subst));
+ }
+ }
+
+ recordProcCallSites = new Dictionary<Block, List<StratifiedCallSite>>();
+ foreach (Block b in info.recordProcCallSites.Keys) {
+ recordProcCallSites[b] = new List<StratifiedCallSite>();
+ foreach (CallSite cs in info.recordProcCallSites[b]) {
+ recordProcCallSites[b].Add(new StratifiedCallSite(cs, substVisitor, subst));
+ }
+ }
+ }
+
+ public VCExpr MustReach(Block block)
+ {
+ Contract.Assert(!CommandLineOptions.Clo.UseLabels);
+
+ // This information is computed lazily
+ if (mustReachBindings == null)
+ {
+ var vcgen = info.vcgen;
+ var gen = vcgen.prover.VCExprGen;
+ var impl = info.impl;
+ mustReachVar = new Dictionary<Block, VCExprVar>();
+ mustReachBindings = new List<VCExprLetBinding>();
+ foreach (Block b in impl.Blocks)
+ mustReachVar[b] = vcgen.CreateNewVar(Bpl.Type.Bool);
+
+ var dag = new Graph<Block>();
+ dag.AddSource(impl.Blocks[0]);
+ foreach (Block b in impl.Blocks)
+ {
+ var gtc = b.TransferCmd as GotoCmd;
+ if (gtc != null)
+ foreach (Block dest in gtc.labelTargets)
+ dag.AddEdge(dest, b);
+ }
+ IEnumerable sortedNodes = dag.TopologicalSort();
+
+ foreach (Block currBlock in dag.TopologicalSort())
+ {
+ if (currBlock == impl.Blocks[0])
+ {
+ mustReachBindings.Add(gen.LetBinding(mustReachVar[currBlock], VCExpressionGenerator.True));
+ continue;
+ }
+
+ VCExpr expr = VCExpressionGenerator.False;
+ foreach (var pred in dag.Successors(currBlock))
+ {
+ VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(gen.Integer(BigNum.FromInt(id)), gen.Integer(BigNum.FromInt(pred.UniqueId)));
+ VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(currBlock.UniqueId)));
+ expr = gen.Or(expr, gen.And(mustReachVar[pred], controlTransferExpr));
+ }
+ mustReachBindings.Add(gen.LetBinding(mustReachVar[currBlock], expr));
+ }
+ }
+
+ Contract.Assert(mustReachVar.ContainsKey(block));
+ return info.vcgen.prover.VCExprGen.Let(mustReachBindings, mustReachVar[block]);
+ }
+
+ public List<StratifiedCallSite> CallSites {
+ get {
+ var ret = new List<StratifiedCallSite>();
+ foreach (var b in callSites.Keys) {
+ foreach (var cs in callSites[b]) {
+ ret.Add(cs);
+ }
+ }
+ return ret;
+ }
+ }
+
+ public List<StratifiedCallSite> RecordProcCallSites {
+ get {
+ var ret = new List<StratifiedCallSite>();
+ foreach (var b in recordProcCallSites.Keys) {
+ foreach (var cs in recordProcCallSites[b]) {
+ ret.Add(cs);
+ }
+ }
+ return ret;
+ }
+ }
+
+ public override string ToString()
+ {
+ return info.impl.Name;
+ }
+ }
+
+ // Rename all labels in a VC to (globally) fresh labels
+ class RenameVCExprLabels : MutatingVCExprVisitor<bool>
+ {
+ Dictionary<int, Absy> label2absy;
+ Dictionary<Absy, string> absy2newlabel;
+ static int counter = 11;
+
+ RenameVCExprLabels(VCExpressionGenerator gen, Dictionary<int, Absy> label2absy, Dictionary<Absy, string> absy2newlabel)
+ : base(gen)
+ {
+ this.label2absy = label2absy;
+ this.absy2newlabel = absy2newlabel;
+ }
+
+ public static VCExpr Apply(VCExpr expr, VCExpressionGenerator gen, Dictionary<int, Absy> label2absy, Dictionary<Absy, string> absy2newlabel)
+ {
+ return (new RenameVCExprLabels(gen, label2absy, absy2newlabel)).Mutate(expr, true);
+ }
+
+ // Finds labels and changes them to a globally unique label:
+ protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
+ List<VCExpr/*!*/>/*!*/ newSubExprs,
+ bool changed,
+ bool arg)
+ {
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ VCExpr ret;
+ if (changed)
+ ret = Gen.Function(originalNode.Op,
+ newSubExprs, originalNode.TypeArguments);
+ else
+ ret = originalNode;
+
+ VCExprLabelOp lop = originalNode.Op as VCExprLabelOp;
+ if (lop == null) return ret;
+ if (!(ret is VCExprNAry)) return ret;
+ VCExprNAry retnary = (VCExprNAry)ret;
+
+ // remove the sign
+ var nosign = 0;
+ if (!Int32.TryParse(lop.label.Substring(1), out nosign))
+ return ret;
+
+ if (!label2absy.ContainsKey(nosign))
+ return ret;
+
+ string newLabel = "SI" + counter.ToString();
+ counter++;
+ absy2newlabel[label2absy[nosign]] = newLabel;
+
+ if (lop.pos)
+ {
+ return Gen.LabelPos(newLabel, retnary[0]);
+ }
+ else
+ {
+ return Gen.LabelNeg(newLabel, retnary[0]);
+ }
+
+ }
+ }
+
+ // Remove the uninterpreted function calls that substitute procedure calls
+ class RemoveProcedureCalls : MutatingVCExprVisitor<bool>
+ {
+ HashSet<string> procNames;
+
+ RemoveProcedureCalls(VCExpressionGenerator gen, HashSet<string> procNames)
+ : base(gen)
+ {
+ this.procNames = procNames;
+ }
+
+ public static VCExpr Apply(VCExpr expr, VCExpressionGenerator gen, HashSet<string> procNames)
+ {
+ return (new RemoveProcedureCalls(gen, procNames)).Mutate(expr, true);
+ }
+
+ // Finds labels and changes them to a globally unique label:
+ protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
+ List<VCExpr/*!*/>/*!*/ newSubExprs,
+ bool changed,
+ bool arg)
+ {
+ //Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ VCExpr ret;
+ if (changed)
+ ret = Gen.Function(originalNode.Op,
+ newSubExprs, originalNode.TypeArguments);
+ else
+ ret = originalNode;
+
+ if (!(ret is VCExprNAry)) return ret;
+ VCExprNAry retnary = (VCExprNAry)ret;
+ if (!(retnary.Op is VCExprBoogieFunctionOp))
+ return ret;
+
+ var fcall = (retnary.Op as VCExprBoogieFunctionOp).Func.Name;
+ if (procNames.Contains(fcall))
+ return VCExpressionGenerator.True;
+ return ret;
+ }
+ }
+
+
+ public class CallSite {
+ public string calleeName;
+ public List<VCExpr> interfaceExprs;
+ public Block block;
+ public int numInstr; // for TraceLocation
+ public VCExprVar callSiteVar;
+ public QKeyValue Attributes; // attributes on the call cmd
+ public CallSite(string callee, List<VCExpr> interfaceExprs, VCExprVar callSiteVar, Block block, int numInstr, QKeyValue Attributes)
+ {
+ this.calleeName = callee;
+ this.interfaceExprs = interfaceExprs;
+ this.callSiteVar = callSiteVar;
+ this.block = block;
+ this.numInstr = numInstr;
+ this.Attributes = Attributes;
+ }
+ }
+
+ public class StratifiedCallSite {
+ public CallSite callSite;
+ public List<VCExpr> interfaceExprs;
+ public VCExpr callSiteExpr;
+
+ public StratifiedCallSite(CallSite cs, SubstitutingVCExprVisitor substVisitor, VCExprSubstitution subst) {
+ callSite = cs;
+ interfaceExprs = new List<VCExpr>();
+ foreach (VCExpr v in cs.interfaceExprs) {
+ interfaceExprs.Add(substVisitor.Mutate(v, subst));
+ }
+ if (callSite.callSiteVar != null)
+ callSiteExpr = substVisitor.Mutate(callSite.callSiteVar, subst);
+ }
+
+ public VCExpr Attach(StratifiedVC svc) {
+ Contract.Assert(interfaceExprs.Count == svc.interfaceExprVars.Count);
+ StratifiedInliningInfo info = svc.info;
+ ProverInterface prover = info.vcgen.prover;
+ VCExpressionGenerator gen = prover.VCExprGen;
+
+ Dictionary<VCExprVar, VCExpr> substDict = new Dictionary<VCExprVar, VCExpr>();
+ for (int i = 0; i < svc.interfaceExprVars.Count; i++) {
+ VCExprVar v = svc.interfaceExprVars[i];
+ substDict.Add(v, interfaceExprs[i]);
+ }
+ VCExprSubstitution subst = new VCExprSubstitution(substDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
+ SubstitutingVCExprVisitor substVisitor = new SubstitutingVCExprVisitor(prover.VCExprGen);
+ svc.vcexpr = substVisitor.Mutate(svc.vcexpr, subst);
+ foreach (StratifiedCallSite scs in svc.CallSites) {
+ List<VCExpr> newInterfaceExprs = new List<VCExpr>();
+ foreach (VCExpr expr in scs.interfaceExprs) {
+ newInterfaceExprs.Add(substVisitor.Mutate(expr, subst));
+ }
+ scs.interfaceExprs = newInterfaceExprs;
+ }
+ foreach (StratifiedCallSite scs in svc.RecordProcCallSites) {
+ List<VCExpr> newInterfaceExprs = new List<VCExpr>();
+ foreach (VCExpr expr in scs.interfaceExprs) {
+ newInterfaceExprs.Add(substVisitor.Mutate(expr, subst));
+ }
+ scs.interfaceExprs = newInterfaceExprs;
+ }
+ //return gen.Implies(callSiteExpr, svc.vcexpr);
+ return svc.vcexpr;
+ }
+
+ public override string ToString()
+ {
+ return callSite.calleeName;
+ }
+ }
+
+ public class StratifiedInliningInfo {
+ public StratifiedVCGenBase vcgen;
+ public Implementation impl;
+ public Function function;
+ public Variable controlFlowVariable;
+ public Cmd exitAssertCmd;
+ public VCExpr vcexpr;
+ public List<VCExprVar> interfaceExprVars;
+ public List<VCExprVar> privateExprVars;
+ public Dictionary<int, Absy> label2absy;
+ public ModelViewInfo mvInfo;
+ public Dictionary<Block, List<CallSite>> callSites;
+ public Dictionary<Block, List<CallSite>> recordProcCallSites;
+ public bool initialized { get; private set; }
+ // Instrumentation to apply after PassiveImpl, but before VCGen
+ Action<Implementation> PassiveImplInstrumentation;
+
+ // boolControlVC (block -> its Bool variable)
+ public Dictionary<Block, VCExprVar> blockToControlVar;
+
+ public StratifiedInliningInfo(Implementation implementation, StratifiedVCGenBase stratifiedVcGen, Action<Implementation> PassiveImplInstrumentation) {
+ vcgen = stratifiedVcGen;
+ impl = implementation;
+ this.PassiveImplInstrumentation = PassiveImplInstrumentation;
+
+ List<Variable> functionInterfaceVars = new List<Variable>();
+ foreach (Variable v in vcgen.program.GlobalVariables) {
+ functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
+ }
+ foreach (Variable v in impl.InParams) {
+ functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
+ }
+ foreach (Variable v in impl.OutParams) {
+ functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
+ }
+ foreach (IdentifierExpr e in impl.Proc.Modifies) {
+ if (e.Decl == null) continue;
+ functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", e.Decl.TypedIdent.Type), true));
+ }
+ Formal returnVar = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Bpl.Type.Bool), false);
+ function = new Function(Token.NoToken, impl.Name, functionInterfaceVars, returnVar);
+ vcgen.prover.Context.DeclareFunction(function, "");
+
+ List<Expr> exprs = new List<Expr>();
+ foreach (Variable v in vcgen.program.GlobalVariables) {
+ Contract.Assert(v != null);
+ exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
+ }
+ foreach (Variable v in impl.Proc.InParams) {
+ Contract.Assert(v != null);
+ exprs.Add(new IdentifierExpr(Token.NoToken, v));
+ }
+ foreach (Variable v in impl.Proc.OutParams) {
+ Contract.Assert(v != null);
+ exprs.Add(new IdentifierExpr(Token.NoToken, v));
+ }
+ foreach (IdentifierExpr ie in impl.Proc.Modifies) {
+ Contract.Assert(ie != null);
+ if (ie.Decl == null)
+ continue;
+ exprs.Add(ie);
+ }
+ Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
+ impl.Proc.Ensures.Add(new Ensures(Token.NoToken, true, freePostExpr, "", new QKeyValue(Token.NoToken, "si_fcall", new List<object>(), null)));
+
+ initialized = false;
+ }
+
+ public void GenerateVCBoolControl()
+ {
+ Debug.Assert(!initialized);
+ Debug.Assert(CommandLineOptions.Clo.SIBoolControlVC);
+
+ // fix names for exit variables
+ var outputVariables = new List<Variable>();
+ var assertConjuncts = new List<Expr>();
+ foreach (Variable v in impl.OutParams)
+ {
+ Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
+ outputVariables.Add(c);
+ Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
+ assertConjuncts.Add(eqExpr);
+ }
+ foreach (IdentifierExpr e in impl.Proc.Modifies)
+ {
+ if (e.Decl == null) continue;
+ Variable v = e.Decl;
+ Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
+ outputVariables.Add(c);
+ Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
+ assertConjuncts.Add(eqExpr);
+ }
+ exitAssertCmd = new AssumeCmd(Token.NoToken, Expr.BinaryTreeAnd(assertConjuncts));
+ (exitAssertCmd as AssumeCmd).Attributes = new QKeyValue(Token.NoToken, "exitAssert", new List<object>(), null);
+
+ // no need for label2absy
+ label2absy = new Dictionary<int, Absy>();
+
+ // Passify
+ Program program = vcgen.program;
+ ProverInterface proverInterface = vcgen.prover;
+ vcgen.ConvertCFG2DAG(impl);
+ vcgen.PassifyImpl(impl, out mvInfo);
+
+ VCExpressionGenerator gen = proverInterface.VCExprGen;
+ var exprGen = proverInterface.Context.ExprGen;
+ var translator = proverInterface.Context.BoogieExprTranslator;
+
+ // add a boolean variable at each call site
+ vcgen.InstrumentCallSites(impl);
+
+ // typecheck
+ var tc = new TypecheckingContext(null);
+ impl.Typecheck(tc);
+
+ ///////////////////
+ // Generate the VC
+ ///////////////////
+
+ // block -> bool variable
+ blockToControlVar = new Dictionary<Block, VCExprVar>();
+ foreach (var b in impl.Blocks)
+ blockToControlVar.Add(b, gen.Variable(b.Label + "_holds", Bpl.Type.Bool));
+
+ vcexpr = VCExpressionGenerator.True;
+ foreach (var b in impl.Blocks)
+ {
+ // conjoin all assume cmds
+ VCExpr c = VCExpressionGenerator.True;
+ foreach (var cmd in b.Cmds)
+ {
+ var acmd = cmd as AssumeCmd;
+ if (acmd == null)
+ {
+ Debug.Assert(cmd is AssertCmd && (cmd as AssertCmd).Expr is LiteralExpr &&
+ ((cmd as AssertCmd).Expr as LiteralExpr).IsTrue);
+ continue;
+ }
+ var expr = translator.Translate(acmd.Expr);
+ // Label the assume if it is a procedure call
+ NAryExpr naryExpr = acmd.Expr as NAryExpr;
+ if (naryExpr != null && naryExpr.Fun is FunctionCall)
+ {
+ var id = acmd.UniqueId;
+ label2absy[id] = acmd;
+ expr = gen.LabelPos(cce.NonNull("si_fcall_" + id.ToString()), expr);
+ }
+
+ c = gen.AndSimp(c, expr);
+ }
+
+ // block implies a disjunction of successors
+ Debug.Assert(!(b.TransferCmd is ReturnExprCmd), "Not supported");
+ var gc = b.TransferCmd as GotoCmd;
+ if (gc != null)
+ {
+ VCExpr succ = VCExpressionGenerator.False;
+ foreach (var sb in gc.labelTargets)
+ succ = gen.OrSimp(succ, blockToControlVar[sb]);
+ c = gen.AndSimp(c, succ);
+ }
+ else
+ {
+ // nothing to do
+ }
+ vcexpr = gen.AndSimp(vcexpr, gen.Eq(blockToControlVar[b], c));
+ }
+ // assert start block
+ vcexpr = gen.AndSimp(vcexpr, blockToControlVar[impl.Blocks[0]]);
+
+ //Console.WriteLine("VC of {0}: {1}", impl.Name, vcexpr);
+ // Collect other information
+ callSites = vcgen.CollectCallSites(impl);
+ recordProcCallSites = vcgen.CollectRecordProcedureCallSites(impl);
+
+ // record interface variables
+ privateExprVars = new List<VCExprVar>();
+ foreach (Variable v in impl.LocVars)
+ {
+ privateExprVars.Add(translator.LookupVariable(v));
+ }
+ foreach (Variable v in impl.OutParams)
+ {
+ privateExprVars.Add(translator.LookupVariable(v));
+ }
+ privateExprVars.AddRange(blockToControlVar.Values);
+
+ interfaceExprVars = new List<VCExprVar>();
+ foreach (Variable v in program.GlobalVariables)
+ {
+ interfaceExprVars.Add(translator.LookupVariable(v));
+ }
+ foreach (Variable v in impl.InParams)
+ {
+ interfaceExprVars.Add(translator.LookupVariable(v));
+ }
+ foreach (Variable v in outputVariables)
+ {
+ interfaceExprVars.Add(translator.LookupVariable(v));
+ }
+ }
+
+ public void GenerateVC() {
+ if (initialized) return;
+ if (CommandLineOptions.Clo.SIBoolControlVC)
+ {
+ GenerateVCBoolControl();
+ initialized = true;
+ return;
+ }
+ List<Variable> outputVariables = new List<Variable>();
+ List<Expr> assertConjuncts = new List<Expr>();
+ foreach (Variable v in impl.OutParams) {
+ Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
+ outputVariables.Add(c);
+ Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
+ assertConjuncts.Add(eqExpr);
+ }
+ foreach (IdentifierExpr e in impl.Proc.Modifies) {
+ if (e.Decl == null) continue;
+ Variable v = e.Decl;
+ Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
+ outputVariables.Add(c);
+ Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
+ assertConjuncts.Add(eqExpr);
+ }
+ exitAssertCmd = new AssertCmd(Token.NoToken, Expr.Not(Expr.BinaryTreeAnd(assertConjuncts)));
+
+ Program program = vcgen.program;
+ ProverInterface proverInterface = vcgen.prover;
+ vcgen.ConvertCFG2DAG(impl);
+ vcgen.PassifyImpl(impl, out mvInfo);
+
+ VCExpressionGenerator gen = proverInterface.VCExprGen;
+ var exprGen = proverInterface.Context.ExprGen;
+ var translator = proverInterface.Context.BoogieExprTranslator;
+
+ VCExpr controlFlowVariableExpr = null;
+ if (!CommandLineOptions.Clo.UseLabels) {
+ controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "@cfc", Microsoft.Boogie.Type.Int));
+ controlFlowVariableExpr = translator.LookupVariable(controlFlowVariable);
+ }
+
+ vcgen.InstrumentCallSites(impl);
+
+ if (PassiveImplInstrumentation != null)
+ PassiveImplInstrumentation(impl);
+
+ label2absy = new Dictionary<int, Absy>();
+ VCGen.CodeExprConversionClosure cc = new VCGen.CodeExprConversionClosure(label2absy, proverInterface.Context);
+ translator.SetCodeExprConverter(cc.CodeExprToVerificationCondition);
+ vcexpr = gen.Not(vcgen.GenerateVCAux(impl, controlFlowVariableExpr, label2absy, proverInterface.Context));
+
+ if (controlFlowVariableExpr != null)
+ {
+ VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(controlFlowVariableExpr, exprGen.Integer(BigNum.ZERO));
+ VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
+ vcexpr = exprGen.And(eqExpr, vcexpr);
+ }
+
+ callSites = vcgen.CollectCallSites(impl);
+ recordProcCallSites = vcgen.CollectRecordProcedureCallSites(impl);
+
+ privateExprVars = new List<VCExprVar>();
+ foreach (Variable v in impl.LocVars) {
+ privateExprVars.Add(translator.LookupVariable(v));
+ }
+ foreach (Variable v in impl.OutParams) {
+ privateExprVars.Add(translator.LookupVariable(v));
+ }
+
+ interfaceExprVars = new List<VCExprVar>();
+ foreach (Variable v in program.GlobalVariables) {
+ interfaceExprVars.Add(translator.LookupVariable(v));
+ }
+ foreach (Variable v in impl.InParams) {
+ interfaceExprVars.Add(translator.LookupVariable(v));
+ }
+ foreach (Variable v in outputVariables) {
+ interfaceExprVars.Add(translator.LookupVariable(v));
+ }
+
+ initialized = true;
+ }
+ }
+
+ public abstract class StratifiedVCGenBase : VCGen {
+ public readonly static string recordProcName = "boogie_si_record";
+ public readonly static string callSiteVarAttr = "callSiteVar";
+ public Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo;
+ public ProverInterface prover;
+
+ public StratifiedVCGenBase(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers, Action<Implementation> PassiveImplInstrumentation)
+ : base(program, logFilePath, appendLogFile, checkers) {
+ implName2StratifiedInliningInfo = new Dictionary<string, StratifiedInliningInfo>();
+ prover = ProverInterface.CreateProver(program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime);
+ foreach (var impl in program.Implementations) {
+ implName2StratifiedInliningInfo[impl.Name] = new StratifiedInliningInfo(impl, this, PassiveImplInstrumentation);
+ }
+ GenerateRecordFunctions();
+ }
+
+ private void GenerateRecordFunctions() {
+ foreach (var proc in program.Procedures) {
+ if (!proc.Name.StartsWith(recordProcName)) continue;
+ Contract.Assert(proc.InParams.Count == 1);
+
+ // Make a new function
+ TypedIdent ti = new TypedIdent(Token.NoToken, "", Bpl.Type.Bool);
+ Contract.Assert(ti != null);
+ Formal returnVar = new Formal(Token.NoToken, ti, false);
+ Contract.Assert(returnVar != null);
+
+ // Get record type
+ var argtype = proc.InParams[0].TypedIdent.Type;
+
+ var ins = new List<Variable>();
+ ins.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "x", argtype), true));
+
+ var recordFunc = new Function(Token.NoToken, proc.Name, ins, returnVar);
+ prover.Context.DeclareFunction(recordFunc, "");
+
+ var exprs = new List<Expr>();
+ exprs.Add(new IdentifierExpr(Token.NoToken, proc.InParams[0]));
+
+ Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(recordFunc), exprs);
+ proc.Ensures.Add(new Ensures(true, freePostExpr));
+ }
+ }
+
+ public override void Close() {
+ prover.Close();
+ base.Close();
+ }
+
+ public void InstrumentCallSites(Implementation implementation) {
+ var callSiteId = 0;
+ foreach (Block block in implementation.Blocks) {
+ List<Cmd> newCmds = new List<Cmd>();
+ for (int i = 0; i < block.Cmds.Count; i++) {
+ Cmd cmd = block.Cmds[i];
+ newCmds.Add(cmd);
+ AssumeCmd assumeCmd = cmd as AssumeCmd;
+ if (assumeCmd == null) continue;
+ NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
+ if (naryExpr == null) continue;
+ if (!implName2StratifiedInliningInfo.ContainsKey(naryExpr.Fun.FunctionName)) continue;
+ Variable callSiteVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "SICS" + callSiteId, Microsoft.Boogie.Type.Bool));
+ implementation.LocVars.Add(callSiteVar);
+ var toInsert = new AssumeCmd(Token.NoToken, new IdentifierExpr(Token.NoToken, callSiteVar),
+ new QKeyValue(Token.NoToken, callSiteVarAttr, new List<object>(), null));
+ newCmds.Add(toInsert);
+ callSiteId++;
+ }
+ block.Cmds = newCmds;
+ }
+ }
+
+ public Dictionary<Block, List<CallSite>> CollectCallSites(Implementation implementation) {
+ var callSites = new Dictionary<Block, List<CallSite>>();
+ foreach (Block block in implementation.Blocks) {
+ for (int i = 0; i < block.Cmds.Count; i++) {
+ Cmd cmd = block.Cmds[i];
+ AssumeCmd assumeCmd = cmd as AssumeCmd;
+ if (assumeCmd == null) continue;
+ NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
+ if (naryExpr == null) continue;
+ if (!implName2StratifiedInliningInfo.ContainsKey(naryExpr.Fun.FunctionName)) continue;
+ List<VCExpr> interfaceExprs = new List<VCExpr>();
+ foreach (Expr e in naryExpr.Args) {
+ interfaceExprs.Add(prover.Context.BoogieExprTranslator.Translate(e));
+ }
+ int instr = i;
+ i++;
+ AssumeCmd callSiteAssumeCmd = (AssumeCmd)block.Cmds[i];
+ IdentifierExpr iexpr = (IdentifierExpr) callSiteAssumeCmd.Expr;
+ CallSite cs = new CallSite(naryExpr.Fun.FunctionName, interfaceExprs, prover.Context.BoogieExprTranslator.LookupVariable(iexpr.Decl), block, instr, assumeCmd.Attributes);
+ if (!callSites.ContainsKey(block))
+ callSites[block] = new List<CallSite>();
+ callSites[block].Add(cs);
+ }
+ }
+ return callSites;
+ }
+
+ public Dictionary<Block, List<CallSite>> CollectRecordProcedureCallSites(Implementation implementation) {
+ var callSites = new Dictionary<Block, List<CallSite>>();
+ foreach (Block block in implementation.Blocks) {
+ for (int i = 0; i < block.Cmds.Count; i++) {
+ AssumeCmd assumeCmd = block.Cmds[i] as AssumeCmd;
+ if (assumeCmd == null) continue;
+ NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
+ if (naryExpr == null) continue;
+ if (!naryExpr.Fun.FunctionName.StartsWith(recordProcName)) continue;
+ List<VCExpr> interfaceExprs = new List<VCExpr>();
+ foreach (Expr e in naryExpr.Args) {
+ interfaceExprs.Add(prover.Context.BoogieExprTranslator.Translate(e));
+ }
+ CallSite cs = new CallSite(naryExpr.Fun.FunctionName, interfaceExprs, null, block, i, assumeCmd.Attributes);
+ if (!callSites.ContainsKey(block))
+ callSites[block] = new List<CallSite>();
+ callSites[block].Add(cs);
+ }
+ }
+ return callSites;
+ }
+
+ private int macroCountForStratifiedInlining = 0;
+ public Macro CreateNewMacro() {
+ string newName = "SIMacro@" + macroCountForStratifiedInlining.ToString();
+ macroCountForStratifiedInlining++;
+ return new Macro(Token.NoToken, newName, new List<Variable>(), new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool), false));
+ }
+ private int varCountForStratifiedInlining = 0;
+ public VCExprVar CreateNewVar(Microsoft.Boogie.Type type) {
+ string newName = "SIV@" + varCountForStratifiedInlining.ToString();
+ varCountForStratifiedInlining++;
+ Constant newVar = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, newName, type));
+ prover.Context.DeclareConstant(newVar, false, null);
+ return prover.VCExprGen.Variable(newVar.Name, type);
+ }
+ private int idCountForStratifiedInlining = 0;
+ public int CreateNewId() {
+ return idCountForStratifiedInlining++;
+ }
+
+ // Used inside PassifyImpl
+ protected override void addExitAssert(string implName, Block exitBlock) {
+ if (implName2StratifiedInliningInfo != null && implName2StratifiedInliningInfo.ContainsKey(implName)) {
+ var exitAssertCmd = implName2StratifiedInliningInfo[implName].exitAssertCmd;
+ if(exitAssertCmd != null) exitBlock.Cmds.Add(exitAssertCmd);
+ }
+ }
+
+ public override Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo) {
+ // Construct the set of inlined procs in the original program
+ var inlinedProcs = new HashSet<string>();
+ foreach (var decl in program.TopLevelDeclarations) {
+ // Implementations
+ if (decl is Implementation) {
+ var impl = decl as Implementation;
+ if (!(impl.Proc is LoopProcedure)) {
+ inlinedProcs.Add(impl.Name);
+ }
+ }
+
+ // And recording procedures
+ if (decl is Procedure) {
+ var proc = decl as Procedure;
+ if (proc.Name.StartsWith(recordProcName)) {
+ Debug.Assert(!(decl is LoopProcedure));
+ inlinedProcs.Add(proc.Name);
+ }
+ }
+ }
+
+ return extractLoopTraceRec(
+ new CalleeCounterexampleInfo(cex, new List<object>()),
+ mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample;
+ }
+
+ protected override bool elIsLoop(string procname) {
+ StratifiedInliningInfo info = null;
+ if (implName2StratifiedInliningInfo.ContainsKey(procname)) {
+ info = implName2StratifiedInliningInfo[procname];
+ }
+
+ if (info == null) return false;
+
+ var lp = info.impl.Proc as LoopProcedure;
+
+ if (lp == null) return false;
+ return true;
+ }
+
+ public abstract Outcome FindLeastToVerify(Implementation impl, ref HashSet<string> allBoolVars);
+ }
+
+ public class StratifiedVCGen : StratifiedVCGenBase {
+ public bool PersistCallTree;
+ public static HashSet<string> callTree = null;
+ public int numInlined = 0;
+ public int vcsize = 0;
+ private HashSet<string> procsThatReachedRecBound;
+ private Dictionary<string, int> extraRecBound;
+
+ public StratifiedVCGen(bool usePrevCallTree, HashSet<string> prevCallTree,
+ Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
+ : this(program, logFilePath, appendLogFile, checkers)
+ {
+ if (usePrevCallTree) {
+ callTree = prevCallTree;
+ PersistCallTree = true;
+ }
+ else {
+ PersistCallTree = false;
+ }
+ }
+
+ public StratifiedVCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
+ : base(program, logFilePath, appendLogFile, checkers, null) {
+ PersistCallTree = false;
+ procsThatReachedRecBound = new HashSet<string>();
+
+ extraRecBound = new Dictionary<string, int>();
+ program.TopLevelDeclarations.OfType<Implementation>()
+ .Iter(impl =>
+ {
+ var b = QKeyValue.FindIntAttribute(impl.Attributes, "SIextraRecBound", -1);
+ if (b != -1) extraRecBound.Add(impl.Name, b);
+ });
+ }
+
+ // Extra rec bound for procedures
+ public int GetExtraRecBound(string procName) {
+ if (!extraRecBound.ContainsKey(procName))
+ return 0;
+ else return extraRecBound[procName];
+ }
+
+ public class ApiChecker {
+ public ProverInterface prover;
+ public ProverInterface.ErrorHandler reporter;
+
+ public ApiChecker(ProverInterface prover, ProverInterface.ErrorHandler reporter) {
+ this.reporter = reporter;
+ this.prover = prover;
+ }
+
+ private Outcome CheckVC() {
+ prover.Check();
+ ProverInterface.Outcome outcome = prover.CheckOutcomeCore(reporter);
+
+ return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
+ }
+
+ public Outcome CheckAssumptions(List<VCExpr> assumptions) {
+ if (assumptions.Count == 0) {
+ return CheckVC();
+ }
+
+ prover.Push();
+ foreach (var a in assumptions) {
+ prover.Assert(a, true);
+ }
+ Outcome ret = CheckVC();
+ prover.Pop();
+ return ret;
+ }
+
+ public Outcome CheckAssumptions(List<VCExpr> hardAssumptions, List<VCExpr> softAssumptions) {
+ List<int> unsatisfiedSoftAssumptions;
+ ProverInterface.Outcome outcome = prover.CheckAssumptions(hardAssumptions, softAssumptions, out unsatisfiedSoftAssumptions, reporter);
+ return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
+ }
+
+ public Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore) {
+ ProverInterface.Outcome outcome = prover.CheckAssumptions(assumptions, out unsatCore, reporter);
+ return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
+ }
+ }
+
+ // Store important information related to a single VerifyImplementation query
+ public class VerificationState {
+ // The call tree
+ public FCallHandler calls;
+ public ApiChecker checker;
+ // For statistics
+ public int vcSize;
+ public int expansionCount;
+
+ public VerificationState(VCExpr vcMain, FCallHandler calls, ProverInterface prover, ProverInterface.ErrorHandler reporter) {
+ prover.Assert(vcMain, true);
+ this.calls = calls;
+ this.checker = new ApiChecker(prover, reporter);
+ vcSize = 0;
+ expansionCount = 0;
+ }
+ }
+
+ class FindLeastOORException : Exception
+ {
+ public Outcome outcome;
+
+ public FindLeastOORException(string msg, Outcome outcome)
+ : base(msg)
+ {
+ this.outcome = outcome;
+ }
+ }
+
+ public override Outcome FindLeastToVerify(Implementation impl, ref HashSet<string> allBoolVars) {
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+
+ // Record current time
+ var startTime = DateTime.UtcNow;
+
+ // No Max: avoids theorem prover restarts
+ CommandLineOptions.Clo.MaxProverMemory = 0;
+
+ // Initialize cache
+ satQueryCache = new Dictionary<int, List<HashSet<string>>>();
+ unsatQueryCache = new Dictionary<int, List<HashSet<string>>>();
+
+ Contract.Assert(implName2StratifiedInliningInfo != null);
+
+ // Build VCs for all procedures
+ implName2StratifiedInliningInfo.Values
+ .Iter(info => info.GenerateVC());
+
+ // Get the VC of the current procedure
+ VCExpr vcMain = implName2StratifiedInliningInfo[impl.Name].vcexpr;
+ Dictionary<int, Absy> mainLabel2absy = implName2StratifiedInliningInfo[impl.Name].label2absy;
+
+ // Find all procedure calls in vc and put labels on them
+ FCallHandler calls = new FCallHandler(prover.VCExprGen, implName2StratifiedInliningInfo, impl.Name, mainLabel2absy);
+ calls.setCurrProcAsMain();
+ vcMain = calls.Mutate(vcMain, true);
+
+ try
+ {
+
+ // Put all of the necessary state into one object
+ var vState = new VerificationState(vcMain, calls, prover, new EmptyErrorHandler());
+
+ // We'll restore the original state of the theorem prover at the end
+ // of this procedure
+ vState.checker.prover.Push();
+
+ // Do eager inlining
+ while (calls.currCandidates.Count > 0)
+ {
+ List<int> toExpand = new List<int>();
+
+ foreach (int id in calls.currCandidates)
+ {
+ Debug.Assert(calls.getRecursionBound(id) <= 1, "Recursion not supported");
+ toExpand.Add(id);
+ }
+ DoExpansion(toExpand, vState);
+ }
+
+ // Find all the boolean constants
+ var allConsts = new HashSet<VCExprVar>();
+ foreach (var constant in program.Constants)
+ {
+ if (!allBoolVars.Contains(constant.Name)) continue;
+ var v = prover.Context.BoogieExprTranslator.LookupVariable(constant);
+ allConsts.Add(v);
+ }
+
+ // Now, lets start the algo
+ var min = refinementLoop(vState.checker, new HashSet<VCExprVar>(), allConsts, allConsts);
+
+ var ret = new HashSet<string>();
+ foreach (var v in min)
+ {
+ //Console.WriteLine(v.Name);
+ ret.Add(v.Name);
+ }
+ allBoolVars = ret;
+
+ vState.checker.prover.Pop();
+
+ return Outcome.Correct;
+ }
+ catch (FindLeastOORException e)
+ {
+ Console.WriteLine("Exception in FindLeastToVerify: {0}, {1}", e.Message, e.outcome);
+ return e.outcome;
+ }
+ }
+
+ private HashSet<VCExprVar> refinementLoop(ApiChecker apiChecker, HashSet<VCExprVar> trackedVars, HashSet<VCExprVar> trackedVarsUpperBound, HashSet<VCExprVar> allVars) {
+ Debug.Assert(trackedVars.IsSubsetOf(trackedVarsUpperBound));
+
+ // If we already know the fate of all vars, then we're done.
+ if (trackedVars.Count == trackedVarsUpperBound.Count)
+ return new HashSet<VCExprVar>(trackedVars);
+
+ // See if we already have enough variables tracked
+ var success = refinementLoopCheckPath(apiChecker, trackedVars, allVars);
+ if (success) {
+ // We have enough
+ return new HashSet<VCExprVar>(trackedVars);
+ }
+
+ // If all that remains is 1 variable, then we know that we must track it
+ if (trackedVars.Count + 1 == trackedVarsUpperBound.Count)
+ return new HashSet<VCExprVar>(trackedVarsUpperBound);
+
+ // Partition the remaining set of variables
+ HashSet<VCExprVar> part1, part2;
+ var temp = new HashSet<VCExprVar>(trackedVarsUpperBound);
+ temp.ExceptWith(trackedVars);
+ Partition<VCExprVar>(temp, out part1, out part2);
+
+ // First half
+ var fh = new HashSet<VCExprVar>(trackedVars); fh.UnionWith(part2);
+ var s1 = refinementLoop(apiChecker, fh, trackedVarsUpperBound, allVars);
+
+ var a = new HashSet<VCExprVar>(part1); a.IntersectWith(s1);
+ var b = new HashSet<VCExprVar>(part1); b.ExceptWith(s1);
+ var c = new HashSet<VCExprVar>(trackedVarsUpperBound); c.ExceptWith(b);
+ a.UnionWith(trackedVars);
+
+ // Second half
+ return refinementLoop(apiChecker, a, c, allVars);
+ }
+
+ Dictionary<int, List<HashSet<string>>> satQueryCache;
+ Dictionary<int, List<HashSet<string>>> unsatQueryCache;
+
+ private bool refinementLoopCheckPath(ApiChecker apiChecker, HashSet<VCExprVar> varsToSet, HashSet<VCExprVar> allVars) {
+ var assumptions = new List<VCExpr>();
+ var prover = apiChecker.prover;
+ var query = new HashSet<string>();
+ varsToSet.Iter(v => query.Add(v.Name));
+
+ if (checkCache(query, unsatQueryCache)) {
+ prover.LogComment("FindLeast: Query Cache Hit");
+ return true;
+ }
+ if (checkCache(query, satQueryCache)) {
+ prover.LogComment("FindLeast: Query Cache Hit");
+ return false;
+ }
+
+ prover.LogComment("FindLeast: Query Begin");
+
+ foreach (var c in allVars) {
+ if (varsToSet.Contains(c)) {
+ assumptions.Add(c);
+ }
+ else {
+ assumptions.Add(prover.VCExprGen.Not(c));
+ }
+ }
+
+ var o = apiChecker.CheckAssumptions(assumptions);
+ if (o != Outcome.Correct && o != Outcome.Errors)
+ {
+ throw new FindLeastOORException("OOR", o);
+ }
+ //Console.WriteLine("Result = " + o.ToString());
+ prover.LogComment("FindLeast: Query End");
+
+ if (o == Outcome.Correct) {
+ insertCache(query, unsatQueryCache);
+ return true;
+ }
+
+ insertCache(query, satQueryCache);
+ return false;
+ }
+
+ private bool checkCache(HashSet<string> q, Dictionary<int, List<HashSet<string>>> cache) {
+ if (!cache.ContainsKey(q.Count)) return false;
+ foreach (var s in cache[q.Count]) {
+ if (q.SetEquals(s)) return true;
+ }
+ return false;
+ }
+
+ private void insertCache(HashSet<string> q, Dictionary<int, List<HashSet<string>>> cache) {
+ if (!cache.ContainsKey(q.Count)) {
+ cache.Add(q.Count, new List<HashSet<string>>());
+ }
+ cache[q.Count].Add(q);
+ }
+
+ public static void Partition<T>(HashSet<T> values, out HashSet<T> part1, out HashSet<T> part2) {
+ part1 = new HashSet<T>();
+ part2 = new HashSet<T>();
+ var size = values.Count;
+ var crossed = false;
+ var curr = 0;
+ foreach (var s in values) {
+ if (crossed) part2.Add(s);
+ else part1.Add(s);
+ curr++;
+ if (!crossed && curr >= size / 2) crossed = true;
+ }
+ }
+
+ public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback) {
+ Debug.Assert(QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"));
+ Debug.Assert(this.program == program);
+
+ // Record current time
+ var startTime = DateTime.UtcNow;
+
+ // Flush any axioms that came with the program before we start SI on this implementation
+ prover.AssertAxioms();
+
+ // Run live variable analysis
+ if (CommandLineOptions.Clo.LiveVariableAnalysis == 2) {
+ Microsoft.Boogie.InterProcGenKill.ComputeLiveVars(impl, program);
+ }
+
+ // Get the VC of the current procedure
+ StratifiedInliningInfo info = implName2StratifiedInliningInfo[impl.Name];
+ info.GenerateVC();
+ VCExpr vc = info.vcexpr;
+ Dictionary<int, Absy> mainLabel2absy = info.label2absy;
+ var reporter = new StratifiedInliningErrorReporter(implName2StratifiedInliningInfo, prover, callback, info);
+
+ // Find all procedure calls in vc and put labels on them
+ FCallHandler calls = new FCallHandler(prover.VCExprGen, implName2StratifiedInliningInfo, impl.Name, mainLabel2absy);
+ calls.setCurrProcAsMain();
+ vc = calls.Mutate(vc, true);
+ reporter.SetCandidateHandler(calls);
+ calls.id2VC.Add(0, vc);
+ calls.extraRecursion = extraRecBound;
+ if (CommandLineOptions.Clo.SIBoolControlVC)
+ {
+ calls.candiate2block2controlVar.Add(0, new Dictionary<Block, VCExpr>());
+ implName2StratifiedInliningInfo[impl.Name].blockToControlVar.Iter(tup =>
+ calls.candiate2block2controlVar[0].Add(tup.Key, tup.Value));
+ }
+
+ // We'll restore the original state of the theorem prover at the end
+ // of this procedure
+ prover.Push();
+
+ // Put all of the necessary state into one object
+ var vState = new VerificationState(vc, calls, prover, reporter);
+ vState.vcSize += SizeComputingVisitor.ComputeSize(vc);
+
+ Outcome ret = Outcome.ReachedBound;
+
+ #region eager inlining
+ for (int i = 1; i < CommandLineOptions.Clo.StratifiedInlining && calls.currCandidates.Count > 0; i++) {
+ List<int> toExpand = new List<int>();
+
+ foreach (int id in calls.currCandidates) {
+ if (calls.getRecursionBound(id) <= CommandLineOptions.Clo.RecursionBound) {
+ toExpand.Add(id);
+ }
+ }
+ DoExpansion(toExpand, vState);
+ }
+ #endregion
+
+ #region Repopulate call tree, if there is one
+ if (PersistCallTree && callTree != null) {
+ bool expand = true;
+ while (expand) {
+ List<int> toExpand = new List<int>();
+ foreach (int id in calls.currCandidates) {
+ if (callTree.Contains(calls.getPersistentId(id))) {
+ toExpand.Add(id);
+ }
+ }
+ if (toExpand.Count == 0) expand = false;
+ else {
+ DoExpansion(toExpand, vState);
+ }
+ }
+ }
+ #endregion
+
+ if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1) {
+ Console.WriteLine(">> SI: Size of VC after eager inlining: {0}", vState.vcSize);
+ }
+
+ // Under-approx query is only needed if something was inlined since
+ // the last time an under-approx query was made
+ // TODO: introduce this
+ // bool underApproxNeeded = true;
+
+ // The recursion bound for stratified search
+ int bound = CommandLineOptions.Clo.NonUniformUnfolding ? CommandLineOptions.Clo.RecursionBound : 1;
+
+ int done = 0;
+
+ int iters = 0;
+
+ // for blocking candidates (and focusing on a counterexample)
+ var block = new HashSet<int>();
+
+ // Process tasks while not done. We're done when:
+ // case 1: (correct) We didn't find a bug (either an over-approx query was valid
+ // or we reached the recursion bound) and the task is "step"
+ // case 2: (bug) We find a bug
+ // case 3: (internal error) The theorem prover TimesOut of runs OutOfMemory
+ while (true)
+ {
+ // Check timeout
+ if (CommandLineOptions.Clo.ProverKillTime != -1)
+ {
+ if ((DateTime.UtcNow - startTime).TotalSeconds > CommandLineOptions.Clo.ProverKillTime)
+ {
+ ret = Outcome.TimedOut;
+ break;
+ }
+ }
+
+ if (done > 0)
+ {
+ break;
+ }
+
+ // Stratified Step
+ ret = stratifiedStep(bound, vState, block);
+ iters++;
+
+ // Sorry, out of luck (time/memory)
+ if (ret == Outcome.Inconclusive || ret == Outcome.OutOfMemory || ret == Outcome.TimedOut)
+ {
+ done = 3;
+ continue;
+ }
+
+ if (ret == Outcome.Errors && reporter.underapproximationMode)
+ {
+ // Found a bug
+ done = 2;
+ }
+ else if (ret == Outcome.Correct)
+ {
+ if (block.Count == 0)
+ {
+ // Correct
+ done = 1;
+ }
+ else
+ {
+ // reset blocked and continue loop
+ block.Clear();
+ }
+ }
+ else if (ret == Outcome.ReachedBound)
+ {
+ if (block.Count == 0)
+ {
+ if (CommandLineOptions.Clo.StratifiedInliningVerbose > 0)
+ Console.WriteLine(">> SI: Exhausted Bound {0}", bound);
+
+ // Increment bound
+ bound++;
+
+ if (bound > CommandLineOptions.Clo.RecursionBound)
+ {
+ // Correct under bound
+ done = 1;
+ }
+ }
+ else
+ {
+ // reset blocked and continue loop
+ block.Clear();
+ }
+ }
+ else
+ {
+ // Do inlining
+ Debug.Assert(ret == Outcome.Errors && !reporter.underapproximationMode);
+ Contract.Assert(reporter.candidatesToExpand.Count != 0);
+
+ #region expand call tree
+ if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1)
+ {
+ Console.Write(">> SI Inlining: ");
+ reporter.candidatesToExpand
+ .Select(c => calls.getProc(c))
+ .Iter(c => Console.Write("{0} ", c));
+
+ Console.WriteLine();
+ }
+
+ // Expand and try again
+ vState.checker.prover.LogComment(";;;;;;;;;;;; Expansion begin ;;;;;;;;;;");
+ DoExpansion(reporter.candidatesToExpand, vState);
+ vState.checker.prover.LogComment(";;;;;;;;;;;; Expansion end ;;;;;;;;;;");
+
+ #endregion
+ }
+ }
+
+ // Pop off everything that we pushed so that there are no side effects from
+ // this call to VerifyImplementation
+ vState.checker.prover.Pop();
+
+ if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1) {
+ Console.WriteLine(">> SI: Expansions performed: {0}", vState.expansionCount);
+ Console.WriteLine(">> SI: Candidates left: {0}", calls.currCandidates.Count);
+ Console.WriteLine(">> SI: VC Size: {0}", vState.vcSize);
+ }
+
+ vcsize = vState.vcSize;
+ numInlined = (calls.candidateParent.Keys.Count + 1) - (calls.currCandidates.Count);
+
+ var rbound = "Procs that reached bound: ";
+ foreach (var s in procsThatReachedRecBound) rbound += " " + s;
+ if (ret == Outcome.ReachedBound) Helpers.ExtraTraceInformation(rbound);
+ if (CommandLineOptions.Clo.StackDepthBound > 0 && ret == Outcome.Correct) ret = Outcome.ReachedBound;
+
+ // Store current call tree
+ if (PersistCallTree && (ret == Outcome.Correct || ret == Outcome.Errors || ret == Outcome.ReachedBound)) {
+ callTree = new HashSet<string>();
+ //var persistentNodes = new HashSet<int>(calls.candidateParent.Values);
+ var persistentNodes = new HashSet<int>(calls.candidateParent.Keys);
+ persistentNodes.Add(0);
+ persistentNodes.ExceptWith(calls.currCandidates);
+
+ foreach (var id in persistentNodes) {
+ var pid = calls.getPersistentId(id);
+ Debug.Assert(!callTree.Contains(pid));
+ callTree.Add(pid);
+ }
+ }
+ return ret;
+ }
+
+ // A step of the stratified inlining algorithm: both under-approx and over-approx queries
+ private Outcome stratifiedStep(int bound, VerificationState vState, HashSet<int> block) {
+ var calls = vState.calls;
+ var checker = vState.checker;
+ var prover = checker.prover;
+ var reporter = checker.reporter as StratifiedInliningErrorReporter;
+
+ reporter.underapproximationMode = true;
+ prover.LogComment(";;;;;;;;;;;; Underapprox mode begin ;;;;;;;;;;");
+ List<VCExpr> assumptions = new List<VCExpr>();
+
+ foreach (int id in calls.currCandidates) {
+ assumptions.Add(calls.getFalseExpr(id));
+ }
+ Outcome ret = checker.CheckAssumptions(assumptions);
+ prover.LogComment(";;;;;;;;;;;; Underapprox mode end ;;;;;;;;;;");
+
+ if (ret != Outcome.Correct) {
+ // Either the query returned an error or it ran out of memory or time.
+ // In all cases, we are done.
+ return ret;
+ }
+
+ if (calls.currCandidates.Count == 0) {
+ // If we didn't underapproximate, then we're done
+ return ret;
+ }
+
+ prover.LogComment(";;;;;;;;;;;; Overapprox mode begin ;;;;;;;;;;");
+
+ // Over-approx query
+ reporter.underapproximationMode = false;
+
+ // Push "true" for all, except:
+ // push "false" for all candidates that have reached
+ // the recursion bounds
+
+ bool allTrue = true;
+ bool allFalse = true;
+ List<VCExpr> softAssumptions = new List<VCExpr>();
+
+ assumptions = new List<VCExpr>();
+ procsThatReachedRecBound.Clear();
+
+ foreach (int id in calls.currCandidates) {
+
+ int idBound = calls.getRecursionBound(id);
+ int sd = calls.getStackDepth(id);
+ if (idBound <= bound && (CommandLineOptions.Clo.StackDepthBound == 0 || sd <= CommandLineOptions.Clo.StackDepthBound)) {
+ if (idBound > 1)
+ softAssumptions.Add(calls.getFalseExpr(id));
+
+ if (block.Contains(id)) {
+ assumptions.Add(calls.getFalseExpr(id));
+ allTrue = false;
+ }
+ else {
+ allFalse = false;
+ }
+ }
+ else {
+ procsThatReachedRecBound.Add(calls.getProc(id));
+ assumptions.Add(calls.getFalseExpr(id));
+ allTrue = false;
+ }
+ }
+
+ if (allFalse) {
+ // If we made all candidates false, then this is the same
+ // as the underapprox query. We already know the answer.
+ ret = Outcome.Correct;
+ }
+ else {
+ ret = CommandLineOptions.Clo.NonUniformUnfolding
+ ? checker.CheckAssumptions(assumptions, softAssumptions)
+ : checker.CheckAssumptions(assumptions);
+ }
+
+ if (ret != Outcome.Correct && ret != Outcome.Errors) {
+ // The query ran out of memory or time, that's it,
+ // we cannot do better. Give up!
+ return ret;
+ }
+
+ if (ret == Outcome.Correct) {
+ // If nothing was made false, then the program is correct
+ if (allTrue) {
+ return ret;
+ }
+
+ // Nothing more can be done with current recursion bound.
+ return Outcome.ReachedBound;
+ }
+
+ Contract.Assert(ret == Outcome.Errors);
+
+ prover.LogComment(";;;;;;;;;;;; Overapprox mode end ;;;;;;;;;;");
+
+ return ret;
+ }
+
+ // A counter for adding new variables
+ static int newVarCnt = 0;
+
+ // Does on-demand inlining -- pushes procedure bodies on the theorem prover stack.
+ private void DoExpansion(List<int>/*!*/ candidates, VerificationState vState) {
+ Contract.Requires(candidates != null);
+ Contract.Requires(vState.calls != null);
+ Contract.Requires(vState.checker.prover != null);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+
+ vState.expansionCount += candidates.Count;
+
+ var prover = vState.checker.prover;
+ var calls = vState.calls;
+
+ VCExpr exprToPush = VCExpressionGenerator.True;
+ Contract.Assert(exprToPush != null);
+ foreach (int id in candidates) {
+ VCExprNAry expr = calls.id2Candidate[id];
+ Contract.Assert(expr != null);
+ string procName = cce.NonNull(expr.Op as VCExprBoogieFunctionOp).Func.Name;
+ if (!implName2StratifiedInliningInfo.ContainsKey(procName)) continue;
+
+ StratifiedInliningInfo info = implName2StratifiedInliningInfo[procName];
+ info.GenerateVC();
+ //Console.WriteLine("Inlining {0}", procName);
+ VCExpr expansion = cce.NonNull(info.vcexpr);
+
+ // Instantiate the "forall" variables
+ Dictionary<VCExprVar, VCExpr> substForallDict = new Dictionary<VCExprVar, VCExpr>();
+ Contract.Assert(info.interfaceExprVars.Count == expr.Length);
+ for (int i = 0; i < info.interfaceExprVars.Count; i++) {
+ substForallDict.Add(info.interfaceExprVars[i], expr[i]);
+ }
+ VCExprSubstitution substForall = new VCExprSubstitution(substForallDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
+
+ SubstitutingVCExprVisitor subst = new SubstitutingVCExprVisitor(prover.VCExprGen);
+ Contract.Assert(subst != null);
+ expansion = subst.Mutate(expansion, substForall);
+
+ // Instantiate and declare the "exists" variables
+ Dictionary<VCExprVar, VCExpr> substExistsDict = new Dictionary<VCExprVar, VCExpr>();
+ foreach (VCExprVar v in info.privateExprVars) {
+ Contract.Assert(v != null);
+ string newName = v.Name + "_si_" + newVarCnt.ToString();
+ newVarCnt++;
+ prover.Context.DeclareConstant(new Constant(Token.NoToken, new TypedIdent(Token.NoToken, newName, v.Type)), false, null);
+ substExistsDict.Add(v, prover.VCExprGen.Variable(newName, v.Type));
+ }
+ if (CommandLineOptions.Clo.SIBoolControlVC)
+ {
+ // record the mapping for control booleans (for tracing the path later)
+ calls.candiate2block2controlVar[id] = new Dictionary<Block, VCExpr>();
+ foreach (var tup in info.blockToControlVar)
+ {
+ calls.candiate2block2controlVar[id].Add(tup.Key,
+ substExistsDict[tup.Value]);
+ }
+ }
+ if (CommandLineOptions.Clo.ModelViewFile != null) {
+ SaveSubstitution(vState, id, substForallDict, substExistsDict);
+ }
+ VCExprSubstitution substExists = new VCExprSubstitution(substExistsDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
+
+ subst = new SubstitutingVCExprVisitor(prover.VCExprGen);
+ expansion = subst.Mutate(expansion, substExists);
+
+ if (!calls.currCandidates.Contains(id)) {
+ Console.WriteLine("Don't know what we just expanded");
+ }
+
+ calls.currCandidates.Remove(id);
+
+ // Record the new set of candidates and rename absy labels
+ calls.currInlineCount = id;
+ calls.setCurrProc(procName);
+ expansion = calls.Mutate(expansion, true);
+
+ //expansion = checker.VCExprGen.Eq(calls.id2ControlVar[id], expansion);
+ expansion = prover.VCExprGen.Implies(calls.id2ControlVar[id], expansion);
+ calls.id2VC.Add(id, expansion);
+
+ exprToPush = prover.VCExprGen.And(exprToPush, expansion);
+ }
+ vState.checker.prover.Assert(exprToPush, true);
+ vState.vcSize += SizeComputingVisitor.ComputeSize(exprToPush);
+ }
+
+ private void SaveSubstitution(VerificationState vState, int id,
+ Dictionary<VCExprVar, VCExpr> substForallDict, Dictionary<VCExprVar, VCExpr> substExistsDict) {
+ var prover = vState.checker.prover;
+ var calls = vState.calls;
+ Boogie2VCExprTranslator translator = prover.Context.BoogieExprTranslator;
+ VCExprVar mvStateConstant = translator.LookupVariable(ModelViewInfo.MVState_ConstantDef);
+ substExistsDict.Add(mvStateConstant, prover.VCExprGen.Integer(BigNum.FromInt(id)));
+ Dictionary<VCExprVar, VCExpr> mapping = new Dictionary<VCExprVar, VCExpr>();
+ foreach (var key in substForallDict.Keys)
+ mapping[key] = substForallDict[key];
+ foreach (var key in substExistsDict.Keys)
+ mapping[key] = substExistsDict[key];
+ calls.id2Vars[id] = mapping;
+ }
+
+ // Uniquely identifies a procedure call (the call expr, instance)
+ public class BoogieCallExpr : IEquatable<BoogieCallExpr> {
+ public NAryExpr expr;
+ public int inlineCnt;
+
+ public BoogieCallExpr(NAryExpr expr, int inlineCnt) {
+ this.expr = expr;
+ this.inlineCnt = inlineCnt;
+ }
+
+ public override int GetHashCode() {
+ return expr.GetHashCode() + 131 * inlineCnt.GetHashCode();
+ }
+
+ public override bool Equals(object obj) {
+ BoogieCallExpr that = obj as BoogieCallExpr;
+ return (expr == that.expr && inlineCnt == that.inlineCnt);
+ }
+
+ public bool Equals(BoogieCallExpr that) {
+ return (expr == that.expr && inlineCnt == that.inlineCnt);
+ }
+ }
+
+ // This class is used to traverse VCs and do the following:
+ // -- collect the set of FunctionCall nodes and label them with a unique string
+ // -- Rename all other labels (so that calling this on the same VC results in
+ // VCs with different labels each time)
+ public class FCallHandler : MutatingVCExprVisitor<bool> {
+ Dictionary<string/*!*/, StratifiedInliningInfo/*!*/>/*!*/ implName2StratifiedInliningInfo;
+ public readonly Dictionary<int, Absy>/*!*/ mainLabel2absy;
+ public Dictionary<BoogieCallExpr/*!*/, int>/*!*/ boogieExpr2Id;
+ public Dictionary<BoogieCallExpr/*!*/, VCExpr>/*!*/ recordExpr2Var;
+ public Dictionary<int, VCExprNAry/*!*/>/*!*/ id2Candidate;
+ public Dictionary<int, VCExprVar/*!*/>/*!*/ id2ControlVar;
+ public Dictionary<int, VCExpr> id2VC;
+ public Dictionary<string/*!*/, int>/*!*/ label2Id;
+ // candidate to block to Bool Control variable
+ public Dictionary<int, Dictionary<Block, VCExpr>> candiate2block2controlVar;
+ // Stores the candidate from which this one originated
+ public Dictionary<int, int> candidateParent;
+ // Mapping from candidate Id to the "si_unique_call" id that led to
+ // this candidate. This is useful for getting persistent names for
+ // candidates
+ public Dictionary<int, int> candidate2callId;
+ // A cache for candidate id to its persistent name
+ public Dictionary<int, string> persistentNameCache;
+ // Inverse of the above map
+ public Dictionary<string, int> persistentNameInv;
+ // Used to record candidates recently added
+ public HashSet<int> recentlyAddedCandidates;
+ // Name of main procedure
+ private string mainProcName;
+ // A map from candidate id to the VCExpr that represents its
+ // first argument (used for obtaining concrete values in error trace)
+ public Dictionary<int, VCExpr> argExprMap;
+
+ // map from candidate to summary candidates
+ public Dictionary<int, List<Tuple<VCExprVar, VCExpr>>> summaryCandidates;
+ private Dictionary<string, List<Tuple<VCExprVar, VCExpr>>> summaryTemp;
+ // set of all boolean guards of summaries
+ public HashSet<VCExprVar> allSummaryConst;
+
+ public HashSet<int> forcedCandidates;
+
+ // User info -- to decrease/increase calculation of recursion bound
+ public Dictionary<int, int> recursionIncrement;
+ public Dictionary<string, int> extraRecursion;
+
+ public HashSet<int> currCandidates;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
+ Contract.Invariant(mainLabel2absy != null);
+ Contract.Invariant(boogieExpr2Id != null);
+ Contract.Invariant(cce.NonNullDictionaryAndValues(id2Candidate));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(id2ControlVar));
+ Contract.Invariant(label2Id != null);
+ }
+
+ // Name of the procedure whose VC we're mutating
+ string currProc;
+
+ // The 0^th candidate is main
+ static int candidateCount = 1;
+ public int currInlineCount;
+
+ public Dictionary<int, Dictionary<VCExprVar, VCExpr>> id2Vars;
+
+ public FCallHandler(VCExpressionGenerator/*!*/ gen,
+ Dictionary<string/*!*/, StratifiedInliningInfo/*!*/>/*!*/ implName2StratifiedInliningInfo,
+ string mainProcName, Dictionary<int, Absy>/*!*/ mainLabel2absy)
+ : base(gen) {
+ Contract.Requires(gen != null);
+ Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
+ Contract.Requires(mainLabel2absy != null);
+ this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo;
+ this.mainProcName = mainProcName;
+ this.mainLabel2absy = mainLabel2absy;
+ id2Candidate = new Dictionary<int, VCExprNAry>();
+ id2ControlVar = new Dictionary<int, VCExprVar>();
+ boogieExpr2Id = new Dictionary<BoogieCallExpr, int>();
+ label2Id = new Dictionary<string, int>();
+ currCandidates = new HashSet<int>();
+ currInlineCount = 0;
+ currProc = null;
+ labelRenamer = new Dictionary<string, int>();
+ labelRenamerInv = new Dictionary<string, string>();
+ candidateParent = new Dictionary<int, int>();
+ //callGraphMapping = new Dictionary<int, int>();
+ recursionIncrement = new Dictionary<int, int>();
+ candidate2callId = new Dictionary<int, int>();
+ persistentNameCache = new Dictionary<int, string>();
+ persistentNameInv = new Dictionary<string, int>();
+ persistentNameCache[0] = "0";
+ persistentNameInv["0"] = 0;
+ recentlyAddedCandidates = new HashSet<int>();
+ argExprMap = new Dictionary<int, VCExpr>();
+ recordExpr2Var = new Dictionary<BoogieCallExpr, VCExpr>();
+ candiate2block2controlVar = new Dictionary<int, Dictionary<Block, VCExpr>>();
+
+ forcedCandidates = new HashSet<int>();
+ extraRecursion = new Dictionary<string, int>();
+
+ id2Vars = new Dictionary<int, Dictionary<VCExprVar, VCExpr>>();
+ summaryCandidates = new Dictionary<int, List<Tuple<VCExprVar, VCExpr>>>();
+ summaryTemp = new Dictionary<string, List<Tuple<VCExprVar, VCExpr>>>();
+ allSummaryConst = new HashSet<VCExprVar>();
+ id2VC = new Dictionary<int, VCExpr>();
+ }
+
+ public void Clear() {
+ currCandidates = new HashSet<int>();
+ }
+
+ // Return the set of all candidates
+ public HashSet<int> getAllCandidates() {
+ var ret = new HashSet<int>(candidateParent.Keys);
+ ret.Add(0);
+ return ret;
+ }
+
+ // Given a candidate "id", let proc(id) be the
+ // procedure corresponding to id. This procedure returns
+ // the number of times proc(id) appears as an ancestor
+ // of id. This is the same as the number of times we've
+ // recursed on proc(id)
+ public int getRecursionBound(int id) {
+ int ret = 1;
+ var str = getProc(id);
+
+ while (candidateParent.ContainsKey(id)) {
+ if (recursionIncrement.ContainsKey(id)) ret += recursionIncrement[id];
+ id = candidateParent[id];
+ if (getProc(id) == str && !forcedCandidates.Contains(id)) ret++;
+ }
+
+ // Usual
+ if (!extraRecursion.ContainsKey(str))
+ return ret;
+
+ // Usual
+ if (ret <= CommandLineOptions.Clo.RecursionBound - 1)
+ return ret;
+
+ // Special
+ if (ret >= CommandLineOptions.Clo.RecursionBound &&
+ ret <= CommandLineOptions.Clo.RecursionBound + extraRecursion[str] - 1)
+ return CommandLineOptions.Clo.RecursionBound - 1;
+
+ // Special
+ return ret - extraRecursion[str];
+ }
+
+ // This procedure returns the stack depth of the candidate
+ // (distance from main)
+ public int getStackDepth(int id)
+ {
+ int ret = 1;
+
+ while (candidateParent.ContainsKey(id))
+ {
+ ret++;
+ id = candidateParent[id];
+ }
+
+ return ret;
+ }
+
+ // Set user-define increment/decrement to recursionBound
+ public void setRecursionIncrement(int id, int incr) {
+ if (recursionIncrement.ContainsKey(id))
+ recursionIncrement[id] = incr;
+ else
+ recursionIncrement.Add(id, incr);
+ }
+
+ // Returns the name of the procedure corresponding to candidate id
+ public string getProc(int id) {
+ if (id == 0) return mainProcName;
+
+ return (id2Candidate[id].Op as VCExprBoogieFunctionOp).Func.Name;
+ }
+
+ // Get a unique id for this candidate (dependent only on the Call
+ // graph of the program). The persistent id is:
+ // 0: for main
+ // a_b_c: where a is the persistent id of parent, and b is the procedure name
+ // and c is the unique call id (if any)
+ public string getPersistentId(int top_id) {
+ if (top_id == 0) return "0";
+ Debug.Assert(candidateParent.ContainsKey(top_id));
+ if (persistentNameCache.ContainsKey(top_id))
+ return persistentNameCache[top_id];
+
+ var parent_id = getPersistentId(candidateParent[top_id]);
+ var call_id = candidate2callId.ContainsKey(top_id) ? candidate2callId[top_id] : -1;
+ var ret = string.Format("{0}_131_{1}_131_{2}", parent_id, getProc(top_id), call_id);
+ persistentNameCache[top_id] = ret;
+ persistentNameInv[ret] = top_id;
+ return ret;
+ }
+
+ public int getCandidateFromGraphNode(string n) {
+ if (!persistentNameInv.ContainsKey(n)) {
+ return -1;
+ }
+ return persistentNameInv[n];
+ }
+
+ private int GetNewId(VCExprNAry vc) {
+ Contract.Requires(vc != null);
+ int id = candidateCount;
+
+ id2Candidate[id] = vc;
+ id2ControlVar[id] = Gen.Variable("si_control_var_bool_" + id.ToString(), Microsoft.Boogie.Type.Bool);
+
+ candidateCount++;
+ currCandidates.Add(id);
+ recentlyAddedCandidates.Add(id);
+
+ return id;
+ }
+
+ private string GetLabel(int id) {
+ Contract.Ensures(Contract.Result<string>() != null);
+
+ string ret = "si_fcall_" + id.ToString();
+ if (!label2Id.ContainsKey(ret))
+ label2Id[ret] = id;
+
+ return ret;
+ }
+
+ public int GetId(string label) {
+ Contract.Requires(label != null);
+ if (!label2Id.ContainsKey(label))
+ return -1;
+ return label2Id[label];
+ }
+
+ Dictionary<string, int> labelRenamer;
+ Dictionary<string, string> labelRenamerInv;
+
+ public string RenameAbsyLabel(string label) {
+ Contract.Requires(label != null);
+ Contract.Requires(label.Length >= 1);
+ Contract.Ensures(Contract.Result<string>() != null);
+
+ // Remove the sign from the label
+ string nosign = label.Substring(1);
+ var ret = "si_inline_" + currInlineCount.ToString() + "_" + nosign;
+
+ if (!labelRenamer.ContainsKey(ret)) {
+ var c = labelRenamer.Count + 11; // two digit labels only
+ labelRenamer.Add(ret, c);
+ labelRenamerInv.Add(c.ToString(), ret);
+ }
+ return labelRenamer[ret].ToString();
+ }
+
+ public string ParseRenamedAbsyLabel(string label, int cnt) {
+ Contract.Requires(label != null);
+ if (!labelRenamerInv.ContainsKey(label)) {
+ return null;
+ }
+ var str = labelRenamerInv[label];
+ var prefix = "si_inline_" + cnt.ToString() + "_";
+ if (!str.StartsWith(prefix)) return null;
+ return str.Substring(prefix.Length);
+ }
+
+ public void setCurrProc(string name) {
+ Contract.Requires(name != null);
+ currProc = name;
+ Contract.Assert(implName2StratifiedInliningInfo.ContainsKey(name));
+ }
+
+ public void setCurrProcAsMain() {
+ currProc = "";
+ }
+
+ // Return the formula (candidate IFF false)
+ public VCExpr getFalseExpr(int candidateId) {
+ //return Gen.Eq(VCExpressionGenerator.False, id2ControlVar[candidateId]);
+ return Gen.Not(id2ControlVar[candidateId]);
+ }
+
+ // Return the formula (candidate IFF true)
+ public VCExpr getTrueExpr(int candidateId) {
+ return Gen.Eq(VCExpressionGenerator.True, id2ControlVar[candidateId]);
+ }
+
+ public Dictionary<int, Absy> getLabel2absy() {
+ Contract.Ensures(Contract.Result<Dictionary<int, Absy>>() != null);
+
+ Contract.Assert(currProc != null);
+ if (currProc == "") {
+ return mainLabel2absy;
+ }
+ return cce.NonNull(implName2StratifiedInliningInfo[currProc].label2absy);
+ }
+
+ // Finds labels and changes them:
+ // si_fcall_id: if "id" corresponds to a tracked procedure call, then
+ // si_control_var_candidateId
+ // si_fcall_id: if "id" does not corresponds to a tracked procedure call, then
+ // delete
+ // num: si_inline_num
+ //
+ protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
+ List<VCExpr/*!*/>/*!*/ newSubExprs,
+ // has any of the subexpressions changed?
+ bool changed,
+ bool arg) {
+ //Contract.Requires(originalNode != null);
+ //Contract.Requires(cce.NonNullElements(newSubExprs));
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ VCExpr ret;
+ if (changed)
+ ret = Gen.Function(originalNode.Op,
+ newSubExprs, originalNode.TypeArguments);
+ else
+ ret = originalNode;
+
+ VCExprLabelOp lop = originalNode.Op as VCExprLabelOp;
+ if (lop == null) return ret;
+ if (!(ret is VCExprNAry)) return ret;
+
+ VCExprNAry retnary = (VCExprNAry)ret;
+ Contract.Assert(retnary != null);
+ string prefix = "si_fcall_"; // from Wlp.ssc::Cmd(...)
+ if (lop.label.Substring(1).StartsWith(prefix)) {
+ int id = Int32.Parse(lop.label.Substring(prefix.Length + 1));
+ Dictionary<int, Absy> label2absy = getLabel2absy();
+ Absy cmd = label2absy[id] as Absy;
+ //label2absy.Remove(id);
+
+ Contract.Assert(cmd != null);
+ AssumeCmd acmd = cmd as AssumeCmd;
+ Contract.Assert(acmd != null);
+ NAryExpr naryExpr = acmd.Expr as NAryExpr;
+ Contract.Assert(naryExpr != null);
+
+ string calleeName = naryExpr.Fun.FunctionName;
+
+ VCExprNAry callExpr = retnary[0] as VCExprNAry;
+
+ if (implName2StratifiedInliningInfo.ContainsKey(calleeName)) {
+ Contract.Assert(callExpr != null);
+ int candidateId = GetNewId(callExpr);
+ boogieExpr2Id[new BoogieCallExpr(naryExpr, currInlineCount)] = candidateId;
+ candidateParent[candidateId] = currInlineCount;
+ candiate2block2controlVar[candidateId] = new Dictionary<Block, VCExpr>();
+
+ string label = GetLabel(candidateId);
+ var unique_call_id = QKeyValue.FindIntAttribute(acmd.Attributes, "si_unique_call", -1);
+ if (unique_call_id != -1)
+ candidate2callId[candidateId] = unique_call_id;
+
+ //return Gen.LabelPos(label, callExpr);
+ return Gen.LabelPos(label, id2ControlVar[candidateId]);
+ }
+ else if (calleeName.StartsWith(recordProcName)) {
+ Contract.Assert(callExpr != null);
+ Debug.Assert(callExpr.Length == 1);
+ Debug.Assert(callExpr[0] != null);
+ recordExpr2Var[new BoogieCallExpr(naryExpr, currInlineCount)] = callExpr[0];
+ return callExpr;
+ }
+ else {
+ // callExpr can be null; this happens when the FunctionCall was on a
+ // pure function (not procedure) and the function got inlined
+ return retnary[0];
+ }
+ }
+
+ // Else, rename label
+ string newLabel = RenameAbsyLabel(lop.label);
+ if (lop.pos) {
+ return Gen.LabelPos(newLabel, retnary[0]);
+ }
+ else {
+ return Gen.LabelNeg(newLabel, retnary[0]);
+ }
+
+ }
+
+ // Upgrades summaryTemp to summaryCandidates by matching ensure clauses with
+ // the appropriate candidate they came from
+ public void matchSummaries() {
+ var id2Set = new Dictionary<string, List<Tuple<int, HashSet<VCExprVar>>>>();
+ foreach (var id in recentlyAddedCandidates) {
+ var collect = new CollectVCVars();
+ var proc = getProc(id);
+ if (!id2Set.ContainsKey(proc)) id2Set.Add(proc, new List<Tuple<int, HashSet<VCExprVar>>>());
+ id2Set[proc].Add(Tuple.Create(id, collect.Collect(id2Candidate[id], true)));
+ }
+
+ foreach (var kvp in summaryTemp) {
+ Contract.Assert(id2Set.ContainsKey(kvp.Key));
+ var ls = id2Set[kvp.Key];
+ foreach (var tup in kvp.Value) {
+ var collect = new CollectVCVars();
+ var s1 = collect.Collect(tup.Item2, true);
+ var found = false;
+ foreach (var t in ls) {
+ var s2 = t.Item2;
+ if (s1.IsSubsetOf(s2)) {
+ if (!summaryCandidates.ContainsKey(t.Item1))
+ summaryCandidates.Add(t.Item1, new List<Tuple<VCExprVar, VCExpr>>());
+ summaryCandidates[t.Item1].Add(tup);
+ allSummaryConst.Add(tup.Item1);
+ found = true;
+ break;
+ }
+ }
+ Contract.Assert(found);
+ }
+ }
+ summaryTemp.Clear();
+ }
+
+ public IEnumerable<int> getInlinedCandidates() {
+ return candidateParent.Keys.Except(currCandidates).Union(new int[] { 0 });
+ }
+
+ } // end FCallHandler
+
+ // Collects the set of all VCExprVar in a given VCExpr
+ class CollectVCVars : CollectingVCExprVisitor<HashSet<VCExprVar>, bool> {
+ public override HashSet<VCExprVar> Visit(VCExprVar node, bool arg) {
+ var ret = new HashSet<VCExprVar>();
+ ret.Add(node);
+ return ret;
+ }
+
+ protected override HashSet<VCExprVar> CombineResults(List<HashSet<VCExprVar>> results, bool arg) {
+ var ret = new HashSet<VCExprVar>();
+ results.Iter(s => ret.UnionWith(s));
+ return ret;
+ }
+ }
+
+ public class FCallInliner : MutatingVCExprVisitor<bool> {
+ public Dictionary<int, VCExpr/*!*/>/*!*/ subst;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullDictionaryAndValues(subst));
+ }
+
+
+ public FCallInliner(VCExpressionGenerator gen)
+ : base(gen) {
+ Contract.Requires(gen != null);
+ subst = new Dictionary<int, VCExpr>();
+ }
+
+ public void Clear() {
+ subst = new Dictionary<int, VCExpr>();
+ }
+
+ protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
+ List<VCExpr/*!*/>/*!*/ newSubExprs,
+ // has any of the subexpressions changed?
+ bool changed,
+ bool arg) {
+ //Contract.Requires(originalNode != null);Contract.Requires(newSubExprs != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ VCExpr ret;
+ if (changed)
+ ret = Gen.Function(originalNode.Op, newSubExprs, originalNode.TypeArguments);
+ else
+ ret = originalNode;
+
+ VCExprLabelOp lop = originalNode.Op as VCExprLabelOp;
+ if (lop == null) return ret;
+ if (!(ret is VCExprNAry)) return ret;
+
+ string prefix = "si_fcall_"; // from FCallHandler::GetLabel
+ if (lop.label.Substring(1).StartsWith(prefix)) {
+ int id = Int32.Parse(lop.label.Substring(prefix.Length + 1));
+ if (subst.ContainsKey(id)) {
+ return subst[id];
+ }
+ }
+ return ret;
+ }
+
+ } // end FCallInliner
+
+
+
+ public class StratifiedInliningErrorReporter : ProverInterface.ErrorHandler {
+ Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo;
+ ProverInterface theoremProver;
+ VerifierCallback callback;
+ FCallHandler calls;
+ StratifiedInliningInfo mainInfo;
+ StratifiedVC mainVC;
+
+ public bool underapproximationMode;
+ public List<int> candidatesToExpand;
+ public List<StratifiedCallSite> callSitesToExpand;
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(candidatesToExpand != null);
+ Contract.Invariant(mainInfo != null);
+ Contract.Invariant(callback != null);
+ Contract.Invariant(theoremProver != null);
+ Contract.Invariant(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
+ }
+
+
+ public StratifiedInliningErrorReporter(Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo,
+ ProverInterface theoremProver, VerifierCallback callback,
+ StratifiedInliningInfo mainInfo) {
+ Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
+ Contract.Requires(theoremProver != null);
+ Contract.Requires(callback != null);
+ Contract.Requires(mainInfo != null);
+ this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo;
+ this.theoremProver = theoremProver;
+ this.callback = callback;
+ this.mainInfo = mainInfo;
+ this.underapproximationMode = false;
+ this.calls = null;
+ this.candidatesToExpand = new List<int>();
+ }
+
+ public StratifiedInliningErrorReporter(Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo,
+ ProverInterface theoremProver, VerifierCallback callback,
+ StratifiedVC mainVC) {
+ Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
+ Contract.Requires(theoremProver != null);
+ Contract.Requires(callback != null);
+ Contract.Requires(mainVC != null);
+ this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo;
+ this.theoremProver = theoremProver;
+ this.callback = callback;
+ this.mainVC = mainVC;
+ this.underapproximationMode = false;
+ this.candidatesToExpand = new List<int>();
+ }
+
+ public void SetCandidateHandler(FCallHandler calls) {
+ Contract.Requires(calls != null);
+ this.calls = calls;
+ }
+
+ List<Tuple<int, int>> orderedStateIds;
+
+ private Model.Element GetModelValue(Model m, Variable v, int candidateId) {
+ // first, get the unique name
+ string uniqueName;
+
+ VCExprVar vvar = theoremProver.Context.BoogieExprTranslator.TryLookupVariable(v);
+ if (vvar == null) {
+ uniqueName = v.Name;
+ }
+ else {
+ if (candidateId != 0) {
+ Dictionary<VCExprVar, VCExpr> mapping = calls.id2Vars[candidateId];
+ if (mapping.ContainsKey(vvar)) {
+ VCExpr e = mapping[vvar];
+ if (e is VCExprLiteral) {
+ VCExprLiteral lit = (VCExprLiteral)e;
+ return m.MkElement(lit.ToString());
+ }
+ vvar = (VCExprVar)mapping[vvar];
+ }
+ }
+ uniqueName = theoremProver.Context.Lookup(vvar);
+ }
+
+ var f = m.TryGetFunc(uniqueName);
+ if (f == null)
+ return m.MkFunc("@undefined", 0).GetConstant();
+ return f.GetConstant();
+ }
+
+ public readonly static int CALL = -1;
+ public readonly static int RETURN = -2;
+
+ public void PrintModel(Model model) {
+ var filename = CommandLineOptions.Clo.ModelViewFile;
+ if (model == null || filename == null) return;
+
+ if (filename == "-") {
+ model.Write(Console.Out);
+ Console.Out.Flush();
+ }
+ else {
+ using (var wr = new StreamWriter(filename, !Counterexample.firstModelFile)) {
+ Counterexample.firstModelFile = false;
+ model.Write(wr);
+ }
+ }
+ }
+
+ private void GetModelWithStates(Model m) {
+ if (m == null) return;
+ var mvInfo = mainInfo.mvInfo;
+ var mvstates = m.TryGetFunc("$mv_state");
+ if (mvstates == null)
+ return;
+
+ Contract.Assert(mvstates.Arity == 2);
+
+ foreach (Variable v in mvInfo.AllVariables) {
+ m.InitialState.AddBinding(v.Name, GetModelValue(m, v, 0));
+ }
+
+ int lastCandidate = 0;
+ int lastCapturePoint = CALL;
+ for (int i = 0; i < this.orderedStateIds.Count; ++i) {
+ var s = orderedStateIds[i];
+ int candidate = s.Item1;
+ int capturePoint = s.Item2;
+ string implName = calls.getProc(candidate);
+ ModelViewInfo info = candidate == 0 ? mvInfo : implName2StratifiedInliningInfo[implName].mvInfo;
+
+ if (capturePoint == CALL || capturePoint == RETURN) {
+ lastCandidate = candidate;
+ lastCapturePoint = capturePoint;
+ continue;
+ }
+
+ Contract.Assume(0 <= capturePoint && capturePoint < info.CapturePoints.Count);
+ VC.ModelViewInfo.Mapping map = info.CapturePoints[capturePoint];
+ var prevInc = (lastCapturePoint != CALL && lastCapturePoint != RETURN && candidate == lastCandidate)
+ ? info.CapturePoints[lastCapturePoint].IncarnationMap : new Dictionary<Variable, Expr>();
+ var cs = m.MkState(map.Description);
+
+ foreach (Variable v in info.AllVariables) {
+ var e = (Expr)map.IncarnationMap[v];
+
+ if (e == null) {
+ if (lastCapturePoint == CALL || lastCapturePoint == RETURN) {
+ cs.AddBinding(v.Name, GetModelValue(m, v, candidate));
+ }
+ continue;
+ }
+
+ if (lastCapturePoint != CALL && lastCapturePoint != RETURN && prevInc[v] == e) continue; // skip unchanged variables
+
+ Model.Element elt;
+ if (e is IdentifierExpr) {
+ IdentifierExpr ide = (IdentifierExpr)e;
+ elt = GetModelValue(m, ide.Decl, candidate);
+ }
+ else if (e is LiteralExpr) {
+ LiteralExpr lit = (LiteralExpr)e;
+ elt = m.MkElement(lit.Val.ToString());
+ }
+ else {
+ Contract.Assume(false);
+ elt = m.MkFunc(e.ToString(), 0).GetConstant();
+ }
+ cs.AddBinding(v.Name, elt);
+ }
+
+ lastCandidate = candidate;
+ lastCapturePoint = capturePoint;
+ }
+
+ return;
+ }
+
+ public override void OnResourceExceeded(string message, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null)
+ {
+ //Contract.Requires(message != null);
+ }
+
+ public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) {
+ if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) {
+ model.Write(ErrorReporter.ModelWriter);
+ ErrorReporter.ModelWriter.Flush();
+ }
+
+ // Timeout?
+ if (proverOutcome != ProverInterface.Outcome.Invalid)
+ return;
+
+ candidatesToExpand = new List<int>();
+ orderedStateIds = new List<Tuple<int, int>>();
+ var cex = GenerateTrace(labels, model, 0, mainInfo.impl, mainInfo.mvInfo);
+
+ if (underapproximationMode && cex != null) {
+ //Debug.Assert(candidatesToExpand.All(calls.isSkipped));
+ GetModelWithStates(model);
+ callback.OnCounterexample(cex, null);
+ this.PrintModel(model);
+ }
+ }
+
+ private Counterexample GenerateTrace(IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel,
+ int candidateId, Implementation procImpl, ModelViewInfo mvInfo) {
+ Contract.Requires(cce.NonNullElements(labels));
+ Contract.Requires(procImpl != null);
+
+ Hashtable traceNodes = new Hashtable();
+
+ if (!CommandLineOptions.Clo.SIBoolControlVC)
+ {
+ foreach (string s in labels)
+ {
+ Contract.Assert(s != null);
+ var absylabel = calls.ParseRenamedAbsyLabel(s, candidateId);
+
+ if (absylabel == null) continue;
+
+ Absy absy;
+
+ if (candidateId == 0)
+ {
+ absy = Label2Absy(absylabel);
+ }
+ else
+ {
+ absy = Label2Absy(procImpl.Name, absylabel);
+ }
+
+ if (traceNodes.ContainsKey(absy))
+ System.Console.WriteLine("Warning: duplicate label: " + s + " read while tracing nodes");
+ else
+ traceNodes.Add(absy, null);
+ }
+ }
+ else
+ {
+ Debug.Assert(CommandLineOptions.Clo.UseProverEvaluate, "Must use prover evaluate option with boolControlVC");
+ var block = procImpl.Blocks[0];
+ traceNodes.Add(block, null);
+ while (true)
+ {
+ var gc = block.TransferCmd as GotoCmd;
+ if (gc == null) break;
+ Block next = null;
+ foreach (var succ in gc.labelTargets)
+ {
+ var succtaken = (bool) theoremProver.Evaluate(calls.candiate2block2controlVar[candidateId][succ]);
+ if (succtaken)
+ {
+ next = succ;
+ traceNodes.Add(succ, null);
+ break;
+ }
+ }
+ Debug.Assert(next != null, "Must find a successor");
+ Debug.Assert(traceNodes.ContainsKey(next), "CFG cannot be cyclic");
+ block = next;
+ }
+ }
+
+ List<Block> trace = new List<Block>();
+ Block entryBlock = cce.NonNull(procImpl.Blocks[0]);
+ Contract.Assert(entryBlock != null);
+ Contract.Assert(traceNodes.Contains(entryBlock));
+ trace.Add(entryBlock);
+
+ var calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
+ Counterexample newCounterexample = GenerateTraceRec(labels, errModel, mvInfo, candidateId, entryBlock, traceNodes, trace, calleeCounterexamples);
+
+ return newCounterexample;
+ }
+
+ private Counterexample GenerateTraceRec(
+ IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel, ModelViewInfo mvInfo,
+ int candidateId,
+ Block/*!*/ b, Hashtable/*!*/ traceNodes, List<Block>/*!*/ trace,
+ Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples) {
+ Contract.Requires(cce.NonNullElements(labels));
+ Contract.Requires(b != null);
+ Contract.Requires(traceNodes != null);
+ Contract.Requires(trace != null);
+ Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples));
+ // After translation, all potential errors come from asserts.
+ while (true) {
+ List<Cmd> cmds = b.Cmds;
+ TransferCmd transferCmd = cce.NonNull(b.TransferCmd);
+ for (int i = 0; i < cmds.Count; i++) {
+ Cmd cmd = cce.NonNull(cmds[i]);
+
+ // Skip if 'cmd' not contained in the trace or not an assert
+ if ((cmd is AssertCmd && traceNodes.Contains(cmd)) ||
+ (cmd is AssumeCmd && QKeyValue.FindBoolAttribute((cmd as AssumeCmd).Attributes, "exitAssert")))
+ {
+ var acmd = cmd as AssertCmd;
+ if (acmd == null) { acmd = new AssertCmd(Token.NoToken, Expr.True); }
+ Counterexample newCounterexample = AssertCmdToCounterexample(acmd, transferCmd, trace, errModel, mvInfo, theoremProver.Context);
+ newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
+ return newCounterexample;
+ }
+
+ // Counterexample generation for inlined procedures
+ AssumeCmd assumeCmd = cmd as AssumeCmd;
+ if (assumeCmd == null)
+ continue;
+ NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
+ if (naryExpr == null)
+ continue;
+ string calleeName = naryExpr.Fun.FunctionName;
+ Contract.Assert(calleeName != null);
+
+ BinaryOperator binOp = naryExpr.Fun as BinaryOperator;
+ if (binOp != null && binOp.Op == BinaryOperator.Opcode.And) {
+ Expr expr = naryExpr.Args[0];
+ NAryExpr mvStateExpr = expr as NAryExpr;
+ if (mvStateExpr != null && mvStateExpr.Fun.FunctionName == ModelViewInfo.MVState_FunctionDef.Name) {
+ LiteralExpr x = mvStateExpr.Args[1] as LiteralExpr;
+ orderedStateIds.Add(new Tuple<int, int>(candidateId, x.asBigNum.ToInt));
+ }
+ }
+
+ if (calleeName.StartsWith(recordProcName) && (errModel != null || CommandLineOptions.Clo.UseProverEvaluate)) {
+ var expr = calls.recordExpr2Var[new BoogieCallExpr(naryExpr, candidateId)];
+
+ // Record concrete value of the argument to this procedure
+ var args = new List<object>();
+ if (errModel == null && CommandLineOptions.Clo.UseProverEvaluate)
+ {
+ object exprv;
+ try
+ {
+ exprv = theoremProver.Evaluate(expr);
+ }
+ catch (Exception)
+ {
+ exprv = null;
+ }
+ args.Add(exprv);
+ }
+ else
+ {
+ if (expr is VCExprIntLit)
+ {
+ args.Add(errModel.MkElement((expr as VCExprIntLit).Val.ToString()));
+ }
+ else if (expr == VCExpressionGenerator.True)
+ {
+ args.Add(errModel.MkElement("true"));
+ }
+ else if (expr == VCExpressionGenerator.False)
+ {
+ args.Add(errModel.MkElement("false"));
+ }
+ else if (expr is VCExprVar)
+ {
+ var idExpr = expr as VCExprVar;
+ string name = theoremProver.Context.Lookup(idExpr);
+ Contract.Assert(name != null);
+ Model.Func f = errModel.TryGetFunc(name);
+ if (f != null)
+ {
+ args.Add(f.GetConstant());
+ }
+ }
+ else
+ {
+ Contract.Assert(false);
+ }
+ }
+ calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] =
+ new CalleeCounterexampleInfo(null, args);
+ continue;
+ }
+
+ if (!implName2StratifiedInliningInfo.ContainsKey(calleeName))
+ continue;
+
+ Contract.Assert(calls != null);
+
+ int calleeId = calls.boogieExpr2Id[new BoogieCallExpr(naryExpr, candidateId)];
+
+ if (calls.currCandidates.Contains(calleeId)) {
+ candidatesToExpand.Add(calleeId);
+ }
+ else {
+ orderedStateIds.Add(new Tuple<int, int>(calleeId, StratifiedInliningErrorReporter.CALL));
+ var calleeInfo = implName2StratifiedInliningInfo[calleeName];
+ calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] =
+ new CalleeCounterexampleInfo(GenerateTrace(labels, errModel, calleeId, calleeInfo.impl, calleeInfo.mvInfo), new List<object>());
+ orderedStateIds.Add(new Tuple<int, int>(candidateId, StratifiedInliningErrorReporter.RETURN));
+ }
+ }
+
+ GotoCmd gotoCmd = transferCmd as GotoCmd;
+ if (gotoCmd != null) {
+ b = null;
+ foreach (Block bb in cce.NonNull(gotoCmd.labelTargets)) {
+ Contract.Assert(bb != null);
+ if (traceNodes.Contains(bb)) {
+ trace.Add(bb);
+ b = bb;
+ break;
+ }
+ }
+ if (b != null) continue;
+ }
+ return null;
+ }
+ }
+
+ public override Absy Label2Absy(string label) {
+ //Contract.Requires(label != null);
+ Contract.Ensures(Contract.Result<Absy>() != null);
+
+ int id = int.Parse(label);
+ Contract.Assert(calls != null);
+ return cce.NonNull((Absy)calls.mainLabel2absy[id]);
+ }
+
+ public Absy Label2Absy(string procName, string label) {
+ Contract.Requires(label != null);
+ Contract.Requires(procName != null);
+ Contract.Ensures(Contract.Result<Absy>() != null);
+
+ int id = int.Parse(label);
+ Dictionary<int, Absy> l2a = cce.NonNull(implName2StratifiedInliningInfo[procName]).label2absy;
+ return cce.NonNull((Absy)l2a[id]);
+ }
+
+ public override void OnProverWarning(string msg) {
+ //Contract.Requires(msg != null);
+ callback.OnWarning(msg);
+ }
+ }
+
+ } // class StratifiedVCGen
+
+ public class EmptyErrorHandler : ProverInterface.ErrorHandler
+ {
+ public override void OnModel(IList<string> labels, Model model, ProverInterface.Outcome proverOutcome)
+ { }
+ }
+
+ public class InvalidProgramForSecureVc : Exception
+ {
+ public InvalidProgramForSecureVc(string msg) :
+ base(msg) { }
+ }
+
+ public class SecureVCGen : VCGen
+ {
+ // Z3
+ ProverInterface prover;
+ // Handler
+ ErrorReporter handler;
+ // dump file
+ public static TokenTextWriter outfile = null;
+
+
+ public SecureVCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
+ : base(program, logFilePath, appendLogFile, checkers)
+ {
+ prover = null;
+ handler = null;
+ if (CommandLineOptions.Clo.SecureVcGen != "" && outfile == null)
+ {
+ outfile = new TokenTextWriter(new StreamWriter(CommandLineOptions.Clo.SecureVcGen));
+ CommandLineOptions.Clo.PrintInstrumented = true;
+ var implsToVerify = new HashSet<string>(
+ program.TopLevelDeclarations.OfType<Implementation>()
+ .Where(impl => !impl.SkipVerification)
+ .Select(impl => impl.Name));
+
+ foreach (var decl in program.TopLevelDeclarations)
+ {
+ if (decl is NamedDeclaration && implsToVerify.Contains((decl as NamedDeclaration).Name))
+ continue;
+ decl.Emit(outfile, 0);
+ }
+ }
+ }
+
+ private Block GetExitBlock(Implementation impl)
+ {
+ var exitblocks = impl.Blocks.Where(blk => blk.TransferCmd is ReturnCmd);
+ if (exitblocks.Count() == 1)
+ return exitblocks.First();
+ // create a new exit block
+ var eb = new Block(Token.NoToken, "SVCeb", new List<Cmd>(), new ReturnCmd(Token.NoToken));
+ foreach (var b in exitblocks)
+ {
+ b.TransferCmd = new GotoCmd(Token.NoToken, new List<Block> { eb });
+ }
+ impl.Blocks.Add(eb);
+ return eb;
+ }
+
+ //static int LocalVarCounter = 0;
+ private LocalVariable GetNewLocal(Variable v, string suffix)
+ {
+ return new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken,
+ string.Format("svc_{0}_{1}", v.Name, suffix), v.TypedIdent.Type));
+ }
+
+ private void GenVc(Implementation impl, VerifierCallback collector)
+ {
+ if (impl.Proc.Requires.Any())
+ throw new InvalidProgramForSecureVc("SecureVc: Requires not supported");
+ if(impl.LocVars.Any(v => isVisible(v)))
+ throw new InvalidProgramForSecureVc("SecureVc: Visible Local variables not allowed");
+
+ // Desugar procedure calls
+ DesugarCalls(impl);
+
+ // Gather spec, remove existing ensures
+ var secureAsserts = new List<AssertCmd>();
+ var logicalAsserts = new List<AssertCmd>();
+
+ foreach (var ens in impl.Proc.Ensures)
+ {
+ if(ens.Free)
+ throw new InvalidProgramForSecureVc("SecureVc: Free Ensures not supported");
+ var dd = new Duplicator();
+ secureAsserts.Add(new AssertCmd(ens.tok, Expr.Not(ens.Condition)));
+ logicalAsserts.Add(dd.VisitAssertCmd(new AssertCmd(ens.tok, ens.Condition)) as AssertCmd);
+ }
+ impl.Proc.Ensures.Clear();
+
+ // Make a copy of the impl
+ var dup = new Duplicator();
+ var implDup = dup.VisitImplementation(impl);
+
+ // Get exit block
+ var eb = GetExitBlock(impl);
+
+ // Create two blocks: one for secureAsserts, one for logical asserts
+ var ebSecure = new Block(Token.NoToken, "svc_secure_asserts", new List<Cmd>(), new ReturnCmd(Token.NoToken));
+ var ebLogical = new Block(Token.NoToken, "svc_logical_asserts", new List<Cmd>(), new ReturnCmd(Token.NoToken));
+
+ eb.TransferCmd = new GotoCmd(eb.TransferCmd.tok, new List<Block> { ebSecure, ebLogical });
+ impl.Blocks.Add(ebSecure);
+ impl.Blocks.Add(ebLogical);
+
+ // Rename spec, while create copies of the hidden variables
+ var substOld = new Dictionary<Variable, Expr>();
+ var substVarSpec = new Dictionary<Variable, Expr>();
+ var substVarPath = new Dictionary<Variable, Expr>();
+ foreach (var g in program.GlobalVariables)
+ {
+ if (!isHidden(g)) continue;
+ var lv = GetNewLocal(g, "In");
+ impl.LocVars.Add(lv);
+ substOld.Add(g, Expr.Ident(lv));
+ }
+
+ for(int i = 0; i < impl.InParams.Count; i++)
+ {
+ var v = impl.Proc.InParams[i];
+ if (!isHidden(v))
+ {
+ substVarSpec.Add(impl.Proc.InParams[i], Expr.Ident(impl.InParams[i]));
+ continue;
+ }
+
+ var lv = GetNewLocal(v, "In");
+ impl.LocVars.Add(lv);
+ substVarSpec.Add(v, Expr.Ident(lv));
+ substVarPath.Add(impl.InParams[i], Expr.Ident(lv));
+ }
+
+ for (int i = 0; i < impl.OutParams.Count; i++)
+ {
+ var v = impl.Proc.OutParams[i];
+ if (!isHidden(v))
+ {
+ substVarSpec.Add(impl.Proc.OutParams[i], Expr.Ident(impl.OutParams[i]));
+ continue;
+ }
+
+ var lv = GetNewLocal(v, "Out");
+ impl.LocVars.Add(lv);
+ substVarSpec.Add(v, Expr.Ident(lv));
+ substVarPath.Add(impl.OutParams[i], Expr.Ident(lv));
+ }
+
+ foreach (var g in program.GlobalVariables)
+ {
+ if (!isHidden(g)) continue;
+ if (!impl.Proc.Modifies.Any(ie => ie.Name == g.Name)) continue;
+
+ var lv = GetNewLocal(g, "Out");
+ impl.LocVars.Add(lv);
+ substVarSpec.Add(g, Expr.Ident(lv));
+ substVarPath.Add(g, Expr.Ident(lv));
+ }
+
+ secureAsserts = secureAsserts.ConvertAll(ac =>
+ Substituter.ApplyReplacingOldExprs(
+ Substituter.SubstitutionFromHashtable(substVarSpec),
+ Substituter.SubstitutionFromHashtable(substOld),
+ ac) as AssertCmd);
+
+ var substVarProcToImpl = new Dictionary<Variable, Expr>();
+ for (int i = 0; i < impl.InParams.Count; i++)
+ substVarProcToImpl.Add(impl.Proc.InParams[i], Expr.Ident(impl.InParams[i]));
+
+ for (int i = 0; i < impl.OutParams.Count; i++)
+ substVarProcToImpl.Add(impl.Proc.OutParams[i], Expr.Ident(impl.OutParams[i]));
+
+ logicalAsserts = logicalAsserts.ConvertAll(ac =>
+ Substituter.Apply(Substituter.SubstitutionFromHashtable(substVarProcToImpl), ac)
+ as AssertCmd);
+
+ // Paths
+ foreach (var path in GetAllPaths(implDup))
+ {
+ var wp = ComputeWP(implDup, path);
+
+ // replace hidden variables to match those used in the spec
+ wp = Substituter.ApplyReplacingOldExprs(
+ Substituter.SubstitutionFromHashtable(substVarPath),
+ Substituter.SubstitutionFromHashtable(substOld),
+ wp);
+
+ ebSecure.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.Not(wp)));
+ }
+
+ ebSecure.Cmds.AddRange(secureAsserts);
+ ebLogical.Cmds.AddRange(logicalAsserts);
+
+ if (outfile != null)
+ {
+ impl.Proc.Emit(outfile, 0);
+ impl.Emit(outfile, 0);
+ }
+
+ ModelViewInfo mvInfo;
+ ConvertCFG2DAG(impl);
+ var gotoCmdOrigins = PassifyImpl(impl, out mvInfo);
+
+ var gen = prover.VCExprGen;
+ var exprGen = prover.Context.ExprGen;
+ var translator = prover.Context.BoogieExprTranslator;
+
+ var label2absy = new Dictionary<int, Absy>();
+ VCGen.CodeExprConversionClosure cc = new VCGen.CodeExprConversionClosure(label2absy, prover.Context);
+ translator.SetCodeExprConverter(cc.CodeExprToVerificationCondition);
+ var implVc = gen.Not(GenerateVCAux(impl, null, label2absy, prover.Context));
+
+ handler = new VCGen.ErrorReporter(gotoCmdOrigins, label2absy, impl.Blocks, incarnationOriginMap, collector, mvInfo, prover.Context, program);
+
+ prover.Assert(implVc, true);
+ }
+
+ Expr ComputeWP(Implementation impl, List<Cmd> path)
+ {
+ Expr expr = Expr.True;
+
+ // create constants for out varibles
+ var subst = new Dictionary<Variable, Expr>();
+ foreach (var g in impl.Proc.Modifies)
+ {
+ var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken,
+ "svc_out_const_" + g.Name, g.Decl.TypedIdent.Type));
+ subst.Add(c, g);
+ expr = Expr.And(expr, Expr.Eq(Expr.Ident(c), g));
+ }
+
+ foreach (var v in impl.OutParams)
+ {
+ var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken,
+ "svc_out_const_" + v.Name, v.TypedIdent.Type));
+ subst.Add(c, Expr.Ident(v));
+ expr = Expr.And(expr, Expr.Eq(Expr.Ident(c), Expr.Ident(v)));
+ }
+
+ // we need this technicality
+ var subst1 = new Dictionary<Variable, Expr>();
+ foreach (var g in program.GlobalVariables)
+ {
+ subst1.Add(g, new OldExpr(Token.NoToken, Expr.Ident(g)));
+ }
+
+ // Implicitly close with havoc of all the locals and OutParams
+ path.Insert(0, new HavocCmd(Token.NoToken, new List<IdentifierExpr>(
+ impl.LocVars.Select(v => Expr.Ident(v)).Concat(
+ impl.OutParams.Select(v => Expr.Ident(v))))));
+
+ for (int i = path.Count - 1; i >= 0; i--)
+ {
+ var cmd = path[i];
+ if (cmd is AssumeCmd)
+ {
+ expr = Expr.And(expr, (cmd as AssumeCmd).Expr);
+ }
+ else if (cmd is AssignCmd)
+ {
+ var h = new Dictionary<Variable, Expr>();
+ var acmd = cmd as AssignCmd;
+ for (int j = 0; j < acmd.Lhss.Count; j++)
+ {
+ h.Add(acmd.Lhss[j].DeepAssignedVariable, acmd.Rhss[j]);
+ }
+ var s = Substituter.SubstitutionFromHashtable(h);
+ expr = Substituter.Apply(s, expr);
+ }
+ else if (cmd is HavocCmd)
+ {
+ var h = new Dictionary<Variable, Expr>();
+ var formals = new List<Variable>();
+
+ var vc = new VariableCollector();
+ vc.VisitExpr(expr);
+
+ foreach (var ie in (cmd as HavocCmd).Vars)
+ {
+ if (!vc.usedVars.Contains(ie.Decl)) continue;
+ var f = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken,
+ ie.Decl.Name + "_formal", ie.Decl.TypedIdent.Type));
+ h.Add(ie.Decl, Expr.Ident(f));
+ formals.Add(f);
+ }
+ if (!formals.Any())
+ continue;
+ var s = Substituter.SubstitutionFromHashtable(h);
+ expr = Substituter.Apply(s, expr);
+ expr = new ExistsExpr(Token.NoToken, formals, expr);
+ }
+ else
+ {
+ throw new InvalidProgramForSecureVc(string.Format("Unhandled cmd: {0}", cmd));
+ }
+ }
+
+ // Implicitly close with havoc of all the locals and OutParams
+
+
+
+ expr = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst1), expr);
+ expr = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst),
+ Substituter.SubstitutionFromHashtable(new Dictionary<Variable,Expr>()), expr);
+ expr.Typecheck(new TypecheckingContext(null));
+ return expr;
+ }
+
+ // Generate all paths in the impl
+ IEnumerable<List<Cmd>> GetAllPaths(Implementation impl)
+ {
+ var stk = new Stack<Tuple<Block, int>>();
+ stk.Push(Tuple.Create(impl.Blocks[0], 0));
+
+ while (stk.Any())
+ {
+ var tup = stk.Peek();
+ if (tup.Item1.TransferCmd is ReturnCmd)
+ {
+ var ret = new List<Cmd>();
+ var ls = stk.ToList();
+ ls.Iter(t => ret.AddRange(t.Item1.Cmds));
+ yield return ret;
+
+ stk.Pop();
+ continue;
+ }
+
+ stk.Pop();
+
+ var gc = tup.Item1.TransferCmd as GotoCmd;
+ if (gc.labelTargets.Count <= tup.Item2)
+ continue;
+
+ stk.Push(Tuple.Create(tup.Item1, tup.Item2 + 1));
+ stk.Push(Tuple.Create(gc.labelTargets[tup.Item2], 0));
+ }
+ yield break;
+ }
+
+ bool isHidden(Variable v)
+ {
+ return QKeyValue.FindBoolAttribute(v.Attributes, "hidden");
+ }
+
+ bool isVisible(Variable v)
+ {
+ return !isHidden(v);
+ }
+
+ public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback)
+ {
+ Debug.Assert(this.program == program);
+
+ // Record current time
+ var startTime = DateTime.UtcNow;
+
+ CommandLineOptions.Clo.ProverCCLimit = 1;
+ prover = ProverInterface.CreateProver(program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime);
+
+ // Flush any axioms that came with the program before we start SI on this implementation
+ prover.AssertAxioms();
+
+ GenVc(impl, callback);
+
+ prover.Check();
+ var outcome = prover.CheckOutcomeCore(handler);
+ //var outcome = ProverInterface.Outcome.Valid;
+
+ prover.Close();
+
+
+
+ //Console.WriteLine("Answer = {0}", outcome);
+
+ return ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
+ }
+ }
+
+} // namespace VC
diff --git a/Source/VCGeneration/VC.cs b/Source/VCGeneration/VC.cs
index 8e5c853c..b457b383 100644
--- a/Source/VCGeneration/VC.cs
+++ b/Source/VCGeneration/VC.cs
@@ -1,3935 +1,3935 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Threading;
-using System.IO;
-using Microsoft.Boogie;
-using Microsoft.Boogie.GraphUtil;
-using System.Diagnostics.Contracts;
-using Microsoft.Basetypes;
-using Microsoft.Boogie.VCExprAST;
-
-namespace VC {
- using Bpl = Microsoft.Boogie;
- using System.Threading.Tasks;
-
- public class VCGen : ConditionGeneration {
- private const bool _print_time = false;
- /// <summary>
- /// Constructor. Initializes the theorem prover.
- /// </summary>
- [NotDelayed]
- public VCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
- : base(program, checkers)
- {
- Contract.Requires(program != null);
- this.appendLogFile = appendLogFile;
- this.logFilePath = logFilePath;
- }
-
- private static AssumeCmd AssertTurnedIntoAssume(AssertCmd assrt) {
- Contract.Requires(assrt != null);
- Contract.Ensures(Contract.Result<AssumeCmd>() != null);
-
- Expr expr = assrt.Expr;
- Contract.Assert(expr != null);
- switch (Wlp.Subsumption(assrt)) {
- case CommandLineOptions.SubsumptionOption.Never:
- expr = Expr.True;
- break;
- case CommandLineOptions.SubsumptionOption.Always:
- break;
- case CommandLineOptions.SubsumptionOption.NotForQuantifiers:
- if (expr is QuantifierExpr) {
- expr = Expr.True;
- }
- break;
- default:
- Contract.Assert(false);
- throw new cce.UnreachableException(); // unexpected case
- }
-
- return new AssumeCmd(assrt.tok, expr);
- }
-
- #region Soundness smoke tester
- class SmokeTester {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(parent != null);
- Contract.Invariant(impl != null);
- Contract.Invariant(initial != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(copies));
- Contract.Invariant(cce.NonNull(visited));
- Contract.Invariant(callback != null);
- }
-
- VCGen parent;
- Implementation impl;
- Block initial;
- int id;
- Dictionary<Block, Block> copies = new Dictionary<Block, Block>();
- HashSet<Block> visited = new HashSet<Block>();
- VerifierCallback callback;
-
- internal SmokeTester(VCGen par, Implementation i, VerifierCallback callback) {
- Contract.Requires(par != null);
- Contract.Requires(i != null);
- Contract.Requires(callback != null);
- parent = par;
- impl = i;
- initial = i.Blocks[0];
- this.callback = callback;
- }
-
- internal void Copy() {
- CloneBlock(impl.Blocks[0]);
- initial = GetCopiedBlocks()[0];
- }
-
- internal void Test() {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- DFS(initial);
- }
-
- void TopologicalSortImpl() {
- Graph<Block> dag = new Graph<Block>();
- dag.AddSource(cce.NonNull(impl.Blocks[0])); // there is always at least one node in the graph
- foreach (Block b in impl.Blocks) {
- GotoCmd gtc = b.TransferCmd as GotoCmd;
- if (gtc != null) {
- Contract.Assume(gtc.labelTargets != null);
- foreach (Block dest in gtc.labelTargets) {
- Contract.Assert(dest != null);
- dag.AddEdge(b, dest);
- }
- }
- }
- impl.Blocks = new List<Block>();
- foreach (Block b in dag.TopologicalSort()) {
- Contract.Assert(b != null);
- impl.Blocks.Add(b);
- }
- }
-
- void Emit() {
- TopologicalSortImpl();
- EmitImpl(impl, false);
- }
-
- // this one copies forward
- Block CloneBlock(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<Block>() != null);
-
- Block fake_res;
- if (copies.TryGetValue(b, out fake_res)) {
- return cce.NonNull(fake_res);
- }
- Block res = new Block(b.tok, b.Label, new List<Cmd>(b.Cmds), null);
- copies[b] = res;
- if (b.TransferCmd is GotoCmd) {
- foreach (Block ch in cce.NonNull((GotoCmd)b.TransferCmd).labelTargets) {
- Contract.Assert(ch != null);
- CloneBlock(ch);
- }
- }
- foreach (Block p in b.Predecessors) {
- Contract.Assert(p != null);
- res.Predecessors.Add(CloneBlock(p));
- }
- return res;
- }
-
- // this one copies backwards
- Block CopyBlock(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<Block>() != null);
-
- Block fake_res;
- if (copies.TryGetValue(b, out fake_res)) {
- // fake_res should be Block! but the compiler fails
- return cce.NonNull(fake_res);
- }
- Block res;
- List<Cmd> seq = new List<Cmd>();
- foreach (Cmd c in b.Cmds) {
- Contract.Assert(c != null);
- AssertCmd turn = c as AssertCmd;
- if (!turnAssertIntoAssumes || turn == null) {
- seq.Add(c);
- } else {
- seq.Add(AssertTurnedIntoAssume(turn));
- }
- }
- res = new Block(b.tok, b.Label, seq, null);
- copies[b] = res;
- foreach (Block p in b.Predecessors) {
- Contract.Assert(p != null);
- res.Predecessors.Add(CopyBlock(p));
- }
- return res;
- }
-
- List<Block> GetCopiedBlocks() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
-
- // the order of nodes in res is random (except for the first one, being the entry)
- List<Block> res = new List<Block>();
- res.Add(copies[initial]);
-
- foreach (KeyValuePair<Block, Block> kv in copies) {
- Contract.Assert(kv.Key != null&&kv.Value!=null);
- GotoCmd go = kv.Key.TransferCmd as GotoCmd;
- ReturnCmd ret = kv.Key.TransferCmd as ReturnCmd;
- if (kv.Key != initial) {
- res.Add(kv.Value);
- }
- if (go != null) {
- GotoCmd copy = new GotoCmd(go.tok, new List<String>(), new List<Block>());
- kv.Value.TransferCmd = copy;
- foreach (Block b in cce.NonNull(go.labelTargets)) {
- Contract.Assert(b != null);
- Block c;
- if (copies.TryGetValue(b, out c)) {
- copy.AddTarget(cce.NonNull(c));
- }
- }
- } else if (ret != null) {
- kv.Value.TransferCmd = ret;
- } else {
- Contract.Assume(false);
- throw new cce.UnreachableException();
- }
- }
-
- copies.Clear();
-
- return res;
- }
-
- // check if e is true, false, !true, !false
- // if so return true and the value of the expression in val
- bool BooleanEval(Expr e, ref bool val) {
- Contract.Requires(e != null);
- LiteralExpr lit = e as LiteralExpr;
- NAryExpr call = e as NAryExpr;
-
- if (lit != null && lit.isBool) {
- val = lit.asBool;
- return true;
- } else if (call != null &&
- call.Fun is UnaryOperator &&
- ((UnaryOperator)call.Fun).Op == UnaryOperator.Opcode.Not &&
- BooleanEval(cce.NonNull(call.Args[0]), ref val)) {
- val = !val;
- return true;
- }
- // this is for the 0bv32 != 0bv32 generated by vcc
- else if (call != null &&
- call.Fun is BinaryOperator &&
- ((BinaryOperator)call.Fun).Op == BinaryOperator.Opcode.Neq &&
- call.Args[0] is LiteralExpr &&
- cce.NonNull(call.Args[0]).Equals(call.Args[1])) {
- val = false;
- return true;
- }
-
- return false;
- }
-
- bool IsFalse(Expr e) {
- Contract.Requires(e != null);
- bool val = false;
- return BooleanEval(e, ref val) && !val;
- }
-
- bool CheckUnreachable(Block cur, List<Cmd> seq)
- {
- Contract.Requires(cur != null);
- Contract.Requires(seq != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- foreach (Cmd cmd in seq)
- {
- AssertCmd assrt = cmd as AssertCmd;
- if (assrt != null && QKeyValue.FindBoolAttribute(assrt.Attributes, "PossiblyUnreachable"))
- return false;
- }
-
- DateTime start = DateTime.UtcNow;
- if (CommandLineOptions.Clo.Trace)
- {
- System.Console.Write(" soundness smoke test #{0} ... ", id);
- }
- callback.OnProgress("smoke", id, id, 0.0);
-
- Token tok = new Token();
- tok.val = "soundness smoke test assertion";
- seq.Add(new AssertCmd(tok, Expr.False));
- Block copy = CopyBlock(cur);
- Contract.Assert(copy != null);
- copy.Cmds = seq;
- List<Block> backup = impl.Blocks;
- Contract.Assert(backup != null);
- impl.Blocks = GetCopiedBlocks();
- copy.TransferCmd = new ReturnCmd(Token.NoToken);
- if (CommandLineOptions.Clo.TraceVerify)
- {
- System.Console.WriteLine();
- System.Console.WriteLine(" --- smoke #{0}, before passify", id);
- Emit();
- }
- parent.CurrentLocalVariables = impl.LocVars;
- ModelViewInfo mvInfo;
- parent.PassifyImpl(impl, out mvInfo);
- Dictionary<int, Absy> label2Absy;
- Checker ch = parent.FindCheckerFor(CommandLineOptions.Clo.SmokeTimeout);
- Contract.Assert(ch != null);
-
- ProverInterface.Outcome outcome = ProverInterface.Outcome.Undetermined;
- try
- {
- lock (ch)
- {
- var exprGen = ch.TheoremProver.Context.ExprGen;
- VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
-
- VCExpr vc = parent.GenerateVC(impl, controlFlowVariableExpr, out label2Absy, ch.TheoremProver.Context);
- Contract.Assert(vc != null);
-
- if (!CommandLineOptions.Clo.UseLabels)
- {
- VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
- VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
- vc = exprGen.Implies(eqExpr, vc);
- }
-
- impl.Blocks = backup;
-
- if (CommandLineOptions.Clo.TraceVerify)
- {
- System.Console.WriteLine(" --- smoke #{0}, after passify", id);
- Emit();
- }
-
- ch.BeginCheck(cce.NonNull(impl.Name + "_smoke" + id++), vc, new ErrorHandler(label2Absy, this.callback));
- }
-
- ch.ProverTask.Wait();
-
- lock (ch)
- {
- outcome = ch.ReadOutcome();
- }
- }
- finally
- {
- ch.GoBackToIdle();
- }
-
- parent.CurrentLocalVariables = null;
-
- DateTime end = DateTime.UtcNow;
- TimeSpan elapsed = end - start;
- if (CommandLineOptions.Clo.Trace)
- {
- System.Console.WriteLine(" [{0} s] {1}", elapsed.TotalSeconds,
- outcome == ProverInterface.Outcome.Valid ? "OOPS" :
- "OK" + (outcome == ProverInterface.Outcome.Invalid ? "" : " (" + outcome + ")"));
- }
-
- if (outcome == ProverInterface.Outcome.Valid)
- {
- // copy it again, so we get the version with calls, assignments and such
- copy = CopyBlock(cur);
- copy.Cmds = seq;
- impl.Blocks = GetCopiedBlocks();
- TopologicalSortImpl();
- callback.OnUnreachableCode(impl);
- impl.Blocks = backup;
- return true;
- }
- return false;
- }
-
- const bool turnAssertIntoAssumes = false;
-
- void DFS(Block cur) {
- Contract.Requires(cur != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- if (visited.Contains(cur))
- return;
- visited.Add(cur);
-
- List<Cmd> seq = new List<Cmd>();
- foreach (Cmd cmd_ in cur.Cmds) {
- Cmd cmd = cmd_;
- Contract.Assert(cmd != null);
- AssertCmd assrt = cmd as AssertCmd;
- AssumeCmd assm = cmd as AssumeCmd;
- CallCmd call = cmd as CallCmd;
-
- bool assumeFalse = false;
-
- if (assrt != null) {
- // we're not going any further
- // it's clear the user expected unreachable code here
- // it's not clear where did he expect it, maybe it would be right to insert
- // a check just one command before
- if (IsFalse(assrt.Expr))
- return;
-
-#if TURN_ASSERT_INFO_ASSUMES
- if (turnAssertIntoAssumes) {
- cmd = AssertTurnedIntoAssume(assrt);
- }
-#endif
- } else if (assm != null) {
- if (IsFalse(assm.Expr))
- assumeFalse = true;
- } else if (call != null) {
- foreach (Ensures e in (cce.NonNull(call.Proc)).Ensures) {
- Contract.Assert(e != null);
- if (IsFalse(e.Condition))
- assumeFalse = true;
- }
- }
-
- if (assumeFalse) {
- CheckUnreachable(cur, seq);
- return;
- }
-
- seq.Add(cmd);
- }
-
-
- GotoCmd go = cur.TransferCmd as GotoCmd;
- ReturnCmd ret = cur.TransferCmd as ReturnCmd;
-
- Contract.Assume(!(go != null && go.labelTargets == null && go.labelNames != null && go.labelNames.Count > 0));
-
- if (ret != null || (go != null && cce.NonNull(go.labelTargets).Count == 0)) {
- // we end in return, so there will be no more places to check
- CheckUnreachable(cur, seq);
- } else if (go != null) {
- bool needToCheck = true;
- // if all of our children have more than one parent, then
- // we're in the right place to check
- foreach (Block target in cce.NonNull(go.labelTargets)) {
- Contract.Assert(target != null);
- if (target.Predecessors.Count == 1) {
- needToCheck = false;
- }
- }
- if (needToCheck) {
- CheckUnreachable(cur, seq);
- }
- foreach (Block target in go.labelTargets) {
- Contract.Assert(target != null);
- DFS(target);
- }
- }
- }
-
- class ErrorHandler : ProverInterface.ErrorHandler {
- Dictionary<int, Absy> label2Absy;
- VerifierCallback callback;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(label2Absy != null);
- Contract.Invariant(callback != null);
- }
-
-
- public ErrorHandler(Dictionary<int, Absy> label2Absy, VerifierCallback callback) {
- Contract.Requires(label2Absy != null);
- Contract.Requires(callback != null);
- this.label2Absy = label2Absy;
- this.callback = callback;
- }
-
- public override Absy Label2Absy(string label) {
- //Contract.Requires(label != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- int id = int.Parse(label);
- return cce.NonNull((Absy)label2Absy[id]);
- }
-
- public override void OnProverWarning(string msg) {
- //Contract.Requires(msg != null);
- this.callback.OnWarning(msg);
- }
- }
- }
-
-
- #endregion
-
- #region Splitter
- class Split {
- class BlockStats {
- public bool big_block;
- public int id;
- public double assertion_cost;
- public double assumption_cost; // before multiplier
- public double incomming_paths;
- public List<Block>/*!>!*/ virtual_successors = new List<Block>();
- public List<Block>/*!>!*/ virtual_predecesors = new List<Block>();
- public HashSet<Block> reachable_blocks;
- public readonly Block block;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(virtual_successors));
- Contract.Invariant(cce.NonNullElements(virtual_predecesors));
- Contract.Invariant(block != null);
- }
-
-
- public BlockStats(Block b, int i) {
- Contract.Requires(b != null);
- block = b;
- assertion_cost = -1;
- id = i;
- }
- }
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(blocks));
- Contract.Invariant(cce.NonNullElements(big_blocks));
- Contract.Invariant(cce.NonNullDictionaryAndValues(stats));
- Contract.Invariant(cce.NonNullElements(assumized_branches));
- Contract.Invariant(gotoCmdOrigins != null);
- Contract.Invariant(parent != null);
- Contract.Invariant(impl != null);
- Contract.Invariant(copies != null);
- Contract.Invariant(cce.NonNull(protected_from_assert_to_assume));
- Contract.Invariant(cce.NonNull(keep_at_all));
- }
-
-
- readonly List<Block> blocks;
- readonly List<Block> big_blocks = new List<Block>();
- readonly Dictionary<Block/*!*/, BlockStats/*!*/>/*!*/ stats = new Dictionary<Block/*!*/, BlockStats/*!*/>();
- readonly int id;
- static int current_id = -1;
- Block split_block;
- bool assert_to_assume;
- List<Block/*!*/>/*!*/ assumized_branches = new List<Block/*!*/>();
-
- double score;
- bool score_computed;
- double total_cost;
- int assertion_count;
- double assertion_cost; // without multiplication by paths
- Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins;
- readonly public VCGen/*!*/ parent;
- Implementation/*!*/ impl;
-
- Dictionary<Block/*!*/, Block/*!*/>/*!*/ copies = new Dictionary<Block/*!*/, Block/*!*/>();
- bool doing_slice;
- double slice_initial_limit;
- double slice_limit;
- bool slice_pos;
- HashSet<Block/*!*/>/*!*/ protected_from_assert_to_assume = new HashSet<Block/*!*/>();
- HashSet<Block/*!*/>/*!*/ keep_at_all = new HashSet<Block/*!*/>();
-
- // async interface
- private Checker checker;
- private int splitNo;
- internal ErrorReporter reporter;
-
- public Split(List<Block/*!*/>/*!*/ blocks, Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins, VCGen/*!*/ par, Implementation/*!*/ impl) {
- Contract.Requires(cce.NonNullElements(blocks));
- Contract.Requires(gotoCmdOrigins != null);
- Contract.Requires(par != null);
- Contract.Requires(impl != null);
- this.blocks = blocks;
- this.gotoCmdOrigins = gotoCmdOrigins;
- this.parent = par;
- this.impl = impl;
- this.id = Interlocked.Increment(ref current_id);
- }
-
- public double Cost {
- get {
- ComputeBestSplit();
- return total_cost;
- }
- }
-
- public bool LastChance {
- get {
- ComputeBestSplit();
- return assertion_count == 1 && score < 0;
- }
- }
-
- public string Stats {
- get {
- ComputeBestSplit();
- return string.Format("(cost:{0:0}/{1:0}{2})", total_cost, assertion_cost, LastChance ? " last" : "");
- }
- }
-
- public void DumpDot(int no) {
- using (System.IO.StreamWriter sw = System.IO.File.CreateText(string.Format("split.{0}.dot", no))) {
- sw.WriteLine("digraph G {");
-
- ComputeBestSplit();
- List<Block> saved = assumized_branches;
- Contract.Assert(saved != null);
- assumized_branches = new List<Block>();
- DoComputeScore(false);
- assumized_branches = saved;
-
- foreach (Block b in big_blocks) {
- Contract.Assert(b != null);
- BlockStats s = GetBlockStats(b);
- foreach (Block t in s.virtual_successors) {
- Contract.Assert(t != null);
- sw.WriteLine("n{0} -> n{1};", s.id, GetBlockStats(t).id);
- }
- sw.WriteLine("n{0} [label=\"{1}:\\n({2:0.0}+{3:0.0})*{4:0.0}\"{5}];",
- s.id, b.Label,
- s.assertion_cost, s.assumption_cost, s.incomming_paths,
- s.assertion_cost > 0 ? ",shape=box" : "");
-
- }
- sw.WriteLine("}");
- sw.Close();
- }
-
- string filename = string.Format("split.{0}.bpl", no);
- using (System.IO.StreamWriter sw = System.IO.File.CreateText(filename)) {
- int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured;
- CommandLineOptions.Clo.PrintUnstructured = 2; // print only the unstructured program
- bool oldPrintDesugaringSetting = CommandLineOptions.Clo.PrintDesugarings;
- CommandLineOptions.Clo.PrintDesugarings = false;
- List<Block> backup = impl.Blocks;
- Contract.Assert(backup != null);
- impl.Blocks = blocks;
- impl.Emit(new TokenTextWriter(filename, sw, /*setTokens=*/ false, /*pretty=*/ false), 0);
- impl.Blocks = backup;
- CommandLineOptions.Clo.PrintDesugarings = oldPrintDesugaringSetting;
- CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured;
- }
- }
-
- int bsid;
- BlockStats GetBlockStats(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<BlockStats>() != null);
-
- BlockStats s;
- if (!stats.TryGetValue(b, out s)) {
- s = new BlockStats(b, bsid++);
- stats[b] = s;
- }
- return cce.NonNull(s);
- }
-
- double AssertionCost(PredicateCmd c) {
- return 1.0;
- }
-
- void CountAssertions(Block b) {
- Contract.Requires(b != null);
- BlockStats s = GetBlockStats(b);
- if (s.assertion_cost >= 0)
- return; // already done
- s.big_block = true;
- s.assertion_cost = 0;
- s.assumption_cost = 0;
- foreach (Cmd c in b.Cmds) {
- if (c is AssertCmd) {
- double cost = AssertionCost((AssertCmd)c);
- s.assertion_cost += cost;
- assertion_count++;
- assertion_cost += cost;
- } else if (c is AssumeCmd) {
- s.assumption_cost += AssertionCost((AssumeCmd)c);
- }
- }
- foreach (Block c in Exits(b)) {
- Contract.Assert(c != null);
- s.virtual_successors.Add(c);
- }
- if (s.virtual_successors.Count == 1) {
- Block next = s.virtual_successors[0];
- BlockStats se = GetBlockStats(next);
- CountAssertions(next);
- if (next.Predecessors.Count > 1 || se.virtual_successors.Count != 1)
- return;
- s.virtual_successors[0] = se.virtual_successors[0];
- s.assertion_cost += se.assertion_cost;
- s.assumption_cost += se.assumption_cost;
- se.big_block = false;
- }
- }
-
- HashSet<Block/*!*/>/*!*/ ComputeReachableNodes(Block/*!*/ b) {
- Contract.Requires(b != null);
- Contract.Ensures(cce.NonNull(Contract.Result<HashSet<Block/*!*/>>()));
- BlockStats s = GetBlockStats(b);
- if (s.reachable_blocks != null) {
- return s.reachable_blocks;
- }
- HashSet<Block/*!*/> blocks = new HashSet<Block/*!*/>();
- s.reachable_blocks = blocks;
- blocks.Add(b);
- foreach (Block/*!*/ succ in Exits(b)) {
- Contract.Assert(succ != null);
- foreach (Block r in ComputeReachableNodes(succ)) {
- Contract.Assert(r != null);
- blocks.Add(r);
- }
- }
- return blocks;
- }
-
- double ProverCost(double vc_cost) {
- return vc_cost * vc_cost;
- }
-
- void ComputeBestSplit() {
- if (score_computed)
- return;
- score_computed = true;
-
- assertion_count = 0;
-
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- CountAssertions(b);
- }
-
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- BlockStats bs = GetBlockStats(b);
- if (bs.big_block) {
- big_blocks.Add(b);
- foreach (Block ch in bs.virtual_successors) {
- Contract.Assert(ch != null);
- BlockStats chs = GetBlockStats(ch);
- if (!chs.big_block) {
- Console.WriteLine("non-big {0} accessed from {1}", ch, b);
- DumpDot(-1);
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- chs.virtual_predecesors.Add(b);
- }
- }
- }
-
- assumized_branches.Clear();
- total_cost = ProverCost(DoComputeScore(false));
-
- score = double.PositiveInfinity;
- Block best_split = null;
- List<Block> saved_branches = new List<Block>();
-
- foreach (Block b in big_blocks) {
- Contract.Assert(b != null);
- GotoCmd gt = b.TransferCmd as GotoCmd;
- if (gt == null)
- continue;
- List<Block> targ = cce.NonNull(gt.labelTargets);
- if (targ.Count < 2)
- continue;
- // caution, we only consider two first exits
-
- double left0, right0, left1, right1;
- split_block = b;
-
- assumized_branches.Clear();
- assumized_branches.Add(cce.NonNull(targ[0]));
- left0 = DoComputeScore(true);
- right0 = DoComputeScore(false);
-
- assumized_branches.Clear();
- for (int idx = 1; idx < targ.Count; idx++) {
- assumized_branches.Add(cce.NonNull(targ[idx]));
- }
- left1 = DoComputeScore(true);
- right1 = DoComputeScore(false);
-
- double current_score = ProverCost(left1) + ProverCost(right1);
- double other_score = ProverCost(left0) + ProverCost(right0);
-
- if (other_score < current_score) {
- current_score = other_score;
- assumized_branches.Clear();
- assumized_branches.Add(cce.NonNull(targ[0]));
- }
-
- if (current_score < score) {
- score = current_score;
- best_split = split_block;
- saved_branches.Clear();
- saved_branches.AddRange(assumized_branches);
- }
- }
-
- if (CommandLineOptions.Clo.VcsPathSplitMult * score > total_cost) {
- split_block = null;
- score = -1;
- } else {
- assumized_branches = saved_branches;
- split_block = best_split;
- }
- }
-
- void UpdateIncommingPaths(BlockStats s) {
- Contract.Requires(s != null);
- if (s.incomming_paths < 0.0) {
- int count = 0;
- s.incomming_paths = 0.0;
- if (!keep_at_all.Contains(s.block))
- return;
- foreach (Block b in s.virtual_predecesors) {
- Contract.Assert(b != null);
- BlockStats ch = GetBlockStats(b);
- Contract.Assert(ch != null);
- UpdateIncommingPaths(ch);
- if (ch.incomming_paths > 0.0) {
- s.incomming_paths += ch.incomming_paths;
- count++;
- }
- }
- if (count > 1) {
- s.incomming_paths *= CommandLineOptions.Clo.VcsPathJoinMult;
- }
- }
- }
-
- void ComputeBlockSetsHelper(Block b, bool allow_small) {
- Contract.Requires(b != null);
- if (keep_at_all.Contains(b))
- return;
- keep_at_all.Add(b);
-
- if (allow_small) {
- foreach (Block ch in Exits(b)) {
- Contract.Assert(ch != null);
- if (b == split_block && assumized_branches.Contains(ch))
- continue;
- ComputeBlockSetsHelper(ch, allow_small);
- }
- } else {
- foreach (Block ch in GetBlockStats(b).virtual_successors) {
- Contract.Assert(ch != null);
- if (b == split_block && assumized_branches.Contains(ch))
- continue;
- ComputeBlockSetsHelper(ch, allow_small);
- }
- }
- }
-
- void ComputeBlockSets(bool allow_small) {
- protected_from_assert_to_assume.Clear();
- keep_at_all.Clear();
-
- Debug.Assert(split_block == null || GetBlockStats(split_block).big_block);
- Debug.Assert(GetBlockStats(blocks[0]).big_block);
-
- if (assert_to_assume) {
- foreach (Block b in allow_small ? blocks : big_blocks) {
- Contract.Assert(b != null);
- if (ComputeReachableNodes(b).Contains(cce.NonNull(split_block))) {
- keep_at_all.Add(b);
- }
- }
-
- foreach (Block b in assumized_branches) {
- Contract.Assert(b != null);
- foreach (Block r in ComputeReachableNodes(b)) {
- Contract.Assert(r != null);
- if (allow_small || GetBlockStats(r).big_block) {
- keep_at_all.Add(r);
- protected_from_assert_to_assume.Add(r);
- }
- }
- }
- } else {
- ComputeBlockSetsHelper(blocks[0], allow_small);
- }
- }
-
- bool ShouldAssumize(Block b) {
- Contract.Requires(b != null);
- return assert_to_assume && !protected_from_assert_to_assume.Contains(b);
- }
-
- double DoComputeScore(bool aa) {
- assert_to_assume = aa;
- ComputeBlockSets(false);
-
- foreach (Block b in big_blocks) {
- Contract.Assert(b != null);
- GetBlockStats(b).incomming_paths = -1.0;
- }
-
- GetBlockStats(blocks[0]).incomming_paths = 1.0;
-
- double cost = 0.0;
- foreach (Block b in big_blocks) {
- Contract.Assert(b != null);
- if (keep_at_all.Contains(b)) {
- BlockStats s = GetBlockStats(b);
- UpdateIncommingPaths(s);
- double local = s.assertion_cost;
- if (ShouldAssumize(b)) {
- local = (s.assertion_cost + s.assumption_cost) * CommandLineOptions.Clo.VcsAssumeMult;
- } else {
- local = s.assumption_cost * CommandLineOptions.Clo.VcsAssumeMult + s.assertion_cost;
- }
- local = local + local * s.incomming_paths * CommandLineOptions.Clo.VcsPathCostMult;
- cost += local;
- }
- }
-
- return cost;
- }
-
- List<Cmd> SliceCmds(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
-
- List<Cmd> seq = b.Cmds;
- Contract.Assert(seq != null);
- if (!doing_slice && !ShouldAssumize(b))
- return seq;
- List<Cmd> res = new List<Cmd>();
- foreach (Cmd c in seq) {
- Contract.Assert(c != null);
- AssertCmd a = c as AssertCmd;
- Cmd the_new = c;
- bool swap = false;
- if (a != null) {
- if (doing_slice) {
- double cost = AssertionCost(a);
- bool first = (slice_limit - cost) >= 0 || slice_initial_limit == slice_limit;
- slice_limit -= cost;
- swap = slice_pos == first;
- } else if (assert_to_assume) {
- swap = true;
- } else {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
-
- if (swap) {
- the_new = AssertTurnedIntoAssume(a);
- }
- }
- res.Add(the_new);
- }
- return res;
- }
-
- Block CloneBlock(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<Block>() != null);
-
- Block res;
- if (copies.TryGetValue(b, out res)) {
- return cce.NonNull(res);
- }
- res = new Block(b.tok, b.Label, SliceCmds(b), b.TransferCmd);
- GotoCmd gt = b.TransferCmd as GotoCmd;
- copies[b] = res;
- if (gt != null) {
- GotoCmd newGoto = new GotoCmd(gt.tok, new List<String>(), new List<Block>());
- res.TransferCmd = newGoto;
- int pos = 0;
- foreach (Block ch in cce.NonNull(gt.labelTargets)) {
- Contract.Assert(ch != null);
- Contract.Assert(doing_slice ||
- (assert_to_assume || (keep_at_all.Contains(ch) || assumized_branches.Contains(ch))));
- if (doing_slice ||
- ((b != split_block || assumized_branches.Contains(ch) == assert_to_assume) &&
- keep_at_all.Contains(ch))) {
- newGoto.AddTarget(CloneBlock(ch));
- }
- pos++;
- }
- }
- return res;
- }
-
- Split DoSplit() {
- Contract.Ensures(Contract.Result<Split>() != null);
-
- copies.Clear();
- CloneBlock(blocks[0]);
- List<Block> newBlocks = new List<Block>();
- Dictionary<TransferCmd, ReturnCmd> newGotoCmdOrigins = new Dictionary<TransferCmd, ReturnCmd>();
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- Block tmp;
- if (copies.TryGetValue(b, out tmp)) {
- newBlocks.Add(cce.NonNull(tmp));
- if (gotoCmdOrigins.ContainsKey(b.TransferCmd)) {
- newGotoCmdOrigins[tmp.TransferCmd] = gotoCmdOrigins[b.TransferCmd];
- }
-
- foreach (Block p in b.Predecessors) {
- Contract.Assert(p != null);
- Block tmp2;
- if (copies.TryGetValue(p, out tmp2)) {
- tmp.Predecessors.Add(tmp2);
- }
- }
- }
- }
-
- return new Split(newBlocks, newGotoCmdOrigins, parent, impl);
- }
-
- Split SplitAt(int idx) {
- Contract.Ensures(Contract.Result<Split>() != null);
-
- assert_to_assume = idx == 0;
- doing_slice = false;
- ComputeBlockSets(true);
-
- return DoSplit();
- }
-
- Split SliceAsserts(double limit, bool pos) {
- Contract.Ensures(Contract.Result<Split>() != null);
-
- slice_pos = pos;
- slice_limit = limit;
- slice_initial_limit = limit;
- doing_slice = true;
- Split r = DoSplit();
- /*
- Console.WriteLine("split {0} / {1} -->", limit, pos);
- List<Block!> tmp = impl.Blocks;
- impl.Blocks = r.blocks;
- EmitImpl(impl, false);
- impl.Blocks = tmp;
- */
-
- return r;
- }
-
- void Print() {
- List<Block> tmp = impl.Blocks;
- Contract.Assert(tmp != null);
- impl.Blocks = blocks;
- EmitImpl(impl, false);
- impl.Blocks = tmp;
- }
-
- public Counterexample ToCounterexample(ProverContext context) {
- Contract.Requires(context != null);
- Contract.Ensures(Contract.Result<Counterexample>() != null);
-
- List<Block> trace = new List<Block>();
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- trace.Add(b);
- }
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- foreach (Cmd c in b.Cmds) {
- Contract.Assert(c != null);
- if (c is AssertCmd) {
- return AssertCmdToCounterexample((AssertCmd)c, cce.NonNull(b.TransferCmd), trace, null, null, context);
- }
- }
- }
- Contract.Assume(false);
- throw new cce.UnreachableException();
- }
-
- /// <summary>
- /// Starting from the 0-index "split_here" annotation in begin, verifies until it reaches a subsequent "split_here" annotation
- /// Returns a list of blocks where all code not verified has asserts converted into assumes
- /// </summary>
- /// <param name="blocks">Implementation's collection of blocks</param>
- /// <param name="begin">Block containing the first split_here from which to start verifying</param>
- /// <param name="begin_split_id">0-based ID of the "split_here" annotation within begin at which to start verifying</param>
- /// <param name="blockInternalSplit">True if the entire split is contained within block begin</param>
- /// <param name="endPoints">Set of all blocks containing a "split_here" annotation</param>
- /// <returns></returns>
- // Note: Current implementation may over report errors.
- // For example, if the control flow graph is a diamond (e.g., A -> B, C, B->D, C->D),
- // and there is a split in B and an error in D, then D will be verified twice and hence report the error twice.
- // Best solution may be to memoize blocks that have been fully verified and be sure not to verify them again
- private static List<Block> DoManualSplit(List<Block> blocks, Block begin, int begin_split_id, bool blockInternalSplit, IEnumerable<Block> endPoints) {
- // Compute the set of blocks reachable from begin but not included in endPoints. These will be verified in their entirety.
- var blocksToVerifyEntirely = new HashSet<Block>();
- var reachableEndPoints = new HashSet<Block>(); // Reachable end points will be verified up to their first split point
- var todo = new Stack<Block>();
- todo.Push(begin);
- while (todo.Count > 0) {
- var currentBlock = todo.Pop();
- if (blocksToVerifyEntirely.Contains(currentBlock)) continue;
- blocksToVerifyEntirely.Add(currentBlock);
- var exit = currentBlock.TransferCmd as GotoCmd;
- if (exit != null)
- foreach (Block targetBlock in exit.labelTargets) {
- if (!endPoints.Contains(targetBlock)) {
- todo.Push(targetBlock);
- } else {
- reachableEndPoints.Add(targetBlock);
- }
- }
-
- }
- blocksToVerifyEntirely.Remove(begin);
-
- // Convert assumes to asserts in "unreachable" blocks, including portions of blocks containing "split_here"
- var newBlocks = new List<Block>(blocks.Count()); // Copies of the original blocks
- var duplicator = new Duplicator();
- var oldToNewBlockMap = new Dictionary<Block, Block>(blocks.Count()); // Maps original blocks to their new copies in newBlocks
-
- foreach (var currentBlock in blocks) {
- var newBlock = (Block)duplicator.VisitBlock(currentBlock);
- oldToNewBlockMap[currentBlock] = newBlock;
- newBlocks.Add(newBlock);
-
- if (!blockInternalSplit && blocksToVerifyEntirely.Contains(currentBlock)) continue; // All reachable blocks must be checked in their entirety, so don't change anything
- // Otherwise, we only verify a portion of the current block, so we'll need to look at each of its commands
-
- // !verify -> convert assert to assume
- var verify = (currentBlock == begin && begin_split_id == -1) // -1 tells us to start verifying from the very beginning (i.e., there is no split in the begin block)
- || (reachableEndPoints.Contains(currentBlock) // This endpoint is reachable from begin, so we verify until we hit the first split point
- && !blockInternalSplit); // Don't bother verifying if all of the splitting is within the begin block
- var newCmds = new List<Cmd>();
- var split_here_count = 0;
-
- foreach (Cmd c in currentBlock.Cmds) {
- var p = c as PredicateCmd;
- if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "split_here")) {
- if (currentBlock == begin) { // Verify everything between the begin_split_id we were given and the next split
- if (split_here_count == begin_split_id) {
- verify = true;
- } else if (split_here_count == begin_split_id + 1) {
- verify = false;
- }
- } else { // We're in an endPoint so we stop verifying as soon as we hit a "split_here"
- verify = false;
- }
- split_here_count++;
- }
-
- var asrt = c as AssertCmd;
- if (verify || asrt == null)
- newCmds.Add(c);
- else
- newCmds.Add(AssertTurnedIntoAssume(asrt));
- }
-
- newBlock.Cmds = newCmds;
- }
-
- // Patch the edges between the new blocks
- foreach (var oldBlock in blocks) {
- if (oldBlock.TransferCmd is ReturnCmd) { continue; }
- var gotoCmd = (GotoCmd)oldBlock.TransferCmd;
- var newLabelTargets = new List<Block>(gotoCmd.labelTargets.Count());
- var newLabelNames = new List<string>(gotoCmd.labelTargets.Count());
- foreach (var target in gotoCmd.labelTargets) {
- newLabelTargets.Add(oldToNewBlockMap[target]);
- newLabelNames.Add(oldToNewBlockMap[target].Label);
- }
- oldToNewBlockMap[oldBlock].TransferCmd = new GotoCmd(gotoCmd.tok, newLabelNames, newLabelTargets);
- }
-
- return newBlocks;
- }
-
- public static List<Split/*!*/> FindManualSplits(Implementation/*!*/ impl, Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins, VCGen/*!*/ par) {
- Contract.Requires(impl != null);
- Contract.Ensures(Contract.Result<List<Split>>() == null || cce.NonNullElements(Contract.Result<List<Split>>()));
-
- var splitPoints = new Dictionary<Block,int>();
- foreach (var b in impl.Blocks) {
- foreach (Cmd c in b.Cmds) {
- var p = c as PredicateCmd;
- if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "split_here")) {
- int count;
- splitPoints.TryGetValue(b, out count);
- splitPoints[b] = count + 1;
- }
- }
- }
-
- if (splitPoints.Count() == 0) { // No manual split points here
- return null;
- }
-
- List<Split> splits = new List<Split>();
- Block entryPoint = impl.Blocks[0];
- var newEntryBlocks = DoManualSplit(impl.Blocks, entryPoint, -1, splitPoints.Keys.Contains(entryPoint), splitPoints.Keys);
- splits.Add(new Split(newEntryBlocks, gotoCmdOrigins, par, impl)); // REVIEW: Does gotoCmdOrigins need to be changed at all?
-
- foreach (KeyValuePair<Block,int> pair in splitPoints) {
- for (int i = 0; i < pair.Value; i++) {
- bool blockInternalSplit = i < pair.Value - 1; // There's at least one more split, after this one, in the current block
- var newBlocks = DoManualSplit(impl.Blocks, pair.Key, i, blockInternalSplit, splitPoints.Keys);
- Split s = new Split(newBlocks, gotoCmdOrigins, par, impl); // REVIEW: Does gotoCmdOrigins need to be changed at all?
- splits.Add(s);
- }
- }
-
- return splits;
- }
-
- public static List<Split/*!*/>/*!*/ DoSplit(Split initial, double max_cost, int max) {
- Contract.Requires(initial != null);
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<Split>>()));
-
- List<Split> res = new List<Split>();
- res.Add(initial);
-
- while (res.Count < max) {
- Split best = null;
- int best_idx = 0, pos = 0;
- foreach (Split s in res) {
- Contract.Assert(s != null);
- s.ComputeBestSplit(); // TODO check total_cost first
- if (s.total_cost > max_cost &&
- (best == null || best.total_cost < s.total_cost) &&
- (s.assertion_count > 1 || s.split_block != null)) {
- best = s;
- best_idx = pos;
- }
- pos++;
- }
-
- if (best == null)
- break; // no split found
-
- Split s0, s1;
-
- bool split_stats = CommandLineOptions.Clo.TraceVerify;
-
- if (split_stats) {
- Console.WriteLine("{0} {1} -->", best.split_block == null ? "SLICE" : ("SPLIT@" + best.split_block.Label), best.Stats);
- if (best.split_block != null) {
- GotoCmd g = best.split_block.TransferCmd as GotoCmd;
- if (g != null) {
- Console.Write(" exits: ");
- foreach (Block b in cce.NonNull(g.labelTargets)) {
- Contract.Assert(b != null);
- Console.Write("{0} ", b.Label);
- }
- Console.WriteLine("");
- Console.Write(" assumized: ");
- foreach (Block b in best.assumized_branches) {
- Contract.Assert(b != null);
- Console.Write("{0} ", b.Label);
- }
- Console.WriteLine("");
- }
- }
- }
-
- if (best.split_block != null) {
- s0 = best.SplitAt(0);
- s1 = best.SplitAt(1);
- } else {
- best.split_block = null;
- s0 = best.SliceAsserts(best.assertion_cost / 2, true);
- s1 = best.SliceAsserts(best.assertion_cost / 2, false);
- }
-
- if (true) {
- List<Block> ss = new List<Block>();
- ss.Add(s0.blocks[0]);
- ss.Add(s1.blocks[0]);
- try {
- best.SoundnessCheck(new HashSet<List<Block>>(new BlockListComparer()), best.blocks[0], ss);
- } catch (System.Exception e) {
- Console.WriteLine(e);
- best.DumpDot(-1);
- s0.DumpDot(-2);
- s1.DumpDot(-3);
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- }
-
- if (split_stats) {
- s0.ComputeBestSplit();
- s1.ComputeBestSplit();
- Console.WriteLine(" --> {0}", s0.Stats);
- Console.WriteLine(" --> {0}", s1.Stats);
- }
-
- if (CommandLineOptions.Clo.TraceVerify) {
- best.Print();
- }
-
- res[best_idx] = s0;
- res.Add(s1);
- }
-
- return res;
- }
-
- class BlockListComparer : IEqualityComparer<List<Block>>
- {
- public bool Equals(List<Block> x, List<Block> y)
- {
- return x == y || x.SequenceEqual(y);
- }
-
- public int GetHashCode(List<Block> obj)
- {
- int h = 0;
- Contract.Assume(obj != null);
- foreach (var b in obj)
- {
- if (b != null)
- {
- h += b.GetHashCode();
- }
- }
- return h;
- }
- }
-
- public Checker Checker {
- get {
- Contract.Ensures(Contract.Result<Checker>() != null);
-
- Contract.Assert(checker != null);
- return checker;
- }
- }
-
- public Task ProverTask {
- get {
- Contract.Assert(checker != null);
- return checker.ProverTask;
- }
- }
-
- public void ReadOutcome(ref Outcome cur_outcome, out bool prover_failed) {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- ProverInterface.Outcome outcome = cce.NonNull(checker).ReadOutcome();
-
- if (CommandLineOptions.Clo.Trace && splitNo >= 0) {
- System.Console.WriteLine(" --> split #{0} done, [{1} s] {2}", splitNo, checker.ProverRunTime.TotalSeconds, outcome);
- }
-
- if (CommandLineOptions.Clo.VcsDumpSplits) {
- DumpDot(splitNo);
- }
-
- prover_failed = false;
-
- switch (outcome) {
- case ProverInterface.Outcome.Valid:
- return;
- case ProverInterface.Outcome.Invalid:
- cur_outcome = Outcome.Errors;
- return;
- case ProverInterface.Outcome.OutOfMemory:
- prover_failed = true;
- if (cur_outcome != Outcome.Errors && cur_outcome != Outcome.Inconclusive)
- cur_outcome = Outcome.OutOfMemory;
- return;
- case ProverInterface.Outcome.TimeOut:
- prover_failed = true;
- if (cur_outcome != Outcome.Errors && cur_outcome != Outcome.Inconclusive)
- cur_outcome = Outcome.TimedOut;
- return;
- case ProverInterface.Outcome.Undetermined:
- if (cur_outcome != Outcome.Errors)
- cur_outcome = Outcome.Inconclusive;
- return;
- default:
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- }
-
- /// <summary>
- /// As a side effect, updates "this.parent.CumulativeAssertionCount".
- /// </summary>
- public void BeginCheck(Checker checker, VerifierCallback callback, ModelViewInfo mvInfo, int no, int timeout)
- {
- Contract.Requires(checker != null);
- Contract.Requires(callback != null);
-
- splitNo = no;
-
- impl.Blocks = blocks;
-
- this.checker = checker;
-
- Dictionary<int, Absy> label2absy = new Dictionary<int, Absy>();
-
- ProverContext ctx = checker.TheoremProver.Context;
- Boogie2VCExprTranslator bet = ctx.BoogieExprTranslator;
- CodeExprConversionClosure cc = new CodeExprConversionClosure(label2absy, ctx);
- bet.SetCodeExprConverter(cc.CodeExprToVerificationCondition);
-
- var exprGen = ctx.ExprGen;
- VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
-
- VCExpr vc = parent.GenerateVCAux(impl, controlFlowVariableExpr, label2absy, checker.TheoremProver.Context);
- Contract.Assert(vc != null);
-
- if (!CommandLineOptions.Clo.UseLabels)
- {
- VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
- VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
- vc = exprGen.Implies(eqExpr, vc);
- }
-
- if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Local)
- {
- reporter = new ErrorReporterLocal(gotoCmdOrigins, label2absy, impl.Blocks, parent.incarnationOriginMap, callback, mvInfo, cce.NonNull(this.Checker.TheoremProver.Context), parent.program);
- }
- else
- {
- reporter = new ErrorReporter(gotoCmdOrigins, label2absy, impl.Blocks, parent.incarnationOriginMap, callback, mvInfo, this.Checker.TheoremProver.Context, parent.program);
- }
-
- if (CommandLineOptions.Clo.TraceVerify && no >= 0)
- {
- Console.WriteLine("-- after split #{0}", no);
- Print();
- }
-
- string desc = cce.NonNull(impl.Name);
- if (no >= 0)
- desc += "_split" + no;
- checker.BeginCheck(desc, vc, reporter);
- }
-
- private void SoundnessCheck(HashSet<List<Block>/*!*/>/*!*/ cache, Block/*!*/ orig, List<Block/*!*/>/*!*/ copies) {
- Contract.Requires(cce.NonNull(cache));
- Contract.Requires(orig != null);
- Contract.Requires(copies != null);
- {
- var t = new List<Block> { orig };
- foreach (Block b in copies) {
- Contract.Assert(b != null);
- t.Add(b);
- }
- if (cache.Contains(t)) {
- return;
- }
- cache.Add(t);
- }
-
- for (int i = 0; i < orig.Cmds.Count; ++i) {
- Cmd cmd = orig.Cmds[i];
- if (cmd is AssertCmd) {
- int found = 0;
- foreach (Block c in copies) {
- Contract.Assert(c != null);
- if (c.Cmds[i] == cmd) {
- found++;
- }
- }
- if (found == 0) {
- throw new System.Exception(string.Format("missing assertion: {0}({1})", cmd.tok.filename, cmd.tok.line));
- }
- }
- }
-
- foreach (Block exit in Exits(orig)) {
- Contract.Assert(exit != null);
- List<Block> newcopies = new List<Block>();
- foreach (Block c in copies) {
- foreach (Block cexit in Exits(c)) {
- Contract.Assert(cexit != null);
- if (cexit.Label == exit.Label) {
- newcopies.Add(cexit);
- }
- }
- }
- if (newcopies.Count == 0) {
- throw new System.Exception("missing exit " + exit.Label);
- }
- SoundnessCheck(cache, exit, newcopies);
- }
- }
- }
- #endregion
-
-
- public class CodeExprConversionClosure
- {
- Dictionary<int, Absy> label2absy;
- ProverContext ctx;
- public CodeExprConversionClosure(Dictionary<int, Absy> label2absy, ProverContext ctx)
- {
- this.label2absy = label2absy;
- this.ctx = ctx;
- }
-
- public VCExpr CodeExprToVerificationCondition(CodeExpr codeExpr, Hashtable blockVariables, List<VCExprLetBinding> bindings, bool isPositiveContext)
- {
- VCGen vcgen = new VCGen(new Program(), null, false, new List<Checker>());
- vcgen.variable2SequenceNumber = new Dictionary<Variable, int>();
- vcgen.incarnationOriginMap = new Dictionary<Incarnation, Absy>();
- vcgen.CurrentLocalVariables = codeExpr.LocVars;
-
- ResetPredecessors(codeExpr.Blocks);
- vcgen.AddBlocksBetween(codeExpr.Blocks);
- Dictionary<Variable, Expr> gotoCmdOrigins = vcgen.ConvertBlocks2PassiveCmd(codeExpr.Blocks, new List<IdentifierExpr>(), new ModelViewInfo(codeExpr));
- int ac; // computed, but then ignored for this CodeExpr
- VCExpr startCorrect = VCGen.LetVCIterative(codeExpr.Blocks, null, label2absy, ctx, out ac, isPositiveContext);
- VCExpr vce = ctx.ExprGen.Let(bindings, startCorrect);
- if (vcgen.CurrentLocalVariables.Count != 0)
- {
- Boogie2VCExprTranslator translator = ctx.BoogieExprTranslator;
- List<VCExprVar> boundVars = new List<VCExprVar>();
- foreach (Variable v in vcgen.CurrentLocalVariables)
- {
- Contract.Assert(v != null);
- VCExprVar ev = translator.LookupVariable(v);
- Contract.Assert(ev != null);
- boundVars.Add(ev);
- if (v.TypedIdent.Type.Equals(Bpl.Type.Bool))
- {
- // add an antecedent (tickleBool ev) to help the prover find a possible trigger
- vce = ctx.ExprGen.Implies(ctx.ExprGen.Function(VCExpressionGenerator.TickleBoolOp, ev), vce);
- }
- }
- vce = ctx.ExprGen.Forall(boundVars, new List<VCTrigger>(), vce);
- }
- if (isPositiveContext)
- {
- vce = ctx.ExprGen.Not(vce);
- }
- return vce;
- }
- }
-
- public VCExpr GenerateVC(Implementation/*!*/ impl, VCExpr controlFlowVariableExpr, out Dictionary<int, Absy>/*!*/ label2absy, ProverContext proverContext)
- {
- Contract.Requires(impl != null);
- Contract.Requires(proverContext != null);
- Contract.Ensures(Contract.ValueAtReturn(out label2absy) != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- label2absy = new Dictionary<int, Absy>();
- return GenerateVCAux(impl, controlFlowVariableExpr, label2absy, proverContext);
- }
-
- public VCExpr GenerateVCAux(Implementation/*!*/ impl, VCExpr controlFlowVariableExpr, Dictionary<int, Absy>/*!*/ label2absy, ProverContext proverContext) {
- Contract.Requires(impl != null);
- Contract.Requires(proverContext != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- TypecheckingContext tc = new TypecheckingContext(null);
- impl.Typecheck(tc);
-
- VCExpr vc;
- int assertionCount;
- switch (CommandLineOptions.Clo.vcVariety) {
- case CommandLineOptions.VCVariety.Structured:
- vc = VCViaStructuredProgram(impl, label2absy, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.Block:
- vc = FlatBlockVC(impl, label2absy, false, false, false, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.BlockReach:
- vc = FlatBlockVC(impl, label2absy, false, true, false, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.Local:
- vc = FlatBlockVC(impl, label2absy, true, false, false, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.BlockNested:
- vc = NestedBlockVC(impl, label2absy, false, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.BlockNestedReach:
- vc = NestedBlockVC(impl, label2absy, true, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.Dag:
- if (cce.NonNull(CommandLineOptions.Clo.TheProverFactory).SupportsDags || CommandLineOptions.Clo.FixedPointEngine != null) {
- vc = DagVC(cce.NonNull(impl.Blocks[0]), controlFlowVariableExpr, label2absy, new Hashtable/*<Block, VCExpr!>*/(), proverContext, out assertionCount);
- } else {
- vc = LetVC(cce.NonNull(impl.Blocks[0]), controlFlowVariableExpr, label2absy, proverContext, out assertionCount);
- }
- break;
- case CommandLineOptions.VCVariety.DagIterative:
- vc = LetVCIterative(impl.Blocks, controlFlowVariableExpr, label2absy, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.Doomed:
- vc = FlatBlockVC(impl, label2absy, false, false, true, proverContext, out assertionCount);
- break;
- default:
- Contract.Assert(false);
- throw new cce.UnreachableException(); // unexpected enumeration value
- }
- CumulativeAssertionCount += assertionCount;
- return vc;
- }
-
- void CheckIntAttributeOnImpl(Implementation impl, string name, ref int val) {
- Contract.Requires(impl != null);
- Contract.Requires(name != null);
- if (!(cce.NonNull(impl.Proc).CheckIntAttribute(name, ref val) || !impl.CheckIntAttribute(name, ref val))) {
- Console.WriteLine("ignoring ill-formed {:{0} ...} attribute on {1}, parameter should be an int", name, impl.Name);
- }
- }
-
- public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback) {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- if (impl.SkipVerification) {
- return Outcome.Inconclusive; // not sure about this one
- }
-
- callback.OnProgress("VCgen", 0, 0, 0.0);
-
- Stopwatch watch = new Stopwatch();
- if (_print_time)
- {
- Console.WriteLine("Checking function {0}", impl.Name);
- watch.Reset();
- watch.Start();
- }
-
- ConvertCFG2DAG(impl);
-
- SmokeTester smoke_tester = null;
- if (CommandLineOptions.Clo.SoundnessSmokeTest) {
- smoke_tester = new SmokeTester(this, impl, callback);
- smoke_tester.Copy();
- }
-
- ModelViewInfo mvInfo;
- var gotoCmdOrigins = PassifyImpl(impl, out mvInfo);
-
- // If "expand" attribute is supplied, expand any assertion of conjunctions into multiple assertions, one per conjunct
- foreach (var b in impl.Blocks)
- {
- List<Cmd> newCmds = new List<Cmd>();
- bool changed = false;
- foreach (var c in b.Cmds)
- {
- var a = c as AssertCmd;
- var ar = c as AssertRequiresCmd;
- var ae = c as AssertEnsuresCmd;
- var ai = c as LoopInitAssertCmd;
- var am = c as LoopInvMaintainedAssertCmd;
- // TODO:
- //use Duplicator and Substituter rather than new
- //nested IToken?
- //document expand attribute (search for {:ignore}, for example)
- //fix up new CallCmd, new Requires, new Ensures in OwickiGries.cs
- Func<Expr,Expr,Expr> withType = (Expr from, Expr to) =>
- {
- NAryExpr nFrom = from as NAryExpr;
- NAryExpr nTo = to as NAryExpr;
- to.Type = from.Type;
- if (nFrom != null && nTo != null) nTo.TypeParameters = nFrom.TypeParameters;
- return to;
- };
-
- Action<int,Expr,Action<Expr>> traverse = null;
- traverse = (depth, e, act) =>
- {
- ForallExpr forall = e as ForallExpr;
- NAryExpr nary = e as NAryExpr;
- if (forall != null)
- {
- traverse(depth, forall.Body, e1 => act(withType(forall,
- new ForallExpr(e1.tok, forall.TypeParameters, forall.Dummies, forall.Attributes, forall.Triggers, e1))));
- return;
- }
- if (nary != null)
- {
- var args = nary.Args;
- IAppliable fun = nary.Fun;
- BinaryOperator bop = fun as BinaryOperator;
- FunctionCall call = fun as FunctionCall;
- if (bop != null)
- {
- switch (bop.Op)
- {
- case BinaryOperator.Opcode.And:
- traverse(depth, args[0], act);
- traverse(depth, args[1], act);
- return;
- case BinaryOperator.Opcode.Imp:
- traverse(depth, args[1], e1 => act(withType(nary,
- new NAryExpr(e1.tok, fun, new List<Expr>() { args[0], e1 }))));
- return;
- }
- }
- if (depth > 0 && call != null && call.Func != null)
- {
- Function cf = call.Func;
- Expr body = cf.Body;
- List<Variable> ins = cf.InParams;
- if (body == null && cf.DefinitionAxiom != null)
- {
- ForallExpr all = cf.DefinitionAxiom.Expr as ForallExpr;
- if (all != null)
- {
- NAryExpr def = all.Body as NAryExpr;
- if (def != null && def.Fun is BinaryOperator && ((BinaryOperator) (def.Fun)).Op == BinaryOperator.Opcode.Iff)
- {
- body = def.Args[1];
- ins = all.Dummies;
- }
- }
- }
- if (body != null)
- {
- Func<Expr,Expr> new_f = e1 =>
- {
- Function f = new Function(cf.tok, "expand<" + cf.Name + ">", cf.TypeParameters, ins, cf.OutParams[0], cf.Comment);
- f.Body = e1;
- Token tok = new Token(e1.tok.line, e1.tok.col);
- tok.filename = e.tok.filename + "(" + e.tok.line + "," + e.tok.col + ") --> " + e1.tok.filename;
- return withType(nary, new NAryExpr(tok, new FunctionCall(f), args));
- };
- traverse(depth - 1, body, e1 => act(new_f(e1)));
- return;
- }
- }
- }
- act(e);
- };
-
- if (a != null)
- {
- var attr = a.Attributes;
- if (ar != null && ar.Requires.Attributes != null) attr = ar.Requires.Attributes;
- if (ar != null && ar.Call.Attributes != null) attr = ar.Call.Attributes;
- if (ae != null && ae.Ensures.Attributes != null) attr = ae.Ensures.Attributes;
- if (QKeyValue.FindExprAttribute(attr, "expand") != null || QKeyValue.FindBoolAttribute(attr, "expand"))
- {
- int depth = QKeyValue.FindIntAttribute(attr, "expand", 100);
- Func<Expr,Expr> fe = e => Expr.Or(a.Expr, e);
- //traverse(depth, a.Expr, e => System.Console.WriteLine(e.GetType() + " :: " + e + " @ " + e.tok.line + ", " + e.tok.col));
- traverse(depth, a.Expr, e =>
- {
- AssertCmd new_c =
- (ar != null) ? new AssertRequiresCmd(ar.Call, new Requires(e.tok, ar.Requires.Free, fe(e), ar.Requires.Comment)) :
- (ae != null) ? new AssertEnsuresCmd(new Ensures(e.tok, ae.Ensures.Free, fe(e), ae.Ensures.Comment)) :
- (ai != null) ? new LoopInitAssertCmd(e.tok, fe(e)) :
- (am != null) ? new LoopInvMaintainedAssertCmd(e.tok, fe(e)) :
- new AssertCmd(e.tok, fe(e));
- new_c.Attributes = new QKeyValue(e.tok, "subsumption", new List<object>() { new LiteralExpr(e.tok, BigNum.FromInt(0)) }, a.Attributes);
- newCmds.Add(new_c);
- });
- }
- newCmds.Add(c);
- changed = true;
- }
- else
- {
- newCmds.Add(c);
- }
- }
- if (changed) b.Cmds = newCmds;
- }
-
- double max_vc_cost = CommandLineOptions.Clo.VcsMaxCost;
- int tmp_max_vc_cost = -1, max_splits = CommandLineOptions.Clo.VcsMaxSplits,
- max_kg_splits = CommandLineOptions.Clo.VcsMaxKeepGoingSplits;
- CheckIntAttributeOnImpl(impl, "vcs_max_cost", ref tmp_max_vc_cost);
- CheckIntAttributeOnImpl(impl, "vcs_max_splits", ref max_splits);
- CheckIntAttributeOnImpl(impl, "vcs_max_keep_going_splits", ref max_kg_splits);
- if (tmp_max_vc_cost >= 0) {
- max_vc_cost = tmp_max_vc_cost;
- }
-
- Outcome outcome = Outcome.Correct;
-
- // Report all recycled failing assertions for this implementation.
- if (impl.RecycledFailingAssertions != null && impl.RecycledFailingAssertions.Any())
- {
- outcome = Outcome.Errors;
- foreach (var a in impl.RecycledFailingAssertions)
- {
- var checksum = a.Checksum;
- var oldCex = impl.ErrorChecksumToCachedError[checksum] as Counterexample;
- if (oldCex != null) {
- if (CommandLineOptions.Clo.VerifySnapshots < 3) {
- callback.OnCounterexample(oldCex, null);
- } else {
- // If possible, we use the old counterexample, but with the location information of "a"
- var cex = AssertCmdToCloneCounterexample(a, oldCex);
- callback.OnCounterexample(cex, null);
- // OnCounterexample may have had side effects on the RequestId and OriginalRequestId fields. We make
- // any such updates available in oldCex. (Is this really a good design? --KRML)
- oldCex.RequestId = cex.RequestId;
- oldCex.OriginalRequestId = cex.OriginalRequestId;
- }
- }
- }
- }
-
- Cores = CommandLineOptions.Clo.VcsCores;
- Stack<Split> work = new Stack<Split>();
- List<Split> currently_running = new List<Split>();
- ResetPredecessors(impl.Blocks);
- List<Split> manual_splits = Split.FindManualSplits(impl, gotoCmdOrigins, this);
- if (manual_splits != null) {
- foreach (var split in manual_splits) {
- work.Push(split);
- }
- } else {
- work.Push(new Split(impl.Blocks, gotoCmdOrigins, this, impl));
- }
-
- bool keep_going = max_kg_splits > 1;
- int total = 0;
- int no = max_splits == 1 && !keep_going ? -1 : 0;
- bool first_round = true;
- bool do_splitting = keep_going || max_splits > 1;
- double remaining_cost = 0.0, proven_cost = 0.0;
-
- if (do_splitting) {
- remaining_cost = work.Peek().Cost;
- }
-
- while (work.Any() || currently_running.Any())
- {
- bool prover_failed = false;
- Split s = null;
- var isWaiting = !work.Any();
-
- if (!isWaiting)
- {
- s = work.Peek();
-
- if (first_round && max_splits > 1)
- {
- prover_failed = true;
- remaining_cost -= s.Cost;
- }
- else
- {
- var timeout = (keep_going && s.LastChance) ? CommandLineOptions.Clo.VcsFinalAssertTimeout :
- keep_going ? CommandLineOptions.Clo.VcsKeepGoingTimeout :
- impl.TimeLimit;
-
- var checker = s.parent.FindCheckerFor(timeout, false);
- try
- {
- if (checker == null)
- {
- isWaiting = true;
- goto waiting;
- }
- else
- {
- s = work.Pop();
- }
-
- if (CommandLineOptions.Clo.Trace && no >= 0)
- {
- System.Console.WriteLine(" checking split {1}/{2}, {3:0.00}%, {0} ...",
- s.Stats, no + 1, total, 100 * proven_cost / (proven_cost + remaining_cost));
- }
- callback.OnProgress("VCprove", no < 0 ? 0 : no, total, proven_cost / (remaining_cost + proven_cost));
-
- Contract.Assert(s.parent == this);
- lock (checker)
- {
- s.BeginCheck(checker, callback, mvInfo, no, timeout);
- }
-
- no++;
-
- currently_running.Add(s);
- }
- catch (Exception)
- {
- checker.GoBackToIdle();
- throw;
- }
- }
- }
-
- waiting:
- if (isWaiting)
- {
- // Wait for one split to terminate.
- var tasks = currently_running.Select(splt => splt.ProverTask).ToArray();
-
- if (tasks.Any())
- {
- try
- {
- int index = Task.WaitAny(tasks);
- s = currently_running[index];
- currently_running.RemoveAt(index);
-
- if (do_splitting)
- {
- remaining_cost -= s.Cost;
- }
-
- lock (s.Checker)
- {
- s.ReadOutcome(ref outcome, out prover_failed);
- }
-
- if (do_splitting)
- {
- if (prover_failed)
- {
- // even if the prover fails, we have learned something, i.e., it is
- // annoying to watch Boogie say Timeout, 0.00% a couple of times
- proven_cost += s.Cost / 100;
- }
- else
- {
- proven_cost += s.Cost;
- }
- }
- callback.OnProgress("VCprove", no < 0 ? 0 : no, total, proven_cost / (remaining_cost + proven_cost));
-
- if (prover_failed && !first_round && s.LastChance)
- {
- string msg = "some timeout";
- if (s.reporter != null && s.reporter.resourceExceededMessage != null)
- {
- msg = s.reporter.resourceExceededMessage;
- }
- callback.OnCounterexample(s.ToCounterexample(s.Checker.TheoremProver.Context), msg);
- outcome = Outcome.Errors;
- break;
- }
- }
- finally
- {
- s.Checker.GoBackToIdle();
- }
-
- Contract.Assert(prover_failed || outcome == Outcome.Correct || outcome == Outcome.Errors || outcome == Outcome.Inconclusive);
- }
- }
-
- if (prover_failed)
- {
- int splits = first_round && max_splits > 1 ? max_splits : max_kg_splits;
-
- if (splits > 1)
- {
- List<Split> tmp = Split.DoSplit(s, max_vc_cost, splits);
- Contract.Assert(tmp != null);
- max_vc_cost = 1.0; // for future
- first_round = false;
- //tmp.Sort(new Comparison<Split!>(Split.Compare));
- foreach (Split a in tmp)
- {
- Contract.Assert(a != null);
- work.Push(a);
- total++;
- remaining_cost += a.Cost;
- }
- if (outcome != Outcome.Errors)
- {
- outcome = Outcome.Correct;
- }
- }
- else
- {
- Contract.Assert(outcome != Outcome.Correct);
- if (outcome == Outcome.TimedOut)
- {
- string msg = "some timeout";
- if (s.reporter != null && s.reporter.resourceExceededMessage != null)
- {
- msg = s.reporter.resourceExceededMessage;
- }
- callback.OnTimeout(msg);
- }
- else if (outcome == Outcome.OutOfMemory)
- {
- string msg = "out of memory";
- if (s.reporter != null && s.reporter.resourceExceededMessage != null)
- {
- msg = s.reporter.resourceExceededMessage;
- }
- callback.OnOutOfMemory(msg);
- }
-
- break;
- }
- }
- }
-
- if (outcome == Outcome.Correct && smoke_tester != null) {
- smoke_tester.Test();
- }
-
- callback.OnProgress("done", 0, 0, 1.0);
-
- if (_print_time)
- {
- watch.Stop();
- Console.WriteLine("Total time for this method: {0}", watch.Elapsed.ToString());
- }
-
- return outcome;
- }
-
- public class ErrorReporter : ProverInterface.ErrorHandler {
- Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins;
- Dictionary<int, Absy>/*!*/ label2absy;
- List<Block/*!*/>/*!*/ blocks;
- protected Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap;
- protected VerifierCallback/*!*/ callback;
- protected ModelViewInfo MvInfo;
- internal string resourceExceededMessage;
- static System.IO.TextWriter modelWriter;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(gotoCmdOrigins != null);
- Contract.Invariant(label2absy != null);
- Contract.Invariant(cce.NonNullElements(blocks));
- Contract.Invariant(cce.NonNullDictionaryAndValues(incarnationOriginMap));
- Contract.Invariant(callback != null);
- Contract.Invariant(context != null);
- Contract.Invariant(program != null);
- }
-
-
- public static TextWriter ModelWriter {
- get {
- Contract.Ensures(Contract.Result<TextWriter>() != null);
-
- if (ErrorReporter.modelWriter == null)
- ErrorReporter.modelWriter = CommandLineOptions.Clo.PrintErrorModelFile == null ? Console.Out : new StreamWriter(CommandLineOptions.Clo.PrintErrorModelFile, false);
- return ErrorReporter.modelWriter;
- }
- }
-
- protected ProverContext/*!*/ context;
- Program/*!*/ program;
-
- public ErrorReporter(Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins,
- Dictionary<int, Absy>/*!*/ label2absy,
- List<Block/*!*/>/*!*/ blocks,
- Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap,
- VerifierCallback/*!*/ callback,
- ModelViewInfo mvInfo,
- ProverContext/*!*/ context,
- Program/*!*/ program) {
- Contract.Requires(gotoCmdOrigins != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(cce.NonNullElements(blocks));
- Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap));
- Contract.Requires(callback != null);
- Contract.Requires(context!=null);
- Contract.Requires(program!=null);
- this.gotoCmdOrigins = gotoCmdOrigins;
- this.label2absy = label2absy;
- this.blocks = blocks;
- this.incarnationOriginMap = incarnationOriginMap;
- this.callback = callback;
- this.MvInfo = mvInfo;
-
- this.context = context;
- this.program = program;
- }
-
- public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) {
- //Contract.Requires(cce.NonNullElements(labels));
- if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) {
- if (VC.ConditionGeneration.errorModelList != null)
- {
- VC.ConditionGeneration.errorModelList.Add(model);
- }
-
- model.Write(ErrorReporter.ModelWriter);
- ErrorReporter.ModelWriter.Flush();
- }
-
- Hashtable traceNodes = new Hashtable();
- foreach (string s in labels) {
- Contract.Assert(s != null);
- Absy absy = Label2Absy(s);
- Contract.Assert(absy != null);
- if (traceNodes.ContainsKey(absy))
- System.Console.WriteLine("Warning: duplicate label: " + s + " read while tracing nodes");
- else
- traceNodes.Add(absy, null);
- }
-
- List<Block> trace = new List<Block>();
- Block entryBlock = cce.NonNull(this.blocks[0]);
- Contract.Assert(traceNodes.Contains(entryBlock));
- trace.Add(entryBlock);
-
- Counterexample newCounterexample = TraceCounterexample(entryBlock, traceNodes, trace, model, MvInfo, incarnationOriginMap, context, new Dictionary<TraceLocation, CalleeCounterexampleInfo>());
-
- if (newCounterexample == null)
- return;
-
- #region Map passive program errors back to original program errors
- ReturnCounterexample returnExample = newCounterexample as ReturnCounterexample;
- if (returnExample != null) {
- foreach (Block b in returnExample.Trace) {
- Contract.Assert(b != null);
- Contract.Assume(b.TransferCmd != null);
- ReturnCmd cmd = gotoCmdOrigins.ContainsKey(b.TransferCmd) ? gotoCmdOrigins[b.TransferCmd] : null;
- if (cmd != null) {
- returnExample.FailingReturn = cmd;
- break;
- }
- }
- }
- #endregion
- callback.OnCounterexample(newCounterexample, null);
- }
-
- public override Absy Label2Absy(string label) {
- //Contract.Requires(label != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- int id = int.Parse(label);
- return cce.NonNull((Absy)label2absy[id]);
- }
-
- public override void OnResourceExceeded(string msg, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null) {
- //Contract.Requires(msg != null);
- resourceExceededMessage = msg;
- if (assertCmds != null)
- {
- foreach (var cmd in assertCmds)
- {
- Counterexample cex = AssertCmdToCounterexample(cmd.Item1, cmd.Item2 , new List<Block>(), null, null, context);
- callback.OnCounterexample(cex, msg);
- }
- }
- }
-
- public override void OnProverWarning(string msg) {
- //Contract.Requires(msg != null);
- callback.OnWarning(msg);
- }
- }
-
- public class ErrorReporterLocal : ErrorReporter {
- public ErrorReporterLocal(Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins,
- Dictionary<int, Absy>/*!*/ label2absy,
- List<Block/*!*/>/*!*/ blocks,
- Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap,
- VerifierCallback/*!*/ callback,
- ModelViewInfo mvInfo,
- ProverContext/*!*/ context,
- Program/*!*/ program)
- : base(gotoCmdOrigins, label2absy, blocks, incarnationOriginMap, callback, mvInfo, context, program) // here for aesthetic purposes //TODO: Maybe nix?
- {
- Contract.Requires(gotoCmdOrigins != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(cce.NonNullElements(blocks));
- Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap));
- Contract.Requires(callback != null);
- Contract.Requires(context != null);
- Contract.Requires(program != null);
- }
-
- public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) {
- //Contract.Requires(cce.NonNullElements(labels));
- // We ignore the error model here for enhanced error message purposes.
- // It is only printed to the command line.
- if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) {
- if (CommandLineOptions.Clo.PrintErrorModelFile != null) {
- model.Write(ErrorReporter.ModelWriter);
- ErrorReporter.ModelWriter.Flush();
- }
- }
- List<Block> traceNodes = new List<Block>();
- List<AssertCmd> assertNodes = new List<AssertCmd>();
- foreach (string s in labels) {
- Contract.Assert(s != null);
- Absy node = Label2Absy(s);
- if (node is Block) {
- Block b = (Block)node;
- traceNodes.Add(b);
- } else {
- AssertCmd a = (AssertCmd)node;
- assertNodes.Add(a);
- }
- }
- Contract.Assert(assertNodes.Count > 0);
- Contract.Assert(traceNodes.Count == assertNodes.Count);
-
- foreach (AssertCmd a in assertNodes) {
- // find the corresponding Block (assertNodes.Count is likely to be 1, or small in any case, so just do a linear search here)
- foreach (Block b in traceNodes) {
- if (b.Cmds.Contains(a)) {
- List<Block> trace = new List<Block>();
- trace.Add(b);
- Counterexample newCounterexample = AssertCmdToCounterexample(a, cce.NonNull(b.TransferCmd), trace, model, MvInfo, context);
- callback.OnCounterexample(newCounterexample, null);
- goto NEXT_ASSERT;
- }
- }
- Contract.Assert(false);
- throw new cce.UnreachableException(); // there was no block that contains the assert
- NEXT_ASSERT: {
- }
- }
- }
- }
-
- private void RecordCutEdge(Dictionary<Block,List<Block>> edgesCut, Block from, Block to){
- if (edgesCut != null)
- {
- if (!edgesCut.ContainsKey(from))
- edgesCut.Add(from, new List<Block>());
- edgesCut[from].Add(to);
- }
- }
-
- public void ConvertCFG2DAG(Implementation impl, Dictionary<Block,List<Block>> edgesCut = null, int taskID = -1)
- {
- Contract.Requires(impl != null);
- impl.PruneUnreachableBlocks(); // This is needed for VCVariety.BlockNested, and is otherwise just an optimization
-
- CurrentLocalVariables = impl.LocVars;
- variable2SequenceNumber = new Dictionary<Variable, int>();
- incarnationOriginMap = new Dictionary<Incarnation, Absy>();
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("original implementation");
- EmitImpl(impl, false);
- }
- #endregion
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after desugaring sugared commands like procedure calls");
- EmitImpl(impl, true);
- }
- #endregion
-
- // Recompute the predecessors, but first insert a dummy start node that is sure not to be the target of any goto (because the cutting of back edges
- // below assumes that the start node has no predecessor)
- impl.Blocks.Insert(0, new Block(new Token(-17, -4), "0", new List<Cmd>(), new GotoCmd(Token.NoToken, new List<String> { impl.Blocks[0].Label }, new List<Block> { impl.Blocks[0] })));
- ResetPredecessors(impl.Blocks);
-
- if(CommandLineOptions.Clo.KInductionDepth < 0) {
- ConvertCFG2DAGStandard(impl, edgesCut, taskID);
- } else {
- ConvertCFG2DAGKInduction(impl, edgesCut, taskID);
- }
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after conversion into a DAG");
- EmitImpl(impl, true);
- }
- #endregion
- }
-
- private void ConvertCFG2DAGStandard(Implementation impl, Dictionary<Block, List<Block>> edgesCut, int taskID)
- {
- #region Convert program CFG into a DAG
-
- #region Use the graph library to figure out where the (natural) loops are
-
- #region Create the graph by adding the source node and each edge
- Graph<Block> g = Program.GraphFromImpl(impl);
- #endregion
-
- //Graph<Block> g = program.ProcessLoops(impl);
-
- g.ComputeLoops(); // this is the call that does all of the processing
- if (!g.Reducible)
- {
- throw new VCGenException("Irreducible flow graphs are unsupported.");
- }
-
- #endregion
-
- #region Cut the backedges, push assert/assume statements from loop header into predecessors, change them all into assume statements at top of loop, introduce havoc statements
- foreach (Block header in cce.NonNull(g.Headers))
- {
- Contract.Assert(header != null);
- IDictionary<Block, object> backEdgeNodes = new Dictionary<Block, object>();
- foreach (Block b in cce.NonNull(g.BackEdgeNodes(header)))
- {
- Contract.Assert(b != null);
- backEdgeNodes.Add(b, null);
- }
-
- #region Find the (possibly empty) prefix of assert commands in the header, replace each assert with an assume of the same condition
- List<Cmd> prefixOfPredicateCmdsInit = new List<Cmd>();
- List<Cmd> prefixOfPredicateCmdsMaintained = new List<Cmd>();
- for (int i = 0, n = header.Cmds.Count; i < n; i++)
- {
- PredicateCmd a = header.Cmds[i] as PredicateCmd;
- if (a != null)
- {
- if (a is AssertCmd)
- {
- AssertCmd c = (AssertCmd)a;
- AssertCmd b = null;
-
- if (CommandLineOptions.Clo.ConcurrentHoudini)
- {
- Contract.Assert(taskID >= 0);
- if (CommandLineOptions.Clo.Cho[taskID].DisableLoopInvEntryAssert)
- b = new LoopInitAssertCmd(c.tok, Expr.True);
- else
- b = new LoopInitAssertCmd(c.tok, c.Expr);
- }
- else
- {
- b = new LoopInitAssertCmd(c.tok, c.Expr);
- }
-
- b.Attributes = c.Attributes;
- b.ErrorData = c.ErrorData;
- prefixOfPredicateCmdsInit.Add(b);
-
- if (CommandLineOptions.Clo.ConcurrentHoudini)
- {
- Contract.Assert(taskID >= 0);
- if (CommandLineOptions.Clo.Cho[taskID].DisableLoopInvMaintainedAssert)
- b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, Expr.True);
- else
- b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, c.Expr);
- }
- else
- {
- b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, c.Expr);
- }
-
- b.Attributes = c.Attributes;
- b.ErrorData = c.ErrorData;
- prefixOfPredicateCmdsMaintained.Add(b);
- header.Cmds[i] = new AssumeCmd(c.tok, c.Expr);
- }
- else
- {
- Contract.Assert(a is AssumeCmd);
- if (Bpl.CommandLineOptions.Clo.AlwaysAssumeFreeLoopInvariants)
- {
- // Usually, "free" stuff, like free loop invariants (and the assume statements
- // that stand for such loop invariants) are ignored on the checking side. This
- // command-line option changes that behavior to always assume the conditions.
- prefixOfPredicateCmdsInit.Add(a);
- prefixOfPredicateCmdsMaintained.Add(a);
- }
- }
- }
- else if (header.Cmds[i] is CommentCmd)
- {
- // ignore
- }
- else
- {
- break; // stop when an assignment statement (or any other non-predicate cmd) is encountered
- }
- }
- #endregion
-
- #region Copy the prefix of predicate commands into each predecessor. Do this *before* cutting the backedge!!
- for (int predIndex = 0, n = header.Predecessors.Count; predIndex < n; predIndex++)
- {
- Block pred = cce.NonNull(header.Predecessors[predIndex]);
-
- // Create a block between header and pred for the predicate commands if pred has more than one successor
- GotoCmd gotocmd = cce.NonNull((GotoCmd)pred.TransferCmd);
- Contract.Assert(gotocmd.labelNames != null); // if "pred" is really a predecessor, it may be a GotoCmd with at least one label
- if (gotocmd.labelNames.Count > 1)
- {
- Block newBlock = CreateBlockBetween(predIndex, header);
- impl.Blocks.Add(newBlock);
-
- // if pred is a back edge node, then now newBlock is the back edge node
- if (backEdgeNodes.ContainsKey(pred))
- {
- backEdgeNodes.Remove(pred);
- backEdgeNodes.Add(newBlock, null);
- }
-
- pred = newBlock;
- }
- // Add the predicate commands
- if (backEdgeNodes.ContainsKey(pred))
- {
- pred.Cmds.AddRange(prefixOfPredicateCmdsMaintained);
- }
- else
- {
- pred.Cmds.AddRange(prefixOfPredicateCmdsInit);
- }
- }
- #endregion
-
- #region Cut the back edge
- foreach (Block backEdgeNode in cce.NonNull(backEdgeNodes.Keys))
- {
- Contract.Assert(backEdgeNode != null);
- Debug.Assert(backEdgeNode.TransferCmd is GotoCmd, "An node was identified as the source for a backedge, but it does not have a goto command.");
- GotoCmd gtc = backEdgeNode.TransferCmd as GotoCmd;
- if (gtc != null && gtc.labelTargets != null && gtc.labelTargets.Count > 1)
- {
- // then remove the backedge by removing the target block from the list of gotos
- List<Block> remainingTargets = new List<Block>();
- List<String> remainingLabels = new List<String>();
- Contract.Assume(gtc.labelNames != null);
- for (int i = 0, n = gtc.labelTargets.Count; i < n; i++)
- {
- if (gtc.labelTargets[i] != header)
- {
- remainingTargets.Add(gtc.labelTargets[i]);
- remainingLabels.Add(gtc.labelNames[i]);
- }
- else
- RecordCutEdge(edgesCut, backEdgeNode, header);
- }
- gtc.labelTargets = remainingTargets;
- gtc.labelNames = remainingLabels;
- }
- else
- {
- // This backedge is the only out-going edge from this node.
- // Add an "assume false" statement to the end of the statements
- // inside of the block and change the goto command to a return command.
- AssumeCmd ac = new AssumeCmd(Token.NoToken, Expr.False);
- backEdgeNode.Cmds.Add(ac);
- backEdgeNode.TransferCmd = new ReturnCmd(Token.NoToken);
- if (gtc != null && gtc.labelTargets != null && gtc.labelTargets.Count == 1)
- RecordCutEdge(edgesCut, backEdgeNode, gtc.labelTargets[0]);
- }
- #region Remove the backedge node from the list of predecessor nodes in the header
- List<Block> newPreds = new List<Block>();
- foreach (Block p in header.Predecessors)
- {
- if (p != backEdgeNode)
- newPreds.Add(p);
- }
- header.Predecessors = newPreds;
- #endregion
- }
- #endregion
-
- #region Collect all variables that are assigned to in all of the natural loops for which this is the header
- List<Variable> varsToHavoc = VarsAssignedInLoop(g, header);
- List<IdentifierExpr> havocExprs = new List<IdentifierExpr>();
- foreach (Variable v in varsToHavoc)
- {
- Contract.Assert(v != null);
- IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v);
- if (!havocExprs.Contains(ie))
- havocExprs.Add(ie);
- }
- // pass the token of the enclosing loop header to the HavocCmd so we can reconstruct
- // the source location for this later on
- HavocCmd hc = new HavocCmd(header.tok, havocExprs);
- List<Cmd> newCmds = new List<Cmd>();
- newCmds.Add(hc);
- foreach (Cmd c in header.Cmds)
- {
- newCmds.Add(c);
- }
- header.Cmds = newCmds;
- #endregion
- }
- #endregion
- #endregion Convert program CFG into a DAG
- }
-
- public static List<Variable> VarsAssignedInLoop(Graph<Block> g, Block header)
- {
- List<Variable> varsToHavoc = new List<Variable>();
- foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header)))
- {
- Contract.Assert(backEdgeNode != null);
- foreach (Block b in g.NaturalLoops(header, backEdgeNode))
- {
- Contract.Assert(b != null);
- foreach (Cmd c in b.Cmds)
- {
- Contract.Assert(c != null);
- c.AddAssignedVariables(varsToHavoc);
- }
- }
- }
- return varsToHavoc;
- }
-
- public static IEnumerable<Variable> VarsReferencedInLoop(Graph<Block> g, Block header)
- {
- HashSet<Variable> referencedVars = new HashSet<Variable>();
- foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header)))
- {
- Contract.Assert(backEdgeNode != null);
- foreach (Block b in g.NaturalLoops(header, backEdgeNode))
- {
- Contract.Assert(b != null);
- foreach (Cmd c in b.Cmds)
- {
- Contract.Assert(c != null);
- var Collector = new VariableCollector();
- Collector.Visit(c);
- foreach(var v in Collector.usedVars) {
- referencedVars.Add(v);
- }
- }
- }
- }
- return referencedVars;
- }
-
- private void ConvertCFG2DAGKInduction(Implementation impl, Dictionary<Block, List<Block>> edgesCut, int taskID) {
-
- // K-induction has not been adapted to be aware of these parameters which standard CFG to DAG transformation uses
- Contract.Requires(edgesCut == null);
- Contract.Requires(taskID == -1);
-
- int inductionK = CommandLineOptions.Clo.KInductionDepth;
- Contract.Assume(inductionK >= 0);
-
- bool contRuleApplication = true;
- while (contRuleApplication) {
- contRuleApplication = false;
-
- #region Use the graph library to figure out where the (natural) loops are
-
- #region Create the graph by adding the source node and each edge
- Graph<Block> g = Program.GraphFromImpl(impl);
- #endregion
-
- g.ComputeLoops(); // this is the call that does all of the processing
- if (!g.Reducible) {
- throw new VCGenException("Irreducible flow graphs are unsupported.");
- }
-
- #endregion
-
- foreach (Block header in cce.NonNull(g.Headers)) {
- Contract.Assert(header != null);
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("Applying k-induction rule with k=" + inductionK);
- }
- #endregion
-
- #region generate the step case
- Block newHeader = DuplicateLoop(impl, g, header, null,
- false, false, "_step_assertion");
- for (int i = 0; i < inductionK; ++i)
- {
- newHeader = DuplicateLoop(impl, g, header, newHeader,
- true, true,
- "_step_" + (inductionK - i));
- }
- #endregion
-
- #region havoc variables that can be assigned in the loop
-
- List<Variable> varsToHavoc = VarsAssignedInLoop(g, header);
- List<IdentifierExpr> havocExprs = new List<IdentifierExpr>();
- foreach (Variable v in varsToHavoc)
- {
- Contract.Assert(v != null);
- IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v);
- if (!havocExprs.Contains(ie))
- havocExprs.Add(ie);
- }
- // pass the token of the enclosing loop header to the HavocCmd so we can reconstruct
- // the source location for this later on
- HavocCmd hc = new HavocCmd(newHeader.tok, havocExprs);
- List<Cmd> havocCmds = new List<Cmd>();
- havocCmds.Add(hc);
-
- Block havocBlock = new Block(newHeader.tok, newHeader.Label + "_havoc", havocCmds,
- new GotoCmd (newHeader.tok, new List<Block> { newHeader }));
-
- impl.Blocks.Add(havocBlock);
- newHeader.Predecessors.Add(havocBlock);
- newHeader = havocBlock;
-
- #endregion
-
- #region generate the base case loop copies
- for (int i = 0; i < inductionK; ++i)
- {
- newHeader = DuplicateLoop(impl, g, header, newHeader,
- false, false,
- "_base_" + (inductionK - i));
- }
- #endregion
-
- #region redirect into the new loop copies and remove the original loop (but don't redirect back-edges)
-
- IDictionary<Block, object> backEdgeNodes = new Dictionary<Block, object>();
- foreach (Block b in cce.NonNull(g.BackEdgeNodes(header))) { Contract.Assert(b != null); backEdgeNodes.Add(b, null); }
-
- for (int predIndex = 0, n = header.Predecessors.Count(); predIndex < n; predIndex++)
- {
- Block pred = cce.NonNull(header.Predecessors[predIndex]);
- if (!backEdgeNodes.ContainsKey(pred))
- {
- GotoCmd gc = pred.TransferCmd as GotoCmd;
- Contract.Assert(gc != null);
- for (int i = 0; i < gc.labelTargets.Count(); ++i)
- {
- if (gc.labelTargets[i] == header)
- {
- gc.labelTargets[i] = newHeader;
- gc.labelNames[i] = newHeader.Label;
- newHeader.Predecessors.Add(pred);
- }
- }
- }
- }
- impl.PruneUnreachableBlocks();
-
- #endregion
-
- contRuleApplication = true;
- break;
- }
-
- }
-
- ResetPredecessors(impl.Blocks);
- impl.FreshenCaptureStates();
-
- }
-
- private Block DuplicateLoop(Implementation impl, Graph<Block> g,
- Block header, Block nextHeader, bool cutExits,
- bool toAssumptions, string suffix)
- {
- IDictionary<Block, Block> ori2CopiedBlocks = new Dictionary<Block, Block>();
- Duplicator duplicator = new Duplicator();
-
- #region create copies of all blocks in the loop
- foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header)))
- {
- Contract.Assert(backEdgeNode != null);
- foreach (Block b in g.NaturalLoops(header, backEdgeNode))
- {
- Contract.Assert(b != null);
- if (!ori2CopiedBlocks.ContainsKey(b))
- {
- Block copy = (Block)duplicator.Visit(b);
- copy.Cmds = new List<Cmd>(copy.Cmds); // Philipp Ruemmer commented that this was necessary due to a bug in the Duplicator. That was a long time; worth checking whether this has been fixed
- copy.Predecessors = new List<Block>();
- copy.Label = copy.Label + suffix;
-
- #region turn asserts into assumptions
- if (toAssumptions)
- {
- for (int i = 0; i < copy.Cmds.Count(); ++i)
- {
- AssertCmd ac = copy.Cmds[i] as AssertCmd;
- if (ac != null)
- {
- copy.Cmds[i] = new AssumeCmd(ac.tok, ac.Expr);
- }
- }
- }
- #endregion
-
- impl.Blocks.Add(copy);
- ori2CopiedBlocks.Add(b, copy);
- }
- }
- }
- #endregion
-
- #region adjust the transfer commands of the newly created blocks
- foreach (KeyValuePair<Block, Block> pair in ori2CopiedBlocks)
- {
- Block copy = pair.Value;
- GotoCmd gc = copy.TransferCmd as GotoCmd;
- if (gc != null)
- {
- List<Block> newTargets = new List<Block>();
- List<string> newLabels = new List<string>();
-
- for (int i = 0; i < gc.labelTargets.Count(); ++i)
- {
- Block newTarget;
- if (gc.labelTargets[i] == header)
- {
- if (nextHeader != null)
- {
- newTargets.Add(nextHeader);
- newLabels.Add(nextHeader.Label);
- nextHeader.Predecessors.Add(copy);
- }
- }
- else if (ori2CopiedBlocks.TryGetValue(gc.labelTargets[i], out newTarget))
- {
- newTargets.Add(newTarget);
- newLabels.Add(newTarget.Label);
- newTarget.Predecessors.Add(copy);
- }
- else if (!cutExits)
- {
- newTargets.Add(gc.labelTargets[i]);
- newLabels.Add(gc.labelNames[i]);
- gc.labelTargets[i].Predecessors.Add(copy);
- }
- }
-
- if (newTargets.Count() == 0)
- {
- // if no targets are left, we assume false and return
- copy.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False));
- copy.TransferCmd = new ReturnCmd(Token.NoToken);
- }
- else
- {
- copy.TransferCmd = new GotoCmd(gc.tok, newLabels, newTargets);
- }
- }
- else if (cutExits && (copy.TransferCmd is ReturnCmd))
- {
- // because return is a kind of exit from the loop, we
- // assume false to cut this path
- copy.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False));
- }
- }
- #endregion
-
- return ori2CopiedBlocks[header];
- }
-
- public void DesugarCalls(Implementation impl) {
- foreach (Block block in impl.Blocks) {
- List<Cmd> newCmds = new List<Cmd>();
- foreach (Cmd cmd in block.Cmds) {
- SugaredCmd sugaredCmd = cmd as SugaredCmd;
- if (sugaredCmd != null) {
- StateCmd stateCmd = sugaredCmd.Desugaring as StateCmd;
- foreach (Variable v in stateCmd.Locals) {
- impl.LocVars.Add(v);
- }
- newCmds.AddRange(stateCmd.Cmds);
- }
- else {
- newCmds.Add(cmd);
- }
- }
- block.Cmds = newCmds;
- }
- }
-
- public Dictionary<TransferCmd, ReturnCmd> PassifyImpl(Implementation impl, out ModelViewInfo mvInfo)
- {
- Contract.Requires(impl != null);
- Contract.Requires(program != null);
- Contract.Ensures(Contract.Result<Dictionary<TransferCmd, ReturnCmd>>() != null);
-
- Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins = new Dictionary<TransferCmd, ReturnCmd>();
- Block exitBlock = GenerateUnifiedExit(impl, gotoCmdOrigins);
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after creating a unified exit block");
- EmitImpl(impl, true);
- }
- #endregion
-
- #region Insert pre- and post-conditions and where clauses as assume and assert statements
- {
- List<Cmd> cc = new List<Cmd>();
- // where clauses of global variables
- lock (program.TopLevelDeclarations)
- {
- foreach (var gvar in program.GlobalVariables)
- {
- if (gvar != null && gvar.TypedIdent.WhereExpr != null)
- {
- Cmd c = new AssumeCmd(gvar.tok, gvar.TypedIdent.WhereExpr);
- cc.Add(c);
- }
- }
- }
- // where clauses of in- and out-parameters
- cc.AddRange(GetParamWhereClauses(impl));
- // where clauses of local variables
- foreach (Variable lvar in impl.LocVars) {Contract.Assert(lvar != null);
- if (lvar.TypedIdent.WhereExpr != null) {
- Cmd c = new AssumeCmd(lvar.tok, lvar.TypedIdent.WhereExpr);
- cc.Add(c);
- } else if (QKeyValue.FindBoolAttribute(lvar.Attributes, "assumption")) {
- cc.Add(new AssumeCmd(lvar.tok, new IdentifierExpr(lvar.tok, lvar), new QKeyValue(lvar.tok, "assumption_variable_initialization", new List<object>(), null)));
- }
- }
- // add cc and the preconditions to new blocks preceding impl.Blocks[0]
- InjectPreconditions(impl, cc);
-
- // append postconditions, starting in exitBlock and continuing into other blocks, if needed
- InjectPostConditions(impl, exitBlock, gotoCmdOrigins);
- }
- #endregion
-
- #region Support for stratified inlining
- addExitAssert(impl.Name, exitBlock);
- #endregion
-
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after inserting pre- and post-conditions");
- EmitImpl(impl, true);
- }
- #endregion
-
- AddBlocksBetween(impl.Blocks);
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after adding empty blocks as needed to catch join assumptions");
- EmitImpl(impl, true);
- }
- #endregion
-
- if (CommandLineOptions.Clo.LiveVariableAnalysis > 0) {
- Microsoft.Boogie.LiveVariableAnalysis.ComputeLiveVariables(impl);
- }
-
- mvInfo = new ModelViewInfo(program, impl);
- Convert2PassiveCmd(impl, mvInfo);
-
- #region Peep-hole optimizations
- if (CommandLineOptions.Clo.RemoveEmptyBlocks){
- #region Get rid of empty blocks
- {
- RemoveEmptyBlocksIterative(impl.Blocks);
- impl.PruneUnreachableBlocks();
- }
- #endregion Get rid of empty blocks
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after peep-hole optimizations");
- EmitImpl(impl, true);
- }
- #endregion
- }
- #endregion Peep-hole optimizations
-
- HandleSelectiveChecking(impl);
-
-
-// #region Constant Folding
-// #endregion
-// #region Debug Tracing
-// if (CommandLineOptions.Clo.TraceVerify)
-// {
-// Console.WriteLine("after constant folding");
-// EmitImpl(impl, true);
-// }
-// #endregion
-
- return gotoCmdOrigins;
- }
-
- private static void HandleSelectiveChecking(Implementation impl)
- {
- if (QKeyValue.FindBoolAttribute(impl.Attributes, "selective_checking") ||
- QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "selective_checking")) {
-
- var startPoints = new List<Block>();
- foreach (var b in impl.Blocks) {
- foreach (Cmd c in b.Cmds) {
- var p = c as PredicateCmd;
- if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "start_checking_here")) {
- startPoints.Add(b);
- break;
- }
- }
- }
-
- // Compute the set of blocks reachable from blocks containing "start_checking_here"
- var blocksToCheck = new HashSet<Block>();
- foreach (var b in startPoints) {
- var todo = new Stack<Block>();
- var wasThere = blocksToCheck.Contains(b);
- todo.Push(b);
- while (todo.Count > 0) {
- var x = todo.Pop();
- if (blocksToCheck.Contains(x)) continue;
- blocksToCheck.Add(x);
- var ex = x.TransferCmd as GotoCmd;
- if (ex != null)
- foreach (Block e in ex.labelTargets)
- todo.Push(e);
- }
- if (!wasThere) blocksToCheck.Remove(b);
- }
-
- // Convert asserts to assumes in "unreachable" blocks, as well as in portions of blocks before we reach "start_checking_here"
- foreach (var b in impl.Blocks) {
- if (blocksToCheck.Contains(b)) continue; // All reachable blocks must be checked in their entirety, so don't change anything
- var newCmds = new List<Cmd>();
- var copyMode = false;
- foreach (Cmd c in b.Cmds) {
- var p = c as PredicateCmd;
- if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "start_checking_here"))
- copyMode = true;
- var asrt = c as AssertCmd;
- if (copyMode || asrt == null)
- newCmds.Add(c);
- else
- newCmds.Add(AssertTurnedIntoAssume(asrt));
- }
-
- b.Cmds = newCmds;
- }
- }
- }
-
- // Used by stratified inlining
- protected virtual void addExitAssert(string implName, Block exitBlock)
- {
- }
-
- public virtual Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
- {
- // Construct the set of inlined procs in the original program
- var inlinedProcs = new HashSet<string>();
- foreach (var proc in program.Procedures)
- {
- if (!(proc is LoopProcedure))
- {
- inlinedProcs.Add(proc.Name);
- }
- }
-
- return extractLoopTraceRec(
- new CalleeCounterexampleInfo(cex, new List<object>()),
- mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample;
- }
-
- protected CalleeCounterexampleInfo extractLoopTraceRec(
- CalleeCounterexampleInfo cexInfo, string currProc,
- HashSet<string> inlinedProcs,
- Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
- {
- Contract.Requires(currProc != null);
- if (cexInfo.counterexample == null) return cexInfo;
-
- var cex = cexInfo.counterexample;
- // Go through all blocks in the trace, map them back to blocks in the original program (if there is one)
- var ret = cex.Clone();
- ret.Trace = new List<Block>();
- ret.calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
-
- for (int numBlock = 0; numBlock < cex.Trace.Count; numBlock ++ )
- {
- Block block = cex.Trace[numBlock];
- var origBlock = elGetBlock(currProc, block, extractLoopMappingInfo);
- if (origBlock != null) ret.Trace.Add(origBlock);
- var callCnt = 1;
- for (int numInstr = 0; numInstr < block.Cmds.Count; numInstr ++) {
- Cmd cmd = block.Cmds[numInstr];
- var loc = new TraceLocation(numBlock, numInstr);
- if (!cex.calleeCounterexamples.ContainsKey(loc))
- {
- if (getCallee(cex.getTraceCmd(loc), inlinedProcs) != null) callCnt++;
- continue;
- }
- string callee = cex.getCalledProcName(cex.getTraceCmd(loc));
- Contract.Assert(callee != null);
- var calleeTrace = cex.calleeCounterexamples[loc];
- Debug.Assert(calleeTrace != null);
-
- var origTrace = extractLoopTraceRec(calleeTrace, callee, inlinedProcs, extractLoopMappingInfo);
-
- if (elIsLoop(callee))
- {
- // Absorb the trace into the current trace
-
- int currLen = ret.Trace.Count;
- ret.Trace.AddRange(origTrace.counterexample.Trace);
-
- foreach (var kvp in origTrace.counterexample.calleeCounterexamples)
- {
- var newloc = new TraceLocation(kvp.Key.numBlock + currLen, kvp.Key.numInstr);
- ret.calleeCounterexamples.Add(newloc, kvp.Value);
- }
-
- }
- else
- {
- var origLoc = new TraceLocation(ret.Trace.Count - 1, getCallCmdPosition(origBlock, callCnt, inlinedProcs, callee));
- ret.calleeCounterexamples.Add(origLoc, origTrace);
- callCnt++;
- }
- }
- }
- return new CalleeCounterexampleInfo(ret, cexInfo.args);
- }
-
- // return the position of the i^th CallCmd in the block (count only those Calls that call a procedure in inlinedProcs).
- // Assert failure if there isn't any.
- // Assert that the CallCmd found calls "callee"
- private int getCallCmdPosition(Block block, int i, HashSet<string> inlinedProcs, string callee)
- {
- Debug.Assert(i >= 1);
- for (int pos = 0; pos < block.Cmds.Count; pos++)
- {
- Cmd cmd = block.Cmds[pos];
- string procCalled = getCallee(cmd, inlinedProcs);
-
- if (procCalled != null)
- {
- if (i == 1)
- {
- Debug.Assert(procCalled == callee);
- return pos;
- }
- i--;
- }
- }
-
- Debug.Assert(false, "Didn't find the i^th call cmd");
- return -1;
- }
-
- private string getCallee(Cmd cmd, HashSet<string> inlinedProcs)
- {
- string procCalled = null;
- if (cmd is CallCmd)
- {
- var cc = (CallCmd)cmd;
- if (inlinedProcs.Contains(cc.Proc.Name))
- {
- procCalled = cc.Proc.Name;
- }
- }
-
- if (cmd is AssumeCmd)
- {
- var expr = (cmd as AssumeCmd).Expr as NAryExpr;
- if (expr != null)
- {
- if (inlinedProcs.Contains(expr.Fun.FunctionName))
- {
- procCalled = expr.Fun.FunctionName;
- }
- }
- }
- return procCalled;
- }
-
- protected virtual bool elIsLoop(string procname)
- {
- return false;
- }
-
- private Block elGetBlock(string procname, Block block, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
- {
- Contract.Requires(procname != null);
-
- if (!extractLoopMappingInfo.ContainsKey(procname))
- return block;
-
- if (!extractLoopMappingInfo[procname].ContainsKey(block.Label))
- return null;
-
- return extractLoopMappingInfo[procname][block.Label];
- }
-
- static Counterexample TraceCounterexample(
- Block/*!*/ b, Hashtable/*!*/ traceNodes, List<Block>/*!*/ trace, Model errModel, ModelViewInfo mvInfo,
- Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap,
- ProverContext/*!*/ context,
- Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples)
- {
- Contract.Requires(b != null);
- Contract.Requires(traceNodes != null);
- Contract.Requires(trace != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap));
- Contract.Requires(context != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples));
- // After translation, all potential errors come from asserts.
-
- while (true)
- {
- List<Cmd> cmds = b.Cmds;
- Contract.Assert(cmds != null);
- TransferCmd transferCmd = cce.NonNull(b.TransferCmd);
- for (int i = 0; i < cmds.Count; i++)
- {
- Cmd cmd = cce.NonNull(cmds[i]);
-
- // Skip if 'cmd' not contained in the trace or not an assert
- if (cmd is AssertCmd && traceNodes.Contains(cmd))
- {
- Counterexample newCounterexample = AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, errModel, mvInfo, context);
- Contract.Assert(newCounterexample != null);
- newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
- return newCounterexample;
- }
- }
-
- GotoCmd gotoCmd = transferCmd as GotoCmd;
- if (gotoCmd == null) return null;
- Block foundBlock = null;
- foreach (Block bb in cce.NonNull(gotoCmd.labelTargets))
- {
- Contract.Assert(bb != null);
- if (traceNodes.Contains(bb))
- {
- foundBlock = bb;
- break;
- }
- }
- if (foundBlock == null) return null;
- trace.Add(foundBlock);
- b = foundBlock;
- }
- }
-
- public static Counterexample AssertCmdToCounterexample(AssertCmd cmd, TransferCmd transferCmd, List<Block> trace, Model errModel, ModelViewInfo mvInfo, ProverContext context)
- {
- Contract.Requires(cmd != null);
- Contract.Requires(transferCmd != null);
- Contract.Requires(trace != null);
- Contract.Requires(context != null);
- Contract.Ensures(Contract.Result<Counterexample>() != null);
-
- List<string> relatedInformation = new List<string>();
-
- // See if it is a special assert inserted in translation
- if (cmd is AssertRequiresCmd)
- {
- AssertRequiresCmd assertCmd = (AssertRequiresCmd)cmd;
- Contract.Assert(assertCmd != null);
- CallCounterexample cc = new CallCounterexample(trace, assertCmd.Call, assertCmd.Requires, errModel, mvInfo, context, assertCmd.Checksum);
- cc.relatedInformation = relatedInformation;
- return cc;
- }
- else if (cmd is AssertEnsuresCmd)
- {
- AssertEnsuresCmd assertCmd = (AssertEnsuresCmd)cmd;
- Contract.Assert(assertCmd != null);
- ReturnCounterexample rc = new ReturnCounterexample(trace, transferCmd, assertCmd.Ensures, errModel, mvInfo, context, cmd.Checksum);
- rc.relatedInformation = relatedInformation;
- return rc;
- }
- else
- {
- AssertCounterexample ac = new AssertCounterexample(trace, (AssertCmd)cmd, errModel, mvInfo, context);
- ac.relatedInformation = relatedInformation;
- return ac;
- }
- }
-
- /// <summary>
- /// Returns a clone of "cex", but with the location stored in "cex" replaced by those from "assrt".
- /// </summary>
- public static Counterexample AssertCmdToCloneCounterexample(AssertCmd assrt, Counterexample cex) {
- Contract.Requires(assrt != null);
- Contract.Requires(cex != null);
- Contract.Ensures(Contract.Result<Counterexample>() != null);
-
- List<string> relatedInformation = new List<string>();
-
- Counterexample cc;
- if (assrt is AssertRequiresCmd) {
- var aa = (AssertRequiresCmd)assrt;
- cc = new CallCounterexample(cex.Trace, aa.Call, aa.Requires, cex.Model, cex.MvInfo, cex.Context, aa.Checksum);
- } else if (assrt is AssertEnsuresCmd && cex is ReturnCounterexample) {
- var aa = (AssertEnsuresCmd)assrt;
- var oldCex = (ReturnCounterexample)cex;
- cc = new ReturnCounterexample(cex.Trace, oldCex.FailingReturn, aa.Ensures, cex.Model, cex.MvInfo, cex.Context, aa.Checksum);
- } else {
- cc = new AssertCounterexample(cex.Trace, assrt, cex.Model, cex.MvInfo, cex.Context);
- }
- cc.relatedInformation = relatedInformation;
- return cc;
- }
-
- static VCExpr LetVC(Block startBlock,
- VCExpr controlFlowVariableExpr,
- Dictionary<int, Absy> label2absy,
- ProverContext proverCtxt,
- out int assertionCount) {
- Contract.Requires(startBlock != null);
- Contract.Requires(proverCtxt != null);
-
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- Hashtable/*<Block, LetVariable!>*/ blockVariables = new Hashtable/*<Block, LetVariable!!>*/();
- List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
- VCExpr startCorrect = LetVC(startBlock, controlFlowVariableExpr, label2absy, blockVariables, bindings, proverCtxt, out assertionCount);
- return proverCtxt.ExprGen.Let(bindings, startCorrect);
- }
-
- static VCExpr LetVCIterative(List<Block> blocks,
- VCExpr controlFlowVariableExpr,
- Dictionary<int, Absy> label2absy,
- ProverContext proverCtxt,
- out int assertionCount,
- bool isPositiveContext = true)
- {
- Contract.Requires(blocks != null);
- Contract.Requires(proverCtxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- assertionCount = 0;
-
- Graph<Block> dag = new Graph<Block>();
- dag.AddSource(blocks[0]);
- foreach (Block b in blocks) {
- GotoCmd gtc = b.TransferCmd as GotoCmd;
- if (gtc != null) {
- Contract.Assume(gtc.labelTargets != null);
- foreach (Block dest in gtc.labelTargets) {
- Contract.Assert(dest != null);
- dag.AddEdge(dest, b);
- }
- }
- }
- IEnumerable sortedNodes = dag.TopologicalSort();
- Contract.Assert(sortedNodes != null);
-
- Dictionary<Block, VCExprVar> blockVariables = new Dictionary<Block, VCExprVar>();
- List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
- VCExpressionGenerator gen = proverCtxt.ExprGen;
- Contract.Assert(gen != null);
- foreach (Block block in sortedNodes) {
- VCExpr SuccCorrect;
- GotoCmd gotocmd = block.TransferCmd as GotoCmd;
- if (gotocmd == null) {
- ReturnExprCmd re = block.TransferCmd as ReturnExprCmd;
- if (re == null) {
- SuccCorrect = VCExpressionGenerator.True;
- }
- else {
- SuccCorrect = proverCtxt.BoogieExprTranslator.Translate(re.Expr);
- if (isPositiveContext)
- {
- SuccCorrect = gen.Not(SuccCorrect);
- }
- }
- }
- else {
- Contract.Assert(gotocmd.labelTargets != null);
- List<VCExpr> SuccCorrectVars = new List<VCExpr>(gotocmd.labelTargets.Count);
- foreach (Block successor in gotocmd.labelTargets) {
- Contract.Assert(successor != null);
- VCExpr s = blockVariables[successor];
- if (controlFlowVariableExpr != null) {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
- VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
- s = gen.Implies(controlTransferExpr, s);
- }
- SuccCorrectVars.Add(s);
- }
- SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars);
- }
-
- VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr, isPositiveContext);
- VCExpr vc = Wlp.Block(block, SuccCorrect, context);
- assertionCount += context.AssertionCount;
-
- VCExprVar v = gen.Variable(block.Label + "_correct", Bpl.Type.Bool);
- bindings.Add(gen.LetBinding(v, vc));
- blockVariables.Add(block, v);
- }
-
- return proverCtxt.ExprGen.Let(bindings, blockVariables[blocks[0]]);
- }
-
- static VCExpr LetVC(Block block,
- VCExpr controlFlowVariableExpr,
- Dictionary<int, Absy> label2absy,
- Hashtable/*<Block, VCExprVar!>*/ blockVariables,
- List<VCExprLetBinding/*!*/>/*!*/ bindings,
- ProverContext proverCtxt,
- out int assertionCount)
- {
- Contract.Requires(block != null);
- Contract.Requires(blockVariables!= null);
- Contract.Requires(cce.NonNullElements(bindings));
- Contract.Requires(proverCtxt != null);
-
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- assertionCount = 0;
-
- VCExpressionGenerator gen = proverCtxt.ExprGen;
- Contract.Assert(gen != null);
- VCExprVar v = (VCExprVar)blockVariables[block];
- if (v == null) {
- /*
- * For block A (= block), generate:
- * LET_binding A_correct = wp(A_body, (/\ S \in Successors(A) :: S_correct))
- * with the side effect of adding the let bindings to "bindings" for any
- * successor not yet visited.
- */
- VCExpr SuccCorrect;
- GotoCmd gotocmd = block.TransferCmd as GotoCmd;
- if (gotocmd == null) {
- ReturnExprCmd re = block.TransferCmd as ReturnExprCmd;
- if (re == null) {
- SuccCorrect = VCExpressionGenerator.True;
- } else {
- SuccCorrect = proverCtxt.BoogieExprTranslator.Translate(re.Expr);
- }
- } else {
- Contract.Assert( gotocmd.labelTargets != null);
- List<VCExpr> SuccCorrectVars = new List<VCExpr>(gotocmd.labelTargets.Count);
- foreach (Block successor in gotocmd.labelTargets) {
- Contract.Assert(successor != null);
- int ac;
- VCExpr s = LetVC(successor, controlFlowVariableExpr, label2absy, blockVariables, bindings, proverCtxt, out ac);
- assertionCount += ac;
- if (controlFlowVariableExpr != null)
- {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
- VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
- s = gen.Implies(controlTransferExpr, s);
- }
- SuccCorrectVars.Add(s);
- }
- SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars);
- }
-
-
- VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr);
- VCExpr vc = Wlp.Block(block, SuccCorrect, context);
- assertionCount += context.AssertionCount;
-
- v = gen.Variable(block.Label + "_correct", Bpl.Type.Bool);
- bindings.Add(gen.LetBinding(v, vc));
- blockVariables.Add(block, v);
- }
- return v;
- }
-
- static VCExpr DagVC(Block block,
- VCExpr controlFlowVariableExpr,
- Dictionary<int, Absy> label2absy,
- Hashtable/*<Block, VCExpr!>*/ blockEquations,
- ProverContext proverCtxt,
- out int assertionCount)
- {
- Contract.Requires(block != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(blockEquations != null);
- Contract.Requires(proverCtxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- assertionCount = 0;
- VCExpressionGenerator gen = proverCtxt.ExprGen;
- Contract.Assert(gen != null);
- VCExpr vc = (VCExpr)blockEquations[block];
- if (vc != null) {
- return vc;
- }
-
- /*
- * For block A (= block), generate:
- * wp(A_body, (/\ S \in Successors(A) :: DagVC(S)))
- */
- VCExpr SuccCorrect = null;
- GotoCmd gotocmd = block.TransferCmd as GotoCmd;
- if (gotocmd != null)
- {
- foreach (Block successor in cce.NonNull(gotocmd.labelTargets)) {
- Contract.Assert(successor != null);
- int ac;
- VCExpr c = DagVC(successor, controlFlowVariableExpr, label2absy, blockEquations, proverCtxt, out ac);
- assertionCount += ac;
- if (controlFlowVariableExpr != null) {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
- VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
- c = gen.Implies(controlTransferExpr, c);
- }
- SuccCorrect = SuccCorrect == null ? c : gen.And(SuccCorrect, c);
- }
- }
- if (SuccCorrect == null) {
- SuccCorrect = VCExpressionGenerator.True;
- }
-
- VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr);
- vc = Wlp.Block(block, SuccCorrect, context);
- assertionCount += context.AssertionCount;
-
- // gen.MarkAsSharedFormula(vc); PR: don't know yet what to do with this guy
-
- blockEquations.Add(block, vc);
- return vc;
- }
-
- static VCExpr FlatBlockVC(Implementation impl,
- Dictionary<int, Absy> label2absy,
- bool local, bool reach, bool doomed,
- ProverContext proverCtxt,
- out int assertionCount)
- {
- Contract.Requires(impl != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(proverCtxt != null);
- Contract.Requires( !local || !reach); // "reach" must be false for local
-
- VCExpressionGenerator gen = proverCtxt.ExprGen;
- Contract.Assert(gen != null);
- Hashtable/* Block --> VCExprVar */ BlkCorrect = BlockVariableMap(impl.Blocks, "_correct", gen);
- Hashtable/* Block --> VCExprVar */ BlkReached = reach ? BlockVariableMap(impl.Blocks, "_reached", gen) : null;
-
- List<Block> blocks = impl.Blocks;
- Contract.Assert(blocks != null);
- // block sorting is now done on the VCExpr
- // if (!local && (cce.NonNull(CommandLineOptions.Clo.TheProverFactory).NeedsBlockSorting) {
- // blocks = SortBlocks(blocks);
- // }
-
- VCExpr proofObligation;
- if (!local) {
- proofObligation = cce.NonNull((VCExprVar)BlkCorrect[impl.Blocks[0]]);
- } else {
- List<VCExpr> conjuncts = new List<VCExpr>(blocks.Count);
- foreach (Block b in blocks) {Contract.Assert(b != null);
- VCExpr v = cce.NonNull((VCExprVar)BlkCorrect[b]);
- conjuncts.Add(v);
- }
- proofObligation = gen.NAry(VCExpressionGenerator.AndOp, conjuncts);
- }
-
- VCContext context = new VCContext(label2absy, proverCtxt);
- Contract.Assert(context != null);
-
- List<VCExprLetBinding> programSemantics = new List<VCExprLetBinding>(blocks.Count);
- foreach (Block b in blocks) {Contract.Assert(b != null);
- /*
- * In block mode,
- * For a return block A, generate:
- * A_correct <== wp(A_body, true) [post-condition has been translated into an assert]
- * For all other blocks, generate:
- * A_correct <== wp(A_body, (/\ S \in Successors(A) :: S_correct))
- *
- * In doomed mode, proceed as in block mode, except for a return block A, generate:
- * A_correct <== wp(A_body, false) [post-condition has been translated into an assert]
- *
- * In block reach mode, the wp(A_body,...) in the equations above change to:
- * A_reached ==> wp(A_body,...)
- * and the conjunction above changes to:
- * (/\ S \in Successors(A) :: S_correct \/ (\/ T \in Successors(A) && T != S :: T_reached))
- *
- * In local mode, generate:
- * A_correct <== wp(A_body, true)
- */
- VCExpr SuccCorrect;
- if (local) {
- SuccCorrect = VCExpressionGenerator.True;
- } else {
- SuccCorrect = SuccessorsCorrect(b, BlkCorrect, BlkReached, doomed, gen);
- }
-
- VCExpr wlp = Wlp.Block(b, SuccCorrect, context);
- if (BlkReached != null) {
- wlp = gen.Implies(cce.NonNull((VCExprVar)BlkReached[b]), wlp);
- }
-
- VCExprVar okVar = cce.NonNull((VCExprVar)BlkCorrect[b]);
- VCExprLetBinding binding = gen.LetBinding(okVar, wlp);
- programSemantics.Add(binding);
- }
-
- assertionCount = context.AssertionCount;
- return gen.Let(programSemantics, proofObligation);
- }
-
- private static Hashtable/* Block --> VCExprVar */ BlockVariableMap(List<Block/*!*/>/*!*/ blocks, string suffix,
- Microsoft.Boogie.VCExpressionGenerator gen) {
- Contract.Requires(cce.NonNullElements(blocks));
- Contract.Requires(suffix != null);
- Contract.Requires(gen != null);
- Contract.Ensures(Contract.Result<Hashtable>() != null);
-
- Hashtable/* Block --> VCExprVar */ map = new Hashtable/* Block --> (Let)Variable */();
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- VCExprVar v = gen.Variable(b.Label + suffix, Bpl.Type.Bool);
- Contract.Assert(v != null);
- map.Add(b, v);
- }
- return map;
- }
-
- private static VCExpr SuccessorsCorrect(
- Block b,
- Hashtable/* Block --> VCExprVar */ BlkCorrect,
- Hashtable/* Block --> VCExprVar */ BlkReached,
- bool doomed,
- Microsoft.Boogie.VCExpressionGenerator gen) {
- Contract.Requires(b != null);
- Contract.Requires(BlkCorrect != null);
- Contract.Requires(gen != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr SuccCorrect = null;
- GotoCmd gotocmd = b.TransferCmd as GotoCmd;
- if (gotocmd != null) {
- foreach (Block successor in cce.NonNull(gotocmd.labelTargets)) {
- Contract.Assert(successor != null);
- // c := S_correct
- VCExpr c = (VCExprVar)BlkCorrect[successor];
- Contract.Assert(c != null);
- if (BlkReached != null) {
- // c := S_correct \/ Sibling0_reached \/ Sibling1_reached \/ ...;
- foreach (Block successorSibling in gotocmd.labelTargets) {
- Contract.Assert(successorSibling != null);
- if (successorSibling != successor) {
- c = gen.Or(c, cce.NonNull((VCExprVar)BlkReached[successorSibling]));
- }
- }
- }
- SuccCorrect = SuccCorrect == null ? c : gen.And(SuccCorrect, c);
- }
- }
- if (SuccCorrect == null) {
- return VCExpressionGenerator.True;
- } else if (doomed) {
- return VCExpressionGenerator.False;
- } else {
- return SuccCorrect;
- }
- }
-
- static VCExpr NestedBlockVC(Implementation impl,
- Dictionary<int, Absy> label2absy,
- bool reach,
- ProverContext proverCtxt,
- out int assertionCount){
- Contract.Requires(impl != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(proverCtxt != null);
- Contract.Requires( impl.Blocks.Count != 0);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpressionGenerator gen = proverCtxt.ExprGen;
- Contract.Assert(gen != null);
- Graph<Block> g = Program.GraphFromImpl(impl);
-
- Hashtable/* Block --> VCExprVar */ BlkCorrect = BlockVariableMap(impl.Blocks, "_correct", gen);
- Hashtable/* Block --> VCExprVar */ BlkReached = reach ? BlockVariableMap(impl.Blocks, "_reached", gen) : null;
-
- Block startBlock = cce.NonNull( impl.Blocks[0]);
- VCExpr proofObligation = (VCExprVar)BlkCorrect[startBlock];
- Contract.Assert(proofObligation != null);
- VCContext context = new VCContext(label2absy, proverCtxt);
-
- Hashtable/*Block->int*/ totalOrder = new Hashtable/*Block->int*/();
- {
- List<Block> blocks = impl.Blocks;
-
- // block sorting is now done on the VCExpr
- // if (((!)CommandLineOptions.Clo.TheProverFactory).NeedsBlockSorting) {
- // blocks = SortBlocks(blocks);
- // }
- int i = 0;
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- totalOrder[b] = i;
- i++;
- }
- }
-
- VCExprLetBinding programSemantics = NestedBlockEquation(cce.NonNull(impl.Blocks[0]), BlkCorrect, BlkReached, totalOrder, context, g, gen);
- List<VCExprLetBinding> ps = new List<VCExprLetBinding>(1);
- ps.Add(programSemantics);
-
- assertionCount = context.AssertionCount;
- return gen.Let(ps, proofObligation);
- }
-
- private static VCExprLetBinding NestedBlockEquation(Block b,
- Hashtable/*Block-->VCExprVar*/ BlkCorrect,
- Hashtable/*Block-->VCExprVar*/ BlkReached,
- Hashtable/*Block->int*/ totalOrder,
- VCContext context,
- Graph<Block> g,
- Microsoft.Boogie.VCExpressionGenerator gen) {
- Contract.Requires(b != null);
- Contract.Requires(BlkCorrect != null);
- Contract.Requires(totalOrder != null);
- Contract.Requires(g != null);
- Contract.Requires(context != null);
-
- Contract.Ensures(Contract.Result<VCExprLetBinding>() != null);
-
- /*
- * For a block b, return:
- * LET_BINDING b_correct = wp(b_body, X)
- * where X is:
- * LET (THOSE d \in DirectDominates(b) :: BlockEquation(d))
- * IN (/\ s \in Successors(b) :: s_correct)
- *
- * When the VC-expression generator does not support LET expresions, this
- * will eventually turn into:
- * b_correct <== wp(b_body, X)
- * where X is:
- * (/\ s \in Successors(b) :: s_correct)
- * <==
- * (/\ d \in DirectDominatees(b) :: BlockEquation(d))
- *
- * In both cases above, if BlkReached is non-null, then the wp expression
- * is instead:
- * b_reached ==> wp(b_body, X)
- */
-
- VCExpr SuccCorrect = SuccessorsCorrect(b, BlkCorrect, null, false, gen);
- Contract.Assert(SuccCorrect != null);
-
- List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
- foreach (Block dominee in GetSortedBlocksImmediatelyDominatedBy(g, b, totalOrder)) {
- Contract.Assert(dominee != null);
- VCExprLetBinding c = NestedBlockEquation(dominee, BlkCorrect, BlkReached, totalOrder, context, g, gen);
- bindings.Add(c);
- }
-
- VCExpr X = gen.Let(bindings, SuccCorrect);
- VCExpr wlp = Wlp.Block(b, X, context);
- if (BlkReached != null) {
- wlp = gen.Implies((VCExprVar)BlkReached[b], wlp);
- Contract.Assert(wlp != null);
- }
- VCExprVar okVar = cce.NonNull((VCExprVar)BlkCorrect[b]);
- return gen.LetBinding(okVar, wlp);
- }
-
- /// <summary>
- /// Returns a list of g.ImmediatelyDominatedBy(b), but in a sorted order, hoping to steer around
- /// the nondeterminism problems we've been seeing by using just this call.
- /// </summary>
- static List<Block/*!*/>/*!*/ GetSortedBlocksImmediatelyDominatedBy(Graph<Block>/*!*/ g, Block/*!*/ b, Hashtable/*Block->int*//*!*/ totalOrder) {
- Contract.Requires(g != null);
- Contract.Requires(b != null);
- Contract.Requires(totalOrder != null);
- Contract.Ensures(Contract.Result<List<Block>>() != null);
-
- List<Block> list = new List<Block>();
- foreach (Block dominee in g.ImmediatelyDominatedBy(b)) {
- Contract.Assert(dominee != null);
- list.Add(dominee);
- }
- list.Sort(new Comparison<Block>(delegate(Block x, Block y) {
- return (int)cce.NonNull(totalOrder[x]) - (int)cce.NonNull(totalOrder[y]);
- }));
- return list;
- }
-
- static VCExpr VCViaStructuredProgram
- (Implementation impl, Dictionary<int, Absy> label2absy,
- ProverContext proverCtxt,
- out int assertionCount)
- {
- Contract.Requires(impl != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(proverCtxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- #region Convert block structure back to a "regular expression"
- RE r = DAG2RE.Transform(cce.NonNull(impl.Blocks[0]));
- Contract.Assert(r != null);
- #endregion
-
- VCContext ctxt = new VCContext(label2absy, proverCtxt);
- Contract.Assert(ctxt != null);
- #region Send wlp(program,true) to Simplify
- var vcexp = Wlp.RegExpr(r, VCExpressionGenerator.True, ctxt);
- assertionCount = ctxt.AssertionCount;
- return vcexp;
- #endregion
- }
-
- /// <summary>
- /// Remove empty blocks reachable from the startBlock of the CFG
- /// </summary>
- static void RemoveEmptyBlocksIterative(List<Block> blocks) {
- // postorder traversal of cfg
- // noting loop heads in [keep] and
- // generating token information in [renameInfo]
- Block startBlock = blocks[0];
- var postorder = new List<Block>();
- var keep = new HashSet<Block>();
- var visited = new HashSet<Block>();
- var grey = new HashSet<Block>();
- var stack = new Stack<Block>();
- Dictionary<Block, Block> renameInfo = new Dictionary<Block, Block>();
-
- stack.Push(startBlock);
- visited.Add(startBlock);
- while (stack.Count != 0) {
- var curr = stack.Pop();
- if (grey.Contains(curr)) {
- postorder.Add(curr);
-
- // generate renameInfoForStartBlock
- GotoCmd gtc = curr.TransferCmd as GotoCmd;
- renameInfo[curr] = null;
- if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0) {
- if (curr.Cmds.Count == 0 && curr.tok.IsValid) {
- renameInfo[curr] = curr;
- }
- } else {
- if (curr.Cmds.Count == 0 || curr == startBlock) {
- if (curr.tok.IsValid) {
- renameInfo[curr] = curr;
- } else {
- HashSet<Block> successorRenameInfo = new HashSet<Block>();
- foreach (Block s in gtc.labelTargets) {
- if (keep.Contains(s)) {
- successorRenameInfo.Add(null);
- } else {
- successorRenameInfo.Add(renameInfo[s]);
- }
- }
- if (successorRenameInfo.Count == 1) {
- renameInfo[curr] = successorRenameInfo.Single();
- }
- }
- }
- }
- // end generate renameInfoForStartBlock
-
- } else {
- grey.Add(curr);
- stack.Push(curr);
- GotoCmd gtc = curr.TransferCmd as GotoCmd;
- if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0) continue;
- foreach (Block s in gtc.labelTargets) {
- if (!visited.Contains(s)) {
- visited.Add(s);
- stack.Push(s);
- } else if (grey.Contains(s) && !postorder.Contains(s)) { // s is a loop head
- keep.Add(s);
- }
- }
- }
- }
- keep.Add(startBlock);
-
- foreach (Block b in postorder) {
- if (!keep.Contains(b) && b.Cmds.Count == 0) {
- GotoCmd bGtc = b.TransferCmd as GotoCmd;
- foreach (Block p in b.Predecessors) {
- GotoCmd pGtc = p.TransferCmd as GotoCmd;
- Contract.Assert(pGtc != null);
- pGtc.labelTargets.Remove(b);
- pGtc.labelNames.Remove(b.Label);
- }
- if (bGtc == null || bGtc.labelTargets == null || bGtc.labelTargets.Count == 0) {
- continue;
- }
-
- List<Block> successors = bGtc.labelTargets;
-
- // Try to push token information if possible
- if (b.tok.IsValid && successors.Count == 1 && b != renameInfo[startBlock]) {
- var s = successors.Single();
- if (!s.tok.IsValid) {
- foreach (Block p in s.Predecessors) {
- if (p != b) {
- GotoCmd pGtc = p.TransferCmd as GotoCmd;
- Contract.Assert(pGtc != null);
- pGtc.labelTargets.Remove(s);
- pGtc.labelNames.Remove(s.Label);
- pGtc.labelTargets.Add(s);
- pGtc.labelNames.Add(b.Label);
- }
- }
- s.tok = b.tok;
- s.Label = b.Label;
- }
- }
-
- foreach (Block p in b.Predecessors) {
- GotoCmd pGtc = p.TransferCmd as GotoCmd;
- Contract.Assert(pGtc != null);
- foreach (Block s in successors) {
- if (!pGtc.labelTargets.Contains(s)) {
- pGtc.labelTargets.Add(s);
- pGtc.labelNames.Add(s.Label);
- }
- }
- }
- }
- }
-
- if (!startBlock.tok.IsValid && startBlock.Cmds.All(c => c is AssumeCmd)) {
- if (renameInfo[startBlock] != null) {
- startBlock.tok = renameInfo[startBlock].tok;
- startBlock.Label = renameInfo[startBlock].Label;
- }
- }
-
- }
-
- /// <summary>
- /// Remove the empty blocks reachable from the block.
- /// It changes the visiting state of the blocks, so that if you want to visit again the blocks, you have to reset them...
- /// </summary>
- static List<Block> RemoveEmptyBlocks(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<List<Block>>() != null);
-
- Contract.Assert(b.TraversingStatus == Block.VisitState.ToVisit);
- Block renameInfo;
- List<Block> retVal = removeEmptyBlocksWorker(b, true, out renameInfo);
- if (renameInfo != null && !b.tok.IsValid) {
- bool onlyAssumes = true;
- foreach (Cmd c in b.Cmds) {
- if (!(c is AssumeCmd)) {
- onlyAssumes = false;
- break;
- }
- }
- if (onlyAssumes) {
- b.tok = renameInfo.tok;
- b.Label = renameInfo.Label;
- }
- }
- return retVal;
- }
-
- /// <summary>
- /// For every not-yet-visited block n reachable from b, change n's successors to skip empty nodes.
- /// Return the *set* of blocks reachable from b without passing through a nonempty block.
- /// The target of any backedge is counted as a nonempty block.
- /// If renameInfoForStartBlock is non-null, it denotes an empty block with location information, and that
- /// information would be appropriate to display
- /// </summary>
- private static List<Block> removeEmptyBlocksWorker(Block b, bool startNode, out Block renameInfoForStartBlock)
- {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.ValueAtReturn(out renameInfoForStartBlock) == null || Contract.ValueAtReturn(out renameInfoForStartBlock).tok.IsValid);
- // ensures: b in result ==> renameInfoForStartBlock == null;
-
- renameInfoForStartBlock = null;
- List<Block> bs = new List<Block>();
- GotoCmd gtc = b.TransferCmd as GotoCmd;
-
- // b has no successors
- if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0)
- {
- if (b.Cmds.Count != 0){ // only empty blocks are removed...
- bs.Add(b);
- } else if (b.tok.IsValid) {
- renameInfoForStartBlock = b;
- }
- return bs;
- }
- else if (b.TraversingStatus == Block.VisitState.ToVisit) // if b has some successors and we have not seen it so far...
- {
- b.TraversingStatus = Block.VisitState.BeingVisited;
-
- // Before recursing down to successors, make a sobering observation:
- // If b has no commands and is not the start node, then it will see
- // extinction (because it will not be included in the "return setOfSuccessors"
- // statement below). In that case, if b has a location, then the location
- // information would be lost. Hence, make an attempt to save the location
- // by pushing the location onto b's successor. This can be done if (0) b has
- // exactly one successor, (1) that successor has no location of its own, and
- // (2) that successor has no other predecessors.
- if (b.Cmds.Count == 0 && !startNode) {
- // b is about to become extinct; try to save its name and location, if possible
- if (b.tok.IsValid && gtc.labelTargets.Count == 1) {
- Block succ = cce.NonNull(gtc.labelTargets[0]);
- if (!succ.tok.IsValid && succ.Predecessors.Count == 1) {
- succ.tok = b.tok;
- succ.Label = b.Label;
- }
- }
- }
-
- // recursively call this method on each successor
- // merge result into a *set* of blocks
- HashSet<Block> mergedSuccessors = new HashSet<Block>();
- int m = 0; // in the following loop, set renameInfoForStartBlock to the value that all recursive calls agree on, if possible; otherwise, null
- foreach (Block dest in gtc.labelTargets){Contract.Assert(dest != null);
- Block renameInfo;
- List<Block> ys = removeEmptyBlocksWorker(dest, false, out renameInfo);
- Contract.Assert(ys != null);
- if (m == 0) {
- renameInfoForStartBlock = renameInfo;
- } else if (renameInfoForStartBlock != renameInfo) {
- renameInfoForStartBlock = null;
- }
- foreach (Block successor in ys){
- if (!mergedSuccessors.Contains(successor))
- mergedSuccessors.Add(successor);
- }
- m++;
- }
- b.TraversingStatus = Block.VisitState.AlreadyVisited;
-
- List<Block> setOfSuccessors = new List<Block>();
- foreach (Block d in mergedSuccessors)
- setOfSuccessors.Add(d);
- if (b.Cmds.Count == 0 && !startNode) {
- // b is about to become extinct
- if (b.tok.IsValid) {
- renameInfoForStartBlock = b;
- }
- return setOfSuccessors;
- }
- // otherwise, update the list of successors of b to be the blocks in setOfSuccessors
- gtc.labelTargets = setOfSuccessors;
- gtc.labelNames = new List<String>();
- foreach (Block d in setOfSuccessors){
- Contract.Assert(d != null);
- gtc.labelNames.Add(d.Label);}
- if (!startNode) {
- renameInfoForStartBlock = null;
- }
- return new List<Block> { b };
- }
- else // b has some successors, but we are already visiting it, or we have already visited it...
- {
- return new List<Block> { b };
- }
- }
-
- static void DumpMap(Hashtable /*Variable->Expr*/ map) {
- Contract.Requires(map != null);
- foreach (DictionaryEntry de in map) {
- Variable v = (Variable)de.Key;
- Contract.Assert(v != null);
- Expr e = (Expr)de.Value;
- Contract.Assert(e != null);
- Console.Write(" ");
- v.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 0);
- Console.Write(" --> ");
- e.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false));
- Console.WriteLine();
- }
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.IO;
+using Microsoft.Boogie;
+using Microsoft.Boogie.GraphUtil;
+using System.Diagnostics.Contracts;
+using Microsoft.Basetypes;
+using Microsoft.Boogie.VCExprAST;
+
+namespace VC {
+ using Bpl = Microsoft.Boogie;
+ using System.Threading.Tasks;
+
+ public class VCGen : ConditionGeneration {
+ private const bool _print_time = false;
+ /// <summary>
+ /// Constructor. Initializes the theorem prover.
+ /// </summary>
+ [NotDelayed]
+ public VCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
+ : base(program, checkers)
+ {
+ Contract.Requires(program != null);
+ this.appendLogFile = appendLogFile;
+ this.logFilePath = logFilePath;
+ }
+
+ private static AssumeCmd AssertTurnedIntoAssume(AssertCmd assrt) {
+ Contract.Requires(assrt != null);
+ Contract.Ensures(Contract.Result<AssumeCmd>() != null);
+
+ Expr expr = assrt.Expr;
+ Contract.Assert(expr != null);
+ switch (Wlp.Subsumption(assrt)) {
+ case CommandLineOptions.SubsumptionOption.Never:
+ expr = Expr.True;
+ break;
+ case CommandLineOptions.SubsumptionOption.Always:
+ break;
+ case CommandLineOptions.SubsumptionOption.NotForQuantifiers:
+ if (expr is QuantifierExpr) {
+ expr = Expr.True;
+ }
+ break;
+ default:
+ Contract.Assert(false);
+ throw new cce.UnreachableException(); // unexpected case
+ }
+
+ return new AssumeCmd(assrt.tok, expr);
+ }
+
+ #region Soundness smoke tester
+ class SmokeTester {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(parent != null);
+ Contract.Invariant(impl != null);
+ Contract.Invariant(initial != null);
+ Contract.Invariant(cce.NonNullDictionaryAndValues(copies));
+ Contract.Invariant(cce.NonNull(visited));
+ Contract.Invariant(callback != null);
+ }
+
+ VCGen parent;
+ Implementation impl;
+ Block initial;
+ int id;
+ Dictionary<Block, Block> copies = new Dictionary<Block, Block>();
+ HashSet<Block> visited = new HashSet<Block>();
+ VerifierCallback callback;
+
+ internal SmokeTester(VCGen par, Implementation i, VerifierCallback callback) {
+ Contract.Requires(par != null);
+ Contract.Requires(i != null);
+ Contract.Requires(callback != null);
+ parent = par;
+ impl = i;
+ initial = i.Blocks[0];
+ this.callback = callback;
+ }
+
+ internal void Copy() {
+ CloneBlock(impl.Blocks[0]);
+ initial = GetCopiedBlocks()[0];
+ }
+
+ internal void Test() {
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+
+ DFS(initial);
+ }
+
+ void TopologicalSortImpl() {
+ Graph<Block> dag = new Graph<Block>();
+ dag.AddSource(cce.NonNull(impl.Blocks[0])); // there is always at least one node in the graph
+ foreach (Block b in impl.Blocks) {
+ GotoCmd gtc = b.TransferCmd as GotoCmd;
+ if (gtc != null) {
+ Contract.Assume(gtc.labelTargets != null);
+ foreach (Block dest in gtc.labelTargets) {
+ Contract.Assert(dest != null);
+ dag.AddEdge(b, dest);
+ }
+ }
+ }
+ impl.Blocks = new List<Block>();
+ foreach (Block b in dag.TopologicalSort()) {
+ Contract.Assert(b != null);
+ impl.Blocks.Add(b);
+ }
+ }
+
+ void Emit() {
+ TopologicalSortImpl();
+ EmitImpl(impl, false);
+ }
+
+ // this one copies forward
+ Block CloneBlock(Block b) {
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<Block>() != null);
+
+ Block fake_res;
+ if (copies.TryGetValue(b, out fake_res)) {
+ return cce.NonNull(fake_res);
+ }
+ Block res = new Block(b.tok, b.Label, new List<Cmd>(b.Cmds), null);
+ copies[b] = res;
+ if (b.TransferCmd is GotoCmd) {
+ foreach (Block ch in cce.NonNull((GotoCmd)b.TransferCmd).labelTargets) {
+ Contract.Assert(ch != null);
+ CloneBlock(ch);
+ }
+ }
+ foreach (Block p in b.Predecessors) {
+ Contract.Assert(p != null);
+ res.Predecessors.Add(CloneBlock(p));
+ }
+ return res;
+ }
+
+ // this one copies backwards
+ Block CopyBlock(Block b) {
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<Block>() != null);
+
+ Block fake_res;
+ if (copies.TryGetValue(b, out fake_res)) {
+ // fake_res should be Block! but the compiler fails
+ return cce.NonNull(fake_res);
+ }
+ Block res;
+ List<Cmd> seq = new List<Cmd>();
+ foreach (Cmd c in b.Cmds) {
+ Contract.Assert(c != null);
+ AssertCmd turn = c as AssertCmd;
+ if (!turnAssertIntoAssumes || turn == null) {
+ seq.Add(c);
+ } else {
+ seq.Add(AssertTurnedIntoAssume(turn));
+ }
+ }
+ res = new Block(b.tok, b.Label, seq, null);
+ copies[b] = res;
+ foreach (Block p in b.Predecessors) {
+ Contract.Assert(p != null);
+ res.Predecessors.Add(CopyBlock(p));
+ }
+ return res;
+ }
+
+ List<Block> GetCopiedBlocks() {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
+
+ // the order of nodes in res is random (except for the first one, being the entry)
+ List<Block> res = new List<Block>();
+ res.Add(copies[initial]);
+
+ foreach (KeyValuePair<Block, Block> kv in copies) {
+ Contract.Assert(kv.Key != null&&kv.Value!=null);
+ GotoCmd go = kv.Key.TransferCmd as GotoCmd;
+ ReturnCmd ret = kv.Key.TransferCmd as ReturnCmd;
+ if (kv.Key != initial) {
+ res.Add(kv.Value);
+ }
+ if (go != null) {
+ GotoCmd copy = new GotoCmd(go.tok, new List<String>(), new List<Block>());
+ kv.Value.TransferCmd = copy;
+ foreach (Block b in cce.NonNull(go.labelTargets)) {
+ Contract.Assert(b != null);
+ Block c;
+ if (copies.TryGetValue(b, out c)) {
+ copy.AddTarget(cce.NonNull(c));
+ }
+ }
+ } else if (ret != null) {
+ kv.Value.TransferCmd = ret;
+ } else {
+ Contract.Assume(false);
+ throw new cce.UnreachableException();
+ }
+ }
+
+ copies.Clear();
+
+ return res;
+ }
+
+ // check if e is true, false, !true, !false
+ // if so return true and the value of the expression in val
+ bool BooleanEval(Expr e, ref bool val) {
+ Contract.Requires(e != null);
+ LiteralExpr lit = e as LiteralExpr;
+ NAryExpr call = e as NAryExpr;
+
+ if (lit != null && lit.isBool) {
+ val = lit.asBool;
+ return true;
+ } else if (call != null &&
+ call.Fun is UnaryOperator &&
+ ((UnaryOperator)call.Fun).Op == UnaryOperator.Opcode.Not &&
+ BooleanEval(cce.NonNull(call.Args[0]), ref val)) {
+ val = !val;
+ return true;
+ }
+ // this is for the 0bv32 != 0bv32 generated by vcc
+ else if (call != null &&
+ call.Fun is BinaryOperator &&
+ ((BinaryOperator)call.Fun).Op == BinaryOperator.Opcode.Neq &&
+ call.Args[0] is LiteralExpr &&
+ cce.NonNull(call.Args[0]).Equals(call.Args[1])) {
+ val = false;
+ return true;
+ }
+
+ return false;
+ }
+
+ bool IsFalse(Expr e) {
+ Contract.Requires(e != null);
+ bool val = false;
+ return BooleanEval(e, ref val) && !val;
+ }
+
+ bool CheckUnreachable(Block cur, List<Cmd> seq)
+ {
+ Contract.Requires(cur != null);
+ Contract.Requires(seq != null);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ foreach (Cmd cmd in seq)
+ {
+ AssertCmd assrt = cmd as AssertCmd;
+ if (assrt != null && QKeyValue.FindBoolAttribute(assrt.Attributes, "PossiblyUnreachable"))
+ return false;
+ }
+
+ DateTime start = DateTime.UtcNow;
+ if (CommandLineOptions.Clo.Trace)
+ {
+ System.Console.Write(" soundness smoke test #{0} ... ", id);
+ }
+ callback.OnProgress("smoke", id, id, 0.0);
+
+ Token tok = new Token();
+ tok.val = "soundness smoke test assertion";
+ seq.Add(new AssertCmd(tok, Expr.False));
+ Block copy = CopyBlock(cur);
+ Contract.Assert(copy != null);
+ copy.Cmds = seq;
+ List<Block> backup = impl.Blocks;
+ Contract.Assert(backup != null);
+ impl.Blocks = GetCopiedBlocks();
+ copy.TransferCmd = new ReturnCmd(Token.NoToken);
+ if (CommandLineOptions.Clo.TraceVerify)
+ {
+ System.Console.WriteLine();
+ System.Console.WriteLine(" --- smoke #{0}, before passify", id);
+ Emit();
+ }
+ parent.CurrentLocalVariables = impl.LocVars;
+ ModelViewInfo mvInfo;
+ parent.PassifyImpl(impl, out mvInfo);
+ Dictionary<int, Absy> label2Absy;
+ Checker ch = parent.FindCheckerFor(CommandLineOptions.Clo.SmokeTimeout);
+ Contract.Assert(ch != null);
+
+ ProverInterface.Outcome outcome = ProverInterface.Outcome.Undetermined;
+ try
+ {
+ lock (ch)
+ {
+ var exprGen = ch.TheoremProver.Context.ExprGen;
+ VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
+
+ VCExpr vc = parent.GenerateVC(impl, controlFlowVariableExpr, out label2Absy, ch.TheoremProver.Context);
+ Contract.Assert(vc != null);
+
+ if (!CommandLineOptions.Clo.UseLabels)
+ {
+ VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
+ VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
+ vc = exprGen.Implies(eqExpr, vc);
+ }
+
+ impl.Blocks = backup;
+
+ if (CommandLineOptions.Clo.TraceVerify)
+ {
+ System.Console.WriteLine(" --- smoke #{0}, after passify", id);
+ Emit();
+ }
+
+ ch.BeginCheck(cce.NonNull(impl.Name + "_smoke" + id++), vc, new ErrorHandler(label2Absy, this.callback));
+ }
+
+ ch.ProverTask.Wait();
+
+ lock (ch)
+ {
+ outcome = ch.ReadOutcome();
+ }
+ }
+ finally
+ {
+ ch.GoBackToIdle();
+ }
+
+ parent.CurrentLocalVariables = null;
+
+ DateTime end = DateTime.UtcNow;
+ TimeSpan elapsed = end - start;
+ if (CommandLineOptions.Clo.Trace)
+ {
+ System.Console.WriteLine(" [{0} s] {1}", elapsed.TotalSeconds,
+ outcome == ProverInterface.Outcome.Valid ? "OOPS" :
+ "OK" + (outcome == ProverInterface.Outcome.Invalid ? "" : " (" + outcome + ")"));
+ }
+
+ if (outcome == ProverInterface.Outcome.Valid)
+ {
+ // copy it again, so we get the version with calls, assignments and such
+ copy = CopyBlock(cur);
+ copy.Cmds = seq;
+ impl.Blocks = GetCopiedBlocks();
+ TopologicalSortImpl();
+ callback.OnUnreachableCode(impl);
+ impl.Blocks = backup;
+ return true;
+ }
+ return false;
+ }
+
+ const bool turnAssertIntoAssumes = false;
+
+ void DFS(Block cur) {
+ Contract.Requires(cur != null);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ if (visited.Contains(cur))
+ return;
+ visited.Add(cur);
+
+ List<Cmd> seq = new List<Cmd>();
+ foreach (Cmd cmd_ in cur.Cmds) {
+ Cmd cmd = cmd_;
+ Contract.Assert(cmd != null);
+ AssertCmd assrt = cmd as AssertCmd;
+ AssumeCmd assm = cmd as AssumeCmd;
+ CallCmd call = cmd as CallCmd;
+
+ bool assumeFalse = false;
+
+ if (assrt != null) {
+ // we're not going any further
+ // it's clear the user expected unreachable code here
+ // it's not clear where did he expect it, maybe it would be right to insert
+ // a check just one command before
+ if (IsFalse(assrt.Expr))
+ return;
+
+#if TURN_ASSERT_INFO_ASSUMES
+ if (turnAssertIntoAssumes) {
+ cmd = AssertTurnedIntoAssume(assrt);
+ }
+#endif
+ } else if (assm != null) {
+ if (IsFalse(assm.Expr))
+ assumeFalse = true;
+ } else if (call != null) {
+ foreach (Ensures e in (cce.NonNull(call.Proc)).Ensures) {
+ Contract.Assert(e != null);
+ if (IsFalse(e.Condition))
+ assumeFalse = true;
+ }
+ }
+
+ if (assumeFalse) {
+ CheckUnreachable(cur, seq);
+ return;
+ }
+
+ seq.Add(cmd);
+ }
+
+
+ GotoCmd go = cur.TransferCmd as GotoCmd;
+ ReturnCmd ret = cur.TransferCmd as ReturnCmd;
+
+ Contract.Assume(!(go != null && go.labelTargets == null && go.labelNames != null && go.labelNames.Count > 0));
+
+ if (ret != null || (go != null && cce.NonNull(go.labelTargets).Count == 0)) {
+ // we end in return, so there will be no more places to check
+ CheckUnreachable(cur, seq);
+ } else if (go != null) {
+ bool needToCheck = true;
+ // if all of our children have more than one parent, then
+ // we're in the right place to check
+ foreach (Block target in cce.NonNull(go.labelTargets)) {
+ Contract.Assert(target != null);
+ if (target.Predecessors.Count == 1) {
+ needToCheck = false;
+ }
+ }
+ if (needToCheck) {
+ CheckUnreachable(cur, seq);
+ }
+ foreach (Block target in go.labelTargets) {
+ Contract.Assert(target != null);
+ DFS(target);
+ }
+ }
+ }
+
+ class ErrorHandler : ProverInterface.ErrorHandler {
+ Dictionary<int, Absy> label2Absy;
+ VerifierCallback callback;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(label2Absy != null);
+ Contract.Invariant(callback != null);
+ }
+
+
+ public ErrorHandler(Dictionary<int, Absy> label2Absy, VerifierCallback callback) {
+ Contract.Requires(label2Absy != null);
+ Contract.Requires(callback != null);
+ this.label2Absy = label2Absy;
+ this.callback = callback;
+ }
+
+ public override Absy Label2Absy(string label) {
+ //Contract.Requires(label != null);
+ Contract.Ensures(Contract.Result<Absy>() != null);
+
+ int id = int.Parse(label);
+ return cce.NonNull((Absy)label2Absy[id]);
+ }
+
+ public override void OnProverWarning(string msg) {
+ //Contract.Requires(msg != null);
+ this.callback.OnWarning(msg);
+ }
+ }
+ }
+
+
+ #endregion
+
+ #region Splitter
+ class Split {
+ class BlockStats {
+ public bool big_block;
+ public int id;
+ public double assertion_cost;
+ public double assumption_cost; // before multiplier
+ public double incomming_paths;
+ public List<Block>/*!>!*/ virtual_successors = new List<Block>();
+ public List<Block>/*!>!*/ virtual_predecesors = new List<Block>();
+ public HashSet<Block> reachable_blocks;
+ public readonly Block block;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(virtual_successors));
+ Contract.Invariant(cce.NonNullElements(virtual_predecesors));
+ Contract.Invariant(block != null);
+ }
+
+
+ public BlockStats(Block b, int i) {
+ Contract.Requires(b != null);
+ block = b;
+ assertion_cost = -1;
+ id = i;
+ }
+ }
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(blocks));
+ Contract.Invariant(cce.NonNullElements(big_blocks));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(stats));
+ Contract.Invariant(cce.NonNullElements(assumized_branches));
+ Contract.Invariant(gotoCmdOrigins != null);
+ Contract.Invariant(parent != null);
+ Contract.Invariant(impl != null);
+ Contract.Invariant(copies != null);
+ Contract.Invariant(cce.NonNull(protected_from_assert_to_assume));
+ Contract.Invariant(cce.NonNull(keep_at_all));
+ }
+
+
+ readonly List<Block> blocks;
+ readonly List<Block> big_blocks = new List<Block>();
+ readonly Dictionary<Block/*!*/, BlockStats/*!*/>/*!*/ stats = new Dictionary<Block/*!*/, BlockStats/*!*/>();
+ readonly int id;
+ static int current_id = -1;
+ Block split_block;
+ bool assert_to_assume;
+ List<Block/*!*/>/*!*/ assumized_branches = new List<Block/*!*/>();
+
+ double score;
+ bool score_computed;
+ double total_cost;
+ int assertion_count;
+ double assertion_cost; // without multiplication by paths
+ Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins;
+ readonly public VCGen/*!*/ parent;
+ Implementation/*!*/ impl;
+
+ Dictionary<Block/*!*/, Block/*!*/>/*!*/ copies = new Dictionary<Block/*!*/, Block/*!*/>();
+ bool doing_slice;
+ double slice_initial_limit;
+ double slice_limit;
+ bool slice_pos;
+ HashSet<Block/*!*/>/*!*/ protected_from_assert_to_assume = new HashSet<Block/*!*/>();
+ HashSet<Block/*!*/>/*!*/ keep_at_all = new HashSet<Block/*!*/>();
+
+ // async interface
+ private Checker checker;
+ private int splitNo;
+ internal ErrorReporter reporter;
+
+ public Split(List<Block/*!*/>/*!*/ blocks, Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins, VCGen/*!*/ par, Implementation/*!*/ impl) {
+ Contract.Requires(cce.NonNullElements(blocks));
+ Contract.Requires(gotoCmdOrigins != null);
+ Contract.Requires(par != null);
+ Contract.Requires(impl != null);
+ this.blocks = blocks;
+ this.gotoCmdOrigins = gotoCmdOrigins;
+ this.parent = par;
+ this.impl = impl;
+ this.id = Interlocked.Increment(ref current_id);
+ }
+
+ public double Cost {
+ get {
+ ComputeBestSplit();
+ return total_cost;
+ }
+ }
+
+ public bool LastChance {
+ get {
+ ComputeBestSplit();
+ return assertion_count == 1 && score < 0;
+ }
+ }
+
+ public string Stats {
+ get {
+ ComputeBestSplit();
+ return string.Format("(cost:{0:0}/{1:0}{2})", total_cost, assertion_cost, LastChance ? " last" : "");
+ }
+ }
+
+ public void DumpDot(int no) {
+ using (System.IO.StreamWriter sw = System.IO.File.CreateText(string.Format("split.{0}.dot", no))) {
+ sw.WriteLine("digraph G {");
+
+ ComputeBestSplit();
+ List<Block> saved = assumized_branches;
+ Contract.Assert(saved != null);
+ assumized_branches = new List<Block>();
+ DoComputeScore(false);
+ assumized_branches = saved;
+
+ foreach (Block b in big_blocks) {
+ Contract.Assert(b != null);
+ BlockStats s = GetBlockStats(b);
+ foreach (Block t in s.virtual_successors) {
+ Contract.Assert(t != null);
+ sw.WriteLine("n{0} -> n{1};", s.id, GetBlockStats(t).id);
+ }
+ sw.WriteLine("n{0} [label=\"{1}:\\n({2:0.0}+{3:0.0})*{4:0.0}\"{5}];",
+ s.id, b.Label,
+ s.assertion_cost, s.assumption_cost, s.incomming_paths,
+ s.assertion_cost > 0 ? ",shape=box" : "");
+
+ }
+ sw.WriteLine("}");
+ sw.Close();
+ }
+
+ string filename = string.Format("split.{0}.bpl", no);
+ using (System.IO.StreamWriter sw = System.IO.File.CreateText(filename)) {
+ int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured;
+ CommandLineOptions.Clo.PrintUnstructured = 2; // print only the unstructured program
+ bool oldPrintDesugaringSetting = CommandLineOptions.Clo.PrintDesugarings;
+ CommandLineOptions.Clo.PrintDesugarings = false;
+ List<Block> backup = impl.Blocks;
+ Contract.Assert(backup != null);
+ impl.Blocks = blocks;
+ impl.Emit(new TokenTextWriter(filename, sw, /*setTokens=*/ false, /*pretty=*/ false), 0);
+ impl.Blocks = backup;
+ CommandLineOptions.Clo.PrintDesugarings = oldPrintDesugaringSetting;
+ CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured;
+ }
+ }
+
+ int bsid;
+ BlockStats GetBlockStats(Block b) {
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<BlockStats>() != null);
+
+ BlockStats s;
+ if (!stats.TryGetValue(b, out s)) {
+ s = new BlockStats(b, bsid++);
+ stats[b] = s;
+ }
+ return cce.NonNull(s);
+ }
+
+ double AssertionCost(PredicateCmd c) {
+ return 1.0;
+ }
+
+ void CountAssertions(Block b) {
+ Contract.Requires(b != null);
+ BlockStats s = GetBlockStats(b);
+ if (s.assertion_cost >= 0)
+ return; // already done
+ s.big_block = true;
+ s.assertion_cost = 0;
+ s.assumption_cost = 0;
+ foreach (Cmd c in b.Cmds) {
+ if (c is AssertCmd) {
+ double cost = AssertionCost((AssertCmd)c);
+ s.assertion_cost += cost;
+ assertion_count++;
+ assertion_cost += cost;
+ } else if (c is AssumeCmd) {
+ s.assumption_cost += AssertionCost((AssumeCmd)c);
+ }
+ }
+ foreach (Block c in Exits(b)) {
+ Contract.Assert(c != null);
+ s.virtual_successors.Add(c);
+ }
+ if (s.virtual_successors.Count == 1) {
+ Block next = s.virtual_successors[0];
+ BlockStats se = GetBlockStats(next);
+ CountAssertions(next);
+ if (next.Predecessors.Count > 1 || se.virtual_successors.Count != 1)
+ return;
+ s.virtual_successors[0] = se.virtual_successors[0];
+ s.assertion_cost += se.assertion_cost;
+ s.assumption_cost += se.assumption_cost;
+ se.big_block = false;
+ }
+ }
+
+ HashSet<Block/*!*/>/*!*/ ComputeReachableNodes(Block/*!*/ b) {
+ Contract.Requires(b != null);
+ Contract.Ensures(cce.NonNull(Contract.Result<HashSet<Block/*!*/>>()));
+ BlockStats s = GetBlockStats(b);
+ if (s.reachable_blocks != null) {
+ return s.reachable_blocks;
+ }
+ HashSet<Block/*!*/> blocks = new HashSet<Block/*!*/>();
+ s.reachable_blocks = blocks;
+ blocks.Add(b);
+ foreach (Block/*!*/ succ in Exits(b)) {
+ Contract.Assert(succ != null);
+ foreach (Block r in ComputeReachableNodes(succ)) {
+ Contract.Assert(r != null);
+ blocks.Add(r);
+ }
+ }
+ return blocks;
+ }
+
+ double ProverCost(double vc_cost) {
+ return vc_cost * vc_cost;
+ }
+
+ void ComputeBestSplit() {
+ if (score_computed)
+ return;
+ score_computed = true;
+
+ assertion_count = 0;
+
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ CountAssertions(b);
+ }
+
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ BlockStats bs = GetBlockStats(b);
+ if (bs.big_block) {
+ big_blocks.Add(b);
+ foreach (Block ch in bs.virtual_successors) {
+ Contract.Assert(ch != null);
+ BlockStats chs = GetBlockStats(ch);
+ if (!chs.big_block) {
+ Console.WriteLine("non-big {0} accessed from {1}", ch, b);
+ DumpDot(-1);
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ }
+ chs.virtual_predecesors.Add(b);
+ }
+ }
+ }
+
+ assumized_branches.Clear();
+ total_cost = ProverCost(DoComputeScore(false));
+
+ score = double.PositiveInfinity;
+ Block best_split = null;
+ List<Block> saved_branches = new List<Block>();
+
+ foreach (Block b in big_blocks) {
+ Contract.Assert(b != null);
+ GotoCmd gt = b.TransferCmd as GotoCmd;
+ if (gt == null)
+ continue;
+ List<Block> targ = cce.NonNull(gt.labelTargets);
+ if (targ.Count < 2)
+ continue;
+ // caution, we only consider two first exits
+
+ double left0, right0, left1, right1;
+ split_block = b;
+
+ assumized_branches.Clear();
+ assumized_branches.Add(cce.NonNull(targ[0]));
+ left0 = DoComputeScore(true);
+ right0 = DoComputeScore(false);
+
+ assumized_branches.Clear();
+ for (int idx = 1; idx < targ.Count; idx++) {
+ assumized_branches.Add(cce.NonNull(targ[idx]));
+ }
+ left1 = DoComputeScore(true);
+ right1 = DoComputeScore(false);
+
+ double current_score = ProverCost(left1) + ProverCost(right1);
+ double other_score = ProverCost(left0) + ProverCost(right0);
+
+ if (other_score < current_score) {
+ current_score = other_score;
+ assumized_branches.Clear();
+ assumized_branches.Add(cce.NonNull(targ[0]));
+ }
+
+ if (current_score < score) {
+ score = current_score;
+ best_split = split_block;
+ saved_branches.Clear();
+ saved_branches.AddRange(assumized_branches);
+ }
+ }
+
+ if (CommandLineOptions.Clo.VcsPathSplitMult * score > total_cost) {
+ split_block = null;
+ score = -1;
+ } else {
+ assumized_branches = saved_branches;
+ split_block = best_split;
+ }
+ }
+
+ void UpdateIncommingPaths(BlockStats s) {
+ Contract.Requires(s != null);
+ if (s.incomming_paths < 0.0) {
+ int count = 0;
+ s.incomming_paths = 0.0;
+ if (!keep_at_all.Contains(s.block))
+ return;
+ foreach (Block b in s.virtual_predecesors) {
+ Contract.Assert(b != null);
+ BlockStats ch = GetBlockStats(b);
+ Contract.Assert(ch != null);
+ UpdateIncommingPaths(ch);
+ if (ch.incomming_paths > 0.0) {
+ s.incomming_paths += ch.incomming_paths;
+ count++;
+ }
+ }
+ if (count > 1) {
+ s.incomming_paths *= CommandLineOptions.Clo.VcsPathJoinMult;
+ }
+ }
+ }
+
+ void ComputeBlockSetsHelper(Block b, bool allow_small) {
+ Contract.Requires(b != null);
+ if (keep_at_all.Contains(b))
+ return;
+ keep_at_all.Add(b);
+
+ if (allow_small) {
+ foreach (Block ch in Exits(b)) {
+ Contract.Assert(ch != null);
+ if (b == split_block && assumized_branches.Contains(ch))
+ continue;
+ ComputeBlockSetsHelper(ch, allow_small);
+ }
+ } else {
+ foreach (Block ch in GetBlockStats(b).virtual_successors) {
+ Contract.Assert(ch != null);
+ if (b == split_block && assumized_branches.Contains(ch))
+ continue;
+ ComputeBlockSetsHelper(ch, allow_small);
+ }
+ }
+ }
+
+ void ComputeBlockSets(bool allow_small) {
+ protected_from_assert_to_assume.Clear();
+ keep_at_all.Clear();
+
+ Debug.Assert(split_block == null || GetBlockStats(split_block).big_block);
+ Debug.Assert(GetBlockStats(blocks[0]).big_block);
+
+ if (assert_to_assume) {
+ foreach (Block b in allow_small ? blocks : big_blocks) {
+ Contract.Assert(b != null);
+ if (ComputeReachableNodes(b).Contains(cce.NonNull(split_block))) {
+ keep_at_all.Add(b);
+ }
+ }
+
+ foreach (Block b in assumized_branches) {
+ Contract.Assert(b != null);
+ foreach (Block r in ComputeReachableNodes(b)) {
+ Contract.Assert(r != null);
+ if (allow_small || GetBlockStats(r).big_block) {
+ keep_at_all.Add(r);
+ protected_from_assert_to_assume.Add(r);
+ }
+ }
+ }
+ } else {
+ ComputeBlockSetsHelper(blocks[0], allow_small);
+ }
+ }
+
+ bool ShouldAssumize(Block b) {
+ Contract.Requires(b != null);
+ return assert_to_assume && !protected_from_assert_to_assume.Contains(b);
+ }
+
+ double DoComputeScore(bool aa) {
+ assert_to_assume = aa;
+ ComputeBlockSets(false);
+
+ foreach (Block b in big_blocks) {
+ Contract.Assert(b != null);
+ GetBlockStats(b).incomming_paths = -1.0;
+ }
+
+ GetBlockStats(blocks[0]).incomming_paths = 1.0;
+
+ double cost = 0.0;
+ foreach (Block b in big_blocks) {
+ Contract.Assert(b != null);
+ if (keep_at_all.Contains(b)) {
+ BlockStats s = GetBlockStats(b);
+ UpdateIncommingPaths(s);
+ double local = s.assertion_cost;
+ if (ShouldAssumize(b)) {
+ local = (s.assertion_cost + s.assumption_cost) * CommandLineOptions.Clo.VcsAssumeMult;
+ } else {
+ local = s.assumption_cost * CommandLineOptions.Clo.VcsAssumeMult + s.assertion_cost;
+ }
+ local = local + local * s.incomming_paths * CommandLineOptions.Clo.VcsPathCostMult;
+ cost += local;
+ }
+ }
+
+ return cost;
+ }
+
+ List<Cmd> SliceCmds(Block b) {
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+
+ List<Cmd> seq = b.Cmds;
+ Contract.Assert(seq != null);
+ if (!doing_slice && !ShouldAssumize(b))
+ return seq;
+ List<Cmd> res = new List<Cmd>();
+ foreach (Cmd c in seq) {
+ Contract.Assert(c != null);
+ AssertCmd a = c as AssertCmd;
+ Cmd the_new = c;
+ bool swap = false;
+ if (a != null) {
+ if (doing_slice) {
+ double cost = AssertionCost(a);
+ bool first = (slice_limit - cost) >= 0 || slice_initial_limit == slice_limit;
+ slice_limit -= cost;
+ swap = slice_pos == first;
+ } else if (assert_to_assume) {
+ swap = true;
+ } else {
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ }
+
+ if (swap) {
+ the_new = AssertTurnedIntoAssume(a);
+ }
+ }
+ res.Add(the_new);
+ }
+ return res;
+ }
+
+ Block CloneBlock(Block b) {
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<Block>() != null);
+
+ Block res;
+ if (copies.TryGetValue(b, out res)) {
+ return cce.NonNull(res);
+ }
+ res = new Block(b.tok, b.Label, SliceCmds(b), b.TransferCmd);
+ GotoCmd gt = b.TransferCmd as GotoCmd;
+ copies[b] = res;
+ if (gt != null) {
+ GotoCmd newGoto = new GotoCmd(gt.tok, new List<String>(), new List<Block>());
+ res.TransferCmd = newGoto;
+ int pos = 0;
+ foreach (Block ch in cce.NonNull(gt.labelTargets)) {
+ Contract.Assert(ch != null);
+ Contract.Assert(doing_slice ||
+ (assert_to_assume || (keep_at_all.Contains(ch) || assumized_branches.Contains(ch))));
+ if (doing_slice ||
+ ((b != split_block || assumized_branches.Contains(ch) == assert_to_assume) &&
+ keep_at_all.Contains(ch))) {
+ newGoto.AddTarget(CloneBlock(ch));
+ }
+ pos++;
+ }
+ }
+ return res;
+ }
+
+ Split DoSplit() {
+ Contract.Ensures(Contract.Result<Split>() != null);
+
+ copies.Clear();
+ CloneBlock(blocks[0]);
+ List<Block> newBlocks = new List<Block>();
+ Dictionary<TransferCmd, ReturnCmd> newGotoCmdOrigins = new Dictionary<TransferCmd, ReturnCmd>();
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ Block tmp;
+ if (copies.TryGetValue(b, out tmp)) {
+ newBlocks.Add(cce.NonNull(tmp));
+ if (gotoCmdOrigins.ContainsKey(b.TransferCmd)) {
+ newGotoCmdOrigins[tmp.TransferCmd] = gotoCmdOrigins[b.TransferCmd];
+ }
+
+ foreach (Block p in b.Predecessors) {
+ Contract.Assert(p != null);
+ Block tmp2;
+ if (copies.TryGetValue(p, out tmp2)) {
+ tmp.Predecessors.Add(tmp2);
+ }
+ }
+ }
+ }
+
+ return new Split(newBlocks, newGotoCmdOrigins, parent, impl);
+ }
+
+ Split SplitAt(int idx) {
+ Contract.Ensures(Contract.Result<Split>() != null);
+
+ assert_to_assume = idx == 0;
+ doing_slice = false;
+ ComputeBlockSets(true);
+
+ return DoSplit();
+ }
+
+ Split SliceAsserts(double limit, bool pos) {
+ Contract.Ensures(Contract.Result<Split>() != null);
+
+ slice_pos = pos;
+ slice_limit = limit;
+ slice_initial_limit = limit;
+ doing_slice = true;
+ Split r = DoSplit();
+ /*
+ Console.WriteLine("split {0} / {1} -->", limit, pos);
+ List<Block!> tmp = impl.Blocks;
+ impl.Blocks = r.blocks;
+ EmitImpl(impl, false);
+ impl.Blocks = tmp;
+ */
+
+ return r;
+ }
+
+ void Print() {
+ List<Block> tmp = impl.Blocks;
+ Contract.Assert(tmp != null);
+ impl.Blocks = blocks;
+ EmitImpl(impl, false);
+ impl.Blocks = tmp;
+ }
+
+ public Counterexample ToCounterexample(ProverContext context) {
+ Contract.Requires(context != null);
+ Contract.Ensures(Contract.Result<Counterexample>() != null);
+
+ List<Block> trace = new List<Block>();
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ trace.Add(b);
+ }
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ foreach (Cmd c in b.Cmds) {
+ Contract.Assert(c != null);
+ if (c is AssertCmd) {
+ return AssertCmdToCounterexample((AssertCmd)c, cce.NonNull(b.TransferCmd), trace, null, null, context);
+ }
+ }
+ }
+ Contract.Assume(false);
+ throw new cce.UnreachableException();
+ }
+
+ /// <summary>
+ /// Starting from the 0-index "split_here" annotation in begin, verifies until it reaches a subsequent "split_here" annotation
+ /// Returns a list of blocks where all code not verified has asserts converted into assumes
+ /// </summary>
+ /// <param name="blocks">Implementation's collection of blocks</param>
+ /// <param name="begin">Block containing the first split_here from which to start verifying</param>
+ /// <param name="begin_split_id">0-based ID of the "split_here" annotation within begin at which to start verifying</param>
+ /// <param name="blockInternalSplit">True if the entire split is contained within block begin</param>
+ /// <param name="endPoints">Set of all blocks containing a "split_here" annotation</param>
+ /// <returns></returns>
+ // Note: Current implementation may over report errors.
+ // For example, if the control flow graph is a diamond (e.g., A -> B, C, B->D, C->D),
+ // and there is a split in B and an error in D, then D will be verified twice and hence report the error twice.
+ // Best solution may be to memoize blocks that have been fully verified and be sure not to verify them again
+ private static List<Block> DoManualSplit(List<Block> blocks, Block begin, int begin_split_id, bool blockInternalSplit, IEnumerable<Block> endPoints) {
+ // Compute the set of blocks reachable from begin but not included in endPoints. These will be verified in their entirety.
+ var blocksToVerifyEntirely = new HashSet<Block>();
+ var reachableEndPoints = new HashSet<Block>(); // Reachable end points will be verified up to their first split point
+ var todo = new Stack<Block>();
+ todo.Push(begin);
+ while (todo.Count > 0) {
+ var currentBlock = todo.Pop();
+ if (blocksToVerifyEntirely.Contains(currentBlock)) continue;
+ blocksToVerifyEntirely.Add(currentBlock);
+ var exit = currentBlock.TransferCmd as GotoCmd;
+ if (exit != null)
+ foreach (Block targetBlock in exit.labelTargets) {
+ if (!endPoints.Contains(targetBlock)) {
+ todo.Push(targetBlock);
+ } else {
+ reachableEndPoints.Add(targetBlock);
+ }
+ }
+
+ }
+ blocksToVerifyEntirely.Remove(begin);
+
+ // Convert assumes to asserts in "unreachable" blocks, including portions of blocks containing "split_here"
+ var newBlocks = new List<Block>(blocks.Count()); // Copies of the original blocks
+ var duplicator = new Duplicator();
+ var oldToNewBlockMap = new Dictionary<Block, Block>(blocks.Count()); // Maps original blocks to their new copies in newBlocks
+
+ foreach (var currentBlock in blocks) {
+ var newBlock = (Block)duplicator.VisitBlock(currentBlock);
+ oldToNewBlockMap[currentBlock] = newBlock;
+ newBlocks.Add(newBlock);
+
+ if (!blockInternalSplit && blocksToVerifyEntirely.Contains(currentBlock)) continue; // All reachable blocks must be checked in their entirety, so don't change anything
+ // Otherwise, we only verify a portion of the current block, so we'll need to look at each of its commands
+
+ // !verify -> convert assert to assume
+ var verify = (currentBlock == begin && begin_split_id == -1) // -1 tells us to start verifying from the very beginning (i.e., there is no split in the begin block)
+ || (reachableEndPoints.Contains(currentBlock) // This endpoint is reachable from begin, so we verify until we hit the first split point
+ && !blockInternalSplit); // Don't bother verifying if all of the splitting is within the begin block
+ var newCmds = new List<Cmd>();
+ var split_here_count = 0;
+
+ foreach (Cmd c in currentBlock.Cmds) {
+ var p = c as PredicateCmd;
+ if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "split_here")) {
+ if (currentBlock == begin) { // Verify everything between the begin_split_id we were given and the next split
+ if (split_here_count == begin_split_id) {
+ verify = true;
+ } else if (split_here_count == begin_split_id + 1) {
+ verify = false;
+ }
+ } else { // We're in an endPoint so we stop verifying as soon as we hit a "split_here"
+ verify = false;
+ }
+ split_here_count++;
+ }
+
+ var asrt = c as AssertCmd;
+ if (verify || asrt == null)
+ newCmds.Add(c);
+ else
+ newCmds.Add(AssertTurnedIntoAssume(asrt));
+ }
+
+ newBlock.Cmds = newCmds;
+ }
+
+ // Patch the edges between the new blocks
+ foreach (var oldBlock in blocks) {
+ if (oldBlock.TransferCmd is ReturnCmd) { continue; }
+ var gotoCmd = (GotoCmd)oldBlock.TransferCmd;
+ var newLabelTargets = new List<Block>(gotoCmd.labelTargets.Count());
+ var newLabelNames = new List<string>(gotoCmd.labelTargets.Count());
+ foreach (var target in gotoCmd.labelTargets) {
+ newLabelTargets.Add(oldToNewBlockMap[target]);
+ newLabelNames.Add(oldToNewBlockMap[target].Label);
+ }
+ oldToNewBlockMap[oldBlock].TransferCmd = new GotoCmd(gotoCmd.tok, newLabelNames, newLabelTargets);
+ }
+
+ return newBlocks;
+ }
+
+ public static List<Split/*!*/> FindManualSplits(Implementation/*!*/ impl, Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins, VCGen/*!*/ par) {
+ Contract.Requires(impl != null);
+ Contract.Ensures(Contract.Result<List<Split>>() == null || cce.NonNullElements(Contract.Result<List<Split>>()));
+
+ var splitPoints = new Dictionary<Block,int>();
+ foreach (var b in impl.Blocks) {
+ foreach (Cmd c in b.Cmds) {
+ var p = c as PredicateCmd;
+ if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "split_here")) {
+ int count;
+ splitPoints.TryGetValue(b, out count);
+ splitPoints[b] = count + 1;
+ }
+ }
+ }
+
+ if (splitPoints.Count() == 0) { // No manual split points here
+ return null;
+ }
+
+ List<Split> splits = new List<Split>();
+ Block entryPoint = impl.Blocks[0];
+ var newEntryBlocks = DoManualSplit(impl.Blocks, entryPoint, -1, splitPoints.Keys.Contains(entryPoint), splitPoints.Keys);
+ splits.Add(new Split(newEntryBlocks, gotoCmdOrigins, par, impl)); // REVIEW: Does gotoCmdOrigins need to be changed at all?
+
+ foreach (KeyValuePair<Block,int> pair in splitPoints) {
+ for (int i = 0; i < pair.Value; i++) {
+ bool blockInternalSplit = i < pair.Value - 1; // There's at least one more split, after this one, in the current block
+ var newBlocks = DoManualSplit(impl.Blocks, pair.Key, i, blockInternalSplit, splitPoints.Keys);
+ Split s = new Split(newBlocks, gotoCmdOrigins, par, impl); // REVIEW: Does gotoCmdOrigins need to be changed at all?
+ splits.Add(s);
+ }
+ }
+
+ return splits;
+ }
+
+ public static List<Split/*!*/>/*!*/ DoSplit(Split initial, double max_cost, int max) {
+ Contract.Requires(initial != null);
+ Contract.Ensures(cce.NonNullElements(Contract.Result<List<Split>>()));
+
+ List<Split> res = new List<Split>();
+ res.Add(initial);
+
+ while (res.Count < max) {
+ Split best = null;
+ int best_idx = 0, pos = 0;
+ foreach (Split s in res) {
+ Contract.Assert(s != null);
+ s.ComputeBestSplit(); // TODO check total_cost first
+ if (s.total_cost > max_cost &&
+ (best == null || best.total_cost < s.total_cost) &&
+ (s.assertion_count > 1 || s.split_block != null)) {
+ best = s;
+ best_idx = pos;
+ }
+ pos++;
+ }
+
+ if (best == null)
+ break; // no split found
+
+ Split s0, s1;
+
+ bool split_stats = CommandLineOptions.Clo.TraceVerify;
+
+ if (split_stats) {
+ Console.WriteLine("{0} {1} -->", best.split_block == null ? "SLICE" : ("SPLIT@" + best.split_block.Label), best.Stats);
+ if (best.split_block != null) {
+ GotoCmd g = best.split_block.TransferCmd as GotoCmd;
+ if (g != null) {
+ Console.Write(" exits: ");
+ foreach (Block b in cce.NonNull(g.labelTargets)) {
+ Contract.Assert(b != null);
+ Console.Write("{0} ", b.Label);
+ }
+ Console.WriteLine("");
+ Console.Write(" assumized: ");
+ foreach (Block b in best.assumized_branches) {
+ Contract.Assert(b != null);
+ Console.Write("{0} ", b.Label);
+ }
+ Console.WriteLine("");
+ }
+ }
+ }
+
+ if (best.split_block != null) {
+ s0 = best.SplitAt(0);
+ s1 = best.SplitAt(1);
+ } else {
+ best.split_block = null;
+ s0 = best.SliceAsserts(best.assertion_cost / 2, true);
+ s1 = best.SliceAsserts(best.assertion_cost / 2, false);
+ }
+
+ if (true) {
+ List<Block> ss = new List<Block>();
+ ss.Add(s0.blocks[0]);
+ ss.Add(s1.blocks[0]);
+ try {
+ best.SoundnessCheck(new HashSet<List<Block>>(new BlockListComparer()), best.blocks[0], ss);
+ } catch (System.Exception e) {
+ Console.WriteLine(e);
+ best.DumpDot(-1);
+ s0.DumpDot(-2);
+ s1.DumpDot(-3);
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ }
+ }
+
+ if (split_stats) {
+ s0.ComputeBestSplit();
+ s1.ComputeBestSplit();
+ Console.WriteLine(" --> {0}", s0.Stats);
+ Console.WriteLine(" --> {0}", s1.Stats);
+ }
+
+ if (CommandLineOptions.Clo.TraceVerify) {
+ best.Print();
+ }
+
+ res[best_idx] = s0;
+ res.Add(s1);
+ }
+
+ return res;
+ }
+
+ class BlockListComparer : IEqualityComparer<List<Block>>
+ {
+ public bool Equals(List<Block> x, List<Block> y)
+ {
+ return x == y || x.SequenceEqual(y);
+ }
+
+ public int GetHashCode(List<Block> obj)
+ {
+ int h = 0;
+ Contract.Assume(obj != null);
+ foreach (var b in obj)
+ {
+ if (b != null)
+ {
+ h += b.GetHashCode();
+ }
+ }
+ return h;
+ }
+ }
+
+ public Checker Checker {
+ get {
+ Contract.Ensures(Contract.Result<Checker>() != null);
+
+ Contract.Assert(checker != null);
+ return checker;
+ }
+ }
+
+ public Task ProverTask {
+ get {
+ Contract.Assert(checker != null);
+ return checker.ProverTask;
+ }
+ }
+
+ public void ReadOutcome(ref Outcome cur_outcome, out bool prover_failed) {
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ ProverInterface.Outcome outcome = cce.NonNull(checker).ReadOutcome();
+
+ if (CommandLineOptions.Clo.Trace && splitNo >= 0) {
+ System.Console.WriteLine(" --> split #{0} done, [{1} s] {2}", splitNo, checker.ProverRunTime.TotalSeconds, outcome);
+ }
+
+ if (CommandLineOptions.Clo.VcsDumpSplits) {
+ DumpDot(splitNo);
+ }
+
+ prover_failed = false;
+
+ switch (outcome) {
+ case ProverInterface.Outcome.Valid:
+ return;
+ case ProverInterface.Outcome.Invalid:
+ cur_outcome = Outcome.Errors;
+ return;
+ case ProverInterface.Outcome.OutOfMemory:
+ prover_failed = true;
+ if (cur_outcome != Outcome.Errors && cur_outcome != Outcome.Inconclusive)
+ cur_outcome = Outcome.OutOfMemory;
+ return;
+ case ProverInterface.Outcome.TimeOut:
+ prover_failed = true;
+ if (cur_outcome != Outcome.Errors && cur_outcome != Outcome.Inconclusive)
+ cur_outcome = Outcome.TimedOut;
+ return;
+ case ProverInterface.Outcome.Undetermined:
+ if (cur_outcome != Outcome.Errors)
+ cur_outcome = Outcome.Inconclusive;
+ return;
+ default:
+ Contract.Assert(false);
+ throw new cce.UnreachableException();
+ }
+ }
+
+ /// <summary>
+ /// As a side effect, updates "this.parent.CumulativeAssertionCount".
+ /// </summary>
+ public void BeginCheck(Checker checker, VerifierCallback callback, ModelViewInfo mvInfo, int no, int timeout)
+ {
+ Contract.Requires(checker != null);
+ Contract.Requires(callback != null);
+
+ splitNo = no;
+
+ impl.Blocks = blocks;
+
+ this.checker = checker;
+
+ Dictionary<int, Absy> label2absy = new Dictionary<int, Absy>();
+
+ ProverContext ctx = checker.TheoremProver.Context;
+ Boogie2VCExprTranslator bet = ctx.BoogieExprTranslator;
+ CodeExprConversionClosure cc = new CodeExprConversionClosure(label2absy, ctx);
+ bet.SetCodeExprConverter(cc.CodeExprToVerificationCondition);
+
+ var exprGen = ctx.ExprGen;
+ VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
+
+ VCExpr vc = parent.GenerateVCAux(impl, controlFlowVariableExpr, label2absy, checker.TheoremProver.Context);
+ Contract.Assert(vc != null);
+
+ if (!CommandLineOptions.Clo.UseLabels)
+ {
+ VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
+ VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
+ vc = exprGen.Implies(eqExpr, vc);
+ }
+
+ if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Local)
+ {
+ reporter = new ErrorReporterLocal(gotoCmdOrigins, label2absy, impl.Blocks, parent.incarnationOriginMap, callback, mvInfo, cce.NonNull(this.Checker.TheoremProver.Context), parent.program);
+ }
+ else
+ {
+ reporter = new ErrorReporter(gotoCmdOrigins, label2absy, impl.Blocks, parent.incarnationOriginMap, callback, mvInfo, this.Checker.TheoremProver.Context, parent.program);
+ }
+
+ if (CommandLineOptions.Clo.TraceVerify && no >= 0)
+ {
+ Console.WriteLine("-- after split #{0}", no);
+ Print();
+ }
+
+ string desc = cce.NonNull(impl.Name);
+ if (no >= 0)
+ desc += "_split" + no;
+ checker.BeginCheck(desc, vc, reporter);
+ }
+
+ private void SoundnessCheck(HashSet<List<Block>/*!*/>/*!*/ cache, Block/*!*/ orig, List<Block/*!*/>/*!*/ copies) {
+ Contract.Requires(cce.NonNull(cache));
+ Contract.Requires(orig != null);
+ Contract.Requires(copies != null);
+ {
+ var t = new List<Block> { orig };
+ foreach (Block b in copies) {
+ Contract.Assert(b != null);
+ t.Add(b);
+ }
+ if (cache.Contains(t)) {
+ return;
+ }
+ cache.Add(t);
+ }
+
+ for (int i = 0; i < orig.Cmds.Count; ++i) {
+ Cmd cmd = orig.Cmds[i];
+ if (cmd is AssertCmd) {
+ int found = 0;
+ foreach (Block c in copies) {
+ Contract.Assert(c != null);
+ if (c.Cmds[i] == cmd) {
+ found++;
+ }
+ }
+ if (found == 0) {
+ throw new System.Exception(string.Format("missing assertion: {0}({1})", cmd.tok.filename, cmd.tok.line));
+ }
+ }
+ }
+
+ foreach (Block exit in Exits(orig)) {
+ Contract.Assert(exit != null);
+ List<Block> newcopies = new List<Block>();
+ foreach (Block c in copies) {
+ foreach (Block cexit in Exits(c)) {
+ Contract.Assert(cexit != null);
+ if (cexit.Label == exit.Label) {
+ newcopies.Add(cexit);
+ }
+ }
+ }
+ if (newcopies.Count == 0) {
+ throw new System.Exception("missing exit " + exit.Label);
+ }
+ SoundnessCheck(cache, exit, newcopies);
+ }
+ }
+ }
+ #endregion
+
+
+ public class CodeExprConversionClosure
+ {
+ Dictionary<int, Absy> label2absy;
+ ProverContext ctx;
+ public CodeExprConversionClosure(Dictionary<int, Absy> label2absy, ProverContext ctx)
+ {
+ this.label2absy = label2absy;
+ this.ctx = ctx;
+ }
+
+ public VCExpr CodeExprToVerificationCondition(CodeExpr codeExpr, Hashtable blockVariables, List<VCExprLetBinding> bindings, bool isPositiveContext)
+ {
+ VCGen vcgen = new VCGen(new Program(), null, false, new List<Checker>());
+ vcgen.variable2SequenceNumber = new Dictionary<Variable, int>();
+ vcgen.incarnationOriginMap = new Dictionary<Incarnation, Absy>();
+ vcgen.CurrentLocalVariables = codeExpr.LocVars;
+
+ ResetPredecessors(codeExpr.Blocks);
+ vcgen.AddBlocksBetween(codeExpr.Blocks);
+ Dictionary<Variable, Expr> gotoCmdOrigins = vcgen.ConvertBlocks2PassiveCmd(codeExpr.Blocks, new List<IdentifierExpr>(), new ModelViewInfo(codeExpr));
+ int ac; // computed, but then ignored for this CodeExpr
+ VCExpr startCorrect = VCGen.LetVCIterative(codeExpr.Blocks, null, label2absy, ctx, out ac, isPositiveContext);
+ VCExpr vce = ctx.ExprGen.Let(bindings, startCorrect);
+ if (vcgen.CurrentLocalVariables.Count != 0)
+ {
+ Boogie2VCExprTranslator translator = ctx.BoogieExprTranslator;
+ List<VCExprVar> boundVars = new List<VCExprVar>();
+ foreach (Variable v in vcgen.CurrentLocalVariables)
+ {
+ Contract.Assert(v != null);
+ VCExprVar ev = translator.LookupVariable(v);
+ Contract.Assert(ev != null);
+ boundVars.Add(ev);
+ if (v.TypedIdent.Type.Equals(Bpl.Type.Bool))
+ {
+ // add an antecedent (tickleBool ev) to help the prover find a possible trigger
+ vce = ctx.ExprGen.Implies(ctx.ExprGen.Function(VCExpressionGenerator.TickleBoolOp, ev), vce);
+ }
+ }
+ vce = ctx.ExprGen.Forall(boundVars, new List<VCTrigger>(), vce);
+ }
+ if (isPositiveContext)
+ {
+ vce = ctx.ExprGen.Not(vce);
+ }
+ return vce;
+ }
+ }
+
+ public VCExpr GenerateVC(Implementation/*!*/ impl, VCExpr controlFlowVariableExpr, out Dictionary<int, Absy>/*!*/ label2absy, ProverContext proverContext)
+ {
+ Contract.Requires(impl != null);
+ Contract.Requires(proverContext != null);
+ Contract.Ensures(Contract.ValueAtReturn(out label2absy) != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ label2absy = new Dictionary<int, Absy>();
+ return GenerateVCAux(impl, controlFlowVariableExpr, label2absy, proverContext);
+ }
+
+ public VCExpr GenerateVCAux(Implementation/*!*/ impl, VCExpr controlFlowVariableExpr, Dictionary<int, Absy>/*!*/ label2absy, ProverContext proverContext) {
+ Contract.Requires(impl != null);
+ Contract.Requires(proverContext != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ TypecheckingContext tc = new TypecheckingContext(null);
+ impl.Typecheck(tc);
+
+ VCExpr vc;
+ int assertionCount;
+ switch (CommandLineOptions.Clo.vcVariety) {
+ case CommandLineOptions.VCVariety.Structured:
+ vc = VCViaStructuredProgram(impl, label2absy, proverContext, out assertionCount);
+ break;
+ case CommandLineOptions.VCVariety.Block:
+ vc = FlatBlockVC(impl, label2absy, false, false, false, proverContext, out assertionCount);
+ break;
+ case CommandLineOptions.VCVariety.BlockReach:
+ vc = FlatBlockVC(impl, label2absy, false, true, false, proverContext, out assertionCount);
+ break;
+ case CommandLineOptions.VCVariety.Local:
+ vc = FlatBlockVC(impl, label2absy, true, false, false, proverContext, out assertionCount);
+ break;
+ case CommandLineOptions.VCVariety.BlockNested:
+ vc = NestedBlockVC(impl, label2absy, false, proverContext, out assertionCount);
+ break;
+ case CommandLineOptions.VCVariety.BlockNestedReach:
+ vc = NestedBlockVC(impl, label2absy, true, proverContext, out assertionCount);
+ break;
+ case CommandLineOptions.VCVariety.Dag:
+ if (cce.NonNull(CommandLineOptions.Clo.TheProverFactory).SupportsDags || CommandLineOptions.Clo.FixedPointEngine != null) {
+ vc = DagVC(cce.NonNull(impl.Blocks[0]), controlFlowVariableExpr, label2absy, new Hashtable/*<Block, VCExpr!>*/(), proverContext, out assertionCount);
+ } else {
+ vc = LetVC(cce.NonNull(impl.Blocks[0]), controlFlowVariableExpr, label2absy, proverContext, out assertionCount);
+ }
+ break;
+ case CommandLineOptions.VCVariety.DagIterative:
+ vc = LetVCIterative(impl.Blocks, controlFlowVariableExpr, label2absy, proverContext, out assertionCount);
+ break;
+ case CommandLineOptions.VCVariety.Doomed:
+ vc = FlatBlockVC(impl, label2absy, false, false, true, proverContext, out assertionCount);
+ break;
+ default:
+ Contract.Assert(false);
+ throw new cce.UnreachableException(); // unexpected enumeration value
+ }
+ CumulativeAssertionCount += assertionCount;
+ return vc;
+ }
+
+ void CheckIntAttributeOnImpl(Implementation impl, string name, ref int val) {
+ Contract.Requires(impl != null);
+ Contract.Requires(name != null);
+ if (!(cce.NonNull(impl.Proc).CheckIntAttribute(name, ref val) || !impl.CheckIntAttribute(name, ref val))) {
+ Console.WriteLine("ignoring ill-formed {:{0} ...} attribute on {1}, parameter should be an int", name, impl.Name);
+ }
+ }
+
+ public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback) {
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+
+ if (impl.SkipVerification) {
+ return Outcome.Inconclusive; // not sure about this one
+ }
+
+ callback.OnProgress("VCgen", 0, 0, 0.0);
+
+ Stopwatch watch = new Stopwatch();
+ if (_print_time)
+ {
+ Console.WriteLine("Checking function {0}", impl.Name);
+ watch.Reset();
+ watch.Start();
+ }
+
+ ConvertCFG2DAG(impl);
+
+ SmokeTester smoke_tester = null;
+ if (CommandLineOptions.Clo.SoundnessSmokeTest) {
+ smoke_tester = new SmokeTester(this, impl, callback);
+ smoke_tester.Copy();
+ }
+
+ ModelViewInfo mvInfo;
+ var gotoCmdOrigins = PassifyImpl(impl, out mvInfo);
+
+ // If "expand" attribute is supplied, expand any assertion of conjunctions into multiple assertions, one per conjunct
+ foreach (var b in impl.Blocks)
+ {
+ List<Cmd> newCmds = new List<Cmd>();
+ bool changed = false;
+ foreach (var c in b.Cmds)
+ {
+ var a = c as AssertCmd;
+ var ar = c as AssertRequiresCmd;
+ var ae = c as AssertEnsuresCmd;
+ var ai = c as LoopInitAssertCmd;
+ var am = c as LoopInvMaintainedAssertCmd;
+ // TODO:
+ //use Duplicator and Substituter rather than new
+ //nested IToken?
+ //document expand attribute (search for {:ignore}, for example)
+ //fix up new CallCmd, new Requires, new Ensures in OwickiGries.cs
+ Func<Expr,Expr,Expr> withType = (Expr from, Expr to) =>
+ {
+ NAryExpr nFrom = from as NAryExpr;
+ NAryExpr nTo = to as NAryExpr;
+ to.Type = from.Type;
+ if (nFrom != null && nTo != null) nTo.TypeParameters = nFrom.TypeParameters;
+ return to;
+ };
+
+ Action<int,Expr,Action<Expr>> traverse = null;
+ traverse = (depth, e, act) =>
+ {
+ ForallExpr forall = e as ForallExpr;
+ NAryExpr nary = e as NAryExpr;
+ if (forall != null)
+ {
+ traverse(depth, forall.Body, e1 => act(withType(forall,
+ new ForallExpr(e1.tok, forall.TypeParameters, forall.Dummies, forall.Attributes, forall.Triggers, e1))));
+ return;
+ }
+ if (nary != null)
+ {
+ var args = nary.Args;
+ IAppliable fun = nary.Fun;
+ BinaryOperator bop = fun as BinaryOperator;
+ FunctionCall call = fun as FunctionCall;
+ if (bop != null)
+ {
+ switch (bop.Op)
+ {
+ case BinaryOperator.Opcode.And:
+ traverse(depth, args[0], act);
+ traverse(depth, args[1], act);
+ return;
+ case BinaryOperator.Opcode.Imp:
+ traverse(depth, args[1], e1 => act(withType(nary,
+ new NAryExpr(e1.tok, fun, new List<Expr>() { args[0], e1 }))));
+ return;
+ }
+ }
+ if (depth > 0 && call != null && call.Func != null)
+ {
+ Function cf = call.Func;
+ Expr body = cf.Body;
+ List<Variable> ins = cf.InParams;
+ if (body == null && cf.DefinitionAxiom != null)
+ {
+ ForallExpr all = cf.DefinitionAxiom.Expr as ForallExpr;
+ if (all != null)
+ {
+ NAryExpr def = all.Body as NAryExpr;
+ if (def != null && def.Fun is BinaryOperator && ((BinaryOperator) (def.Fun)).Op == BinaryOperator.Opcode.Iff)
+ {
+ body = def.Args[1];
+ ins = all.Dummies;
+ }
+ }
+ }
+ if (body != null)
+ {
+ Func<Expr,Expr> new_f = e1 =>
+ {
+ Function f = new Function(cf.tok, "expand<" + cf.Name + ">", cf.TypeParameters, ins, cf.OutParams[0], cf.Comment);
+ f.Body = e1;
+ Token tok = new Token(e1.tok.line, e1.tok.col);
+ tok.filename = e.tok.filename + "(" + e.tok.line + "," + e.tok.col + ") --> " + e1.tok.filename;
+ return withType(nary, new NAryExpr(tok, new FunctionCall(f), args));
+ };
+ traverse(depth - 1, body, e1 => act(new_f(e1)));
+ return;
+ }
+ }
+ }
+ act(e);
+ };
+
+ if (a != null)
+ {
+ var attr = a.Attributes;
+ if (ar != null && ar.Requires.Attributes != null) attr = ar.Requires.Attributes;
+ if (ar != null && ar.Call.Attributes != null) attr = ar.Call.Attributes;
+ if (ae != null && ae.Ensures.Attributes != null) attr = ae.Ensures.Attributes;
+ if (QKeyValue.FindExprAttribute(attr, "expand") != null || QKeyValue.FindBoolAttribute(attr, "expand"))
+ {
+ int depth = QKeyValue.FindIntAttribute(attr, "expand", 100);
+ Func<Expr,Expr> fe = e => Expr.Or(a.Expr, e);
+ //traverse(depth, a.Expr, e => System.Console.WriteLine(e.GetType() + " :: " + e + " @ " + e.tok.line + ", " + e.tok.col));
+ traverse(depth, a.Expr, e =>
+ {
+ AssertCmd new_c =
+ (ar != null) ? new AssertRequiresCmd(ar.Call, new Requires(e.tok, ar.Requires.Free, fe(e), ar.Requires.Comment)) :
+ (ae != null) ? new AssertEnsuresCmd(new Ensures(e.tok, ae.Ensures.Free, fe(e), ae.Ensures.Comment)) :
+ (ai != null) ? new LoopInitAssertCmd(e.tok, fe(e)) :
+ (am != null) ? new LoopInvMaintainedAssertCmd(e.tok, fe(e)) :
+ new AssertCmd(e.tok, fe(e));
+ new_c.Attributes = new QKeyValue(e.tok, "subsumption", new List<object>() { new LiteralExpr(e.tok, BigNum.FromInt(0)) }, a.Attributes);
+ newCmds.Add(new_c);
+ });
+ }
+ newCmds.Add(c);
+ changed = true;
+ }
+ else
+ {
+ newCmds.Add(c);
+ }
+ }
+ if (changed) b.Cmds = newCmds;
+ }
+
+ double max_vc_cost = CommandLineOptions.Clo.VcsMaxCost;
+ int tmp_max_vc_cost = -1, max_splits = CommandLineOptions.Clo.VcsMaxSplits,
+ max_kg_splits = CommandLineOptions.Clo.VcsMaxKeepGoingSplits;
+ CheckIntAttributeOnImpl(impl, "vcs_max_cost", ref tmp_max_vc_cost);
+ CheckIntAttributeOnImpl(impl, "vcs_max_splits", ref max_splits);
+ CheckIntAttributeOnImpl(impl, "vcs_max_keep_going_splits", ref max_kg_splits);
+ if (tmp_max_vc_cost >= 0) {
+ max_vc_cost = tmp_max_vc_cost;
+ }
+
+ Outcome outcome = Outcome.Correct;
+
+ // Report all recycled failing assertions for this implementation.
+ if (impl.RecycledFailingAssertions != null && impl.RecycledFailingAssertions.Any())
+ {
+ outcome = Outcome.Errors;
+ foreach (var a in impl.RecycledFailingAssertions)
+ {
+ var checksum = a.Checksum;
+ var oldCex = impl.ErrorChecksumToCachedError[checksum] as Counterexample;
+ if (oldCex != null) {
+ if (CommandLineOptions.Clo.VerifySnapshots < 3) {
+ callback.OnCounterexample(oldCex, null);
+ } else {
+ // If possible, we use the old counterexample, but with the location information of "a"
+ var cex = AssertCmdToCloneCounterexample(a, oldCex);
+ callback.OnCounterexample(cex, null);
+ // OnCounterexample may have had side effects on the RequestId and OriginalRequestId fields. We make
+ // any such updates available in oldCex. (Is this really a good design? --KRML)
+ oldCex.RequestId = cex.RequestId;
+ oldCex.OriginalRequestId = cex.OriginalRequestId;
+ }
+ }
+ }
+ }
+
+ Cores = CommandLineOptions.Clo.VcsCores;
+ Stack<Split> work = new Stack<Split>();
+ List<Split> currently_running = new List<Split>();
+ ResetPredecessors(impl.Blocks);
+ List<Split> manual_splits = Split.FindManualSplits(impl, gotoCmdOrigins, this);
+ if (manual_splits != null) {
+ foreach (var split in manual_splits) {
+ work.Push(split);
+ }
+ } else {
+ work.Push(new Split(impl.Blocks, gotoCmdOrigins, this, impl));
+ }
+
+ bool keep_going = max_kg_splits > 1;
+ int total = 0;
+ int no = max_splits == 1 && !keep_going ? -1 : 0;
+ bool first_round = true;
+ bool do_splitting = keep_going || max_splits > 1;
+ double remaining_cost = 0.0, proven_cost = 0.0;
+
+ if (do_splitting) {
+ remaining_cost = work.Peek().Cost;
+ }
+
+ while (work.Any() || currently_running.Any())
+ {
+ bool prover_failed = false;
+ Split s = null;
+ var isWaiting = !work.Any();
+
+ if (!isWaiting)
+ {
+ s = work.Peek();
+
+ if (first_round && max_splits > 1)
+ {
+ prover_failed = true;
+ remaining_cost -= s.Cost;
+ }
+ else
+ {
+ var timeout = (keep_going && s.LastChance) ? CommandLineOptions.Clo.VcsFinalAssertTimeout :
+ keep_going ? CommandLineOptions.Clo.VcsKeepGoingTimeout :
+ impl.TimeLimit;
+
+ var checker = s.parent.FindCheckerFor(timeout, false);
+ try
+ {
+ if (checker == null)
+ {
+ isWaiting = true;
+ goto waiting;
+ }
+ else
+ {
+ s = work.Pop();
+ }
+
+ if (CommandLineOptions.Clo.Trace && no >= 0)
+ {
+ System.Console.WriteLine(" checking split {1}/{2}, {3:0.00}%, {0} ...",
+ s.Stats, no + 1, total, 100 * proven_cost / (proven_cost + remaining_cost));
+ }
+ callback.OnProgress("VCprove", no < 0 ? 0 : no, total, proven_cost / (remaining_cost + proven_cost));
+
+ Contract.Assert(s.parent == this);
+ lock (checker)
+ {
+ s.BeginCheck(checker, callback, mvInfo, no, timeout);
+ }
+
+ no++;
+
+ currently_running.Add(s);
+ }
+ catch (Exception)
+ {
+ checker.GoBackToIdle();
+ throw;
+ }
+ }
+ }
+
+ waiting:
+ if (isWaiting)
+ {
+ // Wait for one split to terminate.
+ var tasks = currently_running.Select(splt => splt.ProverTask).ToArray();
+
+ if (tasks.Any())
+ {
+ try
+ {
+ int index = Task.WaitAny(tasks);
+ s = currently_running[index];
+ currently_running.RemoveAt(index);
+
+ if (do_splitting)
+ {
+ remaining_cost -= s.Cost;
+ }
+
+ lock (s.Checker)
+ {
+ s.ReadOutcome(ref outcome, out prover_failed);
+ }
+
+ if (do_splitting)
+ {
+ if (prover_failed)
+ {
+ // even if the prover fails, we have learned something, i.e., it is
+ // annoying to watch Boogie say Timeout, 0.00% a couple of times
+ proven_cost += s.Cost / 100;
+ }
+ else
+ {
+ proven_cost += s.Cost;
+ }
+ }
+ callback.OnProgress("VCprove", no < 0 ? 0 : no, total, proven_cost / (remaining_cost + proven_cost));
+
+ if (prover_failed && !first_round && s.LastChance)
+ {
+ string msg = "some timeout";
+ if (s.reporter != null && s.reporter.resourceExceededMessage != null)
+ {
+ msg = s.reporter.resourceExceededMessage;
+ }
+ callback.OnCounterexample(s.ToCounterexample(s.Checker.TheoremProver.Context), msg);
+ outcome = Outcome.Errors;
+ break;
+ }
+ }
+ finally
+ {
+ s.Checker.GoBackToIdle();
+ }
+
+ Contract.Assert(prover_failed || outcome == Outcome.Correct || outcome == Outcome.Errors || outcome == Outcome.Inconclusive);
+ }
+ }
+
+ if (prover_failed)
+ {
+ int splits = first_round && max_splits > 1 ? max_splits : max_kg_splits;
+
+ if (splits > 1)
+ {
+ List<Split> tmp = Split.DoSplit(s, max_vc_cost, splits);
+ Contract.Assert(tmp != null);
+ max_vc_cost = 1.0; // for future
+ first_round = false;
+ //tmp.Sort(new Comparison<Split!>(Split.Compare));
+ foreach (Split a in tmp)
+ {
+ Contract.Assert(a != null);
+ work.Push(a);
+ total++;
+ remaining_cost += a.Cost;
+ }
+ if (outcome != Outcome.Errors)
+ {
+ outcome = Outcome.Correct;
+ }
+ }
+ else
+ {
+ Contract.Assert(outcome != Outcome.Correct);
+ if (outcome == Outcome.TimedOut)
+ {
+ string msg = "some timeout";
+ if (s.reporter != null && s.reporter.resourceExceededMessage != null)
+ {
+ msg = s.reporter.resourceExceededMessage;
+ }
+ callback.OnTimeout(msg);
+ }
+ else if (outcome == Outcome.OutOfMemory)
+ {
+ string msg = "out of memory";
+ if (s.reporter != null && s.reporter.resourceExceededMessage != null)
+ {
+ msg = s.reporter.resourceExceededMessage;
+ }
+ callback.OnOutOfMemory(msg);
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (outcome == Outcome.Correct && smoke_tester != null) {
+ smoke_tester.Test();
+ }
+
+ callback.OnProgress("done", 0, 0, 1.0);
+
+ if (_print_time)
+ {
+ watch.Stop();
+ Console.WriteLine("Total time for this method: {0}", watch.Elapsed.ToString());
+ }
+
+ return outcome;
+ }
+
+ public class ErrorReporter : ProverInterface.ErrorHandler {
+ Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins;
+ Dictionary<int, Absy>/*!*/ label2absy;
+ List<Block/*!*/>/*!*/ blocks;
+ protected Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap;
+ protected VerifierCallback/*!*/ callback;
+ protected ModelViewInfo MvInfo;
+ internal string resourceExceededMessage;
+ static System.IO.TextWriter modelWriter;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(gotoCmdOrigins != null);
+ Contract.Invariant(label2absy != null);
+ Contract.Invariant(cce.NonNullElements(blocks));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(incarnationOriginMap));
+ Contract.Invariant(callback != null);
+ Contract.Invariant(context != null);
+ Contract.Invariant(program != null);
+ }
+
+
+ public static TextWriter ModelWriter {
+ get {
+ Contract.Ensures(Contract.Result<TextWriter>() != null);
+
+ if (ErrorReporter.modelWriter == null)
+ ErrorReporter.modelWriter = CommandLineOptions.Clo.PrintErrorModelFile == null ? Console.Out : new StreamWriter(CommandLineOptions.Clo.PrintErrorModelFile, false);
+ return ErrorReporter.modelWriter;
+ }
+ }
+
+ protected ProverContext/*!*/ context;
+ Program/*!*/ program;
+
+ public ErrorReporter(Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins,
+ Dictionary<int, Absy>/*!*/ label2absy,
+ List<Block/*!*/>/*!*/ blocks,
+ Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap,
+ VerifierCallback/*!*/ callback,
+ ModelViewInfo mvInfo,
+ ProverContext/*!*/ context,
+ Program/*!*/ program) {
+ Contract.Requires(gotoCmdOrigins != null);
+ Contract.Requires(label2absy != null);
+ Contract.Requires(cce.NonNullElements(blocks));
+ Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap));
+ Contract.Requires(callback != null);
+ Contract.Requires(context!=null);
+ Contract.Requires(program!=null);
+ this.gotoCmdOrigins = gotoCmdOrigins;
+ this.label2absy = label2absy;
+ this.blocks = blocks;
+ this.incarnationOriginMap = incarnationOriginMap;
+ this.callback = callback;
+ this.MvInfo = mvInfo;
+
+ this.context = context;
+ this.program = program;
+ }
+
+ public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) {
+ //Contract.Requires(cce.NonNullElements(labels));
+ if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) {
+ if (VC.ConditionGeneration.errorModelList != null)
+ {
+ VC.ConditionGeneration.errorModelList.Add(model);
+ }
+
+ model.Write(ErrorReporter.ModelWriter);
+ ErrorReporter.ModelWriter.Flush();
+ }
+
+ Hashtable traceNodes = new Hashtable();
+ foreach (string s in labels) {
+ Contract.Assert(s != null);
+ Absy absy = Label2Absy(s);
+ Contract.Assert(absy != null);
+ if (traceNodes.ContainsKey(absy))
+ System.Console.WriteLine("Warning: duplicate label: " + s + " read while tracing nodes");
+ else
+ traceNodes.Add(absy, null);
+ }
+
+ List<Block> trace = new List<Block>();
+ Block entryBlock = cce.NonNull(this.blocks[0]);
+ Contract.Assert(traceNodes.Contains(entryBlock));
+ trace.Add(entryBlock);
+
+ Counterexample newCounterexample = TraceCounterexample(entryBlock, traceNodes, trace, model, MvInfo, incarnationOriginMap, context, new Dictionary<TraceLocation, CalleeCounterexampleInfo>());
+
+ if (newCounterexample == null)
+ return;
+
+ #region Map passive program errors back to original program errors
+ ReturnCounterexample returnExample = newCounterexample as ReturnCounterexample;
+ if (returnExample != null) {
+ foreach (Block b in returnExample.Trace) {
+ Contract.Assert(b != null);
+ Contract.Assume(b.TransferCmd != null);
+ ReturnCmd cmd = gotoCmdOrigins.ContainsKey(b.TransferCmd) ? gotoCmdOrigins[b.TransferCmd] : null;
+ if (cmd != null) {
+ returnExample.FailingReturn = cmd;
+ break;
+ }
+ }
+ }
+ #endregion
+ callback.OnCounterexample(newCounterexample, null);
+ }
+
+ public override Absy Label2Absy(string label) {
+ //Contract.Requires(label != null);
+ Contract.Ensures(Contract.Result<Absy>() != null);
+
+ int id = int.Parse(label);
+ return cce.NonNull((Absy)label2absy[id]);
+ }
+
+ public override void OnResourceExceeded(string msg, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null) {
+ //Contract.Requires(msg != null);
+ resourceExceededMessage = msg;
+ if (assertCmds != null)
+ {
+ foreach (var cmd in assertCmds)
+ {
+ Counterexample cex = AssertCmdToCounterexample(cmd.Item1, cmd.Item2 , new List<Block>(), null, null, context);
+ callback.OnCounterexample(cex, msg);
+ }
+ }
+ }
+
+ public override void OnProverWarning(string msg) {
+ //Contract.Requires(msg != null);
+ callback.OnWarning(msg);
+ }
+ }
+
+ public class ErrorReporterLocal : ErrorReporter {
+ public ErrorReporterLocal(Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins,
+ Dictionary<int, Absy>/*!*/ label2absy,
+ List<Block/*!*/>/*!*/ blocks,
+ Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap,
+ VerifierCallback/*!*/ callback,
+ ModelViewInfo mvInfo,
+ ProverContext/*!*/ context,
+ Program/*!*/ program)
+ : base(gotoCmdOrigins, label2absy, blocks, incarnationOriginMap, callback, mvInfo, context, program) // here for aesthetic purposes //TODO: Maybe nix?
+ {
+ Contract.Requires(gotoCmdOrigins != null);
+ Contract.Requires(label2absy != null);
+ Contract.Requires(cce.NonNullElements(blocks));
+ Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap));
+ Contract.Requires(callback != null);
+ Contract.Requires(context != null);
+ Contract.Requires(program != null);
+ }
+
+ public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) {
+ //Contract.Requires(cce.NonNullElements(labels));
+ // We ignore the error model here for enhanced error message purposes.
+ // It is only printed to the command line.
+ if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) {
+ if (CommandLineOptions.Clo.PrintErrorModelFile != null) {
+ model.Write(ErrorReporter.ModelWriter);
+ ErrorReporter.ModelWriter.Flush();
+ }
+ }
+ List<Block> traceNodes = new List<Block>();
+ List<AssertCmd> assertNodes = new List<AssertCmd>();
+ foreach (string s in labels) {
+ Contract.Assert(s != null);
+ Absy node = Label2Absy(s);
+ if (node is Block) {
+ Block b = (Block)node;
+ traceNodes.Add(b);
+ } else {
+ AssertCmd a = (AssertCmd)node;
+ assertNodes.Add(a);
+ }
+ }
+ Contract.Assert(assertNodes.Count > 0);
+ Contract.Assert(traceNodes.Count == assertNodes.Count);
+
+ foreach (AssertCmd a in assertNodes) {
+ // find the corresponding Block (assertNodes.Count is likely to be 1, or small in any case, so just do a linear search here)
+ foreach (Block b in traceNodes) {
+ if (b.Cmds.Contains(a)) {
+ List<Block> trace = new List<Block>();
+ trace.Add(b);
+ Counterexample newCounterexample = AssertCmdToCounterexample(a, cce.NonNull(b.TransferCmd), trace, model, MvInfo, context);
+ callback.OnCounterexample(newCounterexample, null);
+ goto NEXT_ASSERT;
+ }
+ }
+ Contract.Assert(false);
+ throw new cce.UnreachableException(); // there was no block that contains the assert
+ NEXT_ASSERT: {
+ }
+ }
+ }
+ }
+
+ private void RecordCutEdge(Dictionary<Block,List<Block>> edgesCut, Block from, Block to){
+ if (edgesCut != null)
+ {
+ if (!edgesCut.ContainsKey(from))
+ edgesCut.Add(from, new List<Block>());
+ edgesCut[from].Add(to);
+ }
+ }
+
+ public void ConvertCFG2DAG(Implementation impl, Dictionary<Block,List<Block>> edgesCut = null, int taskID = -1)
+ {
+ Contract.Requires(impl != null);
+ impl.PruneUnreachableBlocks(); // This is needed for VCVariety.BlockNested, and is otherwise just an optimization
+
+ CurrentLocalVariables = impl.LocVars;
+ variable2SequenceNumber = new Dictionary<Variable, int>();
+ incarnationOriginMap = new Dictionary<Incarnation, Absy>();
+
+ #region Debug Tracing
+ if (CommandLineOptions.Clo.TraceVerify)
+ {
+ Console.WriteLine("original implementation");
+ EmitImpl(impl, false);
+ }
+ #endregion
+
+ #region Debug Tracing
+ if (CommandLineOptions.Clo.TraceVerify)
+ {
+ Console.WriteLine("after desugaring sugared commands like procedure calls");
+ EmitImpl(impl, true);
+ }
+ #endregion
+
+ // Recompute the predecessors, but first insert a dummy start node that is sure not to be the target of any goto (because the cutting of back edges
+ // below assumes that the start node has no predecessor)
+ impl.Blocks.Insert(0, new Block(new Token(-17, -4), "0", new List<Cmd>(), new GotoCmd(Token.NoToken, new List<String> { impl.Blocks[0].Label }, new List<Block> { impl.Blocks[0] })));
+ ResetPredecessors(impl.Blocks);
+
+ if(CommandLineOptions.Clo.KInductionDepth < 0) {
+ ConvertCFG2DAGStandard(impl, edgesCut, taskID);
+ } else {
+ ConvertCFG2DAGKInduction(impl, edgesCut, taskID);
+ }
+
+ #region Debug Tracing
+ if (CommandLineOptions.Clo.TraceVerify)
+ {
+ Console.WriteLine("after conversion into a DAG");
+ EmitImpl(impl, true);
+ }
+ #endregion
+ }
+
+ private void ConvertCFG2DAGStandard(Implementation impl, Dictionary<Block, List<Block>> edgesCut, int taskID)
+ {
+ #region Convert program CFG into a DAG
+
+ #region Use the graph library to figure out where the (natural) loops are
+
+ #region Create the graph by adding the source node and each edge
+ Graph<Block> g = Program.GraphFromImpl(impl);
+ #endregion
+
+ //Graph<Block> g = program.ProcessLoops(impl);
+
+ g.ComputeLoops(); // this is the call that does all of the processing
+ if (!g.Reducible)
+ {
+ throw new VCGenException("Irreducible flow graphs are unsupported.");
+ }
+
+ #endregion
+
+ #region Cut the backedges, push assert/assume statements from loop header into predecessors, change them all into assume statements at top of loop, introduce havoc statements
+ foreach (Block header in cce.NonNull(g.Headers))
+ {
+ Contract.Assert(header != null);
+ IDictionary<Block, object> backEdgeNodes = new Dictionary<Block, object>();
+ foreach (Block b in cce.NonNull(g.BackEdgeNodes(header)))
+ {
+ Contract.Assert(b != null);
+ backEdgeNodes.Add(b, null);
+ }
+
+ #region Find the (possibly empty) prefix of assert commands in the header, replace each assert with an assume of the same condition
+ List<Cmd> prefixOfPredicateCmdsInit = new List<Cmd>();
+ List<Cmd> prefixOfPredicateCmdsMaintained = new List<Cmd>();
+ for (int i = 0, n = header.Cmds.Count; i < n; i++)
+ {
+ PredicateCmd a = header.Cmds[i] as PredicateCmd;
+ if (a != null)
+ {
+ if (a is AssertCmd)
+ {
+ AssertCmd c = (AssertCmd)a;
+ AssertCmd b = null;
+
+ if (CommandLineOptions.Clo.ConcurrentHoudini)
+ {
+ Contract.Assert(taskID >= 0);
+ if (CommandLineOptions.Clo.Cho[taskID].DisableLoopInvEntryAssert)
+ b = new LoopInitAssertCmd(c.tok, Expr.True);
+ else
+ b = new LoopInitAssertCmd(c.tok, c.Expr);
+ }
+ else
+ {
+ b = new LoopInitAssertCmd(c.tok, c.Expr);
+ }
+
+ b.Attributes = c.Attributes;
+ b.ErrorData = c.ErrorData;
+ prefixOfPredicateCmdsInit.Add(b);
+
+ if (CommandLineOptions.Clo.ConcurrentHoudini)
+ {
+ Contract.Assert(taskID >= 0);
+ if (CommandLineOptions.Clo.Cho[taskID].DisableLoopInvMaintainedAssert)
+ b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, Expr.True);
+ else
+ b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, c.Expr);
+ }
+ else
+ {
+ b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, c.Expr);
+ }
+
+ b.Attributes = c.Attributes;
+ b.ErrorData = c.ErrorData;
+ prefixOfPredicateCmdsMaintained.Add(b);
+ header.Cmds[i] = new AssumeCmd(c.tok, c.Expr);
+ }
+ else
+ {
+ Contract.Assert(a is AssumeCmd);
+ if (Bpl.CommandLineOptions.Clo.AlwaysAssumeFreeLoopInvariants)
+ {
+ // Usually, "free" stuff, like free loop invariants (and the assume statements
+ // that stand for such loop invariants) are ignored on the checking side. This
+ // command-line option changes that behavior to always assume the conditions.
+ prefixOfPredicateCmdsInit.Add(a);
+ prefixOfPredicateCmdsMaintained.Add(a);
+ }
+ }
+ }
+ else if (header.Cmds[i] is CommentCmd)
+ {
+ // ignore
+ }
+ else
+ {
+ break; // stop when an assignment statement (or any other non-predicate cmd) is encountered
+ }
+ }
+ #endregion
+
+ #region Copy the prefix of predicate commands into each predecessor. Do this *before* cutting the backedge!!
+ for (int predIndex = 0, n = header.Predecessors.Count; predIndex < n; predIndex++)
+ {
+ Block pred = cce.NonNull(header.Predecessors[predIndex]);
+
+ // Create a block between header and pred for the predicate commands if pred has more than one successor
+ GotoCmd gotocmd = cce.NonNull((GotoCmd)pred.TransferCmd);
+ Contract.Assert(gotocmd.labelNames != null); // if "pred" is really a predecessor, it may be a GotoCmd with at least one label
+ if (gotocmd.labelNames.Count > 1)
+ {
+ Block newBlock = CreateBlockBetween(predIndex, header);
+ impl.Blocks.Add(newBlock);
+
+ // if pred is a back edge node, then now newBlock is the back edge node
+ if (backEdgeNodes.ContainsKey(pred))
+ {
+ backEdgeNodes.Remove(pred);
+ backEdgeNodes.Add(newBlock, null);
+ }
+
+ pred = newBlock;
+ }
+ // Add the predicate commands
+ if (backEdgeNodes.ContainsKey(pred))
+ {
+ pred.Cmds.AddRange(prefixOfPredicateCmdsMaintained);
+ }
+ else
+ {
+ pred.Cmds.AddRange(prefixOfPredicateCmdsInit);
+ }
+ }
+ #endregion
+
+ #region Cut the back edge
+ foreach (Block backEdgeNode in cce.NonNull(backEdgeNodes.Keys))
+ {
+ Contract.Assert(backEdgeNode != null);
+ Debug.Assert(backEdgeNode.TransferCmd is GotoCmd, "An node was identified as the source for a backedge, but it does not have a goto command.");
+ GotoCmd gtc = backEdgeNode.TransferCmd as GotoCmd;
+ if (gtc != null && gtc.labelTargets != null && gtc.labelTargets.Count > 1)
+ {
+ // then remove the backedge by removing the target block from the list of gotos
+ List<Block> remainingTargets = new List<Block>();
+ List<String> remainingLabels = new List<String>();
+ Contract.Assume(gtc.labelNames != null);
+ for (int i = 0, n = gtc.labelTargets.Count; i < n; i++)
+ {
+ if (gtc.labelTargets[i] != header)
+ {
+ remainingTargets.Add(gtc.labelTargets[i]);
+ remainingLabels.Add(gtc.labelNames[i]);
+ }
+ else
+ RecordCutEdge(edgesCut, backEdgeNode, header);
+ }
+ gtc.labelTargets = remainingTargets;
+ gtc.labelNames = remainingLabels;
+ }
+ else
+ {
+ // This backedge is the only out-going edge from this node.
+ // Add an "assume false" statement to the end of the statements
+ // inside of the block and change the goto command to a return command.
+ AssumeCmd ac = new AssumeCmd(Token.NoToken, Expr.False);
+ backEdgeNode.Cmds.Add(ac);
+ backEdgeNode.TransferCmd = new ReturnCmd(Token.NoToken);
+ if (gtc != null && gtc.labelTargets != null && gtc.labelTargets.Count == 1)
+ RecordCutEdge(edgesCut, backEdgeNode, gtc.labelTargets[0]);
+ }
+ #region Remove the backedge node from the list of predecessor nodes in the header
+ List<Block> newPreds = new List<Block>();
+ foreach (Block p in header.Predecessors)
+ {
+ if (p != backEdgeNode)
+ newPreds.Add(p);
+ }
+ header.Predecessors = newPreds;
+ #endregion
+ }
+ #endregion
+
+ #region Collect all variables that are assigned to in all of the natural loops for which this is the header
+ List<Variable> varsToHavoc = VarsAssignedInLoop(g, header);
+ List<IdentifierExpr> havocExprs = new List<IdentifierExpr>();
+ foreach (Variable v in varsToHavoc)
+ {
+ Contract.Assert(v != null);
+ IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v);
+ if (!havocExprs.Contains(ie))
+ havocExprs.Add(ie);
+ }
+ // pass the token of the enclosing loop header to the HavocCmd so we can reconstruct
+ // the source location for this later on
+ HavocCmd hc = new HavocCmd(header.tok, havocExprs);
+ List<Cmd> newCmds = new List<Cmd>();
+ newCmds.Add(hc);
+ foreach (Cmd c in header.Cmds)
+ {
+ newCmds.Add(c);
+ }
+ header.Cmds = newCmds;
+ #endregion
+ }
+ #endregion
+ #endregion Convert program CFG into a DAG
+ }
+
+ public static List<Variable> VarsAssignedInLoop(Graph<Block> g, Block header)
+ {
+ List<Variable> varsToHavoc = new List<Variable>();
+ foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header)))
+ {
+ Contract.Assert(backEdgeNode != null);
+ foreach (Block b in g.NaturalLoops(header, backEdgeNode))
+ {
+ Contract.Assert(b != null);
+ foreach (Cmd c in b.Cmds)
+ {
+ Contract.Assert(c != null);
+ c.AddAssignedVariables(varsToHavoc);
+ }
+ }
+ }
+ return varsToHavoc;
+ }
+
+ public static IEnumerable<Variable> VarsReferencedInLoop(Graph<Block> g, Block header)
+ {
+ HashSet<Variable> referencedVars = new HashSet<Variable>();
+ foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header)))
+ {
+ Contract.Assert(backEdgeNode != null);
+ foreach (Block b in g.NaturalLoops(header, backEdgeNode))
+ {
+ Contract.Assert(b != null);
+ foreach (Cmd c in b.Cmds)
+ {
+ Contract.Assert(c != null);
+ var Collector = new VariableCollector();
+ Collector.Visit(c);
+ foreach(var v in Collector.usedVars) {
+ referencedVars.Add(v);
+ }
+ }
+ }
+ }
+ return referencedVars;
+ }
+
+ private void ConvertCFG2DAGKInduction(Implementation impl, Dictionary<Block, List<Block>> edgesCut, int taskID) {
+
+ // K-induction has not been adapted to be aware of these parameters which standard CFG to DAG transformation uses
+ Contract.Requires(edgesCut == null);
+ Contract.Requires(taskID == -1);
+
+ int inductionK = CommandLineOptions.Clo.KInductionDepth;
+ Contract.Assume(inductionK >= 0);
+
+ bool contRuleApplication = true;
+ while (contRuleApplication) {
+ contRuleApplication = false;
+
+ #region Use the graph library to figure out where the (natural) loops are
+
+ #region Create the graph by adding the source node and each edge
+ Graph<Block> g = Program.GraphFromImpl(impl);
+ #endregion
+
+ g.ComputeLoops(); // this is the call that does all of the processing
+ if (!g.Reducible) {
+ throw new VCGenException("Irreducible flow graphs are unsupported.");
+ }
+
+ #endregion
+
+ foreach (Block header in cce.NonNull(g.Headers)) {
+ Contract.Assert(header != null);
+
+ #region Debug Tracing
+ if (CommandLineOptions.Clo.TraceVerify)
+ {
+ Console.WriteLine("Applying k-induction rule with k=" + inductionK);
+ }
+ #endregion
+
+ #region generate the step case
+ Block newHeader = DuplicateLoop(impl, g, header, null,
+ false, false, "_step_assertion");
+ for (int i = 0; i < inductionK; ++i)
+ {
+ newHeader = DuplicateLoop(impl, g, header, newHeader,
+ true, true,
+ "_step_" + (inductionK - i));
+ }
+ #endregion
+
+ #region havoc variables that can be assigned in the loop
+
+ List<Variable> varsToHavoc = VarsAssignedInLoop(g, header);
+ List<IdentifierExpr> havocExprs = new List<IdentifierExpr>();
+ foreach (Variable v in varsToHavoc)
+ {
+ Contract.Assert(v != null);
+ IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v);
+ if (!havocExprs.Contains(ie))
+ havocExprs.Add(ie);
+ }
+ // pass the token of the enclosing loop header to the HavocCmd so we can reconstruct
+ // the source location for this later on
+ HavocCmd hc = new HavocCmd(newHeader.tok, havocExprs);
+ List<Cmd> havocCmds = new List<Cmd>();
+ havocCmds.Add(hc);
+
+ Block havocBlock = new Block(newHeader.tok, newHeader.Label + "_havoc", havocCmds,
+ new GotoCmd (newHeader.tok, new List<Block> { newHeader }));
+
+ impl.Blocks.Add(havocBlock);
+ newHeader.Predecessors.Add(havocBlock);
+ newHeader = havocBlock;
+
+ #endregion
+
+ #region generate the base case loop copies
+ for (int i = 0; i < inductionK; ++i)
+ {
+ newHeader = DuplicateLoop(impl, g, header, newHeader,
+ false, false,
+ "_base_" + (inductionK - i));
+ }
+ #endregion
+
+ #region redirect into the new loop copies and remove the original loop (but don't redirect back-edges)
+
+ IDictionary<Block, object> backEdgeNodes = new Dictionary<Block, object>();
+ foreach (Block b in cce.NonNull(g.BackEdgeNodes(header))) { Contract.Assert(b != null); backEdgeNodes.Add(b, null); }
+
+ for (int predIndex = 0, n = header.Predecessors.Count(); predIndex < n; predIndex++)
+ {
+ Block pred = cce.NonNull(header.Predecessors[predIndex]);
+ if (!backEdgeNodes.ContainsKey(pred))
+ {
+ GotoCmd gc = pred.TransferCmd as GotoCmd;
+ Contract.Assert(gc != null);
+ for (int i = 0; i < gc.labelTargets.Count(); ++i)
+ {
+ if (gc.labelTargets[i] == header)
+ {
+ gc.labelTargets[i] = newHeader;
+ gc.labelNames[i] = newHeader.Label;
+ newHeader.Predecessors.Add(pred);
+ }
+ }
+ }
+ }
+ impl.PruneUnreachableBlocks();
+
+ #endregion
+
+ contRuleApplication = true;
+ break;
+ }
+
+ }
+
+ ResetPredecessors(impl.Blocks);
+ impl.FreshenCaptureStates();
+
+ }
+
+ private Block DuplicateLoop(Implementation impl, Graph<Block> g,
+ Block header, Block nextHeader, bool cutExits,
+ bool toAssumptions, string suffix)
+ {
+ IDictionary<Block, Block> ori2CopiedBlocks = new Dictionary<Block, Block>();
+ Duplicator duplicator = new Duplicator();
+
+ #region create copies of all blocks in the loop
+ foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header)))
+ {
+ Contract.Assert(backEdgeNode != null);
+ foreach (Block b in g.NaturalLoops(header, backEdgeNode))
+ {
+ Contract.Assert(b != null);
+ if (!ori2CopiedBlocks.ContainsKey(b))
+ {
+ Block copy = (Block)duplicator.Visit(b);
+ copy.Cmds = new List<Cmd>(copy.Cmds); // Philipp Ruemmer commented that this was necessary due to a bug in the Duplicator. That was a long time; worth checking whether this has been fixed
+ copy.Predecessors = new List<Block>();
+ copy.Label = copy.Label + suffix;
+
+ #region turn asserts into assumptions
+ if (toAssumptions)
+ {
+ for (int i = 0; i < copy.Cmds.Count(); ++i)
+ {
+ AssertCmd ac = copy.Cmds[i] as AssertCmd;
+ if (ac != null)
+ {
+ copy.Cmds[i] = new AssumeCmd(ac.tok, ac.Expr);
+ }
+ }
+ }
+ #endregion
+
+ impl.Blocks.Add(copy);
+ ori2CopiedBlocks.Add(b, copy);
+ }
+ }
+ }
+ #endregion
+
+ #region adjust the transfer commands of the newly created blocks
+ foreach (KeyValuePair<Block, Block> pair in ori2CopiedBlocks)
+ {
+ Block copy = pair.Value;
+ GotoCmd gc = copy.TransferCmd as GotoCmd;
+ if (gc != null)
+ {
+ List<Block> newTargets = new List<Block>();
+ List<string> newLabels = new List<string>();
+
+ for (int i = 0; i < gc.labelTargets.Count(); ++i)
+ {
+ Block newTarget;
+ if (gc.labelTargets[i] == header)
+ {
+ if (nextHeader != null)
+ {
+ newTargets.Add(nextHeader);
+ newLabels.Add(nextHeader.Label);
+ nextHeader.Predecessors.Add(copy);
+ }
+ }
+ else if (ori2CopiedBlocks.TryGetValue(gc.labelTargets[i], out newTarget))
+ {
+ newTargets.Add(newTarget);
+ newLabels.Add(newTarget.Label);
+ newTarget.Predecessors.Add(copy);
+ }
+ else if (!cutExits)
+ {
+ newTargets.Add(gc.labelTargets[i]);
+ newLabels.Add(gc.labelNames[i]);
+ gc.labelTargets[i].Predecessors.Add(copy);
+ }
+ }
+
+ if (newTargets.Count() == 0)
+ {
+ // if no targets are left, we assume false and return
+ copy.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False));
+ copy.TransferCmd = new ReturnCmd(Token.NoToken);
+ }
+ else
+ {
+ copy.TransferCmd = new GotoCmd(gc.tok, newLabels, newTargets);
+ }
+ }
+ else if (cutExits && (copy.TransferCmd is ReturnCmd))
+ {
+ // because return is a kind of exit from the loop, we
+ // assume false to cut this path
+ copy.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False));
+ }
+ }
+ #endregion
+
+ return ori2CopiedBlocks[header];
+ }
+
+ public void DesugarCalls(Implementation impl) {
+ foreach (Block block in impl.Blocks) {
+ List<Cmd> newCmds = new List<Cmd>();
+ foreach (Cmd cmd in block.Cmds) {
+ SugaredCmd sugaredCmd = cmd as SugaredCmd;
+ if (sugaredCmd != null) {
+ StateCmd stateCmd = sugaredCmd.Desugaring as StateCmd;
+ foreach (Variable v in stateCmd.Locals) {
+ impl.LocVars.Add(v);
+ }
+ newCmds.AddRange(stateCmd.Cmds);
+ }
+ else {
+ newCmds.Add(cmd);
+ }
+ }
+ block.Cmds = newCmds;
+ }
+ }
+
+ public Dictionary<TransferCmd, ReturnCmd> PassifyImpl(Implementation impl, out ModelViewInfo mvInfo)
+ {
+ Contract.Requires(impl != null);
+ Contract.Requires(program != null);
+ Contract.Ensures(Contract.Result<Dictionary<TransferCmd, ReturnCmd>>() != null);
+
+ Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins = new Dictionary<TransferCmd, ReturnCmd>();
+ Block exitBlock = GenerateUnifiedExit(impl, gotoCmdOrigins);
+
+ #region Debug Tracing
+ if (CommandLineOptions.Clo.TraceVerify)
+ {
+ Console.WriteLine("after creating a unified exit block");
+ EmitImpl(impl, true);
+ }
+ #endregion
+
+ #region Insert pre- and post-conditions and where clauses as assume and assert statements
+ {
+ List<Cmd> cc = new List<Cmd>();
+ // where clauses of global variables
+ lock (program.TopLevelDeclarations)
+ {
+ foreach (var gvar in program.GlobalVariables)
+ {
+ if (gvar != null && gvar.TypedIdent.WhereExpr != null)
+ {
+ Cmd c = new AssumeCmd(gvar.tok, gvar.TypedIdent.WhereExpr);
+ cc.Add(c);
+ }
+ }
+ }
+ // where clauses of in- and out-parameters
+ cc.AddRange(GetParamWhereClauses(impl));
+ // where clauses of local variables
+ foreach (Variable lvar in impl.LocVars) {Contract.Assert(lvar != null);
+ if (lvar.TypedIdent.WhereExpr != null) {
+ Cmd c = new AssumeCmd(lvar.tok, lvar.TypedIdent.WhereExpr);
+ cc.Add(c);
+ } else if (QKeyValue.FindBoolAttribute(lvar.Attributes, "assumption")) {
+ cc.Add(new AssumeCmd(lvar.tok, new IdentifierExpr(lvar.tok, lvar), new QKeyValue(lvar.tok, "assumption_variable_initialization", new List<object>(), null)));
+ }
+ }
+ // add cc and the preconditions to new blocks preceding impl.Blocks[0]
+ InjectPreconditions(impl, cc);
+
+ // append postconditions, starting in exitBlock and continuing into other blocks, if needed
+ InjectPostConditions(impl, exitBlock, gotoCmdOrigins);
+ }
+ #endregion
+
+ #region Support for stratified inlining
+ addExitAssert(impl.Name, exitBlock);
+ #endregion
+
+
+ #region Debug Tracing
+ if (CommandLineOptions.Clo.TraceVerify)
+ {
+ Console.WriteLine("after inserting pre- and post-conditions");
+ EmitImpl(impl, true);
+ }
+ #endregion
+
+ AddBlocksBetween(impl.Blocks);
+
+ #region Debug Tracing
+ if (CommandLineOptions.Clo.TraceVerify)
+ {
+ Console.WriteLine("after adding empty blocks as needed to catch join assumptions");
+ EmitImpl(impl, true);
+ }
+ #endregion
+
+ if (CommandLineOptions.Clo.LiveVariableAnalysis > 0) {
+ Microsoft.Boogie.LiveVariableAnalysis.ComputeLiveVariables(impl);
+ }
+
+ mvInfo = new ModelViewInfo(program, impl);
+ Convert2PassiveCmd(impl, mvInfo);
+
+ #region Peep-hole optimizations
+ if (CommandLineOptions.Clo.RemoveEmptyBlocks){
+ #region Get rid of empty blocks
+ {
+ RemoveEmptyBlocksIterative(impl.Blocks);
+ impl.PruneUnreachableBlocks();
+ }
+ #endregion Get rid of empty blocks
+
+ #region Debug Tracing
+ if (CommandLineOptions.Clo.TraceVerify)
+ {
+ Console.WriteLine("after peep-hole optimizations");
+ EmitImpl(impl, true);
+ }
+ #endregion
+ }
+ #endregion Peep-hole optimizations
+
+ HandleSelectiveChecking(impl);
+
+
+// #region Constant Folding
+// #endregion
+// #region Debug Tracing
+// if (CommandLineOptions.Clo.TraceVerify)
+// {
+// Console.WriteLine("after constant folding");
+// EmitImpl(impl, true);
+// }
+// #endregion
+
+ return gotoCmdOrigins;
+ }
+
+ private static void HandleSelectiveChecking(Implementation impl)
+ {
+ if (QKeyValue.FindBoolAttribute(impl.Attributes, "selective_checking") ||
+ QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "selective_checking")) {
+
+ var startPoints = new List<Block>();
+ foreach (var b in impl.Blocks) {
+ foreach (Cmd c in b.Cmds) {
+ var p = c as PredicateCmd;
+ if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "start_checking_here")) {
+ startPoints.Add(b);
+ break;
+ }
+ }
+ }
+
+ // Compute the set of blocks reachable from blocks containing "start_checking_here"
+ var blocksToCheck = new HashSet<Block>();
+ foreach (var b in startPoints) {
+ var todo = new Stack<Block>();
+ var wasThere = blocksToCheck.Contains(b);
+ todo.Push(b);
+ while (todo.Count > 0) {
+ var x = todo.Pop();
+ if (blocksToCheck.Contains(x)) continue;
+ blocksToCheck.Add(x);
+ var ex = x.TransferCmd as GotoCmd;
+ if (ex != null)
+ foreach (Block e in ex.labelTargets)
+ todo.Push(e);
+ }
+ if (!wasThere) blocksToCheck.Remove(b);
+ }
+
+ // Convert asserts to assumes in "unreachable" blocks, as well as in portions of blocks before we reach "start_checking_here"
+ foreach (var b in impl.Blocks) {
+ if (blocksToCheck.Contains(b)) continue; // All reachable blocks must be checked in their entirety, so don't change anything
+ var newCmds = new List<Cmd>();
+ var copyMode = false;
+ foreach (Cmd c in b.Cmds) {
+ var p = c as PredicateCmd;
+ if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "start_checking_here"))
+ copyMode = true;
+ var asrt = c as AssertCmd;
+ if (copyMode || asrt == null)
+ newCmds.Add(c);
+ else
+ newCmds.Add(AssertTurnedIntoAssume(asrt));
+ }
+
+ b.Cmds = newCmds;
+ }
+ }
+ }
+
+ // Used by stratified inlining
+ protected virtual void addExitAssert(string implName, Block exitBlock)
+ {
+ }
+
+ public virtual Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
+ {
+ // Construct the set of inlined procs in the original program
+ var inlinedProcs = new HashSet<string>();
+ foreach (var proc in program.Procedures)
+ {
+ if (!(proc is LoopProcedure))
+ {
+ inlinedProcs.Add(proc.Name);
+ }
+ }
+
+ return extractLoopTraceRec(
+ new CalleeCounterexampleInfo(cex, new List<object>()),
+ mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample;
+ }
+
+ protected CalleeCounterexampleInfo extractLoopTraceRec(
+ CalleeCounterexampleInfo cexInfo, string currProc,
+ HashSet<string> inlinedProcs,
+ Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
+ {
+ Contract.Requires(currProc != null);
+ if (cexInfo.counterexample == null) return cexInfo;
+
+ var cex = cexInfo.counterexample;
+ // Go through all blocks in the trace, map them back to blocks in the original program (if there is one)
+ var ret = cex.Clone();
+ ret.Trace = new List<Block>();
+ ret.calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
+
+ for (int numBlock = 0; numBlock < cex.Trace.Count; numBlock ++ )
+ {
+ Block block = cex.Trace[numBlock];
+ var origBlock = elGetBlock(currProc, block, extractLoopMappingInfo);
+ if (origBlock != null) ret.Trace.Add(origBlock);
+ var callCnt = 1;
+ for (int numInstr = 0; numInstr < block.Cmds.Count; numInstr ++) {
+ Cmd cmd = block.Cmds[numInstr];
+ var loc = new TraceLocation(numBlock, numInstr);
+ if (!cex.calleeCounterexamples.ContainsKey(loc))
+ {
+ if (getCallee(cex.getTraceCmd(loc), inlinedProcs) != null) callCnt++;
+ continue;
+ }
+ string callee = cex.getCalledProcName(cex.getTraceCmd(loc));
+ Contract.Assert(callee != null);
+ var calleeTrace = cex.calleeCounterexamples[loc];
+ Debug.Assert(calleeTrace != null);
+
+ var origTrace = extractLoopTraceRec(calleeTrace, callee, inlinedProcs, extractLoopMappingInfo);
+
+ if (elIsLoop(callee))
+ {
+ // Absorb the trace into the current trace
+
+ int currLen = ret.Trace.Count;
+ ret.Trace.AddRange(origTrace.counterexample.Trace);
+
+ foreach (var kvp in origTrace.counterexample.calleeCounterexamples)
+ {
+ var newloc = new TraceLocation(kvp.Key.numBlock + currLen, kvp.Key.numInstr);
+ ret.calleeCounterexamples.Add(newloc, kvp.Value);
+ }
+
+ }
+ else
+ {
+ var origLoc = new TraceLocation(ret.Trace.Count - 1, getCallCmdPosition(origBlock, callCnt, inlinedProcs, callee));
+ ret.calleeCounterexamples.Add(origLoc, origTrace);
+ callCnt++;
+ }
+ }
+ }
+ return new CalleeCounterexampleInfo(ret, cexInfo.args);
+ }
+
+ // return the position of the i^th CallCmd in the block (count only those Calls that call a procedure in inlinedProcs).
+ // Assert failure if there isn't any.
+ // Assert that the CallCmd found calls "callee"
+ private int getCallCmdPosition(Block block, int i, HashSet<string> inlinedProcs, string callee)
+ {
+ Debug.Assert(i >= 1);
+ for (int pos = 0; pos < block.Cmds.Count; pos++)
+ {
+ Cmd cmd = block.Cmds[pos];
+ string procCalled = getCallee(cmd, inlinedProcs);
+
+ if (procCalled != null)
+ {
+ if (i == 1)
+ {
+ Debug.Assert(procCalled == callee);
+ return pos;
+ }
+ i--;
+ }
+ }
+
+ Debug.Assert(false, "Didn't find the i^th call cmd");
+ return -1;
+ }
+
+ private string getCallee(Cmd cmd, HashSet<string> inlinedProcs)
+ {
+ string procCalled = null;
+ if (cmd is CallCmd)
+ {
+ var cc = (CallCmd)cmd;
+ if (inlinedProcs.Contains(cc.Proc.Name))
+ {
+ procCalled = cc.Proc.Name;
+ }
+ }
+
+ if (cmd is AssumeCmd)
+ {
+ var expr = (cmd as AssumeCmd).Expr as NAryExpr;
+ if (expr != null)
+ {
+ if (inlinedProcs.Contains(expr.Fun.FunctionName))
+ {
+ procCalled = expr.Fun.FunctionName;
+ }
+ }
+ }
+ return procCalled;
+ }
+
+ protected virtual bool elIsLoop(string procname)
+ {
+ return false;
+ }
+
+ private Block elGetBlock(string procname, Block block, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
+ {
+ Contract.Requires(procname != null);
+
+ if (!extractLoopMappingInfo.ContainsKey(procname))
+ return block;
+
+ if (!extractLoopMappingInfo[procname].ContainsKey(block.Label))
+ return null;
+
+ return extractLoopMappingInfo[procname][block.Label];
+ }
+
+ static Counterexample TraceCounterexample(
+ Block/*!*/ b, Hashtable/*!*/ traceNodes, List<Block>/*!*/ trace, Model errModel, ModelViewInfo mvInfo,
+ Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap,
+ ProverContext/*!*/ context,
+ Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples)
+ {
+ Contract.Requires(b != null);
+ Contract.Requires(traceNodes != null);
+ Contract.Requires(trace != null);
+ Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap));
+ Contract.Requires(context != null);
+ Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples));
+ // After translation, all potential errors come from asserts.
+
+ while (true)
+ {
+ List<Cmd> cmds = b.Cmds;
+ Contract.Assert(cmds != null);
+ TransferCmd transferCmd = cce.NonNull(b.TransferCmd);
+ for (int i = 0; i < cmds.Count; i++)
+ {
+ Cmd cmd = cce.NonNull(cmds[i]);
+
+ // Skip if 'cmd' not contained in the trace or not an assert
+ if (cmd is AssertCmd && traceNodes.Contains(cmd))
+ {
+ Counterexample newCounterexample = AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, errModel, mvInfo, context);
+ Contract.Assert(newCounterexample != null);
+ newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
+ return newCounterexample;
+ }
+ }
+
+ GotoCmd gotoCmd = transferCmd as GotoCmd;
+ if (gotoCmd == null) return null;
+ Block foundBlock = null;
+ foreach (Block bb in cce.NonNull(gotoCmd.labelTargets))
+ {
+ Contract.Assert(bb != null);
+ if (traceNodes.Contains(bb))
+ {
+ foundBlock = bb;
+ break;
+ }
+ }
+ if (foundBlock == null) return null;
+ trace.Add(foundBlock);
+ b = foundBlock;
+ }
+ }
+
+ public static Counterexample AssertCmdToCounterexample(AssertCmd cmd, TransferCmd transferCmd, List<Block> trace, Model errModel, ModelViewInfo mvInfo, ProverContext context)
+ {
+ Contract.Requires(cmd != null);
+ Contract.Requires(transferCmd != null);
+ Contract.Requires(trace != null);
+ Contract.Requires(context != null);
+ Contract.Ensures(Contract.Result<Counterexample>() != null);
+
+ List<string> relatedInformation = new List<string>();
+
+ // See if it is a special assert inserted in translation
+ if (cmd is AssertRequiresCmd)
+ {
+ AssertRequiresCmd assertCmd = (AssertRequiresCmd)cmd;
+ Contract.Assert(assertCmd != null);
+ CallCounterexample cc = new CallCounterexample(trace, assertCmd.Call, assertCmd.Requires, errModel, mvInfo, context, assertCmd.Checksum);
+ cc.relatedInformation = relatedInformation;
+ return cc;
+ }
+ else if (cmd is AssertEnsuresCmd)
+ {
+ AssertEnsuresCmd assertCmd = (AssertEnsuresCmd)cmd;
+ Contract.Assert(assertCmd != null);
+ ReturnCounterexample rc = new ReturnCounterexample(trace, transferCmd, assertCmd.Ensures, errModel, mvInfo, context, cmd.Checksum);
+ rc.relatedInformation = relatedInformation;
+ return rc;
+ }
+ else
+ {
+ AssertCounterexample ac = new AssertCounterexample(trace, (AssertCmd)cmd, errModel, mvInfo, context);
+ ac.relatedInformation = relatedInformation;
+ return ac;
+ }
+ }
+
+ /// <summary>
+ /// Returns a clone of "cex", but with the location stored in "cex" replaced by those from "assrt".
+ /// </summary>
+ public static Counterexample AssertCmdToCloneCounterexample(AssertCmd assrt, Counterexample cex) {
+ Contract.Requires(assrt != null);
+ Contract.Requires(cex != null);
+ Contract.Ensures(Contract.Result<Counterexample>() != null);
+
+ List<string> relatedInformation = new List<string>();
+
+ Counterexample cc;
+ if (assrt is AssertRequiresCmd) {
+ var aa = (AssertRequiresCmd)assrt;
+ cc = new CallCounterexample(cex.Trace, aa.Call, aa.Requires, cex.Model, cex.MvInfo, cex.Context, aa.Checksum);
+ } else if (assrt is AssertEnsuresCmd && cex is ReturnCounterexample) {
+ var aa = (AssertEnsuresCmd)assrt;
+ var oldCex = (ReturnCounterexample)cex;
+ cc = new ReturnCounterexample(cex.Trace, oldCex.FailingReturn, aa.Ensures, cex.Model, cex.MvInfo, cex.Context, aa.Checksum);
+ } else {
+ cc = new AssertCounterexample(cex.Trace, assrt, cex.Model, cex.MvInfo, cex.Context);
+ }
+ cc.relatedInformation = relatedInformation;
+ return cc;
+ }
+
+ static VCExpr LetVC(Block startBlock,
+ VCExpr controlFlowVariableExpr,
+ Dictionary<int, Absy> label2absy,
+ ProverContext proverCtxt,
+ out int assertionCount) {
+ Contract.Requires(startBlock != null);
+ Contract.Requires(proverCtxt != null);
+
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ Hashtable/*<Block, LetVariable!>*/ blockVariables = new Hashtable/*<Block, LetVariable!!>*/();
+ List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
+ VCExpr startCorrect = LetVC(startBlock, controlFlowVariableExpr, label2absy, blockVariables, bindings, proverCtxt, out assertionCount);
+ return proverCtxt.ExprGen.Let(bindings, startCorrect);
+ }
+
+ static VCExpr LetVCIterative(List<Block> blocks,
+ VCExpr controlFlowVariableExpr,
+ Dictionary<int, Absy> label2absy,
+ ProverContext proverCtxt,
+ out int assertionCount,
+ bool isPositiveContext = true)
+ {
+ Contract.Requires(blocks != null);
+ Contract.Requires(proverCtxt != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ assertionCount = 0;
+
+ Graph<Block> dag = new Graph<Block>();
+ dag.AddSource(blocks[0]);
+ foreach (Block b in blocks) {
+ GotoCmd gtc = b.TransferCmd as GotoCmd;
+ if (gtc != null) {
+ Contract.Assume(gtc.labelTargets != null);
+ foreach (Block dest in gtc.labelTargets) {
+ Contract.Assert(dest != null);
+ dag.AddEdge(dest, b);
+ }
+ }
+ }
+ IEnumerable sortedNodes = dag.TopologicalSort();
+ Contract.Assert(sortedNodes != null);
+
+ Dictionary<Block, VCExprVar> blockVariables = new Dictionary<Block, VCExprVar>();
+ List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
+ VCExpressionGenerator gen = proverCtxt.ExprGen;
+ Contract.Assert(gen != null);
+ foreach (Block block in sortedNodes) {
+ VCExpr SuccCorrect;
+ GotoCmd gotocmd = block.TransferCmd as GotoCmd;
+ if (gotocmd == null) {
+ ReturnExprCmd re = block.TransferCmd as ReturnExprCmd;
+ if (re == null) {
+ SuccCorrect = VCExpressionGenerator.True;
+ }
+ else {
+ SuccCorrect = proverCtxt.BoogieExprTranslator.Translate(re.Expr);
+ if (isPositiveContext)
+ {
+ SuccCorrect = gen.Not(SuccCorrect);
+ }
+ }
+ }
+ else {
+ Contract.Assert(gotocmd.labelTargets != null);
+ List<VCExpr> SuccCorrectVars = new List<VCExpr>(gotocmd.labelTargets.Count);
+ foreach (Block successor in gotocmd.labelTargets) {
+ Contract.Assert(successor != null);
+ VCExpr s = blockVariables[successor];
+ if (controlFlowVariableExpr != null) {
+ VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
+ VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
+ s = gen.Implies(controlTransferExpr, s);
+ }
+ SuccCorrectVars.Add(s);
+ }
+ SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars);
+ }
+
+ VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr, isPositiveContext);
+ VCExpr vc = Wlp.Block(block, SuccCorrect, context);
+ assertionCount += context.AssertionCount;
+
+ VCExprVar v = gen.Variable(block.Label + "_correct", Bpl.Type.Bool);
+ bindings.Add(gen.LetBinding(v, vc));
+ blockVariables.Add(block, v);
+ }
+
+ return proverCtxt.ExprGen.Let(bindings, blockVariables[blocks[0]]);
+ }
+
+ static VCExpr LetVC(Block block,
+ VCExpr controlFlowVariableExpr,
+ Dictionary<int, Absy> label2absy,
+ Hashtable/*<Block, VCExprVar!>*/ blockVariables,
+ List<VCExprLetBinding/*!*/>/*!*/ bindings,
+ ProverContext proverCtxt,
+ out int assertionCount)
+ {
+ Contract.Requires(block != null);
+ Contract.Requires(blockVariables!= null);
+ Contract.Requires(cce.NonNullElements(bindings));
+ Contract.Requires(proverCtxt != null);
+
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ assertionCount = 0;
+
+ VCExpressionGenerator gen = proverCtxt.ExprGen;
+ Contract.Assert(gen != null);
+ VCExprVar v = (VCExprVar)blockVariables[block];
+ if (v == null) {
+ /*
+ * For block A (= block), generate:
+ * LET_binding A_correct = wp(A_body, (/\ S \in Successors(A) :: S_correct))
+ * with the side effect of adding the let bindings to "bindings" for any
+ * successor not yet visited.
+ */
+ VCExpr SuccCorrect;
+ GotoCmd gotocmd = block.TransferCmd as GotoCmd;
+ if (gotocmd == null) {
+ ReturnExprCmd re = block.TransferCmd as ReturnExprCmd;
+ if (re == null) {
+ SuccCorrect = VCExpressionGenerator.True;
+ } else {
+ SuccCorrect = proverCtxt.BoogieExprTranslator.Translate(re.Expr);
+ }
+ } else {
+ Contract.Assert( gotocmd.labelTargets != null);
+ List<VCExpr> SuccCorrectVars = new List<VCExpr>(gotocmd.labelTargets.Count);
+ foreach (Block successor in gotocmd.labelTargets) {
+ Contract.Assert(successor != null);
+ int ac;
+ VCExpr s = LetVC(successor, controlFlowVariableExpr, label2absy, blockVariables, bindings, proverCtxt, out ac);
+ assertionCount += ac;
+ if (controlFlowVariableExpr != null)
+ {
+ VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
+ VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
+ s = gen.Implies(controlTransferExpr, s);
+ }
+ SuccCorrectVars.Add(s);
+ }
+ SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars);
+ }
+
+
+ VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr);
+ VCExpr vc = Wlp.Block(block, SuccCorrect, context);
+ assertionCount += context.AssertionCount;
+
+ v = gen.Variable(block.Label + "_correct", Bpl.Type.Bool);
+ bindings.Add(gen.LetBinding(v, vc));
+ blockVariables.Add(block, v);
+ }
+ return v;
+ }
+
+ static VCExpr DagVC(Block block,
+ VCExpr controlFlowVariableExpr,
+ Dictionary<int, Absy> label2absy,
+ Hashtable/*<Block, VCExpr!>*/ blockEquations,
+ ProverContext proverCtxt,
+ out int assertionCount)
+ {
+ Contract.Requires(block != null);
+ Contract.Requires(label2absy != null);
+ Contract.Requires(blockEquations != null);
+ Contract.Requires(proverCtxt != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ assertionCount = 0;
+ VCExpressionGenerator gen = proverCtxt.ExprGen;
+ Contract.Assert(gen != null);
+ VCExpr vc = (VCExpr)blockEquations[block];
+ if (vc != null) {
+ return vc;
+ }
+
+ /*
+ * For block A (= block), generate:
+ * wp(A_body, (/\ S \in Successors(A) :: DagVC(S)))
+ */
+ VCExpr SuccCorrect = null;
+ GotoCmd gotocmd = block.TransferCmd as GotoCmd;
+ if (gotocmd != null)
+ {
+ foreach (Block successor in cce.NonNull(gotocmd.labelTargets)) {
+ Contract.Assert(successor != null);
+ int ac;
+ VCExpr c = DagVC(successor, controlFlowVariableExpr, label2absy, blockEquations, proverCtxt, out ac);
+ assertionCount += ac;
+ if (controlFlowVariableExpr != null) {
+ VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
+ VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
+ c = gen.Implies(controlTransferExpr, c);
+ }
+ SuccCorrect = SuccCorrect == null ? c : gen.And(SuccCorrect, c);
+ }
+ }
+ if (SuccCorrect == null) {
+ SuccCorrect = VCExpressionGenerator.True;
+ }
+
+ VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr);
+ vc = Wlp.Block(block, SuccCorrect, context);
+ assertionCount += context.AssertionCount;
+
+ // gen.MarkAsSharedFormula(vc); PR: don't know yet what to do with this guy
+
+ blockEquations.Add(block, vc);
+ return vc;
+ }
+
+ static VCExpr FlatBlockVC(Implementation impl,
+ Dictionary<int, Absy> label2absy,
+ bool local, bool reach, bool doomed,
+ ProverContext proverCtxt,
+ out int assertionCount)
+ {
+ Contract.Requires(impl != null);
+ Contract.Requires(label2absy != null);
+ Contract.Requires(proverCtxt != null);
+ Contract.Requires( !local || !reach); // "reach" must be false for local
+
+ VCExpressionGenerator gen = proverCtxt.ExprGen;
+ Contract.Assert(gen != null);
+ Hashtable/* Block --> VCExprVar */ BlkCorrect = BlockVariableMap(impl.Blocks, "_correct", gen);
+ Hashtable/* Block --> VCExprVar */ BlkReached = reach ? BlockVariableMap(impl.Blocks, "_reached", gen) : null;
+
+ List<Block> blocks = impl.Blocks;
+ Contract.Assert(blocks != null);
+ // block sorting is now done on the VCExpr
+ // if (!local && (cce.NonNull(CommandLineOptions.Clo.TheProverFactory).NeedsBlockSorting) {
+ // blocks = SortBlocks(blocks);
+ // }
+
+ VCExpr proofObligation;
+ if (!local) {
+ proofObligation = cce.NonNull((VCExprVar)BlkCorrect[impl.Blocks[0]]);
+ } else {
+ List<VCExpr> conjuncts = new List<VCExpr>(blocks.Count);
+ foreach (Block b in blocks) {Contract.Assert(b != null);
+ VCExpr v = cce.NonNull((VCExprVar)BlkCorrect[b]);
+ conjuncts.Add(v);
+ }
+ proofObligation = gen.NAry(VCExpressionGenerator.AndOp, conjuncts);
+ }
+
+ VCContext context = new VCContext(label2absy, proverCtxt);
+ Contract.Assert(context != null);
+
+ List<VCExprLetBinding> programSemantics = new List<VCExprLetBinding>(blocks.Count);
+ foreach (Block b in blocks) {Contract.Assert(b != null);
+ /*
+ * In block mode,
+ * For a return block A, generate:
+ * A_correct <== wp(A_body, true) [post-condition has been translated into an assert]
+ * For all other blocks, generate:
+ * A_correct <== wp(A_body, (/\ S \in Successors(A) :: S_correct))
+ *
+ * In doomed mode, proceed as in block mode, except for a return block A, generate:
+ * A_correct <== wp(A_body, false) [post-condition has been translated into an assert]
+ *
+ * In block reach mode, the wp(A_body,...) in the equations above change to:
+ * A_reached ==> wp(A_body,...)
+ * and the conjunction above changes to:
+ * (/\ S \in Successors(A) :: S_correct \/ (\/ T \in Successors(A) && T != S :: T_reached))
+ *
+ * In local mode, generate:
+ * A_correct <== wp(A_body, true)
+ */
+ VCExpr SuccCorrect;
+ if (local) {
+ SuccCorrect = VCExpressionGenerator.True;
+ } else {
+ SuccCorrect = SuccessorsCorrect(b, BlkCorrect, BlkReached, doomed, gen);
+ }
+
+ VCExpr wlp = Wlp.Block(b, SuccCorrect, context);
+ if (BlkReached != null) {
+ wlp = gen.Implies(cce.NonNull((VCExprVar)BlkReached[b]), wlp);
+ }
+
+ VCExprVar okVar = cce.NonNull((VCExprVar)BlkCorrect[b]);
+ VCExprLetBinding binding = gen.LetBinding(okVar, wlp);
+ programSemantics.Add(binding);
+ }
+
+ assertionCount = context.AssertionCount;
+ return gen.Let(programSemantics, proofObligation);
+ }
+
+ private static Hashtable/* Block --> VCExprVar */ BlockVariableMap(List<Block/*!*/>/*!*/ blocks, string suffix,
+ Microsoft.Boogie.VCExpressionGenerator gen) {
+ Contract.Requires(cce.NonNullElements(blocks));
+ Contract.Requires(suffix != null);
+ Contract.Requires(gen != null);
+ Contract.Ensures(Contract.Result<Hashtable>() != null);
+
+ Hashtable/* Block --> VCExprVar */ map = new Hashtable/* Block --> (Let)Variable */();
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ VCExprVar v = gen.Variable(b.Label + suffix, Bpl.Type.Bool);
+ Contract.Assert(v != null);
+ map.Add(b, v);
+ }
+ return map;
+ }
+
+ private static VCExpr SuccessorsCorrect(
+ Block b,
+ Hashtable/* Block --> VCExprVar */ BlkCorrect,
+ Hashtable/* Block --> VCExprVar */ BlkReached,
+ bool doomed,
+ Microsoft.Boogie.VCExpressionGenerator gen) {
+ Contract.Requires(b != null);
+ Contract.Requires(BlkCorrect != null);
+ Contract.Requires(gen != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ VCExpr SuccCorrect = null;
+ GotoCmd gotocmd = b.TransferCmd as GotoCmd;
+ if (gotocmd != null) {
+ foreach (Block successor in cce.NonNull(gotocmd.labelTargets)) {
+ Contract.Assert(successor != null);
+ // c := S_correct
+ VCExpr c = (VCExprVar)BlkCorrect[successor];
+ Contract.Assert(c != null);
+ if (BlkReached != null) {
+ // c := S_correct \/ Sibling0_reached \/ Sibling1_reached \/ ...;
+ foreach (Block successorSibling in gotocmd.labelTargets) {
+ Contract.Assert(successorSibling != null);
+ if (successorSibling != successor) {
+ c = gen.Or(c, cce.NonNull((VCExprVar)BlkReached[successorSibling]));
+ }
+ }
+ }
+ SuccCorrect = SuccCorrect == null ? c : gen.And(SuccCorrect, c);
+ }
+ }
+ if (SuccCorrect == null) {
+ return VCExpressionGenerator.True;
+ } else if (doomed) {
+ return VCExpressionGenerator.False;
+ } else {
+ return SuccCorrect;
+ }
+ }
+
+ static VCExpr NestedBlockVC(Implementation impl,
+ Dictionary<int, Absy> label2absy,
+ bool reach,
+ ProverContext proverCtxt,
+ out int assertionCount){
+ Contract.Requires(impl != null);
+ Contract.Requires(label2absy != null);
+ Contract.Requires(proverCtxt != null);
+ Contract.Requires( impl.Blocks.Count != 0);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ VCExpressionGenerator gen = proverCtxt.ExprGen;
+ Contract.Assert(gen != null);
+ Graph<Block> g = Program.GraphFromImpl(impl);
+
+ Hashtable/* Block --> VCExprVar */ BlkCorrect = BlockVariableMap(impl.Blocks, "_correct", gen);
+ Hashtable/* Block --> VCExprVar */ BlkReached = reach ? BlockVariableMap(impl.Blocks, "_reached", gen) : null;
+
+ Block startBlock = cce.NonNull( impl.Blocks[0]);
+ VCExpr proofObligation = (VCExprVar)BlkCorrect[startBlock];
+ Contract.Assert(proofObligation != null);
+ VCContext context = new VCContext(label2absy, proverCtxt);
+
+ Hashtable/*Block->int*/ totalOrder = new Hashtable/*Block->int*/();
+ {
+ List<Block> blocks = impl.Blocks;
+
+ // block sorting is now done on the VCExpr
+ // if (((!)CommandLineOptions.Clo.TheProverFactory).NeedsBlockSorting) {
+ // blocks = SortBlocks(blocks);
+ // }
+ int i = 0;
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ totalOrder[b] = i;
+ i++;
+ }
+ }
+
+ VCExprLetBinding programSemantics = NestedBlockEquation(cce.NonNull(impl.Blocks[0]), BlkCorrect, BlkReached, totalOrder, context, g, gen);
+ List<VCExprLetBinding> ps = new List<VCExprLetBinding>(1);
+ ps.Add(programSemantics);
+
+ assertionCount = context.AssertionCount;
+ return gen.Let(ps, proofObligation);
+ }
+
+ private static VCExprLetBinding NestedBlockEquation(Block b,
+ Hashtable/*Block-->VCExprVar*/ BlkCorrect,
+ Hashtable/*Block-->VCExprVar*/ BlkReached,
+ Hashtable/*Block->int*/ totalOrder,
+ VCContext context,
+ Graph<Block> g,
+ Microsoft.Boogie.VCExpressionGenerator gen) {
+ Contract.Requires(b != null);
+ Contract.Requires(BlkCorrect != null);
+ Contract.Requires(totalOrder != null);
+ Contract.Requires(g != null);
+ Contract.Requires(context != null);
+
+ Contract.Ensures(Contract.Result<VCExprLetBinding>() != null);
+
+ /*
+ * For a block b, return:
+ * LET_BINDING b_correct = wp(b_body, X)
+ * where X is:
+ * LET (THOSE d \in DirectDominates(b) :: BlockEquation(d))
+ * IN (/\ s \in Successors(b) :: s_correct)
+ *
+ * When the VC-expression generator does not support LET expresions, this
+ * will eventually turn into:
+ * b_correct <== wp(b_body, X)
+ * where X is:
+ * (/\ s \in Successors(b) :: s_correct)
+ * <==
+ * (/\ d \in DirectDominatees(b) :: BlockEquation(d))
+ *
+ * In both cases above, if BlkReached is non-null, then the wp expression
+ * is instead:
+ * b_reached ==> wp(b_body, X)
+ */
+
+ VCExpr SuccCorrect = SuccessorsCorrect(b, BlkCorrect, null, false, gen);
+ Contract.Assert(SuccCorrect != null);
+
+ List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
+ foreach (Block dominee in GetSortedBlocksImmediatelyDominatedBy(g, b, totalOrder)) {
+ Contract.Assert(dominee != null);
+ VCExprLetBinding c = NestedBlockEquation(dominee, BlkCorrect, BlkReached, totalOrder, context, g, gen);
+ bindings.Add(c);
+ }
+
+ VCExpr X = gen.Let(bindings, SuccCorrect);
+ VCExpr wlp = Wlp.Block(b, X, context);
+ if (BlkReached != null) {
+ wlp = gen.Implies((VCExprVar)BlkReached[b], wlp);
+ Contract.Assert(wlp != null);
+ }
+ VCExprVar okVar = cce.NonNull((VCExprVar)BlkCorrect[b]);
+ return gen.LetBinding(okVar, wlp);
+ }
+
+ /// <summary>
+ /// Returns a list of g.ImmediatelyDominatedBy(b), but in a sorted order, hoping to steer around
+ /// the nondeterminism problems we've been seeing by using just this call.
+ /// </summary>
+ static List<Block/*!*/>/*!*/ GetSortedBlocksImmediatelyDominatedBy(Graph<Block>/*!*/ g, Block/*!*/ b, Hashtable/*Block->int*//*!*/ totalOrder) {
+ Contract.Requires(g != null);
+ Contract.Requires(b != null);
+ Contract.Requires(totalOrder != null);
+ Contract.Ensures(Contract.Result<List<Block>>() != null);
+
+ List<Block> list = new List<Block>();
+ foreach (Block dominee in g.ImmediatelyDominatedBy(b)) {
+ Contract.Assert(dominee != null);
+ list.Add(dominee);
+ }
+ list.Sort(new Comparison<Block>(delegate(Block x, Block y) {
+ return (int)cce.NonNull(totalOrder[x]) - (int)cce.NonNull(totalOrder[y]);
+ }));
+ return list;
+ }
+
+ static VCExpr VCViaStructuredProgram
+ (Implementation impl, Dictionary<int, Absy> label2absy,
+ ProverContext proverCtxt,
+ out int assertionCount)
+ {
+ Contract.Requires(impl != null);
+ Contract.Requires(label2absy != null);
+ Contract.Requires(proverCtxt != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ #region Convert block structure back to a "regular expression"
+ RE r = DAG2RE.Transform(cce.NonNull(impl.Blocks[0]));
+ Contract.Assert(r != null);
+ #endregion
+
+ VCContext ctxt = new VCContext(label2absy, proverCtxt);
+ Contract.Assert(ctxt != null);
+ #region Send wlp(program,true) to Simplify
+ var vcexp = Wlp.RegExpr(r, VCExpressionGenerator.True, ctxt);
+ assertionCount = ctxt.AssertionCount;
+ return vcexp;
+ #endregion
+ }
+
+ /// <summary>
+ /// Remove empty blocks reachable from the startBlock of the CFG
+ /// </summary>
+ static void RemoveEmptyBlocksIterative(List<Block> blocks) {
+ // postorder traversal of cfg
+ // noting loop heads in [keep] and
+ // generating token information in [renameInfo]
+ Block startBlock = blocks[0];
+ var postorder = new List<Block>();
+ var keep = new HashSet<Block>();
+ var visited = new HashSet<Block>();
+ var grey = new HashSet<Block>();
+ var stack = new Stack<Block>();
+ Dictionary<Block, Block> renameInfo = new Dictionary<Block, Block>();
+
+ stack.Push(startBlock);
+ visited.Add(startBlock);
+ while (stack.Count != 0) {
+ var curr = stack.Pop();
+ if (grey.Contains(curr)) {
+ postorder.Add(curr);
+
+ // generate renameInfoForStartBlock
+ GotoCmd gtc = curr.TransferCmd as GotoCmd;
+ renameInfo[curr] = null;
+ if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0) {
+ if (curr.Cmds.Count == 0 && curr.tok.IsValid) {
+ renameInfo[curr] = curr;
+ }
+ } else {
+ if (curr.Cmds.Count == 0 || curr == startBlock) {
+ if (curr.tok.IsValid) {
+ renameInfo[curr] = curr;
+ } else {
+ HashSet<Block> successorRenameInfo = new HashSet<Block>();
+ foreach (Block s in gtc.labelTargets) {
+ if (keep.Contains(s)) {
+ successorRenameInfo.Add(null);
+ } else {
+ successorRenameInfo.Add(renameInfo[s]);
+ }
+ }
+ if (successorRenameInfo.Count == 1) {
+ renameInfo[curr] = successorRenameInfo.Single();
+ }
+ }
+ }
+ }
+ // end generate renameInfoForStartBlock
+
+ } else {
+ grey.Add(curr);
+ stack.Push(curr);
+ GotoCmd gtc = curr.TransferCmd as GotoCmd;
+ if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0) continue;
+ foreach (Block s in gtc.labelTargets) {
+ if (!visited.Contains(s)) {
+ visited.Add(s);
+ stack.Push(s);
+ } else if (grey.Contains(s) && !postorder.Contains(s)) { // s is a loop head
+ keep.Add(s);
+ }
+ }
+ }
+ }
+ keep.Add(startBlock);
+
+ foreach (Block b in postorder) {
+ if (!keep.Contains(b) && b.Cmds.Count == 0) {
+ GotoCmd bGtc = b.TransferCmd as GotoCmd;
+ foreach (Block p in b.Predecessors) {
+ GotoCmd pGtc = p.TransferCmd as GotoCmd;
+ Contract.Assert(pGtc != null);
+ pGtc.labelTargets.Remove(b);
+ pGtc.labelNames.Remove(b.Label);
+ }
+ if (bGtc == null || bGtc.labelTargets == null || bGtc.labelTargets.Count == 0) {
+ continue;
+ }
+
+ List<Block> successors = bGtc.labelTargets;
+
+ // Try to push token information if possible
+ if (b.tok.IsValid && successors.Count == 1 && b != renameInfo[startBlock]) {
+ var s = successors.Single();
+ if (!s.tok.IsValid) {
+ foreach (Block p in s.Predecessors) {
+ if (p != b) {
+ GotoCmd pGtc = p.TransferCmd as GotoCmd;
+ Contract.Assert(pGtc != null);
+ pGtc.labelTargets.Remove(s);
+ pGtc.labelNames.Remove(s.Label);
+ pGtc.labelTargets.Add(s);
+ pGtc.labelNames.Add(b.Label);
+ }
+ }
+ s.tok = b.tok;
+ s.Label = b.Label;
+ }
+ }
+
+ foreach (Block p in b.Predecessors) {
+ GotoCmd pGtc = p.TransferCmd as GotoCmd;
+ Contract.Assert(pGtc != null);
+ foreach (Block s in successors) {
+ if (!pGtc.labelTargets.Contains(s)) {
+ pGtc.labelTargets.Add(s);
+ pGtc.labelNames.Add(s.Label);
+ }
+ }
+ }
+ }
+ }
+
+ if (!startBlock.tok.IsValid && startBlock.Cmds.All(c => c is AssumeCmd)) {
+ if (renameInfo[startBlock] != null) {
+ startBlock.tok = renameInfo[startBlock].tok;
+ startBlock.Label = renameInfo[startBlock].Label;
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// Remove the empty blocks reachable from the block.
+ /// It changes the visiting state of the blocks, so that if you want to visit again the blocks, you have to reset them...
+ /// </summary>
+ static List<Block> RemoveEmptyBlocks(Block b) {
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<List<Block>>() != null);
+
+ Contract.Assert(b.TraversingStatus == Block.VisitState.ToVisit);
+ Block renameInfo;
+ List<Block> retVal = removeEmptyBlocksWorker(b, true, out renameInfo);
+ if (renameInfo != null && !b.tok.IsValid) {
+ bool onlyAssumes = true;
+ foreach (Cmd c in b.Cmds) {
+ if (!(c is AssumeCmd)) {
+ onlyAssumes = false;
+ break;
+ }
+ }
+ if (onlyAssumes) {
+ b.tok = renameInfo.tok;
+ b.Label = renameInfo.Label;
+ }
+ }
+ return retVal;
+ }
+
+ /// <summary>
+ /// For every not-yet-visited block n reachable from b, change n's successors to skip empty nodes.
+ /// Return the *set* of blocks reachable from b without passing through a nonempty block.
+ /// The target of any backedge is counted as a nonempty block.
+ /// If renameInfoForStartBlock is non-null, it denotes an empty block with location information, and that
+ /// information would be appropriate to display
+ /// </summary>
+ private static List<Block> removeEmptyBlocksWorker(Block b, bool startNode, out Block renameInfoForStartBlock)
+ {
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.ValueAtReturn(out renameInfoForStartBlock) == null || Contract.ValueAtReturn(out renameInfoForStartBlock).tok.IsValid);
+ // ensures: b in result ==> renameInfoForStartBlock == null;
+
+ renameInfoForStartBlock = null;
+ List<Block> bs = new List<Block>();
+ GotoCmd gtc = b.TransferCmd as GotoCmd;
+
+ // b has no successors
+ if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0)
+ {
+ if (b.Cmds.Count != 0){ // only empty blocks are removed...
+ bs.Add(b);
+ } else if (b.tok.IsValid) {
+ renameInfoForStartBlock = b;
+ }
+ return bs;
+ }
+ else if (b.TraversingStatus == Block.VisitState.ToVisit) // if b has some successors and we have not seen it so far...
+ {
+ b.TraversingStatus = Block.VisitState.BeingVisited;
+
+ // Before recursing down to successors, make a sobering observation:
+ // If b has no commands and is not the start node, then it will see
+ // extinction (because it will not be included in the "return setOfSuccessors"
+ // statement below). In that case, if b has a location, then the location
+ // information would be lost. Hence, make an attempt to save the location
+ // by pushing the location onto b's successor. This can be done if (0) b has
+ // exactly one successor, (1) that successor has no location of its own, and
+ // (2) that successor has no other predecessors.
+ if (b.Cmds.Count == 0 && !startNode) {
+ // b is about to become extinct; try to save its name and location, if possible
+ if (b.tok.IsValid && gtc.labelTargets.Count == 1) {
+ Block succ = cce.NonNull(gtc.labelTargets[0]);
+ if (!succ.tok.IsValid && succ.Predecessors.Count == 1) {
+ succ.tok = b.tok;
+ succ.Label = b.Label;
+ }
+ }
+ }
+
+ // recursively call this method on each successor
+ // merge result into a *set* of blocks
+ HashSet<Block> mergedSuccessors = new HashSet<Block>();
+ int m = 0; // in the following loop, set renameInfoForStartBlock to the value that all recursive calls agree on, if possible; otherwise, null
+ foreach (Block dest in gtc.labelTargets){Contract.Assert(dest != null);
+ Block renameInfo;
+ List<Block> ys = removeEmptyBlocksWorker(dest, false, out renameInfo);
+ Contract.Assert(ys != null);
+ if (m == 0) {
+ renameInfoForStartBlock = renameInfo;
+ } else if (renameInfoForStartBlock != renameInfo) {
+ renameInfoForStartBlock = null;
+ }
+ foreach (Block successor in ys){
+ if (!mergedSuccessors.Contains(successor))
+ mergedSuccessors.Add(successor);
+ }
+ m++;
+ }
+ b.TraversingStatus = Block.VisitState.AlreadyVisited;
+
+ List<Block> setOfSuccessors = new List<Block>();
+ foreach (Block d in mergedSuccessors)
+ setOfSuccessors.Add(d);
+ if (b.Cmds.Count == 0 && !startNode) {
+ // b is about to become extinct
+ if (b.tok.IsValid) {
+ renameInfoForStartBlock = b;
+ }
+ return setOfSuccessors;
+ }
+ // otherwise, update the list of successors of b to be the blocks in setOfSuccessors
+ gtc.labelTargets = setOfSuccessors;
+ gtc.labelNames = new List<String>();
+ foreach (Block d in setOfSuccessors){
+ Contract.Assert(d != null);
+ gtc.labelNames.Add(d.Label);}
+ if (!startNode) {
+ renameInfoForStartBlock = null;
+ }
+ return new List<Block> { b };
+ }
+ else // b has some successors, but we are already visiting it, or we have already visited it...
+ {
+ return new List<Block> { b };
+ }
+ }
+
+ static void DumpMap(Hashtable /*Variable->Expr*/ map) {
+ Contract.Requires(map != null);
+ foreach (DictionaryEntry de in map) {
+ Variable v = (Variable)de.Key;
+ Contract.Assert(v != null);
+ Expr e = (Expr)de.Value;
+ Contract.Assert(e != null);
+ Console.Write(" ");
+ v.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 0);
+ Console.Write(" --> ");
+ e.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false));
+ Console.WriteLine();
+ }
+ }
+ }
+}
diff --git a/Source/VCGeneration/VCGeneration.csproj b/Source/VCGeneration/VCGeneration.csproj
index 74e1eef8..9bd3fb1a 100644
--- a/Source/VCGeneration/VCGeneration.csproj
+++ b/Source/VCGeneration/VCGeneration.csproj
@@ -1,230 +1,230 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>9.0.21022</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>VCGeneration</RootNamespace>
- <AssemblyName>VCGeneration</AssemblyName>
- <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
- <FileAlignment>512</FileAlignment>
- <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
- <SignAssembly>true</SignAssembly>
- <AssemblyOriginatorKeyFile>..\InterimKey.snk</AssemblyOriginatorKeyFile>
- <FileUpgradeFlags>
- </FileUpgradeFlags>
- <OldToolsVersion>3.5</OldToolsVersion>
- <UpgradeBackupLocation />
- <PublishUrl>publish\</PublishUrl>
- <Install>true</Install>
- <InstallFrom>Disk</InstallFrom>
- <UpdateEnabled>false</UpdateEnabled>
- <UpdateMode>Foreground</UpdateMode>
- <UpdateInterval>7</UpdateInterval>
- <UpdateIntervalUnits>Days</UpdateIntervalUnits>
- <UpdatePeriodically>false</UpdatePeriodically>
- <UpdateRequired>false</UpdateRequired>
- <MapFileExtensions>true</MapFileExtensions>
- <ApplicationRevision>0</ApplicationRevision>
- <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
- <IsWebBootstrapper>false</IsWebBootstrapper>
- <UseApplicationTrust>false</UseApplicationTrust>
- <BootstrapperEnabled>true</BootstrapperEnabled>
- <TargetFrameworkProfile Condition=" '$(OS)' == 'Windows_NT'" >Client</TargetFrameworkProfile>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
- <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
- <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
- <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
- <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
- <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
- <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
- <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
- <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
- <CodeContractsContainerAnalysis>False</CodeContractsContainerAnalysis>
- <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
- <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
- <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
- <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
- <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
- <CodeContractsCustomRewriterAssembly>
- </CodeContractsCustomRewriterAssembly>
- <CodeContractsCustomRewriterClass>
- </CodeContractsCustomRewriterClass>
- <CodeContractsLibPaths>
- </CodeContractsLibPaths>
- <CodeContractsExtraRewriteOptions>
- </CodeContractsExtraRewriteOptions>
- <CodeContractsExtraAnalysisOptions>
- </CodeContractsExtraAnalysisOptions>
- <CodeContractsBaseLineFile>
- </CodeContractsBaseLineFile>
- <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
- <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'z3apidebug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\z3apidebug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <CodeAnalysisRuleAssemblies>
- </CodeAnalysisRuleAssemblies>
- <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
- <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>Migrated rules for VCGeneration.ruleset</CodeAnalysisRuleSet>
- <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
- <WarningLevel>4</WarningLevel>
- <Optimize>false</Optimize>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Checked|AnyCPU'">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\Checked\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <CodeAnalysisLogFile>bin\Debug\VCGeneration.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
- <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
- <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
- <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
- <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
- <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
- <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
- <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
- <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
- <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
- <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
- <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
- <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
- <CodeContractsEnumObligations>False</CodeContractsEnumObligations>
- <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
- <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
- <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
- <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
- <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
- <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
- <CodeContractsCustomRewriterAssembly />
- <CodeContractsCustomRewriterClass />
- <CodeContractsLibPaths />
- <CodeContractsExtraRewriteOptions />
- <CodeContractsExtraAnalysisOptions />
- <CodeContractsBaseLineFile />
- <CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
- <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
- <CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
- <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
- <WarningLevel>4</WarningLevel>
- <Optimize>false</Optimize>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'QED|AnyCPU'">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\QED\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="Check.cs" />
- <Compile Include="ConditionGeneration.cs" />
- <Compile Include="Context.cs" />
- <Compile Include="ExprExtensions.cs" />
- <Compile Include="FixedpointVC.cs" />
- <Compile Include="OrderingAxioms.cs" />
- <Compile Include="RPFP.cs" />
- <Compile Include="StratifiedVC.cs" />
- <Compile Include="VC.cs" />
- <Compile Include="..\version.cs" />
- <Compile Include="Wlp.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Basetypes\Basetypes.csproj">
- <Project>{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}</Project>
- <Name>Basetypes</Name>
- </ProjectReference>
- <ProjectReference Include="..\CodeContractsExtender\CodeContractsExtender.csproj">
- <Project>{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}</Project>
- <Name>CodeContractsExtender</Name>
- </ProjectReference>
- <ProjectReference Include="..\Core\Core.csproj">
- <Project>{B230A69C-C466-4065-B9C1-84D80E76D802}</Project>
- <Name>Core</Name>
- </ProjectReference>
- <ProjectReference Include="..\Graph\Graph.csproj">
- <Project>{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}</Project>
- <Name>Graph</Name>
- </ProjectReference>
- <ProjectReference Include="..\Model\Model.csproj">
- <Project>{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}</Project>
- <Name>Model</Name>
- </ProjectReference>
- <ProjectReference Include="..\ParserHelper\ParserHelper.csproj">
- <Project>{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}</Project>
- <Name>ParserHelper</Name>
- </ProjectReference>
- <ProjectReference Include="..\VCExpr\VCExpr.csproj">
- <Project>{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}</Project>
- <Name>VCExpr</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <Folder Include="Properties\" />
- </ItemGroup>
- <ItemGroup>
- <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
- <Visible>False</Visible>
- <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
- <Install>false</Install>
- </BootstrapperPackage>
- <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
- <Visible>False</Visible>
- <ProductName>.NET Framework 3.5 SP1</ProductName>
- <Install>true</Install>
- </BootstrapperPackage>
- <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
- <Visible>False</Visible>
- <ProductName>Windows Installer 3.1</ProductName>
- <Install>true</Install>
- </BootstrapperPackage>
- </ItemGroup>
- <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>VCGeneration</RootNamespace>
+ <AssemblyName>VCGeneration</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\InterimKey.snk</AssemblyOriginatorKeyFile>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <UpgradeBackupLocation />
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ <TargetFrameworkProfile Condition=" '$(OS)' == 'Windows_NT'" >Client</TargetFrameworkProfile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
+ <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
+ <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
+ <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
+ <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
+ <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
+ <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
+ <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
+ <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
+ <CodeContractsContainerAnalysis>False</CodeContractsContainerAnalysis>
+ <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
+ <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
+ <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
+ <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
+ <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
+ <CodeContractsCustomRewriterAssembly>
+ </CodeContractsCustomRewriterAssembly>
+ <CodeContractsCustomRewriterClass>
+ </CodeContractsCustomRewriterClass>
+ <CodeContractsLibPaths>
+ </CodeContractsLibPaths>
+ <CodeContractsExtraRewriteOptions>
+ </CodeContractsExtraRewriteOptions>
+ <CodeContractsExtraAnalysisOptions>
+ </CodeContractsExtraAnalysisOptions>
+ <CodeContractsBaseLineFile>
+ </CodeContractsBaseLineFile>
+ <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
+ <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'z3apidebug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\z3apidebug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisRuleAssemblies>
+ </CodeAnalysisRuleAssemblies>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>Migrated rules for VCGeneration.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
+ <WarningLevel>4</WarningLevel>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Checked|AnyCPU'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\Checked\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisLogFile>bin\Debug\VCGeneration.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
+ <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
+ <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
+ <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
+ <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
+ <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
+ <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
+ <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
+ <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
+ <CodeContractsEnumObligations>False</CodeContractsEnumObligations>
+ <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
+ <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
+ <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
+ <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
+ <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
+ <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
+ <CodeContractsCustomRewriterAssembly />
+ <CodeContractsCustomRewriterClass />
+ <CodeContractsLibPaths />
+ <CodeContractsExtraRewriteOptions />
+ <CodeContractsExtraAnalysisOptions />
+ <CodeContractsBaseLineFile />
+ <CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
+ <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
+ <CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
+ <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
+ <WarningLevel>4</WarningLevel>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'QED|AnyCPU'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\QED\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Check.cs" />
+ <Compile Include="ConditionGeneration.cs" />
+ <Compile Include="Context.cs" />
+ <Compile Include="ExprExtensions.cs" />
+ <Compile Include="FixedpointVC.cs" />
+ <Compile Include="OrderingAxioms.cs" />
+ <Compile Include="RPFP.cs" />
+ <Compile Include="StratifiedVC.cs" />
+ <Compile Include="VC.cs" />
+ <Compile Include="..\version.cs" />
+ <Compile Include="Wlp.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Basetypes\Basetypes.csproj">
+ <Project>{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}</Project>
+ <Name>Basetypes</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\CodeContractsExtender\CodeContractsExtender.csproj">
+ <Project>{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}</Project>
+ <Name>CodeContractsExtender</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Core\Core.csproj">
+ <Project>{B230A69C-C466-4065-B9C1-84D80E76D802}</Project>
+ <Name>Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Graph\Graph.csproj">
+ <Project>{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}</Project>
+ <Name>Graph</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Model\Model.csproj">
+ <Project>{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}</Project>
+ <Name>Model</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\ParserHelper\ParserHelper.csproj">
+ <Project>{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}</Project>
+ <Name>ParserHelper</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\VCExpr\VCExpr.csproj">
+ <Project>{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}</Project>
+ <Name>VCExpr</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Properties\" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 3.1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
- -->
+ -->
</Project>
diff --git a/Source/VCGeneration/Wlp.cs b/Source/VCGeneration/Wlp.cs
index 82d3b607..b4ee4c09 100644
--- a/Source/VCGeneration/Wlp.cs
+++ b/Source/VCGeneration/Wlp.cs
@@ -1,255 +1,255 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections;
-using Microsoft.Boogie;
-using Microsoft.Boogie.VCExprAST;
-using System.Diagnostics.Contracts;
-using System.Collections.Generic;
-using Microsoft.Basetypes;
-
-namespace VC {
- public class VCContext
- {
- [ContractInvariantMethod]
- void ObjectInvariant()
- {
- Contract.Invariant(Ctxt != null);
- }
-
- [Rep] public readonly Dictionary<int, Absy> Label2absy;
- [Rep] public readonly ProverContext Ctxt;
- public readonly VCExpr ControlFlowVariableExpr;
- public int AssertionCount; // counts the number of assertions for which Wlp has been computed
- public bool isPositiveContext;
-
- public VCContext(Dictionary<int, Absy> label2absy, ProverContext ctxt, bool isPositiveContext = true)
- {
- Contract.Requires(ctxt != null);
- this.Label2absy = label2absy;
- this.Ctxt = ctxt;
- this.isPositiveContext = isPositiveContext;
- }
-
- public VCContext(Dictionary<int, Absy> label2absy, ProverContext ctxt, VCExpr controlFlowVariableExpr, bool isPositiveContext = true)
- {
- Contract.Requires(ctxt != null);
- this.Label2absy = label2absy;
- this.Ctxt = ctxt;
- this.ControlFlowVariableExpr = controlFlowVariableExpr;
- this.isPositiveContext = isPositiveContext;
- }
- }
-
- #region A class to compute wlp of a passive command program
-
- public class Wlp
- {
- public static VCExpr Block(Block b, VCExpr N, VCContext ctxt)
- //modifies ctxt.*;
- {
- Contract.Requires(b != null);
- Contract.Requires(N != null);
- Contract.Requires(ctxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpressionGenerator gen = ctxt.Ctxt.ExprGen;
- Contract.Assert(gen != null);
-
- VCExpr res = N;
-
- for (int i = b.Cmds.Count; --i >= 0; )
- {
- res = Cmd(b, cce.NonNull( b.Cmds[i]), res, ctxt);
- }
-
- int id = b.UniqueId;
- if (ctxt.Label2absy != null) {
- ctxt.Label2absy[id] = b;
- }
-
- try {
- cce.BeginExpose(ctxt);
- if (ctxt.Label2absy == null) {
- return res;
- }
- else {
- return gen.Implies(gen.LabelPos(cce.NonNull(id.ToString()), VCExpressionGenerator.True), res);
- }
- } finally {
- cce.EndExpose();
- }
- }
-
- /// <summary>
- /// Computes the wlp for an assert or assume command "cmd".
- /// </summary>
- public static VCExpr Cmd(Block b, Cmd cmd, VCExpr N, VCContext ctxt) {
- Contract.Requires(cmd != null);
- Contract.Requires(N != null);
- Contract.Requires(ctxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpressionGenerator gen = ctxt.Ctxt.ExprGen;
- Contract.Assert(gen != null);
- if (cmd is AssertCmd) {
- AssertCmd ac = (AssertCmd)cmd;
-
- var isFullyVerified = false;
- if (ac.VerifiedUnder != null)
- {
- var litExpr = ac.VerifiedUnder as LiteralExpr;
- isFullyVerified = litExpr != null && litExpr.IsTrue;
- }
-
- if (!isFullyVerified)
- {
- ctxt.Ctxt.BoogieExprTranslator.isPositiveContext = !ctxt.Ctxt.BoogieExprTranslator.isPositiveContext;
- }
-
- VCExpr C = ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr);
-
- VCExpr VU = null;
- if (!isFullyVerified)
- {
- if (ac.VerifiedUnder != null)
- {
- VU = ctxt.Ctxt.BoogieExprTranslator.Translate(ac.VerifiedUnder);
-
- if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout)
- {
- ctxt.Ctxt.TimeoutDiagnosticIDToAssertion[ctxt.Ctxt.TimoutDiagnosticsCount] = new Tuple<AssertCmd,TransferCmd>(ac, b.TransferCmd);
- VU = gen.Or(VU, gen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, gen.Integer(BigNum.FromInt(ctxt.Ctxt.TimoutDiagnosticsCount++))));
- }
- }
- else if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout)
- {
- ctxt.Ctxt.TimeoutDiagnosticIDToAssertion[ctxt.Ctxt.TimoutDiagnosticsCount] = new Tuple<AssertCmd,TransferCmd>(ac, b.TransferCmd);
- VU = gen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, gen.Integer(BigNum.FromInt(ctxt.Ctxt.TimoutDiagnosticsCount++)));
- }
- ctxt.Ctxt.BoogieExprTranslator.isPositiveContext = !ctxt.Ctxt.BoogieExprTranslator.isPositiveContext;
- }
-
- VCExpr R = null;
- if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) {
- R = gen.Implies(C, N);
- } else {
- var subsumption = Subsumption(ac);
- if (subsumption == CommandLineOptions.SubsumptionOption.Always
- || (subsumption == CommandLineOptions.SubsumptionOption.NotForQuantifiers && !(C is VCExprQuantifier)))
- {
- N = gen.ImpliesSimp(C, N, false);
- }
-
- if (isFullyVerified)
- {
- return N;
- }
- else if (VU != null)
- {
- C = gen.OrSimp(VU, C);
- }
-
- int id = ac.UniqueId;
- if (ctxt.Label2absy != null)
- {
- ctxt.Label2absy[id] = ac;
- }
-
- ctxt.AssertionCount++;
-
- if (ctxt.ControlFlowVariableExpr == null) {
- Contract.Assert(ctxt.Label2absy != null);
- R = gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), C), N);
- } else {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(ctxt.ControlFlowVariableExpr, gen.Integer(BigNum.FromInt(b.UniqueId)));
- Contract.Assert(controlFlowFunctionAppl != null);
- VCExpr assertFailure = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(-ac.UniqueId)));
- if (ctxt.Label2absy == null) {
- R = gen.AndSimp(gen.Implies(assertFailure, C), N);
- } else {
- R = gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), gen.Implies(assertFailure, C)), N);
- }
- }
- }
- return R;
- } else if (cmd is AssumeCmd) {
- AssumeCmd ac = (AssumeCmd)cmd;
-
- if (CommandLineOptions.Clo.StratifiedInlining > 0) {
- // Label the assume if it is a procedure call
- NAryExpr naryExpr = ac.Expr as NAryExpr;
- if (naryExpr != null) {
- if (naryExpr.Fun is FunctionCall) {
- int id = ac.UniqueId;
- ctxt.Label2absy[id] = ac;
- return gen.ImpliesSimp(gen.LabelPos(cce.NonNull("si_fcall_" + id.ToString()), ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr)), N);
- }
- }
- }
- return gen.ImpliesSimp(ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr), N);
- } else {
- Console.WriteLine(cmd.ToString());
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected command
- }
- }
-
- public static CommandLineOptions.SubsumptionOption Subsumption(AssertCmd ac) {
- Contract.Requires(ac != null);
- int n = QKeyValue.FindIntAttribute(ac.Attributes, "subsumption", -1);
- switch (n) {
- case 0: return CommandLineOptions.SubsumptionOption.Never;
- case 1: return CommandLineOptions.SubsumptionOption.NotForQuantifiers;
- case 2: return CommandLineOptions.SubsumptionOption.Always;
- default: return CommandLineOptions.Clo.UseSubsumption;
- }
- }
-
- public static VCExpr RegExpr(RE r, VCExpr N, VCContext ctxt)
- {
- Contract.Requires(r != null);
- Contract.Requires(N != null);
- Contract.Requires(ctxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- if ( r is AtomicRE )
- {
- AtomicRE ar = (AtomicRE) r;
- return Block(ar.b, N, ctxt);
- }
- else if ( r is Sequential )
- {
- Sequential s = (Sequential) r;
- return RegExpr(s.first, RegExpr(s.second, N, ctxt), ctxt);
- }
- else if ( r is Choice )
- {
- Choice ch = (Choice) r;
- VCExpr res;
- if (ch.rs == null || ch.rs.Count==0)
- {
- res = N;
- }
- else
- {
- VCExpr currentWLP = RegExpr(cce.NonNull(ch.rs[0]), N, ctxt);
- for (int i = 1, n = ch.rs.Count; i < n; i++)
- {
- currentWLP = ctxt.Ctxt.ExprGen.And(currentWLP, RegExpr(cce.NonNull(ch.rs[i]), N, ctxt));
- }
- res = currentWLP;
- }
- return res;
- }
- else
- {
- Contract.Assert(false);throw new cce.UnreachableException(); // unexpected RE subtype
- }
- }
- }
- #endregion
-
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Collections;
+using Microsoft.Boogie;
+using Microsoft.Boogie.VCExprAST;
+using System.Diagnostics.Contracts;
+using System.Collections.Generic;
+using Microsoft.Basetypes;
+
+namespace VC {
+ public class VCContext
+ {
+ [ContractInvariantMethod]
+ void ObjectInvariant()
+ {
+ Contract.Invariant(Ctxt != null);
+ }
+
+ [Rep] public readonly Dictionary<int, Absy> Label2absy;
+ [Rep] public readonly ProverContext Ctxt;
+ public readonly VCExpr ControlFlowVariableExpr;
+ public int AssertionCount; // counts the number of assertions for which Wlp has been computed
+ public bool isPositiveContext;
+
+ public VCContext(Dictionary<int, Absy> label2absy, ProverContext ctxt, bool isPositiveContext = true)
+ {
+ Contract.Requires(ctxt != null);
+ this.Label2absy = label2absy;
+ this.Ctxt = ctxt;
+ this.isPositiveContext = isPositiveContext;
+ }
+
+ public VCContext(Dictionary<int, Absy> label2absy, ProverContext ctxt, VCExpr controlFlowVariableExpr, bool isPositiveContext = true)
+ {
+ Contract.Requires(ctxt != null);
+ this.Label2absy = label2absy;
+ this.Ctxt = ctxt;
+ this.ControlFlowVariableExpr = controlFlowVariableExpr;
+ this.isPositiveContext = isPositiveContext;
+ }
+ }
+
+ #region A class to compute wlp of a passive command program
+
+ public class Wlp
+ {
+ public static VCExpr Block(Block b, VCExpr N, VCContext ctxt)
+ //modifies ctxt.*;
+ {
+ Contract.Requires(b != null);
+ Contract.Requires(N != null);
+ Contract.Requires(ctxt != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ VCExpressionGenerator gen = ctxt.Ctxt.ExprGen;
+ Contract.Assert(gen != null);
+
+ VCExpr res = N;
+
+ for (int i = b.Cmds.Count; --i >= 0; )
+ {
+ res = Cmd(b, cce.NonNull( b.Cmds[i]), res, ctxt);
+ }
+
+ int id = b.UniqueId;
+ if (ctxt.Label2absy != null) {
+ ctxt.Label2absy[id] = b;
+ }
+
+ try {
+ cce.BeginExpose(ctxt);
+ if (ctxt.Label2absy == null) {
+ return res;
+ }
+ else {
+ return gen.Implies(gen.LabelPos(cce.NonNull(id.ToString()), VCExpressionGenerator.True), res);
+ }
+ } finally {
+ cce.EndExpose();
+ }
+ }
+
+ /// <summary>
+ /// Computes the wlp for an assert or assume command "cmd".
+ /// </summary>
+ public static VCExpr Cmd(Block b, Cmd cmd, VCExpr N, VCContext ctxt) {
+ Contract.Requires(cmd != null);
+ Contract.Requires(N != null);
+ Contract.Requires(ctxt != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ VCExpressionGenerator gen = ctxt.Ctxt.ExprGen;
+ Contract.Assert(gen != null);
+ if (cmd is AssertCmd) {
+ AssertCmd ac = (AssertCmd)cmd;
+
+ var isFullyVerified = false;
+ if (ac.VerifiedUnder != null)
+ {
+ var litExpr = ac.VerifiedUnder as LiteralExpr;
+ isFullyVerified = litExpr != null && litExpr.IsTrue;
+ }
+
+ if (!isFullyVerified)
+ {
+ ctxt.Ctxt.BoogieExprTranslator.isPositiveContext = !ctxt.Ctxt.BoogieExprTranslator.isPositiveContext;
+ }
+
+ VCExpr C = ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr);
+
+ VCExpr VU = null;
+ if (!isFullyVerified)
+ {
+ if (ac.VerifiedUnder != null)
+ {
+ VU = ctxt.Ctxt.BoogieExprTranslator.Translate(ac.VerifiedUnder);
+
+ if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout)
+ {
+ ctxt.Ctxt.TimeoutDiagnosticIDToAssertion[ctxt.Ctxt.TimoutDiagnosticsCount] = new Tuple<AssertCmd,TransferCmd>(ac, b.TransferCmd);
+ VU = gen.Or(VU, gen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, gen.Integer(BigNum.FromInt(ctxt.Ctxt.TimoutDiagnosticsCount++))));
+ }
+ }
+ else if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout)
+ {
+ ctxt.Ctxt.TimeoutDiagnosticIDToAssertion[ctxt.Ctxt.TimoutDiagnosticsCount] = new Tuple<AssertCmd,TransferCmd>(ac, b.TransferCmd);
+ VU = gen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, gen.Integer(BigNum.FromInt(ctxt.Ctxt.TimoutDiagnosticsCount++)));
+ }
+ ctxt.Ctxt.BoogieExprTranslator.isPositiveContext = !ctxt.Ctxt.BoogieExprTranslator.isPositiveContext;
+ }
+
+ VCExpr R = null;
+ if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) {
+ R = gen.Implies(C, N);
+ } else {
+ var subsumption = Subsumption(ac);
+ if (subsumption == CommandLineOptions.SubsumptionOption.Always
+ || (subsumption == CommandLineOptions.SubsumptionOption.NotForQuantifiers && !(C is VCExprQuantifier)))
+ {
+ N = gen.ImpliesSimp(C, N, false);
+ }
+
+ if (isFullyVerified)
+ {
+ return N;
+ }
+ else if (VU != null)
+ {
+ C = gen.OrSimp(VU, C);
+ }
+
+ int id = ac.UniqueId;
+ if (ctxt.Label2absy != null)
+ {
+ ctxt.Label2absy[id] = ac;
+ }
+
+ ctxt.AssertionCount++;
+
+ if (ctxt.ControlFlowVariableExpr == null) {
+ Contract.Assert(ctxt.Label2absy != null);
+ R = gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), C), N);
+ } else {
+ VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(ctxt.ControlFlowVariableExpr, gen.Integer(BigNum.FromInt(b.UniqueId)));
+ Contract.Assert(controlFlowFunctionAppl != null);
+ VCExpr assertFailure = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(-ac.UniqueId)));
+ if (ctxt.Label2absy == null) {
+ R = gen.AndSimp(gen.Implies(assertFailure, C), N);
+ } else {
+ R = gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), gen.Implies(assertFailure, C)), N);
+ }
+ }
+ }
+ return R;
+ } else if (cmd is AssumeCmd) {
+ AssumeCmd ac = (AssumeCmd)cmd;
+
+ if (CommandLineOptions.Clo.StratifiedInlining > 0) {
+ // Label the assume if it is a procedure call
+ NAryExpr naryExpr = ac.Expr as NAryExpr;
+ if (naryExpr != null) {
+ if (naryExpr.Fun is FunctionCall) {
+ int id = ac.UniqueId;
+ ctxt.Label2absy[id] = ac;
+ return gen.ImpliesSimp(gen.LabelPos(cce.NonNull("si_fcall_" + id.ToString()), ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr)), N);
+ }
+ }
+ }
+ return gen.ImpliesSimp(ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr), N);
+ } else {
+ Console.WriteLine(cmd.ToString());
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected command
+ }
+ }
+
+ public static CommandLineOptions.SubsumptionOption Subsumption(AssertCmd ac) {
+ Contract.Requires(ac != null);
+ int n = QKeyValue.FindIntAttribute(ac.Attributes, "subsumption", -1);
+ switch (n) {
+ case 0: return CommandLineOptions.SubsumptionOption.Never;
+ case 1: return CommandLineOptions.SubsumptionOption.NotForQuantifiers;
+ case 2: return CommandLineOptions.SubsumptionOption.Always;
+ default: return CommandLineOptions.Clo.UseSubsumption;
+ }
+ }
+
+ public static VCExpr RegExpr(RE r, VCExpr N, VCContext ctxt)
+ {
+ Contract.Requires(r != null);
+ Contract.Requires(N != null);
+ Contract.Requires(ctxt != null);
+ Contract.Ensures(Contract.Result<VCExpr>() != null);
+
+ if ( r is AtomicRE )
+ {
+ AtomicRE ar = (AtomicRE) r;
+ return Block(ar.b, N, ctxt);
+ }
+ else if ( r is Sequential )
+ {
+ Sequential s = (Sequential) r;
+ return RegExpr(s.first, RegExpr(s.second, N, ctxt), ctxt);
+ }
+ else if ( r is Choice )
+ {
+ Choice ch = (Choice) r;
+ VCExpr res;
+ if (ch.rs == null || ch.rs.Count==0)
+ {
+ res = N;
+ }
+ else
+ {
+ VCExpr currentWLP = RegExpr(cce.NonNull(ch.rs[0]), N, ctxt);
+ for (int i = 1, n = ch.rs.Count; i < n; i++)
+ {
+ currentWLP = ctxt.Ctxt.ExprGen.And(currentWLP, RegExpr(cce.NonNull(ch.rs[i]), N, ctxt));
+ }
+ res = currentWLP;
+ }
+ return res;
+ }
+ else
+ {
+ Contract.Assert(false);throw new cce.UnreachableException(); // unexpected RE subtype
+ }
+ }
+ }
+ #endregion
+
+}
diff --git a/Source/VCGeneration/cce.cs b/Source/VCGeneration/cce.cs
index 23d79815..42cabfcb 100644
--- a/Source/VCGeneration/cce.cs
+++ b/Source/VCGeneration/cce.cs
@@ -1,105 +1,105 @@
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.Text;
-using Microsoft.Boogie;
-
- /// <summary>
- /// A class containing static methods to extend the functionality of Code Contracts
- /// </summary>
-
-public static class cce {
- [Pure]
- public static T NonNull<T>(T t) {
- Contract.Assert(t != null);
- return t;
- }
- [Pure]
- public static bool NonNullElements<T>(IEnumerable<T> collection) {
- return collection != null && Contract.ForAll(collection, c => c != null);
- }
- [Pure]
- public static bool NonNullElements<TKey, TValue>(IDictionary<TKey, TValue> collection) {
- return collection != null && NonNullElements(collection.Keys) && NonNullElements(collection.Values);
- }
- [Pure]
- public static bool NonNullElements(VariableSeq collection) {
- return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null);
- }
- [Pure]
- public static void BeginExpose(object o) {
- }
- [Pure]
- public static void EndExpose() {
- }
- [Pure]
- public static bool IsPeerConsistent(object o) {
- return true;
- }
- [Pure]
- public static bool IsConsistent(object o) {
- return true;
- }
- [Pure]
- public static bool IsExposable(object o) {
- return true;
- }
- [Pure]
- public static bool IsExposed(object o) {
- return true;
- }
- public static class Owner {
- [Pure]
- public static bool Same(object o, object p) {
- return true;
- }
- [Pure]
- public static void AssignSame(object o, object p) {
- }
- [Pure]
- public static object ElementProxy(object o) {
- return o;
- }
- [Pure]
- public static bool None(object o) {
- return true;
- }
- }
- [Pure]
- public static void LoopInvariant(bool p) {
- Contract.Assert(p);
- }
-
- public class UnreachableException : Exception {
- public UnreachableException() {
- }
- }
-}
-
-public class PeerAttribute : System.Attribute {
-}
-public class RepAttribute : System.Attribute {
-}
-public class CapturedAttribute : System.Attribute {
-}
-public class NotDelayedAttribute : System.Attribute {
-}
-public class NoDefaultContractAttribute : System.Attribute {
-}
-public class VerifyAttribute : System.Attribute {
- public VerifyAttribute(bool b) {
-
- }
-}
-public class StrictReadonlyAttribute : System.Attribute {
- }
-public class AdditiveAttribute : System.Attribute {
-}
-public class ReadsAttribute : System.Attribute {
- public enum Reads {
- Nothing,
- };
- public ReadsAttribute(object o) {
- }
-}
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Text;
+using Microsoft.Boogie;
+
+ /// <summary>
+ /// A class containing static methods to extend the functionality of Code Contracts
+ /// </summary>
+
+public static class cce {
+ [Pure]
+ public static T NonNull<T>(T t) {
+ Contract.Assert(t != null);
+ return t;
+ }
+ [Pure]
+ public static bool NonNullElements<T>(IEnumerable<T> collection) {
+ return collection != null && Contract.ForAll(collection, c => c != null);
+ }
+ [Pure]
+ public static bool NonNullElements<TKey, TValue>(IDictionary<TKey, TValue> collection) {
+ return collection != null && NonNullElements(collection.Keys) && NonNullElements(collection.Values);
+ }
+ [Pure]
+ public static bool NonNullElements(VariableSeq collection) {
+ return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null);
+ }
+ [Pure]
+ public static void BeginExpose(object o) {
+ }
+ [Pure]
+ public static void EndExpose() {
+ }
+ [Pure]
+ public static bool IsPeerConsistent(object o) {
+ return true;
+ }
+ [Pure]
+ public static bool IsConsistent(object o) {
+ return true;
+ }
+ [Pure]
+ public static bool IsExposable(object o) {
+ return true;
+ }
+ [Pure]
+ public static bool IsExposed(object o) {
+ return true;
+ }
+ public static class Owner {
+ [Pure]
+ public static bool Same(object o, object p) {
+ return true;
+ }
+ [Pure]
+ public static void AssignSame(object o, object p) {
+ }
+ [Pure]
+ public static object ElementProxy(object o) {
+ return o;
+ }
+ [Pure]
+ public static bool None(object o) {
+ return true;
+ }
+ }
+ [Pure]
+ public static void LoopInvariant(bool p) {
+ Contract.Assert(p);
+ }
+
+ public class UnreachableException : Exception {
+ public UnreachableException() {
+ }
+ }
+}
+
+public class PeerAttribute : System.Attribute {
+}
+public class RepAttribute : System.Attribute {
+}
+public class CapturedAttribute : System.Attribute {
+}
+public class NotDelayedAttribute : System.Attribute {
+}
+public class NoDefaultContractAttribute : System.Attribute {
+}
+public class VerifyAttribute : System.Attribute {
+ public VerifyAttribute(bool b) {
+
+ }
+}
+public class StrictReadonlyAttribute : System.Attribute {
+ }
+public class AdditiveAttribute : System.Attribute {
+}
+public class ReadsAttribute : System.Attribute {
+ public enum Reads {
+ Nothing,
+ };
+ public ReadsAttribute(object o) {
+ }
+}