summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar stefanheule <unknown>2012-09-19 14:59:22 +0200
committerGravatar stefanheule <unknown>2012-09-19 14:59:22 +0200
commit935f892b8deb0ef77db8874b4edb64957bcd409b (patch)
tree9e27e7ce235a498d43dd4c87f6dec2cef52ed027
parent3e632e6653605050390ee481fa306707139b812a (diff)
parentb1530597d97bf6adbdc64b6f7698e1e1bee6966b (diff)
Merge
-rw-r--r--.hgignore2
-rw-r--r--BCT/BytecodeTranslator/BytecodeTranslator.csproj1
-rw-r--r--BCT/BytecodeTranslator/ExceptionAnalysis.cs121
-rw-r--r--BCT/BytecodeTranslator/ExpressionTraverser.cs111
-rw-r--r--BCT/BytecodeTranslator/MetadataTraverser.cs4
-rw-r--r--BCT/BytecodeTranslator/Program.cs8
-rw-r--r--BCT/BytecodeTranslator/Sink.cs12
-rw-r--r--BCT/BytecodeTranslator/StatementTraverser.cs15
-rw-r--r--BCT/BytecodeTranslator/WholeProgram.cs237
-rw-r--r--BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt30
-rw-r--r--BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt30
-rw-r--r--Binaries/DafnyPrelude.bpl4
-rw-r--r--Binaries/UnivBackPred2.smt22
-rw-r--r--Source/BoogieDriver/BoogieDriver.cs20
-rw-r--r--Source/Core/AbsyCmd.cs22
-rw-r--r--Source/Core/BoogiePL.atg58
-rw-r--r--Source/Core/CommandLineOptions.cs14
-rw-r--r--Source/Core/Core.csproj3
-rw-r--r--Source/Core/Parser.cs58
-rw-r--r--Source/Core/VCExp.cs4
-rw-r--r--Source/Dafny/Cloner.cs75
-rw-r--r--Source/Dafny/Compiler.cs250
-rw-r--r--Source/Dafny/Dafny.atg247
-rw-r--r--Source/Dafny/DafnyAst.cs425
-rw-r--r--Source/Dafny/DafnyOptions.cs2
-rw-r--r--Source/Dafny/Parser.cs1691
-rw-r--r--Source/Dafny/Printer.cs60
-rw-r--r--Source/Dafny/RefinementTransformer.cs401
-rw-r--r--Source/Dafny/Resolver.cs638
-rw-r--r--Source/Dafny/Rewriter.cs34
-rw-r--r--Source/Dafny/Scanner.cs221
-rw-r--r--Source/Dafny/Translator.cs699
-rw-r--r--Source/DafnyDriver/DafnyDriver.cs43
-rw-r--r--Source/GPUVerify.sln22
-rw-r--r--Source/GPUVerify/AccessRecord.cs10
-rw-r--r--Source/GPUVerify/AdversarialAbstraction.cs203
-rw-r--r--Source/GPUVerify/CommandLineOptions.cs61
-rw-r--r--Source/GPUVerify/GPUVerifier.cs4536
-rw-r--r--Source/GPUVerify/GPUVerify.csproj356
-rw-r--r--Source/GPUVerify/IRaceInstrumenter.cs61
-rw-r--r--Source/GPUVerify/InvariantGenerationRules/LoopVariableBoundsInvariantGenerator.cs109
-rw-r--r--Source/GPUVerify/InvariantGenerationRules/PowerOfTwoInvariantGenerator.cs122
-rw-r--r--Source/GPUVerify/KernelDualiser.cs651
-rw-r--r--Source/GPUVerify/LoopInvariantGenerator.cs490
-rw-r--r--Source/GPUVerify/Main.cs71
-rw-r--r--Source/GPUVerify/NoConflictingAccessOptimiser.cs116
-rw-r--r--Source/GPUVerify/NullRaceInstrumenter.cs115
-rw-r--r--Source/GPUVerify/RaceInstrumenter.cs2240
-rw-r--r--Source/GPUVerify/ReadCollector.cs64
-rw-r--r--Source/GPUVerify/StrideConstraint.cs2
-rw-r--r--Source/GPUVerify/UniformExpressionAnalysisVisitor.cs39
-rw-r--r--Source/GPUVerify/VariableDefinitionAnalysis.cs11
-rw-r--r--Source/GPUVerify/VariableDualiser.cs105
-rw-r--r--Source/GPUVerify/WriteCollector.cs48
-rw-r--r--Source/GPUVerifyBoogieDriver/GPUVerifyBoogieDriver.cs1486
-rw-r--r--Source/GPUVerifyBoogieDriver/GPUVerifyBoogieDriver.csproj99
-rw-r--r--Source/GPUVerifyBoogieDriver/Properties/AssemblyInfo.cs36
-rw-r--r--Source/Graph/Graph.cs1913
-rw-r--r--Source/Houdini/Houdini.cs26
-rw-r--r--Source/Provers/SMTLib/ProverInterface.cs41
-rw-r--r--Source/Provers/SMTLib/SMTLibLineariser.cs18
-rw-r--r--Source/Provers/SMTLib/SMTLibProcess.cs5
-rw-r--r--Source/Provers/SMTLib/SMTLibProverOptions.cs35
-rw-r--r--Source/VCGeneration/GraphAlgorithms.cs43
-rw-r--r--Source/VCGeneration/SmartBlockPredicator.cs523
-rw-r--r--Source/VCGeneration/UniformityAnalyser.cs (renamed from Source/GPUVerify/UniformityAnalyser.cs)938
-rw-r--r--Source/VCGeneration/VC.cs2
-rw-r--r--Source/VCGeneration/VCGeneration.csproj452
-rw-r--r--Test/VSComp2010/Problem2-Invert.dfy1
-rw-r--r--Test/VSI-Benchmarks/b4.dfy7
-rw-r--r--Test/dafny0/Answer256
-rw-r--r--Test/dafny0/Compilation.dfy10
-rw-r--r--Test/dafny0/Datatypes.dfy12
-rw-r--r--Test/dafny0/FunctionSpecifications.dfy6
-rw-r--r--Test/dafny0/Modules0.dfy18
-rw-r--r--Test/dafny0/Modules1.dfy6
-rw-r--r--Test/dafny0/Modules2.dfy57
-rw-r--r--Test/dafny0/ModulesCycle.dfy6
-rw-r--r--Test/dafny0/Predicates.dfy4
-rw-r--r--Test/dafny0/Refinement.dfy2
-rw-r--r--Test/dafny0/RefinementModificationChecking.dfy7
-rw-r--r--Test/dafny0/SmallTests.dfy46
-rw-r--r--Test/dafny0/Superposition.dfy56
-rw-r--r--Test/dafny0/TailCalls.dfy74
-rw-r--r--Test/dafny0/runtest.bat10
-rw-r--r--Test/dafny1/SchorrWaite-stages.dfy4
-rw-r--r--Test/dafny1/SchorrWaite.dfy5
-rw-r--r--Test/dafny2/Answer8
-rw-r--r--Test/dafny2/Calculations.dfy212
-rw-r--r--Test/dafny2/MonotonicHeapstate.dfy143
-rw-r--r--Test/dafny2/StoreAndRetrieve.dfy2
-rw-r--r--Test/dafny2/runtest.bat1
-rw-r--r--Test/inline/Answer76
-rw-r--r--Test/livevars/Answer15
-rw-r--r--Test/smoke/Answer2
-rw-r--r--Test/test15/Answer96
-rw-r--r--Util/Emacs/dafny-mode.el14
-rw-r--r--Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs13
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/ClassificationTagger.cs12
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs455
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/DafnyExtension.csproj28
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/HoverText.cs126
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/IdentifierTagger.cs340
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/Outlining.cs222
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/OutliningTagger.cs88
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/ProgressMargin.cs260
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/ResolverTagger.cs227
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs32
-rw-r--r--Util/VS2010/DafnyExtension/DafnyExtension/source.extension.vsixmanifest2
-rw-r--r--Util/latex/dafny.sty8
-rw-r--r--Util/vim/syntax/dafny.vim6
-rw-r--r--_admin/Boogie/aste/summary.log22
112 files changed, 14690 insertions, 8898 deletions
diff --git a/.hgignore b/.hgignore
index 57ee4491..46d9d269 100644
--- a/.hgignore
+++ b/.hgignore
@@ -22,6 +22,7 @@ Jennisys/Jennisys/examples/bak
Chalice/project/boot
Chalice/project/target
Chalice/target
+Chalice/bin
Chalice/scripts/create_release/release
BCT/InternalBCT.sln
*.pyc
@@ -29,3 +30,4 @@ BCT/InternalBCT.sln
*.exe.mdb
*.pidb
*.userprefs
+Binaries/Dafny.suo
diff --git a/BCT/BytecodeTranslator/BytecodeTranslator.csproj b/BCT/BytecodeTranslator/BytecodeTranslator.csproj
index 7c47c56c..26dfc103 100644
--- a/BCT/BytecodeTranslator/BytecodeTranslator.csproj
+++ b/BCT/BytecodeTranslator/BytecodeTranslator.csproj
@@ -121,6 +121,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="ExceptionAnalysis.cs" />
<Compile Include="TranslationPlugins\PhoneTranslator\PhoneFeedbackPlugin.cs" />
<Compile Include="TranslationPlugins\Translators\BaseTranslator.cs" />
<Compile Include="CLRSemantics.cs" />
diff --git a/BCT/BytecodeTranslator/ExceptionAnalysis.cs b/BCT/BytecodeTranslator/ExceptionAnalysis.cs
new file mode 100644
index 00000000..f1f44fe7
--- /dev/null
+++ b/BCT/BytecodeTranslator/ExceptionAnalysis.cs
@@ -0,0 +1,121 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+
+using Microsoft.Cci;
+using Microsoft.Cci.MetadataReader;
+using Microsoft.Cci.MutableCodeModel;
+using Microsoft.Cci.Contracts;
+using Microsoft.Cci.ILToCodeModel;
+
+using Bpl = Microsoft.Boogie;
+using System.Diagnostics.Contracts;
+using TranslationPlugins;
+using BytecodeTranslator.Phone;
+
+
+namespace BytecodeTranslator {
+
+ internal class ExceptionAnalyzer : CodeTraverser {
+
+ private Dictionary<IMethodDefinition, HashSet<ITypeReference>> exceptionsExplicitlyThrownByMethod;
+ private bool resultsChanged;
+
+ private ExceptionAnalyzer() {
+ this.exceptionsExplicitlyThrownByMethod = new Dictionary<IMethodDefinition, HashSet<ITypeReference>>();
+ }
+
+ public static Predicate<IMethodDefinition> ComputeExplicitlyThrownExceptions(IEnumerable<IUnit> units) {
+ var me = new ExceptionAnalyzer();
+ do {
+ me.resultsChanged = false;
+ foreach (var u in units)
+ me.Traverse(u.UnitNamespaceRoot);
+ } while (me.resultsChanged);
+ return m => m != null && me.exceptionsExplicitlyThrownByMethod.ContainsKey(m);
+ }
+
+ public override void TraverseChildren(IMethodDefinition method) {
+ var newExceptions = MethodExceptionAnalyzer.ExplicitlyThrownExceptions(this, method);
+ HashSet<ITypeReference> alreadyKnownExceptions = null;
+ if (this.exceptionsExplicitlyThrownByMethod.TryGetValue(method, out alreadyKnownExceptions)) {
+ if (!newExceptions.SetEquals(alreadyKnownExceptions)) {
+ this.resultsChanged = true;
+ this.exceptionsExplicitlyThrownByMethod[method] = newExceptions;
+ }
+ } else {
+ if (0 < newExceptions.Count) {
+ this.resultsChanged = true;
+ this.exceptionsExplicitlyThrownByMethod[method] = newExceptions;
+ }
+ }
+
+ }
+
+ private class MethodExceptionAnalyzer : CodeTraverser {
+
+ private ExceptionAnalyzer parent;
+ private HashSet<ITypeReference> exceptionsThrown;
+
+ /// <summary>
+ /// Used to track the type thrown by rethrow statements.
+ /// </summary>
+ private ITypeReference/*?*/ currentCatchClauseExceptionType;
+
+ private MethodExceptionAnalyzer(ExceptionAnalyzer parent) {
+ this.parent = parent;
+ this.exceptionsThrown = new HashSet<ITypeReference>();
+ }
+
+ public static HashSet<ITypeReference> ExplicitlyThrownExceptions(ExceptionAnalyzer parent, IMethodDefinition methodDefinition) {
+ var me = new MethodExceptionAnalyzer(parent);
+ me.Traverse(methodDefinition);
+ return me.exceptionsThrown;
+ }
+
+ public override void TraverseChildren(ICatchClause catchClause) {
+ this.exceptionsThrown.RemoveWhere(t => TypeHelper.Type1DerivesFromOrIsTheSameAsType2(t.ResolvedType, catchClause.ExceptionType, true));
+
+ // no need to save the current value: catch clauses cannot be nested.
+ this.currentCatchClauseExceptionType = catchClause.ExceptionType;
+ base.TraverseChildren(catchClause);
+ this.currentCatchClauseExceptionType = null;
+ }
+
+ public override void TraverseChildren(IMethodCall methodCall) {
+ var calledMethod = MemberHelper.UninstantiateAndUnspecialize(methodCall.MethodToCall.ResolvedMethod).ResolvedMethod;
+ HashSet<ITypeReference> calledMethodExceptionSet;
+ if (this.parent.exceptionsExplicitlyThrownByMethod.TryGetValue(calledMethod, out calledMethodExceptionSet))
+ this.exceptionsThrown.UnionWith(calledMethodExceptionSet);
+ base.TraverseChildren(methodCall);
+ }
+
+ public override void TraverseChildren(IRethrowStatement rethrowStatement) {
+ this.exceptionsThrown.Add(this.currentCatchClauseExceptionType);
+ }
+
+ public override void TraverseChildren(IThrowStatement throwStatement) {
+ this.exceptionsThrown.Add(throwStatement.Exception.Type);
+ }
+
+ public override void TraverseChildren(ITryCatchFinallyStatement tryCatchFilterFinallyStatement) {
+ var savedExceptions = this.exceptionsThrown;
+ this.exceptionsThrown = new HashSet<ITypeReference>();
+
+ base.TraverseChildren(tryCatchFilterFinallyStatement);
+
+ savedExceptions.UnionWith(this.exceptionsThrown);
+ this.exceptionsThrown = savedExceptions;
+ }
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/BCT/BytecodeTranslator/ExpressionTraverser.cs b/BCT/BytecodeTranslator/ExpressionTraverser.cs
index b2d23777..6a830cab 100644
--- a/BCT/BytecodeTranslator/ExpressionTraverser.cs
+++ b/BCT/BytecodeTranslator/ExpressionTraverser.cs
@@ -379,11 +379,11 @@ namespace BytecodeTranslator
}
public override void TraverseChildren(IDupValue dupValue) {
- var e = this.StmtTraverser.operandStack.Peek();
+ var e = this.sink.operandStack.Peek();
this.TranslatedExpressions.Push(e);
}
public override void TraverseChildren(IPopValue popValue) {
- var locExpr = this.StmtTraverser.operandStack.Pop();
+ var locExpr = this.sink.operandStack.Pop();
this.TranslatedExpressions.Push(locExpr);
}
@@ -617,6 +617,44 @@ namespace BytecodeTranslator
}
}
+ // Handle type equality specially when it is testing against a constant, i.e., o.GetType() == typeof(T)
+ if (IsOperator(resolvedMethod) && !IsConversionOperator(resolvedMethod) &&
+ TypeHelper.TypesAreEquivalent(resolvedMethod.ContainingType, this.sink.host.PlatformType.SystemType)) {
+ // REVIEW: Assume the only operators on System.Type are == and !=
+ var typeToTest = methodCall.Arguments.ElementAtOrDefault(0) as ITypeOf;
+ IMethodCall callToGetType;
+ if (typeToTest == null) {
+ typeToTest = methodCall.Arguments.ElementAtOrDefault(1) as ITypeOf;
+ callToGetType = methodCall.Arguments.ElementAtOrDefault(0) as IMethodCall;
+ } else {
+ callToGetType = methodCall.Arguments.ElementAtOrDefault(1) as IMethodCall;
+ }
+ if (typeToTest != null && callToGetType != null &&
+ TypeHelper.TypesAreEquivalent(callToGetType.MethodToCall.ContainingType, this.sink.host.PlatformType.SystemObject) &&
+ MemberHelper.GetMethodSignature(callToGetType.MethodToCall).Equals("System.Object.GetType")) {
+
+ IExpression objectToTest = callToGetType.ThisArgument;
+
+ // generate: is#T($DynamicType(o))
+ var typeFunction = this.sink.FindOrDefineType(typeToTest.TypeToGet.ResolvedType);
+ Contract.Assume(typeFunction != null);
+ var funcName = String.Format("is#{0}", typeFunction.Name);
+ var identExpr = Bpl.Expr.Ident(new Bpl.LocalVariable(methodCallToken, new Bpl.TypedIdent(methodCallToken, funcName, Bpl.Type.Bool)));
+ var funcCall = new Bpl.FunctionCall(identExpr);
+
+ this.Traverse(objectToTest);
+ var e = this.TranslatedExpressions.Pop();
+
+ var exprs = new Bpl.ExprSeq(this.sink.Heap.DynamicType(e));
+ Bpl.Expr typeTestExpression = new Bpl.NAryExpr(methodCallToken, funcCall, exprs);
+ if (MemberHelper.GetMethodSignature(resolvedMethod).Equals("System.Type.op_Inequality"))
+ typeTestExpression = Bpl.Expr.Unary( methodCallToken, Bpl.UnaryOperator.Opcode.Not, typeTestExpression);
+ this.TranslatedExpressions.Push(typeTestExpression);
+ return;
+ }
+ }
+
+
List<Bpl.Expr> inexpr;
List<Bpl.IdentifierExpr> outvars;
Bpl.IdentifierExpr thisExpr;
@@ -687,8 +725,11 @@ namespace BytecodeTranslator
this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(lhs, fromUnion));
}
- Bpl.Expr expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, Bpl.Expr.Ident(this.sink.Heap.ExceptionVariable), Bpl.Expr.Ident(this.sink.Heap.NullRef));
- this.StmtTraverser.RaiseException(expr);
+ if (this.sink.Options.modelExceptions == 2
+ || (this.sink.Options.modelExceptions == 1 && this.sink.MethodThrowsExceptions(resolvedMethod))) {
+ Bpl.Expr expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, Bpl.Expr.Ident(this.sink.Heap.ExceptionVariable), Bpl.Expr.Ident(this.sink.Heap.NullRef));
+ this.StmtTraverser.RaiseException(expr);
+ }
} finally {
// TODO move away phone related code from the translation, it would be better to have 2 or more translation phases
if (PhoneCodeHelper.instance().PhonePlugin != null) {
@@ -709,6 +750,15 @@ namespace BytecodeTranslator
}
}
+ public virtual bool IsOperator(IMethodDefinition methodDefinition) {
+ return (methodDefinition.IsSpecialName && methodDefinition.Name.Value.StartsWith("op_"));
+ }
+
+ public virtual bool IsConversionOperator(IMethodDefinition methodDefinition) {
+ return (methodDefinition.IsSpecialName && (
+ methodDefinition.Name.Value == "op_Explicit" || methodDefinition.Name.Value == "op_Implicit"));
+ }
+
private void EmitLineDirective(Bpl.IToken methodCallToken) {
var sloc = this.StmtTraverser.lastSourceLocation;
if (sloc != null) {
@@ -1059,7 +1109,7 @@ namespace BytecodeTranslator
}
var pop = addressDereference.Address as IPopValue;
if (pop != null) {
- var popValue = this.StmtTraverser.operandStack.Pop();
+ var popValue = this.sink.operandStack.Pop();
var be = popValue as IBoundExpression;
if (be != null) {
TranslateAssignment(tok, be.Definition, be.Instance, source);
@@ -1091,8 +1141,7 @@ namespace BytecodeTranslator
return;
}
}
-
- Contract.Assume(false);
+ throw new TranslationException("Untranslatable assignment statement.");
}
internal delegate void SourceTraverser(IExpression source);
@@ -1215,22 +1264,24 @@ namespace BytecodeTranslator
} else {
Bpl.Expr x = null;
Bpl.IdentifierExpr temp = null;
- if (target.Instance != null) {
- this.Traverse(target.Instance);
- x = this.TranslatedExpressions.Pop();
- if (pushTargetRValue) {
+ if (pushTargetRValue) {
+ if (target.Instance != null) {
+ this.Traverse(target.Instance);
+ x = this.TranslatedExpressions.Pop();
AssertOrAssumeNonNull(tok, x);
var e2 = this.sink.Heap.ReadHeap(x, f, TranslationHelper.IsStruct(field.ContainingType) ? AccessType.Struct : AccessType.Heap, boogieTypeOfField);
this.TranslatedExpressions.Push(e2);
-
- if (!treatAsStatement && resultIsInitialTargetRValue) {
- var loc = this.sink.CreateFreshLocal(source.Type);
- temp = Bpl.Expr.Ident(loc);
- var e3 = this.TranslatedExpressions.Pop();
- var cmd = Bpl.Cmd.SimpleAssign(tok, temp, e3);
- this.StmtTraverser.StmtBuilder.Add(cmd);
- this.TranslatedExpressions.Push(temp);
- }
+ } else {
+ TranslatedExpressions.Push(f);
+ }
+
+ if (!treatAsStatement && resultIsInitialTargetRValue) {
+ var loc = this.sink.CreateFreshLocal(source.Type);
+ temp = Bpl.Expr.Ident(loc);
+ var e3 = this.TranslatedExpressions.Pop();
+ var cmd = Bpl.Cmd.SimpleAssign(tok, temp, e3);
+ this.StmtTraverser.StmtBuilder.Add(cmd);
+ this.TranslatedExpressions.Push(temp);
}
}
sourceTraverser(source);
@@ -1625,6 +1676,8 @@ namespace BytecodeTranslator
e = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.And, lexp, rexp);
}
else {
+ if (lexp.Type != Bpl.Type.Int || rexp.Type != Bpl.Type.Int)
+ throw new TranslationException("BitwiseAnd called in a non-boolean context, but at least one argument is not an integer!");
e = new Bpl.NAryExpr(
bitwiseAnd.Token(),
new Bpl.FunctionCall(this.sink.Heap.BitwiseAnd),
@@ -1944,8 +1997,10 @@ namespace BytecodeTranslator
public override void TraverseChildren(IEquality equal)
{
- if ((equal.LeftOperand.Type.TypeCode != PrimitiveTypeCode.NotPrimitive || equal.LeftOperand.Type.TypeCode != PrimitiveTypeCode.NotPrimitive)
- && !TypeHelper.TypesAreEquivalent(equal.LeftOperand.Type, equal.RightOperand.Type)) {
+ if ((equal.LeftOperand.Type.TypeCode != PrimitiveTypeCode.NotPrimitive || equal.RightOperand.Type.TypeCode != PrimitiveTypeCode.NotPrimitive)
+ && !TypeHelper.TypesAreEquivalent(equal.LeftOperand.Type, equal.RightOperand.Type)
+ && (!(IsConstantNull(equal.LeftOperand) || IsConstantNull(equal.RightOperand))) // null is "polymorphic": it can be compared against any reference type.
+ ) {
throw new TranslationException(
String.Format("Decompiler messed up: equality's left operand is of type '{0}' but right operand is of type '{1}'.",
TypeHelper.GetTypeName(equal.LeftOperand.Type),
@@ -1959,12 +2014,20 @@ namespace BytecodeTranslator
TranslatedExpressions.Push(Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Eq, lexp, rexp));
}
+ private bool IsConstantNull(IExpression iExpression) {
+ var ctc = iExpression as ICompileTimeConstant;
+ if (ctc == null) return false;
+ return ctc.Value == null;
+ }
+
public override void TraverseChildren(INotEquality nonEqual)
{
- if ((nonEqual.LeftOperand.Type.TypeCode != PrimitiveTypeCode.NotPrimitive || nonEqual.LeftOperand.Type.TypeCode != PrimitiveTypeCode.NotPrimitive)
+ if ((nonEqual.LeftOperand.Type.TypeCode != PrimitiveTypeCode.NotPrimitive || nonEqual.RightOperand.Type.TypeCode != PrimitiveTypeCode.NotPrimitive)
&&
- !TypeHelper.TypesAreEquivalent(nonEqual.LeftOperand.Type, nonEqual.RightOperand.Type)) {
+ !TypeHelper.TypesAreEquivalent(nonEqual.LeftOperand.Type, nonEqual.RightOperand.Type)
+ && (!(IsConstantNull(nonEqual.LeftOperand) || IsConstantNull(nonEqual.RightOperand))) // null is "polymorphic": it can be compared against any reference type.
+ ) {
throw new TranslationException(
String.Format("Decompiler messed up: inequality's left operand is of type '{0}' but right operand is of type '{1}'.",
TypeHelper.GetTypeName(nonEqual.LeftOperand.Type),
diff --git a/BCT/BytecodeTranslator/MetadataTraverser.cs b/BCT/BytecodeTranslator/MetadataTraverser.cs
index e65ef6a9..491f0f96 100644
--- a/BCT/BytecodeTranslator/MetadataTraverser.cs
+++ b/BCT/BytecodeTranslator/MetadataTraverser.cs
@@ -532,7 +532,9 @@ namespace BytecodeTranslator {
foreach (Bpl.Variable v in this.sink.LocalVarMap.Values) {
vars.Add(v);
}
- vars.Add(procInfo.LocalExcVariable);
+ // LocalExcVariable holds the exception thrown by any method called from this method, even if this method swallows all exceptions
+ if (0 <this.sink.Options.modelExceptions)
+ vars.Add(procInfo.LocalExcVariable);
vars.Add(procInfo.LabelVariable);
Bpl.VariableSeq vseq = new Bpl.VariableSeq(vars.ToArray());
#endregion
diff --git a/BCT/BytecodeTranslator/Program.cs b/BCT/BytecodeTranslator/Program.cs
index ffee13eb..403067be 100644
--- a/BCT/BytecodeTranslator/Program.cs
+++ b/BCT/BytecodeTranslator/Program.cs
@@ -38,6 +38,9 @@ namespace BytecodeTranslator {
[OptionDescription("Emit a 'capture state' directive after each statement, (default: false)", ShortForm = "c")]
public bool captureState = false;
+ [OptionDescription("Model exceptional control flow, (0: none, 1: explicit exceptions, 2: conservatively, default: 2)", ShortForm = "e")]
+ public int modelExceptions = 2;
+
[OptionDescription("Translation should be done for Get Me Here functionality, (default: false)", ShortForm = "gmh")]
public bool getMeHere = false;
@@ -109,6 +112,11 @@ namespace BytecodeTranslator {
return errorReturnValue;
}
+ if (options.modelExceptions == 1 && !options.wholeProgram) {
+ Console.WriteLine("can specify a precise modeling of exceptions only when doing whole program analysis");
+ return errorReturnValue;
+ }
+
if (options.breakIntoDebugger) {
System.Diagnostics.Debugger.Break();
}
diff --git a/BCT/BytecodeTranslator/Sink.cs b/BCT/BytecodeTranslator/Sink.cs
index 425a6b72..19949297 100644
--- a/BCT/BytecodeTranslator/Sink.cs
+++ b/BCT/BytecodeTranslator/Sink.cs
@@ -951,6 +951,7 @@ namespace BytecodeTranslator {
gArgs.Add(a_prime);
}
var typeExpression = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(genericType), gArgs);
+ return typeExpression;
}
IGenericTypeParameter gtp = type as IGenericTypeParameter;
@@ -1320,6 +1321,7 @@ namespace BytecodeTranslator {
escapingGotoEdges = new Dictionary<ITryCatchFinallyStatement, List<string>>();
nestedTryCatchFinallyStatements = new List<Tuple<ITryCatchFinallyStatement, TryCatchFinallyContext>>();
mostNestedTryStatementTraverser.Traverse(method.Body);
+ this.operandStack.Clear();
}
public void BeginAssembly(IAssembly assembly) {
@@ -1421,5 +1423,15 @@ namespace BytecodeTranslator {
}
+ public Predicate<IMethodDefinition> MethodThrowsExceptions = m => false;
+
+ /// <summary>
+ /// Moved from the statement traverser since it needs to be shared among the different statement
+ /// traversers, e.g., from before a conditional down into the branches. Really the whole idea
+ /// of having different statement traversers needs to be rethought, as does the use of this
+ /// operand stack to hold push and dup values...
+ /// </summary>
+ internal readonly Stack<Bpl.Expr> operandStack = new Stack<Bpl.Expr>();
+
}
} \ No newline at end of file
diff --git a/BCT/BytecodeTranslator/StatementTraverser.cs b/BCT/BytecodeTranslator/StatementTraverser.cs
index 49f932ec..4b328a67 100644
--- a/BCT/BytecodeTranslator/StatementTraverser.cs
+++ b/BCT/BytecodeTranslator/StatementTraverser.cs
@@ -53,7 +53,6 @@ namespace BytecodeTranslator
public readonly Bpl.StmtListBuilder StmtBuilder = new Bpl.StmtListBuilder();
private bool contractContext;
- internal readonly Stack<Bpl.Expr> operandStack = new Stack<Bpl.Expr>();
private bool captureState;
private static int captureStateCounter = 0;
public IPrimarySourceLocation lastSourceLocation;
@@ -366,7 +365,7 @@ namespace BytecodeTranslator
var tok = pushStatement.Token();
var val = pushStatement.ValueToPush;
var e = ExpressionFor(val);
- this.operandStack.Push(e);
+ this.sink.operandStack.Push(e);
return;
}
@@ -518,6 +517,14 @@ namespace BytecodeTranslator
}
public override void TraverseChildren(ITryCatchFinallyStatement tryCatchFinallyStatement) {
+
+ if (this.sink.Options.modelExceptions == 0) {
+ this.Traverse(tryCatchFinallyStatement.TryBody);
+ if (tryCatchFinallyStatement.FinallyBody != null)
+ this.Traverse(tryCatchFinallyStatement.FinallyBody);
+ return;
+ }
+
this.sink.nestedTryCatchFinallyStatements.Add(new Tuple<ITryCatchFinallyStatement, Sink.TryCatchFinallyContext>(tryCatchFinallyStatement, Sink.TryCatchFinallyContext.InTry));
this.Traverse(tryCatchFinallyStatement.TryBody);
StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(this.sink.LabelVariable), Bpl.Expr.Literal(-1)));
@@ -572,6 +579,10 @@ namespace BytecodeTranslator
}
public override void TraverseChildren(IThrowStatement throwStatement) {
+ if (this.sink.Options.modelExceptions == 0) {
+ StmtBuilder.Add(new Bpl.AssumeCmd(throwStatement.Token(), Bpl.Expr.False));
+ return;
+ }
ExpressionTraverser exceptionTraverser = this.factory.MakeExpressionTraverser(this.sink, this, this.contractContext);
exceptionTraverser.Traverse(throwStatement.Exception);
StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(this.sink.Heap.ExceptionVariable), exceptionTraverser.TranslatedExpressions.Pop()));
diff --git a/BCT/BytecodeTranslator/WholeProgram.cs b/BCT/BytecodeTranslator/WholeProgram.cs
index fa345867..91761cb2 100644
--- a/BCT/BytecodeTranslator/WholeProgram.cs
+++ b/BCT/BytecodeTranslator/WholeProgram.cs
@@ -56,6 +56,13 @@ namespace BytecodeTranslator {
typeRecorder.Traverse((IAssembly)a);
}
#endregion
+ #region Possibly gather exception information
+ if (sink.Options.modelExceptions == 1) {
+ this.sink.MethodThrowsExceptions = ExceptionAnalyzer.ComputeExplicitlyThrownExceptions(assemblies);
+ }
+
+ #endregion
+
base.TranslateAssemblies(assemblies);
}
@@ -74,6 +81,7 @@ namespace BytecodeTranslator {
}
this.subTypes[baseClass].Add(typeDefinition);
}
+
foreach (var iface in typeDefinition.Interfaces) {
if (!this.subTypes.ContainsKey(iface)) {
this.subTypes[iface] = new List<ITypeReference>();
@@ -109,6 +117,12 @@ namespace BytecodeTranslator {
public override void TraverseChildren(IMethodCall methodCall) {
var resolvedMethod = Sink.Unspecialize(methodCall.MethodToCall).ResolvedMethod;
+ var methodName = Microsoft.Cci.MemberHelper.GetMethodSignature(resolvedMethod);
+ if (methodName.Equals("System.Object.GetHashCode") || methodName.Equals("System.Object.ToString")) {
+ base.TraverseChildren(methodCall);
+ return;
+ }
+
bool isEventAdd = resolvedMethod.IsSpecialName && resolvedMethod.Name.Value.StartsWith("add_");
bool isEventRemove = resolvedMethod.IsSpecialName && resolvedMethod.Name.Value.StartsWith("remove_");
if (isEventAdd || isEventRemove) {
@@ -141,80 +155,113 @@ namespace BytecodeTranslator {
return;
}
- Bpl.IToken token = methodCall.Token();
-
- List<Bpl.Expr> inexpr;
- List<Bpl.IdentifierExpr> outvars;
- Bpl.IdentifierExpr thisExpr;
- Dictionary<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>> toBoxed;
- var proc = TranslateArgumentsAndReturnProcedure(token, methodCall.MethodToCall, resolvedMethod, methodCall.IsStaticCall ? null : methodCall.ThisArgument, methodCall.Arguments, out inexpr, out outvars, out thisExpr, out toBoxed);
-
-
- Bpl.QKeyValue attrib = null;
- foreach (var a in resolvedMethod.Attributes) {
- if (TypeHelper.GetTypeName(a.Type).EndsWith("AsyncAttribute")) {
- attrib = new Bpl.QKeyValue(token, "async", new List<object>(), null);
- break;
- }
- }
-
- var elseBranch = new Bpl.StmtListBuilder();
-
- var methodname = proc.Name;
-
- Bpl.CallCmd call;
- if (attrib != null)
- call = new Bpl.CallCmd(token, methodname, inexpr, outvars, attrib);
- else
- call = new Bpl.CallCmd(token, methodname, inexpr, outvars);
- elseBranch.Add(call);
+ Contract.Assume(1 <= overrides.Count);
- Bpl.IfCmd ifcmd = null;
+ var getType = new Microsoft.Cci.MethodReference(
+ this.sink.host,
+ this.sink.host.PlatformType.SystemObject,
+ CallingConvention.HasThis,
+ this.sink.host.PlatformType.SystemType,
+ this.sink.host.NameTable.GetNameFor("GetType"), 0);
+ var op_Type_Equality = new Microsoft.Cci.MethodReference(
+ this.sink.host,
+ this.sink.host.PlatformType.SystemType,
+ CallingConvention.Default,
+ this.sink.host.PlatformType.SystemBoolean,
+ this.sink.host.NameTable.GetNameFor("op_Equality"),
+ 0,
+ this.sink.host.PlatformType.SystemType,
+ this.sink.host.PlatformType.SystemType);
+
+ // Depending on whether the method is a void method or not
+ // Turn into expression:
+ // (o.GetType() == typeof(T1)) ? ((T1)o).M(...) : ( (o.GetType() == typeof(T2)) ? ((T2)o).M(...) : ...
+ // Or turn into statements:
+ // if (o.GetType() == typeof(T1)) ((T1)o).M(...) else if ...
+ var turnIntoStatements = resolvedMethod.Type.TypeCode == PrimitiveTypeCode.Void;
+ IStatement elseStatement = null;
+
+ IExpression elseValue = new MethodCall() {
+ Arguments = new List<IExpression>(methodCall.Arguments),
+ IsStaticCall = false,
+ IsVirtualCall = false,
+ MethodToCall = methodCall.MethodToCall,
+ ThisArgument = methodCall.ThisArgument,
+ Type = methodCall.Type,
+ };
+ if (turnIntoStatements)
+ elseStatement = new ExpressionStatement() { Expression = elseValue, };
+
+ Conditional ifConditional = null;
+ ConditionalStatement ifStatement = null;
- Contract.Assume(1 <= overrides.Count);
foreach (var typeMethodPair in overrides) {
var t = typeMethodPair.Item1;
var m = typeMethodPair.Item2;
- // guard: is#T($DynamicType(local_variable))
- var typeFunction = this.sink.FindOrDefineType(t.ResolvedType);
- if (typeFunction == null) {
- // BUGBUG!! This just silently skips the branch that would dispatch to t's implementation of the method!
- continue;
+ if (m.IsGeneric) {
+ var baseMethod = m.ResolvedMethod;
+ m = new GenericMethodInstanceReference() {
+ CallingConvention = baseMethod.CallingConvention,
+ ContainingType = baseMethod.ContainingTypeDefinition,
+ GenericArguments = new List<ITypeReference>(IteratorHelper.GetConversionEnumerable<IGenericMethodParameter, ITypeReference>(baseMethod.GenericParameters)),
+ GenericMethod = baseMethod,
+ InternFactory = this.sink.host.InternFactory,
+ Name = baseMethod.Name,
+ Parameters = baseMethod.ParameterCount == 0 ? null : new List<IParameterTypeInformation>(baseMethod.Parameters),
+ Type = baseMethod.Type,
+ };
}
- var funcName = String.Format("is#{0}", typeFunction.Name);
- var identExpr = Bpl.Expr.Ident(new Bpl.LocalVariable(token, new Bpl.TypedIdent(token, funcName, Bpl.Type.Bool)));
- var funcCall = new Bpl.FunctionCall(identExpr);
- var exprs = new Bpl.ExprSeq(this.sink.Heap.DynamicType(inexpr[0]));
- var guard = new Bpl.NAryExpr(token, funcCall, exprs);
-
- var thenBranch = new Bpl.StmtListBuilder();
- methodname = TranslationHelper.CreateUniqueMethodName(m); // REVIEW: Shouldn't this be call to FindOrCreateProcedure?
- if (attrib != null)
- call = new Bpl.CallCmd(token, methodname, inexpr, outvars, attrib);
- else
- call = new Bpl.CallCmd(token, methodname, inexpr, outvars);
- thenBranch.Add(call);
-
- ifcmd = new Bpl.IfCmd(token,
- guard,
- thenBranch.Collect(token),
- null,
- elseBranch.Collect(token)
- );
- elseBranch = new Bpl.StmtListBuilder();
- elseBranch.Add(ifcmd);
- }
- if (ifcmd == null) {
- // BUGBUG: then no override made it into the if-statement.
- // currently that happens when all types are generic.
- // Should be able to remove this when that is fixed.
- base.Traverse(methodCall);
- return;
+ var cond = new MethodCall() {
+ Arguments = new List<IExpression>(){
+ new MethodCall() {
+ Arguments = new List<IExpression>(),
+ IsStaticCall = false,
+ IsVirtualCall = false,
+ MethodToCall = getType,
+ ThisArgument = methodCall.ThisArgument,
+ },
+ new TypeOf() {
+ TypeToGet = t,
+ },
+ },
+ IsStaticCall = true,
+ IsVirtualCall = false,
+ MethodToCall = op_Type_Equality,
+ Type = this.sink.host.PlatformType.SystemBoolean,
+ };
+ var thenValue = new MethodCall() {
+ Arguments = new List<IExpression>(methodCall.Arguments),
+ IsStaticCall = false,
+ IsVirtualCall = false,
+ MethodToCall = m,
+ ThisArgument = methodCall.ThisArgument,
+ Type = t,
+ };
+ if (turnIntoStatements) {
+ ifStatement = new ConditionalStatement() {
+ Condition = cond,
+ FalseBranch = elseStatement,
+ TrueBranch = new ExpressionStatement() { Expression = thenValue, },
+ };
+ elseStatement = ifStatement;
+ } else {
+ ifConditional = new Conditional() {
+ Condition = cond,
+ ResultIfFalse = elseValue,
+ ResultIfTrue = thenValue,
+ };
+ elseValue = ifConditional;
+ }
+ }
+ if (turnIntoStatements) {
+ Contract.Assume(ifStatement != null);
+ this.StmtTraverser.Traverse(ifStatement);
+ } else {
+ Contract.Assume(ifConditional != null);
+ base.Traverse(ifConditional);
}
-
- this.StmtTraverser.StmtBuilder.Add(ifcmd);
return;
}
@@ -226,19 +273,65 @@ namespace BytecodeTranslator {
Contract.Requires(type != null);
Contract.Requires(resolvedMethod != null);
var overrides = new List<Tuple<ITypeReference, IMethodReference>>();
- foreach (var subType in this.subTypes[type]) {
- var overriddenMethod = MemberHelper.GetImplicitlyOverridingDerivedClassMethod(resolvedMethod, subType.ResolvedType);
- if (overriddenMethod != Dummy.Method) {
- resolvedMethod = overriddenMethod;
+ if (type.ResolvedType.IsInterface) {
+ foreach (var subType in this.subTypes[type]) {
+ var def = subType.ResolvedType;
+ var foundSome = false; // prefer explicit, since if both are there, only the implicit get called through the iface pointer.
+ foreach (var implementingMethod in GetExplicitlyImplementedMethods(def, resolvedMethod)) {
+ overrides.Add(Tuple.Create<ITypeReference, IMethodReference>(subType, implementingMethod));
+ foundSome = true;
+ }
+ if (!foundSome) { // look for implicit
+ var mems = def.GetMatchingMembersNamed(resolvedMethod.Name, true,
+ tdm => {
+ var m = tdm as IMethodDefinition;
+ if (m == null) return false;
+ return TypeHelper.ParameterListsAreEquivalentAssumingGenericMethodParametersAreEquivalentIfTheirIndicesMatch(
+ m.Parameters, resolvedMethod.Parameters);
+ });
+ foreach (var mem in mems) {
+ var methodDef = mem as IMethodDefinition;
+ if (methodDef == null) continue;
+ overrides.Add(Tuple.Create<ITypeReference, IMethodReference>(subType, methodDef));
+
+ }
+ }
}
- overrides.Add(Tuple.Create<ITypeReference, IMethodReference>(subType, resolvedMethod));
- if (this.subTypes.ContainsKey(subType)) {
- overrides.AddRange(FindOverrides(subType, resolvedMethod));
+ } else {
+ foreach (var subType in this.subTypes[type]) {
+ var overridingMethod = MemberHelper.GetImplicitlyOverridingDerivedClassMethod(resolvedMethod, subType.ResolvedType);
+ if (overridingMethod != Dummy.Method) {
+ resolvedMethod = overridingMethod;
+ }
+ overrides.Add(Tuple.Create<ITypeReference, IMethodReference>(subType, resolvedMethod));
+ if (this.subTypes.ContainsKey(subType)) {
+ overrides.AddRange(FindOverrides(subType, resolvedMethod));
+ }
}
}
return overrides;
}
+ /// <summary>
+ /// Returns zero or more explicit implementations of an interface method that are defined in the given type definition.
+ /// </summary>
+ /// <remarks>
+ /// IMethodReferences are returned (as opposed to IMethodDefinitions) because the references are directly available:
+ /// no resolving is needed to find them.
+ /// </remarks>
+ public static IEnumerable<IMethodReference> GetExplicitlyImplementedMethods(ITypeDefinition typeDefinition, IMethodDefinition ifaceMethod) {
+ Contract.Requires(ifaceMethod != null);
+ Contract.Ensures(Contract.Result<IEnumerable<IMethodReference>>() != null);
+ Contract.Ensures(Contract.ForAll(Contract.Result<IEnumerable<IMethodReference>>(), x => x != null));
+
+ foreach (IMethodImplementation methodImplementation in typeDefinition.ExplicitImplementationOverrides) {
+ if (ifaceMethod.InternedKey == methodImplementation.ImplementedMethod.InternedKey)
+ yield return methodImplementation.ImplementingMethod;
+ }
+ var mems = TypeHelper.GetMethod(typeDefinition, ifaceMethod.Name, ifaceMethod.Parameters.Select(p => p.Type).ToArray());
+ }
+
+
}
}
diff --git a/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt b/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt
index 0fe003ae..0a2a515a 100644
--- a/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt
+++ b/BCT/RegressionTests/TranslationTest/GeneralHeapInput.txt
@@ -997,6 +997,36 @@ procedure RegressionTestInput.ClassWithArrayTypes.Main4$System.Int32array($this:
+implementation RegressionTestInput.ClassWithArrayTypes.Main4$System.Int32array($this: Ref, xs$in: Ref)
+{
+ var xs: Ref;
+ var $localExc: Ref;
+ var $label: int;
+
+ xs := xs$in;
+ assume {:breadcrumb 13} true;
+ if (xs != null)
+ {
+ }
+ else
+ {
+ }
+
+ if ((if xs != null then $ArrayLength(xs) > 0 else false))
+ {
+ assert {:first} {:sourceFile "C:\dev\Boogie\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 121} true;
+ assert {:sourceFile "C:\dev\Boogie\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 121} true;
+ assume $this != null;
+ assume xs != null;
+ $ArrayContents := $ArrayContents[Union2Ref(Read($Heap, $this, F$RegressionTestInput.ClassWithArrayTypes.a)) := $ArrayContents[Union2Ref(Read($Heap, $this, F$RegressionTestInput.ClassWithArrayTypes.a))][0 := Int2Union(Union2Int($ArrayContents[xs][0]))]];
+ }
+ else
+ {
+ }
+}
+
+
+
procedure RegressionTestInput.ClassWithArrayTypes.#ctor($this: Ref);
free ensures $allocImp(old($Alloc), $Alloc) == $allocConstBool(true);
diff --git a/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt b/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt
index 5dfc582e..b552ee36 100644
--- a/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt
+++ b/BCT/RegressionTests/TranslationTest/SplitFieldsHeapInput.txt
@@ -983,6 +983,36 @@ procedure RegressionTestInput.ClassWithArrayTypes.Main4$System.Int32array($this:
+implementation RegressionTestInput.ClassWithArrayTypes.Main4$System.Int32array($this: Ref, xs$in: Ref)
+{
+ var xs: Ref;
+ var $localExc: Ref;
+ var $label: int;
+
+ xs := xs$in;
+ assume {:breadcrumb 13} true;
+ if (xs != null)
+ {
+ }
+ else
+ {
+ }
+
+ if ((if xs != null then $ArrayLength(xs) > 0 else false))
+ {
+ assert {:first} {:sourceFile "C:\dev\Boogie\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 121} true;
+ assert {:sourceFile "C:\dev\Boogie\BCT\RegressionTests\RegressionTestInput\Class1.cs"} {:sourceLine 121} true;
+ assume $this != null;
+ assume xs != null;
+ $ArrayContents := $ArrayContents[F$RegressionTestInput.ClassWithArrayTypes.a[$this] := $ArrayContents[F$RegressionTestInput.ClassWithArrayTypes.a[$this]][0 := Int2Union(Union2Int($ArrayContents[xs][0]))]];
+ }
+ else
+ {
+ }
+}
+
+
+
procedure RegressionTestInput.ClassWithArrayTypes.#ctor($this: Ref);
free ensures $allocImp(old($Alloc), $Alloc) == $allocConstBool(true);
diff --git a/Binaries/DafnyPrelude.bpl b/Binaries/DafnyPrelude.bpl
index 53d0b471..ca526173 100644
--- a/Binaries/DafnyPrelude.bpl
+++ b/Binaries/DafnyPrelude.bpl
@@ -357,6 +357,10 @@ axiom (forall<T> s: Seq T, v: T, n: int ::
{ Seq#Drop(Seq#Build(s, v), n) }
0 <= n && n <= Seq#Length(s) ==> Seq#Drop(Seq#Build(s, v), n) == Seq#Build(Seq#Drop(s, n), v) );
+// Additional axioms about common things
+axiom Seq#Take(Seq#Empty(): Seq BoxType, 0) == Seq#Empty(); // [][..0] == []
+axiom Seq#Drop(Seq#Empty(): Seq BoxType, 0) == Seq#Empty(); // [][0..] == []
+
// ---------------------------------------------------------------
// -- Axiomatization of Maps -------------------------------------
// ---------------------------------------------------------------
diff --git a/Binaries/UnivBackPred2.smt2 b/Binaries/UnivBackPred2.smt2
index 97c052c9..d3e3777f 100644
--- a/Binaries/UnivBackPred2.smt2
+++ b/Binaries/UnivBackPred2.smt2
@@ -7,5 +7,3 @@
(declare-fun int_mod (Int Int) Int)
(declare-fun UOrdering2 (|T@U| |T@U|) Bool)
(declare-fun UOrdering3 (|T@T| |T@U| |T@U|) Bool)
-(declare-fun tickleBool (Bool) Bool)
-(assert (and (tickleBool true) (tickleBool false)))
diff --git a/Source/BoogieDriver/BoogieDriver.cs b/Source/BoogieDriver/BoogieDriver.cs
index 114a26cf..1653b723 100644
--- a/Source/BoogieDriver/BoogieDriver.cs
+++ b/Source/BoogieDriver/BoogieDriver.cs
@@ -237,10 +237,9 @@ namespace Microsoft.Boogie {
/// Print newline after the message.
/// </summary>
public static void Inform(string s) {
- if (!CommandLineOptions.Clo.Trace) {
- return;
+ if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.TraceProofObligations) {
+ Console.WriteLine(s);
}
- Console.WriteLine(s);
}
static void WriteTrailer(int verified, int errors, int inconclusives, int timeOuts, int outOfMemories) {
@@ -688,9 +687,9 @@ namespace Microsoft.Boogie {
List<Counterexample/*!*/>/*?*/ errors;
DateTime start = new DateTime(); // to please compiler's definite assignment rules
- if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.XmlSink != null) {
+ if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.TraceProofObligations || CommandLineOptions.Clo.XmlSink != null) {
start = DateTime.UtcNow;
- if (CommandLineOptions.Clo.Trace) {
+ if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.TraceProofObligations) {
Console.WriteLine();
Console.WriteLine("Verifying {0} ...", impl.Name);
}
@@ -741,11 +740,12 @@ namespace Microsoft.Boogie {
string timeIndication = "";
DateTime end = DateTime.UtcNow;
TimeSpan elapsed = end - start;
- if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.XmlSink != null) {
- if (CommandLineOptions.Clo.Trace) {
- int poCount = vcgen.CumulativeAssertionCount - prevAssertionCount;
- timeIndication = string.Format(" [{0} s, {1} proof obligation{2}] ", elapsed.ToString("%s\\.fff"), poCount, poCount == 1 ? "" : "s");
- }
+ if (CommandLineOptions.Clo.Trace) {
+ int poCount = vcgen.CumulativeAssertionCount - prevAssertionCount;
+ timeIndication = string.Format(" [{0:F3} s, {1} proof obligation{2}] ", elapsed.TotalSeconds, poCount, poCount == 1 ? "" : "s");
+ } else if (CommandLineOptions.Clo.TraceProofObligations) {
+ int poCount = vcgen.CumulativeAssertionCount - prevAssertionCount;
+ timeIndication = string.Format(" [{0} proof obligation{1}] ", poCount, poCount == 1 ? "" : "s");
}
ProcessOutcome(outcome, errors, timeIndication, ref errorCount, ref verified, ref inconclusives, ref timeOuts, ref outOfMemories);
diff --git a/Source/Core/AbsyCmd.cs b/Source/Core/AbsyCmd.cs
index 1367a08d..c6b66585 100644
--- a/Source/Core/AbsyCmd.cs
+++ b/Source/Core/AbsyCmd.cs
@@ -502,8 +502,13 @@ namespace Microsoft.Boogie {
CmdSeq ssBody = new CmdSeq();
CmdSeq ssDone = new CmdSeq();
if (wcmd.Guard != null) {
- ssBody.Add(new AssumeCmd(wcmd.tok, wcmd.Guard));
- ssDone.Add(new AssumeCmd(wcmd.tok, Expr.Not(wcmd.Guard)));
+ var ac = new AssumeCmd(wcmd.tok, wcmd.Guard);
+ ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List<object>(), null);
+ ssBody.Add(ac);
+
+ ac = new AssumeCmd(wcmd.tok, Expr.Not(wcmd.Guard));
+ ac.Attributes = new QKeyValue(wcmd.tok, "partition", new List<object>(), null);
+ ssDone.Add(ac);
}
// Try to squeeze in ssBody into the first block of wcmd.Body
@@ -556,8 +561,13 @@ namespace Microsoft.Boogie {
CmdSeq ssThen = new CmdSeq();
CmdSeq ssElse = new CmdSeq();
if (ifcmd.Guard != null) {
- ssThen.Add(new AssumeCmd(ifcmd.tok, ifcmd.Guard));
- ssElse.Add(new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)));
+ var ac = new AssumeCmd(ifcmd.tok, ifcmd.Guard);
+ ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), null);
+ ssThen.Add(ac);
+
+ ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard));
+ ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), null);
+ ssElse.Add(ac);
}
// Try to squeeze in ssThen/ssElse into the first block of ifcmd.thn/ifcmd.elseBlock
@@ -597,7 +607,9 @@ namespace Microsoft.Boogie {
predLabel = elseLabel;
predCmds = new CmdSeq();
if (ifcmd.Guard != null) {
- predCmds.Add(new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard)));
+ var ac = new AssumeCmd(ifcmd.tok, Expr.Not(ifcmd.Guard));
+ ac.Attributes = new QKeyValue(ifcmd.tok, "partition", new List<object>(), null);
+ predCmds.Add(ac);
}
} else {
diff --git a/Source/Core/BoogiePL.atg b/Source/Core/BoogiePL.atg
index aed741d8..9c721703 100644
--- a/Source/Core/BoogiePL.atg
+++ b/Source/Core/BoogiePL.atg
@@ -19,16 +19,15 @@ COMPILER BoogiePL
/*--------------------------------------------------------------------------*/
-static Program/*!*/ Pgm = new Program();
+readonly Program/*!*/ Pgm;
-static Expr/*!*/ dummyExpr = new LiteralExpr(Token.NoToken, false);
-static Cmd/*!*/ dummyCmd = new AssumeCmd(Token.NoToken, dummyExpr);
-static Block/*!*/ dummyBlock = new Block(Token.NoToken, "dummyBlock", new CmdSeq(),
- new ReturnCmd(Token.NoToken));
-static Bpl.Type/*!*/ dummyType = new BasicType(Token.NoToken, SimpleType.Bool);
-static Bpl.ExprSeq/*!*/ dummyExprSeq = new ExprSeq ();
-static TransferCmd/*!*/ dummyTransferCmd = new ReturnCmd(Token.NoToken);
-static StructuredCmd/*!*/ dummyStructuredCmd = new BreakCmd(Token.NoToken, null);
+readonly Expr/*!*/ dummyExpr;
+readonly Cmd/*!*/ dummyCmd;
+readonly Block/*!*/ dummyBlock;
+readonly Bpl.Type/*!*/ dummyType;
+readonly Bpl.ExprSeq/*!*/ dummyExprSeq;
+readonly TransferCmd/*!*/ dummyTransferCmd;
+readonly StructuredCmd/*!*/ dummyStructuredCmd;
///<summary>
///Returns the number of parsing errors encountered. If 0, "program" returns as
@@ -64,20 +63,33 @@ public static int Parse (string s, string/*!*/ filename, out /*maybe null*/ Prog
Errors errors = new Errors();
Scanner scanner = new Scanner(ms, errors, filename);
- Parser parser = new Parser(scanner, errors);
- Pgm = new Program(); // reset the global variable
- parser.Parse();
- if (parser.errors.count == 0)
- {
- program = Pgm;
- program.ProcessDatatypeConstructors();
- return 0;
- }
- else
- {
- program = null;
- return parser.errors.count;
- }
+ Parser parser = new Parser(scanner, errors, false);
+ parser.Parse();
+ if (parser.errors.count == 0)
+ {
+ program = parser.Pgm;
+ program.ProcessDatatypeConstructors();
+ return 0;
+ }
+ else
+ {
+ program = null;
+ return parser.errors.count;
+ }
+}
+
+public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, bool disambiguation)
+ : this(scanner, errors)
+{
+ // initialize readonly fields
+ Pgm = new Program();
+ dummyExpr = new LiteralExpr(Token.NoToken, false);
+ dummyCmd = new AssumeCmd(Token.NoToken, dummyExpr);
+ dummyBlock = new Block(Token.NoToken, "dummyBlock", new CmdSeq(), new ReturnCmd(Token.NoToken));
+ dummyType = new BasicType(Token.NoToken, SimpleType.Bool);
+ dummyExprSeq = new ExprSeq ();
+ dummyTransferCmd = new ReturnCmd(Token.NoToken);
+ dummyStructuredCmd = new BreakCmd(Token.NoToken, null);
}
// Class to represent the bounds of a bitvector expression t[a:b].
diff --git a/Source/Core/CommandLineOptions.cs b/Source/Core/CommandLineOptions.cs
index ff1a0eb1..73fa8946 100644
--- a/Source/Core/CommandLineOptions.cs
+++ b/Source/Core/CommandLineOptions.cs
@@ -254,7 +254,7 @@ namespace Microsoft.Boogie {
/// <summary>
/// This method is called after all parsing is done, if no parse errors were encountered.
/// </summary>
- protected virtual void ApplyDefaultOptions() {
+ public virtual void ApplyDefaultOptions() {
}
/// <summary>
@@ -384,6 +384,7 @@ namespace Microsoft.Boogie {
public bool Wait = false;
public bool Trace = false;
public bool TraceTimes = false;
+ public bool TraceProofObligations = false;
public bool NoResolve = false;
public bool NoTypecheck = false;
public bool OverlookBoogieTypeErrors = false;
@@ -1205,6 +1206,7 @@ namespace Microsoft.Boogie {
ps.CheckBooleanFlag("wait", ref Wait) ||
ps.CheckBooleanFlag("trace", ref Trace) ||
ps.CheckBooleanFlag("traceTimes", ref TraceTimes) ||
+ ps.CheckBooleanFlag("tracePOs", ref TraceProofObligations) ||
ps.CheckBooleanFlag("noResolve", ref NoResolve) ||
ps.CheckBooleanFlag("noTypecheck", ref NoTypecheck) ||
ps.CheckBooleanFlag("overlookTypeErrors", ref OverlookBoogieTypeErrors) ||
@@ -1244,7 +1246,7 @@ namespace Microsoft.Boogie {
return base.ParseOption(name, ps); // defer to superclass
}
- protected override void ApplyDefaultOptions() {
+ public override void ApplyDefaultOptions() {
Contract.Ensures(TheProverFactory != null);
Contract.Ensures(vcVariety != VCVariety.Unspecified);
@@ -1266,6 +1268,12 @@ namespace Microsoft.Boogie {
ProverName = "SMTLib".ToUpper();
}
+ var proverOpts = TheProverFactory.BlankProverOptions();
+ proverOpts.Parse(ProverOptions);
+ if (!TheProverFactory.SupportsLabels(proverOpts)) {
+ UseLabels = false;
+ }
+
if (vcVariety == VCVariety.Unspecified) {
vcVariety = TheProverFactory.DefaultVCVariety;
}
@@ -1509,6 +1517,8 @@ namespace Microsoft.Boogie {
/trace blurt out various debug trace information
/traceTimes output timing information at certain points in the pipeline
+ /tracePOs output information about the number of proof obligations
+ (also included in the /trace output)
/log[:method] Print debug output during translation
/break launch and break into debugger
diff --git a/Source/Core/Core.csproj b/Source/Core/Core.csproj
index cff4f7f2..9a24b6b2 100644
--- a/Source/Core/Core.csproj
+++ b/Source/Core/Core.csproj
@@ -213,6 +213,9 @@
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
+ <ItemGroup>
+ <None Include="BoogiePL.atg" />
+ </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.
diff --git a/Source/Core/Parser.cs b/Source/Core/Parser.cs
index 5a6f8098..69f505bc 100644
--- a/Source/Core/Parser.cs
+++ b/Source/Core/Parser.cs
@@ -38,16 +38,15 @@ public class Parser {
public Token/*!*/ la; // lookahead token
int errDist = minErrDist;
-static Program/*!*/ Pgm = new Program();
+readonly Program/*!*/ Pgm;
-static Expr/*!*/ dummyExpr = new LiteralExpr(Token.NoToken, false);
-static Cmd/*!*/ dummyCmd = new AssumeCmd(Token.NoToken, dummyExpr);
-static Block/*!*/ dummyBlock = new Block(Token.NoToken, "dummyBlock", new CmdSeq(),
- new ReturnCmd(Token.NoToken));
-static Bpl.Type/*!*/ dummyType = new BasicType(Token.NoToken, SimpleType.Bool);
-static Bpl.ExprSeq/*!*/ dummyExprSeq = new ExprSeq ();
-static TransferCmd/*!*/ dummyTransferCmd = new ReturnCmd(Token.NoToken);
-static StructuredCmd/*!*/ dummyStructuredCmd = new BreakCmd(Token.NoToken, null);
+readonly Expr/*!*/ dummyExpr;
+readonly Cmd/*!*/ dummyCmd;
+readonly Block/*!*/ dummyBlock;
+readonly Bpl.Type/*!*/ dummyType;
+readonly Bpl.ExprSeq/*!*/ dummyExprSeq;
+readonly TransferCmd/*!*/ dummyTransferCmd;
+readonly StructuredCmd/*!*/ dummyStructuredCmd;
///<summary>
///Returns the number of parsing errors encountered. If 0, "program" returns as
@@ -83,20 +82,33 @@ public static int Parse (string s, string/*!*/ filename, out /*maybe null*/ Prog
Errors errors = new Errors();
Scanner scanner = new Scanner(ms, errors, filename);
- Parser parser = new Parser(scanner, errors);
- Pgm = new Program(); // reset the global variable
- parser.Parse();
- if (parser.errors.count == 0)
- {
- program = Pgm;
- program.ProcessDatatypeConstructors();
- return 0;
- }
- else
- {
- program = null;
- return parser.errors.count;
- }
+ Parser parser = new Parser(scanner, errors, false);
+ parser.Parse();
+ if (parser.errors.count == 0)
+ {
+ program = parser.Pgm;
+ program.ProcessDatatypeConstructors();
+ return 0;
+ }
+ else
+ {
+ program = null;
+ return parser.errors.count;
+ }
+}
+
+public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, bool disambiguation)
+ : this(scanner, errors)
+{
+ // initialize readonly fields
+ Pgm = new Program();
+ dummyExpr = new LiteralExpr(Token.NoToken, false);
+ dummyCmd = new AssumeCmd(Token.NoToken, dummyExpr);
+ dummyBlock = new Block(Token.NoToken, "dummyBlock", new CmdSeq(), new ReturnCmd(Token.NoToken));
+ dummyType = new BasicType(Token.NoToken, SimpleType.Bool);
+ dummyExprSeq = new ExprSeq ();
+ dummyTransferCmd = new ReturnCmd(Token.NoToken);
+ dummyStructuredCmd = new BreakCmd(Token.NoToken, null);
}
// Class to represent the bounds of a bitvector expression t[a:b].
diff --git a/Source/Core/VCExp.cs b/Source/Core/VCExp.cs
index 6bc43e14..1e82224c 100644
--- a/Source/Core/VCExp.cs
+++ b/Source/Core/VCExp.cs
@@ -202,6 +202,10 @@ The generic options may or may not be used by the prover plugin.
}
}
+ public virtual bool SupportsLabels(ProverOptions options) {
+ return true;
+ }
+
public virtual void Close() {
}
diff --git a/Source/Dafny/Cloner.cs b/Source/Dafny/Cloner.cs
index 3db69fba..a5865a6f 100644
--- a/Source/Dafny/Cloner.cs
+++ b/Source/Dafny/Cloner.cs
@@ -14,7 +14,7 @@ namespace Microsoft.Dafny
if (m is DefaultModuleDecl) {
nw = new DefaultModuleDecl();
} else {
- nw = new ModuleDefinition(Tok(m.tok), name, m.IsGhost, m.IsAbstract, m.RefinementBaseName, null, true);
+ nw = new ModuleDefinition(Tok(m.tok), name, m.IsGhost, m.IsAbstract, m.RefinementBaseName, CloneAttributes(m.Attributes), true);
}
foreach (var d in m.TopLevelDecls) {
nw.TopLevelDecls.Add(CloneDeclaration(d, nw));
@@ -29,18 +29,18 @@ namespace Microsoft.Dafny
if (d is ArbitraryTypeDecl) {
var dd = (ArbitraryTypeDecl)d;
- return new ArbitraryTypeDecl(Tok(dd.tok), dd.Name, m, dd.EqualitySupport, null);
+ return new ArbitraryTypeDecl(Tok(dd.tok), dd.Name, m, dd.EqualitySupport, CloneAttributes(dd.Attributes));
} else if (d is IndDatatypeDecl) {
var dd = (IndDatatypeDecl)d;
var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);
var ctors = dd.Ctors.ConvertAll(CloneCtor);
- var dt = new IndDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, null);
+ var dt = new IndDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, CloneAttributes(dd.Attributes));
return dt;
} else if (d is CoDatatypeDecl) {
var dd = (CoDatatypeDecl)d;
var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);
var ctors = dd.Ctors.ConvertAll(CloneCtor);
- var dt = new CoDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, null);
+ var dt = new CoDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, CloneAttributes(dd.Attributes));
return dt;
} else if (d is ClassDecl) {
if (d is DefaultClassDecl) {
@@ -53,7 +53,7 @@ namespace Microsoft.Dafny
var dd = (ClassDecl)d;
var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);
var mm = dd.Members.ConvertAll(CloneMember);
- var cl = new ClassDecl(Tok(dd.tok), dd.Name, m, tps, mm, null);
+ var cl = new ClassDecl(Tok(dd.tok), dd.Name, m, tps, mm, CloneAttributes(dd.Attributes));
return cl;
}
} else if (d is ModuleDecl) {
@@ -63,13 +63,13 @@ namespace Microsoft.Dafny
return l;
} else if (d is AliasModuleDecl) {
var a = (AliasModuleDecl)d;
- var alias = new AliasModuleDecl(a.Path, a.tok, m);
+ var alias = new AliasModuleDecl(a.Path, a.tok, m, a.Opened);
alias.ModuleReference = a.ModuleReference;
alias.Signature = a.Signature;
return alias;
} else if (d is AbstractModuleDecl) {
var a = (AbstractModuleDecl)d;
- var abs = new AbstractModuleDecl(a.Path, a.tok, m, a.CompilePath);
+ var abs = new AbstractModuleDecl(a.Path, a.tok, m, a.CompilePath, a.Opened);
abs.Signature = a.Signature;
abs.OriginalSignature = a.OriginalSignature;
return abs;
@@ -84,7 +84,7 @@ namespace Microsoft.Dafny
}
public DatatypeCtor CloneCtor(DatatypeCtor ct) {
- return new DatatypeCtor(Tok(ct.tok), ct.Name, ct.Formals.ConvertAll(CloneFormal), null);
+ return new DatatypeCtor(Tok(ct.tok), ct.Name, ct.Formals.ConvertAll(CloneFormal), CloneAttributes(ct.Attributes));
}
public TypeParameter CloneTypeParam(TypeParameter tp) {
@@ -93,8 +93,9 @@ namespace Microsoft.Dafny
public MemberDecl CloneMember(MemberDecl member) {
if (member is Field) {
+ Contract.Assert(!(member is SpecialField)); // we don't expect a SpecialField to be cloned (or do we?)
var f = (Field)member;
- return new Field(Tok(f.tok), f.Name, f.IsGhost, f.IsMutable, CloneType(f.Type), null);
+ return new Field(Tok(f.tok), f.Name, f.IsGhost, f.IsMutable, CloneType(f.Type), CloneAttributes(f.Attributes));
} else if (member is Function) {
var f = (Function)member;
return CloneFunction(f);
@@ -125,7 +126,7 @@ namespace Microsoft.Dafny
} else if (t is InferredTypeProxy) {
return new InferredTypeProxy();
} else if (t is ParamTypeProxy) {
- return new ParamTypeProxy(((ParamTypeProxy)t).orig); // todo: this is not right, as when cloning the type parameter declartion changes.
+ return new ParamTypeProxy(CloneTypeParam(((ParamTypeProxy)t).orig));
} else {
Contract.Assert(false); // unexpected type (e.g., no other type proxies are expected at this time)
return null; // to please compiler
@@ -142,16 +143,23 @@ namespace Microsoft.Dafny
public Specification<Expression> CloneSpecExpr(Specification<Expression> spec) {
var ee = spec.Expressions == null ? null : spec.Expressions.ConvertAll(CloneExpr);
- return new Specification<Expression>(ee, null);
+ return new Specification<Expression>(ee, CloneAttributes(spec.Attributes));
}
public Specification<FrameExpression> CloneSpecFrameExpr(Specification<FrameExpression> frame) {
var ee = frame.Expressions == null ? null : frame.Expressions.ConvertAll(CloneFrameExpr);
- return new Specification<FrameExpression>(ee, null);
+ return new Specification<FrameExpression>(ee, CloneAttributes(frame.Attributes));
}
public FrameExpression CloneFrameExpr(FrameExpression frame) {
- return new FrameExpression(CloneExpr(frame.E), frame.FieldName);
+ return new FrameExpression(Tok(frame.tok), CloneExpr(frame.E), frame.FieldName);
+ }
+ public Attributes CloneAttributes(Attributes attrs) {
+ if (attrs == null) {
+ return null;
+ } else {
+ return new Attributes(attrs.Name, attrs.Args.ConvertAll(CloneAttrArg), CloneAttributes(attrs.Prev));
+ }
}
public Attributes.Argument CloneAttrArg(Attributes.Argument aa) {
if (aa.E != null) {
@@ -162,7 +170,9 @@ namespace Microsoft.Dafny
}
public MaybeFreeExpression CloneMayBeFreeExpr(MaybeFreeExpression expr) {
- return new MaybeFreeExpression(CloneExpr(expr.E), expr.IsFree);
+ var mfe = new MaybeFreeExpression(CloneExpr(expr.E), expr.IsFree);
+ mfe.Attributes = CloneAttributes(expr.Attributes);
+ return mfe;
}
public virtual Expression CloneExpr(Expression expr) {
@@ -247,10 +257,6 @@ namespace Microsoft.Dafny
var e = (FreshExpr)expr;
return new FreshExpr(Tok(e.tok), CloneExpr(e.E));
- } else if (expr is AllocatedExpr) {
- var e = (AllocatedExpr)expr;
- return new AllocatedExpr(Tok(e.tok), CloneExpr(e.E));
-
} else if (expr is UnaryExpr) {
var e = (UnaryExpr)expr;
return new UnaryExpr(Tok(e.tok), e.Op, CloneExpr(e.E));
@@ -277,9 +283,9 @@ namespace Microsoft.Dafny
var range = CloneExpr(e.Range);
var term = CloneExpr(e.Term);
if (e is ForallExpr) {
- return new ForallExpr(tk, bvs, range, term, null);
+ return new ForallExpr(tk, bvs, range, term, CloneAttributes(e.Attributes));
} else if (e is ExistsExpr) {
- return new ExistsExpr(tk, bvs, range, term, null);
+ return new ExistsExpr(tk, bvs, range, term, CloneAttributes(e.Attributes));
} else if (e is MapComprehension) {
return new MapComprehension(tk, bvs, range, term);
} else {
@@ -323,21 +329,24 @@ namespace Microsoft.Dafny
}
public AssignmentRhs CloneRHS(AssignmentRhs rhs) {
+ AssignmentRhs c;
if (rhs is ExprRhs) {
var r = (ExprRhs)rhs;
- return new ExprRhs(CloneExpr(r.Expr));
+ c = new ExprRhs(CloneExpr(r.Expr));
} else if (rhs is HavocRhs) {
- return new HavocRhs(Tok(rhs.Tok));
+ c = new HavocRhs(Tok(rhs.Tok));
} else {
var r = (TypeRhs)rhs;
if (r.ArrayDimensions != null) {
- return new TypeRhs(Tok(r.Tok), CloneType(r.EType), r.ArrayDimensions.ConvertAll(CloneExpr));
+ c = new TypeRhs(Tok(r.Tok), CloneType(r.EType), r.ArrayDimensions.ConvertAll(CloneExpr));
} else if (r.InitCall != null) {
- return new TypeRhs(Tok(r.Tok), CloneType(r.EType), (CallStmt)CloneStmt(r.InitCall));
+ c = new TypeRhs(Tok(r.Tok), CloneType(r.EType), (CallStmt)CloneStmt(r.InitCall));
} else {
- return new TypeRhs(Tok(r.Tok), CloneType(r.EType));
+ c = new TypeRhs(Tok(r.Tok), CloneType(r.EType));
}
}
+ c.Attributes = CloneAttributes(rhs.Attributes);
+ return c;
}
public BlockStmt CloneBlockStmt(BlockStmt stmt) {
@@ -413,6 +422,10 @@ namespace Microsoft.Dafny
var s = (ParallelStmt)stmt;
r = new ParallelStmt(Tok(s.Tok), s.BoundVars.ConvertAll(CloneBoundVar), null, CloneExpr(s.Range), s.Ens.ConvertAll(CloneMayBeFreeExpr), CloneStmt(s.Body));
+ } else if (stmt is CalcStmt) {
+ var s = (CalcStmt)stmt;
+ r = new CalcStmt(Tok(s.Tok), s.Op, s.Lines.ConvertAll(CloneExpr), s.Hints.ConvertAll(CloneStmt), new List<Nullable<BinaryExpr.Opcode>>(s.CustomOps));
+
} else if (stmt is MatchStmt) {
var s = (MatchStmt)stmt;
r = new MatchStmt(Tok(s.Tok), CloneExpr(s.Source),
@@ -436,6 +449,7 @@ namespace Microsoft.Dafny
// add labels to the cloned statement
AddStmtLabels(r, stmt.Labels);
+ r.Attributes = CloneAttributes(stmt.Attributes);
return r;
}
@@ -456,7 +470,6 @@ namespace Microsoft.Dafny
}
public Function CloneFunction(Function f) {
-
var tps = f.TypeArgs.ConvertAll(CloneTypeParam);
var formals = f.Formals.ConvertAll(CloneFormal);
var req = f.Req.ConvertAll(CloneExpr);
@@ -467,13 +480,13 @@ namespace Microsoft.Dafny
if (f is Predicate) {
return new Predicate(Tok(f.tok), f.Name, f.IsStatic, f.IsGhost, tps, f.OpenParen, formals,
- req, reads, ens, decreases, body, false, null, false);
+ req, reads, ens, decreases, body, Predicate.BodyOriginKind.OriginalOrInherited, CloneAttributes(f.Attributes), false);
} else if (f is CoPredicate) {
return new CoPredicate(Tok(f.tok), f.Name, f.IsStatic, tps, f.OpenParen, formals,
- req, reads, ens, body, null, false);
+ req, reads, ens, body, CloneAttributes(f.Attributes), false);
} else {
return new Function(Tok(f.tok), f.Name, f.IsStatic, f.IsGhost, tps, f.OpenParen, formals, CloneType(f.ResultType),
- req, reads, ens, decreases, body, null, false);
+ req, reads, ens, decreases, body, CloneAttributes(f.Attributes), false);
}
}
@@ -491,10 +504,10 @@ namespace Microsoft.Dafny
var body = CloneBlockStmt(m.Body);
if (m is Constructor) {
return new Constructor(Tok(m.tok), m.Name, tps, ins,
- req, mod, ens, decreases, body, null, false);
+ req, mod, ens, decreases, body, CloneAttributes(m.Attributes), false);
} else {
return new Method(Tok(m.tok), m.Name, m.IsStatic, m.IsGhost, tps, ins, m.Outs.ConvertAll(CloneFormal),
- req, mod, ens, decreases, body, null, false);
+ req, mod, ens, decreases, body, CloneAttributes(m.Attributes), false);
}
}
public virtual IToken Tok(IToken tok) {
diff --git a/Source/Dafny/Compiler.cs b/Source/Dafny/Compiler.cs
index 57623068..a138f4d9 100644
--- a/Source/Dafny/Compiler.cs
+++ b/Source/Dafny/Compiler.cs
@@ -25,6 +25,7 @@ namespace Microsoft.Dafny {
}
TextWriter wr;
+ Method enclosingMethod; // non-null when a method body is being translated
public int ErrorCount;
void Error(string msg, params object[] args) {
@@ -633,7 +634,17 @@ namespace Microsoft.Dafny {
if (m.Body == null) {
Error("Method {0} has no body", m.FullName);
} else {
+ if (m.IsTailRecursive) {
+ Indent(indent); wr.WriteLine("TAIL_CALL_START: ;");
+ if (!m.IsStatic) {
+ Indent(indent + IndentAmount); wr.WriteLine("var _this = this;");
+ }
+ }
+ Contract.Assert(enclosingMethod == null);
+ enclosingMethod = m;
TrStmtList(m.Body.Body, indent);
+ Contract.Assert(enclosingMethod == m);
+ enclosingMethod = null;
}
Indent(indent); wr.WriteLine("}");
@@ -1160,11 +1171,11 @@ namespace Microsoft.Dafny {
var ind = indent + i * IndentAmount;
var bound = s.Bounds[i];
var bv = s.BoundVars[i];
- if (bound is QuantifierExpr.BoolBoundedPool) {
+ if (bound is ComprehensionExpr.BoolBoundedPool) {
Indent(ind);
wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName);
- } else if (bound is QuantifierExpr.IntBoundedPool) {
- var b = (QuantifierExpr.IntBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.IntBoundedPool) {
+ var b = (ComprehensionExpr.IntBoundedPool)bound;
SpillLetVariableDecls(b.LowerBound, ind);
SpillLetVariableDecls(b.UpperBound, ind);
Indent(ind);
@@ -1173,22 +1184,22 @@ namespace Microsoft.Dafny {
wr.Write("; @{0} < ", bv.CompileName);
TrExpr(b.UpperBound);
wr.Write("; @{0}++) {{ ", bv.CompileName);
- } else if (bound is QuantifierExpr.SetBoundedPool) {
- var b = (QuantifierExpr.SetBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.SetBoundedPool) {
+ var b = (ComprehensionExpr.SetBoundedPool)bound;
SpillLetVariableDecls(b.Set, ind);
Indent(ind);
wr.Write("foreach (var @{0} in (", bv.CompileName);
TrExpr(b.Set);
wr.Write(").Elements) { ");
- } else if (bound is QuantifierExpr.SeqBoundedPool) {
- var b = (QuantifierExpr.SeqBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.SeqBoundedPool) {
+ var b = (ComprehensionExpr.SeqBoundedPool)bound;
SpillLetVariableDecls(b.Seq, ind);
Indent(ind);
wr.Write("foreach (var @{0} in (", bv.CompileName);
TrExpr(b.Seq);
wr.Write(").UniqueElements) { ");
- } else if (bound is QuantifierExpr.DatatypeBoundedPool) {
- var b = (QuantifierExpr.DatatypeBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.DatatypeBoundedPool) {
+ var b = (ComprehensionExpr.DatatypeBoundedPool)bound;
wr.Write("foreach (var @{0} in {1}.AllSingletonConstructors) {{", bv.CompileName, TypeName(bv.Type));
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type
@@ -1408,66 +1419,125 @@ namespace Microsoft.Dafny {
Contract.Requires(s != null);
Contract.Assert(s.Method != null); // follows from the fact that stmt has been successfully resolved
- var lvalues = new List<string>();
- Contract.Assert(s.Lhs.Count == s.Method.Outs.Count);
- for (int i = 0; i < s.Method.Outs.Count; i++) {
- Formal p = s.Method.Outs[i];
- if (!p.IsGhost) {
- lvalues.Add(CreateLvalue(s.Lhs[i], indent));
+ if (s.Method == enclosingMethod && enclosingMethod.IsTailRecursive) {
+ // compile call as tail-recursive
+
+ // assign the actual in-parameters to temporary variables
+ var inTmps = new List<string>();
+ for (int i = 0; i < s.Method.Ins.Count; i++) {
+ Formal p = s.Method.Ins[i];
+ if (!p.IsGhost) {
+ SpillLetVariableDecls(s.Args[i], indent);
+ }
}
- }
- var outTmps = new List<string>();
- for (int i = 0; i < s.Method.Outs.Count; i++) {
- Formal p = s.Method.Outs[i];
- if (!p.IsGhost) {
- string target = "_out" + tmpVarCount;
+ if (receiverReplacement != null) {
+ // TODO: What to do here? When does this happen, what does it mean?
+ } else if (!s.Method.IsStatic) {
+ SpillLetVariableDecls(s.Receiver, indent);
+
+ string inTmp = "_in" + tmpVarCount;
tmpVarCount++;
- outTmps.Add(target);
+ inTmps.Add(inTmp);
Indent(indent);
- wr.WriteLine("{0} {1};", TypeName(s.Lhs[i].Type), target);
+ wr.Write("var {0} = ", inTmp);
+ TrExpr(s.Receiver);
+ wr.WriteLine(";");
}
- }
- Contract.Assert(lvalues.Count == outTmps.Count);
-
- for (int i = 0; i < s.Method.Ins.Count; i++) {
- Formal p = s.Method.Ins[i];
- if (!p.IsGhost) {
- SpillLetVariableDecls(s.Args[i], indent);
+ for (int i = 0; i < s.Method.Ins.Count; i++) {
+ Formal p = s.Method.Ins[i];
+ if (!p.IsGhost) {
+ string inTmp = "_in" + tmpVarCount;
+ tmpVarCount++;
+ inTmps.Add(inTmp);
+ Indent(indent);
+ wr.Write("var {0} = ", inTmp);
+ TrExpr(s.Args[i]);
+ wr.WriteLine(";");
+ }
}
- }
- if (receiverReplacement != null) {
- Indent(indent);
- wr.Write("@" + receiverReplacement);
- } else if (s.Method.IsStatic) {
+ // Now, assign to the formals
+ int n = 0;
+ if (!s.Method.IsStatic) {
+ Indent(indent);
+ wr.WriteLine("_this = {0};", inTmps[n]);
+ n++;
+ }
+ foreach (var p in s.Method.Ins) {
+ if (!p.IsGhost) {
+ Indent(indent);
+ wr.WriteLine("{0} = {1};", p.CompileName, inTmps[n]);
+ n++;
+ }
+ }
+ Contract.Assert(n == inTmps.Count);
+ // finally, the jump back to the head of the method
Indent(indent);
- wr.Write(TypeName(cce.NonNull(s.Receiver.Type)));
+ wr.WriteLine("goto TAIL_CALL_START;");
+
} else {
- SpillLetVariableDecls(s.Receiver, indent);
- Indent(indent);
- TrParenExpr(s.Receiver);
- }
- wr.Write(".@{0}(", s.Method.CompileName);
+ // compile call as a regular call
+
+ var lvalues = new List<string>();
+ Contract.Assert(s.Lhs.Count == s.Method.Outs.Count);
+ for (int i = 0; i < s.Method.Outs.Count; i++) {
+ Formal p = s.Method.Outs[i];
+ if (!p.IsGhost) {
+ lvalues.Add(CreateLvalue(s.Lhs[i], indent));
+ }
+ }
+ var outTmps = new List<string>();
+ for (int i = 0; i < s.Method.Outs.Count; i++) {
+ Formal p = s.Method.Outs[i];
+ if (!p.IsGhost) {
+ string target = "_out" + tmpVarCount;
+ tmpVarCount++;
+ outTmps.Add(target);
+ Indent(indent);
+ wr.WriteLine("{0} {1};", TypeName(s.Lhs[i].Type), target);
+ }
+ }
+ Contract.Assert(lvalues.Count == outTmps.Count);
- string sep = "";
- for (int i = 0; i < s.Method.Ins.Count; i++) {
- Formal p = s.Method.Ins[i];
- if (!p.IsGhost) {
- wr.Write(sep);
- TrExpr(s.Args[i]);
- sep = ", ";
+ for (int i = 0; i < s.Method.Ins.Count; i++) {
+ Formal p = s.Method.Ins[i];
+ if (!p.IsGhost) {
+ SpillLetVariableDecls(s.Args[i], indent);
+ }
}
- }
+ if (receiverReplacement != null) {
+ Indent(indent);
+ wr.Write("@" + receiverReplacement);
+ } else if (s.Method.IsStatic) {
+ Indent(indent);
+ wr.Write(TypeName(cce.NonNull(s.Receiver.Type)));
+ } else {
+ SpillLetVariableDecls(s.Receiver, indent);
+ Indent(indent);
+ TrParenExpr(s.Receiver);
+ }
+ wr.Write(".@{0}(", s.Method.CompileName);
- foreach (var outTmp in outTmps) {
- wr.Write("{0}out {1}", sep, outTmp);
- sep = ", ";
- }
- wr.WriteLine(");");
+ string sep = "";
+ for (int i = 0; i < s.Method.Ins.Count; i++) {
+ Formal p = s.Method.Ins[i];
+ if (!p.IsGhost) {
+ wr.Write(sep);
+ TrExpr(s.Args[i]);
+ sep = ", ";
+ }
+ }
- // assign to the actual LHSs
- for (int j = 0; j < lvalues.Count; j++) {
- Indent(indent);
- wr.WriteLine("{0} = {1};", lvalues[j], outTmps[j]);
+ foreach (var outTmp in outTmps) {
+ wr.Write("{0}out {1}", sep, outTmp);
+ sep = ", ";
+ }
+ wr.WriteLine(");");
+
+ // assign to the actual LHSs
+ for (int j = 0; j < lvalues.Count; j++) {
+ Indent(indent);
+ wr.WriteLine("{0} = {1};", lvalues[j], outTmps[j]);
+ }
}
}
@@ -1651,7 +1721,7 @@ namespace Microsoft.Dafny {
}
} else if (expr is ThisExpr) {
- wr.Write("this");
+ wr.Write(enclosingMethod != null && enclosingMethod.IsTailRecursive ? "_this" : "this");
} else if (expr is IdentifierExpr) {
IdentifierExpr e = (IdentifierExpr)expr;
@@ -2053,32 +2123,32 @@ namespace Microsoft.Dafny {
var bound = e.Bounds[i];
var bv = e.BoundVars[i];
// emit: Dafny.Helpers.QuantX(boundsInformation, isForall, bv => body)
- if (bound is QuantifierExpr.BoolBoundedPool) {
+ if (bound is ComprehensionExpr.BoolBoundedPool) {
wr.Write("Dafny.Helpers.QuantBool(");
- } else if (bound is QuantifierExpr.IntBoundedPool) {
- var b = (QuantifierExpr.IntBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.IntBoundedPool) {
+ var b = (ComprehensionExpr.IntBoundedPool)bound;
wr.Write("Dafny.Helpers.QuantInt(");
TrExpr(b.LowerBound);
wr.Write(", ");
TrExpr(b.UpperBound);
wr.Write(", ");
- } else if (bound is QuantifierExpr.SetBoundedPool) {
- var b = (QuantifierExpr.SetBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.SetBoundedPool) {
+ var b = (ComprehensionExpr.SetBoundedPool)bound;
wr.Write("Dafny.Helpers.QuantSet(");
TrExpr(b.Set);
wr.Write(", ");
- } else if (bound is QuantifierExpr.MapBoundedPool) {
- var b = (QuantifierExpr.MapBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.MapBoundedPool) {
+ var b = (ComprehensionExpr.MapBoundedPool)bound;
wr.Write("Dafny.Helpers.QuantMap(");
TrExpr(b.Map);
wr.Write(", ");
- } else if (bound is QuantifierExpr.SeqBoundedPool) {
- var b = (QuantifierExpr.SeqBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.SeqBoundedPool) {
+ var b = (ComprehensionExpr.SeqBoundedPool)bound;
wr.Write("Dafny.Helpers.QuantSeq(");
TrExpr(b.Seq);
wr.Write(", ");
- } else if (bound is QuantifierExpr.DatatypeBoundedPool) {
- var b = (QuantifierExpr.DatatypeBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.DatatypeBoundedPool) {
+ var b = (ComprehensionExpr.DatatypeBoundedPool)bound;
wr.Write("Dafny.Helpers.QuantDatatype(");
wr.Write("{0}.AllSingletonConstructors, ", DtName(b.Decl));
@@ -2120,32 +2190,32 @@ namespace Microsoft.Dafny {
for (int i = 0; i < n; i++) {
var bound = e.Bounds[i];
var bv = e.BoundVars[i];
- if (bound is QuantifierExpr.BoolBoundedPool) {
+ if (bound is ComprehensionExpr.BoolBoundedPool) {
wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName);
- } else if (bound is QuantifierExpr.IntBoundedPool) {
- var b = (QuantifierExpr.IntBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.IntBoundedPool) {
+ var b = (ComprehensionExpr.IntBoundedPool)bound;
wr.Write("for (var @{0} = ", bv.CompileName);
TrExpr(b.LowerBound);
wr.Write("; @{0} < ", bv.CompileName);
TrExpr(b.UpperBound);
wr.Write("; @{0}++) {{ ", bv.CompileName);
- } else if (bound is QuantifierExpr.SetBoundedPool) {
- var b = (QuantifierExpr.SetBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.SetBoundedPool) {
+ var b = (ComprehensionExpr.SetBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
TrExpr(b.Set);
wr.Write(").Elements) { ");
- } else if (bound is QuantifierExpr.MapBoundedPool) {
- var b = (QuantifierExpr.MapBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.MapBoundedPool) {
+ var b = (ComprehensionExpr.MapBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
TrExpr(b.Map);
wr.Write(").Domain) { ");
- } else if (bound is QuantifierExpr.SeqBoundedPool) {
- var b = (QuantifierExpr.SeqBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.SeqBoundedPool) {
+ var b = (ComprehensionExpr.SeqBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
TrExpr(b.Seq);
wr.Write(").Elements) { ");
- } else if (bound is QuantifierExpr.DatatypeBoundedPool) {
- var b = (QuantifierExpr.DatatypeBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.DatatypeBoundedPool) {
+ var b = (ComprehensionExpr.DatatypeBoundedPool)bound;
wr.Write("foreach (var @{0} in {1}.AllSingletonConstructors) {{", bv.CompileName, TypeName(bv.Type));
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type
@@ -2189,27 +2259,27 @@ namespace Microsoft.Dafny {
Contract.Assert(e.Bounds.Count == n && n == 1);
var bound = e.Bounds[0];
var bv = e.BoundVars[0];
- if (bound is QuantifierExpr.BoolBoundedPool) {
+ if (bound is ComprehensionExpr.BoolBoundedPool) {
wr.Write("foreach (var @{0} in Dafny.Helpers.AllBooleans) {{ ", bv.CompileName);
- } else if (bound is QuantifierExpr.IntBoundedPool) {
- var b = (QuantifierExpr.IntBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.IntBoundedPool) {
+ var b = (ComprehensionExpr.IntBoundedPool)bound;
wr.Write("for (var @{0} = ", bv.CompileName);
TrExpr(b.LowerBound);
wr.Write("; @{0} < ", bv.CompileName);
TrExpr(b.UpperBound);
wr.Write("; @{0}++) {{ ", bv.CompileName);
- } else if (bound is QuantifierExpr.SetBoundedPool) {
- var b = (QuantifierExpr.SetBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.SetBoundedPool) {
+ var b = (ComprehensionExpr.SetBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
TrExpr(b.Set);
wr.Write(").Elements) { ");
- } else if (bound is QuantifierExpr.MapBoundedPool) {
- var b = (QuantifierExpr.MapBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.MapBoundedPool) {
+ var b = (ComprehensionExpr.MapBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
TrExpr(b.Map);
wr.Write(").Domain) { ");
- } else if (bound is QuantifierExpr.SeqBoundedPool) {
- var b = (QuantifierExpr.SeqBoundedPool)bound;
+ } else if (bound is ComprehensionExpr.SeqBoundedPool) {
+ var b = (ComprehensionExpr.SeqBoundedPool)bound;
wr.Write("foreach (var @{0} in (", bv.CompileName);
TrExpr(b.Seq);
wr.Write(").Elements) { ");
diff --git a/Source/Dafny/Dafny.atg b/Source/Dafny/Dafny.atg
index 52639f07..646d6ee4 100644
--- a/Source/Dafny/Dafny.atg
+++ b/Source/Dafny/Dafny.atg
@@ -14,13 +14,15 @@ using System.IO;
using System.Text;
COMPILER Dafny
/*--------------------------------------------------------------------------*/
-static ModuleDecl theModule;
-static BuiltIns theBuiltIns;
-static Expression/*!*/ dummyExpr = new LiteralExpr(Token.NoToken);
-static FrameExpression/*!*/ dummyFrameExpr = new FrameExpression(dummyExpr, null);
-static Statement/*!*/ dummyStmt = new ReturnStmt(Token.NoToken, null);
-static Attributes.Argument/*!*/ dummyAttrArg = new Attributes.Argument(Token.NoToken, "dummyAttrArg");
-static int anonymousIds = 0;
+readonly Expression/*!*/ dummyExpr;
+readonly AssignmentRhs/*!*/ dummyRhs;
+readonly FrameExpression/*!*/ dummyFrameExpr;
+readonly Statement/*!*/ dummyStmt;
+readonly Attributes.Argument/*!*/ dummyAttrArg;
+readonly ModuleDecl theModule;
+readonly BuiltIns theBuiltIns;
+int anonymousIds = 0;
+
struct MemberModifiers {
public bool IsGhost;
public bool IsStatic;
@@ -71,19 +73,26 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, ModuleDecl module,
Contract.Requires(filename != null);
Contract.Requires(module != null);
Contract.Requires(errors != null);
- var oldModule = theModule;
- theModule = module;
- BuiltIns oldBuiltIns = builtIns;
- theBuiltIns = builtIns;
byte[]/*!*/ buffer = cce.NonNull( UTF8Encoding.Default.GetBytes(s));
MemoryStream ms = new MemoryStream(buffer,false);
Scanner scanner = new Scanner(ms, errors, filename);
- Parser parser = new Parser(scanner, errors);
+ Parser parser = new Parser(scanner, errors, module, builtIns);
parser.Parse();
- theModule = oldModule;
- theBuiltIns = oldBuiltIns;
return parser.errors.count;
}
+public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, ModuleDecl module, BuiltIns builtIns)
+ : this(scanner, errors) // the real work
+{
+ // initialize readonly fields
+ dummyExpr = new LiteralExpr(Token.NoToken);
+ dummyRhs = new ExprRhs(dummyExpr, null);
+ dummyFrameExpr = new FrameExpression(dummyExpr.tok, dummyExpr, null);
+ dummyStmt = new ReturnStmt(Token.NoToken, null);
+ dummyAttrArg = new Attributes.Argument(Token.NoToken, "dummyAttrArg");
+ theModule = module;
+ theBuiltIns = builtIns;
+}
+
bool IsAttribute() {
Token x = scanner.Peek();
return la.kind == _lbrace && x.kind == _colon;
@@ -177,11 +186,12 @@ SubModuleDecl<ModuleDefinition parent, bool isOverallModuleGhost, out ModuleDecl
ModuleDefinition module;
ModuleDecl sm;
submodule = null; // appease compiler
+ bool opened = false;
.)
- "module"
+ ( "module"
{ Attribute<ref attrs> }
NoUSIdent<out id>
- ((
+
[ "refines" QualifiedName<out idRefined> ] (. module = new ModuleDefinition(id, id.val, isOverallModuleGhost, false, idRefined == null ? null : idRefined, attrs, false); .)
"{" (. module.BodyStartTok = t; .)
{ (. isGhost = false; .)
@@ -199,14 +209,17 @@ SubModuleDecl<ModuleDefinition parent, bool isOverallModuleGhost, out ModuleDecl
"}" (. module.BodyEndTok = t;
module.TopLevelDecls.Add(new DefaultClassDecl(module, namedModuleDefaultClassMembers));
submodule = new LiteralModuleDecl(module, parent); .)
- ) |
- "=" QualifiedName<out idPath> ";" (. submodule = new AliasModuleDecl(idPath, id, parent); .)
- |
- ( "as" QualifiedName<out idPath>
- ["=" QualifiedName<out idAssignment> ]
- ";" (.submodule = new AbstractModuleDecl(idPath, id, parent, idAssignment); .)
+ |
+ "import" ["opened" (.opened = true;.)]
+ ( NoUSIdent<out id> ( "=" QualifiedName<out idPath> ";"
+ (. submodule = new AliasModuleDecl(idPath, id, parent, opened); .)
+ | ";"
+ (. idPath = new List<IToken>(); idPath.Add(id); submodule = new AliasModuleDecl(idPath, id, parent, opened); .)
+ | "as" QualifiedName<out idPath> ["default" QualifiedName<out idAssignment> ] ";"
+ (.submodule = new AbstractModuleDecl(idPath, id, parent, idAssignment, opened); .)
+ )
)
- )
+ )
.
QualifiedName<.out List<IToken> ids.>
@@ -305,8 +318,8 @@ FieldDecl<.MemberModifiers mmod, List<MemberDecl/*!*/>/*!*/ mm.>
(. if (mmod.IsStatic) { SemErr(t, "fields cannot be declared 'static'"); }
.)
{ Attribute<ref attrs> }
- IdentType<out id, out ty> (. mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs)); .)
- { "," IdentType<out id, out ty> (. mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs)); .)
+ IdentType<out id, out ty, false> (. mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs)); .)
+ { "," IdentType<out id, out ty, false> (. mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs)); .)
}
SYNC ";"
.
@@ -329,18 +342,18 @@ GIdentType<bool allowGhostKeyword, out IToken/*!*/ id, out Type/*!*/ ty, out boo
isGhost = false; .)
[ "ghost" (. if (allowGhostKeyword) { isGhost = true; } else { SemErr(t, "formal cannot be declared 'ghost' in this context"); } .)
]
- IdentType<out id, out ty>
+ IdentType<out id, out ty, true>
.
-IdentType<out IToken/*!*/ id, out Type/*!*/ ty>
+IdentType<out IToken/*!*/ id, out Type/*!*/ ty, bool allowWildcardId>
= (.Contract.Ensures(Contract.ValueAtReturn(out id) != null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null);.)
- NoUSIdent<out id>
+ WildIdent<out id, allowWildcardId>
":"
Type<out ty>
.
LocalIdentTypeOptional<out VarDecl/*!*/ var, bool isGhost>
= (. IToken/*!*/ id; Type/*!*/ ty; Type optType = null;
.)
- NoUSIdent<out id>
+ WildIdent<out id, true>
[ ":" Type<out ty> (. optType = ty; .)
]
(. var = new VarDecl(id, id.val, optType == null ? new InferredTypeProxy() : optType, isGhost); .)
@@ -348,7 +361,7 @@ LocalIdentTypeOptional<out VarDecl/*!*/ var, bool isGhost>
IdentTypeOptional<out BoundVar/*!*/ var>
= (. Contract.Ensures(Contract.ValueAtReturn(out var)!=null); IToken/*!*/ id; Type/*!*/ ty; Type optType = null;
.)
- NoUSIdent<out id>
+ WildIdent<out id, true>
[ ":" Type<out ty> (. optType = ty; .)
]
(. var = new BoundVar(id, id.val, optType == null ? new InferredTypeProxy() : optType); .)
@@ -386,10 +399,10 @@ GenericParameters<.List<TypeParameter/*!*/>/*!*/ typeArgs.>
TypeParameter.EqualitySupportValue eqSupport;
.)
"<"
- NoUSIdent<out id> (. eqSupport = TypeParameter.EqualitySupportValue.Unspecified; .)
+ NoUSIdent<out id> (. eqSupport = TypeParameter.EqualitySupportValue.Unspecified; .)
[ "(" "==" ")" (. eqSupport = TypeParameter.EqualitySupportValue.Required; .)
] (. typeArgs.Add(new TypeParameter(id, id.val, eqSupport)); .)
- { "," NoUSIdent<out id> (. eqSupport = TypeParameter.EqualitySupportValue.Unspecified; .)
+ { "," NoUSIdent<out id> (. eqSupport = TypeParameter.EqualitySupportValue.Unspecified; .)
[ "(" "==" ")" (. eqSupport = TypeParameter.EqualitySupportValue.Required; .)
] (. typeArgs.Add(new TypeParameter(id, id.val, eqSupport)); .)
}
@@ -474,7 +487,7 @@ MethodSpec<.List<MaybeFreeExpression/*!*/>/*!*/ req, List<FrameExpression/*!*/>/
( "requires" Expression<out e> SYNC ";" (. req.Add(new MaybeFreeExpression(e, isFree)); .)
| "ensures" { IF(IsAttribute()) Attribute<ref ensAttrs> } Expression<out e> SYNC ";" (. ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs)); .)
)
- | "decreases" { IF(IsAttribute()) Attribute<ref decAttrs> } DecreasesList<decreases, false> SYNC ";"
+ | "decreases" { IF(IsAttribute()) Attribute<ref decAttrs> } DecreasesList<decreases, true> SYNC ";"
)
.
Formals<.bool incoming, bool allowGhostKeyword, List<Formal/*!*/>/*!*/ formals, out IToken openParen.>
@@ -647,7 +660,7 @@ FunctionDecl<MemberModifiers mmod, out Function/*!*/ f>
]
(. if (isPredicate) {
f = new Predicate(id, id.val, mmod.IsStatic, !isFunctionMethod, typeArgs, openParen, formals,
- reqs, reads, ens, new Specification<Expression>(decreases, null), body, false, attrs, signatureOmitted);
+ reqs, reads, ens, new Specification<Expression>(decreases, null), body, Predicate.BodyOriginKind.OriginalOrInherited, attrs, signatureOmitted);
} else if (isCoPredicate) {
f = new CoPredicate(id, id.val, mmod.IsStatic, typeArgs, openParen, formals,
reqs, reads, ens, body, attrs, signatureOmitted);
@@ -698,19 +711,24 @@ PossiblyWildFrameExpression<out FrameExpression/*!*/ fe>
* any use of the function. Nevertheless, as an experimental feature, the
* language allows it (and it is sound).
*/
- ( "*" (. fe = new FrameExpression(new WildcardExpr(t), null); .)
+ ( "*" (. fe = new FrameExpression(t, new WildcardExpr(t), null); .)
| FrameExpression<out fe>
)
.
FrameExpression<out FrameExpression/*!*/ fe>
-= (. Contract.Ensures(Contract.ValueAtReturn(out fe) != null); Expression/*!*/ e; IToken/*!*/ id; string fieldName = null; fe = null; .)
- (( Expression<out e>
- [ "`" Ident<out id> (. fieldName = id.val; .)
+= (. Contract.Ensures(Contract.ValueAtReturn(out fe) != null);
+ Expression/*!*/ e;
+ IToken/*!*/ id;
+ string fieldName = null; IToken feTok = null;
+ fe = null;
+ .)
+ (( Expression<out e> (. feTok = e.tok; .)
+ [ "`" Ident<out id> (. fieldName = id.val; feTok = id; .)
]
- (. fe = new FrameExpression(e, fieldName); .)
+ (. fe = new FrameExpression(feTok, e, fieldName); .)
) |
( "`" Ident<out id> (. fieldName = id.val; .)
- (. fe = new FrameExpression(new ImplicitThisExpr(id), fieldName); .)
+ (. fe = new FrameExpression(id, new ImplicitThisExpr(id), fieldName); .)
))
.
FunctionBody<out Expression/*!*/ e, out IToken bodyStart, out IToken bodyEnd>
@@ -753,6 +771,7 @@ OneStmt<out Statement/*!*/ s>
| WhileStmt<out s>
| MatchStmt<out s>
| ParallelStmt<out s>
+ | CalcStmt<out s>
| "label" (. x = t; .)
NoUSIdent<out id> ":"
OneStmt<out s> (. s.Labels = new LList<Label>(new Label(x, id.val), s.Labels); .)
@@ -845,12 +864,13 @@ UpdateStmt<out Statement/*!*/ s>
.)
.
Rhs<out AssignmentRhs r, Expression receiverForInitCall>
-= (. IToken/*!*/ x, newToken; Expression/*!*/ e;
+= (. Contract.Ensures(Contract.ValueAtReturn<AssignmentRhs>(out r) != null);
+ IToken/*!*/ x, newToken; Expression/*!*/ e;
List<Expression> ee = null;
Type ty = null;
CallStmt initCall = null;
List<Expression> args;
- r = null; // to please compiler
+ r = dummyRhs; // to please compiler
Attributes attrs = null;
.)
( "new" (. newToken = t; .)
@@ -895,7 +915,7 @@ Rhs<out AssignmentRhs r, Expression receiverForInitCall>
| "*" (. r = new HavocRhs(t); .)
| Expression<out e> (. r = new ExprRhs(e); .)
)
- { Attribute<ref attrs> } (. if (r != null) r.Attributes = attrs; .)
+ { Attribute<ref attrs> } (. r.Attributes = attrs; .)
.
VarDeclStatement<.out Statement/*!*/ s.>
= (. IToken x = null, assignTok = null; bool isGhost = false;
@@ -1027,6 +1047,8 @@ WhileStmt<out Statement/*!*/ stmt>
stmt = new WhileStmt(x, guard, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(null, null), body);
stmt = new SkeletonStatement(stmt, guardOmitted, bodyOmitted);
} else {
+ // The following statement protects against crashes in case of parsing errors
+ body = body ?? new BlockStmt(x, new List<Statement>());
stmt = new WhileStmt(x, guard, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), body);
}
.)
@@ -1066,13 +1088,13 @@ Invariant<out MaybeFreeExpression/*!*/ invariant>
DecreasesList<.List<Expression/*!*/> decreases, bool allowWildcard.>
= (. Expression/*!*/ e; .)
PossiblyWildExpression<out e> (. if (!allowWildcard && e is WildcardExpr) {
- SemErr(e.tok, "'decreases *' is only allowed on loops");
+ SemErr(e.tok, "'decreases *' is only allowed on loops and tail-recursive methods");
} else {
decreases.Add(e);
}
.)
{ "," PossiblyWildExpression<out e> (. if (!allowWildcard && e is WildcardExpr) {
- SemErr(e.tok, "'decreases *' is only allowed on loops");
+ SemErr(e.tok, "'decreases *' is only allowed on loops and tail-recursive methods");
} else {
decreases.Add(e);
}
@@ -1194,6 +1216,69 @@ ParallelStmt<out Statement/*!*/ s>
BlockStmt<out block, out bodyStart, out bodyEnd>
(. s = new ParallelStmt(x, bvars, attrs, range, ens, block); .)
.
+
+CalcStmt<out Statement/*!*/ s>
+= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);
+ Token x;
+ BinaryExpr.Opcode op, calcOp = BinaryExpr.Opcode.Eq, resOp = BinaryExpr.Opcode.Eq;
+ List<Expression/*!*/> lines = new List<Expression/*!*/>();
+ List<Statement> hints = new List<Statement>();
+ List<BinaryExpr.Opcode?> customOps = new List<BinaryExpr.Opcode?>();
+ BinaryExpr.Opcode? maybeOp;
+ Expression/*!*/ e;
+ BlockStmt/*!*/ block;
+ Statement/*!*/ h;
+ IToken bodyStart, bodyEnd, opTok;
+ .)
+ "calc" (. x = t; .)
+ [ CalcOp<out opTok, out calcOp> ] (. resOp = calcOp; .)
+ "{"
+ Expression<out e> (. lines.Add(e); .)
+ ";"
+ {
+ ( BlockStmt<out block, out bodyStart, out bodyEnd> (. hints.Add(block); .)
+ | CalcStmt<out h> (. hints.Add(h); .)
+ | (. hints.Add(null); .)
+ )
+ ( CalcOp<out opTok, out op> (. maybeOp = Microsoft.Dafny.CalcStmt.ResultOp(resOp, op);
+ if (maybeOp == null) {
+ customOps.Add(null); // pretend the operator was not there to satisfy the precondition of the CalcStmt contructor
+ SemErr(opTok, "this operator cannot continue this calculation");
+ } else {
+ customOps.Add(op);
+ resOp = (BinaryExpr.Opcode)maybeOp;
+ }
+ .)
+ | (. customOps.Add(null); .)
+ )
+ Expression<out e> (. lines.Add(e); .)
+ ";"
+ }
+ "}"
+ (. s = new CalcStmt(x, calcOp, lines, hints, customOps); .)
+ .
+CalcOp<out IToken x, out BinaryExpr.Opcode/*!*/ op>
+= (. Contract.Ensures(Microsoft.Dafny.CalcStmt.ValidOp(Contract.ValueAtReturn(out op)));
+ op = BinaryExpr.Opcode.Eq; // Returns Eq if parsing fails because it is compatible with any other operator
+ x = null;
+ .)
+ ( RelOp<out x, out op> (. if (op == BinaryExpr.Opcode.Add) {
+ // Parsing of RelOp failed, do not report an error again and return Eq
+ op = BinaryExpr.Opcode.Eq;
+ } else if (!Microsoft.Dafny.CalcStmt.ValidOp(op)) {
+ // Invalid operator: resport an error and return Eq
+ SemErr(x, "this operator is not allowed in calculations");
+ op = BinaryExpr.Opcode.Eq;
+ }
+ .)
+ | EquivOp (. op = BinaryExpr.Opcode.Iff;
+ x = t;
+ .)
+ | ImpliesOp (. op = BinaryExpr.Opcode.Imp;
+ x = t;
+ .)
+ )
+ .
/*------------------------------------------------------------------------*/
Expression<out Expression/*!*/ e>
=
@@ -1390,14 +1475,21 @@ UnaryExpression<out Expression/*!*/ e>
| DottedIdentifiersAndFunction<out e>
{ Suffix<ref e> }
| DisplayExpr<out e>
+ { Suffix<ref e> }
| MultiSetExpr<out e>
- | MapExpr<out e>
+ { Suffix<ref e> }
+ | "map" (. x = t; .)
+ ( MapDisplayExpr<x, out e>
+ { Suffix<ref e> }
+ | MapComprehensionExpr<x, out e>
+ | (. SemErr("map must be followed by literal in brackets or comprehension."); .)
+ )
| ConstAtomExpression<out e>
{ Suffix<ref e> }
)
.
Lhs<out Expression e>
-= (. e = null; // to please the compiler
+= (. e = dummyExpr; // the assignment is to please the compiler, the dummy value to satisfy contracts in the event of a parse error
.)
( DottedIdentifiersAndFunction<out e>
{ Suffix<ref e> }
@@ -1423,8 +1515,6 @@ ConstAtomExpression<out Expression/*!*/ e>
| "this" (. e = new ThisExpr(t); .)
| "fresh" (. x = t; .)
"(" Expression<out e> ")" (. e = new FreshExpr(x, e); .)
- | "allocated" (. x = t; .)
- "(" Expression<out e> ")" (. e = new AllocatedExpr(x, e); .)
| "old" (. x = t; .)
"(" Expression<out e> ")" (. e = new OldExpr(x, e); .)
| "|" (. x = t; .)
@@ -1463,39 +1553,36 @@ MultiSetExpr<out Expression e>
| (. SemErr("multiset must be followed by multiset literal or expression to coerce in parentheses."); .)
)
.
-MapExpr<out Expression e>
+MapDisplayExpr<IToken/*!*/ mapToken, out Expression e>
= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);
- IToken/*!*/ x = Token.NoToken;
- List<ExpressionPair/*!*/>/*!*/ elements;
+ List<ExpressionPair/*!*/>/*!*/ elements= new List<ExpressionPair/*!*/>() ;
e = dummyExpr;
.)
- "map" (. x = t; .)
- ( "[" (. elements = new List<ExpressionPair/*!*/>(); .)
- [ MapLiteralExpressions<out elements> ] (. e = new MapDisplayExpr(x, elements);.)
- "]"
- | (
- (.
- BoundVar/*!*/ bv;
- List<BoundVar/*!*/> bvars = new List<BoundVar/*!*/>();
- Expression/*!*/ range;
- Expression body = null;
- .)
- IdentTypeOptional<out bv> (. bvars.Add(bv); .)
- "|" Expression<out range>
- QSep
- Expression<out body>
- (. e = new MapComprehension(x, bvars, range, body); .)
- )
- | (. SemErr("map must be followed by literal in brackets or comprehension."); .)
- )
+ "["
+ [ MapLiteralExpressions<out elements> ] (. e = new MapDisplayExpr(mapToken, elements);.)
+ "]"
.
MapLiteralExpressions<.out List<ExpressionPair> elements.>
= (. Expression/*!*/ d, r;
- elements = new List<ExpressionPair/*!*/>(); .)
+ elements = new List<ExpressionPair/*!*/>(); .)
Expression<out d> ":=" Expression<out r> (. elements.Add(new ExpressionPair(d,r)); .)
{ "," Expression<out d> ":=" Expression<out r>(. elements.Add(new ExpressionPair(d,r)); .)
}
.
+MapComprehensionExpr<IToken/*!*/ mapToken, out Expression e>
+= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);
+ BoundVar/*!*/ bv;
+ List<BoundVar/*!*/> bvars = new List<BoundVar/*!*/>();
+ Expression range = null;
+ Expression body;
+ .)
+ IdentTypeOptional<out bv> (. bvars.Add(bv); .)
+ [ "|" Expression<out range> ]
+ QSep
+ Expression<out body>
+ (. e = new MapComprehension(mapToken, bvars, range ?? new LiteralExpr(mapToken, true), body);
+ .)
+ .
EndlessExpression<out Expression e>
= (. IToken/*!*/ x;
Expression e0, e1;
@@ -1756,12 +1843,26 @@ Ident<out IToken/*!*/ x>
NoUSIdent<out IToken/*!*/ x>
= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); .)
ident (. x = t;
- if (x.val.Length > 0 && x.val.StartsWith("_")) {
+ if (x.val.StartsWith("_")) {
SemErr("cannot declare identifier beginning with underscore");
}
.)
.
+// Identifier, disallowing leading underscores, except possibly the "wildcard" identifier "_"
+WildIdent<out IToken/*!*/ x, bool allowWildcardId>
+= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); .)
+ ident (. x = t;
+ if (x.val.StartsWith("_")) {
+ if (allowWildcardId && x.val.Length == 1) {
+ t.val = "_v" + anonymousIds++;
+ } else {
+ SemErr("cannot declare identifier beginning with underscore");
+ }
+ }
+ .)
+ .
+
Nat<out BigInteger n>
=
digits
diff --git a/Source/Dafny/DafnyAst.cs b/Source/Dafny/DafnyAst.cs
index 4a211aee..36f0aace 100644
--- a/Source/Dafny/DafnyAst.cs
+++ b/Source/Dafny/DafnyAst.cs
@@ -20,7 +20,7 @@ namespace Microsoft.Dafny {
public readonly string Name;
public List<ModuleDefinition/*!*/>/*!*/ Modules; // filled in during resolution.
- // Resolution essentially flattens the module heirarchy, for
+ // Resolution essentially flattens the module hierarchy, for
// purposes of translation and compilation.
public List<ModuleDefinition> CompileModules; // filled in during resolution.
// Contains the definitions to be used for compilation.
@@ -28,6 +28,7 @@ namespace Microsoft.Dafny {
public readonly ModuleDecl DefaultModule;
public readonly ModuleDefinition DefaultModuleDef;
public readonly BuiltIns BuiltIns;
+ public readonly List<TranslationTask> TranslationTasks;
public Program(string name, [Captured] ModuleDecl module, [Captured] BuiltIns builtIns) {
Contract.Requires(name != null);
Contract.Requires(module != null);
@@ -38,6 +39,7 @@ namespace Microsoft.Dafny {
BuiltIns = builtIns;
Modules = new List<ModuleDefinition>();
CompileModules = new List<ModuleDefinition>();
+ TranslationTasks = new List<TranslationTask>();
}
}
@@ -186,6 +188,13 @@ namespace Microsoft.Dafny {
}
}
+ [Pure]
+ public abstract string TypeName(ModuleDefinition/*?*/ context);
+ [Pure]
+ public override string ToString() {
+ return TypeName(null);
+ }
+
/// <summary>
/// Return the most constrained version of "this".
/// </summary>
@@ -309,14 +318,14 @@ namespace Microsoft.Dafny {
public class BoolType : BasicType {
[Pure]
- public override string ToString() {
+ public override string TypeName(ModuleDefinition context) {
return "bool";
}
}
public class IntType : BasicType {
[Pure]
- public override string ToString() {
+ public override string TypeName(ModuleDefinition context) {
return "int";
}
}
@@ -324,7 +333,7 @@ namespace Microsoft.Dafny {
public class NatType : IntType
{
[Pure]
- public override string ToString() {
+ public override string TypeName(ModuleDefinition context) {
return "nat";
}
}
@@ -332,7 +341,7 @@ namespace Microsoft.Dafny {
public class ObjectType : BasicType
{
[Pure]
- public override string ToString() {
+ public override string TypeName(ModuleDefinition context) {
return "object";
}
}
@@ -360,10 +369,10 @@ namespace Microsoft.Dafny {
Contract.Requires(arg != null);
}
[Pure]
- public override string ToString() {
+ public override string TypeName(ModuleDefinition context) {
Contract.Ensures(Contract.Result<string>() != null);
Contract.Assume(cce.IsPeerConsistent(Arg));
- return "set<" + base.Arg + ">";
+ return "set<" + base.Arg.TypeName(context) + ">";
}
}
@@ -373,10 +382,10 @@ namespace Microsoft.Dafny {
Contract.Requires(arg != null);
}
[Pure]
- public override string ToString() {
+ public override string TypeName(ModuleDefinition context) {
Contract.Ensures(Contract.Result<string>() != null);
Contract.Assume(cce.IsPeerConsistent(Arg));
- return "multiset<" + base.Arg + ">";
+ return "multiset<" + base.Arg.TypeName(context) + ">";
}
}
@@ -386,10 +395,10 @@ namespace Microsoft.Dafny {
}
[Pure]
- public override string ToString() {
+ public override string TypeName(ModuleDefinition context) {
Contract.Ensures(Contract.Result<string>() != null);
Contract.Assume(cce.IsPeerConsistent(Arg));
- return "seq<" + base.Arg + ">";
+ return "seq<" + base.Arg.TypeName(context) + ">";
}
}
public class MapType : CollectionType
@@ -403,11 +412,11 @@ namespace Microsoft.Dafny {
get { return Arg; }
}
[Pure]
- public override string ToString() {
+ public override string TypeName(ModuleDefinition context) {
Contract.Ensures(Contract.Result<string>() != null);
Contract.Assume(cce.IsPeerConsistent(Domain));
Contract.Assume(cce.IsPeerConsistent(Range));
- return "map<" + Domain +", " + Range + ">";
+ return "map<" + Domain.TypeName(context) + ", " + Range.TypeName(context) + ">";
}
}
@@ -529,12 +538,20 @@ namespace Microsoft.Dafny {
}
[Pure]
- public override string ToString() {
+ public override string TypeName(ModuleDefinition context) {
Contract.Ensures(Contract.Result<string>() != null);
-
- string s = Util.Comma(".", Path, i => i.val) + (Path.Count == 0 ? "" : ".") + Name;
+ string s = "";
+ foreach (var t in Path) {
+ if (context != null && t == context.tok) {
+ // drop the prefix up to here
+ s = "";
+ } else {
+ s += t.val + ".";
+ }
+ }
+ s += Name;
if (TypeArgs.Count != 0) {
- s += "<" + Util.Comma(",", TypeArgs, ty => ty.ToString()) + ">";
+ s += "<" + Util.Comma(",", TypeArgs, ty => ty.TypeName(context)) + ">";
}
return s;
}
@@ -575,11 +592,11 @@ namespace Microsoft.Dafny {
}
[Pure]
- public override string ToString() {
+ public override string TypeName(ModuleDefinition context) {
Contract.Ensures(Contract.Result<string>() != null);
Contract.Assume(T == null || cce.IsPeerConsistent(T));
- return T == null ? "?" : T.ToString();
+ return T == null ? "?" : T.TypeName(context);
}
public override bool SupportsEquality {
get {
@@ -781,6 +798,14 @@ namespace Microsoft.Dafny {
public bool NecessaryForEqualitySupportOfSurroundingInductiveDatatype = false; // computed during resolution; relevant only when Parent denotes an IndDatatypeDecl
+ public bool IsAbstractTypeDeclaration { // true if this type parameter represents t in type t;
+ get { return parent == null; }
+ }
+ public bool IsToplevelScope { // true if this type parameter is on a toplevel (ie. class C<T>), and false if it is on a member (ie. method m<T>(...))
+ get { return parent is TopLevelDecl; }
+ }
+ public int PositionalIndex; // which type parameter this is (ie. in C<S, T, U>, S is 0, T is 1 and U is 2).
+
public TypeParameter(IToken tok, string name, EqualitySupportValue equalitySupport = EqualitySupportValue.Unspecified)
: base(tok, name, null) {
Contract.Requires(tok != null);
@@ -789,15 +814,17 @@ namespace Microsoft.Dafny {
}
}
- // Represents a submodule declartion at module level scope
+ // Represents a submodule declaration at module level scope
abstract public class ModuleDecl : TopLevelDecl
{
public ModuleSignature Signature; // filled in by resolution, in topological order.
public int Height;
- public ModuleDecl(IToken tok, string name, ModuleDefinition parent)
+ public readonly bool Opened;
+ public ModuleDecl(IToken tok, string name, ModuleDefinition parent, bool opened)
: base(tok, name, parent, new List<TypeParameter>(), null) {
Height = -1;
- Signature = null;
+ Signature = null;
+ Opened = opened;
}
}
// Represents module X { ... }
@@ -805,7 +832,7 @@ namespace Microsoft.Dafny {
{
public readonly ModuleDefinition ModuleDef;
public LiteralModuleDecl(ModuleDefinition module, ModuleDefinition parent)
- : base(module.tok, module.Name, parent) {
+ : base(module.tok, module.Name, parent, false) {
ModuleDef = module;
}
}
@@ -816,8 +843,8 @@ namespace Microsoft.Dafny {
// be detected and warned.
public readonly List<IToken> Path; // generated by the parser, this is looked up
public ModuleDecl Root; // the moduleDecl that Path[0] refers to.
- public AliasModuleDecl(List<IToken> path, IToken name, ModuleDefinition parent)
- : base(name, name.val, parent) {
+ public AliasModuleDecl(List<IToken> path, IToken name, ModuleDefinition parent, bool opened)
+ : base(name, name.val, parent, opened) {
Contract.Requires(path != null && path.Count > 0);
Path = path;
ModuleReference = null;
@@ -832,8 +859,8 @@ namespace Microsoft.Dafny {
public readonly List<IToken> CompilePath;
public ModuleSignature OriginalSignature;
- public AbstractModuleDecl(List<IToken> path, IToken name, ModuleDefinition parent, List<IToken> compilePath)
- : base(name, name.val, parent) {
+ public AbstractModuleDecl(List<IToken> path, IToken name, ModuleDefinition parent, List<IToken> compilePath, bool opened)
+ : base(name, name.val, parent, opened) {
Path = path;
Root = null;
CompilePath = compilePath;
@@ -882,7 +909,7 @@ namespace Microsoft.Dafny {
Contract.Invariant(CallGraph != null);
}
- public ModuleDefinition(IToken tok, string name, bool isGhost, bool isAbstract, List<IToken> refinementBase, Attributes attributes, bool isBuiltinName)
+ public ModuleDefinition(IToken tok, string name, bool isGhost, bool isAbstract, List<IToken> refinementBase, Attributes attributes, bool isBuiltinName)
: base(tok, name, attributes) {
Contract.Requires(tok != null);
Contract.Requires(name != null);
@@ -958,6 +985,13 @@ namespace Microsoft.Dafny {
return Module.Name + "." + Name;
}
}
+ public string FullNameInContext(ModuleDefinition context) {
+ if (Module == context) {
+ return Name;
+ } else {
+ return Module.Name + "." + Name;
+ }
+ }
public string FullCompileName {
get {
return Module.CompileName + "." + CompileName;
@@ -981,8 +1015,6 @@ namespace Microsoft.Dafny {
Contract.Requires(module != null);
Contract.Requires(cce.NonNullElements(typeArgs));
Contract.Requires(cce.NonNullElements(members));
-
-
Members = members;
}
public virtual bool IsDefaultClass {
@@ -1137,6 +1169,12 @@ namespace Microsoft.Dafny {
return EnclosingClass.FullName + "." + Name;
}
}
+ public string FullNameInContext(ModuleDefinition context) {
+ Contract.Requires(EnclosingClass != null);
+ Contract.Ensures(Contract.Result<string>() != null);
+
+ return EnclosingClass.FullNameInContext(context) + "." + Name;
+ }
public string FullCompileName {
get {
Contract.Requires(EnclosingClass != null);
@@ -1241,6 +1279,9 @@ namespace Microsoft.Dafny {
string/*!*/ Name {
get;
}
+ string/*!*/ DisplayName { // what the user thinks he wrote
+ get;
+ }
string/*!*/ UniqueName {
get;
}
@@ -1265,6 +1306,12 @@ namespace Microsoft.Dafny {
throw new NotImplementedException();
}
}
+ public string DisplayName {
+ get {
+ Contract.Ensures(Contract.Result<string>() != null);
+ throw new NotImplementedException();
+ }
+ }
public string UniqueName {
get {
Contract.Ensures(Contract.Result<string>() != null);
@@ -1312,6 +1359,9 @@ namespace Microsoft.Dafny {
return name;
}
}
+ public string/*!*/ DisplayName {
+ get { return VarDecl.DisplayNameHelper(this); }
+ }
readonly int varId = varIdCount++;
public string UniqueName {
get {
@@ -1508,14 +1558,20 @@ namespace Microsoft.Dafny {
public class Predicate : Function
{
- public readonly bool BodyIsExtended; // says that this predicate definition is a refinement extension of a predicate definition is a refining module
+ public enum BodyOriginKind
+ {
+ OriginalOrInherited, // this predicate definition is new (and the predicate may or may not have a body), or the predicate's body (whether or not it exists) is being inherited unmodified (from the previous refinement--it may be that the inherited body was itself an extension, for example)
+ DelayedDefinition, // this predicate declaration provides, for the first time, a body--the declaration refines a previously declared predicate, but the previous one had no body
+ Extension // this predicate extends the definition of a predicate with a body in a module being refined
+ }
+ public readonly BodyOriginKind BodyOrigin;
public Predicate(IToken tok, string name, bool isStatic, bool isGhost,
List<TypeParameter> typeArgs, IToken openParen, List<Formal> formals,
List<Expression> req, List<FrameExpression> reads, List<Expression> ens, Specification<Expression> decreases,
- Expression body, bool bodyIsExtended, Attributes attributes, bool signatureOmitted)
+ Expression body, BodyOriginKind bodyOrigin, Attributes attributes, bool signatureOmitted)
: base(tok, name, isStatic, isGhost, typeArgs, openParen, formals, new BoolType(), req, reads, ens, decreases, body, attributes, signatureOmitted) {
- Contract.Requires(!bodyIsExtended || body != null);
- BodyIsExtended = bodyIsExtended;
+ Contract.Requires(bodyOrigin == Predicate.BodyOriginKind.OriginalOrInherited || body != null);
+ BodyOrigin = bodyOrigin;
}
}
@@ -1535,6 +1591,7 @@ namespace Microsoft.Dafny {
public class Method : MemberDecl, TypeParameter.ParentType
{
public readonly bool SignatureIsOmitted;
+ public bool MustReverify;
public readonly List<TypeParameter/*!*/>/*!*/ TypeArgs;
public readonly List<Formal/*!*/>/*!*/ Ins;
public readonly List<Formal/*!*/>/*!*/ Outs;
@@ -1543,6 +1600,7 @@ namespace Microsoft.Dafny {
public readonly List<MaybeFreeExpression/*!*/>/*!*/ Ens;
public readonly Specification<Expression>/*!*/ Decreases;
public BlockStmt Body; // Body is readonly after construction, except for any kind of rewrite that may take place around the time of resolution
+ public bool IsTailRecursive; // filled in during resolution
[ContractInvariantMethod]
void ObjectInvariant() {
@@ -1583,6 +1641,7 @@ namespace Microsoft.Dafny {
this.Decreases = decreases;
this.Body = body;
this.SignatureIsOmitted = signatureOmitted;
+ MustReverify = false;
}
}
@@ -1653,6 +1712,13 @@ namespace Microsoft.Dafny {
public virtual IEnumerable<Statement> SubStatements {
get { yield break; }
}
+
+ /// <summary>
+ /// Returns the non-null expressions of this statement proper (that is, do not include the expressions of substatements).
+ /// </summary>
+ public virtual IEnumerable<Expression> SubExpressions {
+ get { yield break; }
+ }
}
public class LList<T>
@@ -1717,6 +1783,11 @@ namespace Microsoft.Dafny {
Contract.Requires(expr != null);
this.Expr = expr;
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ yield return Expr;
+ }
+ }
}
public class AssertStmt : PredicateStmt {
@@ -1749,6 +1820,15 @@ namespace Microsoft.Dafny {
Args = args;
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ foreach (var arg in Args) {
+ if (arg.E != null) {
+ yield return arg.E;
+ }
+ }
+ }
+ }
}
public class BreakStmt : Statement {
@@ -1783,6 +1863,17 @@ namespace Microsoft.Dafny {
this.rhss = rhss;
hiddenUpdate = null;
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ if (rhss != null) {
+ foreach (var rhs in rhss) {
+ foreach (var ee in rhs.SubExpressions) {
+ yield return ee;
+ }
+ }
+ }
+ }
+ }
}
public abstract class AssignmentRhs {
@@ -2031,6 +2122,14 @@ namespace Microsoft.Dafny {
AssumeToken = assumeToken;
}
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ yield return Expr;
+ foreach (var lhs in Lhss) {
+ yield return lhs;
+ }
+ }
+ }
}
public class UpdateStmt : ConcreteUpdateStatement
@@ -2091,6 +2190,15 @@ namespace Microsoft.Dafny {
}
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ yield return Lhs;
+ foreach (var ee in Rhs.SubExpressions) {
+ yield return ee;
+ }
+ }
+ }
+
/// <summary>
/// This method assumes "lhs" has been successfully resolved.
/// </summary>
@@ -2135,6 +2243,17 @@ namespace Microsoft.Dafny {
return name;
}
}
+ public static bool HasWildcardName(IVariable v) {
+ Contract.Requires(v != null);
+ return v.Name.StartsWith("_");
+ }
+ public static string DisplayNameHelper(IVariable v) {
+ Contract.Requires(v != null);
+ return HasWildcardName(v) ? "_" : v.Name;
+ }
+ public string/*!*/ DisplayName {
+ get { return DisplayNameHelper(this); }
+ }
readonly int varId = NonglobalVariable.varIdCount++;
public string/*!*/ UniqueName {
get {
@@ -2209,6 +2328,18 @@ namespace Microsoft.Dafny {
this.MethodName = methodName;
this.Args = args;
}
+
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ foreach (var ee in Lhs) {
+ yield return ee;
+ }
+ yield return Receiver;
+ foreach (var ee in Args) {
+ yield return ee;
+ }
+ }
+ }
}
public class BlockStmt : Statement {
@@ -2251,6 +2382,13 @@ namespace Microsoft.Dafny {
}
}
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ if (Guard != null) {
+ yield return Guard;
+ }
+ }
+ }
}
public class GuardedAlternative
@@ -2297,6 +2435,13 @@ namespace Microsoft.Dafny {
}
}
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ foreach (var alt in Alternatives) {
+ yield return alt.Guard;
+ }
+ }
+ }
}
public abstract class LoopStmt : Statement
@@ -2322,6 +2467,23 @@ namespace Microsoft.Dafny {
this.Decreases = decreases;
this.Mod = mod;
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ foreach (var mfe in Invariants) {
+ yield return mfe.E;
+ }
+ if (Decreases.Expressions != null) {
+ foreach (var e in Decreases.Expressions) {
+ yield return e;
+ }
+ }
+ if (Mod.Expressions != null) {
+ foreach (var fe in Mod.Expressions) {
+ yield return fe.E;
+ }
+ }
+ }
+ }
}
public class WhileStmt : LoopStmt
@@ -2348,6 +2510,16 @@ namespace Microsoft.Dafny {
yield return Body;
}
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ if (Guard != null) {
+ yield return Guard;
+ }
+ foreach (var e in base.SubExpressions) {
+ yield return e;
+ }
+ }
+ }
}
/// <summary>
@@ -2389,6 +2561,16 @@ namespace Microsoft.Dafny {
}
}
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ foreach (var alt in Alternatives) {
+ yield return alt.Guard;
+ }
+ foreach (var e in base.SubExpressions) {
+ yield return e;
+ }
+ }
+ }
}
public class ParallelStmt : Statement
@@ -2470,6 +2652,120 @@ namespace Microsoft.Dafny {
yield return Body;
}
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ yield return Range;
+ foreach (var ee in Ens) {
+ yield return ee.E;
+ }
+ }
+ }
+ }
+
+ public class CalcStmt : Statement
+ {
+ public readonly BinaryExpr.Opcode/*!*/ Op; // main operator of the calculation
+ public readonly List<Expression/*!*/> Lines;
+ public readonly List<Statement> Hints; // Hints[i] comes after line i; null denotes an empty an empty hint
+ public readonly List<BinaryExpr.Opcode?> CustomOps; // CustomOps[i] comes after line i; null denotes the absence of a custom operator
+ public readonly List<BinaryExpr/*!*/> Steps; // expressions li op l<i + 1>, filled in during resolution in order to get the correct op
+ public BinaryExpr Result; // expressions l0 op ln, filled in during resolution in order to get the correct op
+
+ public static readonly BinaryExpr.Opcode/*!*/ DefaultOp = BinaryExpr.Opcode.Eq;
+
+ [ContractInvariantMethod]
+ void ObjectInvariant()
+ {
+ Contract.Invariant(ValidOp(Op));
+ Contract.Invariant(Lines != null);
+ Contract.Invariant(Hints != null);
+ Contract.Invariant(CustomOps != null);
+ Contract.Invariant(Steps != null);
+ Contract.Invariant(Lines.Count > 0);
+ Contract.Invariant(Hints.Count == Lines.Count - 1);
+ Contract.Invariant(CustomOps.Count == Lines.Count - 1);
+ }
+
+ public CalcStmt(IToken tok, BinaryExpr.Opcode/*!*/ op, List<Expression/*!*/> lines, List<Statement> hints, List<BinaryExpr.Opcode?> customOps)
+ // Attributes attrs?
+ : base(tok)
+ {
+ Contract.Requires(tok != null);
+ Contract.Requires(ValidOp(op));
+ Contract.Requires(lines != null);
+ Contract.Requires(cce.NonNullElements(lines));
+ Contract.Requires(hints != null);
+ Contract.Requires(lines.Count > 0);
+ Contract.Requires(hints.Count == lines.Count - 1);
+ Contract.Requires(customOps != null);
+ Contract.Requires(customOps.Count == lines.Count - 1);
+ this.Op = op;
+ this.Lines = lines;
+ this.Hints = hints;
+ this.CustomOps = customOps;
+ this.Steps = new List<BinaryExpr>();
+ this.Result = null;
+ }
+
+ public override IEnumerable<Statement> SubStatements
+ {
+ get {
+ foreach (var h in Hints) {
+ if (h != null) yield return h;
+ }
+ }
+ }
+ public override IEnumerable<Expression> SubExpressions
+ {
+ get {
+ foreach (var l in Lines) {
+ yield return l;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Is op a valid calculation operator (i.e. a transitive relational operator)?
+ /// </summary>
+ [Pure]
+ public static bool ValidOp(BinaryExpr.Opcode op) {
+ return op == BinaryExpr.Opcode.Eq || op == BinaryExpr.Opcode.Lt || op == BinaryExpr.Opcode.Le || op == BinaryExpr.Opcode.Gt || op == BinaryExpr.Opcode.Ge
+ || op == BinaryExpr.Opcode.Iff || op == BinaryExpr.Opcode.Imp;
+ }
+
+ /// <summary>
+ /// Does op1 subsume op2 (i.e. forall x, y, z :: (x op1 y op2 z) || (x op2 y op1 z) ==> x op1 z)?
+ /// </summary>
+ [Pure]
+ private static bool Subsumes(BinaryExpr.Opcode op1, BinaryExpr.Opcode op2) {
+ Contract.Requires(ValidOp(op1) && ValidOp(op2));
+ if (op1 == op2)
+ return true;
+ if (op1 == BinaryExpr.Opcode.Iff || op1 == BinaryExpr.Opcode.Imp || op2 == BinaryExpr.Opcode.Iff || op2 == BinaryExpr.Opcode.Imp)
+ return op2 == BinaryExpr.Opcode.Eq ||
+ (op1 == BinaryExpr.Opcode.Imp && op2 == BinaryExpr.Opcode.Iff) ||
+ (op1 == BinaryExpr.Opcode.Eq && op2 == BinaryExpr.Opcode.Iff);
+ return op2 == BinaryExpr.Opcode.Eq ||
+ (op1 == BinaryExpr.Opcode.Lt && op2 == BinaryExpr.Opcode.Le) ||
+ (op1 == BinaryExpr.Opcode.Gt && op2 == BinaryExpr.Opcode.Ge);
+ }
+
+ /// <summary>
+ /// Resulting operator x op z if x op1 y op2 z.
+ /// (Least upper bound in the Subsumes order).
+ /// Returns null if neither of op1 or op2 subsumes the other.
+ /// </summary>
+ [Pure]
+ public static BinaryExpr.Opcode? ResultOp(BinaryExpr.Opcode op1, BinaryExpr.Opcode op2) {
+ Contract.Requires(ValidOp(op1) && ValidOp(op2));
+ Contract.Ensures(Contract.Result<BinaryExpr.Opcode?>() == null || ValidOp((BinaryExpr.Opcode)Contract.Result<BinaryExpr.Opcode?>()));
+ if (Subsumes(op1, op2)) {
+ return op1;
+ } else if (Subsumes(op2, op1)) {
+ return op2;
+ }
+ return null;
+ }
}
public class MatchStmt : Statement
@@ -2503,6 +2799,11 @@ namespace Microsoft.Dafny {
}
}
}
+ public override IEnumerable<Expression> SubExpressions {
+ get {
+ yield return Source;
+ }
+ }
}
public class MatchCaseStmt : MatchCase
@@ -3117,26 +3418,6 @@ namespace Microsoft.Dafny {
}
}
- public class AllocatedExpr : Expression
- {
- public readonly Expression E;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(E != null);
- }
-
- public AllocatedExpr(IToken tok, Expression expr)
- : base(tok) {
- Contract.Requires(tok != null);
- Contract.Requires(expr != null);
- E = expr;
- }
-
- public override IEnumerable<Expression> SubExpressions {
- get { yield return E; }
- }
- }
-
public class UnaryExpr : Expression
{
public enum Opcode {
@@ -3498,6 +3779,11 @@ namespace Microsoft.Dafny {
public readonly Expression Set;
public SetBoundedPool(Expression set) { Set = set; }
}
+ public class SuperSetBoundedPool : BoundedPool
+ {
+ public readonly Expression LowerBound;
+ public SuperSetBoundedPool(Expression set) { LowerBound = set; }
+ }
public class MapBoundedPool : BoundedPool
{
public readonly Expression Map;
@@ -3871,6 +4157,7 @@ namespace Microsoft.Dafny {
public class FrameExpression {
+ public readonly IToken tok;
public readonly Expression E; // may be a WildcardExpr
[ContractInvariantMethod]
void ObjectInvariant() {
@@ -3881,10 +4168,15 @@ namespace Microsoft.Dafny {
public readonly string FieldName;
public Field Field; // filled in during resolution (but is null if FieldName is)
- public FrameExpression(Expression e, string fieldName) {
+ /// <summary>
+ /// If a "fieldName" is given, then "tok" denotes its source location. Otherwise, "tok"
+ /// denotes the source location of "e".
+ /// </summary>
+ public FrameExpression(IToken tok, Expression e, string fieldName) {
+ Contract.Requires(tok != null);
Contract.Requires(e != null);
Contract.Requires(!(e is WildcardExpr) || fieldName == null);
-
+ this.tok = tok;
E = e;
FieldName = fieldName;
}
@@ -4015,5 +4307,26 @@ namespace Microsoft.Dafny {
return Attributes != null;
}
}
+ public abstract class TranslationTask
+ {
+ }
+ public class MethodCheck : TranslationTask
+ {
+ public readonly Method Refined;
+ public readonly Method Refining;
+ public MethodCheck(Method a, Method b) {
+ Refined = b;
+ Refining = a;
+ }
+ }
+ public class FunctionCheck : TranslationTask
+ {
+ public readonly Function Refined;
+ public readonly Function Refining;
+ public FunctionCheck(Function a, Function b) {
+ Refined = b;
+ Refining = a;
+ }
+ }
}
diff --git a/Source/Dafny/DafnyOptions.cs b/Source/Dafny/DafnyOptions.cs
index 34fa0487..d5057017 100644
--- a/Source/Dafny/DafnyOptions.cs
+++ b/Source/Dafny/DafnyOptions.cs
@@ -97,7 +97,7 @@ namespace Microsoft.Dafny
return base.ParseOption(name, ps);
}
- protected override void ApplyDefaultOptions() {
+ public override void ApplyDefaultOptions() {
base.ApplyDefaultOptions();
// expand macros in filenames, now that LogPrefix is fully determined
diff --git a/Source/Dafny/Parser.cs b/Source/Dafny/Parser.cs
index ad2009c2..3a310cd9 100644
--- a/Source/Dafny/Parser.cs
+++ b/Source/Dafny/Parser.cs
@@ -21,7 +21,7 @@ public class Parser {
public const int _colon = 5;
public const int _lbrace = 6;
public const int _rbrace = 7;
- public const int maxT = 109;
+ public const int maxT = 112;
const bool T = true;
const bool x = false;
@@ -34,13 +34,15 @@ public class Parser {
public Token/*!*/ la; // lookahead token
int errDist = minErrDist;
-static ModuleDecl theModule;
-static BuiltIns theBuiltIns;
-static Expression/*!*/ dummyExpr = new LiteralExpr(Token.NoToken);
-static FrameExpression/*!*/ dummyFrameExpr = new FrameExpression(dummyExpr, null);
-static Statement/*!*/ dummyStmt = new ReturnStmt(Token.NoToken, null);
-static Attributes.Argument/*!*/ dummyAttrArg = new Attributes.Argument(Token.NoToken, "dummyAttrArg");
-static int anonymousIds = 0;
+readonly Expression/*!*/ dummyExpr;
+readonly AssignmentRhs/*!*/ dummyRhs;
+readonly FrameExpression/*!*/ dummyFrameExpr;
+readonly Statement/*!*/ dummyStmt;
+readonly Attributes.Argument/*!*/ dummyAttrArg;
+readonly ModuleDecl theModule;
+readonly BuiltIns theBuiltIns;
+int anonymousIds = 0;
+
struct MemberModifiers {
public bool IsGhost;
public bool IsStatic;
@@ -91,19 +93,26 @@ public static int Parse (string/*!*/ s, string/*!*/ filename, ModuleDecl module,
Contract.Requires(filename != null);
Contract.Requires(module != null);
Contract.Requires(errors != null);
- var oldModule = theModule;
- theModule = module;
- BuiltIns oldBuiltIns = builtIns;
- theBuiltIns = builtIns;
byte[]/*!*/ buffer = cce.NonNull( UTF8Encoding.Default.GetBytes(s));
MemoryStream ms = new MemoryStream(buffer,false);
Scanner scanner = new Scanner(ms, errors, filename);
- Parser parser = new Parser(scanner, errors);
+ Parser parser = new Parser(scanner, errors, module, builtIns);
parser.Parse();
- theModule = oldModule;
- theBuiltIns = oldBuiltIns;
return parser.errors.count;
}
+public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, ModuleDecl module, BuiltIns builtIns)
+ : this(scanner, errors) // the real work
+{
+ // initialize readonly fields
+ dummyExpr = new LiteralExpr(Token.NoToken);
+ dummyRhs = new ExprRhs(dummyExpr, null);
+ dummyFrameExpr = new FrameExpression(dummyExpr.tok, dummyExpr, null);
+ dummyStmt = new ReturnStmt(Token.NoToken, null);
+ dummyAttrArg = new Attributes.Argument(Token.NoToken, "dummyAttrArg");
+ theModule = module;
+ theBuiltIns = builtIns;
+}
+
bool IsAttribute() {
Token x = scanner.Peek();
return la.kind == _lbrace && x.kind == _colon;
@@ -195,24 +204,24 @@ bool IsAttribute() {
Get();
isGhost = true;
}
- if (la.kind == 9) {
+ if (la.kind == 9 || la.kind == 11) {
SubModuleDecl(defaultModule, isGhost, out submodule);
defaultModule.TopLevelDecls.Add(submodule);
- } else if (la.kind == 15) {
+ } else if (la.kind == 18) {
if (isGhost) { SemErr(t, "a class is not allowed to be declared as 'ghost'"); }
ClassDecl(defaultModule, out c);
defaultModule.TopLevelDecls.Add(c);
- } else if (la.kind == 17 || la.kind == 18) {
+ } else if (la.kind == 20 || la.kind == 21) {
if (isGhost) { SemErr(t, "a datatype/codatatype is not allowed to be declared as 'ghost'"); }
DatatypeDecl(defaultModule, out dt);
defaultModule.TopLevelDecls.Add(dt);
- } else if (la.kind == 22) {
+ } else if (la.kind == 25) {
if (isGhost) { SemErr(t, "a type is not allowed to be declared as 'ghost'"); }
ArbitraryTypeDecl(defaultModule, out at);
defaultModule.TopLevelDecls.Add(at);
} else if (StartOf(2)) {
ClassMemberDecl(membersDefaultClass, isGhost, false);
- } else SynErr(110);
+ } else SynErr(113);
}
DefaultClassDecl defaultClass = null;
foreach (TopLevelDecl topleveldecl in defaultModule.TopLevelDecls) {
@@ -238,13 +247,14 @@ bool IsAttribute() {
ModuleDefinition module;
ModuleDecl sm;
submodule = null; // appease compiler
+ bool opened = false;
- Expect(9);
- while (la.kind == 6) {
- Attribute(ref attrs);
- }
- NoUSIdent(out id);
- if (la.kind == 6 || la.kind == 10) {
+ if (la.kind == 9) {
+ Get();
+ while (la.kind == 6) {
+ Attribute(ref attrs);
+ }
+ NoUSIdent(out id);
if (la.kind == 10) {
Get();
QualifiedName(out idRefined);
@@ -258,24 +268,24 @@ bool IsAttribute() {
Get();
isGhost = true;
}
- if (la.kind == 9) {
+ if (la.kind == 9 || la.kind == 11) {
SubModuleDecl(module, isGhost, out sm);
module.TopLevelDecls.Add(sm);
- } else if (la.kind == 15) {
+ } else if (la.kind == 18) {
if (isGhost) { SemErr(t, "a class is not allowed to be declared as 'ghost'"); }
ClassDecl(module, out c);
module.TopLevelDecls.Add(c);
- } else if (la.kind == 17 || la.kind == 18) {
+ } else if (la.kind == 20 || la.kind == 21) {
if (isGhost) { SemErr(t, "a datatype/codatatype is not allowed to be declared as 'ghost'"); }
DatatypeDecl(module, out dt);
module.TopLevelDecls.Add(dt);
- } else if (la.kind == 22) {
+ } else if (la.kind == 25) {
if (isGhost) { SemErr(t, "a type is not allowed to be declared as 'ghost'"); }
ArbitraryTypeDecl(module, out at);
module.TopLevelDecls.Add(at);
} else if (StartOf(2)) {
ClassMemberDecl(namedModuleDefaultClassMembers, isGhost, false);
- } else SynErr(111);
+ } else SynErr(114);
}
Expect(7);
module.BodyEndTok = t;
@@ -283,19 +293,30 @@ bool IsAttribute() {
submodule = new LiteralModuleDecl(module, parent);
} else if (la.kind == 11) {
Get();
- QualifiedName(out idPath);
- Expect(12);
- submodule = new AliasModuleDecl(idPath, id, parent);
- } else if (la.kind == 13) {
- Get();
- QualifiedName(out idPath);
- if (la.kind == 11) {
+ if (la.kind == 12) {
Get();
- QualifiedName(out idAssignment);
+ opened = true;
}
- Expect(12);
- submodule = new AbstractModuleDecl(idPath, id, parent, idAssignment);
- } else SynErr(112);
+ NoUSIdent(out id);
+ if (la.kind == 13) {
+ Get();
+ QualifiedName(out idPath);
+ Expect(14);
+ submodule = new AliasModuleDecl(idPath, id, parent, opened);
+ } else if (la.kind == 14) {
+ Get();
+ idPath = new List<IToken>(); idPath.Add(id); submodule = new AliasModuleDecl(idPath, id, parent, opened);
+ } else if (la.kind == 15) {
+ Get();
+ QualifiedName(out idPath);
+ if (la.kind == 16) {
+ Get();
+ QualifiedName(out idAssignment);
+ }
+ Expect(14);
+ submodule = new AbstractModuleDecl(idPath, id, parent, idAssignment, opened);
+ } else SynErr(115);
+ } else SynErr(116);
}
void ClassDecl(ModuleDefinition/*!*/ module, out ClassDecl/*!*/ c) {
@@ -307,13 +328,13 @@ bool IsAttribute() {
List<MemberDecl/*!*/> members = new List<MemberDecl/*!*/>();
IToken bodyStart;
- while (!(la.kind == 0 || la.kind == 15)) {SynErr(113); Get();}
- Expect(15);
+ while (!(la.kind == 0 || la.kind == 18)) {SynErr(117); Get();}
+ Expect(18);
while (la.kind == 6) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 26) {
+ if (la.kind == 29) {
GenericParameters(typeArgs);
}
Expect(6);
@@ -338,29 +359,29 @@ bool IsAttribute() {
IToken bodyStart = Token.NoToken; // dummy assignment
bool co = false;
- while (!(la.kind == 0 || la.kind == 17 || la.kind == 18)) {SynErr(114); Get();}
- if (la.kind == 17) {
+ while (!(la.kind == 0 || la.kind == 20 || la.kind == 21)) {SynErr(118); Get();}
+ if (la.kind == 20) {
Get();
- } else if (la.kind == 18) {
+ } else if (la.kind == 21) {
Get();
co = true;
- } else SynErr(115);
+ } else SynErr(119);
while (la.kind == 6) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 26) {
+ if (la.kind == 29) {
GenericParameters(typeArgs);
}
- Expect(11);
+ Expect(13);
bodyStart = t;
DatatypeMemberDecl(ctors);
- while (la.kind == 19) {
+ while (la.kind == 22) {
Get();
DatatypeMemberDecl(ctors);
}
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(116); Get();}
- Expect(12);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(120); Get();}
+ Expect(14);
if (co) {
dt = new CoDatatypeDecl(id, id.val, module, typeArgs, ctors, attrs);
} else {
@@ -376,20 +397,20 @@ bool IsAttribute() {
Attributes attrs = null;
var eqSupport = TypeParameter.EqualitySupportValue.Unspecified;
- Expect(22);
+ Expect(25);
while (la.kind == 6) {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 23) {
+ if (la.kind == 26) {
Get();
- Expect(24);
- Expect(25);
+ Expect(27);
+ Expect(28);
eqSupport = TypeParameter.EqualitySupportValue.Required;
}
at = new ArbitraryTypeDecl(id, id.val, module, eqSupport, attrs);
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(117); Get();}
- Expect(12);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(121); Get();}
+ Expect(14);
}
void ClassMemberDecl(List<MemberDecl/*!*/>/*!*/ mm, bool isAlreadyGhost, bool allowConstructors) {
@@ -399,7 +420,7 @@ bool IsAttribute() {
MemberModifiers mmod = new MemberModifiers();
mmod.IsGhost = isAlreadyGhost;
- while (la.kind == 8 || la.kind == 16) {
+ while (la.kind == 8 || la.kind == 19) {
if (la.kind == 8) {
Get();
mmod.IsGhost = true;
@@ -408,15 +429,15 @@ bool IsAttribute() {
mmod.IsStatic = true;
}
}
- if (la.kind == 20) {
+ if (la.kind == 23) {
FieldDecl(mmod, mm);
- } else if (la.kind == 45 || la.kind == 46 || la.kind == 47) {
+ } else if (la.kind == 48 || la.kind == 49 || la.kind == 50) {
FunctionDecl(mmod, out f);
mm.Add(f);
- } else if (la.kind == 28 || la.kind == 29) {
+ } else if (la.kind == 31 || la.kind == 32) {
MethodDecl(mmod, allowConstructors, out m);
mm.Add(m);
- } else SynErr(118);
+ } else SynErr(122);
}
void Attribute(ref Attributes attrs) {
@@ -429,7 +450,7 @@ bool IsAttribute() {
Contract.Ensures(Contract.ValueAtReturn(out x) != null);
Expect(1);
x = t;
- if (x.val.Length > 0 && x.val.StartsWith("_")) {
+ if (x.val.StartsWith("_")) {
SemErr("cannot declare identifier beginning with underscore");
}
@@ -439,7 +460,7 @@ bool IsAttribute() {
IToken id; ids = new List<IToken>();
Ident(out id);
ids.Add(id);
- while (la.kind == 14) {
+ while (la.kind == 17) {
Get();
Ident(out id);
ids.Add(id);
@@ -457,29 +478,29 @@ bool IsAttribute() {
IToken/*!*/ id;
TypeParameter.EqualitySupportValue eqSupport;
- Expect(26);
+ Expect(29);
NoUSIdent(out id);
eqSupport = TypeParameter.EqualitySupportValue.Unspecified;
- if (la.kind == 23) {
+ if (la.kind == 26) {
Get();
- Expect(24);
- Expect(25);
+ Expect(27);
+ Expect(28);
eqSupport = TypeParameter.EqualitySupportValue.Required;
}
typeArgs.Add(new TypeParameter(id, id.val, eqSupport));
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
NoUSIdent(out id);
eqSupport = TypeParameter.EqualitySupportValue.Unspecified;
- if (la.kind == 23) {
+ if (la.kind == 26) {
Get();
- Expect(24);
- Expect(25);
+ Expect(27);
+ Expect(28);
eqSupport = TypeParameter.EqualitySupportValue.Required;
}
typeArgs.Add(new TypeParameter(id, id.val, eqSupport));
}
- Expect(27);
+ Expect(30);
}
void FieldDecl(MemberModifiers mmod, List<MemberDecl/*!*/>/*!*/ mm) {
@@ -487,22 +508,22 @@ bool IsAttribute() {
Attributes attrs = null;
IToken/*!*/ id; Type/*!*/ ty;
- while (!(la.kind == 0 || la.kind == 20)) {SynErr(119); Get();}
- Expect(20);
+ while (!(la.kind == 0 || la.kind == 23)) {SynErr(123); Get();}
+ Expect(23);
if (mmod.IsStatic) { SemErr(t, "fields cannot be declared 'static'"); }
while (la.kind == 6) {
Attribute(ref attrs);
}
- IdentType(out id, out ty);
+ IdentType(out id, out ty, false);
mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs));
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
- IdentType(out id, out ty);
+ IdentType(out id, out ty, false);
mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs));
}
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(120); Get();}
- Expect(12);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(124); Get();}
+ Expect(14);
}
void FunctionDecl(MemberModifiers mmod, out Function/*!*/ f) {
@@ -524,9 +545,9 @@ bool IsAttribute() {
IToken bodyEnd = Token.NoToken;
bool signatureOmitted = false;
- if (la.kind == 45) {
+ if (la.kind == 48) {
Get();
- if (la.kind == 28) {
+ if (la.kind == 31) {
Get();
isFunctionMethod = true;
}
@@ -536,22 +557,22 @@ bool IsAttribute() {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 23 || la.kind == 26) {
- if (la.kind == 26) {
+ if (la.kind == 26 || la.kind == 29) {
+ if (la.kind == 29) {
GenericParameters(typeArgs);
}
Formals(true, isFunctionMethod, formals, out openParen);
Expect(5);
Type(out returnType);
- } else if (la.kind == 31) {
+ } else if (la.kind == 34) {
Get();
signatureOmitted = true;
openParen = Token.NoToken;
- } else SynErr(121);
- } else if (la.kind == 46) {
+ } else SynErr(125);
+ } else if (la.kind == 49) {
Get();
isPredicate = true;
- if (la.kind == 28) {
+ if (la.kind == 31) {
Get();
isFunctionMethod = true;
}
@@ -562,22 +583,22 @@ bool IsAttribute() {
}
NoUSIdent(out id);
if (StartOf(3)) {
- if (la.kind == 26) {
+ if (la.kind == 29) {
GenericParameters(typeArgs);
}
- if (la.kind == 23) {
+ if (la.kind == 26) {
Formals(true, isFunctionMethod, formals, out openParen);
if (la.kind == 5) {
Get();
SemErr(t, "predicates do not have an explicitly declared return type; it is always bool");
}
}
- } else if (la.kind == 31) {
+ } else if (la.kind == 34) {
Get();
signatureOmitted = true;
openParen = Token.NoToken;
- } else SynErr(122);
- } else if (la.kind == 47) {
+ } else SynErr(126);
+ } else if (la.kind == 50) {
Get();
isCoPredicate = true;
if (mmod.IsGhost) { SemErr(t, "copredicates cannot be declared 'ghost' (they are ghost by default)"); }
@@ -587,22 +608,22 @@ bool IsAttribute() {
}
NoUSIdent(out id);
if (StartOf(3)) {
- if (la.kind == 26) {
+ if (la.kind == 29) {
GenericParameters(typeArgs);
}
- if (la.kind == 23) {
+ if (la.kind == 26) {
Formals(true, isFunctionMethod, formals, out openParen);
if (la.kind == 5) {
Get();
SemErr(t, "copredicates do not have an explicitly declared return type; it is always bool");
}
}
- } else if (la.kind == 31) {
+ } else if (la.kind == 34) {
Get();
signatureOmitted = true;
openParen = Token.NoToken;
- } else SynErr(123);
- } else SynErr(124);
+ } else SynErr(127);
+ } else SynErr(128);
decreases = isCoPredicate ? null : new List<Expression/*!*/>();
while (StartOf(4)) {
FunctionSpec(reqs, reads, ens, decreases);
@@ -612,7 +633,7 @@ bool IsAttribute() {
}
if (isPredicate) {
f = new Predicate(id, id.val, mmod.IsStatic, !isFunctionMethod, typeArgs, openParen, formals,
- reqs, reads, ens, new Specification<Expression>(decreases, null), body, false, attrs, signatureOmitted);
+ reqs, reads, ens, new Specification<Expression>(decreases, null), body, Predicate.BodyOriginKind.OriginalOrInherited, attrs, signatureOmitted);
} else if (isCoPredicate) {
f = new CoPredicate(id, id.val, mmod.IsStatic, typeArgs, openParen, formals,
reqs, reads, ens, body, attrs, signatureOmitted);
@@ -645,10 +666,10 @@ bool IsAttribute() {
IToken bodyStart = Token.NoToken;
IToken bodyEnd = Token.NoToken;
- while (!(la.kind == 0 || la.kind == 28 || la.kind == 29)) {SynErr(125); Get();}
- if (la.kind == 28) {
+ while (!(la.kind == 0 || la.kind == 31 || la.kind == 32)) {SynErr(129); Get();}
+ if (la.kind == 31) {
Get();
- } else if (la.kind == 29) {
+ } else if (la.kind == 32) {
Get();
if (allowConstructor) {
isConstructor = true;
@@ -656,7 +677,7 @@ bool IsAttribute() {
SemErr(t, "constructors are only allowed in classes");
}
- } else SynErr(126);
+ } else SynErr(130);
if (isConstructor) {
if (mmod.IsGhost) {
SemErr(t, "constructors cannot be declared 'ghost'");
@@ -670,20 +691,20 @@ bool IsAttribute() {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 23 || la.kind == 26) {
- if (la.kind == 26) {
+ if (la.kind == 26 || la.kind == 29) {
+ if (la.kind == 29) {
GenericParameters(typeArgs);
}
Formals(true, !mmod.IsGhost, ins, out openParen);
- if (la.kind == 30) {
+ if (la.kind == 33) {
Get();
if (isConstructor) { SemErr(t, "constructors cannot have out-parameters"); }
Formals(false, !mmod.IsGhost, outs, out openParen);
}
- } else if (la.kind == 31) {
+ } else if (la.kind == 34) {
Get();
signatureOmitted = true; openParen = Token.NoToken;
- } else SynErr(127);
+ } else SynErr(131);
while (StartOf(5)) {
MethodSpec(req, mod, ens, dec, ref decAttrs, ref modAttrs);
}
@@ -712,7 +733,7 @@ bool IsAttribute() {
Attribute(ref attrs);
}
NoUSIdent(out id);
- if (la.kind == 23) {
+ if (la.kind == 26) {
FormalsOptionalIds(formals);
}
ctors.Add(new DatatypeCtor(id, id.val, formals, attrs));
@@ -720,22 +741,22 @@ bool IsAttribute() {
void FormalsOptionalIds(List<Formal/*!*/>/*!*/ formals) {
Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id; Type/*!*/ ty; string/*!*/ name; bool isGhost;
- Expect(23);
+ Expect(26);
if (StartOf(6)) {
TypeIdentOptional(out id, out name, out ty, out isGhost);
formals.Add(new Formal(id, name, ty, true, isGhost));
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
TypeIdentOptional(out id, out name, out ty, out isGhost);
formals.Add(new Formal(id, name, ty, true, isGhost));
}
}
- Expect(25);
+ Expect(28);
}
- void IdentType(out IToken/*!*/ id, out Type/*!*/ ty) {
+ void IdentType(out IToken/*!*/ id, out Type/*!*/ ty, bool allowWildcardId) {
Contract.Ensures(Contract.ValueAtReturn(out id) != null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null);
- NoUSIdent(out id);
+ WildIdent(out id, allowWildcardId);
Expect(5);
Type(out ty);
}
@@ -748,7 +769,21 @@ bool IsAttribute() {
Get();
if (allowGhostKeyword) { isGhost = true; } else { SemErr(t, "formal cannot be declared 'ghost' in this context"); }
}
- IdentType(out id, out ty);
+ IdentType(out id, out ty, true);
+ }
+
+ void WildIdent(out IToken/*!*/ x, bool allowWildcardId) {
+ Contract.Ensures(Contract.ValueAtReturn(out x) != null);
+ Expect(1);
+ x = t;
+ if (x.val.StartsWith("_")) {
+ if (allowWildcardId && x.val.Length == 1) {
+ t.val = "_v" + anonymousIds++;
+ } else {
+ SemErr("cannot declare identifier beginning with underscore");
+ }
+ }
+
}
void Type(out Type/*!*/ ty) {
@@ -759,7 +794,7 @@ bool IsAttribute() {
void LocalIdentTypeOptional(out VarDecl/*!*/ var, bool isGhost) {
IToken/*!*/ id; Type/*!*/ ty; Type optType = null;
- NoUSIdent(out id);
+ WildIdent(out id, true);
if (la.kind == 5) {
Get();
Type(out ty);
@@ -771,7 +806,7 @@ bool IsAttribute() {
void IdentTypeOptional(out BoundVar/*!*/ var) {
Contract.Ensures(Contract.ValueAtReturn(out var)!=null); IToken/*!*/ id; Type/*!*/ ty; Type optType = null;
- NoUSIdent(out id);
+ WildIdent(out id, true);
if (la.kind == 5) {
Get();
Type(out ty);
@@ -814,22 +849,22 @@ bool IsAttribute() {
List<Type/*!*/>/*!*/ gt;
switch (la.kind) {
- case 37: {
+ case 40: {
Get();
tok = t;
break;
}
- case 38: {
+ case 41: {
Get();
tok = t; ty = new NatType();
break;
}
- case 39: {
+ case 42: {
Get();
tok = t; ty = new IntType();
break;
}
- case 40: {
+ case 43: {
Get();
tok = t; gt = new List<Type/*!*/>();
GenericInstantiation(gt);
@@ -840,7 +875,7 @@ bool IsAttribute() {
break;
}
- case 41: {
+ case 44: {
Get();
tok = t; gt = new List<Type/*!*/>();
GenericInstantiation(gt);
@@ -851,7 +886,7 @@ bool IsAttribute() {
break;
}
- case 42: {
+ case 45: {
Get();
tok = t; gt = new List<Type/*!*/>();
GenericInstantiation(gt);
@@ -862,7 +897,7 @@ bool IsAttribute() {
break;
}
- case 43: {
+ case 46: {
Get();
tok = t; gt = new List<Type/*!*/>();
GenericInstantiation(gt);
@@ -873,28 +908,28 @@ bool IsAttribute() {
break;
}
- case 1: case 3: case 44: {
+ case 1: case 3: case 47: {
ReferenceType(out tok, out ty);
break;
}
- default: SynErr(128); break;
+ default: SynErr(132); break;
}
}
void Formals(bool incoming, bool allowGhostKeyword, List<Formal/*!*/>/*!*/ formals, out IToken openParen) {
Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id; Type/*!*/ ty; bool isGhost;
- Expect(23);
+ Expect(26);
openParen = t;
if (la.kind == 1 || la.kind == 8) {
GIdentType(allowGhostKeyword, out id, out ty, out isGhost);
formals.Add(new Formal(id, id.val, ty, incoming, isGhost));
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
GIdentType(allowGhostKeyword, out id, out ty, out isGhost);
formals.Add(new Formal(id, id.val, ty, incoming, isGhost));
}
}
- Expect(25);
+ Expect(28);
}
void MethodSpec(List<MaybeFreeExpression/*!*/>/*!*/ req, List<FrameExpression/*!*/>/*!*/ mod, List<MaybeFreeExpression/*!*/>/*!*/ ens,
@@ -902,8 +937,8 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Requires(cce.NonNullElements(req)); Contract.Requires(cce.NonNullElements(mod)); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(cce.NonNullElements(decreases));
Expression/*!*/ e; FrameExpression/*!*/ fe; bool isFree = false; Attributes ensAttrs = null;
- while (!(StartOf(7))) {SynErr(129); Get();}
- if (la.kind == 32) {
+ while (!(StartOf(7))) {SynErr(133); Get();}
+ if (la.kind == 35) {
Get();
while (IsAttribute()) {
Attribute(ref modAttrs);
@@ -911,44 +946,44 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (StartOf(8)) {
FrameExpression(out fe);
mod.Add(fe);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
FrameExpression(out fe);
mod.Add(fe);
}
}
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(130); Get();}
- Expect(12);
- } else if (la.kind == 33 || la.kind == 34 || la.kind == 35) {
- if (la.kind == 33) {
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(134); Get();}
+ Expect(14);
+ } else if (la.kind == 36 || la.kind == 37 || la.kind == 38) {
+ if (la.kind == 36) {
Get();
isFree = true;
}
- if (la.kind == 34) {
+ if (la.kind == 37) {
Get();
Expression(out e);
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(131); Get();}
- Expect(12);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(135); Get();}
+ Expect(14);
req.Add(new MaybeFreeExpression(e, isFree));
- } else if (la.kind == 35) {
+ } else if (la.kind == 38) {
Get();
while (IsAttribute()) {
Attribute(ref ensAttrs);
}
Expression(out e);
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(132); Get();}
- Expect(12);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(136); Get();}
+ Expect(14);
ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs));
- } else SynErr(133);
- } else if (la.kind == 36) {
+ } else SynErr(137);
+ } else if (la.kind == 39) {
Get();
while (IsAttribute()) {
Attribute(ref decAttrs);
}
- DecreasesList(decreases, false);
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(134); Get();}
- Expect(12);
- } else SynErr(135);
+ DecreasesList(decreases, true);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(138); Get();}
+ Expect(14);
+ } else SynErr(139);
}
void BlockStmt(out BlockStmt/*!*/ block, out IToken bodyStart, out IToken bodyEnd) {
@@ -966,21 +1001,27 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
void FrameExpression(out FrameExpression/*!*/ fe) {
- Contract.Ensures(Contract.ValueAtReturn(out fe) != null); Expression/*!*/ e; IToken/*!*/ id; string fieldName = null; fe = null;
+ Contract.Ensures(Contract.ValueAtReturn(out fe) != null);
+ Expression/*!*/ e;
+ IToken/*!*/ id;
+ string fieldName = null; IToken feTok = null;
+ fe = null;
+
if (StartOf(10)) {
Expression(out e);
- if (la.kind == 50) {
+ feTok = e.tok;
+ if (la.kind == 53) {
Get();
Ident(out id);
- fieldName = id.val;
+ fieldName = id.val; feTok = id;
}
- fe = new FrameExpression(e, fieldName);
- } else if (la.kind == 50) {
+ fe = new FrameExpression(feTok, e, fieldName);
+ } else if (la.kind == 53) {
Get();
Ident(out id);
fieldName = id.val;
- fe = new FrameExpression(new ImplicitThisExpr(id), fieldName);
- } else SynErr(136);
+ fe = new FrameExpression(id, new ImplicitThisExpr(id), fieldName);
+ } else SynErr(140);
}
void Expression(out Expression/*!*/ e) {
@@ -991,16 +1032,16 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression/*!*/ e;
PossiblyWildExpression(out e);
if (!allowWildcard && e is WildcardExpr) {
- SemErr(e.tok, "'decreases *' is only allowed on loops");
+ SemErr(e.tok, "'decreases *' is only allowed on loops and tail-recursive methods");
} else {
decreases.Add(e);
}
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
PossiblyWildExpression(out e);
if (!allowWildcard && e is WildcardExpr) {
- SemErr(e.tok, "'decreases *' is only allowed on loops");
+ SemErr(e.tok, "'decreases *' is only allowed on loops and tail-recursive methods");
} else {
decreases.Add(e);
}
@@ -1010,15 +1051,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void GenericInstantiation(List<Type/*!*/>/*!*/ gt) {
Contract.Requires(cce.NonNullElements(gt)); Type/*!*/ ty;
- Expect(26);
+ Expect(29);
Type(out ty);
gt.Add(ty);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
Type(out ty);
gt.Add(ty);
}
- Expect(27);
+ Expect(30);
}
void ReferenceType(out IToken/*!*/ tok, out Type/*!*/ ty) {
@@ -1027,7 +1068,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<Type/*!*/>/*!*/ gt;
List<IToken> path;
- if (la.kind == 44) {
+ if (la.kind == 47) {
Get();
tok = t; ty = new ObjectType();
} else if (la.kind == 3) {
@@ -1047,16 +1088,16 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Ident(out tok);
gt = new List<Type/*!*/>();
path = new List<IToken>();
- while (la.kind == 14) {
+ while (la.kind == 17) {
path.Add(tok);
Get();
Ident(out tok);
}
- if (la.kind == 26) {
+ if (la.kind == 29) {
GenericInstantiation(gt);
}
ty = new UserDefinedType(tok, tok.val, gt, path);
- } else SynErr(137);
+ } else SynErr(141);
}
void FunctionSpec(List<Expression/*!*/>/*!*/ reqs, List<FrameExpression/*!*/>/*!*/ reads, List<Expression/*!*/>/*!*/ ens, List<Expression/*!*/> decreases) {
@@ -1064,33 +1105,33 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Requires(cce.NonNullElements(reads));
Contract.Requires(decreases == null || cce.NonNullElements(decreases));
Expression/*!*/ e; FrameExpression/*!*/ fe;
- if (la.kind == 34) {
- while (!(la.kind == 0 || la.kind == 34)) {SynErr(138); Get();}
+ if (la.kind == 37) {
+ while (!(la.kind == 0 || la.kind == 37)) {SynErr(142); Get();}
Get();
Expression(out e);
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(139); Get();}
- Expect(12);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(143); Get();}
+ Expect(14);
reqs.Add(e);
- } else if (la.kind == 48) {
+ } else if (la.kind == 51) {
Get();
if (StartOf(11)) {
PossiblyWildFrameExpression(out fe);
reads.Add(fe);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
PossiblyWildFrameExpression(out fe);
reads.Add(fe);
}
}
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(140); Get();}
- Expect(12);
- } else if (la.kind == 35) {
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(144); Get();}
+ Expect(14);
+ } else if (la.kind == 38) {
Get();
Expression(out e);
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(141); Get();}
- Expect(12);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(145); Get();}
+ Expect(14);
ens.Add(e);
- } else if (la.kind == 36) {
+ } else if (la.kind == 39) {
Get();
if (decreases == null) {
SemErr(t, "'decreases' clauses are meaningless for copredicates, so they are not allowed");
@@ -1098,9 +1139,9 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
DecreasesList(decreases, false);
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(142); Get();}
- Expect(12);
- } else SynErr(143);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(146); Get();}
+ Expect(14);
+ } else SynErr(147);
}
void FunctionBody(out Expression/*!*/ e, out IToken bodyStart, out IToken bodyEnd) {
@@ -1114,23 +1155,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void PossiblyWildFrameExpression(out FrameExpression/*!*/ fe) {
Contract.Ensures(Contract.ValueAtReturn(out fe) != null); fe = dummyFrameExpr;
- if (la.kind == 49) {
+ if (la.kind == 52) {
Get();
- fe = new FrameExpression(new WildcardExpr(t), null);
+ fe = new FrameExpression(t, new WildcardExpr(t), null);
} else if (StartOf(8)) {
FrameExpression(out fe);
- } else SynErr(144);
+ } else SynErr(148);
}
void PossiblyWildExpression(out Expression/*!*/ e) {
Contract.Ensures(Contract.ValueAtReturn(out e)!=null);
e = dummyExpr;
- if (la.kind == 49) {
+ if (la.kind == 52) {
Get();
e = new WildcardExpr(t);
} else if (StartOf(10)) {
Expression(out e);
- } else SynErr(145);
+ } else SynErr(149);
}
void Stmt(List<Statement/*!*/>/*!*/ ss) {
@@ -1147,50 +1188,54 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken bodyStart, bodyEnd;
int breakCount;
- while (!(StartOf(12))) {SynErr(146); Get();}
+ while (!(StartOf(12))) {SynErr(150); Get();}
switch (la.kind) {
case 6: {
BlockStmt(out bs, out bodyStart, out bodyEnd);
s = bs;
break;
}
- case 69: {
+ case 72: {
AssertStmt(out s);
break;
}
- case 57: {
+ case 60: {
AssumeStmt(out s);
break;
}
- case 70: {
+ case 73: {
PrintStmt(out s);
break;
}
- case 1: case 2: case 19: case 23: case 94: case 95: case 96: case 97: case 98: case 99: case 100: {
+ case 1: case 2: case 22: case 26: case 98: case 99: case 100: case 101: case 102: case 103: {
UpdateStmt(out s);
break;
}
- case 8: case 20: {
+ case 8: case 23: {
VarDeclStatement(out s);
break;
}
- case 62: {
+ case 65: {
IfStmt(out s);
break;
}
- case 66: {
+ case 69: {
WhileStmt(out s);
break;
}
- case 68: {
+ case 71: {
MatchStmt(out s);
break;
}
- case 71: {
+ case 74: {
ParallelStmt(out s);
break;
}
- case 51: {
+ case 75: {
+ CalcStmt(out s);
+ break;
+ }
+ case 54: {
Get();
x = t;
NoUSIdent(out id);
@@ -1199,33 +1244,33 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
s.Labels = new LList<Label>(new Label(x, id.val), s.Labels);
break;
}
- case 52: {
+ case 55: {
Get();
x = t; breakCount = 1; label = null;
if (la.kind == 1) {
NoUSIdent(out id);
label = id.val;
- } else if (la.kind == 12 || la.kind == 52) {
- while (la.kind == 52) {
+ } else if (la.kind == 14 || la.kind == 55) {
+ while (la.kind == 55) {
Get();
breakCount++;
}
- } else SynErr(147);
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(148); Get();}
- Expect(12);
+ } else SynErr(151);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(152); Get();}
+ Expect(14);
s = label != null ? new BreakStmt(x, label) : new BreakStmt(x, breakCount);
break;
}
- case 55: {
+ case 58: {
ReturnStmt(out s);
break;
}
- case 31: {
+ case 34: {
SkeletonStmt(out s);
- Expect(12);
+ Expect(14);
break;
}
- default: SynErr(149); break;
+ default: SynErr(153); break;
}
}
@@ -1233,17 +1278,17 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x;
Expression e = null; Attributes attrs = null;
- Expect(69);
+ Expect(72);
x = t;
while (IsAttribute()) {
Attribute(ref attrs);
}
if (StartOf(10)) {
Expression(out e);
- } else if (la.kind == 31) {
+ } else if (la.kind == 34) {
Get();
- } else SynErr(150);
- Expect(12);
+ } else SynErr(154);
+ Expect(14);
if (e == null) {
s = new SkeletonStatement(new AssertStmt(x, new LiteralExpr(x, true), attrs), true, false);
} else {
@@ -1256,39 +1301,39 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x;
Expression e = null; Attributes attrs = null;
- Expect(57);
+ Expect(60);
x = t;
while (IsAttribute()) {
Attribute(ref attrs);
}
if (StartOf(10)) {
Expression(out e);
- } else if (la.kind == 31) {
+ } else if (la.kind == 34) {
Get();
- } else SynErr(151);
+ } else SynErr(155);
if (e == null) {
s = new SkeletonStatement(new AssumeStmt(x, new LiteralExpr(x, true), attrs), true, false);
} else {
s = new AssumeStmt(x, e, attrs);
}
- Expect(12);
+ Expect(14);
}
void PrintStmt(out Statement/*!*/ s) {
Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; Attributes.Argument/*!*/ arg;
List<Attributes.Argument/*!*/> args = new List<Attributes.Argument/*!*/>();
- Expect(70);
+ Expect(73);
x = t;
AttributeArg(out arg);
args.Add(arg);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
AttributeArg(out arg);
args.Add(arg);
}
- Expect(12);
+ Expect(14);
s = new PrintStmt(x, args);
}
@@ -1304,43 +1349,43 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Lhs(out e);
x = e.tok;
- if (la.kind == 6 || la.kind == 12) {
+ if (la.kind == 6 || la.kind == 14) {
while (la.kind == 6) {
Attribute(ref attrs);
}
- Expect(12);
+ Expect(14);
rhss.Add(new ExprRhs(e, attrs));
- } else if (la.kind == 21 || la.kind == 54 || la.kind == 56) {
+ } else if (la.kind == 24 || la.kind == 57 || la.kind == 59) {
lhss.Add(e); lhs0 = e;
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
Lhs(out e);
lhss.Add(e);
}
- if (la.kind == 54) {
+ if (la.kind == 57) {
Get();
x = t;
Rhs(out r, lhs0);
rhss.Add(r);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
Rhs(out r, lhs0);
rhss.Add(r);
}
- } else if (la.kind == 56) {
+ } else if (la.kind == 59) {
Get();
x = t;
- if (la.kind == 57) {
+ if (la.kind == 60) {
Get();
suchThatAssume = t;
}
Expression(out suchThat);
- } else SynErr(152);
- Expect(12);
+ } else SynErr(156);
+ Expect(14);
} else if (la.kind == 5) {
Get();
SemErr(t, "invalid statement (did you forget the 'label' keyword?)");
- } else SynErr(153);
+ } else SynErr(157);
if (suchThat != null) {
s = new AssignSuchThatStmt(x, lhss, suchThat, suchThatAssume);
} else {
@@ -1366,17 +1411,17 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Get();
isGhost = true; x = t;
}
- Expect(20);
+ Expect(23);
if (!isGhost) { x = t; }
LocalIdentTypeOptional(out d, isGhost);
lhss.Add(d);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
LocalIdentTypeOptional(out d, isGhost);
lhss.Add(d);
}
- if (la.kind == 54 || la.kind == 56) {
- if (la.kind == 54) {
+ if (la.kind == 57 || la.kind == 59) {
+ if (la.kind == 57) {
Get();
assignTok = t;
lhs0 = new IdentifierExpr(lhss[0].Tok, lhss[0].Name);
@@ -1384,7 +1429,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Rhs(out r, lhs0);
rhss.Add(r);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
Rhs(out r, lhs0);
rhss.Add(r);
@@ -1392,14 +1437,14 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else {
Get();
assignTok = t;
- if (la.kind == 57) {
+ if (la.kind == 60) {
Get();
suchThatAssume = t;
}
Expression(out suchThat);
}
}
- Expect(12);
+ Expect(14);
ConcreteUpdateStatement update;
if (suchThat != null) {
var ies = new List<Expression>();
@@ -1431,25 +1476,25 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<GuardedAlternative> alternatives;
ifStmt = dummyStmt; // to please the compiler
- Expect(62);
+ Expect(65);
x = t;
- if (la.kind == 23 || la.kind == 31) {
- if (la.kind == 23) {
+ if (la.kind == 26 || la.kind == 34) {
+ if (la.kind == 26) {
Guard(out guard);
} else {
Get();
guardOmitted = true;
}
BlockStmt(out thn, out bodyStart, out bodyEnd);
- if (la.kind == 63) {
+ if (la.kind == 66) {
Get();
- if (la.kind == 62) {
+ if (la.kind == 65) {
IfStmt(out s);
els = s;
} else if (la.kind == 6) {
BlockStmt(out bs, out bodyStart, out bodyEnd);
els = bs;
- } else SynErr(154);
+ } else SynErr(158);
}
if (guardOmitted) {
ifStmt = new SkeletonStatement(new IfStmt(x, guard, thn, els), true, false);
@@ -1460,7 +1505,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (la.kind == 6) {
AlternativeBlock(out alternatives);
ifStmt = new AlternativeStmt(x, alternatives);
- } else SynErr(155);
+ } else SynErr(159);
}
void WhileStmt(out Statement/*!*/ stmt) {
@@ -1476,10 +1521,10 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<GuardedAlternative> alternatives;
stmt = dummyStmt; // to please the compiler
- Expect(66);
+ Expect(69);
x = t;
- if (la.kind == 23 || la.kind == 31) {
- if (la.kind == 23) {
+ if (la.kind == 26 || la.kind == 34) {
+ if (la.kind == 26) {
Guard(out guard);
Contract.Assume(guard == null || cce.Owner.None(guard));
} else {
@@ -1489,10 +1534,10 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
LoopSpec(out invariants, out decreases, out mod, ref decAttrs, ref modAttrs);
if (la.kind == 6) {
BlockStmt(out body, out bodyStart, out bodyEnd);
- } else if (la.kind == 31) {
+ } else if (la.kind == 34) {
Get();
bodyOmitted = true;
- } else SynErr(156);
+ } else SynErr(160);
if (guardOmitted || bodyOmitted) {
if (mod != null) {
SemErr(mod[0].E.tok, "'modifies' clauses are not allowed on refining loops");
@@ -1503,6 +1548,8 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
stmt = new WhileStmt(x, guard, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(null, null), body);
stmt = new SkeletonStatement(stmt, guardOmitted, bodyOmitted);
} else {
+ // The following statement protects against crashes in case of parsing errors
+ body = body ?? new BlockStmt(x, new List<Statement>());
stmt = new WhileStmt(x, guard, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), body);
}
@@ -1510,18 +1557,18 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
LoopSpec(out invariants, out decreases, out mod, ref decAttrs, ref modAttrs);
AlternativeBlock(out alternatives);
stmt = new AlternativeLoopStmt(x, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), alternatives);
- } else SynErr(157);
+ } else SynErr(161);
}
void MatchStmt(out Statement/*!*/ s) {
Contract.Ensures(Contract.ValueAtReturn(out s) != null);
Token x; Expression/*!*/ e; MatchCaseStmt/*!*/ c;
List<MatchCaseStmt/*!*/> cases = new List<MatchCaseStmt/*!*/>();
- Expect(68);
+ Expect(71);
x = t;
Expression(out e);
Expect(6);
- while (la.kind == 64) {
+ while (la.kind == 67) {
CaseStatement(out c);
cases.Add(c);
}
@@ -1541,9 +1588,9 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
BlockStmt/*!*/ block;
IToken bodyStart, bodyEnd;
- Expect(71);
+ Expect(74);
x = t;
- Expect(23);
+ Expect(26);
if (la.kind == 1) {
List<BoundVar/*!*/> bvarsX; Attributes attrsX; Expression rangeX;
QuantifierDomain(out bvarsX, out attrsX, out rangeX);
@@ -1553,39 +1600,94 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (bvars == null) { bvars = new List<BoundVar>(); }
if (range == null) { range = new LiteralExpr(x, true); }
- Expect(25);
- while (la.kind == 33 || la.kind == 35) {
+ Expect(28);
+ while (la.kind == 36 || la.kind == 38) {
isFree = false;
- if (la.kind == 33) {
+ if (la.kind == 36) {
Get();
isFree = true;
}
- Expect(35);
+ Expect(38);
Expression(out e);
- Expect(12);
+ Expect(14);
ens.Add(new MaybeFreeExpression(e, isFree));
}
BlockStmt(out block, out bodyStart, out bodyEnd);
s = new ParallelStmt(x, bvars, attrs, range, ens, block);
}
+ void CalcStmt(out Statement/*!*/ s) {
+ Contract.Ensures(Contract.ValueAtReturn(out s) != null);
+ Token x;
+ BinaryExpr.Opcode op, calcOp = BinaryExpr.Opcode.Eq, resOp = BinaryExpr.Opcode.Eq;
+ List<Expression/*!*/> lines = new List<Expression/*!*/>();
+ List<Statement> hints = new List<Statement>();
+ List<BinaryExpr.Opcode?> customOps = new List<BinaryExpr.Opcode?>();
+ BinaryExpr.Opcode? maybeOp;
+ Expression/*!*/ e;
+ BlockStmt/*!*/ block;
+ Statement/*!*/ h;
+ IToken bodyStart, bodyEnd, opTok;
+
+ Expect(75);
+ x = t;
+ if (StartOf(14)) {
+ CalcOp(out opTok, out calcOp);
+ }
+ resOp = calcOp;
+ Expect(6);
+ Expression(out e);
+ lines.Add(e);
+ Expect(14);
+ while (StartOf(15)) {
+ if (la.kind == 6) {
+ BlockStmt(out block, out bodyStart, out bodyEnd);
+ hints.Add(block);
+ } else if (la.kind == 75) {
+ CalcStmt(out h);
+ hints.Add(h);
+ } else {
+ hints.Add(null);
+ }
+ if (StartOf(14)) {
+ CalcOp(out opTok, out op);
+ maybeOp = Microsoft.Dafny.CalcStmt.ResultOp(resOp, op);
+ if (maybeOp == null) {
+ customOps.Add(null); // pretend the operator was not there to satisfy the precondition of the CalcStmt contructor
+ SemErr(opTok, "this operator cannot continue this calculation");
+ } else {
+ customOps.Add(op);
+ resOp = (BinaryExpr.Opcode)maybeOp;
+ }
+
+ } else if (StartOf(10)) {
+ customOps.Add(null);
+ } else SynErr(162);
+ Expression(out e);
+ lines.Add(e);
+ Expect(14);
+ }
+ Expect(7);
+ s = new CalcStmt(x, calcOp, lines, hints, customOps);
+ }
+
void ReturnStmt(out Statement/*!*/ s) {
IToken returnTok = null;
List<AssignmentRhs> rhss = null;
AssignmentRhs r;
- Expect(55);
+ Expect(58);
returnTok = t;
- if (StartOf(14)) {
+ if (StartOf(16)) {
Rhs(out r, null);
rhss = new List<AssignmentRhs>(); rhss.Add(r);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
Rhs(out r, null);
rhss.Add(r);
}
}
- Expect(12);
+ Expect(14);
s = new ReturnStmt(returnTok, rhss);
}
@@ -1594,22 +1696,22 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<Expression> exprs = null;
IToken tok, dotdotdot, whereTok;
Expression e;
- Expect(31);
+ Expect(34);
dotdotdot = t;
- if (la.kind == 53) {
+ if (la.kind == 56) {
Get();
names = new List<IToken>(); exprs = new List<Expression>(); whereTok = t;
Ident(out tok);
names.Add(tok);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
Ident(out tok);
names.Add(tok);
}
- Expect(54);
+ Expect(57);
Expression(out e);
exprs.Add(e);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
Expression(out e);
exprs.Add(e);
@@ -1624,35 +1726,36 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
void Rhs(out AssignmentRhs r, Expression receiverForInitCall) {
+ Contract.Ensures(Contract.ValueAtReturn<AssignmentRhs>(out r) != null);
IToken/*!*/ x, newToken; Expression/*!*/ e;
List<Expression> ee = null;
Type ty = null;
CallStmt initCall = null;
List<Expression> args;
- r = null; // to please compiler
+ r = dummyRhs; // to please compiler
Attributes attrs = null;
- if (la.kind == 58) {
+ if (la.kind == 61) {
Get();
newToken = t;
TypeAndToken(out x, out ty);
- if (la.kind == 14 || la.kind == 23 || la.kind == 59) {
- if (la.kind == 59) {
+ if (la.kind == 17 || la.kind == 26 || la.kind == 62) {
+ if (la.kind == 62) {
Get();
ee = new List<Expression>();
Expressions(ee);
- Expect(60);
+ Expect(63);
UserDefinedType tmp = theBuiltIns.ArrayType(x, ee.Count, new IntType(), true);
- } else if (la.kind == 14) {
+ } else if (la.kind == 17) {
Get();
Ident(out x);
- Expect(23);
+ Expect(26);
args = new List<Expression/*!*/>();
if (StartOf(10)) {
Expressions(args);
}
- Expect(25);
+ Expect(28);
initCall = new CallStmt(x, new List<Expression>(), receiverForInitCall, x.val, args);
} else {
Get();
@@ -1670,7 +1773,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (StartOf(10)) {
Expressions(args);
}
- Expect(25);
+ Expect(28);
if (x != null) {
initCall = new CallStmt(x, new List<Expression>(), receiverForInitCall, x.val, args);
}
@@ -1683,46 +1786,46 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
r = new TypeRhs(newToken, ty, initCall);
}
- } else if (la.kind == 61) {
+ } else if (la.kind == 64) {
Get();
x = t;
Expression(out e);
r = new ExprRhs(new UnaryExpr(x, UnaryExpr.Opcode.SetChoose, e));
- } else if (la.kind == 49) {
+ } else if (la.kind == 52) {
Get();
r = new HavocRhs(t);
} else if (StartOf(10)) {
Expression(out e);
r = new ExprRhs(e);
- } else SynErr(158);
+ } else SynErr(163);
while (la.kind == 6) {
Attribute(ref attrs);
}
- if (r != null) r.Attributes = attrs;
+ r.Attributes = attrs;
}
void Lhs(out Expression e) {
- e = null; // to please the compiler
+ e = dummyExpr; // the assignment is to please the compiler, the dummy value to satisfy contracts in the event of a parse error
if (la.kind == 1) {
DottedIdentifiersAndFunction(out e);
- while (la.kind == 14 || la.kind == 59) {
+ while (la.kind == 17 || la.kind == 62) {
Suffix(ref e);
}
- } else if (StartOf(15)) {
+ } else if (StartOf(17)) {
ConstAtomExpression(out e);
Suffix(ref e);
- while (la.kind == 14 || la.kind == 59) {
+ while (la.kind == 17 || la.kind == 62) {
Suffix(ref e);
}
- } else SynErr(159);
+ } else SynErr(164);
}
void Expressions(List<Expression/*!*/>/*!*/ args) {
Contract.Requires(cce.NonNullElements(args)); Expression/*!*/ e;
Expression(out e);
args.Add(e);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
Expression(out e);
args.Add(e);
@@ -1731,15 +1834,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void Guard(out Expression e) {
Expression/*!*/ ee; e = null;
- Expect(23);
- if (la.kind == 49) {
+ Expect(26);
+ if (la.kind == 52) {
Get();
e = null;
} else if (StartOf(10)) {
Expression(out ee);
e = ee;
- } else SynErr(160);
- Expect(25);
+ } else SynErr(165);
+ Expect(28);
}
void AlternativeBlock(out List<GuardedAlternative> alternatives) {
@@ -1749,11 +1852,11 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<Statement> body;
Expect(6);
- while (la.kind == 64) {
+ while (la.kind == 67) {
Get();
x = t;
Expression(out e);
- Expect(65);
+ Expect(68);
body = new List<Statement>();
while (StartOf(9)) {
Stmt(body);
@@ -1770,23 +1873,23 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
decreases = new List<Expression/*!*/>();
mod = null;
- while (StartOf(16)) {
- if (la.kind == 33 || la.kind == 67) {
+ while (StartOf(18)) {
+ if (la.kind == 36 || la.kind == 70) {
Invariant(out invariant);
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(161); Get();}
- Expect(12);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(166); Get();}
+ Expect(14);
invariants.Add(invariant);
- } else if (la.kind == 36) {
- while (!(la.kind == 0 || la.kind == 36)) {SynErr(162); Get();}
+ } else if (la.kind == 39) {
+ while (!(la.kind == 0 || la.kind == 39)) {SynErr(167); Get();}
Get();
while (IsAttribute()) {
Attribute(ref decAttrs);
}
DecreasesList(decreases, true);
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(163); Get();}
- Expect(12);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(168); Get();}
+ Expect(14);
} else {
- while (!(la.kind == 0 || la.kind == 32)) {SynErr(164); Get();}
+ while (!(la.kind == 0 || la.kind == 35)) {SynErr(169); Get();}
Get();
while (IsAttribute()) {
Attribute(ref modAttrs);
@@ -1795,26 +1898,26 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (StartOf(8)) {
FrameExpression(out fe);
mod.Add(fe);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
FrameExpression(out fe);
mod.Add(fe);
}
}
- while (!(la.kind == 0 || la.kind == 12)) {SynErr(165); Get();}
- Expect(12);
+ while (!(la.kind == 0 || la.kind == 14)) {SynErr(170); Get();}
+ Expect(14);
}
}
}
void Invariant(out MaybeFreeExpression/*!*/ invariant) {
bool isFree = false; Expression/*!*/ e; List<string> ids = new List<string>(); invariant = null; Attributes attrs = null;
- while (!(la.kind == 0 || la.kind == 33 || la.kind == 67)) {SynErr(166); Get();}
- if (la.kind == 33) {
+ while (!(la.kind == 0 || la.kind == 36 || la.kind == 70)) {SynErr(171); Get();}
+ if (la.kind == 36) {
Get();
isFree = true;
}
- Expect(67);
+ Expect(70);
while (IsAttribute()) {
Attribute(ref attrs);
}
@@ -1829,21 +1932,21 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
BoundVar/*!*/ bv;
List<Statement/*!*/> body = new List<Statement/*!*/>();
- Expect(64);
+ Expect(67);
x = t;
Ident(out id);
- if (la.kind == 23) {
+ if (la.kind == 26) {
Get();
IdentTypeOptional(out bv);
arguments.Add(bv);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
IdentTypeOptional(out bv);
arguments.Add(bv);
}
- Expect(25);
+ Expect(28);
}
- Expect(65);
+ Expect(68);
while (StartOf(9)) {
Stmt(body);
}
@@ -1858,7 +1961,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
} else if (StartOf(10)) {
Expression(out e);
arg = new Attributes.Argument(t, e);
- } else SynErr(167);
+ } else SynErr(172);
}
void QuantifierDomain(out List<BoundVar/*!*/> bvars, out Attributes attrs, out Expression range) {
@@ -1869,7 +1972,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IdentTypeOptional(out bv);
bvars.Add(bv);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
IdentTypeOptional(out bv);
bvars.Add(bv);
@@ -1877,16 +1980,144 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
while (la.kind == 6) {
Attribute(ref attrs);
}
- if (la.kind == 19) {
+ if (la.kind == 22) {
Get();
Expression(out range);
}
}
+ void CalcOp(out IToken x, out BinaryExpr.Opcode/*!*/ op) {
+ Contract.Ensures(Microsoft.Dafny.CalcStmt.ValidOp(Contract.ValueAtReturn(out op)));
+ op = BinaryExpr.Opcode.Eq; // Returns Eq if parsing fails because it is compatible with any other operator
+ x = null;
+
+ if (StartOf(19)) {
+ RelOp(out x, out op);
+ if (op == BinaryExpr.Opcode.Add) {
+ // Parsing of RelOp failed, do not report an error again and return Eq
+ op = BinaryExpr.Opcode.Eq;
+ } else if (!Microsoft.Dafny.CalcStmt.ValidOp(op)) {
+ // Invalid operator: resport an error and return Eq
+ SemErr(x, "this operator is not allowed in calculations");
+ op = BinaryExpr.Opcode.Eq;
+ }
+
+ } else if (la.kind == 76 || la.kind == 77) {
+ EquivOp();
+ op = BinaryExpr.Opcode.Iff;
+ x = t;
+
+ } else if (la.kind == 78 || la.kind == 79) {
+ ImpliesOp();
+ op = BinaryExpr.Opcode.Imp;
+ x = t;
+
+ } else SynErr(173);
+ }
+
+ void RelOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) {
+ Contract.Ensures(Contract.ValueAtReturn(out x) != null);
+ x = Token.NoToken; op = BinaryExpr.Opcode.Add/*(dummy)*/;
+ IToken y;
+
+ switch (la.kind) {
+ case 27: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.Eq;
+ break;
+ }
+ case 29: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.Lt;
+ break;
+ }
+ case 30: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.Gt;
+ break;
+ }
+ case 84: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.Le;
+ break;
+ }
+ case 85: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.Ge;
+ break;
+ }
+ case 86: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.Neq;
+ break;
+ }
+ case 87: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.Disjoint;
+ break;
+ }
+ case 88: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.In;
+ break;
+ }
+ case 89: {
+ Get();
+ x = t; y = Token.NoToken;
+ if (la.kind == 88) {
+ Get();
+ y = t;
+ }
+ if (y == Token.NoToken) {
+ SemErr(x, "invalid RelOp");
+ } else if (y.pos != x.pos + 1) {
+ SemErr(x, "invalid RelOp (perhaps you intended \"!in\" with no intervening whitespace?)");
+ } else {
+ x.val = "!in";
+ op = BinaryExpr.Opcode.NotIn;
+ }
+
+ break;
+ }
+ case 90: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.Neq;
+ break;
+ }
+ case 91: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.Le;
+ break;
+ }
+ case 92: {
+ Get();
+ x = t; op = BinaryExpr.Opcode.Ge;
+ break;
+ }
+ default: SynErr(174); break;
+ }
+ }
+
+ void EquivOp() {
+ if (la.kind == 76) {
+ Get();
+ } else if (la.kind == 77) {
+ Get();
+ } else SynErr(175);
+ }
+
+ void ImpliesOp() {
+ if (la.kind == 78) {
+ Get();
+ } else if (la.kind == 79) {
+ Get();
+ } else SynErr(176);
+ }
+
void EquivExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
ImpliesExpression(out e0);
- while (la.kind == 72 || la.kind == 73) {
+ while (la.kind == 76 || la.kind == 77) {
EquivOp();
x = t;
ImpliesExpression(out e1);
@@ -1897,7 +2128,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void ImpliesExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
LogicalExpression(out e0);
- if (la.kind == 74 || la.kind == 75) {
+ if (la.kind == 78 || la.kind == 79) {
ImpliesOp();
x = t;
ImpliesExpression(out e1);
@@ -1905,24 +2136,16 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
}
- void EquivOp() {
- if (la.kind == 72) {
- Get();
- } else if (la.kind == 73) {
- Get();
- } else SynErr(168);
- }
-
void LogicalExpression(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1;
RelationalExpression(out e0);
- if (StartOf(17)) {
- if (la.kind == 76 || la.kind == 77) {
+ if (StartOf(20)) {
+ if (la.kind == 80 || la.kind == 81) {
AndOp();
x = t;
RelationalExpression(out e1);
e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1);
- while (la.kind == 76 || la.kind == 77) {
+ while (la.kind == 80 || la.kind == 81) {
AndOp();
x = t;
RelationalExpression(out e1);
@@ -1933,7 +2156,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
x = t;
RelationalExpression(out e1);
e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, e0, e1);
- while (la.kind == 78 || la.kind == 79) {
+ while (la.kind == 82 || la.kind == 83) {
OrOp();
x = t;
RelationalExpression(out e1);
@@ -1943,14 +2166,6 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
}
- void ImpliesOp() {
- if (la.kind == 74) {
- Get();
- } else if (la.kind == 75) {
- Get();
- } else SynErr(169);
- }
-
void RelationalExpression(out Expression/*!*/ e) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null);
IToken x, firstOpTok = null; Expression e0, e1, acc = null; BinaryExpr.Opcode op;
@@ -1965,7 +2180,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Term(out e0);
e = e0;
- if (StartOf(18)) {
+ if (StartOf(19)) {
RelOp(out x, out op);
firstOpTok = x;
Term(out e1);
@@ -1973,7 +2188,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
if (op == BinaryExpr.Opcode.Disjoint)
acc = new BinaryExpr(x, BinaryExpr.Opcode.Add, e0, e1); // accumulate first two operands.
- while (StartOf(18)) {
+ while (StartOf(19)) {
if (chain == null) {
chain = new List<Expression>();
ops = new List<BinaryExpr.Opcode>();
@@ -2042,118 +2257,35 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
void AndOp() {
- if (la.kind == 76) {
+ if (la.kind == 80) {
Get();
- } else if (la.kind == 77) {
+ } else if (la.kind == 81) {
Get();
- } else SynErr(170);
+ } else SynErr(177);
}
void OrOp() {
- if (la.kind == 78) {
+ if (la.kind == 82) {
Get();
- } else if (la.kind == 79) {
+ } else if (la.kind == 83) {
Get();
- } else SynErr(171);
+ } else SynErr(178);
}
void Term(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; BinaryExpr.Opcode op;
Factor(out e0);
- while (la.kind == 89 || la.kind == 90) {
+ while (la.kind == 93 || la.kind == 94) {
AddOp(out x, out op);
Factor(out e1);
e0 = new BinaryExpr(x, op, e0, e1);
}
}
- void RelOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) {
- Contract.Ensures(Contract.ValueAtReturn(out x) != null);
- x = Token.NoToken; op = BinaryExpr.Opcode.Add/*(dummy)*/;
- IToken y;
-
- switch (la.kind) {
- case 24: {
- Get();
- x = t; op = BinaryExpr.Opcode.Eq;
- break;
- }
- case 26: {
- Get();
- x = t; op = BinaryExpr.Opcode.Lt;
- break;
- }
- case 27: {
- Get();
- x = t; op = BinaryExpr.Opcode.Gt;
- break;
- }
- case 80: {
- Get();
- x = t; op = BinaryExpr.Opcode.Le;
- break;
- }
- case 81: {
- Get();
- x = t; op = BinaryExpr.Opcode.Ge;
- break;
- }
- case 82: {
- Get();
- x = t; op = BinaryExpr.Opcode.Neq;
- break;
- }
- case 83: {
- Get();
- x = t; op = BinaryExpr.Opcode.Disjoint;
- break;
- }
- case 84: {
- Get();
- x = t; op = BinaryExpr.Opcode.In;
- break;
- }
- case 85: {
- Get();
- x = t; y = Token.NoToken;
- if (la.kind == 84) {
- Get();
- y = t;
- }
- if (y == Token.NoToken) {
- SemErr(x, "invalid RelOp");
- } else if (y.pos != x.pos + 1) {
- SemErr(x, "invalid RelOp (perhaps you intended \"!in\" with no intervening whitespace?)");
- } else {
- x.val = "!in";
- op = BinaryExpr.Opcode.NotIn;
- }
-
- break;
- }
- case 86: {
- Get();
- x = t; op = BinaryExpr.Opcode.Neq;
- break;
- }
- case 87: {
- Get();
- x = t; op = BinaryExpr.Opcode.Le;
- break;
- }
- case 88: {
- Get();
- x = t; op = BinaryExpr.Opcode.Ge;
- break;
- }
- default: SynErr(172); break;
- }
- }
-
void Factor(out Expression/*!*/ e0) {
Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x; Expression/*!*/ e1; BinaryExpr.Opcode op;
UnaryExpression(out e0);
- while (la.kind == 49 || la.kind == 91 || la.kind == 92) {
+ while (la.kind == 52 || la.kind == 95 || la.kind == 96) {
MulOp(out x, out op);
UnaryExpression(out e1);
e0 = new BinaryExpr(x, op, e0, e1);
@@ -2162,86 +2294,103 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
void AddOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) {
Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op=BinaryExpr.Opcode.Add/*(dummy)*/;
- if (la.kind == 89) {
+ if (la.kind == 93) {
Get();
x = t; op = BinaryExpr.Opcode.Add;
- } else if (la.kind == 90) {
+ } else if (la.kind == 94) {
Get();
x = t; op = BinaryExpr.Opcode.Sub;
- } else SynErr(173);
+ } else SynErr(179);
}
void UnaryExpression(out Expression/*!*/ e) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; e = dummyExpr;
switch (la.kind) {
- case 90: {
+ case 94: {
Get();
x = t;
UnaryExpression(out e);
e = new BinaryExpr(x, BinaryExpr.Opcode.Sub, new LiteralExpr(x, 0), e);
break;
}
- case 85: case 93: {
+ case 89: case 97: {
NegOp();
x = t;
UnaryExpression(out e);
e = new UnaryExpr(x, UnaryExpr.Opcode.Not, e);
break;
}
- case 20: case 40: case 51: case 57: case 62: case 68: case 69: case 103: case 104: case 105: case 106: {
+ case 23: case 43: case 54: case 60: case 65: case 71: case 72: case 106: case 107: case 108: case 109: {
EndlessExpression(out e);
break;
}
case 1: {
DottedIdentifiersAndFunction(out e);
- while (la.kind == 14 || la.kind == 59) {
+ while (la.kind == 17 || la.kind == 62) {
Suffix(ref e);
}
break;
}
- case 6: case 59: {
+ case 6: case 62: {
DisplayExpr(out e);
+ while (la.kind == 17 || la.kind == 62) {
+ Suffix(ref e);
+ }
break;
}
- case 41: {
+ case 44: {
MultiSetExpr(out e);
+ while (la.kind == 17 || la.kind == 62) {
+ Suffix(ref e);
+ }
break;
}
- case 43: {
- MapExpr(out e);
+ case 46: {
+ Get();
+ x = t;
+ if (la.kind == 62) {
+ MapDisplayExpr(x, out e);
+ while (la.kind == 17 || la.kind == 62) {
+ Suffix(ref e);
+ }
+ } else if (la.kind == 1) {
+ MapComprehensionExpr(x, out e);
+ } else if (StartOf(21)) {
+ SemErr("map must be followed by literal in brackets or comprehension.");
+ } else SynErr(180);
break;
}
- case 2: case 19: case 23: case 94: case 95: case 96: case 97: case 98: case 99: case 100: {
+ case 2: case 22: case 26: case 98: case 99: case 100: case 101: case 102: case 103: {
ConstAtomExpression(out e);
- while (la.kind == 14 || la.kind == 59) {
+ while (la.kind == 17 || la.kind == 62) {
Suffix(ref e);
}
break;
}
- default: SynErr(174); break;
+ default: SynErr(181); break;
}
}
void MulOp(out IToken/*!*/ x, out BinaryExpr.Opcode op) {
Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken; op = BinaryExpr.Opcode.Add/*(dummy)*/;
- if (la.kind == 49) {
+ if (la.kind == 52) {
Get();
x = t; op = BinaryExpr.Opcode.Mul;
- } else if (la.kind == 91) {
+ } else if (la.kind == 95) {
Get();
x = t; op = BinaryExpr.Opcode.Div;
- } else if (la.kind == 92) {
+ } else if (la.kind == 96) {
Get();
x = t; op = BinaryExpr.Opcode.Mod;
- } else SynErr(175);
+ } else SynErr(182);
}
void NegOp() {
- if (la.kind == 85) {
+ if (la.kind == 89) {
Get();
- } else if (la.kind == 93) {
+ } else if (la.kind == 97) {
Get();
- } else SynErr(176);
+ } else SynErr(183);
}
void EndlessExpression(out Expression e) {
@@ -2250,56 +2399,56 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = dummyExpr;
switch (la.kind) {
- case 62: {
+ case 65: {
Get();
x = t;
Expression(out e);
- Expect(101);
+ Expect(104);
Expression(out e0);
- Expect(63);
+ Expect(66);
Expression(out e1);
e = new ITEExpr(x, e, e0, e1);
break;
}
- case 68: {
+ case 71: {
MatchExpression(out e);
break;
}
- case 103: case 104: case 105: case 106: {
+ case 106: case 107: case 108: case 109: {
QuantifierGuts(out e);
break;
}
- case 40: {
+ case 43: {
ComprehensionExpr(out e);
break;
}
- case 69: {
+ case 72: {
Get();
x = t;
Expression(out e0);
- Expect(12);
+ Expect(14);
Expression(out e1);
e = new AssertExpr(x, e0, e1);
break;
}
- case 57: {
+ case 60: {
Get();
x = t;
Expression(out e0);
- Expect(12);
+ Expect(14);
Expression(out e1);
e = new AssumeExpr(x, e0, e1);
break;
}
- case 20: {
+ case 23: {
LetExpr(out e);
break;
}
- case 51: {
+ case 54: {
NamedExpr(out e);
break;
}
- default: SynErr(177); break;
+ default: SynErr(184); break;
}
}
@@ -2310,18 +2459,18 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Ident(out id);
idents.Add(id);
- while (la.kind == 14) {
+ while (la.kind == 17) {
Get();
Ident(out id);
idents.Add(id);
}
- if (la.kind == 23) {
+ if (la.kind == 26) {
Get();
openParen = t; args = new List<Expression>();
if (StartOf(10)) {
Expressions(args);
}
- Expect(25);
+ Expect(28);
}
e = new IdentifierSequence(idents, openParen, args);
}
@@ -2332,38 +2481,38 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
List<Expression> multipleIndices = null;
bool func = false;
- if (la.kind == 14) {
+ if (la.kind == 17) {
Get();
Ident(out id);
- if (la.kind == 23) {
+ if (la.kind == 26) {
Get();
IToken openParen = t; args = new List<Expression/*!*/>(); func = true;
if (StartOf(10)) {
Expressions(args);
}
- Expect(25);
+ Expect(28);
e = new FunctionCallExpr(id, id.val, e, openParen, args);
}
if (!func) { e = new ExprDotName(id, e, id.val); }
- } else if (la.kind == 59) {
+ } else if (la.kind == 62) {
Get();
x = t;
if (StartOf(10)) {
Expression(out ee);
e0 = ee;
- if (la.kind == 102) {
+ if (la.kind == 105) {
Get();
anyDots = true;
if (StartOf(10)) {
Expression(out ee);
e1 = ee;
}
- } else if (la.kind == 54) {
+ } else if (la.kind == 57) {
Get();
Expression(out ee);
e1 = ee;
- } else if (la.kind == 21 || la.kind == 60) {
- while (la.kind == 21) {
+ } else if (la.kind == 24 || la.kind == 63) {
+ while (la.kind == 24) {
Get();
Expression(out ee);
if (multipleIndices == null) {
@@ -2373,15 +2522,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
multipleIndices.Add(ee);
}
- } else SynErr(178);
- } else if (la.kind == 102) {
+ } else SynErr(185);
+ } else if (la.kind == 105) {
Get();
anyDots = true;
if (StartOf(10)) {
Expression(out ee);
e1 = ee;
}
- } else SynErr(179);
+ } else SynErr(186);
if (multipleIndices != null) {
e = new MultiSelectExpr(x, e, multipleIndices);
// make sure an array class with this dimensionality exists
@@ -2404,8 +2553,8 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
}
- Expect(60);
- } else SynErr(180);
+ Expect(63);
+ } else SynErr(187);
}
void DisplayExpr(out Expression e) {
@@ -2421,15 +2570,15 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
e = new SetDisplayExpr(x, elements);
Expect(7);
- } else if (la.kind == 59) {
+ } else if (la.kind == 62) {
Get();
x = t; elements = new List<Expression/*!*/>();
if (StartOf(10)) {
Expressions(elements);
}
e = new SeqDisplayExpr(x, elements);
- Expect(60);
- } else SynErr(181);
+ Expect(63);
+ } else SynErr(188);
}
void MultiSetExpr(out Expression e) {
@@ -2437,7 +2586,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
IToken/*!*/ x = null; List<Expression/*!*/>/*!*/ elements;
e = dummyExpr;
- Expect(41);
+ Expect(44);
x = t;
if (la.kind == 6) {
Get();
@@ -2447,49 +2596,47 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
e = new MultiSetDisplayExpr(x, elements);
Expect(7);
- } else if (la.kind == 23) {
+ } else if (la.kind == 26) {
Get();
x = t; elements = new List<Expression/*!*/>();
Expression(out e);
e = new MultiSetFormingExpr(x, e);
- Expect(25);
- } else if (StartOf(19)) {
+ Expect(28);
+ } else if (StartOf(22)) {
SemErr("multiset must be followed by multiset literal or expression to coerce in parentheses.");
- } else SynErr(182);
+ } else SynErr(189);
}
- void MapExpr(out Expression e) {
+ void MapDisplayExpr(IToken/*!*/ mapToken, out Expression e) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null);
- IToken/*!*/ x = Token.NoToken;
- List<ExpressionPair/*!*/>/*!*/ elements;
+ List<ExpressionPair/*!*/>/*!*/ elements= new List<ExpressionPair/*!*/>() ;
e = dummyExpr;
- Expect(43);
- x = t;
- if (la.kind == 59) {
+ Expect(62);
+ if (StartOf(10)) {
+ MapLiteralExpressions(out elements);
+ }
+ e = new MapDisplayExpr(mapToken, elements);
+ Expect(63);
+ }
+
+ void MapComprehensionExpr(IToken/*!*/ mapToken, out Expression e) {
+ Contract.Ensures(Contract.ValueAtReturn(out e) != null);
+ BoundVar/*!*/ bv;
+ List<BoundVar/*!*/> bvars = new List<BoundVar/*!*/>();
+ Expression range = null;
+ Expression body;
+
+ IdentTypeOptional(out bv);
+ bvars.Add(bv);
+ if (la.kind == 22) {
Get();
- elements = new List<ExpressionPair/*!*/>();
- if (StartOf(10)) {
- MapLiteralExpressions(out elements);
- }
- e = new MapDisplayExpr(x, elements);
- Expect(60);
- } else if (la.kind == 1) {
- BoundVar/*!*/ bv;
- List<BoundVar/*!*/> bvars = new List<BoundVar/*!*/>();
- Expression/*!*/ range;
- Expression body = null;
-
- IdentTypeOptional(out bv);
- bvars.Add(bv);
- Expect(19);
Expression(out range);
- QSep();
- Expression(out body);
- e = new MapComprehension(x, bvars, range, body);
- } else if (StartOf(19)) {
- SemErr("map must be followed by literal in brackets or comprehension.");
- } else SynErr(183);
+ }
+ QSep();
+ Expression(out body);
+ e = new MapComprehension(mapToken, bvars, range ?? new LiteralExpr(mapToken, true), body);
+
}
void ConstAtomExpression(out Expression/*!*/ e) {
@@ -2498,17 +2645,17 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = dummyExpr;
switch (la.kind) {
- case 94: {
+ case 98: {
Get();
e = new LiteralExpr(t, false);
break;
}
- case 95: {
+ case 99: {
Get();
e = new LiteralExpr(t, true);
break;
}
- case 96: {
+ case 100: {
Get();
e = new LiteralExpr(t);
break;
@@ -2518,55 +2665,46 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = new LiteralExpr(t, n);
break;
}
- case 97: {
+ case 101: {
Get();
e = new ThisExpr(t);
break;
}
- case 98: {
+ case 102: {
Get();
x = t;
- Expect(23);
+ Expect(26);
Expression(out e);
- Expect(25);
+ Expect(28);
e = new FreshExpr(x, e);
break;
}
- case 99: {
+ case 103: {
Get();
x = t;
- Expect(23);
+ Expect(26);
Expression(out e);
- Expect(25);
- e = new AllocatedExpr(x, e);
- break;
- }
- case 100: {
- Get();
- x = t;
- Expect(23);
- Expression(out e);
- Expect(25);
+ Expect(28);
e = new OldExpr(x, e);
break;
}
- case 19: {
+ case 22: {
Get();
x = t;
Expression(out e);
e = new UnaryExpr(x, UnaryExpr.Opcode.SeqLength, e);
- Expect(19);
+ Expect(22);
break;
}
- case 23: {
+ case 26: {
Get();
x = t;
Expression(out e);
e = new ParensExpression(x, e);
- Expect(25);
+ Expect(28);
break;
}
- default: SynErr(184); break;
+ default: SynErr(190); break;
}
}
@@ -2585,34 +2723,34 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression/*!*/ d, r;
elements = new List<ExpressionPair/*!*/>();
Expression(out d);
- Expect(54);
+ Expect(57);
Expression(out r);
elements.Add(new ExpressionPair(d,r));
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
Expression(out d);
- Expect(54);
+ Expect(57);
Expression(out r);
elements.Add(new ExpressionPair(d,r));
}
}
void QSep() {
- if (la.kind == 107) {
+ if (la.kind == 110) {
Get();
- } else if (la.kind == 108) {
+ } else if (la.kind == 111) {
Get();
- } else SynErr(185);
+ } else SynErr(191);
}
void MatchExpression(out Expression/*!*/ e) {
Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x; MatchCaseExpr/*!*/ c;
List<MatchCaseExpr/*!*/> cases = new List<MatchCaseExpr/*!*/>();
- Expect(68);
+ Expect(71);
x = t;
Expression(out e);
- while (la.kind == 64) {
+ while (la.kind == 67) {
CaseExpression(out c);
cases.Add(c);
}
@@ -2627,13 +2765,13 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression range;
Expression/*!*/ body;
- if (la.kind == 103 || la.kind == 104) {
+ if (la.kind == 106 || la.kind == 107) {
Forall();
x = t; univ = true;
- } else if (la.kind == 105 || la.kind == 106) {
+ } else if (la.kind == 108 || la.kind == 109) {
Exists();
x = t;
- } else SynErr(186);
+ } else SynErr(192);
QuantifierDomain(out bvars, out attrs, out range);
QSep();
Expression(out body);
@@ -2653,18 +2791,18 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expression/*!*/ range;
Expression body = null;
- Expect(40);
+ Expect(43);
x = t;
IdentTypeOptional(out bv);
bvars.Add(bv);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
IdentTypeOptional(out bv);
bvars.Add(bv);
}
- Expect(19);
+ Expect(22);
Expression(out range);
- if (la.kind == 107 || la.kind == 108) {
+ if (la.kind == 110 || la.kind == 111) {
QSep();
Expression(out body);
}
@@ -2679,26 +2817,26 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
BoundVar d;
List<BoundVar> letVars; List<Expression> letRHSs;
- Expect(20);
+ Expect(23);
x = t;
letVars = new List<BoundVar>();
letRHSs = new List<Expression>();
IdentTypeOptional(out d);
letVars.Add(d);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
IdentTypeOptional(out d);
letVars.Add(d);
}
- Expect(54);
+ Expect(57);
Expression(out e);
letRHSs.Add(e);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
Expression(out e);
letRHSs.Add(e);
}
- Expect(12);
+ Expect(14);
Expression(out e);
e = new LetExpr(x, letVars, letRHSs, e);
}
@@ -2708,7 +2846,7 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
e = dummyExpr;
Expression expr;
- Expect(51);
+ Expect(54);
x = t;
NoUSIdent(out d);
Expect(5);
@@ -2723,39 +2861,39 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
BoundVar/*!*/ bv;
Expression/*!*/ body;
- Expect(64);
+ Expect(67);
x = t;
Ident(out id);
- if (la.kind == 23) {
+ if (la.kind == 26) {
Get();
IdentTypeOptional(out bv);
arguments.Add(bv);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
IdentTypeOptional(out bv);
arguments.Add(bv);
}
- Expect(25);
+ Expect(28);
}
- Expect(65);
+ Expect(68);
Expression(out body);
c = new MatchCaseExpr(x, id.val, arguments, body);
}
void Forall() {
- if (la.kind == 103) {
+ if (la.kind == 106) {
Get();
- } else if (la.kind == 104) {
+ } else if (la.kind == 107) {
Get();
- } else SynErr(187);
+ } else SynErr(193);
}
void Exists() {
- if (la.kind == 105) {
+ if (la.kind == 108) {
Get();
- } else if (la.kind == 106) {
+ } else if (la.kind == 109) {
Get();
- } else SynErr(188);
+ } else SynErr(194);
}
void AttributeBody(ref Attributes attrs) {
@@ -2766,10 +2904,10 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
Expect(5);
Expect(1);
aName = t.val;
- if (StartOf(20)) {
+ if (StartOf(23)) {
AttributeArg(out aArg);
aArgs.Add(aArg);
- while (la.kind == 21) {
+ while (la.kind == 24) {
Get();
AttributeArg(out aArg);
aArgs.Add(aArg);
@@ -2791,27 +2929,30 @@ List<Expression/*!*/>/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo
}
static readonly bool[,]/*!*/ set = {
- {T,T,T,x, x,x,T,x, T,x,x,x, T,x,x,T, x,T,T,T, T,x,x,T, x,x,x,x, T,T,x,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,T,x,x, x,x,T,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,x,x, T,T,x,x, x,x,x,T, T,T,T,x, T,x,T,x, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, T,x,x,x, T,x,x,x, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {T,x,x,x, x,x,T,T, T,T,x,x, x,x,x,T, T,T,T,x, T,x,T,T, x,x,T,x, T,T,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,T,x,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,T, x,x,x,x, x,x,T,T, x,x,x,x, x,T,x,T, x,x,T,x, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x},
- {x,T,T,x, x,x,T,x, T,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,T,x,x, x,x,T,x, x,x,T,x, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
- {x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,T, x,x,T,x, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x},
- {x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,T, x,x,x,x, x,T,T,T, x,x,x,x, x,T,x,T, x,x,T,x, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x},
- {T,T,T,x, x,x,T,x, T,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,T,x,x, x,x,T,x, x,x,T,x, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,T, x,x,x,x, x,T,x,T, x,x,x,x, x,T,T,T, x,T,T,x, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x},
- {x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
- {x,x,x,x, x,x,T,T, x,x,x,x, T,x,x,x, x,x,x,T, x,T,x,x, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,x, x,x,T,x, x,x,x,x, T,x,x,T, T,T,x,x, x,x,x,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,T,T,x, x,x,x,T, T,x,x},
- {x,T,T,x, T,x,T,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,T, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,T, x,x,T,x, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, T,x,x,T, T,T,T,x, x,x,x}
+ {T,T,T,x, x,x,T,x, T,x,x,x, x,x,T,x, x,x,T,x, T,T,T,T, x,x,T,x, x,x,x,T, T,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,x, T,x,x,x, x,T,x,x, x,T,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x},
+ {x,x,x,x, x,x,x,x, T,T,x,T, x,x,x,x, x,x,T,T, T,T,x,T, x,T,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,T, x,x,x,T, x,x,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {T,x,x,x, x,x,T,T, T,T,x,T, x,x,x,x, x,x,T,T, T,T,x,T, x,T,T,x, x,T,x,T, T,x,x,x, x,T,T,T, x,x,x,x, x,x,x,x, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {x,T,x,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,T,x, x,x,x,x, x,T,T,x, x,x,x,x, T,x,T,x, x,T,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, x,x,T,T, T,T,x,x, x,x},
+ {x,T,T,x, x,x,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,x, T,x,x,x, x,T,x,x, x,T,x,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x},
+ {x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,T,x, x,x,x,x, x,x,T,x, x,x,x,x, T,x,T,x, x,T,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, x,x,T,T, T,T,x,x, x,x},
+ {x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,T,x, x,x,x,x, T,T,T,x, x,x,x,x, T,x,T,x, x,T,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, x,x,T,T, T,T,x,x, x,x},
+ {T,T,T,x, x,x,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,x, T,x,x,x, x,T,x,x, x,T,x,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x},
+ {x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, x,x,x,x, T,T,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,T, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,T,x, x,x,x,x, x,x,T,x, x,x,x,x, T,x,T,x, x,T,x,x, x,x,x,T, T,x,x,T, T,T,T,T, x,x,x,x, T,T,T,T, T,T,T,T, T,x,T,x, x,T,T,T, T,T,T,T, x,x,T,T, T,T,x,x, x,x},
+ {x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,T,x, x,x,x,x, T,x,T,x, x,x,x,x, T,T,T,x, T,T,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, x,x,T,T, T,T,x,x, x,x},
+ {x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
+ {x,x,x,x, x,x,T,T, x,x,x,x, x,x,T,x, x,x,x,x, x,x,T,x, T,x,x,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x, x,T,x,x, x,x,x,T, x,x,T,T, T,x,x,x, x,x,x,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,x,x, x,x,x,x, T,T,x,x, x,x,T,T, x,x},
+ {x,x,x,x, x,x,T,T, x,x,x,x, x,x,T,x, x,T,x,x, x,x,T,x, T,x,x,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x, x,T,x,x, x,x,T,T, x,x,T,T, T,x,x,x, x,x,x,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,x,x, x,x,x,x, T,T,x,x, x,x,T,T, x,x},
+ {x,T,T,x, T,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,T,x, x,x,x,x, x,x,T,x, x,x,x,x, T,x,T,x, x,T,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,T,x, x,T,T,T, T,T,T,T, x,x,T,T, T,T,x,x, x,x}
};
} // end Parser
@@ -2847,184 +2988,190 @@ public class Errors {
case 8: s = "\"ghost\" expected"; break;
case 9: s = "\"module\" expected"; break;
case 10: s = "\"refines\" expected"; break;
- case 11: s = "\"=\" expected"; break;
- case 12: s = "\";\" expected"; break;
- case 13: s = "\"as\" expected"; break;
- case 14: s = "\".\" expected"; break;
- case 15: s = "\"class\" expected"; break;
- case 16: s = "\"static\" expected"; break;
- case 17: s = "\"datatype\" expected"; break;
- case 18: s = "\"codatatype\" expected"; break;
- case 19: s = "\"|\" expected"; break;
- case 20: s = "\"var\" expected"; break;
- case 21: s = "\",\" expected"; break;
- case 22: s = "\"type\" expected"; break;
- case 23: s = "\"(\" expected"; break;
- case 24: s = "\"==\" expected"; break;
- case 25: s = "\")\" expected"; break;
- case 26: s = "\"<\" expected"; break;
- case 27: s = "\">\" expected"; break;
- case 28: s = "\"method\" expected"; break;
- case 29: s = "\"constructor\" expected"; break;
- case 30: s = "\"returns\" expected"; break;
- case 31: s = "\"...\" expected"; break;
- case 32: s = "\"modifies\" expected"; break;
- case 33: s = "\"free\" expected"; break;
- case 34: s = "\"requires\" expected"; break;
- case 35: s = "\"ensures\" expected"; break;
- case 36: s = "\"decreases\" expected"; break;
- case 37: s = "\"bool\" expected"; break;
- case 38: s = "\"nat\" expected"; break;
- case 39: s = "\"int\" expected"; break;
- case 40: s = "\"set\" expected"; break;
- case 41: s = "\"multiset\" expected"; break;
- case 42: s = "\"seq\" expected"; break;
- case 43: s = "\"map\" expected"; break;
- case 44: s = "\"object\" expected"; break;
- case 45: s = "\"function\" expected"; break;
- case 46: s = "\"predicate\" expected"; break;
- case 47: s = "\"copredicate\" expected"; break;
- case 48: s = "\"reads\" expected"; break;
- case 49: s = "\"*\" expected"; break;
- case 50: s = "\"`\" expected"; break;
- case 51: s = "\"label\" expected"; break;
- case 52: s = "\"break\" expected"; break;
- case 53: s = "\"where\" expected"; break;
- case 54: s = "\":=\" expected"; break;
- case 55: s = "\"return\" expected"; break;
- case 56: s = "\":|\" expected"; break;
- case 57: s = "\"assume\" expected"; break;
- case 58: s = "\"new\" expected"; break;
- case 59: s = "\"[\" expected"; break;
- case 60: s = "\"]\" expected"; break;
- case 61: s = "\"choose\" expected"; break;
- case 62: s = "\"if\" expected"; break;
- case 63: s = "\"else\" expected"; break;
- case 64: s = "\"case\" expected"; break;
- case 65: s = "\"=>\" expected"; break;
- case 66: s = "\"while\" expected"; break;
- case 67: s = "\"invariant\" expected"; break;
- case 68: s = "\"match\" expected"; break;
- case 69: s = "\"assert\" expected"; break;
- case 70: s = "\"print\" expected"; break;
- case 71: s = "\"parallel\" expected"; break;
- case 72: s = "\"<==>\" expected"; break;
- case 73: s = "\"\\u21d4\" expected"; break;
- case 74: s = "\"==>\" expected"; break;
- case 75: s = "\"\\u21d2\" expected"; break;
- case 76: s = "\"&&\" expected"; break;
- case 77: s = "\"\\u2227\" expected"; break;
- case 78: s = "\"||\" expected"; break;
- case 79: s = "\"\\u2228\" expected"; break;
- case 80: s = "\"<=\" expected"; break;
- case 81: s = "\">=\" expected"; break;
- case 82: s = "\"!=\" expected"; break;
- case 83: s = "\"!!\" expected"; break;
- case 84: s = "\"in\" expected"; break;
- case 85: s = "\"!\" expected"; break;
- case 86: s = "\"\\u2260\" expected"; break;
- case 87: s = "\"\\u2264\" expected"; break;
- case 88: s = "\"\\u2265\" expected"; break;
- case 89: s = "\"+\" expected"; break;
- case 90: s = "\"-\" expected"; break;
- case 91: s = "\"/\" expected"; break;
- case 92: s = "\"%\" expected"; break;
- case 93: s = "\"\\u00ac\" expected"; break;
- case 94: s = "\"false\" expected"; break;
- case 95: s = "\"true\" expected"; break;
- case 96: s = "\"null\" expected"; break;
- case 97: s = "\"this\" expected"; break;
- case 98: s = "\"fresh\" expected"; break;
- case 99: s = "\"allocated\" expected"; break;
- case 100: s = "\"old\" expected"; break;
- case 101: s = "\"then\" expected"; break;
- case 102: s = "\"..\" expected"; break;
- case 103: s = "\"forall\" expected"; break;
- case 104: s = "\"\\u2200\" expected"; break;
- case 105: s = "\"exists\" expected"; break;
- case 106: s = "\"\\u2203\" expected"; break;
- case 107: s = "\"::\" expected"; break;
- case 108: s = "\"\\u2022\" expected"; break;
- case 109: s = "??? expected"; break;
- case 110: s = "invalid Dafny"; break;
- case 111: s = "invalid SubModuleDecl"; break;
- case 112: s = "invalid SubModuleDecl"; break;
- case 113: s = "this symbol not expected in ClassDecl"; break;
- case 114: s = "this symbol not expected in DatatypeDecl"; break;
- case 115: s = "invalid DatatypeDecl"; break;
- case 116: s = "this symbol not expected in DatatypeDecl"; break;
- case 117: s = "this symbol not expected in ArbitraryTypeDecl"; break;
- case 118: s = "invalid ClassMemberDecl"; break;
- case 119: s = "this symbol not expected in FieldDecl"; break;
- case 120: s = "this symbol not expected in FieldDecl"; break;
- case 121: s = "invalid FunctionDecl"; break;
- case 122: s = "invalid FunctionDecl"; break;
- case 123: s = "invalid FunctionDecl"; break;
- case 124: s = "invalid FunctionDecl"; break;
- case 125: s = "this symbol not expected in MethodDecl"; break;
- case 126: s = "invalid MethodDecl"; break;
- case 127: s = "invalid MethodDecl"; break;
- case 128: s = "invalid TypeAndToken"; break;
- case 129: s = "this symbol not expected in MethodSpec"; break;
- case 130: s = "this symbol not expected in MethodSpec"; break;
- case 131: s = "this symbol not expected in MethodSpec"; break;
- case 132: s = "this symbol not expected in MethodSpec"; break;
- case 133: s = "invalid MethodSpec"; break;
+ case 11: s = "\"import\" expected"; break;
+ case 12: s = "\"opened\" expected"; break;
+ case 13: s = "\"=\" expected"; break;
+ case 14: s = "\";\" expected"; break;
+ case 15: s = "\"as\" expected"; break;
+ case 16: s = "\"default\" expected"; break;
+ case 17: s = "\".\" expected"; break;
+ case 18: s = "\"class\" expected"; break;
+ case 19: s = "\"static\" expected"; break;
+ case 20: s = "\"datatype\" expected"; break;
+ case 21: s = "\"codatatype\" expected"; break;
+ case 22: s = "\"|\" expected"; break;
+ case 23: s = "\"var\" expected"; break;
+ case 24: s = "\",\" expected"; break;
+ case 25: s = "\"type\" expected"; break;
+ case 26: s = "\"(\" expected"; break;
+ case 27: s = "\"==\" expected"; break;
+ case 28: s = "\")\" expected"; break;
+ case 29: s = "\"<\" expected"; break;
+ case 30: s = "\">\" expected"; break;
+ case 31: s = "\"method\" expected"; break;
+ case 32: s = "\"constructor\" expected"; break;
+ case 33: s = "\"returns\" expected"; break;
+ case 34: s = "\"...\" expected"; break;
+ case 35: s = "\"modifies\" expected"; break;
+ case 36: s = "\"free\" expected"; break;
+ case 37: s = "\"requires\" expected"; break;
+ case 38: s = "\"ensures\" expected"; break;
+ case 39: s = "\"decreases\" expected"; break;
+ case 40: s = "\"bool\" expected"; break;
+ case 41: s = "\"nat\" expected"; break;
+ case 42: s = "\"int\" expected"; break;
+ case 43: s = "\"set\" expected"; break;
+ case 44: s = "\"multiset\" expected"; break;
+ case 45: s = "\"seq\" expected"; break;
+ case 46: s = "\"map\" expected"; break;
+ case 47: s = "\"object\" expected"; break;
+ case 48: s = "\"function\" expected"; break;
+ case 49: s = "\"predicate\" expected"; break;
+ case 50: s = "\"copredicate\" expected"; break;
+ case 51: s = "\"reads\" expected"; break;
+ case 52: s = "\"*\" expected"; break;
+ case 53: s = "\"`\" expected"; break;
+ case 54: s = "\"label\" expected"; break;
+ case 55: s = "\"break\" expected"; break;
+ case 56: s = "\"where\" expected"; break;
+ case 57: s = "\":=\" expected"; break;
+ case 58: s = "\"return\" expected"; break;
+ case 59: s = "\":|\" expected"; break;
+ case 60: s = "\"assume\" expected"; break;
+ case 61: s = "\"new\" expected"; break;
+ case 62: s = "\"[\" expected"; break;
+ case 63: s = "\"]\" expected"; break;
+ case 64: s = "\"choose\" expected"; break;
+ case 65: s = "\"if\" expected"; break;
+ case 66: s = "\"else\" expected"; break;
+ case 67: s = "\"case\" expected"; break;
+ case 68: s = "\"=>\" expected"; break;
+ case 69: s = "\"while\" expected"; break;
+ case 70: s = "\"invariant\" expected"; break;
+ case 71: s = "\"match\" expected"; break;
+ case 72: s = "\"assert\" expected"; break;
+ case 73: s = "\"print\" expected"; break;
+ case 74: s = "\"parallel\" expected"; break;
+ case 75: s = "\"calc\" expected"; break;
+ case 76: s = "\"<==>\" expected"; break;
+ case 77: s = "\"\\u21d4\" expected"; break;
+ case 78: s = "\"==>\" expected"; break;
+ case 79: s = "\"\\u21d2\" expected"; break;
+ case 80: s = "\"&&\" expected"; break;
+ case 81: s = "\"\\u2227\" expected"; break;
+ case 82: s = "\"||\" expected"; break;
+ case 83: s = "\"\\u2228\" expected"; break;
+ case 84: s = "\"<=\" expected"; break;
+ case 85: s = "\">=\" expected"; break;
+ case 86: s = "\"!=\" expected"; break;
+ case 87: s = "\"!!\" expected"; break;
+ case 88: s = "\"in\" expected"; break;
+ case 89: s = "\"!\" expected"; break;
+ case 90: s = "\"\\u2260\" expected"; break;
+ case 91: s = "\"\\u2264\" expected"; break;
+ case 92: s = "\"\\u2265\" expected"; break;
+ case 93: s = "\"+\" expected"; break;
+ case 94: s = "\"-\" expected"; break;
+ case 95: s = "\"/\" expected"; break;
+ case 96: s = "\"%\" expected"; break;
+ case 97: s = "\"\\u00ac\" expected"; break;
+ case 98: s = "\"false\" expected"; break;
+ case 99: s = "\"true\" expected"; break;
+ case 100: s = "\"null\" expected"; break;
+ case 101: s = "\"this\" expected"; break;
+ case 102: s = "\"fresh\" expected"; break;
+ case 103: s = "\"old\" expected"; break;
+ case 104: s = "\"then\" expected"; break;
+ case 105: s = "\"..\" expected"; break;
+ case 106: s = "\"forall\" expected"; break;
+ case 107: s = "\"\\u2200\" expected"; break;
+ case 108: s = "\"exists\" expected"; break;
+ case 109: s = "\"\\u2203\" expected"; break;
+ case 110: s = "\"::\" expected"; break;
+ case 111: s = "\"\\u2022\" expected"; break;
+ case 112: s = "??? expected"; break;
+ case 113: s = "invalid Dafny"; break;
+ case 114: s = "invalid SubModuleDecl"; break;
+ case 115: s = "invalid SubModuleDecl"; break;
+ case 116: s = "invalid SubModuleDecl"; break;
+ case 117: s = "this symbol not expected in ClassDecl"; break;
+ case 118: s = "this symbol not expected in DatatypeDecl"; break;
+ case 119: s = "invalid DatatypeDecl"; break;
+ case 120: s = "this symbol not expected in DatatypeDecl"; break;
+ case 121: s = "this symbol not expected in ArbitraryTypeDecl"; break;
+ case 122: s = "invalid ClassMemberDecl"; break;
+ case 123: s = "this symbol not expected in FieldDecl"; break;
+ case 124: s = "this symbol not expected in FieldDecl"; break;
+ case 125: s = "invalid FunctionDecl"; break;
+ case 126: s = "invalid FunctionDecl"; break;
+ case 127: s = "invalid FunctionDecl"; break;
+ case 128: s = "invalid FunctionDecl"; break;
+ case 129: s = "this symbol not expected in MethodDecl"; break;
+ case 130: s = "invalid MethodDecl"; break;
+ case 131: s = "invalid MethodDecl"; break;
+ case 132: s = "invalid TypeAndToken"; break;
+ case 133: s = "this symbol not expected in MethodSpec"; break;
case 134: s = "this symbol not expected in MethodSpec"; break;
- case 135: s = "invalid MethodSpec"; break;
- case 136: s = "invalid FrameExpression"; break;
- case 137: s = "invalid ReferenceType"; break;
- case 138: s = "this symbol not expected in FunctionSpec"; break;
- case 139: s = "this symbol not expected in FunctionSpec"; break;
- case 140: s = "this symbol not expected in FunctionSpec"; break;
- case 141: s = "this symbol not expected in FunctionSpec"; break;
+ case 135: s = "this symbol not expected in MethodSpec"; break;
+ case 136: s = "this symbol not expected in MethodSpec"; break;
+ case 137: s = "invalid MethodSpec"; break;
+ case 138: s = "this symbol not expected in MethodSpec"; break;
+ case 139: s = "invalid MethodSpec"; break;
+ case 140: s = "invalid FrameExpression"; break;
+ case 141: s = "invalid ReferenceType"; break;
case 142: s = "this symbol not expected in FunctionSpec"; break;
- case 143: s = "invalid FunctionSpec"; break;
- case 144: s = "invalid PossiblyWildFrameExpression"; break;
- case 145: s = "invalid PossiblyWildExpression"; break;
- case 146: s = "this symbol not expected in OneStmt"; break;
- case 147: s = "invalid OneStmt"; break;
- case 148: s = "this symbol not expected in OneStmt"; break;
- case 149: s = "invalid OneStmt"; break;
- case 150: s = "invalid AssertStmt"; break;
- case 151: s = "invalid AssumeStmt"; break;
- case 152: s = "invalid UpdateStmt"; break;
- case 153: s = "invalid UpdateStmt"; break;
- case 154: s = "invalid IfStmt"; break;
- case 155: s = "invalid IfStmt"; break;
- case 156: s = "invalid WhileStmt"; break;
- case 157: s = "invalid WhileStmt"; break;
- case 158: s = "invalid Rhs"; break;
- case 159: s = "invalid Lhs"; break;
- case 160: s = "invalid Guard"; break;
- case 161: s = "this symbol not expected in LoopSpec"; break;
- case 162: s = "this symbol not expected in LoopSpec"; break;
- case 163: s = "this symbol not expected in LoopSpec"; break;
- case 164: s = "this symbol not expected in LoopSpec"; break;
- case 165: s = "this symbol not expected in LoopSpec"; break;
- case 166: s = "this symbol not expected in Invariant"; break;
- case 167: s = "invalid AttributeArg"; break;
- case 168: s = "invalid EquivOp"; break;
- case 169: s = "invalid ImpliesOp"; break;
- case 170: s = "invalid AndOp"; break;
- case 171: s = "invalid OrOp"; break;
- case 172: s = "invalid RelOp"; break;
- case 173: s = "invalid AddOp"; break;
- case 174: s = "invalid UnaryExpression"; break;
- case 175: s = "invalid MulOp"; break;
- case 176: s = "invalid NegOp"; break;
- case 177: s = "invalid EndlessExpression"; break;
- case 178: s = "invalid Suffix"; break;
- case 179: s = "invalid Suffix"; break;
- case 180: s = "invalid Suffix"; break;
- case 181: s = "invalid DisplayExpr"; break;
- case 182: s = "invalid MultiSetExpr"; break;
- case 183: s = "invalid MapExpr"; break;
- case 184: s = "invalid ConstAtomExpression"; break;
- case 185: s = "invalid QSep"; break;
- case 186: s = "invalid QuantifierGuts"; break;
- case 187: s = "invalid Forall"; break;
- case 188: s = "invalid Exists"; break;
+ case 143: s = "this symbol not expected in FunctionSpec"; break;
+ case 144: s = "this symbol not expected in FunctionSpec"; break;
+ case 145: s = "this symbol not expected in FunctionSpec"; break;
+ case 146: s = "this symbol not expected in FunctionSpec"; break;
+ case 147: s = "invalid FunctionSpec"; break;
+ case 148: s = "invalid PossiblyWildFrameExpression"; break;
+ case 149: s = "invalid PossiblyWildExpression"; break;
+ case 150: s = "this symbol not expected in OneStmt"; break;
+ case 151: s = "invalid OneStmt"; break;
+ case 152: s = "this symbol not expected in OneStmt"; break;
+ case 153: s = "invalid OneStmt"; break;
+ case 154: s = "invalid AssertStmt"; break;
+ case 155: s = "invalid AssumeStmt"; break;
+ case 156: s = "invalid UpdateStmt"; break;
+ case 157: s = "invalid UpdateStmt"; break;
+ case 158: s = "invalid IfStmt"; break;
+ case 159: s = "invalid IfStmt"; break;
+ case 160: s = "invalid WhileStmt"; break;
+ case 161: s = "invalid WhileStmt"; break;
+ case 162: s = "invalid CalcStmt"; break;
+ case 163: s = "invalid Rhs"; break;
+ case 164: s = "invalid Lhs"; break;
+ case 165: s = "invalid Guard"; break;
+ case 166: s = "this symbol not expected in LoopSpec"; break;
+ case 167: s = "this symbol not expected in LoopSpec"; break;
+ case 168: s = "this symbol not expected in LoopSpec"; break;
+ case 169: s = "this symbol not expected in LoopSpec"; break;
+ case 170: s = "this symbol not expected in LoopSpec"; break;
+ case 171: s = "this symbol not expected in Invariant"; break;
+ case 172: s = "invalid AttributeArg"; break;
+ case 173: s = "invalid CalcOp"; break;
+ case 174: s = "invalid RelOp"; break;
+ case 175: s = "invalid EquivOp"; break;
+ case 176: s = "invalid ImpliesOp"; break;
+ case 177: s = "invalid AndOp"; break;
+ case 178: s = "invalid OrOp"; break;
+ case 179: s = "invalid AddOp"; break;
+ case 180: s = "invalid UnaryExpression"; break;
+ case 181: s = "invalid UnaryExpression"; break;
+ case 182: s = "invalid MulOp"; break;
+ case 183: s = "invalid NegOp"; break;
+ case 184: s = "invalid EndlessExpression"; break;
+ case 185: s = "invalid Suffix"; break;
+ case 186: s = "invalid Suffix"; break;
+ case 187: s = "invalid Suffix"; break;
+ case 188: s = "invalid DisplayExpr"; break;
+ case 189: s = "invalid MultiSetExpr"; break;
+ case 190: s = "invalid ConstAtomExpression"; break;
+ case 191: s = "invalid QSep"; break;
+ case 192: s = "invalid QuantifierGuts"; break;
+ case 193: s = "invalid Forall"; break;
+ case 194: s = "invalid Exists"; break;
default: s = "error " + n; break;
}
diff --git a/Source/Dafny/Printer.cs b/Source/Dafny/Printer.cs
index 8d6fa510..2051a54e 100644
--- a/Source/Dafny/Printer.cs
+++ b/Source/Dafny/Printer.cs
@@ -8,6 +8,7 @@ using System.IO;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Numerics;
+using System.Linq;
using Bpl = Microsoft.Boogie;
namespace Microsoft.Dafny {
@@ -84,11 +85,11 @@ namespace Microsoft.Dafny {
wr.WriteLine("}");
}
} else if (d is AliasModuleDecl) {
- wr.Write("module");
+ wr.Write("import"); if (((AliasModuleDecl)d).Opened) wr.Write(" opened");
wr.Write(" {0} ", ((AliasModuleDecl)d).Name);
wr.WriteLine("= {0};", Util.Comma(".", ((AliasModuleDecl)d).Path, id => id.val));
} else if (d is AbstractModuleDecl) {
- wr.Write("module");
+ wr.Write("import"); if (((AbstractModuleDecl)d).Opened) wr.Write(" opened");
wr.Write(" {0} ", ((AbstractModuleDecl)d).Name);
wr.WriteLine("as {0};", Util.Comma(".", ((AbstractModuleDecl)d).Path, id => id.val));
}
@@ -329,7 +330,7 @@ namespace Microsoft.Dafny {
wr.Write("ghost ");
}
if (f.HasName) {
- wr.Write("{0}: ", f.Name);
+ wr.Write("{0}: ", f.DisplayName);
}
PrintType(f.Type);
}
@@ -483,7 +484,7 @@ namespace Microsoft.Dafny {
if (s.IsGhost) {
wr.Write("ghost ");
}
- wr.Write("var {0}", s.Name);
+ wr.Write("var {0}", s.DisplayName);
PrintType(": ", s.OptionalType);
wr.Write(";");
@@ -559,6 +560,38 @@ namespace Microsoft.Dafny {
}
PrintStatement(s.Body, indent);
+ } else if (stmt is CalcStmt) {
+ CalcStmt s = (CalcStmt)stmt;
+ wr.Write("calc ");
+ if (s.Op != CalcStmt.DefaultOp) {
+ wr.Write(BinaryExpr.OpcodeString(s.Op));
+ wr.Write(" ");
+ }
+ wr.WriteLine("{");
+ int lineInd = indent + IndentAmount;
+ Indent(lineInd);
+ PrintExpression(s.Lines.First(), lineInd);
+ wr.WriteLine(";");
+ for (var i = 1; i < s.Lines.Count; i++){
+ var e = s.Lines[i];
+ var h = s.Hints[i - 1];
+ var op = s.CustomOps[i - 1];
+ if (h != null) {
+ Indent(lineInd);
+ PrintStatement(h, lineInd);
+ wr.WriteLine();
+ }
+ Indent(lineInd);
+ if (op != null && (BinaryExpr.Opcode)op != s.Op) {
+ wr.Write(BinaryExpr.OpcodeString((BinaryExpr.Opcode)op));
+ wr.Write(" ");
+ }
+ PrintExpression(e, lineInd);
+ wr.WriteLine(";");
+ }
+ Indent(indent);
+ wr.Write("}");
+
} else if (stmt is MatchStmt) {
MatchStmt s = (MatchStmt)stmt;
wr.Write("match ");
@@ -571,7 +604,7 @@ namespace Microsoft.Dafny {
if (mc.Arguments.Count != 0) {
string sep = "(";
foreach (BoundVar bv in mc.Arguments) {
- wr.Write("{0}{1}", sep, bv.Name);
+ wr.Write("{0}{1}", sep, bv.DisplayName);
sep = ", ";
}
wr.Write(")");
@@ -605,7 +638,7 @@ namespace Microsoft.Dafny {
wr.Write("var ");
string sep = "";
foreach (var lhs in s.Lhss) {
- wr.Write("{0}{1}", sep, lhs.Name);
+ wr.Write("{0}{1}", sep, lhs.DisplayName);
PrintType(": ", lhs.OptionalType);
sep = ", ";
}
@@ -803,7 +836,7 @@ namespace Microsoft.Dafny {
if (mc.Arguments.Count != 0) {
string sep = "(";
foreach (BoundVar bv in mc.Arguments) {
- wr.Write("{0}{1}", sep, bv.Name);
+ wr.Write("{0}{1}", sep, bv.DisplayName);
sep = ", ";
}
wr.Write(")");
@@ -1014,11 +1047,6 @@ namespace Microsoft.Dafny {
PrintExpression(((FreshExpr)expr).E);
wr.Write(")");
- } else if (expr is AllocatedExpr) {
- wr.Write("allocated(");
- PrintExpression(((AllocatedExpr)expr).E);
- wr.Write(")");
-
} else if (expr is UnaryExpr) {
UnaryExpr e = (UnaryExpr)expr;
if (e.Op == UnaryExpr.Opcode.SeqLength) {
@@ -1139,7 +1167,7 @@ namespace Microsoft.Dafny {
wr.Write("var ");
string sep = "";
foreach (var v in e.Vars) {
- wr.Write("{0}{1}", sep, v.Name);
+ wr.Write("{0}{1}", sep, v.DisplayName);
PrintType(": ", v.Type);
sep = ", ";
}
@@ -1179,7 +1207,7 @@ namespace Microsoft.Dafny {
wr.Write("set ");
string sep = "";
foreach (BoundVar bv in e.BoundVars) {
- wr.Write("{0}{1}", sep, bv.Name);
+ wr.Write("{0}{1}", sep, bv.DisplayName);
sep = ", ";
PrintType(": ", bv.Type);
}
@@ -1199,7 +1227,7 @@ namespace Microsoft.Dafny {
wr.Write("map ");
string sep = "";
foreach (BoundVar bv in e.BoundVars) {
- wr.Write("{0}{1}", sep, bv.Name);
+ wr.Write("{0}{1}", sep, bv.DisplayName);
sep = ", ";
PrintType(": ", bv.Type);
}
@@ -1268,7 +1296,7 @@ namespace Microsoft.Dafny {
Contract.Requires(boundVars != null);
string sep = "";
foreach (BoundVar bv in boundVars) {
- wr.Write("{0}{1}", sep, bv.Name);
+ wr.Write("{0}{1}", sep, bv.DisplayName);
PrintType(": ", bv.Type);
sep = ", ";
}
diff --git a/Source/Dafny/RefinementTransformer.cs b/Source/Dafny/RefinementTransformer.cs
index 56063442..f8f00904 100644
--- a/Source/Dafny/RefinementTransformer.cs
+++ b/Source/Dafny/RefinementTransformer.cs
@@ -55,14 +55,18 @@ namespace Microsoft.Dafny
ResolutionErrorReporter reporter;
Cloner rawCloner; // This cloner just gives exactly the same thing back.
RefinementCloner refinementCloner; // This cloner wraps things in a RefinementTransformer
- public RefinementTransformer(ResolutionErrorReporter reporter) {
+ Program program;
+ public RefinementTransformer(ResolutionErrorReporter reporter, Program p) {
Contract.Requires(reporter != null);
this.reporter = reporter;
rawCloner = new Cloner();
+ program = p;
}
private ModuleDefinition moduleUnderConstruction; // non-null for the duration of Construct calls
private Queue<Action> postTasks = new Queue<Action>(); // empty whenever moduleUnderConstruction==null, these tasks are for the post-resolve phase of module moduleUnderConstruction
+ public Queue<Tuple<Method, Method>> translationMethodChecks = new Queue<Tuple<Method, Method>>(); // contains all the methods that need to be checked for structural refinement.
+ private Method currentMethod;
public void PreResolve(ModuleDefinition m) {
@@ -108,7 +112,8 @@ namespace Microsoft.Dafny
}
if (derived != null) {
// check that the new module refines the previous declaration
- CheckIsRefinement(derived, original, nw.tok, "a module (" + d.Name + ") can only be replaced by a refinement of the original module");
+ if (!CheckIsRefinement(derived, original))
+ reporter.Error(nw.tok, "a module ({0}) can only be replaced by a refinement of the original module", d.Name);
}
}
} else if (d is ArbitraryTypeDecl) {
@@ -164,18 +169,280 @@ namespace Microsoft.Dafny
Contract.Assert(moduleUnderConstruction == m); // this should be as it was set earlier in this method
}
- public bool CheckIsRefinement(ModuleSignature derived, ModuleSignature original, IToken errorTok, string errorMsg) {
- while (derived != null) {
- if (derived == original)
- break;
- derived = derived.Refines;
+ public bool CheckIsRefinement(ModuleSignature derived, ModuleSignature original) {
+ // Check refinement by construction.
+ var derivedPointer = derived;
+ while (derivedPointer != null) {
+ if (derivedPointer == original)
+ return true;
+ derivedPointer = derivedPointer.Refines;
}
- if (derived != original) {
- reporter.Error(errorTok, errorMsg);
- return false;
- } else return true;
+ // Check structural refinement. Note this involves several checks.
+ // First, we need to know if the two modules are signature compatible;
+ // this is determined immediately as it is necessary for determining
+ // whether resolution will succeed. This involves checking classes, datatypes,
+ // type declarations, and nested modules.
+ // Second, we need to determine whether the specifications will be compatible
+ // (i.e. substitutable), by translating to Boogie.
+
+ var errorCount = reporter.ErrorCount;
+ foreach (var kv in original.TopLevels) {
+ var d = kv.Value;
+ TopLevelDecl nw;
+ if (derived.TopLevels.TryGetValue(kv.Key, out nw)) {
+ if (d is ModuleDecl) {
+ if (!(nw is ModuleDecl)) {
+ reporter.Error(nw, "a module ({0}) must refine another module", nw.Name);
+ } else {
+ CheckIsRefinement(((ModuleDecl)nw).Signature, ((ModuleDecl)d).Signature);
+ }
+ } else if (d is ArbitraryTypeDecl) {
+ if (nw is ModuleDecl) {
+ reporter.Error(nw, "a module ({0}) must refine another module", nw.Name);
+ } else {
+ bool dDemandsEqualitySupport = ((ArbitraryTypeDecl)d).MustSupportEquality;
+ if (nw is ArbitraryTypeDecl) {
+ if (dDemandsEqualitySupport != ((ArbitraryTypeDecl)nw).MustSupportEquality) {
+ reporter.Error(nw, "type declaration '{0}' is not allowed to change the requirement of supporting equality", nw.Name);
+ }
+ } else if (dDemandsEqualitySupport) {
+ if (nw is ClassDecl) {
+ // fine, as long as "nw" does not take any type parameters
+ if (nw.TypeArgs.Count != 0) {
+ reporter.Error(nw, "arbitrary type '{0}' is not allowed to be replaced by a class that takes type parameters", nw.Name);
+ }
+ } else if (nw is CoDatatypeDecl) {
+ reporter.Error(nw, "a type declaration that requires equality support cannot be replaced by a codatatype");
+ } else {
+ Contract.Assert(nw is IndDatatypeDecl);
+ if (nw.TypeArgs.Count != 0) {
+ reporter.Error(nw, "arbitrary type '{0}' is not allowed to be replaced by a datatype that takes type parameters", nw.Name);
+ } else {
+ var udt = new UserDefinedType(nw.tok, nw.Name, nw, new List<Type>());
+ if (!(udt.SupportsEquality)) {
+ reporter.Error(nw.tok, "datatype '{0}' is used to refine an arbitrary type with equality support, but '{0}' does not support equality", nw.Name);
+ }
+ }
+ }
+ }
+ }
+ } else if (d is DatatypeDecl) {
+ if (nw is DatatypeDecl) {
+ if (d is IndDatatypeDecl && !(nw is IndDatatypeDecl)) {
+ reporter.Error(nw, "a datatype ({0}) must be replaced by a datatype, not a codatatype", d.Name);
+ } else if (d is CoDatatypeDecl && !(nw is CoDatatypeDecl)) {
+ reporter.Error(nw, "a codatatype ({0}) must be replaced by a codatatype, not a datatype", d.Name);
+ }
+ // check constructors, formals, etc.
+ CheckDatatypesAreRefinements((DatatypeDecl)d, (DatatypeDecl)nw);
+ } else {
+ reporter.Error(nw, "a {0} ({1}) must be refined by a {0}", d is IndDatatypeDecl ? "datatype" : "codatatype", d.Name);
+ }
+ } else if (d is ClassDecl) {
+ if (!(nw is ClassDecl)) {
+ reporter.Error(nw, "a class declaration ({0}) must be refined by another class declaration", nw.Name);
+ } else {
+ CheckClassesAreRefinements((ClassDecl)nw, (ClassDecl)d);
+ }
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected toplevel
+ }
+ } else {
+ reporter.Error(d, "declaration {0} must have a matching declaration in the refining module", d.Name);
+ }
+ }
+ return errorCount == reporter.ErrorCount;
}
+ private void CheckClassesAreRefinements(ClassDecl nw, ClassDecl d) {
+ if (nw.TypeArgs.Count != d.TypeArgs.Count) {
+ reporter.Error(nw, "a refining class ({0}) must have the same number of type parameters", nw.Name);
+ } else {
+ var map = new Dictionary<string, MemberDecl>();
+ foreach (var mem in nw.Members) {
+ map.Add(mem.Name, mem);
+ }
+ foreach (var m in d.Members) {
+ MemberDecl newMem;
+ if (map.TryGetValue(m.Name, out newMem)) {
+ if (m.IsStatic != newMem.IsStatic) {
+ reporter.Error(newMem, "member {0} must {1}", m.Name, m.IsStatic? "be static" : "not be static");
+ }
+ if (m is Field) {
+ if (newMem is Field) {
+ var newField = (Field)newMem;
+ if (!ResolvedTypesAreTheSame(newField.Type, ((Field)m).Type))
+ reporter.Error(newMem, "field must be refined by a field with the same type (got {0}, expected {1})", newField.Type, ((Field)m).Type);
+ if (m.IsGhost || !newField.IsGhost)
+ reporter.Error(newField, "a field re-declaration ({0}) must be to ghostify the field", newField.Name, nw.Name);
+ } else {
+ reporter.Error(newMem, "a field declaration ({1}) must be replaced by a field in the refinement base (not {0})", newMem.Name, nw.Name);
+ }
+ } else if (m is Method) {
+ if (newMem is Method) {
+ CheckMethodsAreRefinements((Method)newMem, (Method)m);
+ } else {
+ reporter.Error(newMem, "method must be refined by a method");
+ }
+ } else if (m is Function) {
+ if (newMem is Function) {
+ CheckFunctionsAreRefinements((Function)newMem, (Function)m);
+ } else {
+ bool isPredicate = m is Predicate;
+ bool isCoPredicate = m is CoPredicate;
+ string s = isPredicate ? "predicate" : isCoPredicate ? "copredicate" : "function";
+ reporter.Error(newMem, "{0} must be refined by a {0}", s);
+ }
+ }
+ } else {
+ reporter.Error(nw is DefaultClassDecl ? nw.Module.tok : nw.tok, "refining {0} must have member {1}", nw is DefaultClassDecl ? "module" : "class", m.Name);
+ }
+ }
+ }
+ }
+ void CheckAgreementResolvedParameters(IToken tok, List<Formal> old, List<Formal> nw, string name, string thing, string parameterKind) {
+ Contract.Requires(tok != null);
+ Contract.Requires(old != null);
+ Contract.Requires(nw != null);
+ Contract.Requires(name != null);
+ Contract.Requires(thing != null);
+ Contract.Requires(parameterKind != null);
+ if (old.Count != nw.Count) {
+ reporter.Error(tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines", thing, name, parameterKind, nw.Count, old.Count);
+ } else {
+ for (int i = 0; i < old.Count; i++) {
+ var o = old[i];
+ var n = nw[i];
+ if (!o.IsGhost && n.IsGhost) {
+ reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name);
+ } else if (o.IsGhost && !n.IsGhost) {
+ reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name);
+ } else if (!ResolvedTypesAreTheSame(o.Type, n.Type)) {
+ reporter.Error(n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type);
+ }
+ }
+ }
+ }
+ private void CheckMethodsAreRefinements(Method nw, Method m) {
+ CheckAgreement_TypeParameters(nw.tok, m.TypeArgs, nw.TypeArgs, m.Name, "method", false);
+ CheckAgreementResolvedParameters(nw.tok, m.Ins, nw.Ins, m.Name, "method", "in-parameter");
+ CheckAgreementResolvedParameters(nw.tok, m.Outs, nw.Outs, m.Name, "method", "out-parameter");
+ program.TranslationTasks.Add(new MethodCheck(nw, m));
+ }
+ private void CheckFunctionsAreRefinements(Function nw, Function f) {
+ if (f is Predicate) {
+ if (!(nw is Predicate)) {
+ reporter.Error(nw, "a predicate declaration ({0}) can only be refined by a predicate", nw.Name);
+ } else {
+ CheckAgreement_TypeParameters(nw.tok, f.TypeArgs, nw.TypeArgs, nw.Name, "predicate", false);
+ CheckAgreementResolvedParameters(nw.tok, f.Formals, nw.Formals, nw.Name, "predicate", "parameter");
+ }
+ } else if (f is CoPredicate) {
+ reporter.Error(nw, "refinement of co-predicates is not supported");
+ } else {
+ // f is a plain Function
+ if (nw is Predicate || nw is CoPredicate) {
+ reporter.Error(nw, "a {0} declaration ({1}) can only be refined by a function or function method", nw.IsGhost ? "function" : "function method", nw.Name);
+ } else {
+ CheckAgreement_TypeParameters(nw.tok, f.TypeArgs, nw.TypeArgs, nw.Name, "function", false);
+ CheckAgreementResolvedParameters(nw.tok, f.Formals, nw.Formals, nw.Name, "function", "parameter");
+ if (!ResolvedTypesAreTheSame(nw.ResultType, f.ResultType)) {
+ reporter.Error(nw, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", nw.Name, nw.ResultType, f.ResultType);
+ }
+ }
+ }
+ program.TranslationTasks.Add(new FunctionCheck(nw, f));
+ }
+
+
+ private void CheckDatatypesAreRefinements(DatatypeDecl dd, DatatypeDecl nn) {
+ CheckAgreement_TypeParameters(nn.tok, dd.TypeArgs, nn.TypeArgs, dd.Name, "datatype", false);
+ if (dd.Ctors.Count != nn.Ctors.Count) {
+ reporter.Error(nn.tok, "a refining datatype must have the same number of constructors");
+ } else {
+ var map = new Dictionary<string, DatatypeCtor>();
+ foreach (var ctor in nn.Ctors) {
+ map.Add(ctor.Name, ctor);
+ }
+ foreach (var ctor in dd.Ctors) {
+ DatatypeCtor newCtor;
+ if (map.TryGetValue(ctor.Name, out newCtor)) {
+ if (newCtor.Formals.Count != ctor.Formals.Count) {
+ reporter.Error(newCtor, "the constructor ({0}) must have the same number of formals as in the refined module", newCtor.Name);
+ } else {
+ for (int i = 0; i < newCtor.Formals.Count; i++) {
+ var a = ctor.Formals[i]; var b = newCtor.Formals[i];
+ if (a.HasName) {
+ if (!b.HasName || a.Name != b.Name)
+ reporter.Error(b, "formal argument {0} in constructor {1} does not have the same name as in the refined module (should be {2})", i, ctor.Name, a.Name);
+ }
+ if (!ResolvedTypesAreTheSame(a.Type, b.Type)) {
+ reporter.Error(b, "formal argument {0} in constructor {1} does not have the same type as in the refined module (should be {2}, not {3})", i, ctor.Name, a.Type.ToString(), b.Type.ToString());
+ }
+ }
+ }
+ } else {
+ reporter.Error(nn, "the constructor {0} must be present in the refining datatype", ctor.Name);
+ }
+ }
+ }
+
+ }
+ // Check that two resolved types are the same in a similar context (the same type parameters, method, class, etc.)
+ // Assumes that prev is in a previous refinement, and next is in some refinement. Note this is not communative.
+ public static bool ResolvedTypesAreTheSame(Type prev, Type next) {
+ Contract.Requires(prev != null);
+ Contract.Requires(next != null);
+ if (prev is TypeProxy || next is TypeProxy)
+ return false;
+
+ if (prev is BoolType) {
+ return next is BoolType;
+ } else if (prev is IntType) {
+ if (next is IntType) {
+ return (prev is NatType) == (next is NatType);
+ } else return false;
+ } else if (prev is ObjectType) {
+ return next is ObjectType;
+ } else if (prev is SetType) {
+ return next is SetType && ResolvedTypesAreTheSame(((SetType)prev).Arg, ((SetType)next).Arg);
+ } else if (prev is MultiSetType) {
+ return next is MultiSetType && ResolvedTypesAreTheSame(((MultiSetType)prev).Arg, ((MultiSetType)next).Arg);
+ } else if (prev is MapType) {
+ return next is MapType && ResolvedTypesAreTheSame(((MapType)prev).Domain, ((MapType)next).Domain) && ResolvedTypesAreTheSame(((MapType)prev).Range, ((MapType)next).Range);
+ } else if (prev is SeqType) {
+ return next is SeqType && ResolvedTypesAreTheSame(((SeqType)prev).Arg, ((SeqType)next).Arg);
+ } else if (prev is UserDefinedType) {
+ if (!(next is UserDefinedType)) {
+ return false;
+ }
+ UserDefinedType aa = (UserDefinedType)prev;
+ UserDefinedType bb = (UserDefinedType)next;
+ if (aa.ResolvedClass != null && aa.ResolvedClass.Name == bb.ResolvedClass.Name) {
+ // these are both resolved class/datatype types
+ Contract.Assert(aa.TypeArgs.Count == bb.TypeArgs.Count);
+ for (int i = 0; i < aa.TypeArgs.Count; i++)
+ if (!ResolvedTypesAreTheSame(aa.TypeArgs[i], bb.TypeArgs[i]))
+ return false;
+ return true;
+ } else if (aa.ResolvedParam != null && bb.ResolvedParam != null) {
+ // these are both resolved type parameters
+ Contract.Assert(aa.TypeArgs.Count == 0 && bb.TypeArgs.Count == 0);
+ // Note that this is only correct if the two types occur in the same context, ie. both from the same method
+ // or class field.
+ return aa.ResolvedParam.PositionalIndex == bb.ResolvedParam.PositionalIndex &&
+ aa.ResolvedParam.IsToplevelScope == bb.ResolvedParam.IsToplevelScope;
+ } else if (aa.ResolvedParam.IsAbstractTypeDeclaration && bb.ResolvedClass != null) {
+ return (aa.ResolvedParam.Name == bb.ResolvedClass.Name);
+ } else {
+ // something is wrong; either aa or bb wasn't properly resolved, or they aren't the same
+ return false;
+ }
+
+ } else {
+ Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type
+ }
+ }
public void PostResolve(ModuleDefinition m) {
if (m == moduleUnderConstruction) {
while (this.postTasks.Count != 0) {
@@ -187,7 +454,7 @@ namespace Microsoft.Dafny
}
moduleUnderConstruction = null;
}
- Function CloneFunction(IToken tok, Function f, bool isGhost, List<Expression> moreEnsures, Expression moreBody, Expression replacementBody) {
+ Function CloneFunction(IToken tok, Function f, bool isGhost, List<Expression> moreEnsures, Expression moreBody, Expression replacementBody, bool checkPrevPostconditions, Attributes moreAttributes) {
Contract.Requires(moreBody == null || f is Predicate);
Contract.Requires(moreBody == null || replacementBody == null);
@@ -198,62 +465,69 @@ namespace Microsoft.Dafny
var decreases = refinementCloner.CloneSpecExpr(f.Decreases);
List<Expression> ens;
- if (moreBody != null || replacementBody != null)
+ if (checkPrevPostconditions) // note, if a postcondition includes something that changes in the module, the translator will notice this and still re-check the postcondition
ens = f.Ens.ConvertAll(rawCloner.CloneExpr);
- else ens = f.Ens.ConvertAll(refinementCloner.CloneExpr);
+ else
+ ens = f.Ens.ConvertAll(refinementCloner.CloneExpr);
if (moreEnsures != null) {
ens.AddRange(moreEnsures);
}
Expression body;
+ Predicate.BodyOriginKind bodyOrigin;
if (replacementBody != null) {
body = replacementBody;
+ bodyOrigin = Predicate.BodyOriginKind.DelayedDefinition;
} else if (moreBody != null) {
if (f.Body == null) {
body = moreBody;
+ bodyOrigin = Predicate.BodyOriginKind.DelayedDefinition;
} else {
body = new BinaryExpr(f.tok, BinaryExpr.Opcode.And, refinementCloner.CloneExpr(f.Body), moreBody);
+ bodyOrigin = Predicate.BodyOriginKind.Extension;
}
} else {
body = refinementCloner.CloneExpr(f.Body);
+ bodyOrigin = Predicate.BodyOriginKind.OriginalOrInherited;
}
if (f is Predicate) {
return new Predicate(tok, f.Name, f.IsStatic, isGhost, tps, f.OpenParen, formals,
- req, reads, ens, decreases, body, moreBody != null, null, false);
+ req, reads, ens, decreases, body, bodyOrigin, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), false);
} else if (f is CoPredicate) {
return new CoPredicate(tok, f.Name, f.IsStatic, tps, f.OpenParen, formals,
- req, reads, ens, body, null, false);
+ req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), false);
} else {
return new Function(tok, f.Name, f.IsStatic, isGhost, tps, f.OpenParen, formals, refinementCloner.CloneType(f.ResultType),
- req, reads, ens, decreases, body, null, false);
+ req, reads, ens, decreases, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), false);
}
}
- Method CloneMethod(Method m, List<MaybeFreeExpression> moreEnsures, BlockStmt replacementBody) {
+ Method CloneMethod(Method m, List<MaybeFreeExpression> moreEnsures, Specification<Expression> decreases, BlockStmt newBody, bool checkPreviousPostconditions, Attributes moreAttributes) {
Contract.Requires(m != null);
+ Contract.Requires(decreases != null);
var tps = m.TypeArgs.ConvertAll(refinementCloner.CloneTypeParam);
var ins = m.Ins.ConvertAll(refinementCloner.CloneFormal);
var req = m.Req.ConvertAll(refinementCloner.CloneMayBeFreeExpr);
var mod = refinementCloner.CloneSpecFrameExpr(m.Mod);
- var decreases = refinementCloner.CloneSpecExpr(m.Decreases);
List<MaybeFreeExpression> ens;
- if (replacementBody != null)
+ if (checkPreviousPostconditions)
ens = m.Ens.ConvertAll(rawCloner.CloneMayBeFreeExpr);
- else ens = m.Ens.ConvertAll(refinementCloner.CloneMayBeFreeExpr);
+ else
+ ens = m.Ens.ConvertAll(refinementCloner.CloneMayBeFreeExpr);
if (moreEnsures != null) {
ens.AddRange(moreEnsures);
}
- var body = replacementBody ?? refinementCloner.CloneBlockStmt(m.Body);
+ var body = newBody ?? refinementCloner.CloneBlockStmt(m.Body);
if (m is Constructor) {
return new Constructor(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, tps, ins,
- req, mod, ens, decreases, body, null, false);
+ req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), false);
} else {
return new Method(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.IsStatic, m.IsGhost, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal),
- req, mod, ens, decreases, body, null, false);
+ req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), false);
}
}
@@ -279,7 +553,7 @@ namespace Microsoft.Dafny
} else {
var nwMember = nw.Members[index];
if (nwMember is Field) {
- if (member is Field && TypesAreEqual(((Field)nwMember).Type, ((Field)member).Type)) {
+ if (member is Field && TypesAreSyntacticallyEqual(((Field)nwMember).Type, ((Field)member).Type)) {
if (member.IsGhost || !nwMember.IsGhost)
reporter.Error(nwMember, "a field re-declaration ({0}) must be to ghostify the field", nwMember.Name, nw.Name);
} else {
@@ -318,21 +592,21 @@ namespace Microsoft.Dafny
} else {
CheckAgreement_TypeParameters(f.tok, prevFunction.TypeArgs, f.TypeArgs, f.Name, "function");
CheckAgreement_Parameters(f.tok, prevFunction.Formals, f.Formals, f.Name, "function", "parameter");
- if (!TypesAreEqual(prevFunction.ResultType, f.ResultType)) {
+ if (!TypesAreSyntacticallyEqual(prevFunction.ResultType, f.ResultType)) {
reporter.Error(f, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", f.Name, f.ResultType, prevFunction.ResultType);
}
}
Expression moreBody = null;
Expression replacementBody = null;
- if (isPredicate) {
- moreBody = f.Body;
- } else if (prevFunction.Body == null) {
+ if (prevFunction.Body == null) {
replacementBody = f.Body;
+ } else if (isPredicate) {
+ moreBody = f.Body;
} else if (f.Body != null) {
reporter.Error(nwMember, "a refining function is not allowed to extend/change the body");
}
- nw.Members[index] = CloneFunction(f.tok, prevFunction, f.IsGhost, f.Ens, moreBody, replacementBody);
+ nw.Members[index] = CloneFunction(f.tok, prevFunction, f.IsGhost, f.Ens, moreBody, replacementBody, prevFunction.Body == null, f.Attributes);
}
} else {
@@ -347,10 +621,15 @@ namespace Microsoft.Dafny
if (m.Mod.Expressions.Count != 0) {
reporter.Error(m.Mod.Expressions[0].E.tok, "a refining method is not allowed to extend the modifies clause");
}
- if (m.Decreases.Expressions.Count != 0) {
- reporter.Error(m.Decreases.Expressions[0].tok, "decreases clause on refining method not supported");
+ Specification<Expression> decreases;
+ if (Contract.Exists(prevMethod.Decreases.Expressions, e => e is WildcardExpr)) {
+ decreases = m.Decreases;
+ } else {
+ if (m.Decreases.Expressions.Count != 0) {
+ reporter.Error(m.Decreases.Expressions[0].tok, "decreases clause on refining method not supported, unless the refined method was specified with 'decreases *'");
+ }
+ decreases = refinementCloner.CloneSpecExpr(prevMethod.Decreases);
}
-
if (prevMethod.IsStatic != m.IsStatic) {
reporter.Error(m, "a method in a refining module cannot be changed from static to non-static or vice versa: {0}", m.Name);
}
@@ -368,7 +647,7 @@ namespace Microsoft.Dafny
CheckAgreement_Parameters(m.tok, prevMethod.Ins, m.Ins, m.Name, "method", "in-parameter");
CheckAgreement_Parameters(m.tok, prevMethod.Outs, m.Outs, m.Name, "method", "out-parameter");
}
-
+ currentMethod = m;
var replacementBody = m.Body;
if (replacementBody != null) {
if (prevMethod.Body == null) {
@@ -377,7 +656,7 @@ namespace Microsoft.Dafny
replacementBody = MergeBlockStmt(replacementBody, prevMethod.Body);
}
}
- nw.Members[index] = CloneMethod(prevMethod, m.Ens, replacementBody);
+ nw.Members[index] = CloneMethod(prevMethod, m.Ens, decreases, replacementBody, prevMethod.Body == null, m.Attributes);
}
}
}
@@ -385,7 +664,7 @@ namespace Microsoft.Dafny
return nw;
}
- void CheckAgreement_TypeParameters(IToken tok, List<TypeParameter> old, List<TypeParameter> nw, string name, string thing) {
+ void CheckAgreement_TypeParameters(IToken tok, List<TypeParameter> old, List<TypeParameter> nw, string name, string thing, bool checkNames = true) {
Contract.Requires(tok != null);
Contract.Requires(old != null);
Contract.Requires(nw != null);
@@ -397,7 +676,7 @@ namespace Microsoft.Dafny
for (int i = 0; i < old.Count; i++) {
var o = old[i];
var n = nw[i];
- if (o.Name != n.Name) {
+ if (o.Name != n.Name && checkNames) { // if checkNames is false, then just treat the parameters positionally.
reporter.Error(n.tok, "type parameters are not allowed to be renamed from the names given in the {0} in the module being refined (expected '{1}', found '{2}')", thing, o.Name, n.Name);
} else {
// This explains what we want to do and why:
@@ -444,14 +723,14 @@ namespace Microsoft.Dafny
reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name);
} else if (o.IsGhost && !n.IsGhost) {
reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name);
- } else if (!TypesAreEqual(o.Type, n.Type)) {
+ } else if (!TypesAreSyntacticallyEqual(o.Type, n.Type)) {
reporter.Error(n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type);
}
}
}
}
- bool TypesAreEqual(Type t, Type u) {
+ bool TypesAreSyntacticallyEqual(Type t, Type u) {
Contract.Requires(t != null);
Contract.Requires(u != null);
return t.ToString() == u.ToString();
@@ -506,8 +785,6 @@ namespace Microsoft.Dafny
*
* Note, LoopSpec must contain only invariant declarations (as the parser ensures for the first three cases).
* Note, there is an implicit "...;" at the end of every block in a skeleton.
- *
- * TODO: should also handle labels and some form of new "replace" statement
*/
if (cur is SkeletonStatement) {
var S = ((SkeletonStatement)cur).S;
@@ -560,7 +837,8 @@ namespace Microsoft.Dafny
// it is not allowed to be just assumed in the translation, despite the fact
// that the condition is inherited.
var e = refinementCloner.CloneExpr(oldAssume.Expr);
- body.Add(new AssertStmt(new Translator.ForceCheckToken(skel.Tok), e, new Attributes("prependAssertToken", new List<Attributes.Argument>(), null)));
+ var attrs = refinementCloner.MergeAttributes(oldAssume.Attributes, skel.Attributes);
+ body.Add(new AssertStmt(new Translator.ForceCheckToken(skel.Tok), e, new Attributes("prependAssertToken", new List<Attributes.Argument>(), attrs)));
i++; j++;
}
@@ -573,7 +851,8 @@ namespace Microsoft.Dafny
i++;
} else {
var e = refinementCloner.CloneExpr(oldAssume.Expr);
- body.Add(new AssumeStmt(skel.Tok, e, null));
+ var attrs = refinementCloner.MergeAttributes(oldAssume.Attributes, skel.Attributes);
+ body.Add(new AssumeStmt(skel.Tok, e, attrs));
i++; j++;
}
@@ -792,10 +1071,21 @@ namespace Microsoft.Dafny
}
bool PotentialMatch(Statement nxt, Statement other) {
+ Contract.Requires(nxt != null);
Contract.Requires(!(nxt is SkeletonStatement) || ((SkeletonStatement)nxt).S != null); // nxt is not "...;"
Contract.Requires(other != null);
- if (nxt is SkeletonStatement) {
+ if (nxt.Labels != null) {
+ for (var olbl = other.Labels; olbl != null; olbl = olbl.Next) {
+ var odata = olbl.Data;
+ for (var l = nxt.Labels; l != null; l = l.Next) {
+ if (odata.Name == l.Data.Name) {
+ return true;
+ }
+ }
+ }
+ return false; // labels of 'nxt' don't match any label of 'other'
+ } else if (nxt is SkeletonStatement) {
var S = ((SkeletonStatement)nxt).S;
if (S is AssertStmt) {
return other is PredicateStmt;
@@ -957,7 +1247,7 @@ namespace Microsoft.Dafny
}
// Checks that statement stmt, defined in the constructed module m, is a refinement of skip in the parent module
- private void CheckIsOkayUpdateStmt(ConcreteUpdateStatement stmt, ModuleDefinition m, ResolutionErrorReporter reporter) {
+ private bool CheckIsOkayUpdateStmt(ConcreteUpdateStatement stmt, ModuleDefinition m, ResolutionErrorReporter reporter) {
foreach (var lhs in stmt.Lhss) {
var l = lhs.Resolved;
if (l is IdentifierExpr) {
@@ -966,23 +1256,25 @@ namespace Microsoft.Dafny
if ((ident.Var is VarDecl && RefinementToken.IsInherited(((VarDecl)ident.Var).Tok, m)) || ident.Var is Formal) {
// for some reason, formals are not considered to be inherited.
reporter.Error(l.tok, "cannot assign to variable defined previously");
+ return false;
}
} else if (l is FieldSelectExpr) {
if (RefinementToken.IsInherited(((FieldSelectExpr)l).Field.tok, m)) {
- reporter.Error(l.tok, "cannot assign to field defined previously");
+ return false;
}
} else {
- reporter.Error(lhs.tok, "cannot assign to something which could exist in the previous refinement");
+ return false;
}
}
if (stmt is UpdateStmt) {
var s = (UpdateStmt)stmt;
foreach (var rhs in s.Rhss) {
if (s.Rhss[0].CanAffectPreviouslyKnownExpressions) {
- reporter.Error(s.Rhss[0].Tok, "cannot have method call which can affect the heap");
+ return false;
}
}
}
+ return true;
}
// ---------------------- additional methods -----------------------------------------------------------------------------
@@ -994,7 +1286,7 @@ namespace Microsoft.Dafny
var e = (FunctionCallExpr)expr;
if (e.Function.EnclosingClass.Module == m) {
var p = e.Function as Predicate;
- if (p != null && p.BodyIsExtended) {
+ if (p != null && p.BodyOrigin == Predicate.BodyOriginKind.Extension) {
return true;
}
}
@@ -1014,9 +1306,16 @@ namespace Microsoft.Dafny
public RefinementCloner(ModuleDefinition m) {
moduleUnderConstruction = m;
}
- override public IToken Tok(IToken tok) {
+ public override IToken Tok(IToken tok) {
return new RefinementToken(tok, moduleUnderConstruction);
}
+ public virtual Attributes MergeAttributes(Attributes prevAttrs, Attributes moreAttrs) {
+ if (moreAttrs == null) {
+ return CloneAttributes(prevAttrs);
+ } else {
+ return new Attributes(moreAttrs.Name, moreAttrs.Args.ConvertAll(CloneAttrArg), MergeAttributes(prevAttrs, moreAttrs.Prev));
+ }
+ }
}
class SubstitutionCloner : Cloner {
public Dictionary<string, Expression> Exprs;
@@ -1027,7 +1326,7 @@ namespace Microsoft.Dafny
SubstitutionsMade = new SortedSet<string>();
this.c = c;
}
- new public Expression CloneExpr(Expression expr) {
+ public override Expression CloneExpr(Expression expr) {
if (expr is NamedExpr) {
NamedExpr n = (NamedExpr)expr;
Expression E;
diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs
index 8c14cb0c..a2710c38 100644
--- a/Source/Dafny/Resolver.cs
+++ b/Source/Dafny/Resolver.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Numerics;
using System.Diagnostics.Contracts;
+using System.Linq;
using Microsoft.Boogie;
namespace Microsoft.Dafny
@@ -93,6 +94,31 @@ namespace Microsoft.Dafny
return nm;
}
}
+
+ class AmbiguousMemberDecl : MemberDecl // only used with "classes"
+ {
+ readonly MemberDecl A;
+ readonly MemberDecl B;
+ public AmbiguousMemberDecl(ModuleDefinition m, MemberDecl a, MemberDecl b)
+ : base(a.tok, a.Name + "/" + b.Name, a.IsStatic, a.IsGhost, null) {
+ A = a;
+ B = b;
+ }
+ public string ModuleNames() {
+ string nm;
+ if (A is AmbiguousMemberDecl) {
+ nm = ((AmbiguousMemberDecl)A).ModuleNames();
+ } else {
+ nm = A.EnclosingClass.Module.Name;
+ }
+ if (B is AmbiguousMemberDecl) {
+ nm += ", " + ((AmbiguousMemberDecl)B).ModuleNames();
+ } else {
+ nm += ", " + B.EnclosingClass.Module.Name;
+ }
+ return nm;
+ }
+ }
//Dictionary<string/*!*/, Tuple<DatatypeCtor, bool>> allDatatypeCtors;
readonly Dictionary<ClassDecl/*!*/, Dictionary<string/*!*/, MemberDecl/*!*/>/*!*/>/*!*/ classMembers = new Dictionary<ClassDecl/*!*/, Dictionary<string/*!*/, MemberDecl/*!*/>/*!*/>();
@@ -144,10 +170,10 @@ namespace Microsoft.Dafny
h++;
}
- var refinementTransformer = new RefinementTransformer(this);
+ var refinementTransformer = new RefinementTransformer(this, prog);
IRewriter rewriter = new AutoContractsRewriter();
- systemNameInfo = RegisterTopLevelDecls(prog.BuiltIns.SystemModule);
+ systemNameInfo = RegisterTopLevelDecls(prog.BuiltIns.SystemModule, false);
foreach (var decl in sortedDecls) {
if (decl is LiteralModuleDecl) {
// The declaration is a literal module, so it has members and such that we need
@@ -176,7 +202,7 @@ namespace Microsoft.Dafny
Error(m.RefinementBaseName[0], "module ({0}) named as refinement base does not exist", Util.Comma(".", m.RefinementBaseName, x => x.val));
}
}
- literalDecl.Signature = RegisterTopLevelDecls(m);
+ literalDecl.Signature = RegisterTopLevelDecls(m, true);
literalDecl.Signature.Refines = refinedSig;
var sig = literalDecl.Signature;
// set up environment
@@ -191,7 +217,7 @@ namespace Microsoft.Dafny
if (ErrorCount == errorCount && !m.IsGhost) {
// compilation should only proceed if everything is good, including the signature (which preResolveErrorCount does not include);
var nw = (new Cloner()).CloneModuleDefinition(m, m.CompileName + "_Compile");
- var compileSig = RegisterTopLevelDecls(nw);
+ var compileSig = RegisterTopLevelDecls(nw, true);
compileSig.Refines = refinedSig;
sig.CompileSignature = compileSig;
useCompileSignatures = true;
@@ -216,11 +242,14 @@ namespace Microsoft.Dafny
ModuleSignature compileSig;
if (abs.CompilePath != null) {
if (ResolvePath(abs.CompileRoot, abs.CompilePath, out compileSig)) {
- if (refinementTransformer.CheckIsRefinement(compileSig, p, abs.CompilePath[0],
- "module " + Util.Comma(".", abs.CompilePath, x => x.val) + " must be a refinement of " + Util.Comma(".", abs.Path, x => x.val))) {
+ if (refinementTransformer.CheckIsRefinement(compileSig, p)) {
abs.Signature.CompileSignature = compileSig;
- abs.Signature.IsGhost = compileSig.IsGhost;
+ } else {
+ Error(abs.CompilePath[0],
+ "module " + Util.Comma(".", abs.CompilePath, x => x.val) + " must be a refinement of " + Util.Comma(".", abs.Path, x => x.val));
}
+ abs.Signature.IsGhost = compileSig.IsGhost;
+ // always keep the ghost information, to supress a spurious error message when the compile module isn't actually a refinement
}
}
} else {
@@ -282,10 +311,12 @@ namespace Microsoft.Dafny
return parent.TryLookup(name, out m);
} else return false;
}
- public bool TryLookupLocal(IToken name, out ModuleDecl m) {
+ public bool TryLookupIgnore(IToken name, out ModuleDecl m, ModuleDecl ignore) {
Contract.Requires(name != null);
- if (modules.TryGetValue(name.val, out m)) {
+ if (modules.TryGetValue(name.val, out m) && m != ignore) {
return true;
+ } else if (parent != null) {
+ return parent.TryLookup(name, out m);
} else return false;
}
public IEnumerable<ModuleDecl> ModuleList {
@@ -305,17 +336,17 @@ namespace Microsoft.Dafny
var subdecl = (LiteralModuleDecl)tld;
var subBindings = BindModuleNames(subdecl.ModuleDef, bindings);
if (!bindings.BindName(subdecl.Name, subdecl, subBindings)) {
- Error(subdecl.Module, "Duplicate module name: {0}", subdecl.Name);
+ Error(subdecl.tok, "Duplicate module name: {0}", subdecl.Name);
}
} else if (tld is AbstractModuleDecl) {
var subdecl = (AbstractModuleDecl)tld;
if (!bindings.BindName(subdecl.Name, subdecl, null)) {
- Error(subdecl.Module, "Duplicate module name: {0}", subdecl.Name);
+ Error(subdecl.tok, "Duplicate module name: {0}", subdecl.Name);
}
} else if (tld is AliasModuleDecl) {
var subdecl = (AliasModuleDecl)tld;
if (!bindings.BindName(subdecl.Name, subdecl, null)) {
- Error(subdecl.Module, "Duplicate module name: {0}", subdecl.Name);
+ Error(subdecl.tok, "Duplicate module name: {0}", subdecl.Name);
}
}
}
@@ -351,7 +382,7 @@ namespace Microsoft.Dafny
} else if (moduleDecl is AliasModuleDecl) {
var alias = moduleDecl as AliasModuleDecl;
ModuleDecl root;
- if (!bindings.TryLookup(alias.Path[0], out root))
+ if (!bindings.TryLookupIgnore(alias.Path[0], out root, alias))
Error(alias.tok, ModuleNotFoundErrorMessage(0, alias.Path));
else {
dependencies.AddEdge(moduleDecl, root);
@@ -404,20 +435,62 @@ namespace Microsoft.Dafny
info.IsGhost = m.IsGhost;
return info;
}
- ModuleSignature RegisterTopLevelDecls(ModuleDefinition moduleDef) {
+ ModuleSignature RegisterTopLevelDecls(ModuleDefinition moduleDef, bool useImports) {
Contract.Requires(moduleDef != null);
var sig = new ModuleSignature();
sig.ModuleDef = moduleDef;
sig.IsGhost = moduleDef.IsGhost;
List<TopLevelDecl> declarations = moduleDef.TopLevelDecls;
+ if (useImports) {
+ // First go through and add anything from the opened imports
+ foreach (var im in declarations) {
+ if (im is ModuleDecl && ((ModuleDecl)im).Opened) {
+ var s = ((ModuleDecl)im).Signature;
+ // classes:
+ foreach (var kv in s.TopLevels) {
+ TopLevelDecl d;
+ if (sig.TopLevels.TryGetValue(kv.Key, out d)) {
+ sig.TopLevels[kv.Key] = new AmbiguousTopLevelDecl(moduleDef, d, kv.Value);
+ } else {
+ sig.TopLevels.Add(kv.Key, kv.Value);
+ }
+ }
+ // constructors:
+ foreach (var kv in s.Ctors) {
+ Tuple<DatatypeCtor, bool> pair;
+ if (sig.Ctors.TryGetValue(kv.Key, out pair)) {
+ // mark it as a duplicate
+ sig.Ctors[kv.Key] = new Tuple<DatatypeCtor, bool>(pair.Item1, true);
+ } else {
+ // add new
+ sig.Ctors.Add(kv.Key, kv.Value);
+ }
+ }
+ // static members:
+ foreach (var kv in s.StaticMembers) {
+ MemberDecl md;
+ if (sig.StaticMembers.TryGetValue(kv.Key, out md)) {
+ sig.StaticMembers[kv.Key] = new AmbiguousMemberDecl(moduleDef, md, kv.Value);
+ } else {
+ // add new
+ sig.StaticMembers.Add(kv.Key, kv.Value);
+ }
+ }
+ }
+ }
+ }
+ // This is solely used to detect duplicates amongst the various e
+ Dictionary<string, TopLevelDecl> toplevels = new Dictionary<string, TopLevelDecl>();
+ // Now add the things present
foreach (TopLevelDecl d in declarations) {
Contract.Assert(d != null);
// register the class/datatype/module name
- if (sig.TopLevels.ContainsKey(d.Name)) {
+ if (toplevels.ContainsKey(d.Name)) {
Error(d, "Duplicate name of top-level declaration: {0}", d.Name);
} else {
- sig.TopLevels.Add(d.Name, d);
+ toplevels[d.Name] = d;
+ sig.TopLevels[d.Name] = d;
}
if (d is ModuleDecl) {
// nothing to do
@@ -445,8 +518,8 @@ namespace Microsoft.Dafny
cl.HasConstructor = hasConstructor;
if (cl.IsDefaultClass) {
foreach (MemberDecl m in cl.Members) {
- if (!sig.StaticMembers.ContainsKey(m.Name) && m.IsStatic && (m is Function || m is Method)) {
- sig.StaticMembers.Add(m.Name, m);
+ if (m.IsStatic && (m is Function || m is Method)) {
+ sig.StaticMembers[m.Name] = m;
}
}
}
@@ -513,7 +586,7 @@ namespace Microsoft.Dafny
foreach (var kv in p.TopLevels) {
mod.TopLevelDecls.Add(CloneDeclaration(kv.Value, mod, mods, Name));
}
- var sig = RegisterTopLevelDecls(mod);
+ var sig = RegisterTopLevelDecls(mod, false);
sig.Refines = p.Refines;
sig.CompileSignature = p;
sig.IsGhost = p.IsGhost;
@@ -552,14 +625,14 @@ namespace Microsoft.Dafny
return new LiteralModuleDecl(((LiteralModuleDecl)d).ModuleDef, m);
} else if (d is AliasModuleDecl) {
var a = (AliasModuleDecl)d;
- var alias = new AliasModuleDecl(a.Path, a.tok, m);
+ var alias = new AliasModuleDecl(a.Path, a.tok, m, a.Opened);
alias.ModuleReference = a.ModuleReference;
alias.Signature = a.Signature;
return alias;
} else if (d is AbstractModuleDecl) {
var abs = (AbstractModuleDecl)d;
var sig = MakeAbstractSignature(abs.OriginalSignature, Name + "." + abs.Name, abs.Height, mods);
- var a = new AbstractModuleDecl(abs.Path, abs.tok, m, abs.CompilePath);
+ var a = new AbstractModuleDecl(abs.Path, abs.tok, m, abs.CompilePath, abs.Opened);
a.Signature = sig;
a.OriginalSignature = abs.OriginalSignature;
return a;
@@ -633,7 +706,7 @@ namespace Microsoft.Dafny
if (f is Predicate) {
return new Predicate(tok, f.Name, f.IsStatic, isGhost, tps, f.OpenParen, formals,
- req, reads, ens, decreases, body, false, null, false);
+ req, reads, ens, decreases, body, Predicate.BodyOriginKind.OriginalOrInherited, null, false);
} else if (f is CoPredicate) {
return new CoPredicate(tok, f.Name, f.IsStatic, tps, f.OpenParen, formals,
req, reads, ens, body, null, false);
@@ -670,13 +743,13 @@ namespace Microsoft.Dafny
return new Specification<FrameExpression>(ee, null);
}
FrameExpression CloneFrameExpr(FrameExpression frame) {
- return new FrameExpression(CloneExpr(frame.E), frame.FieldName);
+ return new FrameExpression(frame.tok, CloneExpr(frame.E), frame.FieldName);
}
MaybeFreeExpression CloneMayBeFreeExpr(MaybeFreeExpression expr) {
return new MaybeFreeExpression(CloneExpr(expr.E), expr.IsFree);
}
BoundVar CloneBoundVar(BoundVar bv) {
- return new BoundVar((bv.tok), bv.Name, CloneType(bv.Type));
+ return new BoundVar(bv.tok, bv.Name, CloneType(bv.Type));
}
Expression CloneExpr(Expression expr) {
if (expr == null) {
@@ -684,37 +757,37 @@ namespace Microsoft.Dafny
} else if (expr is LiteralExpr) {
var e = (LiteralExpr)expr;
if (e.Value == null) {
- return new LiteralExpr((e.tok));
+ return new LiteralExpr(e.tok);
} else if (e.Value is bool) {
- return new LiteralExpr((e.tok), (bool)e.Value);
+ return new LiteralExpr(e.tok, (bool)e.Value);
} else {
- return new LiteralExpr((e.tok), (BigInteger)e.Value);
+ return new LiteralExpr(e.tok, (BigInteger)e.Value);
}
} else if (expr is ThisExpr) {
if (expr is ImplicitThisExpr) {
- return new ImplicitThisExpr((expr.tok));
+ return new ImplicitThisExpr(expr.tok);
} else {
- return new ThisExpr((expr.tok));
+ return new ThisExpr(expr.tok);
}
} else if (expr is IdentifierExpr) {
var e = (IdentifierExpr)expr;
- return new IdentifierExpr((e.tok), e.Name);
+ return new IdentifierExpr(e.tok, e.Name);
} else if (expr is DatatypeValue) {
var e = (DatatypeValue)expr;
- return new DatatypeValue((e.tok), e.DatatypeName, e.MemberName, e.Arguments.ConvertAll(CloneExpr));
+ return new DatatypeValue(e.tok, e.DatatypeName, e.MemberName, e.Arguments.ConvertAll(CloneExpr));
} else if (expr is DisplayExpression) {
DisplayExpression e = (DisplayExpression)expr;
if (expr is SetDisplayExpr) {
- return new SetDisplayExpr((e.tok), e.Elements.ConvertAll(CloneExpr));
+ return new SetDisplayExpr(e.tok, e.Elements.ConvertAll(CloneExpr));
} else if (expr is MultiSetDisplayExpr) {
- return new MultiSetDisplayExpr((e.tok), e.Elements.ConvertAll(CloneExpr));
+ return new MultiSetDisplayExpr(e.tok, e.Elements.ConvertAll(CloneExpr));
} else {
Contract.Assert(expr is SeqDisplayExpr);
- return new SeqDisplayExpr((e.tok), e.Elements.ConvertAll(CloneExpr));
+ return new SeqDisplayExpr(e.tok, e.Elements.ConvertAll(CloneExpr));
}
} else if (expr is MapDisplayExpr) {
@@ -723,54 +796,50 @@ namespace Microsoft.Dafny
foreach (ExpressionPair p in e.Elements) {
pp.Add(new ExpressionPair(CloneExpr(p.A), CloneExpr(p.B)));
}
- return new MapDisplayExpr((expr.tok), pp);
+ return new MapDisplayExpr(expr.tok, pp);
} else if (expr is ExprDotName) {
var e = (ExprDotName)expr;
- return new ExprDotName((e.tok), CloneExpr(e.Obj), e.SuffixName);
+ return new ExprDotName(e.tok, CloneExpr(e.Obj), e.SuffixName);
} else if (expr is FieldSelectExpr) {
var e = (FieldSelectExpr)expr;
- return new FieldSelectExpr((e.tok), CloneExpr(e.Obj), e.FieldName);
+ return new FieldSelectExpr(e.tok, CloneExpr(e.Obj), e.FieldName);
} else if (expr is SeqSelectExpr) {
var e = (SeqSelectExpr)expr;
- return new SeqSelectExpr((e.tok), e.SelectOne, CloneExpr(e.Seq), CloneExpr(e.E0), CloneExpr(e.E1));
+ return new SeqSelectExpr(e.tok, e.SelectOne, CloneExpr(e.Seq), CloneExpr(e.E0), CloneExpr(e.E1));
} else if (expr is MultiSelectExpr) {
var e = (MultiSelectExpr)expr;
- return new MultiSelectExpr((e.tok), CloneExpr(e.Array), e.Indices.ConvertAll(CloneExpr));
+ return new MultiSelectExpr(e.tok, CloneExpr(e.Array), e.Indices.ConvertAll(CloneExpr));
} else if (expr is SeqUpdateExpr) {
var e = (SeqUpdateExpr)expr;
- return new SeqUpdateExpr((e.tok), CloneExpr(e.Seq), CloneExpr(e.Index), CloneExpr(e.Value));
+ return new SeqUpdateExpr(e.tok, CloneExpr(e.Seq), CloneExpr(e.Index), CloneExpr(e.Value));
} else if (expr is FunctionCallExpr) {
var e = (FunctionCallExpr)expr;
- return new FunctionCallExpr((e.tok), e.Name, CloneExpr(e.Receiver), e.OpenParen == null ? null : (e.OpenParen), e.Args.ConvertAll(CloneExpr));
+ return new FunctionCallExpr(e.tok, e.Name, CloneExpr(e.Receiver), e.OpenParen == null ? null : (e.OpenParen), e.Args.ConvertAll(CloneExpr));
} else if (expr is OldExpr) {
var e = (OldExpr)expr;
- return new OldExpr((e.tok), CloneExpr(e.E));
+ return new OldExpr(e.tok, CloneExpr(e.E));
} else if (expr is MultiSetFormingExpr) {
var e = (MultiSetFormingExpr)expr;
- return new MultiSetFormingExpr((e.tok), CloneExpr(e.E));
+ return new MultiSetFormingExpr(e.tok, CloneExpr(e.E));
} else if (expr is FreshExpr) {
var e = (FreshExpr)expr;
- return new FreshExpr((e.tok), CloneExpr(e.E));
-
- } else if (expr is AllocatedExpr) {
- var e = (AllocatedExpr)expr;
- return new AllocatedExpr((e.tok), CloneExpr(e.E));
+ return new FreshExpr(e.tok, CloneExpr(e.E));
} else if (expr is UnaryExpr) {
var e = (UnaryExpr)expr;
- return new UnaryExpr((e.tok), e.Op, CloneExpr(e.E));
+ return new UnaryExpr(e.tok, e.Op, CloneExpr(e.E));
} else if (expr is BinaryExpr) {
var e = (BinaryExpr)expr;
- return new BinaryExpr((e.tok), e.Op, CloneExpr(e.E0), CloneExpr(e.E1));
+ return new BinaryExpr(e.tok, e.Op, CloneExpr(e.E0), CloneExpr(e.E1));
} else if (expr is ChainingExpression) {
var e = (ChainingExpression)expr;
@@ -778,11 +847,11 @@ namespace Microsoft.Dafny
} else if (expr is LetExpr) {
var e = (LetExpr)expr;
- return new LetExpr((e.tok), e.Vars.ConvertAll(CloneBoundVar), e.RHSs.ConvertAll(CloneExpr), CloneExpr(e.Body));
+ return new LetExpr(e.tok, e.Vars.ConvertAll(CloneBoundVar), e.RHSs.ConvertAll(CloneExpr), CloneExpr(e.Body));
} else if (expr is ComprehensionExpr) {
var e = (ComprehensionExpr)expr;
- var tk = (e.tok);
+ var tk = e.tok;
var bvs = e.BoundVars.ConvertAll(CloneBoundVar);
var range = CloneExpr(e.Range);
var term = CloneExpr(e.Term);
@@ -798,20 +867,20 @@ namespace Microsoft.Dafny
}
} else if (expr is WildcardExpr) {
- return new WildcardExpr((expr.tok));
+ return new WildcardExpr(expr.tok);
} else if (expr is PredicateExpr) {
var e = (PredicateExpr)expr;
if (e is AssertExpr) {
- return new AssertExpr((e.tok), CloneExpr(e.Guard), CloneExpr(e.Body));
+ return new AssertExpr(e.tok, CloneExpr(e.Guard), CloneExpr(e.Body));
} else {
Contract.Assert(e is AssumeExpr);
- return new AssumeExpr((e.tok), CloneExpr(e.Guard), CloneExpr(e.Body));
+ return new AssumeExpr(e.tok, CloneExpr(e.Guard), CloneExpr(e.Body));
}
} else if (expr is ITEExpr) {
var e = (ITEExpr)expr;
- return new ITEExpr((e.tok), CloneExpr(e.Test), CloneExpr(e.Thn), CloneExpr(e.Els));
+ return new ITEExpr(e.tok, CloneExpr(e.Test), CloneExpr(e.Thn), CloneExpr(e.Els));
} else if (expr is ParensExpression) {
var e = (ParensExpression)expr;
@@ -824,8 +893,8 @@ namespace Microsoft.Dafny
} else if (expr is MatchExpr) {
var e = (MatchExpr)expr;
- return new MatchExpr((e.tok), CloneExpr(e.Source),
- e.Cases.ConvertAll(c => new MatchCaseExpr((c.tok), c.Id, c.Arguments.ConvertAll(CloneBoundVar), CloneExpr(c.Body))));
+ return new MatchExpr(e.tok, CloneExpr(e.Source),
+ e.Cases.ConvertAll(c => new MatchCaseExpr(c.tok, c.Id, c.Arguments.ConvertAll(CloneBoundVar), CloneExpr(c.Body))));
} else {
Contract.Assert(false); throw new cce.UnreachableException(); // unexpected expression
@@ -853,7 +922,7 @@ namespace Microsoft.Dafny
foreach (TopLevelDecl d in declarations) {
Contract.Assert(d != null);
allTypeParameters.PushMarker();
- ResolveTypeParameters(d.TypeArgs, true, d);
+ ResolveTypeParameters(d.TypeArgs, true, d, true);
if (d is ArbitraryTypeDecl) {
// nothing to do
} else if (d is ClassDecl) {
@@ -889,24 +958,54 @@ namespace Microsoft.Dafny
foreach (TopLevelDecl d in declarations) {
Contract.Assert(d != null);
allTypeParameters.PushMarker();
- ResolveTypeParameters(d.TypeArgs, false, d);
+ ResolveTypeParameters(d.TypeArgs, false, d, true);
if (d is ClassDecl) {
ResolveClassMemberBodies((ClassDecl)d);
}
allTypeParameters.PopMarker();
}
- foreach (TopLevelDecl d in declarations) {
- if (d is ClassDecl) {
- foreach (var member in ((ClassDecl)d).Members) {
- if (member is Method) {
- var m = ((Method)member);
- if (m.Body != null)
- CheckTypeInference(m.Body);
- } else if (member is Function) {
- var f = (Function)member;
- if (f.Body != null)
- CheckTypeInference(f.Body);
+ if (ErrorCount == prevErrorCount) {
+ foreach (TopLevelDecl d in declarations) {
+ if (d is ClassDecl) {
+ foreach (var member in ((ClassDecl)d).Members) {
+ if (member is Method) {
+ var m = (Method)member;
+ if (m.Body != null) {
+ CheckTypeInference(m.Body);
+ bool tail = true;
+ bool hasTailRecursionPreference = Attributes.ContainsBool(m.Attributes, "tailrecursion", ref tail);
+ if (hasTailRecursionPreference && !tail) {
+ // the user specifically requested no tail recursion, so do nothing else
+ } else if (hasTailRecursionPreference && tail && m.IsGhost) {
+ Error(m.tok, "tail recursion can be specified only for methods that will be compiled, not for ghost methods");
+ } else {
+ var module = m.EnclosingClass.Module;
+ var sccSize = module.CallGraph.GetSCCSize(m);
+ if (hasTailRecursionPreference && 2 <= sccSize) {
+ Error(m.tok, "sorry, tail-call optimizations are not supported for mutually recursive methods");
+ } else if (hasTailRecursionPreference || sccSize == 1) {
+ CallStmt tailCall = null;
+ var status = CheckTailRecursive(m.Body.Body, m, ref tailCall, hasTailRecursionPreference);
+ if (status != TailRecursionStatus.NotTailRecursive) {
+ m.IsTailRecursive = true;
+ }
+ }
+ }
+ }
+ if (!m.IsTailRecursive && m.Body != null && Contract.Exists(m.Decreases.Expressions, e => e is WildcardExpr)) {
+ Error(m.Decreases.Expressions[0].tok, "'decreases *' is allowed only on tail-recursive methods");
+ }
+ } else if (member is Function) {
+ var f = (Function)member;
+ if (f.Body != null) {
+ CheckTypeInference(f.Body);
+ bool tail = true;
+ if (Attributes.ContainsBool(f.Attributes, "tailrecursion", ref tail) && tail) {
+ Error(f.tok, "sorry, tail-call functions are not supported");
+ }
+ }
+ }
}
}
}
@@ -1074,6 +1173,172 @@ namespace Microsoft.Dafny
}
}
+ enum TailRecursionStatus
+ {
+ NotTailRecursive, // contains code that makes the enclosing method body not tail recursive (in way that is supported)
+ CanBeFollowedByAnything, // the code just analyzed does not do any recursive calls
+ TailCallSpent, // the method body is tail recursive, provided that all code that follows it in the method body is ghost
+ }
+
+ /// <summary>
+ /// Checks if "stmts" can be considered tail recursive, and (provided "reportsError" is true) reports an error if not.
+ /// Note, the current implementation is rather conservative in its analysis; upon need, the
+ /// algorithm could be improved.
+ /// In the current implementation, "enclosingMethod" is not allowed to be a mutually recursive method.
+ ///
+ /// The incoming value of "tailCall" is not used, but it's nevertheless a 'ref' parameter to allow the
+ /// body to return the incoming value or to omit assignments to it.
+ /// If the return value is CanBeFollowedByAnything, "tailCall" is unchanged.
+ /// If the return value is TailCallSpent, "tailCall" shows one of the calls where the tail call was spent. (Note,
+ /// there could be several if the statements have branches.)
+ /// If the return value is NoTailRecursive, "tailCall" could be anything. In this case, an error
+ /// message has been reported (provided "reportsErrors" is true).
+ /// </summary>
+ TailRecursionStatus CheckTailRecursive(List<Statement> stmts, Method enclosingMethod, ref CallStmt tailCall, bool reportErrors) {
+ Contract.Requires(stmts != null);
+ var status = TailRecursionStatus.CanBeFollowedByAnything;
+ foreach (var s in stmts) {
+ if (!s.IsGhost) {
+ if (s is ReturnStmt && ((ReturnStmt)s).hiddenUpdate == null) {
+ return status;
+ }
+ if (status == TailRecursionStatus.TailCallSpent) {
+ // a tail call cannot be followed by non-ghost code
+ if (reportErrors) {
+ Error(tailCall.Tok, "this recursive call is not recognized as being tail recursive, because it is followed by non-ghost code");
+ }
+ return TailRecursionStatus.NotTailRecursive;
+ }
+ status = CheckTailRecursive(s, enclosingMethod, ref tailCall, reportErrors);
+ if (status == TailRecursionStatus.NotTailRecursive) {
+ return status;
+ }
+ }
+ }
+ return status;
+ }
+
+ /// <summary>
+ /// See CheckTailRecursive(List Statement, ...), including its description of "tailCall".
+ /// In the current implementation, "enclosingMethod" is not allowed to be a mutually recursive method.
+ /// </summary>
+ TailRecursionStatus CheckTailRecursive(Statement stmt, Method enclosingMethod, ref CallStmt tailCall, bool reportErrors) {
+ Contract.Requires(stmt != null && !stmt.IsGhost);
+ if (stmt is PrintStmt) {
+ } else if (stmt is BreakStmt) {
+ } else if (stmt is ReturnStmt) {
+ var s = (ReturnStmt)stmt;
+ if (s.hiddenUpdate != null) {
+ return CheckTailRecursive(s.hiddenUpdate, enclosingMethod, ref tailCall, reportErrors);
+ }
+ } else if (stmt is AssignStmt) {
+ } else if (stmt is VarDecl) {
+ } else if (stmt is CallStmt) {
+ var s = (CallStmt)stmt;
+ if (s.Method == enclosingMethod) {
+ // It's a recursive call. It can be considered a tail call only if the LHS of the call are the
+ // formal out-parameters of the method
+ for (int i = 0; i < s.Lhs.Count; i++) {
+ var formal = enclosingMethod.Outs[i];
+ if (!formal.IsGhost) {
+ var lhs = s.Lhs[i] as IdentifierExpr;
+ if (lhs != null && lhs.Var == formal) {
+ // all is good
+ } else {
+ if (reportErrors) {
+ Error(s.Tok, "the recursive call to '{0}' is not tail recursive because the actual out-parameter {1} is not the formal out-parameter '{2}'", s.Method.Name, i, formal.Name);
+ }
+ return TailRecursionStatus.NotTailRecursive;
+ }
+ }
+ }
+ tailCall = s;
+ return TailRecursionStatus.TailCallSpent;
+ }
+ } else if (stmt is BlockStmt) {
+ var s = (BlockStmt)stmt;
+ return CheckTailRecursive(s.Body, enclosingMethod, ref tailCall, reportErrors);
+ } else if (stmt is IfStmt) {
+ var s = (IfStmt)stmt;
+ var stThen = CheckTailRecursive(s.Thn, enclosingMethod, ref tailCall, reportErrors);
+ if (stThen == TailRecursionStatus.NotTailRecursive) {
+ return stThen;
+ }
+ var stElse = s.Els == null ? TailRecursionStatus.CanBeFollowedByAnything : CheckTailRecursive(s.Els, enclosingMethod, ref tailCall, reportErrors);
+ if (stElse == TailRecursionStatus.NotTailRecursive) {
+ return stElse;
+ } else if (stThen == TailRecursionStatus.TailCallSpent || stElse == TailRecursionStatus.TailCallSpent) {
+ return TailRecursionStatus.TailCallSpent;
+ }
+ } else if (stmt is AlternativeStmt) {
+ var s = (AlternativeStmt)stmt;
+ var status = TailRecursionStatus.CanBeFollowedByAnything;
+ foreach (var alt in s.Alternatives) {
+ var st = CheckTailRecursive(alt.Body, enclosingMethod, ref tailCall, reportErrors);
+ if (st == TailRecursionStatus.NotTailRecursive) {
+ return st;
+ } else if (st == TailRecursionStatus.TailCallSpent) {
+ status = st;
+ }
+ }
+ return status;
+ } else if (stmt is WhileStmt) {
+ var s = (WhileStmt)stmt;
+ var status = CheckTailRecursive(s.Body, enclosingMethod, ref tailCall, reportErrors);
+ if (status != TailRecursionStatus.CanBeFollowedByAnything) {
+ if (status == TailRecursionStatus.NotTailRecursive) {
+ // an error has already been reported
+ } else if (reportErrors) {
+ Error(tailCall.Tok, "a recursive call inside a loop is not recognized as being a tail call");
+ }
+ return TailRecursionStatus.NotTailRecursive;
+ }
+ } else if (stmt is AlternativeLoopStmt) {
+ var s = (AlternativeLoopStmt)stmt;
+ foreach (var alt in s.Alternatives) {
+ var status = CheckTailRecursive(alt.Body, enclosingMethod, ref tailCall, reportErrors);
+ if (status != TailRecursionStatus.CanBeFollowedByAnything) {
+ if (status == TailRecursionStatus.NotTailRecursive) {
+ // an error has already been reported
+ } else if (reportErrors) {
+ Error(tailCall.Tok, "a recursive call inside a loop is not recognized as being a tail call");
+ }
+ return TailRecursionStatus.NotTailRecursive;
+ }
+ }
+ } else if (stmt is ParallelStmt) {
+ var s = (ParallelStmt)stmt;
+ var status = CheckTailRecursive(s.Body, enclosingMethod, ref tailCall, reportErrors);
+ if (status != TailRecursionStatus.CanBeFollowedByAnything) {
+ if (status == TailRecursionStatus.NotTailRecursive) {
+ // an error has already been reported
+ } else if (reportErrors) {
+ Error(tailCall.Tok, "a recursive call inside a parallel statement is not a tail call");
+ }
+ return TailRecursionStatus.NotTailRecursive;
+ }
+ } else if (stmt is MatchStmt) {
+ var s = (MatchStmt)stmt;
+ var status = TailRecursionStatus.CanBeFollowedByAnything;
+ foreach (var kase in s.Cases) {
+ var st = CheckTailRecursive(kase.Body, enclosingMethod, ref tailCall, reportErrors);
+ if (st == TailRecursionStatus.NotTailRecursive) {
+ return st;
+ } else if (st == TailRecursionStatus.TailCallSpent) {
+ status = st;
+ }
+ }
+ return status;
+ } else if (stmt is AssignSuchThatStmt) {
+ } else if (stmt is ConcreteSyntaxStatement) {
+ var s = (ConcreteSyntaxStatement)stmt;
+ return CheckTailRecursive(s.ResolvedStatements, enclosingMethod, ref tailCall, reportErrors);
+ } else {
+ Contract.Assert(false); // unexpected statement type
+ }
+ return TailRecursionStatus.CanBeFollowedByAnything;
+ }
+
enum CallingPosition { Positive, Negative, Neither }
static CallingPosition Invert(CallingPosition cp) {
@@ -1129,6 +1394,16 @@ namespace Microsoft.Dafny
default:
break;
}
+ } else if (expr is MatchExpr) {
+ var e = (MatchExpr)expr;
+ CoPredicateChecks(e.Source, context, CallingPosition.Neither);
+ e.Cases.Iter(kase => CoPredicateChecks(kase.Body, context, cp));
+ return;
+ } else if (expr is ITEExpr) {
+ var e = (ITEExpr)expr;
+ CoPredicateChecks(e.Test, context, CallingPosition.Neither);
+ CoPredicateChecks(e.Thn, context, cp);
+ CoPredicateChecks(e.Els, context, cp);
} else if (expr is LetExpr) {
var e = (LetExpr)expr;
CoPredicateChecks(e.Body, context, cp);
@@ -1431,6 +1706,11 @@ namespace Microsoft.Dafny
var s = (ParallelStmt)stmt;
CheckTypeInference(s.Range);
CheckTypeInference(s.Body);
+ } else if (stmt is CalcStmt) {
+ // NadiaToDo: is this correct?
+ var s = (CalcStmt)stmt;
+ s.SubExpressions.Iter(e => CheckTypeInference(e));
+ s.SubStatements.Iter(CheckTypeInference);
} else if (stmt is MatchStmt) {
var s = (MatchStmt)stmt;
CheckTypeInference(s.Source);
@@ -1520,14 +1800,14 @@ namespace Microsoft.Dafny
} else if (member is Function) {
Function f = (Function)member;
allTypeParameters.PushMarker();
- ResolveTypeParameters(f.TypeArgs, true, f);
+ ResolveTypeParameters(f.TypeArgs, true, f, false);
ResolveFunctionSignature(f);
allTypeParameters.PopMarker();
} else if (member is Method) {
Method m = (Method)member;
allTypeParameters.PushMarker();
- ResolveTypeParameters(m.TypeArgs, true, m);
+ ResolveTypeParameters(m.TypeArgs, true, m, false);
ResolveMethodSignature(m);
allTypeParameters.PopMarker();
@@ -1556,14 +1836,14 @@ namespace Microsoft.Dafny
} else if (member is Function) {
Function f = (Function)member;
allTypeParameters.PushMarker();
- ResolveTypeParameters(f.TypeArgs, false, f);
+ ResolveTypeParameters(f.TypeArgs, false, f, false);
ResolveFunction(f);
allTypeParameters.PopMarker();
} else if (member is Method) {
Method m = (Method)member;
allTypeParameters.PushMarker();
- ResolveTypeParameters(m.TypeArgs, false, m);
+ ResolveTypeParameters(m.TypeArgs, false, m, false);
ResolveMethod(m);
allTypeParameters.PopMarker();
} else {
@@ -1832,16 +2112,18 @@ namespace Microsoft.Dafny
}
}
- void ResolveTypeParameters(List<TypeParameter/*!*/>/*!*/ tparams, bool emitErrors, TypeParameter.ParentType/*!*/ parent) {
+ void ResolveTypeParameters(List<TypeParameter/*!*/>/*!*/ tparams, bool emitErrors, TypeParameter.ParentType/*!*/ parent, bool isToplevel) {
Contract.Requires(tparams != null);
Contract.Requires(parent != null);
// push non-duplicated type parameter names
+ int index = 0;
foreach (TypeParameter tp in tparams) {
Contract.Assert(tp != null);
if (emitErrors) {
// we're seeing this TypeParameter for the first time
tp.Parent = parent;
+ tp.PositionalIndex = index;
}
if (!allTypeParameters.Push(tp.Name, tp) && emitErrors) {
Error(tp, "Duplicate type-parameter name: {0}", tp.Name);
@@ -2014,6 +2296,9 @@ namespace Microsoft.Dafny
foreach (Expression e in m.Decreases.Expressions) {
ResolveExpression(e, false);
// any type is fine
+ if (m.IsGhost && e is WildcardExpr) {
+ Error(e, "'decreases *' is not allowed on ghost methods");
+ }
}
// Add out-parameters to a new scope that will also include the outermost-level locals of the body
@@ -2366,7 +2651,7 @@ namespace Microsoft.Dafny
Contract.Requires(a.T == null && b.T == null);
Contract.Requires(a.OrderID <= b.OrderID);
//modifies a.T, b.T;
- Contract.Ensures(Contract.Result<bool>() || a.T != null || b.T != null);
+ Contract.Ensures(!Contract.Result<bool>() || a.T != null || b.T != null);
if (a is DatatypeProxy) {
if (b is DatatypeProxy) {
@@ -2800,7 +3085,7 @@ namespace Microsoft.Dafny
bool bodyMustBeSpecOnly = specContextOnly || (prevErrorCount == ErrorCount && UsesSpecFeatures(s.Range));
if (!bodyMustBeSpecOnly && prevErrorCount == ErrorCount) {
var missingBounds = new List<BoundVar>();
- s.Bounds = DiscoverBounds(s.Tok, s.BoundVars, s.Range, true, missingBounds);
+ s.Bounds = DiscoverBounds(s.Tok, s.BoundVars, s.Range, true, false, missingBounds);
if (missingBounds.Count != 0) {
bodyMustBeSpecOnly = true;
}
@@ -2844,6 +3129,46 @@ namespace Microsoft.Dafny
}
CheckParallelBodyRestrictions(s.Body, s.Kind);
}
+
+ } else if (stmt is CalcStmt) {
+ var prevErrorCount = ErrorCount;
+ CalcStmt s = (CalcStmt)stmt;
+ s.IsGhost = true;
+ Contract.Assert(s.Lines.Count > 0); // follows from the invariant of CalcStatement
+ var resOp = s.Op;
+ var e0 = s.Lines.First();
+ ResolveExpression(e0, true);
+ Contract.Assert(e0.Type != null); // follows from postcondition of ResolveExpression
+ for (int i = 1; i < s.Lines.Count; i++) {
+ var e1 = s.Lines[i];
+ ResolveExpression(e1, true);
+ Contract.Assert(e1.Type != null); // follows from postcondition of ResolveExpression
+ if (!UnifyTypes(e0.Type, e1.Type)) {
+ Error(e1, "all calculation steps must have the same type (got {0} after {1})", e1.Type, e0.Type);
+ } else {
+ BinaryExpr step;
+ var op = s.CustomOps[i - 1];
+ if (op == null) {
+ step = new BinaryExpr(e0.tok, s.Op, e0, e1); // Use calc-wide operator
+ } else {
+ step = new BinaryExpr(e0.tok, (BinaryExpr.Opcode)op, e0, e1); // Use custom line operator
+ Contract.Assert(CalcStmt.ResultOp(resOp, (BinaryExpr.Opcode)op) != null); // This was checked during parsing
+ resOp = (BinaryExpr.Opcode)CalcStmt.ResultOp(resOp, (BinaryExpr.Opcode)op);
+ }
+ ResolveExpression(step, true);
+ s.Steps.Add(step);
+ }
+ e0 = e1;
+ }
+ foreach (var h in s.Hints)
+ {
+ if (h != null) {
+ ResolveStatement(h, true, method);
+ }
+ }
+ s.Result = new BinaryExpr(s.Tok, resOp, s.Lines.First(), s.Lines.Last());
+ ResolveExpression(s.Result, true);
+ Contract.Assert(prevErrorCount != ErrorCount || s.Steps.Count == s.Hints.Count);
} else if (stmt is MatchStmt) {
MatchStmt s = (MatchStmt)stmt;
@@ -3102,6 +3427,7 @@ namespace Microsoft.Dafny
foreach (var a in s.ResolvedStatements) {
ResolveStatement(a, specContextOnly, method);
}
+ s.IsGhost = s.ResolvedStatements.TrueForAll(ss => ss.IsGhost);
}
bool ResolveAlternatives(List<GuardedAlternative> alternatives, bool specContextOnly, AlternativeLoopStmt loopToCatchBreaks, Method method) {
@@ -3441,6 +3767,10 @@ namespace Microsoft.Dafny
Contract.Assert(false); // unexpected kind
break;
}
+
+ } else if (stmt is CalcStmt) {
+ // cool
+ // NadiaTodo: ...I assume because it's always ghost
} else if (stmt is MatchStmt) {
var s = (MatchStmt)stmt;
@@ -3907,17 +4237,13 @@ namespace Microsoft.Dafny
// fine
} else if (UserDefinedType.DenotesClass(t) != null) {
// fine
+ } else if (t.IsDatatype) {
+ // fine, treat this as the datatype itself.
} else {
Error(expr, "the argument of a fresh expression must denote an object or a collection of objects (instead got {0})", e.E.Type);
}
expr.Type = Type.Bool;
- } else if (expr is AllocatedExpr) {
- AllocatedExpr e = (AllocatedExpr)expr;
- ResolveExpression(e.E, twoState);
- // e.E can be of any type
- expr.Type = Type.Bool;
-
} else if (expr is UnaryExpr) {
UnaryExpr e = (UnaryExpr)expr;
ResolveExpression(e.E, twoState);
@@ -4132,7 +4458,7 @@ namespace Microsoft.Dafny
if (prevErrorCount == ErrorCount) {
var missingBounds = new List<BoundVar>();
- e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.LogicalBody(), e is ExistsExpr, missingBounds);
+ e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.LogicalBody(), e is ExistsExpr, false, missingBounds);
if (missingBounds.Count != 0) {
// Report errors here about quantifications that depend on the allocation state.
var mb = missingBounds;
@@ -4176,7 +4502,7 @@ namespace Microsoft.Dafny
if (prevErrorCount == ErrorCount) {
var missingBounds = new List<BoundVar>();
- e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, missingBounds);
+ e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, false, missingBounds);
if (missingBounds.Count != 0) {
e.MissingBounds = missingBounds;
foreach (var bv in e.MissingBounds) {
@@ -4212,7 +4538,7 @@ namespace Microsoft.Dafny
if (prevErrorCount == ErrorCount) {
var missingBounds = new List<BoundVar>();
- e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, missingBounds);
+ e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, false, missingBounds);
if (missingBounds.Count != 0) {
e.MissingBounds = missingBounds;
foreach (var bv in e.MissingBounds) {
@@ -4517,10 +4843,6 @@ namespace Microsoft.Dafny
Error(expr, "fresh expressions are allowed only in specification and ghost contexts");
return;
- } else if (expr is AllocatedExpr) {
- Error(expr, "allocated expressions are allowed only in specification and ghost contexts");
- return;
-
} else if (expr is PredicateExpr) {
var e = (PredicateExpr)expr;
// ignore the guard
@@ -4657,9 +4979,8 @@ namespace Microsoft.Dafny
// - unamibugous type/module name (class, datatype, sub-module (including submodules of imports) or arbitrary-type)
// (if two imported types have the same name, an error message is produced here)
// - unambiguous constructor name of a datatype (if two constructors have the same name, an error message is produced here)
- // - imported module name
// - field, function or method name (with implicit receiver) (if the field is occluded by anything above, one can use an explicit "this.")
- // - static function or method in the enclosing module.
+ // - static function or method in the enclosing module, or its imports.
Expression r = null; // resolved version of e
CallRhs call = null;
@@ -4726,18 +5047,23 @@ namespace Microsoft.Dafny
|| moduleInfo.StaticMembers.TryGetValue(id.val, out member)) // try static members of the current module too.
{
// ----- field, function, or method
- Expression receiver;
- if (member.IsStatic) {
- receiver = new StaticReceiverExpr(id, (ClassDecl)member.EnclosingClass);
+ if (member is AmbiguousMemberDecl) {
+ Contract.Assert(member.IsStatic); // currently, static members of _default are the only thing which can be ambiguous.
+ Error(id, "The name {0} ambiguously refers to a static member in one of the modules {1}", id.val, ((AmbiguousMemberDecl)member).ModuleNames());
} else {
- if (!scope.AllowInstance) {
- Error(id, "'this' is not allowed in a 'static' context");
- // nevertheless, set "receiver" to a value so we can continue resolution
+ Expression receiver;
+ if (member.IsStatic) {
+ receiver = new StaticReceiverExpr(id, (ClassDecl)member.EnclosingClass);
+ } else {
+ if (!scope.AllowInstance) {
+ Error(id, "'this' is not allowed in a 'static' context");
+ // nevertheless, set "receiver" to a value so we can continue resolution
+ }
+ receiver = new ImplicitThisExpr(id);
+ receiver.Type = GetThisType(id, (ClassDecl)member.EnclosingClass); // resolve here
}
- receiver = new ImplicitThisExpr(id);
- receiver.Type = GetThisType(id, (ClassDecl)member.EnclosingClass); // resolve here
+ r = ResolveSuffix(receiver, e, 0, twoState, allowMethodCall, out call);
}
- r = ResolveSuffix(receiver, e, 0, twoState, allowMethodCall, out call);
} else {
Error(id, "unresolved identifier: {0}", id.val);
@@ -4924,34 +5250,52 @@ namespace Microsoft.Dafny
/// <summary>
/// Tries to find a bounded pool for each of the bound variables "bvars" of "expr". If this process
/// fails, then "null" is returned and the bound variables for which the process fails are added to "missingBounds".
+ /// If "returnAllBounds" is false, then:
+ /// -- at most one BoundedPool per variable is returned
+ /// -- every IntBoundedPool returned has both a lower and an upper bound
+ /// -- no SuperSetBoundedPool is returned
+ /// If "returnAllBounds" is true, then:
+ /// -- a variable may give rise to several BoundedPool's
+ /// -- IntBoundedPool bounds may have just one component
+ /// -- a non-null return value means that some bound were found for each variable (but, for example, perhaps one
+ /// variable only has lower bounds, no upper bounds)
/// Requires "expr" to be successfully resolved.
/// </summary>
- List<QuantifierExpr.BoundedPool> DiscoverBounds(IToken tok, List<BoundVar> bvars, Expression expr, bool polarity, List<BoundVar> missingBounds) {
+ public static List<ComprehensionExpr.BoundedPool> DiscoverBounds(IToken tok, List<BoundVar> bvars, Expression expr, bool polarity, bool returnAllBounds, List<BoundVar> missingBounds) {
Contract.Requires(tok != null);
Contract.Requires(bvars != null);
Contract.Requires(missingBounds != null);
Contract.Requires(expr != null);
Contract.Requires(expr.Type != null); // a sanity check (but not a complete proof) that "expr" has been resolved
Contract.Ensures(
- (Contract.Result<List<QuantifierExpr.BoundedPool>>() != null &&
- Contract.Result<List<QuantifierExpr.BoundedPool>>().Count == bvars.Count &&
+ (returnAllBounds && Contract.OldValue(missingBounds.Count) <= missingBounds.Count) ||
+ (!returnAllBounds &&
+ Contract.Result<List<ComprehensionExpr.BoundedPool>>() != null &&
+ Contract.Result<List<ComprehensionExpr.BoundedPool>>().Count == bvars.Count &&
Contract.OldValue(missingBounds.Count) == missingBounds.Count) ||
- (Contract.Result<List<QuantifierExpr.BoundedPool>>() == null &&
+ (!returnAllBounds &&
+ Contract.Result<List<ComprehensionExpr.BoundedPool>>() == null &&
Contract.OldValue(missingBounds.Count) < missingBounds.Count));
- var bounds = new List<QuantifierExpr.BoundedPool>();
+ var bounds = new List<ComprehensionExpr.BoundedPool>();
bool foundError = false;
for (int j = 0; j < bvars.Count; j++) {
var bv = bvars[j];
if (bv.Type is BoolType) {
// easy
- bounds.Add(new QuantifierExpr.BoolBoundedPool());
+ bounds.Add(new ComprehensionExpr.BoolBoundedPool());
} else if (bv.Type.IsIndDatatype && (bv.Type.AsIndDatatype).HasFinitePossibleValues) {
- bounds.Add(new QuantifierExpr.DatatypeBoundedPool(bv.Type.AsIndDatatype));
+ bounds.Add(new ComprehensionExpr.DatatypeBoundedPool(bv.Type.AsIndDatatype));
} else {
// Go through the conjuncts of the range expression to look for bounds.
Expression lowerBound = bv.Type is NatType ? new LiteralExpr(bv.tok, new BigInteger(0)) : null;
Expression upperBound = null;
+ bool foundBoundsForBv = false;
+ if (returnAllBounds && lowerBound != null) {
+ bounds.Add(new ComprehensionExpr.IntBoundedPool(lowerBound, upperBound));
+ lowerBound = null;
+ foundBoundsForBv = true;
+ }
foreach (var conjunct in NormalizedConjuncts(expr, polarity)) {
var c = conjunct as BinaryExpr;
if (c == null) {
@@ -4966,33 +5310,48 @@ namespace Microsoft.Dafny
switch (c.ResolvedOp) {
case BinaryExpr.ResolvedOpcode.InSet:
if (whereIsBv == 0) {
- bounds.Add(new QuantifierExpr.SetBoundedPool(e1));
- goto CHECK_NEXT_BOUND_VARIABLE;
+ bounds.Add(new ComprehensionExpr.SetBoundedPool(e1));
+ foundBoundsForBv = true;
+ if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
+ }
+ break;
+ case BinaryExpr.ResolvedOpcode.Subset:
+ if (returnAllBounds && whereIsBv == 1) {
+ bounds.Add(new ComprehensionExpr.SuperSetBoundedPool(e0));
+ foundBoundsForBv = true;
}
break;
case BinaryExpr.ResolvedOpcode.InMultiSet:
if (whereIsBv == 0) {
- bounds.Add(new QuantifierExpr.SetBoundedPool(e1));
- goto CHECK_NEXT_BOUND_VARIABLE;
+ bounds.Add(new ComprehensionExpr.SetBoundedPool(e1));
+ foundBoundsForBv = true;
+ if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
}
break;
case BinaryExpr.ResolvedOpcode.InSeq:
if (whereIsBv == 0) {
- bounds.Add(new QuantifierExpr.SeqBoundedPool(e1));
- goto CHECK_NEXT_BOUND_VARIABLE;
+ bounds.Add(new ComprehensionExpr.SeqBoundedPool(e1));
+ foundBoundsForBv = true;
+ if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
}
break;
case BinaryExpr.ResolvedOpcode.InMap:
if (whereIsBv == 0) {
- bounds.Add(new QuantifierExpr.SetBoundedPool(e1));
- goto CHECK_NEXT_BOUND_VARIABLE;
+ bounds.Add(new ComprehensionExpr.SetBoundedPool(e1));
+ foundBoundsForBv = true;
+ if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
}
break;
case BinaryExpr.ResolvedOpcode.EqCommon:
if (bv.Type is IntType) {
var otherOperand = whereIsBv == 0 ? e1 : e0;
- bounds.Add(new QuantifierExpr.IntBoundedPool(otherOperand, Plus(otherOperand, 1)));
- goto CHECK_NEXT_BOUND_VARIABLE;
+ bounds.Add(new ComprehensionExpr.IntBoundedPool(otherOperand, Plus(otherOperand, 1)));
+ foundBoundsForBv = true;
+ if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
+ } else if (returnAllBounds && bv.Type is SetType) {
+ var otherOperand = whereIsBv == 0 ? e1 : e0;
+ bounds.Add(new ComprehensionExpr.SuperSetBoundedPool(otherOperand));
+ foundBoundsForBv = true;
}
break;
case BinaryExpr.ResolvedOpcode.Gt:
@@ -5015,16 +5374,22 @@ namespace Microsoft.Dafny
default:
break;
}
- if (lowerBound != null && upperBound != null) {
- // we have found two halves
- bounds.Add(new QuantifierExpr.IntBoundedPool(lowerBound, upperBound));
- goto CHECK_NEXT_BOUND_VARIABLE;
+ if ((lowerBound != null && upperBound != null) ||
+ (returnAllBounds && (lowerBound != null || upperBound != null))) {
+ // we have found two halves (or, in the case of returnAllBounds, we have found some bound)
+ bounds.Add(new ComprehensionExpr.IntBoundedPool(lowerBound, upperBound));
+ lowerBound = null;
+ upperBound = null;
+ foundBoundsForBv = true;
+ if (!returnAllBounds) goto CHECK_NEXT_BOUND_VARIABLE;
}
CHECK_NEXT_CONJUNCT: ;
}
- // we have checked every conjunct in the range expression and still have not discovered good bounds
- missingBounds.Add(bv); // record failing bound variable
- foundError = true;
+ if (!foundBoundsForBv) {
+ // we have checked every conjunct in the range expression and still have not discovered good bounds
+ missingBounds.Add(bv); // record failing bound variable
+ foundError = true;
+ }
}
CHECK_NEXT_BOUND_VARIABLE: ; // should goto here only if the bound for the current variable has been discovered (otherwise, return with null from this method)
}
@@ -5039,7 +5404,7 @@ namespace Microsoft.Dafny
/// The other of "e0" and "e1" is an expression whose free variables are not among "boundVars[bvi..]".
/// Ensures that the resulting "e0" and "e1" are not ConcreteSyntaxExpression's.
/// </summary>
- int SanitizeForBoundDiscovery(List<BoundVar> boundVars, int bvi, BinaryExpr.ResolvedOpcode op, ref Expression e0, ref Expression e1) {
+ static int SanitizeForBoundDiscovery(List<BoundVar> boundVars, int bvi, BinaryExpr.ResolvedOpcode op, ref Expression e0, ref Expression e1) {
Contract.Requires(e0 != null);
Contract.Requires(e1 != null);
Contract.Requires(boundVars != null);
@@ -5163,7 +5528,7 @@ namespace Microsoft.Dafny
/// Requires "expr" to be successfully resolved.
/// Ensures that what is returned is not a ConcreteSyntaxExpression.
/// </summary>
- IEnumerable<Expression> NormalizedConjuncts(Expression expr, bool polarity) {
+ static IEnumerable<Expression> NormalizedConjuncts(Expression expr, bool polarity) {
// We consider 5 cases. To describe them, define P(e)=Conjuncts(e,true) and N(e)=Conjuncts(e,false).
// * X ==> Y is treated as a shorthand for !X || Y, and so is described by the remaining cases
// * X && Y P(_) = P(X),P(Y) and N(_) = !(X && Y)
@@ -5266,7 +5631,7 @@ namespace Microsoft.Dafny
}
}
- Expression Plus(Expression e, int n) {
+ public static Expression Plus(Expression e, int n) {
Contract.Requires(0 <= n);
var nn = new LiteralExpr(e.tok, n);
@@ -5277,12 +5642,23 @@ namespace Microsoft.Dafny
return p;
}
+ public static Expression Minus(Expression e, int n) {
+ Contract.Requires(0 <= n);
+
+ var nn = new LiteralExpr(e.tok, n);
+ nn.Type = Type.Int;
+ var p = new BinaryExpr(e.tok, BinaryExpr.Opcode.Sub, e, nn);
+ p.ResolvedOp = BinaryExpr.ResolvedOpcode.Sub;
+ p.Type = Type.Int;
+ return p;
+ }
+
/// <summary>
/// Returns the set of free variables in "expr".
/// Requires "expr" to be successfully resolved.
/// Ensures that the set returned has no aliases.
/// </summary>
- ISet<IVariable> FreeVariables(Expression expr) {
+ static ISet<IVariable> FreeVariables(Expression expr) {
Contract.Requires(expr != null);
Contract.Ensures(expr.Type != null);
@@ -5582,8 +5958,6 @@ namespace Microsoft.Dafny
return UsesSpecFeatures(e.E);
} else if (expr is FreshExpr) {
return true;
- } else if (expr is AllocatedExpr) {
- return true;
} else if (expr is UnaryExpr) {
UnaryExpr e = (UnaryExpr)expr;
return UsesSpecFeatures(e.E);
diff --git a/Source/Dafny/Rewriter.cs b/Source/Dafny/Rewriter.cs
index 4dea968e..c95be2f4 100644
--- a/Source/Dafny/Rewriter.cs
+++ b/Source/Dafny/Rewriter.cs
@@ -21,6 +21,15 @@ namespace Microsoft.Dafny
}
}
+ public class AutoGeneratedToken : TokenWrapper
+ {
+ public AutoGeneratedToken(Boogie.IToken wrappedToken)
+ : base(wrappedToken)
+ {
+ Contract.Requires(wrappedToken != null);
+ }
+ }
+
/// <summary>
/// AutoContracts is an experimental feature that will fill much of the dynamic-frames boilerplate
/// into a class. From the user's perspective, what needs to be done is simply:
@@ -75,7 +84,7 @@ namespace Microsoft.Dafny
// ...unless a field with that name is already present
if (!cl.Members.Exists(member => member is Field && member.Name == "Repr")) {
Type ty = new SetType(new ObjectType());
- cl.Members.Add(new Field(cl.tok, "Repr", true, ty, null));
+ cl.Members.Add(new Field(new AutoGeneratedToken(cl.tok), "Repr", true, ty, null));
}
foreach (var member in cl.Members) {
@@ -83,17 +92,17 @@ namespace Microsoft.Dafny
if (Attributes.ContainsBool(member.Attributes, "autocontracts", ref sayYes) && !sayYes) {
continue;
}
- var tok = member.tok;
+ Boogie.IToken tok = new AutoGeneratedToken(member.tok);
if (member is Function && member.Name == "Valid" && !member.IsStatic) {
var valid = (Function)member;
// reads this;
- valid.Reads.Add(new FrameExpression(new ThisExpr(tok), null));
+ valid.Reads.Add(new FrameExpression(tok, new ThisExpr(tok), null));
// reads Repr;
- valid.Reads.Add(new FrameExpression(new FieldSelectExpr(tok, new ImplicitThisExpr(tok), "Repr"), null));
+ valid.Reads.Add(new FrameExpression(tok, new FieldSelectExpr(tok, new ImplicitThisExpr(tok), "Repr"), null));
} else if (member is Constructor) {
var ctor = (Constructor)member;
// modifies this;
- ctor.Mod.Expressions.Add(new FrameExpression(new ImplicitThisExpr(tok), null));
+ ctor.Mod.Expressions.Add(new FrameExpression(tok, new ImplicitThisExpr(tok), null));
// ensures Valid();
ctor.Ens.Insert(0, new MaybeFreeExpression(new FunctionCallExpr(tok, "Valid", new ImplicitThisExpr(tok), tok, new List<Expression>())));
// ensures fresh(Repr - {this});
@@ -158,15 +167,16 @@ namespace Microsoft.Dafny
}
Contract.Assert(ReprField != null); // we expect there to be a "Repr" field, since we added one in PreResolve
- Type ty = new UserDefinedType(cl.tok, cl.Name, cl, new List<Type>());
- var self = new ThisExpr(cl.tok);
+ Boogie.IToken clTok = new AutoGeneratedToken(cl.tok);
+ Type ty = new UserDefinedType(clTok, cl.Name, cl, new List<Type>());
+ var self = new ThisExpr(clTok);
self.Type = ty;
- var implicitSelf = new ImplicitThisExpr(cl.tok);
+ var implicitSelf = new ImplicitThisExpr(clTok);
implicitSelf.Type = ty;
- var Repr = new FieldSelectExpr(cl.tok, implicitSelf, "Repr");
+ var Repr = new FieldSelectExpr(clTok, implicitSelf, "Repr");
Repr.Field = ReprField;
Repr.Type = ReprField.Type;
- var cNull = new LiteralExpr(cl.tok);
+ var cNull = new LiteralExpr(clTok);
cNull.Type = new ObjectType();
foreach (var member in cl.Members) {
@@ -174,7 +184,7 @@ namespace Microsoft.Dafny
if (Attributes.ContainsBool(member.Attributes, "autocontracts", ref sayYes) && !sayYes) {
continue;
}
- var tok = member.tok;
+ Boogie.IToken tok = new AutoGeneratedToken(member.tok);
if (member is Function && member.Name == "Valid" && !member.IsStatic) {
var valid = (Function)member;
if (valid.IsGhost && valid.ResultType is BoolType) {
@@ -230,7 +240,7 @@ namespace Microsoft.Dafny
var m = (Method)member;
if (Valid != null && !IsSimpleQueryMethod(m)) {
// modifies Repr;
- m.Mod.Expressions.Add(new FrameExpression(Repr, null));
+ m.Mod.Expressions.Add(new FrameExpression(Repr.tok, Repr, null));
// ensures Valid();
var valid = new FunctionCallExpr(tok, "Valid", implicitSelf, tok, new List<Expression>());
valid.Function = Valid;
diff --git a/Source/Dafny/Scanner.cs b/Source/Dafny/Scanner.cs
index 0433519d..936f699c 100644
--- a/Source/Dafny/Scanner.cs
+++ b/Source/Dafny/Scanner.cs
@@ -211,8 +211,8 @@ public class UTF8Buffer: Buffer {
public class Scanner {
const char EOL = '\n';
const int eofSym = 0; /* pdt */
- const int maxT = 109;
- const int noSym = 109;
+ const int maxT = 112;
+ const int noSym = 112;
[ContractInvariantMethod]
@@ -491,60 +491,63 @@ public class Scanner {
case "ghost": t.kind = 8; break;
case "module": t.kind = 9; break;
case "refines": t.kind = 10; break;
- case "as": t.kind = 13; break;
- case "class": t.kind = 15; break;
- case "static": t.kind = 16; break;
- case "datatype": t.kind = 17; break;
- case "codatatype": t.kind = 18; break;
- case "var": t.kind = 20; break;
- case "type": t.kind = 22; break;
- case "method": t.kind = 28; break;
- case "constructor": t.kind = 29; break;
- case "returns": t.kind = 30; break;
- case "modifies": t.kind = 32; break;
- case "free": t.kind = 33; break;
- case "requires": t.kind = 34; break;
- case "ensures": t.kind = 35; break;
- case "decreases": t.kind = 36; break;
- case "bool": t.kind = 37; break;
- case "nat": t.kind = 38; break;
- case "int": t.kind = 39; break;
- case "set": t.kind = 40; break;
- case "multiset": t.kind = 41; break;
- case "seq": t.kind = 42; break;
- case "map": t.kind = 43; break;
- case "object": t.kind = 44; break;
- case "function": t.kind = 45; break;
- case "predicate": t.kind = 46; break;
- case "copredicate": t.kind = 47; break;
- case "reads": t.kind = 48; break;
- case "label": t.kind = 51; break;
- case "break": t.kind = 52; break;
- case "where": t.kind = 53; break;
- case "return": t.kind = 55; break;
- case "assume": t.kind = 57; break;
- case "new": t.kind = 58; break;
- case "choose": t.kind = 61; break;
- case "if": t.kind = 62; break;
- case "else": t.kind = 63; break;
- case "case": t.kind = 64; break;
- case "while": t.kind = 66; break;
- case "invariant": t.kind = 67; break;
- case "match": t.kind = 68; break;
- case "assert": t.kind = 69; break;
- case "print": t.kind = 70; break;
- case "parallel": t.kind = 71; break;
- case "in": t.kind = 84; break;
- case "false": t.kind = 94; break;
- case "true": t.kind = 95; break;
- case "null": t.kind = 96; break;
- case "this": t.kind = 97; break;
- case "fresh": t.kind = 98; break;
- case "allocated": t.kind = 99; break;
- case "old": t.kind = 100; break;
- case "then": t.kind = 101; break;
- case "forall": t.kind = 103; break;
- case "exists": t.kind = 105; break;
+ case "import": t.kind = 11; break;
+ case "opened": t.kind = 12; break;
+ case "as": t.kind = 15; break;
+ case "default": t.kind = 16; break;
+ case "class": t.kind = 18; break;
+ case "static": t.kind = 19; break;
+ case "datatype": t.kind = 20; break;
+ case "codatatype": t.kind = 21; break;
+ case "var": t.kind = 23; break;
+ case "type": t.kind = 25; break;
+ case "method": t.kind = 31; break;
+ case "constructor": t.kind = 32; break;
+ case "returns": t.kind = 33; break;
+ case "modifies": t.kind = 35; break;
+ case "free": t.kind = 36; break;
+ case "requires": t.kind = 37; break;
+ case "ensures": t.kind = 38; break;
+ case "decreases": t.kind = 39; break;
+ case "bool": t.kind = 40; break;
+ case "nat": t.kind = 41; break;
+ case "int": t.kind = 42; break;
+ case "set": t.kind = 43; break;
+ case "multiset": t.kind = 44; break;
+ case "seq": t.kind = 45; break;
+ case "map": t.kind = 46; break;
+ case "object": t.kind = 47; break;
+ case "function": t.kind = 48; break;
+ case "predicate": t.kind = 49; break;
+ case "copredicate": t.kind = 50; break;
+ case "reads": t.kind = 51; break;
+ case "label": t.kind = 54; break;
+ case "break": t.kind = 55; break;
+ case "where": t.kind = 56; break;
+ case "return": t.kind = 58; break;
+ case "assume": t.kind = 60; break;
+ case "new": t.kind = 61; break;
+ case "choose": t.kind = 64; break;
+ case "if": t.kind = 65; break;
+ case "else": t.kind = 66; break;
+ case "case": t.kind = 67; break;
+ case "while": t.kind = 69; break;
+ case "invariant": t.kind = 70; break;
+ case "match": t.kind = 71; break;
+ case "assert": t.kind = 72; break;
+ case "print": t.kind = 73; break;
+ case "parallel": t.kind = 74; break;
+ case "calc": t.kind = 75; break;
+ case "in": t.kind = 88; break;
+ case "false": t.kind = 98; break;
+ case "true": t.kind = 99; break;
+ case "null": t.kind = 100; break;
+ case "this": t.kind = 101; break;
+ case "fresh": t.kind = 102; break;
+ case "old": t.kind = 103; break;
+ case "then": t.kind = 104; break;
+ case "forall": t.kind = 106; break;
+ case "exists": t.kind = 108; break;
default: break;
}
}
@@ -650,81 +653,81 @@ public class Scanner {
else if (ch >= '0' && ch <= '9') {AddCh(); goto case 18;}
else {t.kind = 3; break;}
case 19:
- {t.kind = 12; break;}
+ {t.kind = 14; break;}
case 20:
- {t.kind = 21; break;}
+ {t.kind = 24; break;}
case 21:
- {t.kind = 23; break;}
+ {t.kind = 26; break;}
case 22:
- {t.kind = 25; break;}
+ {t.kind = 28; break;}
case 23:
- {t.kind = 31; break;}
+ {t.kind = 34; break;}
case 24:
- {t.kind = 49; break;}
+ {t.kind = 52; break;}
case 25:
- {t.kind = 50; break;}
+ {t.kind = 53; break;}
case 26:
- {t.kind = 54; break;}
+ {t.kind = 57; break;}
case 27:
- {t.kind = 56; break;}
- case 28:
{t.kind = 59; break;}
+ case 28:
+ {t.kind = 62; break;}
case 29:
- {t.kind = 60; break;}
+ {t.kind = 63; break;}
case 30:
- {t.kind = 65; break;}
+ {t.kind = 68; break;}
case 31:
if (ch == '>') {AddCh(); goto case 32;}
else {goto case 0;}
case 32:
- {t.kind = 72; break;}
+ {t.kind = 76; break;}
case 33:
- {t.kind = 73; break;}
+ {t.kind = 77; break;}
case 34:
- {t.kind = 74; break;}
+ {t.kind = 78; break;}
case 35:
- {t.kind = 75; break;}
+ {t.kind = 79; break;}
case 36:
if (ch == '&') {AddCh(); goto case 37;}
else {goto case 0;}
case 37:
- {t.kind = 76; break;}
+ {t.kind = 80; break;}
case 38:
- {t.kind = 77; break;}
+ {t.kind = 81; break;}
case 39:
- {t.kind = 78; break;}
+ {t.kind = 82; break;}
case 40:
- {t.kind = 79; break;}
+ {t.kind = 83; break;}
case 41:
- {t.kind = 81; break;}
+ {t.kind = 85; break;}
case 42:
- {t.kind = 82; break;}
+ {t.kind = 86; break;}
case 43:
- {t.kind = 83; break;}
+ {t.kind = 87; break;}
case 44:
- {t.kind = 86; break;}
+ {t.kind = 90; break;}
case 45:
- {t.kind = 87; break;}
+ {t.kind = 91; break;}
case 46:
- {t.kind = 88; break;}
+ {t.kind = 92; break;}
case 47:
- {t.kind = 89; break;}
+ {t.kind = 93; break;}
case 48:
- {t.kind = 90; break;}
+ {t.kind = 94; break;}
case 49:
- {t.kind = 91; break;}
+ {t.kind = 95; break;}
case 50:
- {t.kind = 92; break;}
+ {t.kind = 96; break;}
case 51:
- {t.kind = 93; break;}
+ {t.kind = 97; break;}
case 52:
- {t.kind = 104; break;}
+ {t.kind = 107; break;}
case 53:
- {t.kind = 106; break;}
+ {t.kind = 109; break;}
case 54:
- {t.kind = 107; break;}
+ {t.kind = 110; break;}
case 55:
- {t.kind = 108; break;}
+ {t.kind = 111; break;}
case 56:
recEnd = pos; recKind = 5;
if (ch == '=') {AddCh(); goto case 26;}
@@ -732,43 +735,43 @@ public class Scanner {
else if (ch == ':') {AddCh(); goto case 54;}
else {t.kind = 5; break;}
case 57:
- recEnd = pos; recKind = 11;
+ recEnd = pos; recKind = 13;
if (ch == '=') {AddCh(); goto case 63;}
else if (ch == '>') {AddCh(); goto case 30;}
- else {t.kind = 11; break;}
+ else {t.kind = 13; break;}
case 58:
- recEnd = pos; recKind = 14;
+ recEnd = pos; recKind = 17;
if (ch == '.') {AddCh(); goto case 64;}
- else {t.kind = 14; break;}
+ else {t.kind = 17; break;}
case 59:
- recEnd = pos; recKind = 19;
+ recEnd = pos; recKind = 22;
if (ch == '|') {AddCh(); goto case 39;}
- else {t.kind = 19; break;}
+ else {t.kind = 22; break;}
case 60:
- recEnd = pos; recKind = 26;
+ recEnd = pos; recKind = 29;
if (ch == '=') {AddCh(); goto case 65;}
- else {t.kind = 26; break;}
+ else {t.kind = 29; break;}
case 61:
- recEnd = pos; recKind = 27;
+ recEnd = pos; recKind = 30;
if (ch == '=') {AddCh(); goto case 41;}
- else {t.kind = 27; break;}
+ else {t.kind = 30; break;}
case 62:
- recEnd = pos; recKind = 85;
+ recEnd = pos; recKind = 89;
if (ch == '=') {AddCh(); goto case 42;}
else if (ch == '!') {AddCh(); goto case 43;}
- else {t.kind = 85; break;}
+ else {t.kind = 89; break;}
case 63:
- recEnd = pos; recKind = 24;
+ recEnd = pos; recKind = 27;
if (ch == '>') {AddCh(); goto case 34;}
- else {t.kind = 24; break;}
+ else {t.kind = 27; break;}
case 64:
- recEnd = pos; recKind = 102;
+ recEnd = pos; recKind = 105;
if (ch == '.') {AddCh(); goto case 23;}
- else {t.kind = 102; break;}
+ else {t.kind = 105; break;}
case 65:
- recEnd = pos; recKind = 80;
+ recEnd = pos; recKind = 84;
if (ch == '=') {AddCh(); goto case 31;}
- else {t.kind = 80; break;}
+ else {t.kind = 84; break;}
}
t.val = new String(tval, 0, tlen);
diff --git a/Source/Dafny/Translator.cs b/Source/Dafny/Translator.cs
index 7839c5ad..9bd16f3f 100644
--- a/Source/Dafny/Translator.cs
+++ b/Source/Dafny/Translator.cs
@@ -355,9 +355,30 @@ namespace Microsoft.Dafny {
foreach(var c in fieldConstants.Values) {
sink.TopLevelDeclarations.Add(c);
}
+ HashSet<Tuple<string, string>> checkedMethods = new HashSet<Tuple<string, string>>();
+ HashSet<Tuple<string, string>> checkedFunctions = new HashSet<Tuple<string, string>>();
+ foreach (var t in program.TranslationTasks) {
+ if (t is MethodCheck) {
+ var m = (MethodCheck)t;
+ var id = new Tuple<string, string>(m.Refined.FullCompileName, m.Refining.FullCompileName);
+ if (!checkedMethods.Contains(id)) {
+ AddMethodRefinementCheck(m);
+ checkedMethods.Add(id);
+ }
+ } else if (t is FunctionCheck) {
+ var f = (FunctionCheck)t;
+ var id = new Tuple<string, string>(f.Refined.FullCompileName, f.Refining.FullCompileName);
+ if (!checkedFunctions.Contains(id)) {
+ AddFunctionRefinementCheck(f);
+ checkedFunctions.Add(id);
+ }
+ }
+ }
return sink;
}
+
+
void AddDatatype(DatatypeDecl dt)
{
Contract.Requires(dt != null);
@@ -1584,9 +1605,11 @@ namespace Microsoft.Dafny {
// check that postconditions hold
var ens = new Bpl.EnsuresSeq();
foreach (Expression p in f.Ens) {
- bool splitHappened; // we actually don't care
- foreach (var s in TrSplitExpr(p, etran, out splitHappened)) {
- if (!s.IsFree) {
+ var functionHeight = currentModule.CallGraph.GetSCCRepresentativeId(f);
+ var splits = new List<SplitExprInfo>();
+ bool splitHappened/*we actually don't care*/ = TrSplitExpr(p, splits, true, functionHeight, etran);
+ foreach (var s in splits) {
+ if (!s.IsFree && !RefinementToken.IsInherited(s.E.tok, currentModule)) {
ens.Add(Ensures(s.E.tok, s.IsFree, s.E, null, null));
}
}
@@ -1848,9 +1871,6 @@ namespace Microsoft.Dafny {
} else if (expr is FreshExpr) {
FreshExpr e = (FreshExpr)expr;
return IsTotal(e.E, etran);
- } else if (expr is AllocatedExpr) {
- AllocatedExpr e = (AllocatedExpr)expr;
- return IsTotal(e.E, etran);
} else if (expr is UnaryExpr) {
UnaryExpr e = (UnaryExpr)expr;
Bpl.Expr t = IsTotal(e.E, etran);
@@ -2021,9 +2041,6 @@ namespace Microsoft.Dafny {
} else if (expr is FreshExpr) {
FreshExpr e = (FreshExpr)expr;
return CanCallAssumption(e.E, etran);
- } else if (expr is AllocatedExpr) {
- AllocatedExpr e = (AllocatedExpr)expr;
- return CanCallAssumption(e.E, etran);
} else if (expr is UnaryExpr) {
UnaryExpr e = (UnaryExpr)expr;
Bpl.Expr t = CanCallAssumption(e.E, etran);
@@ -2139,6 +2156,20 @@ namespace Microsoft.Dafny {
}
}
+ Bpl.Expr BplOr(Bpl.Expr a, Bpl.Expr b) {
+ Contract.Requires(a != null);
+ Contract.Requires(b != null);
+ Contract.Ensures(Contract.Result<Bpl.Expr>() != null);
+
+ if (a == Bpl.Expr.False) {
+ return b;
+ } else if (b == Bpl.Expr.False) {
+ return a;
+ } else {
+ return Bpl.Expr.Or(a, b);
+ }
+ }
+
Bpl.Expr BplImp(Bpl.Expr a, Bpl.Expr b) {
Contract.Requires(a != null);
Contract.Requires(b != null);
@@ -2146,6 +2177,8 @@ namespace Microsoft.Dafny {
if (a == Bpl.Expr.True || b == Bpl.Expr.True) {
return b;
+ } else if (a == Bpl.Expr.False) {
+ return Bpl.Expr.True;
} else {
return Bpl.Expr.Imp(a, b);
}
@@ -2464,9 +2497,6 @@ namespace Microsoft.Dafny {
} else if (expr is FreshExpr) {
FreshExpr e = (FreshExpr)expr;
CheckWellformed(e.E, options, locals, builder, etran);
- } else if (expr is AllocatedExpr) {
- AllocatedExpr e = (AllocatedExpr)expr;
- CheckWellformed(e.E, options, locals, builder, etran);
} else if (expr is UnaryExpr) {
UnaryExpr e = (UnaryExpr)expr;
CheckWellformed(e.E, options, locals, builder, etran);
@@ -3021,25 +3051,8 @@ namespace Microsoft.Dafny {
ExpressionTranslator etran = new ExpressionTranslator(this, predef, m.tok);
- Bpl.VariableSeq inParams = new Bpl.VariableSeq();
- Bpl.VariableSeq outParams = new Bpl.VariableSeq();
- if (!m.IsStatic) {
- Bpl.Expr wh = Bpl.Expr.And(
- Bpl.Expr.Neq(new Bpl.IdentifierExpr(m.tok, "this", predef.RefType), predef.Null),
- etran.GoodRef(m.tok, new Bpl.IdentifierExpr(m.tok, "this", predef.RefType), Resolver.GetReceiverType(m.tok, m)));
- Bpl.Formal thVar = new Bpl.Formal(m.tok, new Bpl.TypedIdent(m.tok, "this", predef.RefType, wh), true);
- inParams.Add(thVar);
- }
- foreach (Formal p in m.Ins) {
- Bpl.Type varType = TrType(p.Type);
- Bpl.Expr wh = GetWhereClause(p.tok, new Bpl.IdentifierExpr(p.tok, p.UniqueName, varType), p.Type, etran);
- inParams.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.UniqueName, varType, wh), true));
- }
- foreach (Formal p in m.Outs) {
- Bpl.Type varType = TrType(p.Type);
- Bpl.Expr wh = GetWhereClause(p.tok, new Bpl.IdentifierExpr(p.tok, p.UniqueName, varType), p.Type, etran);
- outParams.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.UniqueName, varType, wh), false));
- }
+ Bpl.VariableSeq inParams, outParams;
+ GenerateMethodParameters(m, etran, out inParams, out outParams);
Bpl.RequiresSeq req = new Bpl.RequiresSeq();
Bpl.IdentifierExprSeq mod = new Bpl.IdentifierExprSeq();
@@ -3110,6 +3123,293 @@ namespace Microsoft.Dafny {
return proc;
}
+ private void AddMethodRefinementCheck(MethodCheck methodCheck) {
+
+ // First, we generate the declaration of the procedure. This procedure has the same
+ // pre and post conditions as the refined method. The body implementation will be a call
+ // to the refining method.
+ Method m = methodCheck.Refined;
+ currentModule = m.EnclosingClass.Module;
+ currentMethod = m;
+
+ ExpressionTranslator etran = new ExpressionTranslator(this, predef, m.tok);
+
+ Bpl.VariableSeq inParams, outParams;
+ GenerateMethodParameters(m, etran, out inParams, out outParams);
+
+ Bpl.RequiresSeq req = new Bpl.RequiresSeq();
+ Bpl.IdentifierExprSeq mod = new Bpl.IdentifierExprSeq();
+ Bpl.EnsuresSeq ens = new Bpl.EnsuresSeq();
+
+ Bpl.Expr context = Bpl.Expr.And(
+ Bpl.Expr.Eq(Bpl.Expr.Literal(m.EnclosingClass.Module.Height), etran.ModuleContextHeight()),
+ etran.InMethodContext());
+ req.Add(Requires(m.tok, true, context, null, null));
+
+ mod.Add((Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr);
+ mod.Add(etran.Tick());
+
+ foreach (MaybeFreeExpression p in m.Req) {
+ if ((p.IsFree && !DafnyOptions.O.DisallowSoundnessCheating)) {
+ req.Add(Requires(p.E.tok, true, etran.TrExpr(p.E), null, null));
+ } else {
+ bool splitHappened; // we actually don't care
+ foreach (var s in TrSplitExpr(p.E, etran, out splitHappened)) {
+ req.Add(Requires(s.E.tok, s.IsFree, s.E, null, null));
+ }
+ }
+ }
+ foreach (MaybeFreeExpression p in m.Ens) {
+ bool splitHappened; // we actually don't care
+ foreach (var s in TrSplitExpr(p.E, etran, out splitHappened)) {
+ ens.Add(Ensures(s.E.tok, s.IsFree, s.E, "Error: postcondition of refined method may be violated", null));
+ }
+ }
+ foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(m.tok, m.Mod.Expressions, etran.Old, etran, etran.Old)) {
+ ens.Add(Ensures(tri.tok, tri.IsFree, tri.Expr, tri.ErrorMessage, tri.Comment));
+ }
+
+ // Generate procedure, and then add it to the sink
+ Bpl.TypeVariableSeq typeParams = TrTypeParamDecls(m.TypeArgs);
+ string name = "CheckRefinement$$" + m.FullCompileName + "$" + methodCheck.Refining.FullCompileName;
+ Bpl.Procedure proc = new Bpl.Procedure(m.tok, name, typeParams, inParams, outParams, req, mod, new Bpl.EnsuresSeq());
+
+ sink.TopLevelDeclarations.Add(proc);
+
+
+ // Generate the implementation
+ typeParams = TrTypeParamDecls(m.TypeArgs);
+ inParams = Bpl.Formal.StripWhereClauses(proc.InParams);
+ outParams = Bpl.Formal.StripWhereClauses(proc.OutParams);
+
+ Bpl.StmtListBuilder builder = new Bpl.StmtListBuilder();
+ Bpl.VariableSeq localVariables = new Bpl.VariableSeq();
+ GenerateImplPrelude(m, inParams, outParams, builder, localVariables);
+
+ // Generate the call to the refining method
+ Method method = methodCheck.Refining;
+ Expression receiver = new ThisExpr(Token.NoToken);
+ Bpl.ExprSeq ins = new Bpl.ExprSeq();
+ if (!method.IsStatic) {
+ ins.Add(etran.TrExpr(receiver));
+ }
+
+ // Ideally, the modifies and decreases checks would be done after the precondition check,
+ // but Boogie doesn't give us a hook for that. So, we set up our own local variables here to
+ // store the actual parameters.
+ // Create a local variable for each formal parameter, and assign each actual parameter to the corresponding local
+ Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();
+ for (int i = 0; i < method.Ins.Count; i++) {
+ Formal p = method.Ins[i];
+ VarDecl local = new VarDecl(p.tok, p.Name + "#", p.Type, p.IsGhost);
+ local.type = local.OptionalType; // resolve local here
+ IdentifierExpr ie = new IdentifierExpr(local.Tok, local.UniqueName);
+ ie.Var = local; ie.Type = ie.Var.Type; // resolve ie here
+ substMap.Add(p, ie);
+ localVariables.Add(new Bpl.LocalVariable(local.Tok, new Bpl.TypedIdent(local.Tok, local.UniqueName, TrType(local.Type))));
+
+ Bpl.IdentifierExpr param = (Bpl.IdentifierExpr)etran.TrExpr(ie); // TODO: is this cast always justified?
+ var bActual = new Bpl.IdentifierExpr(Token.NoToken, m.Ins[i].UniqueName, TrType(m.Ins[i].Type));
+ Bpl.Cmd cmd = Bpl.Cmd.SimpleAssign(p.tok, param, etran.CondApplyUnbox(Token.NoToken, bActual, cce.NonNull( m.Ins[i].Type),p.Type));
+ builder.Add(cmd);
+ ins.Add(param);
+ }
+
+ // Check modifies clause of a subcall is a subset of the current frame.
+ CheckFrameSubset(method.tok, method.Mod.Expressions, receiver, substMap, etran, builder, "call may modify locations not in the refined method's modifies clause", null);
+
+ // Create variables to hold the output parameters of the call, so that appropriate unboxes can be introduced.
+ Bpl.IdentifierExprSeq outs = new Bpl.IdentifierExprSeq();
+ List<Bpl.IdentifierExpr> tmpOuts = new List<Bpl.IdentifierExpr>();
+ for (int i = 0; i < m.Outs.Count; i++) {
+ var bLhs = m.Outs[i];
+ if (!ExpressionTranslator.ModeledAsBoxType(method.Outs[i].Type) && ExpressionTranslator.ModeledAsBoxType(bLhs.Type)) {
+ // we need an Box
+ Bpl.LocalVariable var = new Bpl.LocalVariable(bLhs.tok, new Bpl.TypedIdent(bLhs.tok, "$tmp##" + otherTmpVarCount, TrType(method.Outs[i].Type)));
+ otherTmpVarCount++;
+ localVariables.Add(var);
+ Bpl.IdentifierExpr varIdE = new Bpl.IdentifierExpr(bLhs.tok, var.Name, TrType(method.Outs[i].Type));
+ tmpOuts.Add(varIdE);
+ outs.Add(varIdE);
+ } else {
+ tmpOuts.Add(null);
+ outs.Add(new Bpl.IdentifierExpr(Token.NoToken, bLhs.UniqueName, TrType(bLhs.Type)));
+ }
+ }
+
+ // Make the call
+ Bpl.CallCmd call = new Bpl.CallCmd(method.tok, method.FullCompileName, ins, outs);
+ builder.Add(call);
+
+ for (int i = 0; i < m.Outs.Count; i++) {
+ var bLhs = m.Outs[i];
+ var tmpVarIdE = tmpOuts[i];
+ if (tmpVarIdE != null) {
+ // e := Box(tmpVar);
+ Bpl.Cmd cmd = Bpl.Cmd.SimpleAssign(Token.NoToken, new Bpl.IdentifierExpr(Token.NoToken, bLhs.UniqueName, TrType(bLhs.Type)), FunctionCall(Token.NoToken, BuiltinFunction.Box, null, tmpVarIdE));
+ builder.Add(cmd);
+ }
+ }
+
+ foreach (MaybeFreeExpression p in m.Ens) {
+ bool splitHappened; // we actually don't care
+ foreach (var s in TrSplitExpr(p.E, etran, out splitHappened)) {
+ var assert = new Bpl.AssertCmd(method.tok, s.E, ErrorMessageAttribute(s.E.tok, "This is the postcondition that may not hold."));
+ assert.ErrorData = "Error: A postcondition of the refined method may not hold.";
+ builder.Add(assert);
+ }
+ }
+ Bpl.StmtList stmts = builder.Collect(method.tok); // this token is for the implict return, which should be for the refining method,
+ // as this is where the error is.
+
+ Bpl.Implementation impl = new Bpl.Implementation(m.tok, proc.Name,
+ typeParams, inParams, outParams,
+ localVariables, stmts, etran.TrAttributes(m.Attributes, null));
+ sink.TopLevelDeclarations.Add(impl);
+
+ // Clean up
+ currentModule = null;
+ currentMethod = null;
+ otherTmpVarCount = 0;
+ _tmpIEs.Clear();
+ }
+
+ private static QKeyValue ErrorMessageAttribute(IToken t, string error) {
+ var l = new List<object>(1);
+ l.Add(error);
+ return new QKeyValue(t, "msg", l, null);
+ }
+ private static QKeyValue ErrorMessageAttribute(IToken t, string error, QKeyValue qv) {
+ var l = new List<object>(1);
+ l.Add(error);
+ return new QKeyValue(t, "msg", l, qv);
+ }
+
+ private void AddFunctionRefinementCheck(FunctionCheck functionCheck) {
+ Contract.Requires(sink != null && predef != null);
+ Contract.Requires(currentModule == null);
+ Contract.Ensures(currentModule == null);
+
+ Function f = functionCheck.Refined;
+ Function function = functionCheck.Refining;
+ currentModule = function.EnclosingClass.Module;
+
+ ExpressionTranslator etran = new ExpressionTranslator(this, predef, f.tok);
+ // parameters of the procedure
+ Bpl.VariableSeq inParams = new Bpl.VariableSeq();
+ if (!f.IsStatic) {
+ Bpl.Expr wh = Bpl.Expr.And(
+ Bpl.Expr.Neq(new Bpl.IdentifierExpr(f.tok, "this", predef.RefType), predef.Null),
+ etran.GoodRef(f.tok, new Bpl.IdentifierExpr(f.tok, "this", predef.RefType), Resolver.GetReceiverType(f.tok, f)));
+ Bpl.Formal thVar = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, "this", predef.RefType, wh), true);
+ inParams.Add(thVar);
+ }
+ foreach (Formal p in f.Formals) {
+ Bpl.Type varType = TrType(p.Type);
+ Bpl.Expr wh = GetWhereClause(p.tok, new Bpl.IdentifierExpr(p.tok, p.UniqueName, varType), p.Type, etran);
+ inParams.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.UniqueName, varType, wh), true));
+ }
+ Bpl.TypeVariableSeq typeParams = TrTypeParamDecls(f.TypeArgs);
+ // the procedure itself
+ Bpl.RequiresSeq req = new Bpl.RequiresSeq();
+ // free requires mh == ModuleContextHeight && fh == FunctionContextHeight;
+ ModuleDefinition mod = function.EnclosingClass.Module;
+ Bpl.Expr context = Bpl.Expr.And(
+ Bpl.Expr.Eq(Bpl.Expr.Literal(mod.Height), etran.ModuleContextHeight()),
+ Bpl.Expr.Eq(Bpl.Expr.Literal(mod.CallGraph.GetSCCRepresentativeId(function)), etran.FunctionContextHeight()));
+ req.Add(Requires(f.tok, true, context, null, null));
+
+ foreach (Expression p in f.Req) {
+ req.Add(Requires(p.tok, true, etran.TrExpr(p), null, null));
+ }
+
+ // check that postconditions hold
+ var ens = new Bpl.EnsuresSeq();
+ foreach (Expression p in f.Ens) {
+ bool splitHappened; // we actually don't care
+ foreach (var s in TrSplitExpr(p, etran, out splitHappened)) {
+ if (!s.IsFree) {
+ ens.Add(Ensures(s.E.tok, s.IsFree, s.E, null, null));
+ }
+ }
+ }
+ Bpl.Procedure proc = new Bpl.Procedure(function.tok, "CheckIsRefinement$$" + f.FullCompileName + "$" + functionCheck.Refining.FullCompileName, typeParams, inParams, new Bpl.VariableSeq(),
+ req, new Bpl.IdentifierExprSeq(), ens, etran.TrAttributes(f.Attributes, null));
+ sink.TopLevelDeclarations.Add(proc);
+
+ VariableSeq implInParams = Bpl.Formal.StripWhereClauses(proc.InParams);
+ Bpl.VariableSeq locals = new Bpl.VariableSeq();
+ Bpl.StmtListBuilder builder = new Bpl.StmtListBuilder();
+
+ Bpl.FunctionCall funcOriginal = new Bpl.FunctionCall(new Bpl.IdentifierExpr(f.tok, f.FullCompileName, TrType(f.ResultType)));
+ Bpl.FunctionCall funcRefining = new Bpl.FunctionCall(new Bpl.IdentifierExpr(functionCheck.Refining.tok, functionCheck.Refining.FullCompileName, TrType(f.ResultType)));
+ Bpl.ExprSeq args = new Bpl.ExprSeq();
+ args.Add(etran.HeapExpr);
+ foreach (Variable p in implInParams) {
+ args.Add(new Bpl.IdentifierExpr(f.tok, p));
+ }
+ Bpl.Expr funcAppl = new Bpl.NAryExpr(f.tok, funcOriginal, args);
+ Bpl.Expr funcAppl2 = new Bpl.NAryExpr(f.tok, funcRefining, args);
+
+ Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();
+ for (int i = 0; i < function.Formals.Count; i++) {
+ Formal p = function.Formals[i];
+ IdentifierExpr ie = new IdentifierExpr(f.Formals[i].tok, f.Formals[i].UniqueName);
+ ie.Var = f.Formals[i]; ie.Type = ie.Var.Type; // resolve ie here
+ substMap.Add(p, ie);
+ }
+ // add canCall
+ Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(Token.NoToken, function.FullCompileName + "#canCall", Bpl.Type.Bool);
+ Bpl.Expr canCall = new Bpl.NAryExpr(Token.NoToken, new Bpl.FunctionCall(canCallFuncID), args);
+ builder.Add(new AssumeCmd(function.tok, canCall));
+
+ // check that the preconditions for the call hold
+ foreach (Expression p in function.Req) {
+ Expression precond = Substitute(p, new ThisExpr(Token.NoToken), substMap);
+ var assert = new AssertCmd(p.tok, etran.TrExpr(precond));
+ assert.ErrorData = "Error: the refining function is not allowed to add preconditions";
+ builder.Add(assert);
+ }
+ builder.Add(new AssumeCmd(f.tok, Bpl.Expr.Eq(funcAppl, funcAppl2)));
+
+ foreach (Expression p in f.Ens) {
+ var s = new FunctionCallSubstituter(new ThisExpr(Token.NoToken), substMap, f, function);
+ Expression precond = s.Substitute(p);
+ var assert = new AssertCmd(p.tok, etran.TrExpr(precond));
+ assert.ErrorData = "Error: A postcondition of the refined function may not hold";
+ builder.Add(assert);
+ }
+ Bpl.Implementation impl = new Bpl.Implementation(function.tok, proc.Name,
+ typeParams, implInParams, new Bpl.VariableSeq(),
+ locals, builder.Collect(function.tok));
+ sink.TopLevelDeclarations.Add(impl);
+
+ Contract.Assert(currentModule == function.EnclosingClass.Module);
+ currentModule = null;
+ }
+
+ private void GenerateMethodParameters(Method m, ExpressionTranslator etran, out Bpl.VariableSeq inParams, out Bpl.VariableSeq outParams) {
+ inParams = new Bpl.VariableSeq();
+ outParams = new Bpl.VariableSeq();
+ if (!m.IsStatic) {
+ Bpl.Expr wh = Bpl.Expr.And(
+ Bpl.Expr.Neq(new Bpl.IdentifierExpr(m.tok, "this", predef.RefType), predef.Null),
+ etran.GoodRef(m.tok, new Bpl.IdentifierExpr(m.tok, "this", predef.RefType), Resolver.GetReceiverType(m.tok, m)));
+ Bpl.Formal thVar = new Bpl.Formal(m.tok, new Bpl.TypedIdent(m.tok, "this", predef.RefType, wh), true);
+ inParams.Add(thVar);
+ }
+ foreach (Formal p in m.Ins) {
+ Bpl.Type varType = TrType(p.Type);
+ Bpl.Expr wh = GetWhereClause(p.tok, new Bpl.IdentifierExpr(p.tok, p.UniqueName, varType), p.Type, etran);
+ inParams.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.UniqueName, varType, wh), true));
+ }
+ foreach (Formal p in m.Outs) {
+ Bpl.Type varType = TrType(p.Type);
+ Bpl.Expr wh = GetWhereClause(p.tok, new Bpl.IdentifierExpr(p.tok, p.UniqueName, varType), p.Type, etran);
+ outParams.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.UniqueName, varType, wh), false));
+ }
+ }
+
class BoilerplateTriple { // a triple that is now a quintuple
[ContractInvariantMethod]
void ObjectInvariant() {
@@ -3313,7 +3613,7 @@ namespace Microsoft.Dafny {
Contract.Requires(errorMessage != null);
Contract.Ensures(Contract.Result<Bpl.PredicateCmd>() != null);
- if (RefinementToken.IsInherited(refinesToken, currentModule)) {
+ if (RefinementToken.IsInherited(refinesToken, currentModule) && (currentMethod == null || !currentMethod.MustReverify)) {
// produce an assume instead
return new Bpl.AssumeCmd(tok, condition);
} else {
@@ -3332,7 +3632,7 @@ namespace Microsoft.Dafny {
Contract.Requires(condition != null);
Contract.Ensures(Contract.Result<Bpl.PredicateCmd>() != null);
- if (RefinementToken.IsInherited(refinesTok, currentModule)) {
+ if (RefinementToken.IsInherited(refinesTok, currentModule) && (currentMethod == null || !currentMethod.MustReverify)) {
// produce a "skip" instead
return new Bpl.AssumeCmd(tok, Bpl.Expr.True);
} else {
@@ -3352,7 +3652,7 @@ namespace Microsoft.Dafny {
Contract.Requires(condition != null);
Contract.Ensures(Contract.Result<Bpl.PredicateCmd>() != null);
- if (RefinementToken.IsInherited(tok, currentModule)) {
+ if (RefinementToken.IsInherited(tok, currentModule) && (currentMethod == null || !currentMethod.MustReverify)) {
// produce an assume instead
return new Bpl.AssumeCmd(tok, condition, kv);
} else {
@@ -3509,11 +3809,19 @@ namespace Microsoft.Dafny {
Contract.Assume(false); // unexpected case
}
}
- var bvs = new VariableSeq();
- var typeAntecedent = etran.TrBoundVariables(bvars, bvs);
- var substE = etran.TrExpr(Substitute(s.Expr, null, substMap));
- var ex = new Bpl.ExistsExpr(s.Tok, bvs, BplAnd(typeAntecedent, substE));
- builder.Add(Assert(s.Tok, ex, "cannot establish the existence of LHS values that satisfy the such-that predicate"));
+
+ List<Tuple<List<BoundVar>, Expression>> partialGuesses = GeneratePartialGuesses(bvars, Substitute(s.Expr, null, substMap));
+ Bpl.Expr w = Bpl.Expr.False;
+ foreach (var tup in partialGuesses) {
+ var body = etran.TrExpr(tup.Item2);
+ if (tup.Item1.Count != 0) {
+ var bvs = new VariableSeq();
+ var typeAntecedent = etran.TrBoundVariables(tup.Item1, bvs);
+ body = new Bpl.ExistsExpr(s.Tok, bvs, BplAnd(typeAntecedent, body));
+ }
+ w = BplOr(body, w);
+ }
+ builder.Add(Assert(s.Tok, w, "cannot establish the existence of LHS values that satisfy the such-that predicate"));
}
// End by doing the assume
builder.Add(new Bpl.AssumeCmd(s.Tok, etran.TrExpr(s.Expr)));
@@ -3675,6 +3983,52 @@ namespace Microsoft.Dafny {
Contract.Assert(false); // unexpected kind
}
+ } else if (stmt is CalcStmt) {
+ /* Translate into:
+ if (*) {
+ hint0;
+ assert t0 op t1;
+ assume false;
+ } else if ...
+ } else {
+ hint<n-1>;
+ assert t<n-1> op tn;
+ assume false;
+ }
+ assume t0 op tn;
+ */
+ var s = (CalcStmt)stmt;
+ Contract.Assert(s.Steps.Count == s.Hints.Count); // established by the resolver
+ AddComment(builder, stmt, "calc statement");
+ // NadiaTodo: check well-formedness of lines
+ if (s.Steps.Count > 0) {
+ Bpl.IfCmd ifCmd = null;
+ Bpl.StmtList els = null;
+
+ for (int i = s.Steps.Count; 0 <= --i; ) {
+ var b = new Bpl.StmtListBuilder();
+ var h = s.Hints[i];
+ if (h != null) {
+ TrStmt(h, b, locals, etran);
+ }
+ b.Add(Assert(s.Lines[i + 1].tok, etran.TrExpr(s.Steps[i]), "this calculation step might not hold"));
+ b.Add(new Bpl.AssumeCmd(s.Tok, Bpl.Expr.False));
+ if (i == s.Steps.Count - 1) {
+ // first iteration (last step)
+ els = b.Collect(s.Tok);
+ } else {
+ ifCmd = new Bpl.IfCmd(s.Tok, null, b.Collect(s.Tok), ifCmd, els);
+ els = null;
+ }
+ }
+ if (ifCmd == null) {
+ // single step: generate an if without else parts
+ ifCmd = new Bpl.IfCmd(s.Tok, null, els, null, null);
+ }
+ builder.Add(ifCmd);
+ builder.Add(new Bpl.AssumeCmd(s.Tok, etran.TrExpr(s.Result)));
+ }
+
} else if (stmt is MatchStmt) {
var s = (MatchStmt)stmt;
TrStmt_CheckWellformed(s.Source, builder, locals, etran, true);
@@ -3743,6 +4097,103 @@ namespace Microsoft.Dafny {
}
}
+ List<Tuple<List<BoundVar>, Expression>> GeneratePartialGuesses(List<BoundVar> bvars, Expression expression) {
+ if (bvars.Count == 0) {
+ var tup = new Tuple<List<BoundVar>, Expression>(new List<BoundVar>(), expression);
+ return new List<Tuple<List<BoundVar>, Expression>>() { tup };
+ }
+ var result = new List<Tuple<List<BoundVar>, Expression>>();
+ var x = bvars[0];
+ var otherBvars = bvars.GetRange(1, bvars.Count - 1);
+ foreach (var tup in GeneratePartialGuesses(otherBvars, expression)) {
+ // in the special case that x does not even occur in expression, we can just ignore x
+ if (!ContainsFreeVariable(tup.Item2, false, x)) {
+ result.Add(tup);
+ continue;
+ }
+ // one possible result is to quantify over all the variables
+ var vs = new List<BoundVar>() { x };
+ vs.AddRange(tup.Item1);
+ result.Add(new Tuple<List<BoundVar>, Expression>(vs, tup.Item2));
+ // other possibilities involve guessing a value for x
+ foreach (var guess in GuessWitnesses(x, tup.Item2)) {
+ var substMap = new Dictionary<IVariable, Expression>();
+ substMap.Add(x, guess);
+ result.Add(new Tuple<List<BoundVar>, Expression>(tup.Item1, Substitute(tup.Item2, null, substMap)));
+ }
+ }
+ return result;
+ }
+
+ IEnumerable<Expression> GuessWitnesses(BoundVar x, Expression expr) {
+ Contract.Requires(x != null);
+ Contract.Requires(expr != null);
+ var lookForBounds = false;
+ if (x.Type is BoolType) {
+ var lit = new LiteralExpr(x.tok, false);
+ lit.Type = Type.Bool; // resolve here
+ yield return lit;
+ lit = new LiteralExpr(x.tok, true);
+ lit.Type = Type.Bool; // resolve here
+ yield return lit;
+ } else if (x.Type.IsRefType) {
+ var lit = new LiteralExpr(x.tok);
+ lit.Type = x.Type;
+ yield return lit;
+ } else if (x.Type.IsIndDatatype) {
+ var dt = x.Type.AsIndDatatype;
+ Expression zero = Zero(x.tok, x.Type);
+ if (zero != null) {
+ yield return zero;
+ }
+ } else if (x.Type is SetType) {
+ var empty = new SetDisplayExpr(x.tok, new List<Expression>());
+ empty.Type = x.Type;
+ yield return empty;
+ lookForBounds = true;
+ } else if (x.Type is MultiSetType) {
+ var empty = new MultiSetDisplayExpr(x.tok, new List<Expression>());
+ empty.Type = x.Type;
+ yield return empty;
+ lookForBounds = true;
+ } else if (x.Type is SeqType) {
+ var empty = new SeqDisplayExpr(x.tok, new List<Expression>());
+ empty.Type = x.Type;
+ yield return empty;
+ lookForBounds = true;
+ } else if (x.Type is IntType) {
+ var lit = new LiteralExpr(x.tok, 0);
+ lit.Type = Type.Int; // resolve here
+ yield return lit;
+ lookForBounds = true;
+ }
+ if (lookForBounds) {
+ var missingBounds = new List<BoundVar>();
+ var bounds = Resolver.DiscoverBounds(x.tok, new List<BoundVar>() { x }, expr, true, true, missingBounds);
+ if (missingBounds.Count == 0) {
+ foreach (var bound in bounds) {
+ if (bound is ComprehensionExpr.IntBoundedPool) {
+ var bnd = (ComprehensionExpr.IntBoundedPool)bound;
+ if (bnd.LowerBound != null) yield return bnd.LowerBound;
+ if (bnd.UpperBound != null) yield return Resolver.Minus(bnd.UpperBound, 1);
+ } else if (bound is ComprehensionExpr.SuperSetBoundedPool) {
+ var bnd = (ComprehensionExpr.SuperSetBoundedPool)bound;
+ yield return bnd.LowerBound;
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Return a zero-equivalent value for "typ", or return null (for any reason whatsoever).
+ /// </summary>
+ Expression Zero(Bpl.IToken tok, Type typ) {
+ Contract.Requires(tok != null);
+ Contract.Requires(typ != null);
+ return null; // TODO: this can be improved
+ }
+
void TrParallelAssign(ParallelStmt s, AssignStmt s0,
Bpl.StmtListBuilder definedness, Bpl.StmtListBuilder updater, Bpl.VariableSeq locals, ExpressionTranslator etran) {
// The statement:
@@ -4480,7 +4931,7 @@ namespace Microsoft.Dafny {
// Make the call
string name;
- if (RefinementToken.IsInherited(method.tok, currentModule)) {
+ if (RefinementToken.IsInherited(method.tok, currentModule) && (currentMethod == null || !currentMethod.MustReverify)) {
name = string.Format("RefinementCall_{0}$${1}", currentModule.Name, method.FullCompileName);
} else {
name = method.FullCompileName;
@@ -4522,12 +4973,10 @@ namespace Microsoft.Dafny {
}
static Expression CreateIntSub(IToken tok, Expression e0, Expression e1)
- {
+ {
Contract.Requires(tok != null);
Contract.Requires(e0 != null);
Contract.Requires(e1 != null);
-
-
Contract.Requires(e0.Type is IntType && e1.Type is IntType);
Contract.Ensures(Contract.Result<Expression>() != null);
BinaryExpr s = new BinaryExpr(tok, BinaryExpr.Opcode.Sub, e0, e1);
@@ -4537,7 +4986,7 @@ namespace Microsoft.Dafny {
}
static Expression CreateIntITE(IToken tok, Expression test, Expression e0, Expression e1)
- {
+ {
Contract.Requires(tok != null);
Contract.Requires(test != null);
Contract.Requires(e0 != null);
@@ -4551,7 +5000,7 @@ namespace Microsoft.Dafny {
}
public IEnumerable<Expression> Conjuncts(Expression expr)
- {
+ {
Contract.Requires(expr != null);
Contract.Requires(expr.Type is BoolType);
Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<Expression>>()));
@@ -4639,6 +5088,11 @@ namespace Microsoft.Dafny {
// order where elements from different Dafny types are incomparable. Thus, as an optimization below, if two
// components from different types are compared, the answer is taken to be false.
+ if (Contract.Exists(calleeDecreases, e => e is WildcardExpr)) {
+ // no check needed
+ return;
+ }
+
int N = Math.Min(contextDecreases.Count, calleeDecreases.Count);
List<IToken> toks = new List<IToken>();
List<Type> types = new List<Type>();
@@ -5447,6 +5901,7 @@ namespace Microsoft.Dafny {
void ObjectInvariant()
{
Contract.Invariant(HeapExpr != null);
+ Contract.Invariant(HeapExpr is Bpl.OldExpr || HeapExpr is Bpl.IdentifierExpr);
Contract.Invariant(predef != null);
Contract.Invariant(translator != null);
Contract.Invariant(This != null);
@@ -5822,7 +6277,7 @@ namespace Microsoft.Dafny {
Bpl.Expr body = Bpl.Expr.Imp(Bpl.Expr.And(oNotNull, oInSet), oIsFresh);
return new Bpl.ForallExpr(expr.tok, new Bpl.VariableSeq(oVar), body);
} else if (e.E.Type is SeqType) {
- // generate: (forall $i: int :: 0 <= $i && $i < Seq#Length(X) && Unbox(Seq#Index(X,$i)) != null ==> !old($Heap)[Seq#Index(X,$i),alloc])
+ // generate: (forall $i: int :: 0 <= $i && $i < Seq#Length(X) && Unbox(Seq#Index(X,$i)) != null && !old($Heap)[Seq#Index(X,$i),alloc])
// TODO: trigger?
Bpl.Variable iVar = new Bpl.BoundVariable(expr.tok, new Bpl.TypedIdent(expr.tok, "$i", Bpl.Type.Int));
Bpl.Expr i = new Bpl.IdentifierExpr(expr.tok, iVar);
@@ -5830,20 +6285,18 @@ namespace Microsoft.Dafny {
Bpl.Expr XsubI = translator.FunctionCall(expr.tok, BuiltinFunction.SeqIndex, predef.RefType, TrExpr(e.E), i);
Bpl.Expr oIsFresh = Bpl.Expr.Not(Old.IsAlloced(expr.tok, XsubI));
Bpl.Expr xsubiNotNull = Bpl.Expr.Neq(translator.FunctionCall(expr.tok, BuiltinFunction.Unbox, predef.RefType, XsubI), predef.Null);
- Bpl.Expr body = Bpl.Expr.Imp(Bpl.Expr.And(iBounds, xsubiNotNull), oIsFresh);
+ Bpl.Expr body = Bpl.Expr.And(Bpl.Expr.And(iBounds, xsubiNotNull), oIsFresh);
return new Bpl.ForallExpr(expr.tok, new Bpl.VariableSeq(iVar), body);
+ } else if (e.E.Type.IsDatatype) {
+ Bpl.Expr alloc = translator.FunctionCall(e.tok, BuiltinFunction.DtAlloc, null, TrExpr(e.E), Old.HeapExpr);
+ return Bpl.Expr.Not(alloc);
} else {
- // generate: x == null || !old($Heap)[x]
- Bpl.Expr oNull = Bpl.Expr.Eq(TrExpr(e.E), predef.Null);
+ // generate: x != null && !old($Heap)[x]
+ Bpl.Expr oNull = Bpl.Expr.Neq(TrExpr(e.E), predef.Null);
Bpl.Expr oIsFresh = Bpl.Expr.Not(Old.IsAlloced(expr.tok, TrExpr(e.E)));
- return Bpl.Expr.Binary(expr.tok, BinaryOperator.Opcode.Or, oNull, oIsFresh);
+ return Bpl.Expr.And(oNull, oIsFresh);
}
- } else if (expr is AllocatedExpr) {
- AllocatedExpr e = (AllocatedExpr)expr;
- Bpl.Expr wh = translator.GetWhereClause(e.tok, TrExpr(e.E), e.E.Type, this);
- return wh == null ? Bpl.Expr.True : wh;
-
} else if (expr is UnaryExpr) {
UnaryExpr e = (UnaryExpr)expr;
Bpl.Expr arg = TrExpr(e.E);
@@ -7054,51 +7507,58 @@ namespace Microsoft.Dafny {
if (module == currentModule && functionHeight < heightLimit) {
if (f.Body != null && !(f.Body.Resolved is MatchExpr)) {
- // inline this body
- Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();
- Contract.Assert(fexp.Args.Count == f.Formals.Count);
- for (int i = 0; i < f.Formals.Count; i++) {
- Formal p = f.Formals[i];
- Expression arg = fexp.Args[i];
- arg = new BoxingCastExpr(arg, cce.NonNull(arg.Type), p.Type);
- arg.Type = p.Type; // resolve here
- substMap.Add(p, arg);
- }
- Expression body = Substitute(f.Body, fexp.Receiver, substMap);
-
- // Produce, for a "body" split into b0, b1, b2:
- // free F#canCall(args) && F(args) && (b0 && b1 && b2)
- // checked F#canCall(args) ==> F(args) || b0
- // checked F#canCall(args) ==> F(args) || b1
- // checked F#canCall(args) ==> F(args) || b2
- // Note that "body" does not contain limited calls.
-
- // F#canCall(args)
- Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(expr.tok, f.FullCompileName + "#canCall", Bpl.Type.Bool);
- ExprSeq args = etran.FunctionInvocationArguments(fexp);
- Bpl.Expr canCall = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(canCallFuncID), args);
-
- // F(args)
- Bpl.Expr fargs = etran.TrExpr(fexp);
-
- // body
- Bpl.Expr trBody = etran.TrExpr(body);
- trBody = etran.CondApplyUnbox(trBody.tok, trBody, f.ResultType, expr.Type);
-
- // here goes the free piece:
- splits.Add(new SplitExprInfo(true, Bpl.Expr.Binary(trBody.tok, BinaryOperator.Opcode.And, canCall, BplAnd(fargs, trBody))));
-
- // recurse on body
- var ss = new List<SplitExprInfo>();
- TrSplitExpr(body, ss, position, functionHeight, etran);
- foreach (var s in ss) {
- var unboxedConjunct = etran.CondApplyUnbox(s.E.tok, s.E, f.ResultType, expr.Type);
- var bodyOrConjunct = Bpl.Expr.Or(fargs, unboxedConjunct);
- var p = Bpl.Expr.Binary(new NestedToken(fexp.tok, s.E.tok), BinaryOperator.Opcode.Imp, canCall, bodyOrConjunct);
- splits.Add(new SplitExprInfo(s.IsFree, p));
- }
+ if (RefinementToken.IsInherited(fexp.tok, currentModule) &&
+ f is Predicate && ((Predicate)f).BodyOrigin == Predicate.BodyOriginKind.DelayedDefinition &&
+ (currentMethod == null || !currentMethod.MustReverify)) {
+ // The function was inherited as body-less but is now given a body. Don't inline the body (since, apparently, everything
+ // that needed to be proved about the function was proved already in the previous module, even without the body definition).
+ } else {
+ // inline this body
+ Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();
+ Contract.Assert(fexp.Args.Count == f.Formals.Count);
+ for (int i = 0; i < f.Formals.Count; i++) {
+ Formal p = f.Formals[i];
+ Expression arg = fexp.Args[i];
+ arg = new BoxingCastExpr(arg, cce.NonNull(arg.Type), p.Type);
+ arg.Type = p.Type; // resolve here
+ substMap.Add(p, arg);
+ }
+ Expression body = Substitute(f.Body, fexp.Receiver, substMap);
+
+ // Produce, for a "body" split into b0, b1, b2:
+ // free F#canCall(args) && F(args) && (b0 && b1 && b2)
+ // checked F#canCall(args) ==> F(args) || b0
+ // checked F#canCall(args) ==> F(args) || b1
+ // checked F#canCall(args) ==> F(args) || b2
+ // Note that "body" does not contain limited calls.
+
+ // F#canCall(args)
+ Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(expr.tok, f.FullCompileName + "#canCall", Bpl.Type.Bool);
+ ExprSeq args = etran.FunctionInvocationArguments(fexp);
+ Bpl.Expr canCall = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(canCallFuncID), args);
+
+ // F(args)
+ Bpl.Expr fargs = etran.TrExpr(fexp);
+
+ // body
+ Bpl.Expr trBody = etran.TrExpr(body);
+ trBody = etran.CondApplyUnbox(trBody.tok, trBody, f.ResultType, expr.Type);
+
+ // here goes the free piece:
+ splits.Add(new SplitExprInfo(true, Bpl.Expr.Binary(trBody.tok, BinaryOperator.Opcode.And, canCall, BplAnd(fargs, trBody))));
+
+ // recurse on body
+ var ss = new List<SplitExprInfo>();
+ TrSplitExpr(body, ss, position, functionHeight, etran);
+ foreach (var s in ss) {
+ var unboxedConjunct = etran.CondApplyUnbox(s.E.tok, s.E, f.ResultType, expr.Type);
+ var bodyOrConjunct = Bpl.Expr.Or(fargs, unboxedConjunct);
+ var p = Bpl.Expr.Binary(new NestedToken(fexp.tok, s.E.tok), BinaryOperator.Opcode.Imp, canCall, bodyOrConjunct);
+ splits.Add(new SplitExprInfo(s.IsFree, p));
+ }
- return true;
+ return true;
+ }
}
}
}
@@ -7198,7 +7658,9 @@ namespace Microsoft.Dafny {
translatedExpression = etran.TrExpr(expr);
splitHappened = etran.Statistics_CustomLayerFunctionCount != 0; // return true if the LayerOffset(1) came into play
}
- if (RefinementToken.IsInherited(expr.tok, currentModule) && RefinementTransformer.ContainsChange(expr, currentModule)) {
+ // TODO: Is the the following call to ContainsChange expensive? It's linear in the size of "expr", but we get here many times in TrSpliExpr, so wouldn't the total
+ // time in the size of the expression passed to the first TrSpliExpr be quadratic?
+ if (RefinementToken.IsInherited(expr.tok, currentModule) && (currentMethod == null || !currentMethod.MustReverify) && RefinementTransformer.ContainsChange(expr, currentModule)) {
// If "expr" contains a subexpression that has changed from the inherited expression, we'll destructively
// change the token of the translated expression to make it look like it's not inherited. This will cause "e" to
// be verified again in the refining module.
@@ -7673,7 +8135,9 @@ namespace Microsoft.Dafny {
Bpl.Expr Conclusion = new Bpl.ForallExpr(tok, bvs, new Bpl.Trigger(tok, true, new ExprSeq(etran.TrExpr(C))),
Bpl.Expr.Imp(preStuff, etran.TrExpr(C)));
// Now for the antecedent of the axiom
- // TODO: if e.Body uses a 'match' expression, first desugar it into an ordinary expression
+ if (coPredicate.Body is MatchExpr) {
+ return Bpl.Expr.True; // TODO: if coPredicate.Body uses a 'match' expression, first desugar it into an ordinary expression
+ }
var s = new CoinductionSubstituter(coPredicate, receiverReplacement, substMap, pre, boundVars, receiverReplacement, args);
var body = s.Substitute(coPredicate.Body);
Bpl.Expr Antecedent = new Bpl.ForallExpr(tok, bvs, Bpl.Expr.Imp(preStuff, etran.TrExpr(body)));
@@ -7963,7 +8427,32 @@ namespace Microsoft.Dafny {
// TODO: in the following substitution, it may be that we also need to update the types of the resulting subexpressions (is this true for all Substitute calls?)
return Substitute(fce.Function.Body, fce.Receiver, substMap);
}
-
+ public class FunctionCallSubstituter : Substituter
+ {
+ public readonly Function A, B;
+ public FunctionCallSubstituter(Expression receiverReplacement, Dictionary<IVariable, Expression/*!*/>/*!*/ substMap, Function a, Function b)
+ : base(receiverReplacement, substMap) {
+ A = a;
+ B = b;
+ }
+ public override Expression Substitute(Expression expr) {
+ if (expr is FunctionCallExpr) {
+ FunctionCallExpr e = (FunctionCallExpr)expr;
+ Expression receiver = Substitute(e.Receiver);
+ List<Expression> newArgs = SubstituteExprList(e.Args);
+ FunctionCallExpr newFce = new FunctionCallExpr(expr.tok, e.Name, receiver, e.OpenParen, newArgs);
+ if (e.Function == A) {
+ newFce.Function = B;
+ newFce.Type = e.Type; // TODO: this may not work with type parameters.
+ } else {
+ newFce.Function = e.Function;
+ newFce.Type = e.Type;
+ }
+ return newFce;
+ }
+ return base.Substitute(expr);
+ }
+ }
public class Substituter
{
public readonly Expression receiverReplacement;
@@ -8072,12 +8561,6 @@ namespace Microsoft.Dafny {
if (se != e.E) {
newExpr = new FreshExpr(expr.tok, se);
}
- } else if (expr is AllocatedExpr) {
- AllocatedExpr e = (AllocatedExpr)expr;
- Expression se = Substitute(e.E);
- if (se != e.E) {
- newExpr = new AllocatedExpr(expr.tok, se);
- }
} else if (expr is UnaryExpr) {
UnaryExpr e = (UnaryExpr)expr;
Expression se = Substitute(e.E);
diff --git a/Source/DafnyDriver/DafnyDriver.cs b/Source/DafnyDriver/DafnyDriver.cs
index 3534dcbf..64f5fbbb 100644
--- a/Source/DafnyDriver/DafnyDriver.cs
+++ b/Source/DafnyDriver/DafnyDriver.cs
@@ -280,8 +280,9 @@ namespace Microsoft.Dafny
/// Print newline after the message.
/// </summary>
public static void Inform(string s) {
- if ( ! CommandLineOptions.Clo.Trace) { return; }
- Console.WriteLine(s);
+ if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.TraceProofObligations) {
+ Console.WriteLine(s);
+ }
}
static void WriteTrailer(int verified, int errors, int inconclusives, int timeOuts, int outOfMemories){
@@ -598,10 +599,10 @@ namespace Microsoft.Dafny
List<Counterexample>/*?*/ errors;
DateTime start = new DateTime(); // to please compiler's definite assignment rules
- if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.XmlSink != null)
+ if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.TraceProofObligations || CommandLineOptions.Clo.XmlSink != null)
{
start = DateTime.Now;
- if (CommandLineOptions.Clo.Trace)
+ if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.TraceProofObligations)
{
Console.WriteLine();
Console.WriteLine("Verifying {0} ...", impl.Name);
@@ -634,13 +635,12 @@ namespace Microsoft.Dafny
string timeIndication = "";
DateTime end = DateTime.Now;
TimeSpan elapsed = end - start;
- if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.XmlSink != null)
- {
- if (CommandLineOptions.Clo.Trace)
- {
- int poCount = vcgen.CumulativeAssertionCount - prevAssertionCount;
- timeIndication = string.Format(" [{0} s, {1} proof obligation{2}] ", elapsed.TotalSeconds, poCount, poCount == 1 ? "" : "s");
- }
+ if (CommandLineOptions.Clo.Trace) {
+ int poCount = vcgen.CumulativeAssertionCount - prevAssertionCount;
+ timeIndication = string.Format(" [{0:F3} s, {1} proof obligation{2}] ", elapsed.TotalSeconds, poCount, poCount == 1 ? "" : "s");
+ } else if (CommandLineOptions.Clo.TraceProofObligations) {
+ int poCount = vcgen.CumulativeAssertionCount - prevAssertionCount;
+ timeIndication = string.Format(" [{0} proof obligation{1}] ", poCount, poCount == 1 ? "" : "s");
}
switch (outcome)
@@ -677,8 +677,8 @@ namespace Microsoft.Dafny
if (error is CallCounterexample)
{
CallCounterexample err = (CallCounterexample)error;
- ReportBplError(err.FailingCall.tok, "Error BP5002: A precondition for this call might not hold.", true);
- ReportBplError(err.FailingRequires.tok, "Related location: This is the precondition that might not hold.", false);
+ ReportBplError(err.FailingCall.tok, (err.FailingCall.ErrorData as string) ?? "Error BP5002: A precondition for this call might not hold.", true);
+ ReportBplError(err.FailingRequires.tok, (err.FailingRequires.ErrorData as string) ?? "Related location: This is the precondition that might not hold.", false);
if (CommandLineOptions.Clo.XmlSink != null)
{
CommandLineOptions.Clo.XmlSink.WriteError("precondition violation", err.FailingCall.tok, err.FailingRequires.tok, error.Trace);
@@ -688,7 +688,8 @@ namespace Microsoft.Dafny
{
ReturnCounterexample err = (ReturnCounterexample)error;
ReportBplError(err.FailingReturn.tok, "Error BP5003: A postcondition might not hold on this return path.", true);
- ReportBplError(err.FailingEnsures.tok, "Related location: This is the postcondition that might not hold.", false);
+ ReportBplError(err.FailingEnsures.tok, (err.FailingEnsures.ErrorData as string) ?? "Related location: This is the postcondition that might not hold.", false);
+ ReportAllBplErrors(err.FailingEnsures.Attributes);
if (CommandLineOptions.Clo.XmlSink != null)
{
CommandLineOptions.Clo.XmlSink.WriteError("postcondition violation", err.FailingReturn.tok, err.FailingEnsures.tok, error.Trace);
@@ -722,6 +723,8 @@ namespace Microsoft.Dafny
msg = "Error BP5001: This assertion might not hold.";
}
ReportBplError(err.FailingAssert.tok, msg, true);
+ var attr = err.FailingAssert.Attributes;
+ ReportAllBplErrors(attr);
if (CommandLineOptions.Clo.XmlSink != null)
{
CommandLineOptions.Clo.XmlSink.WriteError("assertion violation", err.FailingAssert.tok, null, error.Trace);
@@ -787,5 +790,17 @@ namespace Microsoft.Dafny
return PipelineOutcome.VerificationCompleted;
}
+ private static void ReportAllBplErrors(QKeyValue attr) {
+ while (attr != null) {
+ if (attr.Key == "msg" && attr.Params.Count == 1) {
+ var str = attr.Params[0] as string;
+ if (str != null) {
+ ReportBplError(attr.tok, "Error: "+str, false);
+ }
+ }
+ attr = attr.Next;
+ }
+ }
+
}
}
diff --git a/Source/GPUVerify.sln b/Source/GPUVerify.sln
index 4d515300..7853459f 100644
--- a/Source/GPUVerify.sln
+++ b/Source/GPUVerify.sln
@@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCExpr", "VCExpr\VCExpr.csp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Isabelle", "Provers\Isabelle\Isabelle.csproj", "{435D5BD0-6F62-49F8-BB24-33E2257519AD}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GPUVerifyBoogieDriver", "GPUVerifyBoogieDriver\GPUVerifyBoogieDriver.csproj", "{FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Checked|Any CPU = Checked|Any CPU
@@ -327,6 +329,26 @@ Global
{435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|Mixed Platforms.ActiveCfg = z3apidebug|Any CPU
{435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|Mixed Platforms.Build.0 = z3apidebug|Any CPU
{435D5BD0-6F62-49F8-BB24-33E2257519AD}.z3apidebug|x86.ActiveCfg = z3apidebug|Any CPU
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Checked|Any CPU.ActiveCfg = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Checked|Mixed Platforms.ActiveCfg = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Checked|Mixed Platforms.Build.0 = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Checked|x86.ActiveCfg = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Checked|x86.Build.0 = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Debug|Mixed Platforms.Build.0 = Debug|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Debug|x86.ActiveCfg = Debug|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Debug|x86.Build.0 = Debug|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Release|Any CPU.ActiveCfg = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Release|Mixed Platforms.ActiveCfg = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Release|Mixed Platforms.Build.0 = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Release|x86.ActiveCfg = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.Release|x86.Build.0 = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.z3apidebug|Any CPU.ActiveCfg = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.z3apidebug|Mixed Platforms.ActiveCfg = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.z3apidebug|Mixed Platforms.Build.0 = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.z3apidebug|x86.ActiveCfg = Release|x86
+ {FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}.z3apidebug|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Source/GPUVerify/AccessRecord.cs b/Source/GPUVerify/AccessRecord.cs
index fedacde3..343cca8c 100644
--- a/Source/GPUVerify/AccessRecord.cs
+++ b/Source/GPUVerify/AccessRecord.cs
@@ -10,16 +10,12 @@ namespace GPUVerify
class AccessRecord
{
public Variable v;
- public Expr IndexZ;
- public Expr IndexY;
- public Expr IndexX;
+ public Expr Index;
- public AccessRecord(Variable v, Expr IndexZ, Expr IndexY, Expr IndexX)
+ public AccessRecord(Variable v, Expr Index)
{
this.v = v;
- this.IndexZ = IndexZ;
- this.IndexY = IndexY;
- this.IndexX = IndexX;
+ this.Index = Index;
}
diff --git a/Source/GPUVerify/AdversarialAbstraction.cs b/Source/GPUVerify/AdversarialAbstraction.cs
new file mode 100644
index 00000000..b6c0ee86
--- /dev/null
+++ b/Source/GPUVerify/AdversarialAbstraction.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using Microsoft.Boogie;
+using System.Diagnostics.Contracts;
+
+namespace GPUVerify {
+
+ class AdversarialAbstraction {
+
+ private GPUVerifier verifier;
+
+ internal AdversarialAbstraction(GPUVerifier verifier) {
+ this.verifier = verifier;
+ }
+
+ internal void Abstract() {
+ List<Declaration> NewTopLevelDeclarations = new List<Declaration>();
+ foreach (Declaration d in verifier.Program.TopLevelDeclarations) {
+ if (d is Variable && verifier.KernelArrayInfo.Contains(d as Variable) &&
+ verifier.ArrayModelledAdversarially(d as Variable)) {
+ continue;
+ }
+
+ if (d is Implementation) {
+ Abstract(d as Implementation);
+ }
+
+ if (d is Procedure) {
+ Abstract(d as Procedure);
+ }
+
+ NewTopLevelDeclarations.Add(d);
+
+ }
+
+ verifier.Program.TopLevelDeclarations = NewTopLevelDeclarations;
+
+ AbstractRequiresClauses(verifier.KernelProcedure);
+ }
+
+
+ private void AbstractRequiresClauses(Procedure proc) {
+ RequiresSeq newRequires = new RequiresSeq();
+ foreach (Requires r in proc.Requires) {
+ var visitor = new AccessesAdversarialArrayVisitor(verifier);
+ visitor.VisitRequires(r);
+ if (!visitor.found) {
+ newRequires.Add(r);
+ }
+ }
+ proc.Requires = newRequires;
+ }
+
+ private void Abstract(Procedure proc) {
+ AbstractModifiesSet(proc);
+ }
+
+ private void AbstractModifiesSet(Procedure proc) {
+ IdentifierExprSeq NewModifies = new IdentifierExprSeq();
+ foreach (IdentifierExpr e in proc.Modifies) {
+ var visitor = new AccessesAdversarialArrayVisitor(verifier);
+ visitor.VisitIdentifierExpr(e);
+ if(!visitor.found) {
+ NewModifies.Add(e);
+ }
+ }
+ proc.Modifies = NewModifies;
+ }
+
+ private void Abstract(Implementation impl) {
+ VariableSeq NewLocVars = new VariableSeq();
+
+ foreach (Variable v in impl.LocVars) {
+ Debug.Assert(!verifier.KernelArrayInfo.getGroupSharedArrays().Contains(v));
+ NewLocVars.Add(v);
+ }
+
+ impl.LocVars = NewLocVars;
+
+ if (CommandLineOptions.Unstructured)
+ impl.Blocks = impl.Blocks.Select(Abstract).ToList();
+ else
+ impl.StructuredStmts = Abstract(impl.StructuredStmts);
+ }
+
+
+ private StmtList Abstract(StmtList stmtList) {
+ Contract.Requires(stmtList != null);
+
+ StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
+
+ foreach (BigBlock bodyBlock in stmtList.BigBlocks) {
+ result.BigBlocks.Add(Abstract(bodyBlock));
+ }
+ return result;
+ }
+
+ private CmdSeq Abstract(CmdSeq cs) {
+ var result = new CmdSeq();
+
+ foreach (Cmd c in cs) {
+ if (c is AssignCmd) {
+ AssignCmd assign = c as AssignCmd;
+
+ var lhss = new List<AssignLhs>();
+ var rhss = new List<Expr>();
+
+ for (int i = 0; i != assign.Lhss.Count; i++) {
+ AssignLhs lhs = assign.Lhss[i];
+ Expr rhs = assign.Rhss[i];
+ ReadCollector rc = new ReadCollector(verifier.KernelArrayInfo);
+ rc.Visit(rhs);
+
+ bool foundAdversarial = false;
+ foreach (AccessRecord ar in rc.accesses) {
+ if (verifier.ArrayModelledAdversarially(ar.v)) {
+ foundAdversarial = true;
+ break;
+ }
+ }
+
+ if (foundAdversarial) {
+ Debug.Assert(lhs is SimpleAssignLhs);
+ result.Add(new HavocCmd(c.tok, new IdentifierExprSeq(new IdentifierExpr[] { (lhs as SimpleAssignLhs).AssignedVariable })));
+ continue;
+ }
+
+ WriteCollector wc = new WriteCollector(verifier.KernelArrayInfo);
+ wc.Visit(lhs);
+ if (wc.GetAccess() != null && verifier.ArrayModelledAdversarially(wc.GetAccess().v)) {
+ continue; // Just remove the write
+ }
+
+ lhss.Add(lhs);
+ rhss.Add(rhs);
+ }
+
+ if (lhss.Count != 0) {
+ result.Add(new AssignCmd(assign.tok, lhss, rhss));
+ }
+ continue;
+ }
+ result.Add(c);
+ }
+
+ return result;
+ }
+
+ private Block Abstract(Block b) {
+ b.Cmds = Abstract(b.Cmds);
+ return b;
+ }
+
+ private BigBlock Abstract(BigBlock bb) {
+ BigBlock result = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
+
+ result.simpleCmds = Abstract(bb.simpleCmds);
+
+ if (bb.ec is WhileCmd) {
+ WhileCmd WhileCommand = bb.ec as WhileCmd;
+ result.ec =
+ new WhileCmd(WhileCommand.tok, WhileCommand.Guard, WhileCommand.Invariants, Abstract(WhileCommand.Body));
+ }
+ else if (bb.ec is IfCmd) {
+ IfCmd IfCommand = bb.ec as IfCmd;
+ Debug.Assert(IfCommand.elseIf == null);
+ result.ec = new IfCmd(IfCommand.tok, IfCommand.Guard, Abstract(IfCommand.thn), IfCommand.elseIf, IfCommand.elseBlock != null ? Abstract(IfCommand.elseBlock) : null);
+ }
+ else {
+ Debug.Assert(bb.ec == null || bb.ec is BreakCmd);
+ }
+
+ return result;
+
+ }
+
+ class AccessesAdversarialArrayVisitor : StandardVisitor {
+ internal bool found;
+ private GPUVerifier verifier;
+
+ internal AccessesAdversarialArrayVisitor(GPUVerifier verifier) {
+ this.found = false;
+ this.verifier = verifier;
+ }
+
+ public override Variable VisitVariable(Variable v) {
+ if (verifier.KernelArrayInfo.Contains(v)) {
+ if (verifier.ArrayModelledAdversarially(v)) {
+ found = true;
+ }
+ }
+ return base.VisitVariable(v);
+ }
+
+ }
+
+ }
+
+
+}
diff --git a/Source/GPUVerify/CommandLineOptions.cs b/Source/GPUVerify/CommandLineOptions.cs
index ed20b08b..5f6f0066 100644
--- a/Source/GPUVerify/CommandLineOptions.cs
+++ b/Source/GPUVerify/CommandLineOptions.cs
@@ -21,24 +21,19 @@ namespace GPUVerify
public static bool Inference = false;
public static bool ArrayEqualities = false;
public static string invariantsFile = null;
- public static bool DividedArray = false;
- public static string ArrayToCheck = null;
- public static bool DividedAccesses = false;
public static bool ShowStages = false;
- public static bool AddDivergenceCandidatesOnlyIfModified = true;
- public static bool AddDivergenceCandidatesOnlyToBarrierLoops = true;
-
public static bool ShowUniformityAnalysis = false;
- public static bool DoUniformityAnalysis = true;
+ public static bool DoUniformityAnalysis = false;
public static bool ShowMayBePowerOfTwoAnalysis = false;
public static bool ShowArrayControlFlowAnalysis = false;
public static bool NoLoopPredicateInvariants = false;
- public static bool Unstructured = false;
+ public static bool Unstructured = true;
+ public static bool SmartPredication = true;
public static bool OnlyIntraGroupRaceChecking = false;
@@ -95,28 +90,6 @@ namespace GPUVerify
break;
- case "-dividedArray":
- case "/dividedArray":
- if (hasColonArgument)
- {
- ArrayToCheck = afterColon;
- }
- DividedArray = true;
-
- break;
-
- case "-dividedAccesses":
- case "/dividedAccesses":
- DividedAccesses = true;
-
- break;
-
- case "-divided":
- case "/divided":
- DividedAccesses = true;
- DividedArray = true;
- break;
-
case "-showStages":
case "/showStages":
ShowStages = true;
@@ -138,20 +111,14 @@ namespace GPUVerify
ArrayEqualities = true;
break;
- case "-alwaysAddDivergenceCandidates":
- case "/alwaysAddDivergenceCandidates":
- AddDivergenceCandidatesOnlyIfModified = false;
- AddDivergenceCandidatesOnlyToBarrierLoops = false;
- break;
-
case "-showUniformityAnalysis":
case "/showUniformityAnalysis":
ShowUniformityAnalysis = true;
break;
- case "-noUniformityAnalysis":
- case "/noUniformityAnalysis":
- DoUniformityAnalysis = false;
+ case "-uniformityAnalysis":
+ case "/uniformityAnalysis":
+ DoUniformityAnalysis = true;
break;
case "-showMayBePowerOfTwoAnalysis":
@@ -169,9 +136,14 @@ namespace GPUVerify
NoLoopPredicateInvariants = true;
break;
- case "-unstructured":
- case "/unstructured":
- Unstructured = true;
+ case "-structured":
+ case "/structured":
+ Unstructured = false;
+ break;
+
+ case "-noSmartPredication":
+ case "/noSmartPredication":
+ SmartPredication = false;
break;
case "-onlyIntraGroupRaceChecking":
@@ -184,11 +156,6 @@ namespace GPUVerify
break;
}
- if (OnlyDivergence)
- {
- DividedArray = false;
- DividedAccesses = false;
- }
}
return 0;
}
diff --git a/Source/GPUVerify/GPUVerifier.cs b/Source/GPUVerify/GPUVerifier.cs
index 56f632f2..868bcaa1 100644
--- a/Source/GPUVerify/GPUVerifier.cs
+++ b/Source/GPUVerify/GPUVerifier.cs
@@ -1,2326 +1,2214 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.IO;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie;
-using Microsoft.Basetypes;
-
-namespace GPUVerify
-{
- class GPUVerifier : CheckingContext
- {
- public string outputFilename;
- public Program Program;
- public ResolutionContext ResContext;
-
- public Procedure KernelProcedure;
- public Implementation KernelImplementation;
- public Procedure BarrierProcedure;
-
- public IKernelArrayInfo KernelArrayInfo = new KernelArrayInfoLists();
-
- private HashSet<string> ReservedNames = new HashSet<string>();
-
- private int TempCounter = 0;
-
- internal const string LOCAL_ID_X_STRING = "local_id_x";
- internal const string LOCAL_ID_Y_STRING = "local_id_y";
- internal const string LOCAL_ID_Z_STRING = "local_id_z";
-
- internal static Constant _X = null;
- internal static Constant _Y = null;
- internal static Constant _Z = null;
-
- internal const string GROUP_SIZE_X_STRING = "group_size_x";
- internal const string GROUP_SIZE_Y_STRING = "group_size_y";
- internal const string GROUP_SIZE_Z_STRING = "group_size_z";
-
- internal static Constant _GROUP_SIZE_X = null;
- internal static Constant _GROUP_SIZE_Y = null;
- internal static Constant _GROUP_SIZE_Z = null;
-
- internal const string GROUP_ID_X_STRING = "group_id_x";
- internal const string GROUP_ID_Y_STRING = "group_id_y";
- internal const string GROUP_ID_Z_STRING = "group_id_z";
-
- internal static Constant _GROUP_X = null;
- internal static Constant _GROUP_Y = null;
- internal static Constant _GROUP_Z = null;
-
- internal const string NUM_GROUPS_X_STRING = "num_groups_x";
- internal const string NUM_GROUPS_Y_STRING = "num_groups_y";
- internal const string NUM_GROUPS_Z_STRING = "num_groups_z";
-
- internal static Constant _NUM_GROUPS_X = null;
- internal static Constant _NUM_GROUPS_Y = null;
- internal static Constant _NUM_GROUPS_Z = null;
-
- internal const int CLK_LOCAL_MEM_FENCE = 1;
- internal const int CLK_GLOBAL_MEM_FENCE = 2;
-
- public IRaceInstrumenter RaceInstrumenter;
-
- public UniformityAnalyser uniformityAnalyser;
- public MayBePowerOfTwoAnalyser mayBePowerOfTwoAnalyser;
- public LiveVariableAnalyser liveVariableAnalyser;
- public ArrayControlFlowAnalyser arrayControlFlowAnalyser;
- public Dictionary<Implementation, VariableDefinitionAnalysis> varDefAnalyses;
- public Dictionary<Implementation, ReducedStrengthAnalysis> reducedStrengthAnalyses;
-
- public GPUVerifier(string filename, Program program, ResolutionContext rc, IRaceInstrumenter raceInstrumenter) : this(filename, program, rc, raceInstrumenter, false)
- {
- }
-
- public GPUVerifier(string filename, Program program, ResolutionContext rc, IRaceInstrumenter raceInstrumenter, bool skipCheck)
- : base((IErrorSink)null)
- {
- this.outputFilename = filename;
- this.Program = program;
- this.ResContext = rc;
- this.RaceInstrumenter = raceInstrumenter;
- if(!skipCheck)
- CheckWellFormedness();
- }
-
- public void setRaceInstrumenter(IRaceInstrumenter ri)
- {
- this.RaceInstrumenter = ri;
- }
-
- private void CheckWellFormedness()
- {
- int errorCount = Check();
- if (errorCount != 0)
- {
- Console.WriteLine("{0} GPUVerify format errors detected in {1}", errorCount, CommandLineOptions.inputFiles[CommandLineOptions.inputFiles.Count - 1]);
- Environment.Exit(1);
- }
- }
-
- private Procedure CheckExactlyOneKernelProcedure()
- {
- var p = CheckSingleInstanceOfAttributedProcedure("kernel");
- if (p == null)
- {
- Error(Program, "\"kernel\" attribute has not been specified for any procedure. You must mark exactly one procedure with this attribute");
- }
-
- return p;
- }
-
- private Procedure FindOrCreateBarrierProcedure()
- {
- var p = CheckSingleInstanceOfAttributedProcedure("barrier");
- if (p == null)
- {
- p = new Procedure(Token.NoToken, "barrier", new TypeVariableSeq(),
- new VariableSeq(new Variable[] { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "__flags", new BvType(32)), true) }),
- new VariableSeq(),
- new RequiresSeq(), new IdentifierExprSeq(),
- new EnsuresSeq(),
- new QKeyValue(Token.NoToken, "barrier", new List<object>(), null));
- Program.TopLevelDeclarations.Add(p);
- ResContext.AddProcedure(p);
- }
- return p;
- }
-
- private Procedure CheckSingleInstanceOfAttributedProcedure(string attribute)
- {
- Procedure attributedProcedure = null;
-
- foreach (Declaration decl in Program.TopLevelDeclarations)
- {
- if (!QKeyValue.FindBoolAttribute(decl.Attributes, attribute))
- {
- continue;
- }
-
- if (decl is Implementation)
- {
- continue;
- }
-
- if (decl is Procedure)
- {
- if (attributedProcedure == null)
- {
- attributedProcedure = decl as Procedure;
- }
- else
- {
- Error(decl, "\"{0}\" attribute specified for procedure {1}, but it has already been specified for procedure {2}", attribute, (decl as Procedure).Name, attributedProcedure.Name);
- }
-
- }
- else
- {
- Error(decl, "\"{0}\" attribute can only be applied to a procedure", attribute);
- }
- }
-
- return attributedProcedure;
- }
-
- private void CheckLocalVariables()
- {
- foreach (LocalVariable LV in KernelImplementation.LocVars)
- {
- if (QKeyValue.FindBoolAttribute(LV.Attributes, "group_shared"))
- {
- Error(LV.tok, "Local variable must not be marked 'group_shared' -- promote the variable to global scope");
- }
- }
- }
-
-
- private void ReportMultipleAttributeError(string attribute, IToken first, IToken second)
- {
- Error(
- second,
- "Can only have one {0} attribute, but previously saw this attribute at ({1}, {2})",
- attribute,
- first.filename,
- first.line, first.col - 1);
- }
-
- private bool setConstAttributeField(Constant constInProgram, string attr, ref Constant constFieldRef)
- {
- if (QKeyValue.FindBoolAttribute(constInProgram.Attributes, attr))
- {
- if (constFieldRef != null)
- {
- ReportMultipleAttributeError(attr, constFieldRef.tok, constInProgram.tok);
- return false;
- }
- CheckSpecialConstantType(constInProgram);
- constFieldRef = constInProgram;
- }
- return true;
- }
-
- private void MaybeCreateAttributedConst(string attr, ref Constant constFieldRef)
- {
- if (constFieldRef == null)
- {
- constFieldRef = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, attr, Microsoft.Boogie.Type.GetBvType(32)), /*unique=*/false);
- constFieldRef.AddAttribute(attr);
- Program.TopLevelDeclarations.Add(constFieldRef);
- }
- }
-
- private bool FindNonLocalVariables()
- {
- bool success = true;
- foreach (Declaration D in Program.TopLevelDeclarations)
- {
- if (D is Variable &&
- (D as Variable).IsMutable &&
- (D as Variable).TypedIdent.Type is MapType &&
- !ReservedNames.Contains((D as Variable).Name))
- {
- if (QKeyValue.FindBoolAttribute(D.Attributes, "group_shared"))
- {
- KernelArrayInfo.getGroupSharedArrays().Add(D as Variable);
- }
- else if (QKeyValue.FindBoolAttribute(D.Attributes, "global"))
- {
- KernelArrayInfo.getGlobalArrays().Add(D as Variable);
- }
- else
- {
- KernelArrayInfo.getPrivateArrays().Add(D as Variable);
- }
- }
- else if (D is Constant)
- {
- Constant C = D as Constant;
-
- success &= setConstAttributeField(C, LOCAL_ID_X_STRING, ref _X);
- success &= setConstAttributeField(C, LOCAL_ID_Y_STRING, ref _Y);
- success &= setConstAttributeField(C, LOCAL_ID_Z_STRING, ref _Z);
-
- success &= setConstAttributeField(C, GROUP_SIZE_X_STRING, ref _GROUP_SIZE_X);
- success &= setConstAttributeField(C, GROUP_SIZE_Y_STRING, ref _GROUP_SIZE_Y);
- success &= setConstAttributeField(C, GROUP_SIZE_Z_STRING, ref _GROUP_SIZE_Z);
-
- success &= setConstAttributeField(C, GROUP_ID_X_STRING, ref _GROUP_X);
- success &= setConstAttributeField(C, GROUP_ID_Y_STRING, ref _GROUP_Y);
- success &= setConstAttributeField(C, GROUP_ID_Z_STRING, ref _GROUP_Z);
-
- success &= setConstAttributeField(C, NUM_GROUPS_X_STRING, ref _NUM_GROUPS_X);
- success &= setConstAttributeField(C, NUM_GROUPS_Y_STRING, ref _NUM_GROUPS_Y);
- success &= setConstAttributeField(C, NUM_GROUPS_Z_STRING, ref _NUM_GROUPS_Z);
-
-
- }
- }
-
- MaybeCreateAttributedConst(LOCAL_ID_X_STRING, ref _X);
- MaybeCreateAttributedConst(LOCAL_ID_Y_STRING, ref _Y);
- MaybeCreateAttributedConst(LOCAL_ID_Z_STRING, ref _Z);
-
- MaybeCreateAttributedConst(GROUP_SIZE_X_STRING, ref _GROUP_SIZE_X);
- MaybeCreateAttributedConst(GROUP_SIZE_Y_STRING, ref _GROUP_SIZE_Y);
- MaybeCreateAttributedConst(GROUP_SIZE_Z_STRING, ref _GROUP_SIZE_Z);
-
- MaybeCreateAttributedConst(GROUP_ID_X_STRING, ref _GROUP_X);
- MaybeCreateAttributedConst(GROUP_ID_Y_STRING, ref _GROUP_Y);
- MaybeCreateAttributedConst(GROUP_ID_Z_STRING, ref _GROUP_Z);
-
- MaybeCreateAttributedConst(NUM_GROUPS_X_STRING, ref _NUM_GROUPS_X);
- MaybeCreateAttributedConst(NUM_GROUPS_Y_STRING, ref _NUM_GROUPS_Y);
- MaybeCreateAttributedConst(NUM_GROUPS_Z_STRING, ref _NUM_GROUPS_Z);
-
- return success;
- }
-
- private void CheckSpecialConstantType(Constant C)
- {
- if (!(C.TypedIdent.Type.Equals(Microsoft.Boogie.Type.Int) || C.TypedIdent.Type.Equals(Microsoft.Boogie.Type.GetBvType(32))))
- {
- Error(C.tok, "Special constant '" + C.Name + "' must have type 'int' or 'bv32'");
- }
- }
-
- private void GetKernelImplementation()
- {
- foreach (Declaration decl in Program.TopLevelDeclarations)
- {
- if (!(decl is Implementation))
- {
- continue;
- }
-
- Implementation Impl = decl as Implementation;
-
- if (Impl.Proc == KernelProcedure)
- {
- KernelImplementation = Impl;
- break;
- }
-
- }
-
- if (KernelImplementation == null)
- {
- Error(Token.NoToken, "*** Error: no implementation of kernel procedure");
- }
- }
-
-
-
-
- protected virtual void CheckKernelImplementation()
- {
- CheckKernelParameters();
- GetKernelImplementation();
-
- if (KernelImplementation == null)
- {
- return;
- }
-
- CheckLocalVariables();
- CheckNoReturns();
- }
-
- private void CheckNoReturns()
- {
- // TODO!
- }
-
- internal void preProcess()
- {
- RemoveRedundantReturns();
-
- RemoveElseIfs();
-
- PullOutNonLocalAccesses();
- }
-
- private void MergeBlocksIntoPredecessors()
- {
- foreach (var impl in Program.TopLevelDeclarations.OfType<Implementation>())
- VC.VCGen.MergeBlocksIntoPredecessors(Program, impl);
- }
-
- internal void doit()
- {
- if (CommandLineOptions.Unstructured)
- {
- Microsoft.Boogie.CommandLineOptions.Clo.PrintUnstructured = 2;
- }
-
- if (CommandLineOptions.ShowStages)
- {
- emitProgram(outputFilename + "_original");
- }
-
- preProcess();
-
- DoLiveVariableAnalysis();
-
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using Microsoft.Boogie;
+using Microsoft.Basetypes;
+
+namespace GPUVerify
+{
+ class GPUVerifier : CheckingContext
+ {
+ public string outputFilename;
+ public Program Program;
+ public ResolutionContext ResContext;
+
+ public Procedure KernelProcedure;
+ public Implementation KernelImplementation;
+ public Procedure BarrierProcedure;
+
+ public IKernelArrayInfo KernelArrayInfo = new KernelArrayInfoLists();
+
+ private HashSet<string> ReservedNames = new HashSet<string>();
+
+ internal HashSet<string> OnlyThread1 = new HashSet<string>();
+ internal HashSet<string> OnlyThread2 = new HashSet<string>();
+
+ private int TempCounter = 0;
+
+ internal const string LOCAL_ID_X_STRING = "local_id_x";
+ internal const string LOCAL_ID_Y_STRING = "local_id_y";
+ internal const string LOCAL_ID_Z_STRING = "local_id_z";
+
+ internal static Constant _X = null;
+ internal static Constant _Y = null;
+ internal static Constant _Z = null;
+
+ internal const string GROUP_SIZE_X_STRING = "group_size_x";
+ internal const string GROUP_SIZE_Y_STRING = "group_size_y";
+ internal const string GROUP_SIZE_Z_STRING = "group_size_z";
+
+ internal static Constant _GROUP_SIZE_X = null;
+ internal static Constant _GROUP_SIZE_Y = null;
+ internal static Constant _GROUP_SIZE_Z = null;
+
+ internal const string GROUP_ID_X_STRING = "group_id_x";
+ internal const string GROUP_ID_Y_STRING = "group_id_y";
+ internal const string GROUP_ID_Z_STRING = "group_id_z";
+
+ internal static Constant _GROUP_X = null;
+ internal static Constant _GROUP_Y = null;
+ internal static Constant _GROUP_Z = null;
+
+ internal const string NUM_GROUPS_X_STRING = "num_groups_x";
+ internal const string NUM_GROUPS_Y_STRING = "num_groups_y";
+ internal const string NUM_GROUPS_Z_STRING = "num_groups_z";
+
+ internal static Constant _NUM_GROUPS_X = null;
+ internal static Constant _NUM_GROUPS_Y = null;
+ internal static Constant _NUM_GROUPS_Z = null;
+
+ public IRaceInstrumenter RaceInstrumenter;
+
+ public UniformityAnalyser uniformityAnalyser;
+ public MayBePowerOfTwoAnalyser mayBePowerOfTwoAnalyser;
+ public LiveVariableAnalyser liveVariableAnalyser;
+ public ArrayControlFlowAnalyser arrayControlFlowAnalyser;
+ public Dictionary<Implementation, VariableDefinitionAnalysis> varDefAnalyses;
+ public Dictionary<Implementation, ReducedStrengthAnalysis> reducedStrengthAnalyses;
+
+ public GPUVerifier(string filename, Program program, ResolutionContext rc, IRaceInstrumenter raceInstrumenter) : this(filename, program, rc, raceInstrumenter, false)
+ {
+ }
+
+ public GPUVerifier(string filename, Program program, ResolutionContext rc, IRaceInstrumenter raceInstrumenter, bool skipCheck)
+ : base((IErrorSink)null)
+ {
+ this.outputFilename = filename;
+ this.Program = program;
+ this.ResContext = rc;
+ this.RaceInstrumenter = raceInstrumenter;
+ if(!skipCheck)
+ CheckWellFormedness();
+ }
+
+ public void setRaceInstrumenter(IRaceInstrumenter ri)
+ {
+ this.RaceInstrumenter = ri;
+ }
+
+ private void CheckWellFormedness()
+ {
+ int errorCount = Check();
+ if (errorCount != 0)
+ {
+ Console.WriteLine("{0} GPUVerify format errors detected in {1}", errorCount, CommandLineOptions.inputFiles[CommandLineOptions.inputFiles.Count - 1]);
+ Environment.Exit(1);
+ }
+ }
+
+ private Procedure CheckExactlyOneKernelProcedure()
+ {
+ var p = CheckSingleInstanceOfAttributedProcedure("kernel");
+ if (p == null)
+ {
+ Error(Program, "\"kernel\" attribute has not been specified for any procedure. You must mark exactly one procedure with this attribute");
+ }
+
+ return p;
+ }
+
+ private Procedure FindOrCreateBarrierProcedure()
+ {
+ var p = CheckSingleInstanceOfAttributedProcedure("barrier");
+ if (p == null)
+ {
+ p = new Procedure(Token.NoToken, "barrier", new TypeVariableSeq(),
+ new VariableSeq(new Variable[] {
+ new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "__local_fence", new BvType(1)), true),
+ new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "__global_fence", new BvType(1)), true) }),
+ new VariableSeq(),
+ new RequiresSeq(), new IdentifierExprSeq(),
+ new EnsuresSeq(),
+ new QKeyValue(Token.NoToken, "barrier", new List<object>(), null));
+ Program.TopLevelDeclarations.Add(p);
+ ResContext.AddProcedure(p);
+ }
+ return p;
+ }
+
+ private Procedure CheckSingleInstanceOfAttributedProcedure(string attribute)
+ {
+ Procedure attributedProcedure = null;
+
+ foreach (Declaration decl in Program.TopLevelDeclarations)
+ {
+ if (!QKeyValue.FindBoolAttribute(decl.Attributes, attribute))
+ {
+ continue;
+ }
+
+ if (decl is Implementation)
+ {
+ continue;
+ }
+
+ if (decl is Procedure)
+ {
+ if (attributedProcedure == null)
+ {
+ attributedProcedure = decl as Procedure;
+ }
+ else
+ {
+ Error(decl, "\"{0}\" attribute specified for procedure {1}, but it has already been specified for procedure {2}", attribute, (decl as Procedure).Name, attributedProcedure.Name);
+ }
+
+ }
+ else
+ {
+ Error(decl, "\"{0}\" attribute can only be applied to a procedure", attribute);
+ }
+ }
+
+ return attributedProcedure;
+ }
+
+ private void CheckLocalVariables()
+ {
+ foreach (LocalVariable LV in KernelImplementation.LocVars)
+ {
+ if (QKeyValue.FindBoolAttribute(LV.Attributes, "group_shared"))
+ {
+ Error(LV.tok, "Local variable must not be marked 'group_shared' -- promote the variable to global scope");
+ }
+ }
+ }
+
+
+ private void ReportMultipleAttributeError(string attribute, IToken first, IToken second)
+ {
+ Error(
+ second,
+ "Can only have one {0} attribute, but previously saw this attribute at ({1}, {2})",
+ attribute,
+ first.filename,
+ first.line, first.col - 1);
+ }
+
+ private bool setConstAttributeField(Constant constInProgram, string attr, ref Constant constFieldRef)
+ {
+ if (QKeyValue.FindBoolAttribute(constInProgram.Attributes, attr))
+ {
+ if (constFieldRef != null)
+ {
+ ReportMultipleAttributeError(attr, constFieldRef.tok, constInProgram.tok);
+ return false;
+ }
+ CheckSpecialConstantType(constInProgram);
+ constFieldRef = constInProgram;
+ }
+ return true;
+ }
+
+ private void MaybeCreateAttributedConst(string attr, ref Constant constFieldRef)
+ {
+ if (constFieldRef == null)
+ {
+ constFieldRef = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, attr, Microsoft.Boogie.Type.GetBvType(32)), /*unique=*/false);
+ constFieldRef.AddAttribute(attr);
+ Program.TopLevelDeclarations.Add(constFieldRef);
+ }
+ }
+
+ private bool FindNonLocalVariables()
+ {
+ bool success = true;
+ foreach (Declaration D in Program.TopLevelDeclarations)
+ {
+ if (D is Variable &&
+ (D as Variable).IsMutable &&
+ (D as Variable).TypedIdent.Type is MapType &&
+ !ReservedNames.Contains((D as Variable).Name))
+ {
+ if (QKeyValue.FindBoolAttribute(D.Attributes, "group_shared"))
+ {
+ KernelArrayInfo.getGroupSharedArrays().Add(D as Variable);
+ }
+ else if (QKeyValue.FindBoolAttribute(D.Attributes, "global"))
+ {
+ KernelArrayInfo.getGlobalArrays().Add(D as Variable);
+ }
+ else
+ {
+ KernelArrayInfo.getPrivateArrays().Add(D as Variable);
+ }
+ }
+ else if (D is Constant)
+ {
+ Constant C = D as Constant;
+
+ success &= setConstAttributeField(C, LOCAL_ID_X_STRING, ref _X);
+ success &= setConstAttributeField(C, LOCAL_ID_Y_STRING, ref _Y);
+ success &= setConstAttributeField(C, LOCAL_ID_Z_STRING, ref _Z);
+
+ success &= setConstAttributeField(C, GROUP_SIZE_X_STRING, ref _GROUP_SIZE_X);
+ success &= setConstAttributeField(C, GROUP_SIZE_Y_STRING, ref _GROUP_SIZE_Y);
+ success &= setConstAttributeField(C, GROUP_SIZE_Z_STRING, ref _GROUP_SIZE_Z);
+
+ success &= setConstAttributeField(C, GROUP_ID_X_STRING, ref _GROUP_X);
+ success &= setConstAttributeField(C, GROUP_ID_Y_STRING, ref _GROUP_Y);
+ success &= setConstAttributeField(C, GROUP_ID_Z_STRING, ref _GROUP_Z);
+
+ success &= setConstAttributeField(C, NUM_GROUPS_X_STRING, ref _NUM_GROUPS_X);
+ success &= setConstAttributeField(C, NUM_GROUPS_Y_STRING, ref _NUM_GROUPS_Y);
+ success &= setConstAttributeField(C, NUM_GROUPS_Z_STRING, ref _NUM_GROUPS_Z);
+
+
+ }
+ }
+
+ MaybeCreateAttributedConst(LOCAL_ID_X_STRING, ref _X);
+ MaybeCreateAttributedConst(LOCAL_ID_Y_STRING, ref _Y);
+ MaybeCreateAttributedConst(LOCAL_ID_Z_STRING, ref _Z);
+
+ MaybeCreateAttributedConst(GROUP_SIZE_X_STRING, ref _GROUP_SIZE_X);
+ MaybeCreateAttributedConst(GROUP_SIZE_Y_STRING, ref _GROUP_SIZE_Y);
+ MaybeCreateAttributedConst(GROUP_SIZE_Z_STRING, ref _GROUP_SIZE_Z);
+
+ MaybeCreateAttributedConst(GROUP_ID_X_STRING, ref _GROUP_X);
+ MaybeCreateAttributedConst(GROUP_ID_Y_STRING, ref _GROUP_Y);
+ MaybeCreateAttributedConst(GROUP_ID_Z_STRING, ref _GROUP_Z);
+
+ MaybeCreateAttributedConst(NUM_GROUPS_X_STRING, ref _NUM_GROUPS_X);
+ MaybeCreateAttributedConst(NUM_GROUPS_Y_STRING, ref _NUM_GROUPS_Y);
+ MaybeCreateAttributedConst(NUM_GROUPS_Z_STRING, ref _NUM_GROUPS_Z);
+
+ return success;
+ }
+
+ private void CheckSpecialConstantType(Constant C)
+ {
+ if (!(C.TypedIdent.Type.Equals(Microsoft.Boogie.Type.Int) || C.TypedIdent.Type.Equals(Microsoft.Boogie.Type.GetBvType(32))))
+ {
+ Error(C.tok, "Special constant '" + C.Name + "' must have type 'int' or 'bv32'");
+ }
+ }
+
+ private void GetKernelImplementation()
+ {
+ foreach (Declaration decl in Program.TopLevelDeclarations)
+ {
+ if (!(decl is Implementation))
+ {
+ continue;
+ }
+
+ Implementation Impl = decl as Implementation;
+
+ if (Impl.Proc == KernelProcedure)
+ {
+ KernelImplementation = Impl;
+ break;
+ }
+
+ }
+
+ if (KernelImplementation == null)
+ {
+ Error(Token.NoToken, "*** Error: no implementation of kernel procedure");
+ }
+ }
+
+
+
+
+ protected virtual void CheckKernelImplementation()
+ {
+ CheckKernelParameters();
+ GetKernelImplementation();
+
+ if (KernelImplementation == null)
+ {
+ return;
+ }
+
+ CheckLocalVariables();
+ CheckNoReturns();
+ }
+
+ private void CheckNoReturns()
+ {
+ // TODO!
+ }
+
+ internal void preProcess()
+ {
+ RemoveRedundantReturns();
+
+ RemoveElseIfs();
+
+ PullOutNonLocalAccesses();
+ }
+
+ private void MergeBlocksIntoPredecessors()
+ {
+ foreach (var impl in Program.TopLevelDeclarations.OfType<Implementation>())
+ VC.VCGen.MergeBlocksIntoPredecessors(Program, impl);
+ }
+
+ internal void doit()
+ {
+ File.Delete(Path.GetFileNameWithoutExtension(CommandLineOptions.inputFiles[0]) + ".loc");
+ if (CommandLineOptions.Unstructured)
+ {
+ Microsoft.Boogie.CommandLineOptions.Clo.PrintUnstructured = 2;
+ }
+
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_original");
+ }
+
+ preProcess();
+
+ if (CommandLineOptions.ShowStages) {
+ emitProgram(outputFilename + "_preprocessed");
+ }
+
+ DoLiveVariableAnalysis();
+
DoUniformityAnalysis();
- DoVariableDefinitionAnalysis();
-
- DoReducedStrengthAnalysis();
-
- DoMayBePowerOfTwoAnalysis();
-
- DoArrayControlFlowAnalysis();
-
- if (CommandLineOptions.ShowStages)
- {
- emitProgram(outputFilename + "_preprocessed");
- }
-
- if (CommandLineOptions.Inference)
- {
- foreach (var impl in Program.TopLevelDeclarations.OfType<Implementation>().ToList())
- {
- LoopInvariantGenerator.PreInstrument(this, impl);
- }
- }
-
- if (RaceInstrumenter.AddRaceCheckingInstrumentation() == false)
- {
- return;
- }
-
- if (CommandLineOptions.ShowStages)
- {
- emitProgram(outputFilename + "_instrumented");
- }
-
- AbstractSharedState();
-
- if (CommandLineOptions.ShowStages)
- {
- emitProgram(outputFilename + "_abstracted");
- }
-
- MergeBlocksIntoPredecessors();
-
- if (CommandLineOptions.ShowStages)
- {
- emitProgram(outputFilename + "_merged_pre_predication");
- }
-
- MakeKernelPredicated();
-
- if (CommandLineOptions.ShowStages)
- {
- emitProgram(outputFilename + "_predicated");
- }
-
- MergeBlocksIntoPredecessors();
-
- if (CommandLineOptions.ShowStages)
- {
- emitProgram(outputFilename + "_merged_post_predication");
- }
-
- MakeKernelDualised();
-
- if (CommandLineOptions.ShowStages)
- {
- emitProgram(outputFilename + "_dualised");
- }
-
- if (CommandLineOptions.ShowStages)
- {
- emitProgram(outputFilename + "_cross_thread_invariants");
- }
-
- RaceInstrumenter.AddRaceCheckingDeclarations();
-
- GenerateBarrierImplementation();
-
- GenerateStandardKernelContract();
-
- if (CommandLineOptions.ShowStages)
- {
- emitProgram(outputFilename + "_ready_to_verify");
- }
-
- if (CommandLineOptions.Inference)
- {
- ComputeInvariant();
- }
-
- emitProgram(outputFilename);
-
-
- if (CommandLineOptions.DividedAccesses)
- {
-
- Program p = GPUVerify.ParseBoogieProgram(new List<string>(new string[] { outputFilename + ".bpl" }), true);
- ResolutionContext rc = new ResolutionContext(null);
- p.Resolve(rc);
- p.Typecheck();
-
- Contract.Assert(p != null);
-
- Implementation impl = null;
-
- {
- GPUVerifier tempGPUV = new GPUVerifier("not_used", p, rc, new NullRaceInstrumenter(), true);
- tempGPUV.KernelProcedure = tempGPUV.CheckExactlyOneKernelProcedure();
- tempGPUV.GetKernelImplementation();
- impl = tempGPUV.KernelImplementation;
- }
-
- Contract.Assert(impl != null);
-
- NoConflictingAccessOptimiser opt = new NoConflictingAccessOptimiser(impl);
- Contract.Assert(opt.NumLogCalls() <= 2);
- if (opt.NumLogCalls() == 2 && !opt.HasConflicting())
- {
- FileInfo f = new FileInfo(outputFilename);
-
- string newName = f.Directory.FullName + "\\" + "NO_CONFLICTS_" + f.Name + ".bpl";
- //File.Delete(newName);
- if (File.Exists(newName))
- {
- File.Delete(newName);
- }
- File.Move(outputFilename + ".bpl", newName);
- //Console.WriteLine("Renamed " + ouputFilename + "; no conflicting accesses (that are not already tested by other output files).");
- }
-
-
- }
-
- }
-
- private void DoMayBePowerOfTwoAnalysis()
- {
- mayBePowerOfTwoAnalyser = new MayBePowerOfTwoAnalyser(this);
- mayBePowerOfTwoAnalyser.Analyse();
- }
-
- private void DoArrayControlFlowAnalysis()
- {
- arrayControlFlowAnalyser = new ArrayControlFlowAnalyser(this);
- arrayControlFlowAnalyser.Analyse();
- }
-
- private void DoUniformityAnalysis()
- {
- uniformityAnalyser = new UniformityAnalyser(this);
- uniformityAnalyser.Analyse();
- }
-
- private void DoLiveVariableAnalysis()
- {
- liveVariableAnalyser = new LiveVariableAnalyser(this);
- liveVariableAnalyser.Analyse();
- }
-
- private void DoVariableDefinitionAnalysis()
- {
- varDefAnalyses = Program.TopLevelDeclarations
- .OfType<Implementation>()
- .ToDictionary(i => i, i => VariableDefinitionAnalysis.Analyse(this, i));
- }
-
- private void DoReducedStrengthAnalysis()
- {
- reducedStrengthAnalyses = Program.TopLevelDeclarations
- .OfType<Implementation>()
- .ToDictionary(i => i, i => ReducedStrengthAnalysis.Analyse(this, i));
- }
-
- private void emitProgram(string filename)
- {
- using (TokenTextWriter writer = new TokenTextWriter(filename + ".bpl"))
- {
- Program.Emit(writer);
- }
- }
-
- private void ComputeInvariant()
- {
- for (int i = 0; i < Program.TopLevelDeclarations.Count; i++)
- {
- if (Program.TopLevelDeclarations[i] is Implementation)
- {
-
- Implementation Impl = Program.TopLevelDeclarations[i] as Implementation;
-
- List<Expr> UserSuppliedInvariants = GetUserSuppliedInvariants(Impl.Name);
-
- LoopInvariantGenerator.PostInstrument(this, Impl, UserSuppliedInvariants);
-
- Procedure Proc = Impl.Proc;
-
- if (QKeyValue.FindIntAttribute(Proc.Attributes, "inline", -1) == 1)
- {
- continue;
- }
-
- if (Proc == KernelProcedure)
- {
- continue;
- }
-
- AddCandidateRequires(Proc);
- RaceInstrumenter.AddRaceCheckingCandidateRequires(Proc);
- AddUserSuppliedCandidateRequires(Proc, UserSuppliedInvariants);
-
- AddCandidateEnsures(Proc);
- RaceInstrumenter.AddRaceCheckingCandidateEnsures(Proc);
- AddUserSuppliedCandidateEnsures(Proc, UserSuppliedInvariants);
-
- }
-
-
- }
-
- }
-
- private void AddCandidateEnsures(Procedure Proc)
- {
- HashSet<string> names = new HashSet<String>();
- foreach (Variable v in Proc.OutParams)
- {
- names.Add(StripThreadIdentifier(v.Name));
- }
-
- foreach (string name in names)
- {
- if (!uniformityAnalyser.IsUniform(Proc.Name, name))
- {
- AddEqualityCandidateEnsures(Proc, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, name, Microsoft.Boogie.Type.Int)));
- }
- }
-
- }
-
- private void AddCandidateRequires(Procedure Proc)
- {
- HashSet<string> names = new HashSet<String>();
- foreach (Variable v in Proc.InParams)
- {
- names.Add(StripThreadIdentifier(v.Name));
- }
-
- foreach (string name in names)
- {
-
- if (IsPredicateOrTemp(name))
- {
- Debug.Assert(name.Equals("_P"));
- Debug.Assert(!uniformityAnalyser.IsUniform(Proc.Name));
- AddCandidateRequires(Proc, Expr.Eq(
- new IdentifierExpr(Proc.tok, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, name + "$1", Microsoft.Boogie.Type.Bool))),
- new IdentifierExpr(Proc.tok, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, name + "$2", Microsoft.Boogie.Type.Bool)))
- ));
- }
- else
- {
- if (!uniformityAnalyser.IsUniform(Proc.Name, name))
- {
- if (!uniformityAnalyser.IsUniform(Proc.Name))
- {
- AddPredicatedEqualityCandidateRequires(Proc, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, name, Microsoft.Boogie.Type.Int)));
- }
- AddEqualityCandidateRequires(Proc, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, name, Microsoft.Boogie.Type.Int)));
- }
- }
- }
-
- }
-
- private void AddPredicatedEqualityCandidateRequires(Procedure Proc, Variable v)
- {
- AddCandidateRequires(Proc, Expr.Imp(
- Expr.And(
- new IdentifierExpr(Proc.tok, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, "_P$1", Microsoft.Boogie.Type.Bool))),
- new IdentifierExpr(Proc.tok, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, "_P$2", Microsoft.Boogie.Type.Bool)))
- ),
- Expr.Eq(
- new IdentifierExpr(Proc.tok, new VariableDualiser(1, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable)),
- new IdentifierExpr(Proc.tok, new VariableDualiser(2, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable))
- )
- ));
- }
-
- private void AddEqualityCandidateRequires(Procedure Proc, Variable v)
- {
- AddCandidateRequires(Proc,
- Expr.Eq(
- new IdentifierExpr(Proc.tok, new VariableDualiser(1, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable)),
- new IdentifierExpr(Proc.tok, new VariableDualiser(2, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable))
- )
- );
- }
-
- private void AddEqualityCandidateEnsures(Procedure Proc, Variable v)
- {
- AddCandidateEnsures(Proc,
- Expr.Eq(
- new IdentifierExpr(Proc.tok, new VariableDualiser(1, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable)),
- new IdentifierExpr(Proc.tok, new VariableDualiser(2, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable))
- ));
- }
-
-
- private void AddUserSuppliedCandidateRequires(Procedure Proc, List<Expr> UserSuppliedInvariants)
- {
- foreach (Expr e in UserSuppliedInvariants)
- {
- Requires r = new Requires(false, e);
- Proc.Requires.Add(r);
- bool OK = ProgramIsOK(Proc);
- Proc.Requires.Remove(r);
- if (OK)
- {
- AddCandidateRequires(Proc, e);
- }
- }
- }
-
- private void AddUserSuppliedCandidateEnsures(Procedure Proc, List<Expr> UserSuppliedInvariants)
- {
- foreach (Expr e in UserSuppliedInvariants)
- {
- Ensures ens = new Ensures(false, e);
- Proc.Ensures.Add(ens);
- bool OK = ProgramIsOK(Proc);
- Proc.Ensures.Remove(ens);
- if (OK)
- {
- AddCandidateEnsures(Proc, e);
- }
- }
- }
-
-
-
- internal void AddCandidateRequires(Procedure Proc, Expr e)
- {
- Constant ExistentialBooleanConstant = Program.MakeExistentialBoolean();
- IdentifierExpr ExistentialBoolean = new IdentifierExpr(Proc.tok, ExistentialBooleanConstant);
- Proc.Requires.Add(new Requires(false, Expr.Imp(ExistentialBoolean, e)));
- }
-
- internal void AddCandidateEnsures(Procedure Proc, Expr e)
- {
- Constant ExistentialBooleanConstant = Program.MakeExistentialBoolean();
- IdentifierExpr ExistentialBoolean = new IdentifierExpr(Proc.tok, ExistentialBooleanConstant);
- Proc.Ensures.Add(new Ensures(false, Expr.Imp(ExistentialBoolean, e)));
- }
-
- private List<Expr> GetUserSuppliedInvariants(string ProcedureName)
- {
- List<Expr> result = new List<Expr>();
-
- if (CommandLineOptions.invariantsFile == null)
- {
- return result;
- }
-
- StreamReader sr = new StreamReader(new FileStream(CommandLineOptions.invariantsFile, FileMode.Open, FileAccess.Read));
- string line;
- int lineNumber = 1;
- while ((line = sr.ReadLine()) != null)
- {
- string[] components = line.Split(':');
-
- if (components.Length != 1 && components.Length != 2)
- {
- Console.WriteLine("Ignoring badly formed candidate invariant '" + line + "' at '" + CommandLineOptions.invariantsFile + "' line " + lineNumber);
- continue;
- }
-
- if (components.Length == 2)
- {
- if (!components[0].Trim().Equals(ProcedureName))
- {
- continue;
- }
-
- line = components[1];
- }
-
- string temp_program_text = "axiom (" + line + ");";
- TokenTextWriter writer = new TokenTextWriter("temp_out.bpl");
- writer.WriteLine(temp_program_text);
- writer.Close();
-
- Program temp_program = GPUVerify.ParseBoogieProgram(new List<string>(new string[] { "temp_out.bpl" }), false);
-
- if (null == temp_program)
- {
- Console.WriteLine("Ignoring badly formed candidate invariant '" + line + "' at '" + CommandLineOptions.invariantsFile + "' line " + lineNumber);
- }
- else
- {
- Debug.Assert(temp_program.TopLevelDeclarations[0] is Axiom);
- result.Add((temp_program.TopLevelDeclarations[0] as Axiom).Expr);
- }
-
- lineNumber++;
- }
-
- return result;
- }
-
- internal bool ContainsNamedVariable(HashSet<Variable> variables, string name)
- {
- foreach(Variable v in variables)
- {
- if(StripThreadIdentifier(v.Name) == name)
- {
- return true;
- }
- }
- return false;
- }
-
-
- internal static bool IsPredicateOrTemp(string lv)
- {
- return (lv.Length >= 2 && lv.Substring(0,2).Equals("_P")) ||
- (lv.Length > 3 && lv.Substring(0,3).Equals("_LC")) ||
- (lv.Length > 5 && lv.Substring(0,5).Equals("_temp"));
- }
-
-
-
-
- internal bool ProgramIsOK(Declaration d)
- {
- Debug.Assert(d is Procedure || d is Implementation);
- TokenTextWriter writer = new TokenTextWriter("temp_out.bpl");
- List<Declaration> RealDecls = Program.TopLevelDeclarations;
- List<Declaration> TempDecls = new List<Declaration>();
- foreach (Declaration d2 in RealDecls)
- {
- if (d is Procedure)
- {
- if ((d == d2) || !(d2 is Implementation || d2 is Procedure))
- {
- TempDecls.Add(d2);
- }
- }
- else if (d is Implementation)
- {
- if ((d == d2) || !(d2 is Implementation))
- {
- TempDecls.Add(d2);
- }
- }
- }
- Program.TopLevelDeclarations = TempDecls;
- Program.Emit(writer);
- writer.Close();
- Program.TopLevelDeclarations = RealDecls;
- Program temp_program = GPUVerify.ParseBoogieProgram(new List<string>(new string[] { "temp_out.bpl" }), false);
-
- if (temp_program == null)
- {
- return false;
- }
-
- if (temp_program.Resolve() != 0)
- {
- return false;
- }
-
- if (temp_program.Typecheck() != 0)
- {
- return false;
- }
- return true;
- }
-
-
-
- public Microsoft.Boogie.Type GetTypeOfIdX()
- {
- Contract.Requires(_X != null);
- return _X.TypedIdent.Type;
- }
-
- public Microsoft.Boogie.Type GetTypeOfIdY()
- {
- Contract.Requires(_Y != null);
- return _Y.TypedIdent.Type;
- }
-
- public Microsoft.Boogie.Type GetTypeOfIdZ()
- {
- Contract.Requires(_Z != null);
- return _Z.TypedIdent.Type;
- }
-
- public Microsoft.Boogie.Type GetTypeOfId(string dimension)
- {
- Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
- if (dimension.Equals("X")) return GetTypeOfIdX();
- if (dimension.Equals("Y")) return GetTypeOfIdY();
- if (dimension.Equals("Z")) return GetTypeOfIdZ();
- Debug.Assert(false);
- return null;
- }
-
- public bool KernelHasIdX()
- {
- return _X != null;
- }
-
- public bool KernelHasIdY()
- {
- return _Y != null;
- }
-
- public bool KernelHasIdZ()
- {
- return _Z != null;
- }
-
- public bool KernelHasGroupIdX()
- {
- return _GROUP_X != null;
- }
-
- public bool KernelHasGroupIdY()
- {
- return _GROUP_Y != null;
- }
-
- public bool KernelHasGroupIdZ()
- {
- return _GROUP_Z != null;
- }
-
- public bool KernelHasNumGroupsX()
- {
- return _NUM_GROUPS_X != null;
- }
-
- public bool KernelHasNumGroupsY()
- {
- return _NUM_GROUPS_Y != null;
- }
-
- public bool KernelHasNumGroupsZ()
- {
- return _NUM_GROUPS_Z != null;
- }
-
- public bool KernelHasGroupSizeX()
- {
- return _GROUP_SIZE_X != null;
- }
-
- public bool KernelHasGroupSizeY()
- {
- return _GROUP_SIZE_Y != null;
- }
-
- public bool KernelHasGroupSizeZ()
- {
- return _GROUP_SIZE_Z != null;
- }
-
- internal static string StripThreadIdentifier(string p, out int id)
- {
- if (p.EndsWith("$1"))
- {
- id = 1;
- return p.Substring(0, p.Length - 2);
- }
- if (p.EndsWith("$2"))
- {
- id = 2;
- return p.Substring(0, p.Length - 2);
- }
-
- id = 0;
- return p;
- }
-
- internal static string StripThreadIdentifier(string p)
- {
- int id;
- return StripThreadIdentifier(p, out id);
- }
-
- private void GenerateStandardKernelContract()
- {
- RaceInstrumenter.AddKernelPrecondition();
-
- IToken tok = KernelImplementation.tok;
-
- GeneratePreconditionsForDimension(tok, "X");
- GeneratePreconditionsForDimension(tok, "Y");
- GeneratePreconditionsForDimension(tok, "Z");
-
- foreach (Declaration D in Program.TopLevelDeclarations)
- {
- if (!(D is Procedure))
- {
- continue;
- }
- Procedure Proc = D as Procedure;
- if (QKeyValue.FindIntAttribute(Proc.Attributes, "inline", -1) == 1)
- {
- continue;
- }
-
- Expr DistinctLocalIds =
- Expr.Or(
- Expr.Or(
- Expr.Neq(
- new IdentifierExpr(tok, MakeThreadId(tok, "X", 1)),
- new IdentifierExpr(tok, MakeThreadId(tok, "X", 2))
- ),
- Expr.Neq(
- new IdentifierExpr(tok, MakeThreadId(tok, "Y", 1)),
- new IdentifierExpr(tok, MakeThreadId(tok, "Y", 2))
- )
- ),
- Expr.Neq(
- new IdentifierExpr(tok, MakeThreadId(tok, "Z", 1)),
- new IdentifierExpr(tok, MakeThreadId(tok, "Z", 2))
- )
- );
-
- Proc.Requires.Add(new Requires(false, Expr.Imp(ThreadsInSameGroup(), DistinctLocalIds)));
-
- if (CommandLineOptions.OnlyIntraGroupRaceChecking)
- {
- Proc.Requires.Add(new Requires(false, ThreadsInSameGroup()));
- }
-
- if (Proc == KernelProcedure)
- {
- bool foundNonUniform = false;
- int indexOfFirstNonUniformParameter;
- for (indexOfFirstNonUniformParameter = 0; indexOfFirstNonUniformParameter < Proc.InParams.Length; indexOfFirstNonUniformParameter++)
- {
- if (!uniformityAnalyser.IsUniform(Proc.Name, StripThreadIdentifier(Proc.InParams[indexOfFirstNonUniformParameter].Name)))
- {
- foundNonUniform = true;
- break;
- }
- }
-
- if (foundNonUniform)
- {
- // I have a feeling this will never be reachable!!!
- int numberOfNonUniformParameters = (Proc.InParams.Length - indexOfFirstNonUniformParameter) / 2;
- for (int i = indexOfFirstNonUniformParameter; i < numberOfNonUniformParameters; i++)
- {
- Proc.Requires.Add(new Requires(false,
- Expr.Eq(new IdentifierExpr(Proc.InParams[i].tok, Proc.InParams[i]),
- new IdentifierExpr(Proc.InParams[i + numberOfNonUniformParameters].tok, Proc.InParams[i + numberOfNonUniformParameters]))));
- }
- }
- }
-
- }
-
- foreach (Declaration D in Program.TopLevelDeclarations)
- {
- if (!(D is Implementation))
- {
- continue;
- }
- Implementation Impl = D as Implementation;
-
- if (QKeyValue.FindIntAttribute(Impl.Proc.Attributes, "inline", -1) == 1)
- {
- continue;
- }
- if (Impl.Proc == KernelProcedure)
- {
- continue;
- }
-
- new EnsureDisabledThreadHasNoEffectInstrumenter(this, Impl).instrument();
-
- }
-
- }
-
- internal Expr ThreadsInSameGroup()
- {
- return Expr.And(
- Expr.And(
- Expr.Eq(
- new IdentifierExpr(Token.NoToken, MakeGroupId("X", 1)),
- new IdentifierExpr(Token.NoToken, MakeGroupId("X", 2))
- ),
- Expr.Eq(
- new IdentifierExpr(Token.NoToken, MakeGroupId("Y", 1)),
- new IdentifierExpr(Token.NoToken, MakeGroupId("Y", 2))
- )
- ),
- Expr.Eq(
- new IdentifierExpr(Token.NoToken, MakeGroupId("Z", 1)),
- new IdentifierExpr(Token.NoToken, MakeGroupId("Z", 2))
- )
- );
- }
-
- internal static void AddInvariantToAllLoops(Expr Invariant, StmtList stmtList)
- {
- foreach (BigBlock bb in stmtList.BigBlocks)
- {
- AddInvariantToAllLoops(Invariant, bb);
- }
- }
-
- internal static void AddInvariantToAllLoops(Expr Invariant, BigBlock bb)
- {
- if (bb.ec is WhileCmd)
- {
- WhileCmd wc = bb.ec as WhileCmd;
- wc.Invariants.Add(new AssertCmd(wc.tok, Invariant));
- AddInvariantToAllLoops(Invariant, wc.Body);
- }
- Debug.Assert(!(bb.ec is IfCmd));
- }
-
- internal static int GetThreadSuffix(string p)
- {
- return Int32.Parse(p.Substring(p.IndexOf("$") + 1, p.Length - (p.IndexOf("$") + 1)));
- }
-
- private void GeneratePreconditionsForDimension(IToken tok, String dimension)
- {
- foreach (Declaration D in Program.TopLevelDeclarations.ToList())
- {
- if (!(D is Procedure))
- {
- continue;
- }
- Procedure Proc = D as Procedure;
- if (QKeyValue.FindIntAttribute(Proc.Attributes, "inline", -1) == 1)
- {
- continue;
- }
-
- Expr GroupSizePositive;
- Expr NumGroupsPositive;
- Expr GroupIdNonNegative;
- Expr GroupIdLessThanNumGroups;
-
- if (GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)))
- {
- GroupSizePositive = MakeBVSgt(new IdentifierExpr(tok, GetGroupSize(dimension)), ZeroBV());
- NumGroupsPositive = MakeBVSgt(new IdentifierExpr(tok, GetNumGroups(dimension)), ZeroBV());
- GroupIdNonNegative = MakeBVSge(new IdentifierExpr(tok, GetGroupId(dimension)), ZeroBV());
- GroupIdLessThanNumGroups = MakeBVSlt(new IdentifierExpr(tok, GetGroupId(dimension)), new IdentifierExpr(tok, GetNumGroups(dimension)));
- }
- else
- {
- GroupSizePositive = Expr.Gt(new IdentifierExpr(tok, GetGroupSize(dimension)), Zero());
- NumGroupsPositive = Expr.Gt(new IdentifierExpr(tok, GetNumGroups(dimension)), Zero());
- GroupIdNonNegative = Expr.Ge(new IdentifierExpr(tok, GetGroupId(dimension)), Zero());
- GroupIdLessThanNumGroups = Expr.Lt(new IdentifierExpr(tok, GetGroupId(dimension)), new IdentifierExpr(tok, GetNumGroups(dimension)));
- }
-
- Proc.Requires.Add(new Requires(false, GroupSizePositive));
- Proc.Requires.Add(new Requires(false, NumGroupsPositive));
- Proc.Requires.Add(new Requires(false, new VariableDualiser(1, null, null).VisitExpr(GroupIdNonNegative)));
- Proc.Requires.Add(new Requires(false, new VariableDualiser(2, null, null).VisitExpr(GroupIdNonNegative)));
- Proc.Requires.Add(new Requires(false, new VariableDualiser(1, null, null).VisitExpr(GroupIdLessThanNumGroups)));
- Proc.Requires.Add(new Requires(false, new VariableDualiser(2, null, null).VisitExpr(GroupIdLessThanNumGroups)));
-
- Expr ThreadIdNonNegative =
- GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)) ?
- MakeBVSge(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), ZeroBV())
- :
- Expr.Ge(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), Zero());
- Expr ThreadIdLessThanGroupSize =
- GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)) ?
- MakeBVSlt(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), new IdentifierExpr(tok, GetGroupSize(dimension)))
- :
- Expr.Lt(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), new IdentifierExpr(tok, GetGroupSize(dimension)));
-
- Proc.Requires.Add(new Requires(false, new VariableDualiser(1, null, null).VisitExpr(ThreadIdNonNegative)));
- Proc.Requires.Add(new Requires(false, new VariableDualiser(2, null, null).VisitExpr(ThreadIdNonNegative)));
- Proc.Requires.Add(new Requires(false, new VariableDualiser(1, null, null).VisitExpr(ThreadIdLessThanGroupSize)));
- Proc.Requires.Add(new Requires(false, new VariableDualiser(2, null, null).VisitExpr(ThreadIdLessThanGroupSize)));
-
- }
-
- }
-
- private Function GetOrCreateBVFunction(string functionName, string smtName, Microsoft.Boogie.Type resultType, params Microsoft.Boogie.Type[] argTypes)
- {
- Function f = (Function)ResContext.LookUpProcedure(functionName);
- if (f != null)
- return f;
-
- f = new Function(Token.NoToken, functionName,
- new VariableSeq(argTypes.Select(t => new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "", t))).ToArray()),
- new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "", resultType)));
- f.AddAttribute("bvbuiltin", smtName);
- Program.TopLevelDeclarations.Add(f);
- ResContext.AddProcedure(f);
- return f;
- }
-
- private Expr MakeBVFunctionCall(string functionName, string smtName, Microsoft.Boogie.Type resultType, params Expr[] args)
- {
- Function f = GetOrCreateBVFunction(functionName, smtName, resultType, args.Select(a => a.Type).ToArray());
- var e = new NAryExpr(Token.NoToken, new FunctionCall(f), new ExprSeq(args));
- e.Type = resultType;
- return e;
- }
-
- private Expr MakeBitVectorBinaryBoolean(string suffix, string smtName, Expr lhs, Expr rhs)
- {
- return MakeBVFunctionCall("BV" + lhs.Type.BvBits + "_" + suffix, smtName, Microsoft.Boogie.Type.Bool, lhs, rhs);
- }
-
- private Expr MakeBitVectorBinaryBitVector(string suffix, string smtName, Expr lhs, Expr rhs)
- {
- return MakeBVFunctionCall("BV" + lhs.Type.BvBits + "_" + suffix, smtName, lhs.Type, lhs, rhs);
- }
-
- internal Expr MakeBVSlt(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBoolean("SLT", "bvslt", lhs, rhs); }
- internal Expr MakeBVSgt(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBoolean("SGT", "bvsgt", lhs, rhs); }
- internal Expr MakeBVSge(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBoolean("SGE", "bvsge", lhs, rhs); }
-
- internal Expr MakeBVAnd(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBitVector("AND", "bvand", lhs, rhs); }
- internal Expr MakeBVAdd(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBitVector("ADD", "bvadd", lhs, rhs); }
- internal Expr MakeBVSub(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBitVector("SUB", "bvsub", lhs, rhs); }
- internal Expr MakeBVMul(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBitVector("MUL", "bvmul", lhs, rhs); }
- internal Expr MakeBVURem(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBitVector("UREM", "bvurem", lhs, rhs); }
-
- internal static Expr MakeBitVectorBinaryBoolean(string functionName, Expr lhs, Expr rhs)
- {
- return new NAryExpr(lhs.tok, new FunctionCall(new Function(lhs.tok, functionName, new VariableSeq(new Variable[] {
- new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "arg1", Microsoft.Boogie.Type.GetBvType(32))),
- new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "arg2", Microsoft.Boogie.Type.GetBvType(32)))
- }), new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "result", Microsoft.Boogie.Type.Bool)))), new ExprSeq(new Expr[] { lhs, rhs }));
- }
-
- internal static Expr MakeBitVectorBinaryBitVector(string functionName, Expr lhs, Expr rhs)
- {
- return new NAryExpr(lhs.tok, new FunctionCall(new Function(lhs.tok, functionName, new VariableSeq(new Variable[] {
- new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "arg1", Microsoft.Boogie.Type.GetBvType(32))),
- new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "arg2", Microsoft.Boogie.Type.GetBvType(32)))
- }), new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "result", Microsoft.Boogie.Type.GetBvType(32))))), new ExprSeq(new Expr[] { lhs, rhs }));
- }
-
- private static bool IsBVFunctionCall(Expr e, string smtName, out ExprSeq args)
- {
- args = null;
- var ne = e as NAryExpr;
- if (ne == null)
- return false;
-
- var fc = ne.Fun as FunctionCall;
- if (fc == null)
- return false;
-
- string bvBuiltin = QKeyValue.FindStringAttribute(fc.Func.Attributes, "bvbuiltin");
- if (bvBuiltin == smtName)
- {
- args = ne.Args;
- return true;
- }
-
- return false;
- }
-
- private static bool IsBVFunctionCall(Expr e, string smtName, out Expr lhs, out Expr rhs)
- {
- ExprSeq es;
- if (IsBVFunctionCall(e, smtName, out es))
- {
- lhs = es[0]; rhs = es[1];
- return true;
- }
- lhs = null; rhs = null;
- return false;
- }
-
- internal static bool IsBVAdd(Expr e, out Expr lhs, out Expr rhs) { return IsBVFunctionCall(e, "bvadd", out lhs, out rhs); }
- internal static bool IsBVMul(Expr e, out Expr lhs, out Expr rhs) { return IsBVFunctionCall(e, "bvmul", out lhs, out rhs); }
-
- internal Constant GetGroupSize(string dimension)
- {
- Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
- if (dimension.Equals("X")) return _GROUP_SIZE_X;
- if (dimension.Equals("Y")) return _GROUP_SIZE_Y;
- if (dimension.Equals("Z")) return _GROUP_SIZE_Z;
- Debug.Assert(false);
- return null;
- }
-
- internal Constant GetNumGroups(string dimension)
- {
- Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
- if (dimension.Equals("X")) return _NUM_GROUPS_X;
- if (dimension.Equals("Y")) return _NUM_GROUPS_Y;
- if (dimension.Equals("Z")) return _NUM_GROUPS_Z;
- Debug.Assert(false);
- return null;
- }
-
- internal Constant MakeThreadId(IToken tok, string dimension)
- {
- Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
- string name = null;
- if (dimension.Equals("X")) name = _X.Name;
- if (dimension.Equals("Y")) name = _Y.Name;
- if (dimension.Equals("Z")) name = _Z.Name;
- Debug.Assert(name != null);
- return new Constant(tok, new TypedIdent(tok, name, GetTypeOfId(dimension)));
- }
-
- internal Constant MakeThreadId(IToken tok, string dimension, int number)
- {
- Constant resultWithoutThreadId = MakeThreadId(tok, dimension);
- return new Constant(tok, new TypedIdent(tok, resultWithoutThreadId.Name + "$" + number, GetTypeOfId(dimension)));
- }
-
- internal Constant GetGroupId(string dimension)
- {
- Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
- if (dimension.Equals("X")) return _GROUP_X;
- if (dimension.Equals("Y")) return _GROUP_Y;
- if (dimension.Equals("Z")) return _GROUP_Z;
- Debug.Assert(false);
- return null;
- }
-
- internal Constant MakeGroupId(string dimension, int number)
- {
- Constant resultWithoutThreadId = GetGroupId(dimension);
- return new Constant(Token.NoToken, new TypedIdent(Token.NoToken, resultWithoutThreadId.Name + "$" + number, GetTypeOfId(dimension)));
- }
-
- private static LiteralExpr Zero()
- {
- return new LiteralExpr(Token.NoToken, BigNum.FromInt(0));
- }
-
- internal static LiteralExpr ZeroBV()
- {
- return new LiteralExpr(Token.NoToken, BigNum.FromInt(0), 32);
- }
-
-
-
- private void GenerateBarrierImplementation()
- {
- IToken tok = BarrierProcedure.tok;
-
- List<BigBlock> bigblocks = new List<BigBlock>();
- BigBlock checkNonDivergence = new BigBlock(tok, "__BarrierImpl", new CmdSeq(), null, null);
- bigblocks.Add(checkNonDivergence);
-
- Debug.Assert((BarrierProcedure.InParams.Length % 2) == 0);
- int paramsPerThread = BarrierProcedure.InParams.Length / 2;
- IdentifierExpr P1 = new IdentifierExpr(tok, new LocalVariable(tok, BarrierProcedure.InParams[0].TypedIdent));
- IdentifierExpr P2 = new IdentifierExpr(tok, new LocalVariable(tok, BarrierProcedure.InParams[paramsPerThread].TypedIdent));
-
- IdentifierExpr Flags1 = new IdentifierExpr(tok, new LocalVariable(tok, BarrierProcedure.InParams[1].TypedIdent));
- IdentifierExpr Flags2 = new IdentifierExpr(tok, new LocalVariable(tok, BarrierProcedure.InParams[paramsPerThread + 1].TypedIdent));
-
- Expr DivergenceCondition = Expr.Imp(ThreadsInSameGroup(), Expr.Eq(P1, P2));
-
- checkNonDivergence.simpleCmds.Add(new AssertCmd(tok, DivergenceCondition));
-
- if (!CommandLineOptions.OnlyDivergence)
- {
- List<BigBlock> returnbigblocks = new List<BigBlock>();
- returnbigblocks.Add(new BigBlock(tok, "__Disabled", new CmdSeq(), null, new ReturnCmd(tok)));
- StmtList returnstatement = new StmtList(returnbigblocks, BarrierProcedure.tok);
-
- Expr IfGuard = Expr.Or(Expr.And(Expr.Not(P1), Expr.Not(P2)), Expr.And(ThreadsInSameGroup(), Expr.Or(Expr.Not(P1), Expr.Not(P2))));
- checkNonDivergence.ec = new IfCmd(tok, IfGuard, returnstatement, null, null);
- }
-
- if(KernelArrayInfo.getGroupSharedArrays().Count > 0) {
-
- Expr IfGuard1 = Expr.And(P1, CLK_LOCAL_MEM_FENCE_isSet(Flags1));
- Expr IfGuard2 = Expr.And(P2, CLK_LOCAL_MEM_FENCE_isSet(Flags2));
-
- bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(),
- new IfCmd(Token.NoToken, IfGuard1, new StmtList(MakeResetAndHavocBlocks(1, KernelArrayInfo.getGroupSharedArrays()), Token.NoToken), null, null),
- null));
- bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(),
- new IfCmd(Token.NoToken, IfGuard2, new StmtList(MakeResetAndHavocBlocks(2, KernelArrayInfo.getGroupSharedArrays()), Token.NoToken), null, null),
- null));
- }
-
- if (KernelArrayInfo.getGlobalArrays().Count > 0)
- {
- Expr IfGuard1 = Expr.And(P1, CLK_GLOBAL_MEM_FENCE_isSet(Flags1));
- Expr IfGuard2 = Expr.And(P2, CLK_GLOBAL_MEM_FENCE_isSet(Flags2));
-
- bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(),
- new IfCmd(Token.NoToken, IfGuard1, new StmtList(MakeResetAndHavocBlocks(1, KernelArrayInfo.getGlobalArrays()), Token.NoToken), null, null),
- null));
- bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(),
- new IfCmd(Token.NoToken, IfGuard2, new StmtList(MakeResetAndHavocBlocks(2, KernelArrayInfo.getGlobalArrays()), Token.NoToken), null, null),
- null));
- }
-
- foreach (Variable v in KernelArrayInfo.getAllNonLocalArrays())
- {
- if (!ArrayModelledAdversarially(v))
- {
- bigblocks.Add(AssumeEqualityBetweenSharedArrays(v, P1, P2, Flags1, Flags2));
- }
- }
-
- StmtList statements = new StmtList(bigblocks, BarrierProcedure.tok);
- Implementation BarrierImplementation =
- new Implementation(BarrierProcedure.tok, BarrierProcedure.Name, new TypeVariableSeq(),
- BarrierProcedure.InParams, BarrierProcedure.OutParams, new VariableSeq(), statements);
-
- if (CommandLineOptions.Unstructured)
- BarrierImplementation.Resolve(ResContext);
-
- BarrierImplementation.AddAttribute("inline", new object[] { new LiteralExpr(tok, BigNum.FromInt(1)) });
- BarrierProcedure.AddAttribute("inline", new object[] { new LiteralExpr(tok, BigNum.FromInt(1)) });
-
- BarrierImplementation.Proc = BarrierProcedure;
-
- Program.TopLevelDeclarations.Add(BarrierImplementation);
- }
-
- private static Expr flagIsSet(Expr Flags, int flag)
- {
- return Expr.Eq(new BvExtractExpr(
- Token.NoToken, Flags, flag, flag - 1),
- new LiteralExpr(Token.NoToken, BigNum.FromInt(1), 1));
- }
-
- private static Expr CLK_GLOBAL_MEM_FENCE_isSet(Expr Flags)
- {
- return flagIsSet(Flags, CLK_GLOBAL_MEM_FENCE);
- }
-
- private static Expr CLK_LOCAL_MEM_FENCE_isSet(Expr Flags)
- {
- return flagIsSet(Flags, CLK_LOCAL_MEM_FENCE);
- }
-
- private List<BigBlock> MakeResetAndHavocBlocks(int Thread, ICollection<Variable> variables)
- {
- Debug.Assert(variables.Count > 0);
- List<BigBlock> ResetAndHavocBlocks = new List<BigBlock>();
- foreach (Variable v in variables)
- {
- ResetAndHavocBlocks.Add(RaceInstrumenter.MakeResetReadWriteSetStatements(v, Thread));
- if (!ArrayModelledAdversarially(v))
- {
- ResetAndHavocBlocks.Add(HavocSharedArray(v, Thread));
- }
- }
- Debug.Assert(ResetAndHavocBlocks.Count > 0);
- return ResetAndHavocBlocks;
- }
-
-
- public static bool HasZDimension(Variable v)
- {
- if (v.TypedIdent.Type is MapType)
- {
- MapType mt = v.TypedIdent.Type as MapType;
-
- if (mt.Result is MapType)
- {
- MapType mt2 = mt.Result as MapType;
- if (mt2.Result is MapType)
- {
- Debug.Assert(!((mt2.Result as MapType).Result is MapType));
- return true;
- }
- }
- }
- return false;
- }
-
- private BigBlock HavocSharedArray(Variable v, int thread)
- {
- IdentifierExpr vForThread = new IdentifierExpr(Token.NoToken, new VariableDualiser(thread, null, null).VisitVariable(v.Clone() as Variable));
- return new BigBlock(Token.NoToken, null, new CmdSeq(new Cmd[] { new HavocCmd(Token.NoToken, new IdentifierExprSeq(new IdentifierExpr[] { vForThread })) }), null, null);
- }
-
- private BigBlock AssumeEqualityBetweenSharedArrays(Variable v, Expr P1, Expr P2, Expr Flags1, Expr Flags2)
- {
- IdentifierExpr v1 = new IdentifierExpr(Token.NoToken, new VariableDualiser(1, null, null).VisitVariable(v.Clone() as Variable));
- IdentifierExpr v2 = new IdentifierExpr(Token.NoToken, new VariableDualiser(2, null, null).VisitVariable(v.Clone() as Variable));
-
- Expr AssumeGuard = Expr.Eq(v1, v2);
-
- Expr EqualityCondition = ThreadsInSameGroup();
-
- if (KernelArrayInfo.getGroupSharedArrays().Contains(v))
- {
- EqualityCondition = Expr.And(EqualityCondition,
- Expr.And(CLK_LOCAL_MEM_FENCE_isSet(Flags1), CLK_LOCAL_MEM_FENCE_isSet(Flags2)));
- }
- else if (KernelArrayInfo.getGlobalArrays().Contains(v))
- {
- EqualityCondition = Expr.And(EqualityCondition,
- Expr.And(CLK_GLOBAL_MEM_FENCE_isSet(Flags1), CLK_GLOBAL_MEM_FENCE_isSet(Flags2)));
- }
-
- AssumeGuard = Expr.Imp(EqualityCondition, AssumeGuard);
-
- return new BigBlock(Token.NoToken, null, new CmdSeq(new Cmd[] { new AssumeCmd(Token.NoToken, AssumeGuard) }), null, null);
- }
-
-
- internal static bool ModifiesSetContains(IdentifierExprSeq Modifies, IdentifierExpr v)
- {
- foreach (IdentifierExpr ie in Modifies)
- {
- if (ie.Name.Equals(v.Name))
- {
- return true;
- }
- }
- return false;
- }
-
- private void AbstractSharedState()
- {
- List<Declaration> NewTopLevelDeclarations = new List<Declaration>();
-
- foreach (Declaration d in Program.TopLevelDeclarations)
- {
- if (d is Variable && KernelArrayInfo.Contains(d as Variable) && ArrayModelledAdversarially(d as Variable))
- {
- continue;
- }
-
- if (d is Implementation)
- {
- PerformFullSharedStateAbstraction(d as Implementation);
- }
-
- if (d is Procedure)
- {
- PerformFullSharedStateAbstraction(d as Procedure);
- }
-
- NewTopLevelDeclarations.Add(d);
-
- }
-
- Program.TopLevelDeclarations = NewTopLevelDeclarations;
-
- }
-
- private void PerformFullSharedStateAbstraction(Procedure proc)
- {
- IdentifierExprSeq NewModifies = new IdentifierExprSeq();
-
- foreach (IdentifierExpr e in proc.Modifies)
- {
- if (!KernelArrayInfo.Contains(e.Decl) || !ArrayModelledAdversarially(e.Decl))
- {
- NewModifies.Add(e);
- }
- }
-
- proc.Modifies = NewModifies;
-
- }
-
- private void PerformFullSharedStateAbstraction(Implementation impl)
- {
- VariableSeq NewLocVars = new VariableSeq();
-
- foreach (Variable v in impl.LocVars)
- {
- Debug.Assert(!KernelArrayInfo.getGroupSharedArrays().Contains(v));
- NewLocVars.Add(v);
- }
-
- impl.LocVars = NewLocVars;
-
- if (CommandLineOptions.Unstructured)
- impl.Blocks = impl.Blocks.Select(PerformFullSharedStateAbstraction).ToList();
- else
- impl.StructuredStmts = PerformFullSharedStateAbstraction(impl.StructuredStmts);
- }
-
-
- private StmtList PerformFullSharedStateAbstraction(StmtList stmtList)
- {
- Contract.Requires(stmtList != null);
-
- StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
-
- foreach (BigBlock bodyBlock in stmtList.BigBlocks)
- {
- result.BigBlocks.Add(PerformFullSharedStateAbstraction(bodyBlock));
- }
- return result;
- }
-
- private CmdSeq PerformFullSharedStateAbstraction(CmdSeq cs)
- {
- var result = new CmdSeq();
-
- foreach (Cmd c in cs)
- {
- if (c is AssignCmd)
- {
- AssignCmd assign = c as AssignCmd;
-
- var lhss = new List<AssignLhs>();
- var rhss = new List<Expr>();
-
- for (int i = 0; i != assign.Lhss.Count; i++)
- {
- AssignLhs lhs = assign.Lhss[i];
- Expr rhs = assign.Rhss[i];
- ReadCollector rc = new ReadCollector(KernelArrayInfo);
- rc.Visit(rhs);
-
- bool foundAdversarial = false;
- foreach (AccessRecord ar in rc.accesses)
- {
- if (ArrayModelledAdversarially(ar.v))
- {
- foundAdversarial = true;
- break;
- }
- }
-
- if (foundAdversarial)
- {
- Debug.Assert(lhs is SimpleAssignLhs);
- result.Add(new HavocCmd(c.tok, new IdentifierExprSeq(new IdentifierExpr[] { (lhs as SimpleAssignLhs).AssignedVariable })));
- continue;
- }
-
- WriteCollector wc = new WriteCollector(KernelArrayInfo);
- wc.Visit(lhs);
- if (wc.GetAccess() != null && ArrayModelledAdversarially(wc.GetAccess().v))
- {
- continue; // Just remove the write
- }
-
- lhss.Add(lhs);
- rhss.Add(rhs);
- }
-
- if (lhss.Count != 0)
- {
- result.Add(new AssignCmd(assign.tok, lhss, rhss));
- }
- continue;
- }
- result.Add(c);
- }
-
- return result;
- }
-
- private Block PerformFullSharedStateAbstraction(Block b)
- {
- b.Cmds = PerformFullSharedStateAbstraction(b.Cmds);
- return b;
- }
-
- private BigBlock PerformFullSharedStateAbstraction(BigBlock bb)
- {
- BigBlock result = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
-
- result.simpleCmds = PerformFullSharedStateAbstraction(bb.simpleCmds);
-
- if (bb.ec is WhileCmd)
- {
- WhileCmd WhileCommand = bb.ec as WhileCmd;
- result.ec =
- new WhileCmd(WhileCommand.tok, WhileCommand.Guard, WhileCommand.Invariants, PerformFullSharedStateAbstraction(WhileCommand.Body));
- }
- else if (bb.ec is IfCmd)
- {
- IfCmd IfCommand = bb.ec as IfCmd;
- Debug.Assert(IfCommand.elseIf == null);
- result.ec = new IfCmd(IfCommand.tok, IfCommand.Guard, PerformFullSharedStateAbstraction(IfCommand.thn), IfCommand.elseIf, IfCommand.elseBlock != null ? PerformFullSharedStateAbstraction(IfCommand.elseBlock) : null);
- }
- else
- {
- Debug.Assert(bb.ec == null || bb.ec is BreakCmd);
- }
-
- return result;
-
- }
-
- internal static string MakeOffsetVariableName(string Name, string AccessType)
- {
- return "_" + AccessType + "_OFFSET_" + Name;
- }
-
- internal static GlobalVariable MakeOffsetVariable(Variable v, string ReadOrWrite)
- {
- return new GlobalVariable(v.tok, new TypedIdent(v.tok, MakeOffsetVariableName(v.Name, ReadOrWrite), IndexType(v)));
- }
-
- public static Microsoft.Boogie.Type IndexType(Variable v)
- {
- Debug.Assert(v.TypedIdent.Type is MapType);
- MapType mt = v.TypedIdent.Type as MapType;
- return mt.Arguments[0];
- }
-
- internal GlobalVariable FindOrCreateAccessHasOccurredVariable(string varName, string accessType)
- {
- string name = MakeAccessHasOccurredVariableName(varName, accessType) + "$1";
- foreach(Declaration D in Program.TopLevelDeclarations)
- {
- if(D is GlobalVariable && ((GlobalVariable)D).Name.Equals(name))
- {
- return D as GlobalVariable;
- }
- }
-
- GlobalVariable result = new VariableDualiser(1, null, null).VisitVariable(
- MakeAccessHasOccurredVariable(varName, accessType)) as GlobalVariable;
-
- Program.TopLevelDeclarations.Add(result);
- return result;
-
- }
-
- internal GlobalVariable FindOrCreateOffsetVariable(Variable v, string accessType)
- {
- string name = MakeOffsetVariableName(v.Name, accessType) + "$1";
- foreach (Declaration D in Program.TopLevelDeclarations)
- {
- if (D is GlobalVariable && ((GlobalVariable)D).Name.Equals(name))
- {
- return D as GlobalVariable;
- }
- }
-
- GlobalVariable result = new VariableDualiser(1, null, null).VisitVariable(
- MakeOffsetVariable(v, accessType)) as GlobalVariable;
-
- Program.TopLevelDeclarations.Add(result);
- return result;
-
- }
-
- internal static GlobalVariable MakeAccessHasOccurredVariable(string varName, string accessType)
- {
- return new GlobalVariable(Token.NoToken, new TypedIdent(Token.NoToken, MakeAccessHasOccurredVariableName(varName, accessType), Microsoft.Boogie.Type.Bool));
- }
-
- internal static string MakeAccessHasOccurredVariableName(string varName, string accessType)
- {
- return "_" + accessType + "_HAS_OCCURRED_" + varName;
- }
-
- internal static IdentifierExpr MakeAccessHasOccurredExpr(string varName, string accessType)
- {
- return new IdentifierExpr(Token.NoToken, MakeAccessHasOccurredVariable(varName, accessType));
- }
-
- internal static bool IsIntOrBv32(Microsoft.Boogie.Type type)
- {
- return type.Equals(Microsoft.Boogie.Type.Int) || type.Equals(Microsoft.Boogie.Type.GetBvType(32));
- }
-
- private void PullOutNonLocalAccesses()
- {
- foreach (Declaration d in Program.TopLevelDeclarations)
- {
- if (d is Implementation)
- {
- (d as Implementation).StructuredStmts = PullOutNonLocalAccesses((d as Implementation).StructuredStmts, (d as Implementation));
- }
- }
- }
-
- private void RemoveElseIfs()
- {
- foreach (Declaration d in Program.TopLevelDeclarations)
- {
- if (d is Implementation)
- {
- (d as Implementation).StructuredStmts = RemoveElseIfs((d as Implementation).StructuredStmts);
- }
- }
- }
-
- private void RemoveRedundantReturns()
- {
- foreach (Declaration d in Program.TopLevelDeclarations)
- {
- if (d is Implementation)
- {
- RemoveRedundantReturns((d as Implementation).StructuredStmts);
- }
- }
- }
-
- private StmtList RemoveElseIfs(StmtList stmtList)
- {
- Contract.Requires(stmtList != null);
-
- StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
-
- foreach (BigBlock bodyBlock in stmtList.BigBlocks)
- {
- result.BigBlocks.Add(RemoveElseIfs(bodyBlock));
- }
-
- return result;
- }
-
- private void RemoveRedundantReturns(StmtList stmtList)
- {
- Contract.Requires(stmtList != null);
-
- BigBlock bb = stmtList.BigBlocks[stmtList.BigBlocks.Count - 1];
-
- if (bb.tc is ReturnCmd)
- {
- bb.tc = null;
- }
- }
-
- private BigBlock RemoveElseIfs(BigBlock bb)
- {
- BigBlock result = bb;
- if (bb.ec is IfCmd)
- {
- IfCmd IfCommand = bb.ec as IfCmd;
-
- Debug.Assert(IfCommand.elseIf == null || IfCommand.elseBlock == null);
-
- if (IfCommand.elseIf != null)
- {
- IfCommand.elseBlock = new StmtList(new List<BigBlock>(new BigBlock[] {
- new BigBlock(bb.tok, null, new CmdSeq(), IfCommand.elseIf, null)
- }), bb.tok);
- IfCommand.elseIf = null;
- }
-
- IfCommand.thn = RemoveElseIfs(IfCommand.thn);
- if (IfCommand.elseBlock != null)
- {
- IfCommand.elseBlock = RemoveElseIfs(IfCommand.elseBlock);
- }
-
- }
- else if (bb.ec is WhileCmd)
- {
- (bb.ec as WhileCmd).Body = RemoveElseIfs((bb.ec as WhileCmd).Body);
- }
-
- return result;
- }
-
- private StmtList PullOutNonLocalAccesses(StmtList stmtList, Implementation impl)
- {
- Contract.Requires(stmtList != null);
-
- StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
-
- foreach (BigBlock bodyBlock in stmtList.BigBlocks)
- {
- result.BigBlocks.Add(PullOutNonLocalAccesses(bodyBlock, impl));
- }
-
- return result;
- }
-
- private BigBlock PullOutNonLocalAccesses(BigBlock bb, Implementation impl)
- {
-
- BigBlock result = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
-
- foreach (Cmd c in bb.simpleCmds)
- {
-
- if (c is CallCmd)
- {
- CallCmd call = c as CallCmd;
-
- List<Expr> newIns = new List<Expr>();
-
- for (int i = 0; i < call.Ins.Count; i++)
- {
- Expr e = call.Ins[i];
-
- while (NonLocalAccessCollector.ContainsNonLocalAccess(e, KernelArrayInfo))
- {
- AssignCmd assignToTemp;
- LocalVariable tempDecl;
- e = ExtractLocalAccessToTemp(e, out assignToTemp, out tempDecl);
- result.simpleCmds.Add(assignToTemp);
- impl.LocVars.Add(tempDecl);
- }
-
- newIns.Add(e);
-
- }
-
- CallCmd newCall = new CallCmd(call.tok, call.callee, newIns, call.Outs);
- newCall.Proc = call.Proc;
- result.simpleCmds.Add(newCall);
- }
- else if (c is AssignCmd)
- {
- AssignCmd assign = c as AssignCmd;
-
- if (assign.Lhss.Zip(assign.Rhss, (lhs, rhs) =>
- !NonLocalAccessCollector.ContainsNonLocalAccess(rhs, KernelArrayInfo) ||
- (!NonLocalAccessCollector.ContainsNonLocalAccess(lhs, KernelArrayInfo) &&
- NonLocalAccessCollector.IsNonLocalAccess(rhs, KernelArrayInfo))).All(b => b))
- {
- result.simpleCmds.Add(c);
- }
- else
- {
- Debug.Assert(assign.Lhss.Count == 1 && assign.Rhss.Count == 1);
- AssignLhs lhs = assign.Lhss.ElementAt(0);
- Expr rhs = assign.Rhss.ElementAt(0);
- rhs = PullOutNonLocalAccessesIntoTemps(result, rhs, impl);
- List<AssignLhs> newLhss = new List<AssignLhs>();
- newLhss.Add(lhs);
- List<Expr> newRhss = new List<Expr>();
- newRhss.Add(rhs);
- result.simpleCmds.Add(new AssignCmd(assign.tok, newLhss, newRhss));
- }
-
- }
- else if (c is HavocCmd)
- {
- result.simpleCmds.Add(c);
- }
- else if (c is AssertCmd)
- {
- result.simpleCmds.Add(new AssertCmd(c.tok, PullOutNonLocalAccessesIntoTemps(result, (c as AssertCmd).Expr, impl)));
- }
- else if (c is AssumeCmd)
- {
- result.simpleCmds.Add(new AssumeCmd(c.tok, PullOutNonLocalAccessesIntoTemps(result, (c as AssumeCmd).Expr, impl)));
- }
- else
- {
- Console.WriteLine(c);
- Debug.Assert(false);
- }
- }
-
- if (bb.ec is WhileCmd)
- {
- WhileCmd WhileCommand = bb.ec as WhileCmd;
- while (NonLocalAccessCollector.ContainsNonLocalAccess(WhileCommand.Guard, KernelArrayInfo))
- {
- AssignCmd assignToTemp;
- LocalVariable tempDecl;
- WhileCommand.Guard = ExtractLocalAccessToTemp(WhileCommand.Guard, out assignToTemp, out tempDecl);
- result.simpleCmds.Add(assignToTemp);
- impl.LocVars.Add(tempDecl);
- }
- result.ec = new WhileCmd(WhileCommand.tok, WhileCommand.Guard, WhileCommand.Invariants, PullOutNonLocalAccesses(WhileCommand.Body, impl));
- }
- else if (bb.ec is IfCmd)
- {
- IfCmd IfCommand = bb.ec as IfCmd;
- Debug.Assert(IfCommand.elseIf == null); // "else if" must have been eliminated by this phase
- while (NonLocalAccessCollector.ContainsNonLocalAccess(IfCommand.Guard, KernelArrayInfo))
- {
- AssignCmd assignToTemp;
- LocalVariable tempDecl;
- IfCommand.Guard = ExtractLocalAccessToTemp(IfCommand.Guard, out assignToTemp, out tempDecl);
- result.simpleCmds.Add(assignToTemp);
- impl.LocVars.Add(tempDecl);
- }
- result.ec = new IfCmd(IfCommand.tok, IfCommand.Guard, PullOutNonLocalAccesses(IfCommand.thn, impl), IfCommand.elseIf, IfCommand.elseBlock != null ? PullOutNonLocalAccesses(IfCommand.elseBlock, impl) : null);
- }
- else if (bb.ec is BreakCmd)
- {
- result.ec = bb.ec;
- }
- else
- {
- Debug.Assert(bb.ec == null);
- }
-
- return result;
-
- }
-
- private Expr PullOutNonLocalAccessesIntoTemps(BigBlock result, Expr e, Implementation impl)
- {
- while (NonLocalAccessCollector.ContainsNonLocalAccess(e, KernelArrayInfo))
- {
- AssignCmd assignToTemp;
- LocalVariable tempDecl;
- e = ExtractLocalAccessToTemp(e, out assignToTemp, out tempDecl);
- result.simpleCmds.Add(assignToTemp);
- impl.LocVars.Add(tempDecl);
- }
- return e;
- }
-
- private Expr ExtractLocalAccessToTemp(Expr rhs, out AssignCmd tempAssignment, out LocalVariable tempDeclaration)
- {
- NonLocalAccessExtractor extractor = new NonLocalAccessExtractor(TempCounter, KernelArrayInfo);
- TempCounter++;
- rhs = extractor.VisitExpr(rhs);
- tempAssignment = extractor.Assignment;
- tempDeclaration = extractor.Declaration;
- return rhs;
- }
-
- private void MakeKernelDualised()
- {
-
- List<Declaration> NewTopLevelDeclarations = new List<Declaration>();
-
- foreach (Declaration d in Program.TopLevelDeclarations)
- {
- if (d is Procedure)
- {
-
- new KernelDualiser(this).DualiseProcedure(d as Procedure);
-
- NewTopLevelDeclarations.Add(d as Procedure);
-
- continue;
-
- }
-
- if (d is Implementation)
- {
-
- new KernelDualiser(this).DualiseImplementation(d as Implementation, CommandLineOptions.Unstructured);
-
- NewTopLevelDeclarations.Add(d as Implementation);
-
- continue;
-
- }
-
- if (d is Variable && ((d as Variable).IsMutable || IsThreadLocalIdConstant(d as Variable)
- || IsGroupIdConstant(d as Variable) ))
- {
- NewTopLevelDeclarations.Add(new VariableDualiser(1, null, null).VisitVariable((Variable)d.Clone()));
- if (!QKeyValue.FindBoolAttribute(d.Attributes, "race_checking"))
- {
- NewTopLevelDeclarations.Add(new VariableDualiser(2, null, null).VisitVariable((Variable)d.Clone()));
- }
-
- continue;
- }
-
- NewTopLevelDeclarations.Add(d);
-
- }
-
- Program.TopLevelDeclarations = NewTopLevelDeclarations;
-
- }
-
- private void MakeKernelPredicated()
- {
- if (CommandLineOptions.Unstructured)
- {
- BlockPredicator.Predicate(Program, /*createCandidateInvariants=*/CommandLineOptions.Inference);
- return;
- }
-
- foreach (Declaration d in Program.TopLevelDeclarations)
- {
- if (d is Procedure)
- {
- Procedure proc = d as Procedure;
- IdentifierExpr enabled = new IdentifierExpr(proc.tok,
- new LocalVariable(proc.tok, new TypedIdent(proc.tok, "_P", Microsoft.Boogie.Type.Bool)));
- Expr predicateExpr;
- if (!uniformityAnalyser.IsUniform(proc.Name))
- {
- // Add predicate to start of parameter list
- VariableSeq NewIns = new VariableSeq();
- NewIns.Add(enabled.Decl);
- foreach (Variable v in proc.InParams)
- {
- NewIns.Add(v);
- }
- proc.InParams = NewIns;
- predicateExpr = enabled;
- }
- else
- {
- predicateExpr = Expr.True;
- }
-
- RequiresSeq newRequires = new RequiresSeq();
- foreach (Requires r in proc.Requires)
- {
- newRequires.Add(new Requires(r.Free, Predicator.ProcessEnabledIntrinsics(r.Condition, predicateExpr)));
- }
- proc.Requires = newRequires;
-
- EnsuresSeq newEnsures = new EnsuresSeq();
- foreach (Ensures e in proc.Ensures)
- {
- newEnsures.Add(new Ensures(e.Free, Predicator.ProcessEnabledIntrinsics(e.Condition, predicateExpr)));
- }
- proc.Ensures = newEnsures;
-
- }
- else if (d is Implementation)
- {
- Implementation impl = d as Implementation;
- new Predicator(this, !uniformityAnalyser.IsUniform(impl.Name)).transform
- (impl);
- }
- }
-
- }
-
- private void CheckKernelParameters()
- {
- if (KernelProcedure.OutParams.Length != 0)
- {
- Error(KernelProcedure.tok, "Kernel should not take return anything");
- }
- }
-
-
- private int Check()
- {
- BarrierProcedure = FindOrCreateBarrierProcedure();
- KernelProcedure = CheckExactlyOneKernelProcedure();
-
- if (ErrorCount > 0)
- {
- return ErrorCount;
- }
-
- if (BarrierProcedure.InParams.Length != 1)
- {
- Error(BarrierProcedure, "Barrier procedure must take exactly one argument");
- }
- else if (!BarrierProcedure.InParams[0].TypedIdent.Type.Equals(new BvType(32)))
- {
- Error(BarrierProcedure, "Argument to barrier procedure must have type bv32");
- }
-
- if (BarrierProcedure.OutParams.Length != 0)
- {
- Error(BarrierProcedure, "Barrier procedure must not return any results");
- }
-
- if (!FindNonLocalVariables())
- {
- return ErrorCount;
- }
-
- CheckKernelImplementation();
- return ErrorCount;
- }
-
- public static bool IsThreadLocalIdConstant(Variable variable)
- {
- return variable.Name.Equals(_X.Name) || variable.Name.Equals(_Y.Name) || variable.Name.Equals(_Z.Name);
- }
-
- public static bool IsGroupIdConstant(Variable variable)
- {
- return variable.Name.Equals(_GROUP_X.Name) || variable.Name.Equals(_GROUP_Y.Name) || variable.Name.Equals(_GROUP_Z.Name);
- }
-
- internal void AddCandidateInvariant(IRegion region, Expr e, string tag)
- {
- region.AddInvariant(Program.CreateCandidateInvariant(e, tag));
- }
-
- internal Implementation GetImplementation(string procedureName)
- {
- foreach (Declaration D in Program.TopLevelDeclarations)
- {
- if (D is Implementation && ((D as Implementation).Name == procedureName))
- {
- return D as Implementation;
- }
- }
- Debug.Assert(false);
- return null;
- }
-
-
- internal bool ContainsBarrierCall(IRegion loop)
- {
- foreach (Cmd c in loop.Cmds())
- {
- if (c is CallCmd && ((c as CallCmd).Proc == BarrierProcedure))
- {
- return true;
- }
- }
-
- return false;
- }
-
-
-
- internal bool ArrayModelledAdversarially(Variable v)
- {
- if (CommandLineOptions.AdversarialAbstraction)
- {
- return true;
- }
- if (CommandLineOptions.EqualityAbstraction)
- {
- return false;
- }
- return !arrayControlFlowAnalyser.MayAffectControlFlow(v.Name);
- }
-
- internal Expr GlobalIdExpr(string dimension)
- {
- return MakeBVAdd(MakeBVMul(
- new IdentifierExpr(Token.NoToken, GetGroupId(dimension)), new IdentifierExpr(Token.NoToken, GetGroupSize(dimension))),
- new IdentifierExpr(Token.NoToken, MakeThreadId(Token.NoToken, dimension)));
- }
-
- internal IRegion RootRegion(Implementation Impl)
- {
- if (CommandLineOptions.Unstructured)
- return new UnstructuredRegion(Program, Impl);
- else
- return new StructuredRegion(Impl);
- }
-
-
- public static bool IsGivenConstant(Expr e, Constant c)
- {
- if (!(e is IdentifierExpr))
- return false;
-
- var varName = ((IdentifierExpr)e).Decl.Name;
- return (StripThreadIdentifier(varName) == StripThreadIdentifier(c.Name));
- }
-
- public bool SubstIsGivenConstant(Implementation impl, Expr e, Constant c)
- {
- if (!(e is IdentifierExpr))
- return false;
- e = varDefAnalyses[impl].SubstDefinitions(e, impl.Name);
- return IsGivenConstant(e, c);
- }
-
- public Constant GetLocalIdConst(int dim)
- {
- switch (dim)
- {
- case 0: return _X;
- case 1: return _Y;
- case 2: return _Z;
- default: Debug.Assert(false);
- return null;
- }
- }
-
- public Constant GetGroupIdConst(int dim)
- {
- switch (dim)
- {
- case 0: return _GROUP_X;
- case 1: return _GROUP_Y;
- case 2: return _GROUP_Z;
- default: Debug.Assert(false);
- return null;
- }
- }
-
- public Constant GetGroupSizeConst(int dim)
- {
- switch (dim)
- {
- case 0: return _GROUP_SIZE_X;
- case 1: return _GROUP_SIZE_Y;
- case 2: return _GROUP_SIZE_Z;
- default: Debug.Assert(false);
- return null;
- }
- }
-
- public bool IsLocalId(Expr e, int dim, Implementation impl)
- {
- return SubstIsGivenConstant(impl, e, GetLocalIdConst(dim));
- }
-
- public bool IsGlobalId(Expr e, int dim, Implementation impl)
- {
- e = varDefAnalyses[impl].SubstDefinitions(e, impl.Name);
-
- if (e is NAryExpr && (e as NAryExpr).Fun.FunctionName.Equals("BV32_ADD"))
- {
- NAryExpr nary = e as NAryExpr;
- Constant localId = GetLocalIdConst(dim);
-
- if (IsGivenConstant(nary.Args[1], localId))
- {
- return IsGroupIdTimesGroupSize(nary.Args[0], dim);
- }
-
- if (IsGivenConstant(nary.Args[0], localId))
- {
- return IsGroupIdTimesGroupSize(nary.Args[1], dim);
- }
- }
-
- return false;
- }
-
- private bool IsGroupIdTimesGroupSize(Expr expr, int dim)
- {
- if (expr is NAryExpr && (expr as NAryExpr).Fun.FunctionName.Equals("BV32_MUL"))
- {
- NAryExpr innerNary = expr as NAryExpr;
-
- if (IsGroupIdAndSize(dim, innerNary.Args[0], innerNary.Args[1]))
- {
- return true;
- }
-
- if (IsGroupIdAndSize(dim, innerNary.Args[1], innerNary.Args[0]))
- {
- return true;
- }
- }
- return false;
- }
-
- private bool IsGroupIdAndSize(int dim, Expr maybeGroupId, Expr maybeGroupSize)
- {
- return IsGivenConstant(maybeGroupId, GetGroupIdConst(dim)) &&
- IsGivenConstant(maybeGroupSize, GetGroupSizeConst(dim));
- }
-
- internal Expr MaybeDualise(Expr e, int id, string procName)
- {
- if (id == 0)
- return e;
- else
- return (Expr)new VariableDualiser(id, uniformityAnalyser, procName).Visit(e.Clone());
- }
- }
-
-}
+ DoVariableDefinitionAnalysis();
+
+ DoReducedStrengthAnalysis();
+
+ DoMayBePowerOfTwoAnalysis();
+
+ DoArrayControlFlowAnalysis();
+
+ if (CommandLineOptions.Inference)
+ {
+ foreach (var proc in Program.TopLevelDeclarations.OfType<Procedure>().ToList())
+ {
+ RaceInstrumenter.DoHoudiniPointerAnalysis(proc);
+ }
+
+ foreach (var impl in Program.TopLevelDeclarations.OfType<Implementation>().ToList())
+ {
+ LoopInvariantGenerator.PreInstrument(this, impl);
+ }
+
+ if (CommandLineOptions.ShowStages) {
+ emitProgram(outputFilename + "_pre_inference");
+ }
+
+ }
+
+ RaceInstrumenter.AddRaceCheckingInstrumentation();
+
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_instrumented");
+ }
+
+ AbstractSharedState();
+
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_abstracted");
+ }
+
+ MergeBlocksIntoPredecessors();
+
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_merged_pre_predication");
+ }
+
+ MakeKernelPredicated();
+
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_predicated");
+ }
+
+ MergeBlocksIntoPredecessors();
+
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_merged_post_predication");
+ }
+
+ MakeKernelDualised();
+
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_dualised");
+ }
+
+ RaceInstrumenter.AddRaceCheckingDeclarations();
+
+ GenerateBarrierImplementation();
+
+ GenerateStandardKernelContract();
+
+ if (CommandLineOptions.ShowStages)
+ {
+ emitProgram(outputFilename + "_ready_to_verify");
+ }
+
+ if (CommandLineOptions.Inference)
+ {
+ ComputeInvariant();
+ }
+
+ emitProgram(outputFilename);
+
+ }
+
+ private void DoMayBePowerOfTwoAnalysis()
+ {
+ mayBePowerOfTwoAnalyser = new MayBePowerOfTwoAnalyser(this);
+ mayBePowerOfTwoAnalyser.Analyse();
+ }
+
+ private void DoArrayControlFlowAnalysis()
+ {
+ arrayControlFlowAnalyser = new ArrayControlFlowAnalyser(this);
+ arrayControlFlowAnalyser.Analyse();
+ }
+
+ private void DoUniformityAnalysis()
+ {
+ var entryPoints = new HashSet<Implementation>();
+ if (CommandLineOptions.DoUniformityAnalysis) {
+ entryPoints.Add(KernelImplementation);
+ }
+
+ var nonUniformVars = new Variable[] { _X, _Y, _Z, _GROUP_X, _GROUP_Y, _GROUP_Z };
+
+ uniformityAnalyser = new UniformityAnalyser(Program, CommandLineOptions.DoUniformityAnalysis, CommandLineOptions.Unstructured,
+ entryPoints, nonUniformVars);
+ uniformityAnalyser.Analyse();
+ }
+
+ private void DoLiveVariableAnalysis()
+ {
+ liveVariableAnalyser = new LiveVariableAnalyser(this);
+ liveVariableAnalyser.Analyse();
+ }
+
+ private void DoVariableDefinitionAnalysis()
+ {
+ varDefAnalyses = Program.TopLevelDeclarations
+ .OfType<Implementation>()
+ .ToDictionary(i => i, i => VariableDefinitionAnalysis.Analyse(this, i));
+ }
+
+ private void DoReducedStrengthAnalysis()
+ {
+ reducedStrengthAnalyses = Program.TopLevelDeclarations
+ .OfType<Implementation>()
+ .ToDictionary(i => i, i => ReducedStrengthAnalysis.Analyse(this, i));
+ }
+
+ private void emitProgram(string filename)
+ {
+ using (TokenTextWriter writer = new TokenTextWriter(filename + ".bpl"))
+ {
+ Program.Emit(writer);
+ }
+ }
+
+ private void ComputeInvariant()
+ {
+ for (int i = 0; i < Program.TopLevelDeclarations.Count; i++)
+ {
+ if (Program.TopLevelDeclarations[i] is Implementation)
+ {
+
+ Implementation Impl = Program.TopLevelDeclarations[i] as Implementation;
+
+ List<Expr> UserSuppliedInvariants = GetUserSuppliedInvariants(Impl.Name);
+
+ LoopInvariantGenerator.PostInstrument(this, Impl, UserSuppliedInvariants);
+
+ Procedure Proc = Impl.Proc;
+
+ if (QKeyValue.FindIntAttribute(Proc.Attributes, "inline", -1) == 1)
+ {
+ continue;
+ }
+
+ if (Proc == KernelProcedure)
+ {
+ continue;
+ }
+
+ AddCandidateRequires(Proc);
+ RaceInstrumenter.AddRaceCheckingCandidateRequires(Proc);
+ AddUserSuppliedCandidateRequires(Proc, UserSuppliedInvariants);
+
+ AddCandidateEnsures(Proc);
+ RaceInstrumenter.AddRaceCheckingCandidateEnsures(Proc);
+ AddUserSuppliedCandidateEnsures(Proc, UserSuppliedInvariants);
+
+ }
+
+
+ }
+
+ }
+
+ private void AddCandidateEnsures(Procedure Proc)
+ {
+ HashSet<string> names = new HashSet<String>();
+ foreach (Variable v in Proc.OutParams)
+ {
+ names.Add(StripThreadIdentifier(v.Name));
+ }
+
+ foreach (string name in names)
+ {
+ if (!uniformityAnalyser.IsUniform(Proc.Name, name))
+ {
+ AddEqualityCandidateEnsures(Proc, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, name, Microsoft.Boogie.Type.Int)));
+ }
+ }
+
+ }
+
+ private void AddCandidateRequires(Procedure Proc)
+ {
+ HashSet<string> names = new HashSet<String>();
+ foreach (Variable v in Proc.InParams)
+ {
+ names.Add(StripThreadIdentifier(v.Name));
+ }
+
+ foreach (string name in names)
+ {
+
+ if (IsPredicateOrTemp(name))
+ {
+ Debug.Assert(name.Equals("_P"));
+ Debug.Assert(!uniformityAnalyser.IsUniform(Proc.Name));
+ AddCandidateRequires(Proc, Expr.Eq(
+ new IdentifierExpr(Proc.tok, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, name + "$1", Microsoft.Boogie.Type.Bool))),
+ new IdentifierExpr(Proc.tok, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, name + "$2", Microsoft.Boogie.Type.Bool)))
+ ));
+ }
+ else
+ {
+ if (!uniformityAnalyser.IsUniform(Proc.Name, name))
+ {
+ if (!uniformityAnalyser.IsUniform(Proc.Name))
+ {
+ AddPredicatedEqualityCandidateRequires(Proc, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, name, Microsoft.Boogie.Type.Int)));
+ }
+ AddEqualityCandidateRequires(Proc, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, name, Microsoft.Boogie.Type.Int)));
+ }
+ }
+ }
+
+ }
+
+ private void AddPredicatedEqualityCandidateRequires(Procedure Proc, Variable v)
+ {
+ AddCandidateRequires(Proc, Expr.Imp(
+ Expr.And(
+ new IdentifierExpr(Proc.tok, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, "_P$1", Microsoft.Boogie.Type.Bool))),
+ new IdentifierExpr(Proc.tok, new LocalVariable(Proc.tok, new TypedIdent(Proc.tok, "_P$2", Microsoft.Boogie.Type.Bool)))
+ ),
+ Expr.Eq(
+ new IdentifierExpr(Proc.tok, new VariableDualiser(1, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable)),
+ new IdentifierExpr(Proc.tok, new VariableDualiser(2, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable))
+ )
+ ));
+ }
+
+ private void AddEqualityCandidateRequires(Procedure Proc, Variable v)
+ {
+ AddCandidateRequires(Proc,
+ Expr.Eq(
+ new IdentifierExpr(Proc.tok, new VariableDualiser(1, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable)),
+ new IdentifierExpr(Proc.tok, new VariableDualiser(2, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable))
+ )
+ );
+ }
+
+ private void AddEqualityCandidateEnsures(Procedure Proc, Variable v)
+ {
+ AddCandidateEnsures(Proc,
+ Expr.Eq(
+ new IdentifierExpr(Proc.tok, new VariableDualiser(1, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable)),
+ new IdentifierExpr(Proc.tok, new VariableDualiser(2, uniformityAnalyser, Proc.Name).VisitVariable(v.Clone() as Variable))
+ ));
+ }
+
+
+ private void AddUserSuppliedCandidateRequires(Procedure Proc, List<Expr> UserSuppliedInvariants)
+ {
+ foreach (Expr e in UserSuppliedInvariants)
+ {
+ Requires r = new Requires(false, e);
+ Proc.Requires.Add(r);
+ bool OK = ProgramIsOK(Proc);
+ Proc.Requires.Remove(r);
+ if (OK)
+ {
+ AddCandidateRequires(Proc, e);
+ }
+ }
+ }
+
+ private void AddUserSuppliedCandidateEnsures(Procedure Proc, List<Expr> UserSuppliedInvariants)
+ {
+ foreach (Expr e in UserSuppliedInvariants)
+ {
+ Ensures ens = new Ensures(false, e);
+ Proc.Ensures.Add(ens);
+ bool OK = ProgramIsOK(Proc);
+ Proc.Ensures.Remove(ens);
+ if (OK)
+ {
+ AddCandidateEnsures(Proc, e);
+ }
+ }
+ }
+
+
+
+ internal void AddCandidateRequires(Procedure Proc, Expr e)
+ {
+ Constant ExistentialBooleanConstant = Program.MakeExistentialBoolean();
+ IdentifierExpr ExistentialBoolean = new IdentifierExpr(Proc.tok, ExistentialBooleanConstant);
+ Proc.Requires.Add(new Requires(false, Expr.Imp(ExistentialBoolean, e)));
+ }
+
+ internal void AddCandidateEnsures(Procedure Proc, Expr e)
+ {
+ Constant ExistentialBooleanConstant = Program.MakeExistentialBoolean();
+ IdentifierExpr ExistentialBoolean = new IdentifierExpr(Proc.tok, ExistentialBooleanConstant);
+ Proc.Ensures.Add(new Ensures(false, Expr.Imp(ExistentialBoolean, e)));
+ }
+
+ private List<Expr> GetUserSuppliedInvariants(string ProcedureName)
+ {
+ List<Expr> result = new List<Expr>();
+
+ if (CommandLineOptions.invariantsFile == null)
+ {
+ return result;
+ }
+
+ StreamReader sr = new StreamReader(new FileStream(CommandLineOptions.invariantsFile, FileMode.Open, FileAccess.Read));
+ string line;
+ int lineNumber = 1;
+ while ((line = sr.ReadLine()) != null)
+ {
+ string[] components = line.Split(':');
+
+ if (components.Length != 1 && components.Length != 2)
+ {
+ Console.WriteLine("Ignoring badly formed candidate invariant '" + line + "' at '" + CommandLineOptions.invariantsFile + "' line " + lineNumber);
+ continue;
+ }
+
+ if (components.Length == 2)
+ {
+ if (!components[0].Trim().Equals(ProcedureName))
+ {
+ continue;
+ }
+
+ line = components[1];
+ }
+
+ string temp_program_text = "axiom (" + line + ");";
+ TokenTextWriter writer = new TokenTextWriter("temp_out.bpl");
+ writer.WriteLine(temp_program_text);
+ writer.Close();
+
+ Program temp_program = GPUVerify.ParseBoogieProgram(new List<string>(new string[] { "temp_out.bpl" }), false);
+
+ if (null == temp_program)
+ {
+ Console.WriteLine("Ignoring badly formed candidate invariant '" + line + "' at '" + CommandLineOptions.invariantsFile + "' line " + lineNumber);
+ }
+ else
+ {
+ Debug.Assert(temp_program.TopLevelDeclarations[0] is Axiom);
+ result.Add((temp_program.TopLevelDeclarations[0] as Axiom).Expr);
+ }
+
+ lineNumber++;
+ }
+
+ return result;
+ }
+
+ internal bool ContainsNamedVariable(HashSet<Variable> variables, string name)
+ {
+ foreach(Variable v in variables)
+ {
+ if(StripThreadIdentifier(v.Name) == name)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ internal static bool IsPredicate(string v) {
+ if (v.Length < 2) {
+ return false;
+ }
+ if (!v.Substring(0, 1).Equals("p")) {
+ return false;
+ }
+ for (int i = 1; i < v.Length; i++) {
+ if (!Char.IsDigit(v.ToCharArray()[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ internal static bool IsPredicateOrTemp(string lv) {
+
+ // We should improve this by having a general convention
+ // for names of temporary or predicate variables
+
+ if (lv.Length >= 2) {
+ if (lv.Substring(0, 1).Equals("p") || lv.Substring(0, 1).Equals("v")) {
+ for (int i = 1; i < lv.Length; i++) {
+ if (!Char.IsDigit(lv.ToCharArray()[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ }
+
+ if (lv.Contains("_HAVOC_")) {
+ return true;
+ }
+
+ return (lv.Length >= 2 && lv.Substring(0,2).Equals("_P")) ||
+ (lv.Length > 3 && lv.Substring(0,3).Equals("_LC")) ||
+ (lv.Length > 5 && lv.Substring(0,5).Equals("_temp"));
+ }
+
+
+
+
+ internal bool ProgramIsOK(Declaration d)
+ {
+ Debug.Assert(d is Procedure || d is Implementation);
+ TokenTextWriter writer = new TokenTextWriter("temp_out.bpl");
+ List<Declaration> RealDecls = Program.TopLevelDeclarations;
+ List<Declaration> TempDecls = new List<Declaration>();
+ foreach (Declaration d2 in RealDecls)
+ {
+ if (d is Procedure)
+ {
+ if ((d == d2) || !(d2 is Implementation || d2 is Procedure))
+ {
+ TempDecls.Add(d2);
+ }
+ }
+ else if (d is Implementation)
+ {
+ if ((d == d2) || !(d2 is Implementation))
+ {
+ TempDecls.Add(d2);
+ }
+ }
+ }
+ Program.TopLevelDeclarations = TempDecls;
+ Program.Emit(writer);
+ writer.Close();
+ Program.TopLevelDeclarations = RealDecls;
+ Program temp_program = GPUVerify.ParseBoogieProgram(new List<string>(new string[] { "temp_out.bpl" }), false);
+
+ if (temp_program == null)
+ {
+ return false;
+ }
+
+ if (temp_program.Resolve() != 0)
+ {
+ return false;
+ }
+
+ if (temp_program.Typecheck() != 0)
+ {
+ return false;
+ }
+ return true;
+ }
+
+
+
+ public static Microsoft.Boogie.Type GetTypeOfIdX()
+ {
+ Contract.Requires(_X != null);
+ return _X.TypedIdent.Type;
+ }
+
+ public static Microsoft.Boogie.Type GetTypeOfIdY()
+ {
+ Contract.Requires(_Y != null);
+ return _Y.TypedIdent.Type;
+ }
+
+ public static Microsoft.Boogie.Type GetTypeOfIdZ()
+ {
+ Contract.Requires(_Z != null);
+ return _Z.TypedIdent.Type;
+ }
+
+ public static Microsoft.Boogie.Type GetTypeOfId(string dimension)
+ {
+ Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
+ if (dimension.Equals("X")) return GetTypeOfIdX();
+ if (dimension.Equals("Y")) return GetTypeOfIdY();
+ if (dimension.Equals("Z")) return GetTypeOfIdZ();
+ Debug.Assert(false);
+ return null;
+ }
+
+ public bool KernelHasIdX()
+ {
+ return _X != null;
+ }
+
+ public bool KernelHasIdY()
+ {
+ return _Y != null;
+ }
+
+ public bool KernelHasIdZ()
+ {
+ return _Z != null;
+ }
+
+ public bool KernelHasGroupIdX()
+ {
+ return _GROUP_X != null;
+ }
+
+ public bool KernelHasGroupIdY()
+ {
+ return _GROUP_Y != null;
+ }
+
+ public bool KernelHasGroupIdZ()
+ {
+ return _GROUP_Z != null;
+ }
+
+ public bool KernelHasNumGroupsX()
+ {
+ return _NUM_GROUPS_X != null;
+ }
+
+ public bool KernelHasNumGroupsY()
+ {
+ return _NUM_GROUPS_Y != null;
+ }
+
+ public bool KernelHasNumGroupsZ()
+ {
+ return _NUM_GROUPS_Z != null;
+ }
+
+ public bool KernelHasGroupSizeX()
+ {
+ return _GROUP_SIZE_X != null;
+ }
+
+ public bool KernelHasGroupSizeY()
+ {
+ return _GROUP_SIZE_Y != null;
+ }
+
+ public bool KernelHasGroupSizeZ()
+ {
+ return _GROUP_SIZE_Z != null;
+ }
+
+ internal static string StripThreadIdentifier(string p, out int id)
+ {
+ if (p.EndsWith("$1"))
+ {
+ id = 1;
+ return p.Substring(0, p.Length - 2);
+ }
+ if (p.EndsWith("$2"))
+ {
+ id = 2;
+ return p.Substring(0, p.Length - 2);
+ }
+
+ id = 0;
+ return p;
+ }
+
+ internal static string StripThreadIdentifier(string p)
+ {
+ int id;
+ return StripThreadIdentifier(p, out id);
+ }
+
+ private void GenerateStandardKernelContract()
+ {
+ RaceInstrumenter.AddKernelPrecondition();
+
+ IToken tok = KernelImplementation.tok;
+
+ GeneratePreconditionsForDimension(tok, "X");
+ GeneratePreconditionsForDimension(tok, "Y");
+ GeneratePreconditionsForDimension(tok, "Z");
+
+ RaceInstrumenter.AddStandardSourceVariablePreconditions();
+ RaceInstrumenter.AddStandardSourceVariablePostconditions();
+
+ foreach (Declaration D in Program.TopLevelDeclarations)
+ {
+ if (!(D is Procedure))
+ {
+ continue;
+ }
+ Procedure Proc = D as Procedure;
+ if (QKeyValue.FindIntAttribute(Proc.Attributes, "inline", -1) == 1)
+ {
+ continue;
+ }
+
+ Expr DistinctLocalIds =
+ Expr.Or(
+ Expr.Or(
+ Expr.Neq(
+ new IdentifierExpr(tok, MakeThreadId(tok, "X", 1)),
+ new IdentifierExpr(tok, MakeThreadId(tok, "X", 2))
+ ),
+ Expr.Neq(
+ new IdentifierExpr(tok, MakeThreadId(tok, "Y", 1)),
+ new IdentifierExpr(tok, MakeThreadId(tok, "Y", 2))
+ )
+ ),
+ Expr.Neq(
+ new IdentifierExpr(tok, MakeThreadId(tok, "Z", 1)),
+ new IdentifierExpr(tok, MakeThreadId(tok, "Z", 2))
+ )
+ );
+
+ Proc.Requires.Add(new Requires(false, Expr.Imp(ThreadsInSameGroup(), DistinctLocalIds)));
+
+ if (CommandLineOptions.OnlyIntraGroupRaceChecking)
+ {
+ Proc.Requires.Add(new Requires(false, ThreadsInSameGroup()));
+ }
+
+ if (Proc == KernelProcedure)
+ {
+ bool foundNonUniform = false;
+ int indexOfFirstNonUniformParameter;
+ for (indexOfFirstNonUniformParameter = 0; indexOfFirstNonUniformParameter < Proc.InParams.Length; indexOfFirstNonUniformParameter++)
+ {
+ if (!uniformityAnalyser.IsUniform(Proc.Name, StripThreadIdentifier(Proc.InParams[indexOfFirstNonUniformParameter].Name)))
+ {
+ foundNonUniform = true;
+ break;
+ }
+ }
+
+ if (foundNonUniform)
+ {
+ // I have a feeling this will never be reachable!!!
+ int numberOfNonUniformParameters = (Proc.InParams.Length - indexOfFirstNonUniformParameter) / 2;
+ for (int i = indexOfFirstNonUniformParameter; i < numberOfNonUniformParameters; i++)
+ {
+ Proc.Requires.Add(new Requires(false,
+ Expr.Eq(new IdentifierExpr(Proc.InParams[i].tok, Proc.InParams[i]),
+ new IdentifierExpr(Proc.InParams[i + numberOfNonUniformParameters].tok, Proc.InParams[i + numberOfNonUniformParameters]))));
+ }
+ }
+ }
+
+ }
+
+ foreach (Declaration D in Program.TopLevelDeclarations)
+ {
+ if (!(D is Implementation))
+ {
+ continue;
+ }
+ Implementation Impl = D as Implementation;
+
+ foreach (IRegion subregion in RootRegion(Impl).SubRegions())
+ {
+ RaceInstrumenter.AddSourceLocationLoopInvariants(Impl, subregion);
+ }
+ }
+
+ foreach (Declaration D in Program.TopLevelDeclarations)
+ {
+ if (!(D is Implementation))
+ {
+ continue;
+ }
+ Implementation Impl = D as Implementation;
+
+ if (QKeyValue.FindIntAttribute(Impl.Proc.Attributes, "inline", -1) == 1)
+ {
+ continue;
+ }
+ if (Impl.Proc == KernelProcedure)
+ {
+ continue;
+ }
+
+ new EnsureDisabledThreadHasNoEffectInstrumenter(this, Impl).instrument();
+
+ }
+
+ }
+
+ internal static Expr ThreadsInSameGroup()
+ {
+ return Expr.And(
+ Expr.And(
+ Expr.Eq(
+ new IdentifierExpr(Token.NoToken, MakeGroupId("X", 1)),
+ new IdentifierExpr(Token.NoToken, MakeGroupId("X", 2))
+ ),
+ Expr.Eq(
+ new IdentifierExpr(Token.NoToken, MakeGroupId("Y", 1)),
+ new IdentifierExpr(Token.NoToken, MakeGroupId("Y", 2))
+ )
+ ),
+ Expr.Eq(
+ new IdentifierExpr(Token.NoToken, MakeGroupId("Z", 1)),
+ new IdentifierExpr(Token.NoToken, MakeGroupId("Z", 2))
+ )
+ );
+ }
+
+ internal static void AddInvariantToAllLoops(Expr Invariant, StmtList stmtList)
+ {
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ AddInvariantToAllLoops(Invariant, bb);
+ }
+ }
+
+ internal static void AddInvariantToAllLoops(Expr Invariant, BigBlock bb)
+ {
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd wc = bb.ec as WhileCmd;
+ wc.Invariants.Add(new AssertCmd(wc.tok, Invariant));
+ AddInvariantToAllLoops(Invariant, wc.Body);
+ }
+ Debug.Assert(!(bb.ec is IfCmd));
+ }
+
+ internal static int GetThreadSuffix(string p)
+ {
+ return Int32.Parse(p.Substring(p.IndexOf("$") + 1, p.Length - (p.IndexOf("$") + 1)));
+ }
+
+ private void GeneratePreconditionsForDimension(IToken tok, String dimension)
+ {
+ foreach (Declaration D in Program.TopLevelDeclarations.ToList())
+ {
+ if (!(D is Procedure))
+ {
+ continue;
+ }
+ Procedure Proc = D as Procedure;
+ if (QKeyValue.FindIntAttribute(Proc.Attributes, "inline", -1) == 1)
+ {
+ continue;
+ }
+
+ Expr GroupSizePositive;
+ Expr NumGroupsPositive;
+ Expr GroupIdNonNegative;
+ Expr GroupIdLessThanNumGroups;
+
+ if (GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)))
+ {
+ GroupSizePositive = MakeBVSgt(new IdentifierExpr(tok, GetGroupSize(dimension)), ZeroBV());
+ NumGroupsPositive = MakeBVSgt(new IdentifierExpr(tok, GetNumGroups(dimension)), ZeroBV());
+ GroupIdNonNegative = MakeBVSge(new IdentifierExpr(tok, GetGroupId(dimension)), ZeroBV());
+ GroupIdLessThanNumGroups = MakeBVSlt(new IdentifierExpr(tok, GetGroupId(dimension)), new IdentifierExpr(tok, GetNumGroups(dimension)));
+ }
+ else
+ {
+ GroupSizePositive = Expr.Gt(new IdentifierExpr(tok, GetGroupSize(dimension)), Zero());
+ NumGroupsPositive = Expr.Gt(new IdentifierExpr(tok, GetNumGroups(dimension)), Zero());
+ GroupIdNonNegative = Expr.Ge(new IdentifierExpr(tok, GetGroupId(dimension)), Zero());
+ GroupIdLessThanNumGroups = Expr.Lt(new IdentifierExpr(tok, GetGroupId(dimension)), new IdentifierExpr(tok, GetNumGroups(dimension)));
+ }
+
+ Proc.Requires.Add(new Requires(false, GroupSizePositive));
+ Proc.Requires.Add(new Requires(false, NumGroupsPositive));
+ Proc.Requires.Add(new Requires(false, new VariableDualiser(1, null, null).VisitExpr(GroupIdNonNegative)));
+ Proc.Requires.Add(new Requires(false, new VariableDualiser(2, null, null).VisitExpr(GroupIdNonNegative)));
+ Proc.Requires.Add(new Requires(false, new VariableDualiser(1, null, null).VisitExpr(GroupIdLessThanNumGroups)));
+ Proc.Requires.Add(new Requires(false, new VariableDualiser(2, null, null).VisitExpr(GroupIdLessThanNumGroups)));
+
+ Expr ThreadIdNonNegative =
+ GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)) ?
+ MakeBVSge(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), ZeroBV())
+ :
+ Expr.Ge(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), Zero());
+ Expr ThreadIdLessThanGroupSize =
+ GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)) ?
+ MakeBVSlt(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), new IdentifierExpr(tok, GetGroupSize(dimension)))
+ :
+ Expr.Lt(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), new IdentifierExpr(tok, GetGroupSize(dimension)));
+
+ Proc.Requires.Add(new Requires(false, new VariableDualiser(1, null, null).VisitExpr(ThreadIdNonNegative)));
+ Proc.Requires.Add(new Requires(false, new VariableDualiser(2, null, null).VisitExpr(ThreadIdNonNegative)));
+ Proc.Requires.Add(new Requires(false, new VariableDualiser(1, null, null).VisitExpr(ThreadIdLessThanGroupSize)));
+ Proc.Requires.Add(new Requires(false, new VariableDualiser(2, null, null).VisitExpr(ThreadIdLessThanGroupSize)));
+
+ }
+
+ }
+
+ private Function GetOrCreateBVFunction(string functionName, string smtName, Microsoft.Boogie.Type resultType, params Microsoft.Boogie.Type[] argTypes)
+ {
+ Function f = (Function)ResContext.LookUpProcedure(functionName);
+ if (f != null)
+ return f;
+
+ f = new Function(Token.NoToken, functionName,
+ new VariableSeq(argTypes.Select(t => new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "", t))).ToArray()),
+ new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "", resultType)));
+ f.AddAttribute("bvbuiltin", smtName);
+ Program.TopLevelDeclarations.Add(f);
+ ResContext.AddProcedure(f);
+ return f;
+ }
+
+ private Expr MakeBVFunctionCall(string functionName, string smtName, Microsoft.Boogie.Type resultType, params Expr[] args)
+ {
+ Function f = GetOrCreateBVFunction(functionName, smtName, resultType, args.Select(a => a.Type).ToArray());
+ var e = new NAryExpr(Token.NoToken, new FunctionCall(f), new ExprSeq(args));
+ e.Type = resultType;
+ return e;
+ }
+
+ private Expr MakeBitVectorBinaryBoolean(string suffix, string smtName, Expr lhs, Expr rhs)
+ {
+ return MakeBVFunctionCall("BV" + lhs.Type.BvBits + "_" + suffix, smtName, Microsoft.Boogie.Type.Bool, lhs, rhs);
+ }
+
+ private Expr MakeBitVectorBinaryBitVector(string suffix, string smtName, Expr lhs, Expr rhs)
+ {
+ return MakeBVFunctionCall("BV" + lhs.Type.BvBits + "_" + suffix, smtName, lhs.Type, lhs, rhs);
+ }
+
+ internal Expr MakeBVSlt(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBoolean("SLT", "bvslt", lhs, rhs); }
+ internal Expr MakeBVSgt(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBoolean("SGT", "bvsgt", lhs, rhs); }
+ internal Expr MakeBVSge(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBoolean("SGE", "bvsge", lhs, rhs); }
+
+ internal Expr MakeBVAnd(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBitVector("AND", "bvand", lhs, rhs); }
+ internal Expr MakeBVAdd(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBitVector("ADD", "bvadd", lhs, rhs); }
+ internal Expr MakeBVSub(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBitVector("SUB", "bvsub", lhs, rhs); }
+ internal Expr MakeBVMul(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBitVector("MUL", "bvmul", lhs, rhs); }
+ internal Expr MakeBVURem(Expr lhs, Expr rhs) { return MakeBitVectorBinaryBitVector("UREM", "bvurem", lhs, rhs); }
+
+ internal static Expr MakeBitVectorBinaryBoolean(string functionName, Expr lhs, Expr rhs)
+ {
+ return new NAryExpr(lhs.tok, new FunctionCall(new Function(lhs.tok, functionName, new VariableSeq(new Variable[] {
+ new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "arg1", Microsoft.Boogie.Type.GetBvType(32))),
+ new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "arg2", Microsoft.Boogie.Type.GetBvType(32)))
+ }), new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "result", Microsoft.Boogie.Type.Bool)))), new ExprSeq(new Expr[] { lhs, rhs }));
+ }
+
+ internal static Expr MakeBitVectorBinaryBitVector(string functionName, Expr lhs, Expr rhs)
+ {
+ return new NAryExpr(lhs.tok, new FunctionCall(new Function(lhs.tok, functionName, new VariableSeq(new Variable[] {
+ new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "arg1", Microsoft.Boogie.Type.GetBvType(32))),
+ new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "arg2", Microsoft.Boogie.Type.GetBvType(32)))
+ }), new LocalVariable(lhs.tok, new TypedIdent(lhs.tok, "result", Microsoft.Boogie.Type.GetBvType(32))))), new ExprSeq(new Expr[] { lhs, rhs }));
+ }
+
+ private static bool IsBVFunctionCall(Expr e, string smtName, out ExprSeq args)
+ {
+ args = null;
+ var ne = e as NAryExpr;
+ if (ne == null)
+ return false;
+
+ var fc = ne.Fun as FunctionCall;
+ if (fc == null)
+ return false;
+
+ string bvBuiltin = QKeyValue.FindStringAttribute(fc.Func.Attributes, "bvbuiltin");
+ if (bvBuiltin == smtName)
+ {
+ args = ne.Args;
+ return true;
+ }
+
+ return false;
+ }
+
+ private static bool IsBVFunctionCall(Expr e, string smtName, out Expr lhs, out Expr rhs)
+ {
+ ExprSeq es;
+ if (IsBVFunctionCall(e, smtName, out es))
+ {
+ lhs = es[0]; rhs = es[1];
+ return true;
+ }
+ lhs = null; rhs = null;
+ return false;
+ }
+
+ internal static bool IsBVAdd(Expr e, out Expr lhs, out Expr rhs) { return IsBVFunctionCall(e, "bvadd", out lhs, out rhs); }
+ internal static bool IsBVMul(Expr e, out Expr lhs, out Expr rhs) { return IsBVFunctionCall(e, "bvmul", out lhs, out rhs); }
+
+ internal Constant GetGroupSize(string dimension)
+ {
+ Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
+ if (dimension.Equals("X")) return _GROUP_SIZE_X;
+ if (dimension.Equals("Y")) return _GROUP_SIZE_Y;
+ if (dimension.Equals("Z")) return _GROUP_SIZE_Z;
+ Debug.Assert(false);
+ return null;
+ }
+
+ internal Constant GetNumGroups(string dimension)
+ {
+ Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
+ if (dimension.Equals("X")) return _NUM_GROUPS_X;
+ if (dimension.Equals("Y")) return _NUM_GROUPS_Y;
+ if (dimension.Equals("Z")) return _NUM_GROUPS_Z;
+ Debug.Assert(false);
+ return null;
+ }
+
+ internal Constant MakeThreadId(IToken tok, string dimension)
+ {
+ Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
+ string name = null;
+ if (dimension.Equals("X")) name = _X.Name;
+ if (dimension.Equals("Y")) name = _Y.Name;
+ if (dimension.Equals("Z")) name = _Z.Name;
+ Debug.Assert(name != null);
+ return new Constant(tok, new TypedIdent(tok, name, GetTypeOfId(dimension)));
+ }
+
+ internal Constant MakeThreadId(IToken tok, string dimension, int number)
+ {
+ Constant resultWithoutThreadId = MakeThreadId(tok, dimension);
+ return new Constant(tok, new TypedIdent(tok, resultWithoutThreadId.Name + "$" + number, GetTypeOfId(dimension)));
+ }
+
+ internal static Constant GetGroupId(string dimension)
+ {
+ Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z"));
+ if (dimension.Equals("X")) return _GROUP_X;
+ if (dimension.Equals("Y")) return _GROUP_Y;
+ if (dimension.Equals("Z")) return _GROUP_Z;
+ Debug.Assert(false);
+ return null;
+ }
+
+ internal static Constant MakeGroupId(string dimension, int number)
+ {
+ Constant resultWithoutThreadId = GetGroupId(dimension);
+ return new Constant(Token.NoToken, new TypedIdent(Token.NoToken, resultWithoutThreadId.Name + "$" + number, GetTypeOfId(dimension)));
+ }
+
+ private static LiteralExpr Zero()
+ {
+ return new LiteralExpr(Token.NoToken, BigNum.FromInt(0));
+ }
+
+ internal static LiteralExpr ZeroBV()
+ {
+ return new LiteralExpr(Token.NoToken, BigNum.FromInt(0), 32);
+ }
+
+
+
+ private void GenerateBarrierImplementation()
+ {
+ IToken tok = BarrierProcedure.tok;
+
+ List<BigBlock> bigblocks = new List<BigBlock>();
+ BigBlock barrierEntryBlock = new BigBlock(tok, "__BarrierImpl", new CmdSeq(), null, null);
+ bigblocks.Add(barrierEntryBlock);
+
+ Debug.Assert((BarrierProcedure.InParams.Length % 2) == 0);
+ int paramsPerThread = BarrierProcedure.InParams.Length / 2;
+ IdentifierExpr P1 = new IdentifierExpr(tok, new LocalVariable(tok, BarrierProcedure.InParams[0].TypedIdent));
+ IdentifierExpr P2 = new IdentifierExpr(tok, new LocalVariable(tok, BarrierProcedure.InParams[paramsPerThread].TypedIdent));
+
+ Expr LocalFence1 = MakeFenceExpr(BarrierProcedure.InParams[1]);
+ Expr LocalFence2 = MakeFenceExpr(BarrierProcedure.InParams[paramsPerThread + 1]);
+
+ Expr GlobalFence1 = MakeFenceExpr(BarrierProcedure.InParams[2]);
+ Expr GlobalFence2 = MakeFenceExpr(BarrierProcedure.InParams[paramsPerThread + 2]);
+
+ Expr DivergenceCondition = Expr.Imp(ThreadsInSameGroup(), Expr.Eq(P1, P2));
+
+ Requires nonDivergenceRequires = new Requires(false, DivergenceCondition);
+ nonDivergenceRequires.Attributes = new QKeyValue(Token.NoToken, "barrier_divergence",
+ new List<object>(new object[] { }), null);
+ BarrierProcedure.Requires.Add(nonDivergenceRequires);
+
+ if (!CommandLineOptions.OnlyDivergence)
+ {
+ List<BigBlock> returnbigblocks = new List<BigBlock>();
+ returnbigblocks.Add(new BigBlock(tok, "__Disabled", new CmdSeq(), null, new ReturnCmd(tok)));
+ StmtList returnstatement = new StmtList(returnbigblocks, BarrierProcedure.tok);
+
+ Expr IfGuard = Expr.Or(Expr.And(Expr.Not(P1), Expr.Not(P2)), Expr.And(ThreadsInSameGroup(), Expr.Or(Expr.Not(P1), Expr.Not(P2))));
+ barrierEntryBlock.ec = new IfCmd(tok, IfGuard, returnstatement, null, null);
+ }
+
+ if(KernelArrayInfo.getGroupSharedArrays().Count > 0) {
+
+ Expr IfGuard1 = Expr.And(P1, LocalFence1);
+ Expr IfGuard2 = Expr.And(P2, LocalFence2);
+
+ bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(),
+ new IfCmd(Token.NoToken, IfGuard1, new StmtList(MakeResetBlocks(1, KernelArrayInfo.getGroupSharedArrays()), Token.NoToken), null, null),
+ null));
+ bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(),
+ new IfCmd(Token.NoToken, IfGuard2, new StmtList(MakeResetBlocks(2, KernelArrayInfo.getGroupSharedArrays()), Token.NoToken), null, null),
+ null));
+
+ bigblocks.AddRange(MakeHavocBlocks(KernelArrayInfo.getGroupSharedArrays()));
+ }
+
+ if (KernelArrayInfo.getGlobalArrays().Count > 0)
+ {
+ Expr IfGuard1 = Expr.And(P1, GlobalFence1);
+ Expr IfGuard2 = Expr.And(P2, GlobalFence2);
+
+ bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(),
+ new IfCmd(Token.NoToken, IfGuard1, new StmtList(MakeResetBlocks(1, KernelArrayInfo.getGlobalArrays()), Token.NoToken), null, null),
+ null));
+ bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(),
+ new IfCmd(Token.NoToken, IfGuard2, new StmtList(MakeResetBlocks(2, KernelArrayInfo.getGlobalArrays()), Token.NoToken), null, null),
+ null));
+
+ bigblocks.AddRange(MakeHavocBlocks(KernelArrayInfo.getGlobalArrays()));
+ }
+
+ StmtList statements = new StmtList(bigblocks, BarrierProcedure.tok);
+ Implementation BarrierImplementation =
+ new Implementation(BarrierProcedure.tok, BarrierProcedure.Name, new TypeVariableSeq(),
+ BarrierProcedure.InParams, BarrierProcedure.OutParams, new VariableSeq(), statements);
+
+ if (CommandLineOptions.Unstructured)
+ BarrierImplementation.Resolve(ResContext);
+
+ BarrierImplementation.AddAttribute("inline", new object[] { new LiteralExpr(tok, BigNum.FromInt(1)) });
+ BarrierProcedure.AddAttribute("inline", new object[] { new LiteralExpr(tok, BigNum.FromInt(1)) });
+
+ BarrierImplementation.Proc = BarrierProcedure;
+
+ Program.TopLevelDeclarations.Add(BarrierImplementation);
+ }
+
+ private static NAryExpr MakeFenceExpr(Variable v) {
+ return Expr.Eq(new IdentifierExpr(Token.NoToken, new LocalVariable(Token.NoToken, v.TypedIdent)),
+ new LiteralExpr(Token.NoToken, BigNum.FromInt(1), 1));
+ }
+
+ private static Expr flagIsSet(Expr Flags, int flag)
+ {
+ return Expr.Eq(new BvExtractExpr(
+ Token.NoToken, Flags, flag, flag - 1),
+ new LiteralExpr(Token.NoToken, BigNum.FromInt(1), 1));
+ }
+
+ private List<BigBlock> MakeResetBlocks(int Thread, ICollection<Variable> variables)
+ {
+ Debug.Assert(variables.Count > 0);
+ List<BigBlock> ResetAndHavocBlocks = new List<BigBlock>();
+ foreach (Variable v in variables)
+ {
+ ResetAndHavocBlocks.Add(RaceInstrumenter.MakeResetReadWriteSetStatements(v, Thread));
+ }
+ Debug.Assert(ResetAndHavocBlocks.Count > 0);
+ return ResetAndHavocBlocks;
+ }
+
+ private List<BigBlock> MakeHavocBlocks(ICollection<Variable> variables) {
+ Debug.Assert(variables.Count > 0);
+ List<BigBlock> result = new List<BigBlock>();
+ foreach (Variable v in variables) {
+ if (!ArrayModelledAdversarially(v)) {
+ result.Add(HavocSharedArray(v));
+ }
+ }
+ return result;
+ }
+
+ public static bool HasZDimension(Variable v)
+ {
+ if (v.TypedIdent.Type is MapType)
+ {
+ MapType mt = v.TypedIdent.Type as MapType;
+
+ if (mt.Result is MapType)
+ {
+ MapType mt2 = mt.Result as MapType;
+ if (mt2.Result is MapType)
+ {
+ Debug.Assert(!((mt2.Result as MapType).Result is MapType));
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private BigBlock HavocSharedArray(Variable v)
+ {
+ return new BigBlock(Token.NoToken, null,
+ new CmdSeq(new Cmd[] { new HavocCmd(Token.NoToken,
+ new IdentifierExprSeq(new IdentifierExpr[] { new IdentifierExpr(Token.NoToken, v) })) }), null, null);
+ }
+
+ internal static bool ModifiesSetContains(IdentifierExprSeq Modifies, IdentifierExpr v)
+ {
+ foreach (IdentifierExpr ie in Modifies)
+ {
+ if (ie.Name.Equals(v.Name))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void AbstractSharedState()
+ {
+ new AdversarialAbstraction(this).Abstract();
+ }
+
+ internal static string MakeOffsetVariableName(string Name, string AccessType)
+ {
+ return "_" + AccessType + "_OFFSET_" + Name;
+ }
+
+ internal static GlobalVariable MakeOffsetVariable(string Name, string ReadOrWrite)
+ {
+ return new GlobalVariable(Token.NoToken, new TypedIdent(Token.NoToken, MakeOffsetVariableName(Name, ReadOrWrite),
+ Microsoft.Boogie.Type.GetBvType(32)));
+ }
+
+ internal static string MakeSourceVariableName(string Name, string AccessType)
+ {
+ return "_" + AccessType + "_SOURCE_" + Name;
+ }
+
+ internal static GlobalVariable MakeSourceVariable(string name, string ReadOrWrite)
+ {
+ return new GlobalVariable(Token.NoToken, new TypedIdent(Token.NoToken, MakeSourceVariableName(name, ReadOrWrite),
+ Microsoft.Boogie.Type.GetBvType(32)));
+ }
+
+ internal GlobalVariable FindOrCreateAccessHasOccurredVariable(string varName, string accessType)
+ {
+ string name = MakeAccessHasOccurredVariableName(varName, accessType) + "$1";
+ foreach(Declaration D in Program.TopLevelDeclarations)
+ {
+ if(D is GlobalVariable && ((GlobalVariable)D).Name.Equals(name))
+ {
+ return D as GlobalVariable;
+ }
+ }
+
+ GlobalVariable result = new VariableDualiser(1, null, null).VisitVariable(
+ MakeAccessHasOccurredVariable(varName, accessType)) as GlobalVariable;
+
+ Program.TopLevelDeclarations.Add(result);
+ return result;
+
+ }
+
+ internal GlobalVariable FindOrCreateOffsetVariable(string varName, string accessType)
+ {
+ string name = MakeOffsetVariableName(varName, accessType) + "$1";
+ foreach (Declaration D in Program.TopLevelDeclarations)
+ {
+ if (D is GlobalVariable && ((GlobalVariable)D).Name.Equals(name))
+ {
+ return D as GlobalVariable;
+ }
+ }
+
+ GlobalVariable result = new VariableDualiser(1, null, null).VisitVariable(
+ MakeOffsetVariable(varName, accessType)) as GlobalVariable;
+
+ Program.TopLevelDeclarations.Add(result);
+ return result;
+
+ }
+
+ internal GlobalVariable FindOrCreateSourceVariable(string varName, string accessType) {
+ string name = MakeSourceVariableName(varName, accessType) + "$1";
+ foreach (Declaration D in Program.TopLevelDeclarations) {
+ if (D is GlobalVariable && ((GlobalVariable)D).Name.Equals(name)) {
+ return D as GlobalVariable;
+ }
+ }
+
+ GlobalVariable result = new VariableDualiser(1, null, null).VisitVariable(
+ MakeSourceVariable(varName, accessType)) as GlobalVariable;
+
+ Program.TopLevelDeclarations.Add(result);
+ return result;
+
+ }
+
+ internal static GlobalVariable MakeAccessHasOccurredVariable(string varName, string accessType)
+ {
+ return new GlobalVariable(Token.NoToken, new TypedIdent(Token.NoToken, MakeAccessHasOccurredVariableName(varName, accessType), Microsoft.Boogie.Type.Bool));
+ }
+
+ internal static string MakeAccessHasOccurredVariableName(string varName, string accessType)
+ {
+ return "_" + accessType + "_HAS_OCCURRED_" + varName;
+ }
+
+ internal static IdentifierExpr MakeAccessHasOccurredExpr(string varName, string accessType)
+ {
+ return new IdentifierExpr(Token.NoToken, MakeAccessHasOccurredVariable(varName, accessType));
+ }
+
+ internal static bool IsIntOrBv32(Microsoft.Boogie.Type type)
+ {
+ return type.Equals(Microsoft.Boogie.Type.Int) || type.Equals(Microsoft.Boogie.Type.GetBvType(32));
+ }
+
+ private void PullOutNonLocalAccesses()
+ {
+ foreach (Declaration d in Program.TopLevelDeclarations)
+ {
+ if (d is Implementation)
+ {
+ (d as Implementation).StructuredStmts = PullOutNonLocalAccesses((d as Implementation).StructuredStmts, (d as Implementation));
+ }
+ }
+ }
+
+ private void RemoveElseIfs()
+ {
+ foreach (Declaration d in Program.TopLevelDeclarations)
+ {
+ if (d is Implementation)
+ {
+ (d as Implementation).StructuredStmts = RemoveElseIfs((d as Implementation).StructuredStmts);
+ }
+ }
+ }
+
+ private void RemoveRedundantReturns()
+ {
+ foreach (Declaration d in Program.TopLevelDeclarations)
+ {
+ if (d is Implementation)
+ {
+ RemoveRedundantReturns((d as Implementation).StructuredStmts);
+ }
+ }
+ }
+
+ private StmtList RemoveElseIfs(StmtList stmtList)
+ {
+ Contract.Requires(stmtList != null);
+
+ StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
+
+ foreach (BigBlock bodyBlock in stmtList.BigBlocks)
+ {
+ result.BigBlocks.Add(RemoveElseIfs(bodyBlock));
+ }
+
+ return result;
+ }
+
+ private void RemoveRedundantReturns(StmtList stmtList)
+ {
+ Contract.Requires(stmtList != null);
+
+ BigBlock bb = stmtList.BigBlocks[stmtList.BigBlocks.Count - 1];
+
+ if (bb.tc is ReturnCmd)
+ {
+ bb.tc = null;
+ }
+ }
+
+ private BigBlock RemoveElseIfs(BigBlock bb)
+ {
+ BigBlock result = bb;
+ if (bb.ec is IfCmd)
+ {
+ IfCmd IfCommand = bb.ec as IfCmd;
+
+ Debug.Assert(IfCommand.elseIf == null || IfCommand.elseBlock == null);
+
+ if (IfCommand.elseIf != null)
+ {
+ IfCommand.elseBlock = new StmtList(new List<BigBlock>(new BigBlock[] {
+ new BigBlock(bb.tok, null, new CmdSeq(), IfCommand.elseIf, null)
+ }), bb.tok);
+ IfCommand.elseIf = null;
+ }
+
+ IfCommand.thn = RemoveElseIfs(IfCommand.thn);
+ if (IfCommand.elseBlock != null)
+ {
+ IfCommand.elseBlock = RemoveElseIfs(IfCommand.elseBlock);
+ }
+
+ }
+ else if (bb.ec is WhileCmd)
+ {
+ (bb.ec as WhileCmd).Body = RemoveElseIfs((bb.ec as WhileCmd).Body);
+ }
+
+ return result;
+ }
+
+ private StmtList PullOutNonLocalAccesses(StmtList stmtList, Implementation impl)
+ {
+ Contract.Requires(stmtList != null);
+
+ StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
+
+ foreach (BigBlock bodyBlock in stmtList.BigBlocks)
+ {
+ result.BigBlocks.Add(PullOutNonLocalAccesses(bodyBlock, impl));
+ }
+
+ return result;
+ }
+
+ private BigBlock PullOutNonLocalAccesses(BigBlock bb, Implementation impl)
+ {
+
+ BigBlock result = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
+
+ foreach (Cmd c in bb.simpleCmds)
+ {
+
+ if (c is CallCmd)
+ {
+ CallCmd call = c as CallCmd;
+
+ List<Expr> newIns = new List<Expr>();
+
+ for (int i = 0; i < call.Ins.Count; i++)
+ {
+ Expr e = call.Ins[i];
+
+ while (NonLocalAccessCollector.ContainsNonLocalAccess(e, KernelArrayInfo))
+ {
+ AssignCmd assignToTemp;
+ LocalVariable tempDecl;
+ e = ExtractLocalAccessToTemp(e, out assignToTemp, out tempDecl);
+ result.simpleCmds.Add(assignToTemp);
+ impl.LocVars.Add(tempDecl);
+ }
+
+ newIns.Add(e);
+
+ }
+
+ CallCmd newCall = new CallCmd(call.tok, call.callee, newIns, call.Outs);
+ newCall.Proc = call.Proc;
+ result.simpleCmds.Add(newCall);
+ }
+ else if (c is AssignCmd)
+ {
+ AssignCmd assign = c as AssignCmd;
+
+ if (assign.Lhss.Zip(assign.Rhss, (lhs, rhs) =>
+ !NonLocalAccessCollector.ContainsNonLocalAccess(rhs, KernelArrayInfo) ||
+ (!NonLocalAccessCollector.ContainsNonLocalAccess(lhs, KernelArrayInfo) &&
+ NonLocalAccessCollector.IsNonLocalAccess(rhs, KernelArrayInfo))).All(b => b))
+ {
+ result.simpleCmds.Add(c);
+ }
+ else
+ {
+ Debug.Assert(assign.Lhss.Count == 1 && assign.Rhss.Count == 1);
+ AssignLhs lhs = assign.Lhss.ElementAt(0);
+ Expr rhs = assign.Rhss.ElementAt(0);
+ rhs = PullOutNonLocalAccessesIntoTemps(result, rhs, impl);
+ List<AssignLhs> newLhss = new List<AssignLhs>();
+ newLhss.Add(lhs);
+ List<Expr> newRhss = new List<Expr>();
+ newRhss.Add(rhs);
+ result.simpleCmds.Add(new AssignCmd(assign.tok, newLhss, newRhss));
+ }
+
+ }
+ else if (c is HavocCmd)
+ {
+ result.simpleCmds.Add(c);
+ }
+ else if (c is AssertCmd)
+ {
+ result.simpleCmds.Add(new AssertCmd(c.tok, PullOutNonLocalAccessesIntoTemps(result, (c as AssertCmd).Expr, impl)));
+ }
+ else if (c is AssumeCmd)
+ {
+ result.simpleCmds.Add(new AssumeCmd(c.tok, PullOutNonLocalAccessesIntoTemps(result, (c as AssumeCmd).Expr, impl)));
+ }
+ else
+ {
+ Console.WriteLine(c);
+ Debug.Assert(false);
+ }
+ }
+
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd WhileCommand = bb.ec as WhileCmd;
+ while (NonLocalAccessCollector.ContainsNonLocalAccess(WhileCommand.Guard, KernelArrayInfo))
+ {
+ AssignCmd assignToTemp;
+ LocalVariable tempDecl;
+ WhileCommand.Guard = ExtractLocalAccessToTemp(WhileCommand.Guard, out assignToTemp, out tempDecl);
+ result.simpleCmds.Add(assignToTemp);
+ impl.LocVars.Add(tempDecl);
+ }
+ result.ec = new WhileCmd(WhileCommand.tok, WhileCommand.Guard, WhileCommand.Invariants, PullOutNonLocalAccesses(WhileCommand.Body, impl));
+ }
+ else if (bb.ec is IfCmd)
+ {
+ IfCmd IfCommand = bb.ec as IfCmd;
+ Debug.Assert(IfCommand.elseIf == null); // "else if" must have been eliminated by this phase
+ while (NonLocalAccessCollector.ContainsNonLocalAccess(IfCommand.Guard, KernelArrayInfo))
+ {
+ AssignCmd assignToTemp;
+ LocalVariable tempDecl;
+ IfCommand.Guard = ExtractLocalAccessToTemp(IfCommand.Guard, out assignToTemp, out tempDecl);
+ result.simpleCmds.Add(assignToTemp);
+ impl.LocVars.Add(tempDecl);
+ }
+ result.ec = new IfCmd(IfCommand.tok, IfCommand.Guard, PullOutNonLocalAccesses(IfCommand.thn, impl), IfCommand.elseIf, IfCommand.elseBlock != null ? PullOutNonLocalAccesses(IfCommand.elseBlock, impl) : null);
+ }
+ else if (bb.ec is BreakCmd)
+ {
+ result.ec = bb.ec;
+ }
+ else
+ {
+ Debug.Assert(bb.ec == null);
+ }
+
+ return result;
+
+ }
+
+ private Expr PullOutNonLocalAccessesIntoTemps(BigBlock result, Expr e, Implementation impl)
+ {
+ while (NonLocalAccessCollector.ContainsNonLocalAccess(e, KernelArrayInfo))
+ {
+ AssignCmd assignToTemp;
+ LocalVariable tempDecl;
+ e = ExtractLocalAccessToTemp(e, out assignToTemp, out tempDecl);
+ result.simpleCmds.Add(assignToTemp);
+ impl.LocVars.Add(tempDecl);
+ }
+ return e;
+ }
+
+ private Expr ExtractLocalAccessToTemp(Expr rhs, out AssignCmd tempAssignment, out LocalVariable tempDeclaration)
+ {
+ NonLocalAccessExtractor extractor = new NonLocalAccessExtractor(TempCounter, KernelArrayInfo);
+ TempCounter++;
+ rhs = extractor.VisitExpr(rhs);
+ tempAssignment = extractor.Assignment;
+ tempDeclaration = extractor.Declaration;
+ return rhs;
+ }
+
+ private void MakeKernelDualised()
+ {
+
+ List<Declaration> NewTopLevelDeclarations = new List<Declaration>();
+
+ foreach (Declaration d in Program.TopLevelDeclarations)
+ {
+ if (d is Procedure)
+ {
+
+ new KernelDualiser(this).DualiseProcedure(d as Procedure);
+
+ NewTopLevelDeclarations.Add(d as Procedure);
+
+ continue;
+
+ }
+
+ if (d is Implementation)
+ {
+
+ new KernelDualiser(this).DualiseImplementation(d as Implementation, CommandLineOptions.Unstructured);
+
+ NewTopLevelDeclarations.Add(d as Implementation);
+
+ continue;
+
+ }
+
+ if (d is Variable && ((d as Variable).IsMutable ||
+ IsThreadLocalIdConstant(d as Variable) ||
+ IsGroupIdConstant(d as Variable))) {
+ var v = d as Variable;
+
+ if (KernelArrayInfo.getGlobalArrays().Contains(v)) {
+ NewTopLevelDeclarations.Add(v);
+ continue;
+ }
+
+ if (KernelArrayInfo.getGroupSharedArrays().Contains(v)) {
+ Variable newV = new GlobalVariable(Token.NoToken, new TypedIdent(Token.NoToken,
+ v.Name, new MapType(Token.NoToken, new TypeVariableSeq(),
+ new TypeSeq(new Microsoft.Boogie.Type[] { Microsoft.Boogie.Type.Bool }),
+ v.TypedIdent.Type)));
+ newV.Attributes = v.Attributes;
+ NewTopLevelDeclarations.Add(newV);
+ continue;
+ }
+
+ NewTopLevelDeclarations.Add(new VariableDualiser(1, null, null).VisitVariable((Variable)v.Clone()));
+ if (!QKeyValue.FindBoolAttribute(v.Attributes, "race_checking")) {
+ NewTopLevelDeclarations.Add(new VariableDualiser(2, null, null).VisitVariable((Variable)v.Clone()));
+ }
+
+ continue;
+ }
+
+ NewTopLevelDeclarations.Add(d);
+
+ }
+
+ Program.TopLevelDeclarations = NewTopLevelDeclarations;
+
+ }
+
+ private void MakeKernelPredicated()
+ {
+ if (CommandLineOptions.Unstructured)
+ {
+ if (CommandLineOptions.SmartPredication)
+ {
+ SmartBlockPredicator.Predicate(Program, proc => true, uniformityAnalyser);
+ }
+ else
+ {
+ BlockPredicator.Predicate(Program, /*createCandidateInvariants=*/CommandLineOptions.Inference);
+ }
+ return;
+ }
+
+ foreach (Declaration d in Program.TopLevelDeclarations)
+ {
+ if (d is Procedure)
+ {
+ Procedure proc = d as Procedure;
+ IdentifierExpr enabled = new IdentifierExpr(proc.tok,
+ new LocalVariable(proc.tok, new TypedIdent(proc.tok, "_P", Microsoft.Boogie.Type.Bool)));
+ Expr predicateExpr;
+ if (!uniformityAnalyser.IsUniform(proc.Name))
+ {
+ // Add predicate to start of parameter list
+ VariableSeq NewIns = new VariableSeq();
+ NewIns.Add(enabled.Decl);
+ foreach (Variable v in proc.InParams)
+ {
+ NewIns.Add(v);
+ }
+ proc.InParams = NewIns;
+ predicateExpr = enabled;
+ }
+ else
+ {
+ predicateExpr = Expr.True;
+ }
+
+ RequiresSeq newRequires = new RequiresSeq();
+ foreach (Requires r in proc.Requires)
+ {
+ newRequires.Add(new Requires(r.Free, Predicator.ProcessEnabledIntrinsics(r.Condition, predicateExpr)));
+ }
+ proc.Requires = newRequires;
+
+ EnsuresSeq newEnsures = new EnsuresSeq();
+ foreach (Ensures e in proc.Ensures)
+ {
+ newEnsures.Add(new Ensures(e.Free, Predicator.ProcessEnabledIntrinsics(e.Condition, predicateExpr)));
+ }
+ proc.Ensures = newEnsures;
+
+ }
+ else if (d is Implementation)
+ {
+ Implementation impl = d as Implementation;
+ new Predicator(this, !uniformityAnalyser.IsUniform(impl.Name)).transform
+ (impl);
+ }
+ }
+
+ }
+
+ private void CheckKernelParameters()
+ {
+ if (KernelProcedure.OutParams.Length != 0)
+ {
+ Error(KernelProcedure.tok, "Kernel should not take return anything");
+ }
+ }
+
+
+ private int Check()
+ {
+ BarrierProcedure = FindOrCreateBarrierProcedure();
+ KernelProcedure = CheckExactlyOneKernelProcedure();
+
+ if (ErrorCount > 0)
+ {
+ return ErrorCount;
+ }
+
+ if (BarrierProcedure.InParams.Length != 2)
+ {
+ Error(BarrierProcedure, "Barrier procedure must take exactly two arguments");
+ }
+ else if (!BarrierProcedure.InParams[0].TypedIdent.Type.Equals(new BvType(1)))
+ {
+ Error(BarrierProcedure, "First argument to barrier procedure must have type bv1");
+ }
+ else if (!BarrierProcedure.InParams[1].TypedIdent.Type.Equals(new BvType(1))) {
+ Error(BarrierProcedure, "Second argument to barrier procedure must have type bv1");
+ }
+
+ if (BarrierProcedure.OutParams.Length != 0)
+ {
+ Error(BarrierProcedure, "Barrier procedure must not return any results");
+ }
+
+ if (!FindNonLocalVariables())
+ {
+ return ErrorCount;
+ }
+
+ CheckKernelImplementation();
+ return ErrorCount;
+ }
+
+ public static bool IsThreadLocalIdConstant(Variable variable)
+ {
+ return variable.Name.Equals(_X.Name) || variable.Name.Equals(_Y.Name) || variable.Name.Equals(_Z.Name);
+ }
+
+ public static bool IsGroupIdConstant(Variable variable)
+ {
+ return variable.Name.Equals(_GROUP_X.Name) || variable.Name.Equals(_GROUP_Y.Name) || variable.Name.Equals(_GROUP_Z.Name);
+ }
+
+ internal void AddCandidateInvariant(IRegion region, Expr e, string tag)
+ {
+ region.AddInvariant(Program.CreateCandidateInvariant(e, tag));
+ }
+
+ internal Implementation GetImplementation(string procedureName)
+ {
+ foreach (Declaration D in Program.TopLevelDeclarations)
+ {
+ if (D is Implementation && ((D as Implementation).Name == procedureName))
+ {
+ return D as Implementation;
+ }
+ }
+ Debug.Assert(false);
+ return null;
+ }
+
+
+ internal bool ContainsBarrierCall(IRegion loop)
+ {
+ foreach (Cmd c in loop.Cmds())
+ {
+ if (c is CallCmd && ((c as CallCmd).Proc == BarrierProcedure))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+
+ internal bool ArrayModelledAdversarially(Variable v)
+ {
+ if (CommandLineOptions.AdversarialAbstraction)
+ {
+ return true;
+ }
+ if (CommandLineOptions.EqualityAbstraction)
+ {
+ return false;
+ }
+ return !arrayControlFlowAnalyser.MayAffectControlFlow(v.Name);
+ }
+
+ internal Expr GlobalIdExpr(string dimension)
+ {
+ return MakeBVAdd(MakeBVMul(
+ new IdentifierExpr(Token.NoToken, GetGroupId(dimension)), new IdentifierExpr(Token.NoToken, GetGroupSize(dimension))),
+ new IdentifierExpr(Token.NoToken, MakeThreadId(Token.NoToken, dimension)));
+ }
+
+ internal IRegion RootRegion(Implementation Impl)
+ {
+ if (CommandLineOptions.Unstructured)
+ return new UnstructuredRegion(Program, Impl);
+ else
+ return new StructuredRegion(Impl);
+ }
+
+
+ public static bool IsGivenConstant(Expr e, Constant c)
+ {
+ if (!(e is IdentifierExpr))
+ return false;
+
+ var varName = ((IdentifierExpr)e).Decl.Name;
+ return (StripThreadIdentifier(varName) == StripThreadIdentifier(c.Name));
+ }
+
+ public bool SubstIsGivenConstant(Implementation impl, Expr e, Constant c)
+ {
+ if (!(e is IdentifierExpr))
+ return false;
+ e = varDefAnalyses[impl].SubstDefinitions(e, impl.Name);
+ return IsGivenConstant(e, c);
+ }
+
+ public Constant GetLocalIdConst(int dim)
+ {
+ switch (dim)
+ {
+ case 0: return _X;
+ case 1: return _Y;
+ case 2: return _Z;
+ default: Debug.Assert(false);
+ return null;
+ }
+ }
+
+ public Constant GetGroupIdConst(int dim)
+ {
+ switch (dim)
+ {
+ case 0: return _GROUP_X;
+ case 1: return _GROUP_Y;
+ case 2: return _GROUP_Z;
+ default: Debug.Assert(false);
+ return null;
+ }
+ }
+
+ public Constant GetGroupSizeConst(int dim)
+ {
+ switch (dim)
+ {
+ case 0: return _GROUP_SIZE_X;
+ case 1: return _GROUP_SIZE_Y;
+ case 2: return _GROUP_SIZE_Z;
+ default: Debug.Assert(false);
+ return null;
+ }
+ }
+
+ public bool IsLocalId(Expr e, int dim, Implementation impl)
+ {
+ return SubstIsGivenConstant(impl, e, GetLocalIdConst(dim));
+ }
+
+ public bool IsGlobalId(Expr e, int dim, Implementation impl)
+ {
+ e = varDefAnalyses[impl].SubstDefinitions(e, impl.Name);
+
+ if (e is NAryExpr && (e as NAryExpr).Fun.FunctionName.Equals("BV32_ADD"))
+ {
+ NAryExpr nary = e as NAryExpr;
+ Constant localId = GetLocalIdConst(dim);
+
+ if (IsGivenConstant(nary.Args[1], localId))
+ {
+ return IsGroupIdTimesGroupSize(nary.Args[0], dim);
+ }
+
+ if (IsGivenConstant(nary.Args[0], localId))
+ {
+ return IsGroupIdTimesGroupSize(nary.Args[1], dim);
+ }
+ }
+
+ return false;
+ }
+
+ private bool IsGroupIdTimesGroupSize(Expr expr, int dim)
+ {
+ if (expr is NAryExpr && (expr as NAryExpr).Fun.FunctionName.Equals("BV32_MUL"))
+ {
+ NAryExpr innerNary = expr as NAryExpr;
+
+ if (IsGroupIdAndSize(dim, innerNary.Args[0], innerNary.Args[1]))
+ {
+ return true;
+ }
+
+ if (IsGroupIdAndSize(dim, innerNary.Args[1], innerNary.Args[0]))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private bool IsGroupIdAndSize(int dim, Expr maybeGroupId, Expr maybeGroupSize)
+ {
+ return IsGivenConstant(maybeGroupId, GetGroupIdConst(dim)) &&
+ IsGivenConstant(maybeGroupSize, GetGroupSizeConst(dim));
+ }
+
+ internal Expr MaybeDualise(Expr e, int id, string procName)
+ {
+ if (id == 0)
+ return e;
+ else
+ return (Expr)new VariableDualiser(id, uniformityAnalyser, procName).Visit(e.Clone());
+ }
+
+ internal static bool IsConstantInCurrentRegion(IdentifierExpr expr) {
+ return (expr.Decl is Constant) ||
+ (expr.Decl is Formal && ((Formal)expr.Decl).InComing);
+ }
+
+ }
+
+
+}
diff --git a/Source/GPUVerify/GPUVerify.csproj b/Source/GPUVerify/GPUVerify.csproj
index 342c0539..e7122edf 100644
--- a/Source/GPUVerify/GPUVerify.csproj
+++ b/Source/GPUVerify/GPUVerify.csproj
@@ -1,180 +1,178 @@
-<?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)' == '' ">x86</Platform>
- <ProductVersion>8.0.30703</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{E5D16606-06D0-434F-A9D7-7D079BC80229}</ProjectGuid>
- <OutputType>Exe</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>GPUVerify</RootNamespace>
- <AssemblyName>GPUVerify</AssemblyName>
- <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
- <TargetFrameworkProfile>Client</TargetFrameworkProfile>
- <FileAlignment>512</FileAlignment>
- <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
- <PlatformTarget>x86</PlatformTarget>
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
- <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
- <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
- <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
- <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
- <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
- <CodeContractsNonNullObligations>True</CodeContractsNonNullObligations>
- <CodeContractsBoundsObligations>True</CodeContractsBoundsObligations>
- <CodeContractsArithmeticObligations>True</CodeContractsArithmeticObligations>
- <CodeContractsEnumObligations>False</CodeContractsEnumObligations>
- <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
- <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
- <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
- <CodeContractsShowSquigglies>True</CodeContractsShowSquigglies>
- <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
- <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
- <CodeContractsCustomRewriterAssembly />
- <CodeContractsCustomRewriterClass />
- <CodeContractsLibPaths />
- <CodeContractsExtraRewriteOptions />
- <CodeContractsExtraAnalysisOptions />
- <CodeContractsBaseLineFile />
- <CodeContractsCacheAnalysisResults>True</CodeContractsCacheAnalysisResults>
- <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
- <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
- <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
- <CodeContractsAnalysisPrecisionLevel>0</CodeContractsAnalysisPrecisionLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
- <PlatformTarget>x86</PlatformTarget>
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <CodeAnalysisLogFile>bin\Debug\GPUVerify.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
- <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
- <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
- <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
- <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
- <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
- <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
- <CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <Optimize>true</Optimize>
- <DebugType>pdbonly</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <CodeAnalysisLogFile>bin\Release\GPUVerify.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
- <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
- <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>MinimumRecommendedRules.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>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Core" />
- <Reference Include="System.Windows.Forms" />
- <Reference Include="System.Xml.Linq" />
- <Reference Include="System.Data.DataSetExtensions" />
- <Reference Include="Microsoft.CSharp" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="AccessCollector.cs" />
- <Compile Include="AccessRecord.cs" />
- <Compile Include="ArrayControlFlowAnalyser.cs" />
- <Compile Include="AsymmetricExpressionFinder.cs" />
- <Compile Include="StrideConstraint.cs" />
- <Compile Include="ReducedStrengthAnalysis.cs" />
- <Compile Include="UnstructuredRegion.cs" />
- <Compile Include="IRegion.cs" />
- <Compile Include="InvariantGenerationRules\LoopVariableBoundsInvariantGenerator.cs" />
- <Compile Include="InvariantGenerationRules\InvariantGenerationRule.cs" />
- <Compile Include="InvariantGenerationRules\PowerOfTwoInvariantGenerator.cs" />
- <Compile Include="EnsureDisabledThreadHasNoEffectInstrumenter.cs" />
- <Compile Include="KernelDualiser.cs" />
- <Compile Include="LiveVariableAnalyser.cs" />
- <Compile Include="LoopInvariantGenerator.cs" />
- <Compile Include="MayBePowerOfTwoAnalyser.cs" />
- <Compile Include="StructuredProgramVisitor.cs" />
- <Compile Include="EnabledToPredicateVisitor.cs" />
- <Compile Include="CommandLineOptions.cs" />
- <Compile Include="GPUVerifier.cs" />
- <Compile Include="IKernelArrayInfo.cs" />
- <Compile Include="IRaceInstrumenter.cs" />
- <Compile Include="Main.cs" />
- <Compile Include="NoConflictingAccessOptimiser.cs" />
- <Compile Include="NonLocalAccessCollector.cs" />
- <Compile Include="NonLocalAccessExtractor.cs" />
- <Compile Include="KernelArrayInfoLists.cs" />
- <Compile Include="NullRaceInstrumenter.cs" />
- <Compile Include="Predicator.cs" />
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="RaceInstrumenter.cs" />
- <Compile Include="ReadCollector.cs" />
- <Compile Include="UniformExpressionAnalysisVisitor.cs" />
- <Compile Include="UniformityAnalyser.cs" />
- <Compile Include="VariableDualiser.cs" />
- <Compile Include="VariablesOccurringInExpressionVisitor.cs" />
- <Compile Include="VariableDefinitionAnalysis.cs" />
- <Compile Include="StructuredRegion.cs" />
- <Compile Include="WriteCollector.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\AIFramework\AIFramework.csproj">
- <Project>{39B0658D-C955-41C5-9A43-48C97A1EF5FD}</Project>
- <Name>AIFramework</Name>
- </ProjectReference>
- <ProjectReference Include="..\Basetypes\Basetypes.csproj">
- <Project>{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}</Project>
- <Name>Basetypes</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="..\ParserHelper\ParserHelper.csproj">
- <Project>{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}</Project>
- <Name>ParserHelper</Name>
- </ProjectReference>
- <ProjectReference Include="..\VCGeneration\VCGeneration.csproj">
- <Project>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</Project>
- <Name>VCGeneration</Name>
- </ProjectReference>
- </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>
- -->
+<?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)' == '' ">x86</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{E5D16606-06D0-434F-A9D7-7D079BC80229}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>GPUVerify</RootNamespace>
+ <AssemblyName>GPUVerifyVCGen</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+ <FileAlignment>512</FileAlignment>
+ <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
+ <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
+ <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
+ <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
+ <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
+ <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
+ <CodeContractsNonNullObligations>True</CodeContractsNonNullObligations>
+ <CodeContractsBoundsObligations>True</CodeContractsBoundsObligations>
+ <CodeContractsArithmeticObligations>True</CodeContractsArithmeticObligations>
+ <CodeContractsEnumObligations>False</CodeContractsEnumObligations>
+ <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
+ <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
+ <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
+ <CodeContractsShowSquigglies>True</CodeContractsShowSquigglies>
+ <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
+ <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
+ <CodeContractsCustomRewriterAssembly />
+ <CodeContractsCustomRewriterClass />
+ <CodeContractsLibPaths />
+ <CodeContractsExtraRewriteOptions />
+ <CodeContractsExtraAnalysisOptions />
+ <CodeContractsBaseLineFile />
+ <CodeContractsCacheAnalysisResults>True</CodeContractsCacheAnalysisResults>
+ <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
+ <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
+ <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
+ <CodeContractsAnalysisPrecisionLevel>0</CodeContractsAnalysisPrecisionLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisLogFile>bin\Debug\GPUVerify.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+ <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+ <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+ <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+ <CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <Optimize>true</Optimize>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <CodeAnalysisLogFile>bin\Release\GPUVerify.exe.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+ <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+ <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.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>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AccessCollector.cs" />
+ <Compile Include="AccessRecord.cs" />
+ <Compile Include="AdversarialAbstraction.cs" />
+ <Compile Include="ArrayControlFlowAnalyser.cs" />
+ <Compile Include="AsymmetricExpressionFinder.cs" />
+ <Compile Include="StrideConstraint.cs" />
+ <Compile Include="ReducedStrengthAnalysis.cs" />
+ <Compile Include="UnstructuredRegion.cs" />
+ <Compile Include="IRegion.cs" />
+ <Compile Include="InvariantGenerationRules\LoopVariableBoundsInvariantGenerator.cs" />
+ <Compile Include="InvariantGenerationRules\InvariantGenerationRule.cs" />
+ <Compile Include="InvariantGenerationRules\PowerOfTwoInvariantGenerator.cs" />
+ <Compile Include="EnsureDisabledThreadHasNoEffectInstrumenter.cs" />
+ <Compile Include="KernelDualiser.cs" />
+ <Compile Include="LiveVariableAnalyser.cs" />
+ <Compile Include="LoopInvariantGenerator.cs" />
+ <Compile Include="MayBePowerOfTwoAnalyser.cs" />
+ <Compile Include="StructuredProgramVisitor.cs" />
+ <Compile Include="EnabledToPredicateVisitor.cs" />
+ <Compile Include="CommandLineOptions.cs" />
+ <Compile Include="GPUVerifier.cs" />
+ <Compile Include="IKernelArrayInfo.cs" />
+ <Compile Include="IRaceInstrumenter.cs" />
+ <Compile Include="Main.cs" />
+ <Compile Include="NonLocalAccessCollector.cs" />
+ <Compile Include="NonLocalAccessExtractor.cs" />
+ <Compile Include="KernelArrayInfoLists.cs" />
+ <Compile Include="NullRaceInstrumenter.cs" />
+ <Compile Include="Predicator.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="RaceInstrumenter.cs" />
+ <Compile Include="ReadCollector.cs" />
+ <Compile Include="VariableDualiser.cs" />
+ <Compile Include="VariablesOccurringInExpressionVisitor.cs" />
+ <Compile Include="VariableDefinitionAnalysis.cs" />
+ <Compile Include="StructuredRegion.cs" />
+ <Compile Include="WriteCollector.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\AIFramework\AIFramework.csproj">
+ <Project>{39B0658D-C955-41C5-9A43-48C97A1EF5FD}</Project>
+ <Name>AIFramework</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Basetypes\Basetypes.csproj">
+ <Project>{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}</Project>
+ <Name>Basetypes</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="..\ParserHelper\ParserHelper.csproj">
+ <Project>{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}</Project>
+ <Name>ParserHelper</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\VCGeneration\VCGeneration.csproj">
+ <Project>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</Project>
+ <Name>VCGeneration</Name>
+ </ProjectReference>
+ </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> \ No newline at end of file
diff --git a/Source/GPUVerify/IRaceInstrumenter.cs b/Source/GPUVerify/IRaceInstrumenter.cs
index 63b1ea1a..c85989c9 100644
--- a/Source/GPUVerify/IRaceInstrumenter.cs
+++ b/Source/GPUVerify/IRaceInstrumenter.cs
@@ -1,30 +1,31 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.Boogie;
-
-namespace GPUVerify
-{
- interface IRaceInstrumenter
- {
- void AddRaceCheckingCandidateInvariants(Implementation impl, IRegion region);
- void AddKernelPrecondition();
-
- // Summary:
- // Returns whether we should continue.
- // E.g. if race checking code could not be added because
- // the specified accesses to check were read/read or did not exist,
- // this will return false.
- bool AddRaceCheckingInstrumentation();
-
- void AddRaceCheckingDeclarations();
-
- BigBlock MakeResetReadWriteSetStatements(Variable v, int thread);
-
- void AddRaceCheckingCandidateRequires(Procedure Proc);
-
- void AddRaceCheckingCandidateEnsures(Procedure Proc);
-
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ interface IRaceInstrumenter
+ {
+ void AddRaceCheckingCandidateInvariants(Implementation impl, IRegion region);
+ void AddKernelPrecondition();
+
+ void AddRaceCheckingInstrumentation();
+
+ void AddRaceCheckingDeclarations();
+
+ BigBlock MakeResetReadWriteSetStatements(Variable v, int thread);
+
+ void AddRaceCheckingCandidateRequires(Procedure Proc);
+
+ void AddRaceCheckingCandidateEnsures(Procedure Proc);
+
+ void AddSourceLocationLoopInvariants(Implementation impl, IRegion region);
+
+ void DoHoudiniPointerAnalysis(Procedure Proc);
+ void AddStandardSourceVariablePreconditions();
+
+ void AddStandardSourceVariablePostconditions();
+ }
+}
diff --git a/Source/GPUVerify/InvariantGenerationRules/LoopVariableBoundsInvariantGenerator.cs b/Source/GPUVerify/InvariantGenerationRules/LoopVariableBoundsInvariantGenerator.cs
index f73bddb6..c21261b0 100644
--- a/Source/GPUVerify/InvariantGenerationRules/LoopVariableBoundsInvariantGenerator.cs
+++ b/Source/GPUVerify/InvariantGenerationRules/LoopVariableBoundsInvariantGenerator.cs
@@ -1,54 +1,55 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Diagnostics;
-using Microsoft.Boogie;
-using Microsoft.Basetypes;
-
-namespace GPUVerify.InvariantGenerationRules
-{
- class LoopVariableBoundsInvariantGenerator : InvariantGenerationRule
- {
-
- public LoopVariableBoundsInvariantGenerator(GPUVerifier verifier)
- : base(verifier)
- {
-
- }
-
- public override void GenerateCandidates(Implementation Impl, IRegion region)
- {
- if (verifier.uniformityAnalyser.IsUniform(Impl.Name, region.Guard()))
- {
- VariablesOccurringInExpressionVisitor visitor = new VariablesOccurringInExpressionVisitor();
- visitor.VisitExpr(region.Guard());
- foreach (Variable v in visitor.GetVariables())
- {
- if (!verifier.ContainsNamedVariable(LoopInvariantGenerator.GetModifiedVariables(region), v.Name))
- {
- continue;
- }
-
- if (IsBVType (v.TypedIdent.Type))
- {
- int BVWidth = (v.TypedIdent.Type as BvType).Bits;
-
- verifier.AddCandidateInvariant(region,
- verifier.MakeBVSge(
- new IdentifierExpr(v.tok, v),
- new LiteralExpr(v.tok, BigNum.FromInt(0), BVWidth)), "loop guard variable non-negative");
- }
- }
- }
- }
-
- private bool IsBVType(Microsoft.Boogie.Type type)
- {
- return type.Equals(Microsoft.Boogie.Type.GetBvType(32))
- || type.Equals(Microsoft.Boogie.Type.GetBvType(16))
- || type.Equals(Microsoft.Boogie.Type.GetBvType(8));
- }
-
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using Microsoft.Boogie;
+using Microsoft.Basetypes;
+
+namespace GPUVerify.InvariantGenerationRules
+{
+ class LoopVariableBoundsInvariantGenerator : InvariantGenerationRule
+ {
+
+ public LoopVariableBoundsInvariantGenerator(GPUVerifier verifier)
+ : base(verifier)
+ {
+
+ }
+
+ public override void GenerateCandidates(Implementation Impl, IRegion region)
+ {
+ var guard = region.Guard();
+ if (guard != null && verifier.uniformityAnalyser.IsUniform(Impl.Name, guard))
+ {
+ var visitor = new VariablesOccurringInExpressionVisitor();
+ visitor.VisitExpr(guard);
+ foreach (Variable v in visitor.GetVariables())
+ {
+ if (!verifier.ContainsNamedVariable(LoopInvariantGenerator.GetModifiedVariables(region), v.Name))
+ {
+ continue;
+ }
+
+ if (IsBVType (v.TypedIdent.Type))
+ {
+ int BVWidth = (v.TypedIdent.Type as BvType).Bits;
+
+ verifier.AddCandidateInvariant(region,
+ verifier.MakeBVSge(
+ new IdentifierExpr(v.tok, v),
+ new LiteralExpr(v.tok, BigNum.FromInt(0), BVWidth)), "loop guard variable non-negative");
+ }
+ }
+ }
+ }
+
+ private bool IsBVType(Microsoft.Boogie.Type type)
+ {
+ return type.Equals(Microsoft.Boogie.Type.GetBvType(32))
+ || type.Equals(Microsoft.Boogie.Type.GetBvType(16))
+ || type.Equals(Microsoft.Boogie.Type.GetBvType(8));
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/InvariantGenerationRules/PowerOfTwoInvariantGenerator.cs b/Source/GPUVerify/InvariantGenerationRules/PowerOfTwoInvariantGenerator.cs
index 8b24bb0a..8dab8474 100644
--- a/Source/GPUVerify/InvariantGenerationRules/PowerOfTwoInvariantGenerator.cs
+++ b/Source/GPUVerify/InvariantGenerationRules/PowerOfTwoInvariantGenerator.cs
@@ -1,61 +1,61 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Diagnostics;
-using Microsoft.Boogie;
-using Microsoft.Basetypes;
-
-namespace GPUVerify.InvariantGenerationRules
-{
- class PowerOfTwoInvariantGenerator : InvariantGenerationRule
- {
-
- public PowerOfTwoInvariantGenerator(GPUVerifier verifier)
- : base(verifier)
- {
-
- }
-
- public override void GenerateCandidates(Implementation Impl, IRegion region)
- {
- foreach (Variable v in Impl.LocVars)
- {
- string basicName = GPUVerifier.StripThreadIdentifier(v.Name);
- if (verifier.uniformityAnalyser.IsUniform(Impl.Name, basicName))
- {
- if (verifier.mayBePowerOfTwoAnalyser.MayBePowerOfTwo(Impl.Name, basicName))
- {
- if (verifier.ContainsNamedVariable(LoopInvariantGenerator.GetModifiedVariables(region), basicName))
- {
- verifier.AddCandidateInvariant(region, MakePowerOfTwoExpr(v), "pow2 disjunction");
- for (int i = (1 << 15); i > 0; i >>= 1)
- {
- verifier.AddCandidateInvariant(region,
- GPUVerifier.MakeBitVectorBinaryBoolean("BV32_LT",
- new IdentifierExpr(v.tok, v),
- new LiteralExpr(v.tok, BigNum.FromInt(i), 32)), "pow2 less than " + i);
- }
- verifier.AddCandidateInvariant(region,
- Expr.Neq(new IdentifierExpr(v.tok, v),
- new LiteralExpr(v.tok, BigNum.FromInt(0), 32)), "pow2 not zero");
- }
- }
- }
- }
- }
-
- private Expr MakePowerOfTwoExpr(Variable v)
- {
- Expr result = null;
- for (int i = 1 << 15; i > 0; i >>= 1)
- {
- Expr eq = Expr.Eq(new IdentifierExpr(v.tok, v), new LiteralExpr(v.tok, BigNum.FromInt(i), 32));
- result = (result == null ? eq : Expr.Or(eq, result));
- }
-
- return Expr.Or(Expr.Eq(new IdentifierExpr(v.tok, v), new LiteralExpr(v.tok, BigNum.FromInt(0), 32)), result);
- }
-
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using Microsoft.Boogie;
+using Microsoft.Basetypes;
+
+namespace GPUVerify.InvariantGenerationRules
+{
+ class PowerOfTwoInvariantGenerator : InvariantGenerationRule
+ {
+
+ public PowerOfTwoInvariantGenerator(GPUVerifier verifier)
+ : base(verifier)
+ {
+
+ }
+
+ public override void GenerateCandidates(Implementation Impl, IRegion region)
+ {
+ foreach (Variable v in Impl.LocVars)
+ {
+ string basicName = GPUVerifier.StripThreadIdentifier(v.Name);
+ if (verifier.uniformityAnalyser.IsUniform(Impl.Name, basicName))
+ {
+ if (verifier.mayBePowerOfTwoAnalyser.MayBePowerOfTwo(Impl.Name, basicName))
+ {
+ if (verifier.ContainsNamedVariable(LoopInvariantGenerator.GetModifiedVariables(region), basicName))
+ {
+ verifier.AddCandidateInvariant(region, MakePowerOfTwoExpr(v), "pow2 disjunction");
+ for (int i = (1 << 15); i > 0; i >>= 1)
+ {
+ verifier.AddCandidateInvariant(region,
+ verifier.MakeBVSlt(
+ new IdentifierExpr(v.tok, v),
+ new LiteralExpr(v.tok, BigNum.FromInt(i), 32)), "pow2 less than " + i);
+ }
+ verifier.AddCandidateInvariant(region,
+ Expr.Neq(new IdentifierExpr(v.tok, v),
+ new LiteralExpr(v.tok, BigNum.FromInt(0), 32)), "pow2 not zero");
+ }
+ }
+ }
+ }
+ }
+
+ private Expr MakePowerOfTwoExpr(Variable v)
+ {
+ Expr result = null;
+ for (int i = 1 << 15; i > 0; i >>= 1)
+ {
+ Expr eq = Expr.Eq(new IdentifierExpr(v.tok, v), new LiteralExpr(v.tok, BigNum.FromInt(i), 32));
+ result = (result == null ? eq : Expr.Or(eq, result));
+ }
+
+ return Expr.Or(Expr.Eq(new IdentifierExpr(v.tok, v), new LiteralExpr(v.tok, BigNum.FromInt(0), 32)), result);
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/KernelDualiser.cs b/Source/GPUVerify/KernelDualiser.cs
index 967b69ef..201018bb 100644
--- a/Source/GPUVerify/KernelDualiser.cs
+++ b/Source/GPUVerify/KernelDualiser.cs
@@ -5,382 +5,369 @@ using System.Text;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using Microsoft.Boogie;
+using Microsoft.Basetypes;
-namespace GPUVerify
-{
- class KernelDualiser
- {
- private GPUVerifier verifier;
+namespace GPUVerify {
+ class KernelDualiser {
+ private GPUVerifier verifier;
- public KernelDualiser(GPUVerifier verifier)
- {
- this.verifier = verifier;
- }
+ public KernelDualiser(GPUVerifier verifier) {
+ this.verifier = verifier;
+ }
- private string procName = null;
+ private string procName = null;
- internal void DualiseProcedure(Microsoft.Boogie.Procedure proc)
- {
- procName = proc.Name;
+ internal void DualiseProcedure(Microsoft.Boogie.Procedure proc) {
+ procName = proc.Name;
- proc.Requires = DualiseRequires(proc.Requires);
- proc.Ensures = DualiseEnsures(proc.Ensures);
+ proc.Requires = DualiseRequires(proc.Requires);
+ proc.Ensures = DualiseEnsures(proc.Ensures);
- proc.InParams = DualiseVariableSequence(proc.InParams);
- proc.OutParams = DualiseVariableSequence(proc.OutParams);
+ proc.InParams = DualiseVariableSequence(proc.InParams);
+ proc.OutParams = DualiseVariableSequence(proc.OutParams);
- procName = null;
+ procName = null;
+ }
+
+ private RequiresSeq DualiseRequires(RequiresSeq requiresSeq) {
+ RequiresSeq newRequires = new RequiresSeq();
+ foreach (Requires r in requiresSeq) {
+ newRequires.Add(MakeThreadSpecificRequires(r, 1));
+ if (!ContainsAsymmetricExpression(r.Condition)
+ && !verifier.uniformityAnalyser.IsUniform(procName, r.Condition)) {
+ newRequires.Add(MakeThreadSpecificRequires(r, 2));
}
+ }
+ return newRequires;
+ }
- private RequiresSeq DualiseRequires(RequiresSeq requiresSeq)
- {
- RequiresSeq newRequires = new RequiresSeq();
- foreach (Requires r in requiresSeq)
- {
- newRequires.Add(new Requires(r.Free, new VariableDualiser(1, verifier.uniformityAnalyser, procName).
- VisitExpr(r.Condition.Clone() as Expr)));
-
- if (!ContainsAsymmetricExpression(r.Condition)
- && !verifier.uniformityAnalyser.IsUniform(procName, r.Condition))
- {
- newRequires.Add(new Requires(r.Free, new VariableDualiser(2, verifier.uniformityAnalyser, procName).
- VisitExpr(r.Condition.Clone() as Expr)));
- }
- }
- return newRequires;
+ private EnsuresSeq DualiseEnsures(EnsuresSeq ensuresSeq) {
+ EnsuresSeq newEnsures = new EnsuresSeq();
+ foreach (Ensures e in ensuresSeq) {
+ newEnsures.Add(MakeThreadSpecificEnsures(e, 1));
+ if (!ContainsAsymmetricExpression(e.Condition)
+ && !verifier.uniformityAnalyser.IsUniform(procName, e.Condition)) {
+ newEnsures.Add(MakeThreadSpecificEnsures(e, 2));
}
+ }
+ return newEnsures;
+ }
- private EnsuresSeq DualiseEnsures(EnsuresSeq ensuresSeq)
- {
- EnsuresSeq newEnsures = new EnsuresSeq();
- foreach (Ensures e in ensuresSeq)
- {
- newEnsures.Add(new Ensures(e.Free, new VariableDualiser(1, verifier.uniformityAnalyser, procName).
- VisitExpr(e.Condition.Clone() as Expr)));
- if (!ContainsAsymmetricExpression(e.Condition)
- && !verifier.uniformityAnalyser.IsUniform(procName, e.Condition))
- {
- newEnsures.Add(new Ensures(e.Free, new VariableDualiser(2, verifier.uniformityAnalyser, procName).
- VisitExpr(e.Condition.Clone() as Expr)));
- }
- }
- return newEnsures;
+ private Requires MakeThreadSpecificRequires(Requires r, int Thread) {
+ Requires newR = new Requires(r.Free, new VariableDualiser(Thread, verifier.uniformityAnalyser, procName).
+ VisitExpr(r.Condition.Clone() as Expr));
+ newR.Attributes = MakeThreadSpecificAttributes(r.Attributes, Thread);
+ return newR;
+ }
+
+ private Ensures MakeThreadSpecificEnsures(Ensures e, int Thread) {
+ Ensures newE = new Ensures(e.Free, new VariableDualiser(Thread, verifier.uniformityAnalyser, procName).
+ VisitExpr(e.Condition.Clone() as Expr));
+ newE.Attributes = MakeThreadSpecificAttributes(e.Attributes, Thread);
+ return newE;
+ }
+
+ private AssertCmd MakeThreadSpecificAssert(AssertCmd a, int Thread) {
+ AssertCmd result = new AssertCmd(Token.NoToken, new VariableDualiser(Thread,
+ verifier.uniformityAnalyser, procName).VisitExpr(a.Expr.Clone() as Expr),
+ MakeThreadSpecificAttributes(a.Attributes, Thread));
+ return result;
+ }
+
+ private QKeyValue MakeThreadSpecificAttributes(QKeyValue attributes, int Thread) {
+ if (attributes == null) {
+ return null;
+ }
+ QKeyValue result = (QKeyValue)attributes.Clone();
+ result.AddLast(new QKeyValue(Token.NoToken, "thread",
+ new List<object>(new object[] { new LiteralExpr(Token.NoToken, BigNum.FromInt(Thread)) }), null));
+ return result;
+ }
+
+ private StmtList MakeDual(StmtList stmtList) {
+ Contract.Requires(stmtList != null);
+
+ StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
+
+ foreach (BigBlock bodyBlock in stmtList.BigBlocks) {
+ result.BigBlocks.Add(MakeDual(bodyBlock));
+ }
+
+ return result;
+ }
+
+ private void MakeDual(CmdSeq cs, Cmd c) {
+ if (c is CallCmd) {
+ CallCmd Call = c as CallCmd;
+
+ List<Expr> uniformNewIns = new List<Expr>();
+ List<Expr> nonUniformNewIns = new List<Expr>();
+ for (int i = 0; i < Call.Ins.Count; i++) {
+ if (verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetInParameter(Call.callee, i))) {
+ uniformNewIns.Add(Call.Ins[i]);
+ }
+ else if(!verifier.OnlyThread2.Contains(Call.callee)) {
+ nonUniformNewIns.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(Call.Ins[i]));
+ }
+ }
+ for (int i = 0; i < Call.Ins.Count; i++) {
+ if (
+ !(verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetInParameter(Call.callee, i)))
+ && !verifier.OnlyThread1.Contains(Call.callee)) {
+ nonUniformNewIns.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(Call.Ins[i]));
+ }
}
+ List<Expr> newIns = uniformNewIns;
+ newIns.AddRange(nonUniformNewIns);
- private StmtList MakeDual(StmtList stmtList)
- {
- Contract.Requires(stmtList != null);
+ List<IdentifierExpr> uniformNewOuts = new List<IdentifierExpr>();
+ List<IdentifierExpr> nonUniformNewOuts = new List<IdentifierExpr>();
+ for (int i = 0; i < Call.Outs.Count; i++) {
+ if (verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetOutParameter(Call.callee, i))) {
+ uniformNewOuts.Add(Call.Outs[i]);
+ }
+ else {
+ nonUniformNewOuts.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(Call.Outs[i].Clone() as IdentifierExpr) as IdentifierExpr);
+ }
- StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
+ }
+ for (int i = 0; i < Call.Outs.Count; i++) {
+ if (!(verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetOutParameter(Call.callee, i)))) {
+ nonUniformNewOuts.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(Call.Outs[i].Clone() as IdentifierExpr) as IdentifierExpr);
+ }
+ }
+
+ List<IdentifierExpr> newOuts = uniformNewOuts;
+ newOuts.AddRange(nonUniformNewOuts);
+
+ CallCmd NewCallCmd = new CallCmd(Call.tok, Call.callee, newIns, newOuts);
+
+ NewCallCmd.Proc = Call.Proc;
+
+ NewCallCmd.Attributes = Call.Attributes;
+
+ cs.Add(NewCallCmd);
+ }
+ else if (c is AssignCmd) {
+ AssignCmd assign = c as AssignCmd;
+
+ var vd1 = new VariableDualiser(1, verifier.uniformityAnalyser, procName);
+ var vd2 = new VariableDualiser(2, verifier.uniformityAnalyser, procName);
+
+ List<AssignLhs> lhss1 = new List<AssignLhs>();
+ List<AssignLhs> lhss2 = new List<AssignLhs>();
+
+ List<Expr> rhss1 = new List<Expr>();
+ List<Expr> rhss2 = new List<Expr>();
+
+ foreach(var pair in assign.Lhss.Zip(assign.Rhss)) {
+ if(pair.Item1 is SimpleAssignLhs &&
+ verifier.uniformityAnalyser.IsUniform(procName,
+ (pair.Item1 as SimpleAssignLhs).AssignedVariable.Name)) {
+ lhss1.Add(pair.Item1);
+ rhss1.Add(pair.Item2);
+ } else {
+ lhss1.Add(vd1.Visit(pair.Item1.Clone() as AssignLhs) as AssignLhs);
+ lhss2.Add(vd2.Visit(pair.Item1.Clone() as AssignLhs) as AssignLhs);
+ rhss1.Add(vd1.VisitExpr(pair.Item2.Clone() as Expr));
+ rhss2.Add(vd2.VisitExpr(pair.Item2.Clone() as Expr));
+ }
+ }
- foreach (BigBlock bodyBlock in stmtList.BigBlocks)
- {
- result.BigBlocks.Add(MakeDual(bodyBlock));
- }
+ Debug.Assert(lhss1.Count > 0);
+ cs.Add(new AssignCmd(Token.NoToken, lhss1, rhss1));
- return result;
+ if(lhss2.Count > 0) {
+ cs.Add(new AssignCmd(Token.NoToken, lhss2, rhss2));
}
- private void MakeDual(CmdSeq cs, Cmd c)
- {
- if (c is CallCmd)
- {
- CallCmd Call = c as CallCmd;
-
- List<Expr> uniformNewIns = new List<Expr>();
- List<Expr> nonUniformNewIns = new List<Expr>();
- for (int i = 0; i < Call.Ins.Count; i++)
- {
- if (verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetInParameter(Call.callee, i)))
- {
- uniformNewIns.Add(Call.Ins[i]);
- }
- else
- {
- nonUniformNewIns.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(Call.Ins[i]));
- }
- }
- for (int i = 0; i < Call.Ins.Count; i++)
- {
- if (!(verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetInParameter(Call.callee, i))))
- {
- nonUniformNewIns.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(Call.Ins[i]));
- }
- }
-
- List<Expr> newIns = uniformNewIns;
- newIns.AddRange(nonUniformNewIns);
-
- List<IdentifierExpr> uniformNewOuts = new List<IdentifierExpr>();
- List<IdentifierExpr> nonUniformNewOuts = new List<IdentifierExpr>();
- for (int i = 0; i < Call.Outs.Count; i++)
- {
- if (verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetOutParameter(Call.callee, i)))
- {
- uniformNewOuts.Add(Call.Outs[i]);
- }
- else
- {
- nonUniformNewOuts.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(Call.Outs[i].Clone() as IdentifierExpr) as IdentifierExpr);
- }
-
- }
- for (int i = 0; i < Call.Outs.Count; i++)
- {
- if (!(verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetOutParameter(Call.callee, i))))
- {
- nonUniformNewOuts.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(Call.Outs[i].Clone() as IdentifierExpr) as IdentifierExpr);
- }
- }
-
- List<IdentifierExpr> newOuts = uniformNewOuts;
- newOuts.AddRange(nonUniformNewOuts);
-
- CallCmd NewCallCmd = new CallCmd(Call.tok, Call.callee, newIns, newOuts);
-
- NewCallCmd.Proc = Call.Proc;
-
- cs.Add(NewCallCmd);
- }
- else if (c is AssignCmd)
- {
- AssignCmd assign = c as AssignCmd;
-
- if (assign.Lhss.All(lhs =>
- lhs is SimpleAssignLhs &&
- verifier.uniformityAnalyser.IsUniform(procName, (lhs as SimpleAssignLhs).AssignedVariable.Name)))
- {
- cs.Add(assign);
- }
- else
- {
- List<AssignLhs> newLhss = assign.Lhss.SelectMany(lhs => new AssignLhs[] {
- new VariableDualiser(1, verifier.uniformityAnalyser, procName).Visit(lhs.Clone() as AssignLhs) as AssignLhs,
- new VariableDualiser(2, verifier.uniformityAnalyser, procName).Visit(lhs.Clone() as AssignLhs) as AssignLhs
- }).ToList();
- List<Expr> newRhss = assign.Rhss.SelectMany(rhs => new Expr[] {
- new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(rhs.Clone() as Expr),
- new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(rhs.Clone() as Expr)
- }).ToList();
-
- AssignCmd newAssign = new AssignCmd(assign.tok, newLhss, newRhss);
-
- cs.Add(newAssign);
- }
- }
- else if (c is HavocCmd)
- {
- HavocCmd havoc = c as HavocCmd;
- Debug.Assert(havoc.Vars.Length == 1);
-
- HavocCmd newHavoc;
-
- newHavoc = new HavocCmd(havoc.tok, new IdentifierExprSeq(new IdentifierExpr[] {
+ }
+ else if (c is HavocCmd) {
+ HavocCmd havoc = c as HavocCmd;
+ Debug.Assert(havoc.Vars.Length == 1);
+
+ HavocCmd newHavoc;
+
+ newHavoc = new HavocCmd(havoc.tok, new IdentifierExprSeq(new IdentifierExpr[] {
(IdentifierExpr)(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr)),
(IdentifierExpr)(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr))
}));
- cs.Add(newHavoc);
- }
- else if (c is AssertCmd)
- {
- AssertCmd ass = c as AssertCmd;
- cs.Add(new AssertCmd(c.tok, new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr), ass.Attributes));
- if (!ContainsAsymmetricExpression(ass.Expr))
- {
- cs.Add(new AssertCmd(c.tok, new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr), ass.Attributes));
- }
- }
- else if (c is AssumeCmd)
- {
- AssumeCmd ass = c as AssumeCmd;
- if (QKeyValue.FindBoolAttribute(ass.Attributes, "backedge"))
- {
- cs.Add(new AssumeCmd(c.tok, Expr.Or(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr),
- new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr))));
- }
- else
- {
- cs.Add(new AssumeCmd(c.tok, new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr)));
- if (!ContainsAsymmetricExpression(ass.Expr))
- {
- cs.Add(new AssumeCmd(c.tok, new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr)));
- }
- }
- }
- else
- {
- Debug.Assert(false);
- }
+ cs.Add(newHavoc);
+ }
+ else if (c is AssertCmd) {
+ AssertCmd a = c as AssertCmd;
+
+ if (QKeyValue.FindBoolAttribute(a.Attributes, "sourceloc")) {
+ // This is just a location marker, so we do not dualise it
+ cs.Add(new AssertCmd(Token.NoToken, new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(a.Expr.Clone() as Expr),
+ (QKeyValue)a.Attributes.Clone()));
}
+ else {
+ cs.Add(MakeThreadSpecificAssert(a, 1));
+ if (!ContainsAsymmetricExpression(a.Expr)) {
+ cs.Add(MakeThreadSpecificAssert(a, 2));
+ }
+ }
+ }
+ else if (c is AssumeCmd) {
+ AssumeCmd ass = c as AssumeCmd;
+ if (QKeyValue.FindBoolAttribute(ass.Attributes, "backedge")) {
+ cs.Add(new AssumeCmd(c.tok, Expr.Or(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr),
+ new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr))));
+ }
+ else {
+ cs.Add(new AssumeCmd(c.tok, new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr)));
+ if (!ContainsAsymmetricExpression(ass.Expr)) {
+ cs.Add(new AssumeCmd(c.tok, new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr)));
+ }
+ }
+ }
+ else {
+ Debug.Assert(false);
+ }
+ }
- private BigBlock MakeDual(BigBlock bb)
- {
- // Not sure what to do about the transfer command
-
- BigBlock result = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
-
- foreach (Cmd c in bb.simpleCmds)
- {
- MakeDual(result.simpleCmds, c);
- }
-
- if (bb.ec is WhileCmd)
- {
- Expr NewGuard;
- if (verifier.uniformityAnalyser.IsUniform(procName, (bb.ec as WhileCmd).Guard))
- {
- NewGuard = (bb.ec as WhileCmd).Guard;
- }
- else
- {
- NewGuard = Expr.Or(Dualise((bb.ec as WhileCmd).Guard, 1),
- Dualise((bb.ec as WhileCmd).Guard, 2)
- );
- }
- result.ec = new WhileCmd(bb.ec.tok,
- NewGuard,
- MakeDualInvariants((bb.ec as WhileCmd).Invariants), MakeDual((bb.ec as WhileCmd).Body));
- }
- else if (bb.ec is IfCmd)
- {
- Debug.Assert(verifier.uniformityAnalyser.IsUniform(procName, (bb.ec as IfCmd).Guard));
- result.ec = new IfCmd(bb.ec.tok,
- (bb.ec as IfCmd).Guard,
- MakeDual((bb.ec as IfCmd).thn),
- null,
- (bb.ec as IfCmd).elseBlock == null ? null : MakeDual((bb.ec as IfCmd).elseBlock));
-
- }
- else if (bb.ec is BreakCmd)
- {
- result.ec = bb.ec;
- }
- else
- {
- Debug.Assert(bb.ec == null);
- }
-
- return result;
+ private BigBlock MakeDual(BigBlock bb) {
+ // Not sure what to do about the transfer command
- }
+ BigBlock result = new BigBlock(bb.tok, bb.LabelName, new CmdSeq(), null, bb.tc);
- private Block MakeDual(Block b)
- {
- var newCmds = new CmdSeq();
- foreach (Cmd c in b.Cmds)
- {
- MakeDual(newCmds, c);
- }
- b.Cmds = newCmds;
- return b;
- }
+ foreach (Cmd c in bb.simpleCmds) {
+ MakeDual(result.simpleCmds, c);
+ }
- private List<PredicateCmd> MakeDualInvariants(List<PredicateCmd> originalInvariants)
- {
- List<PredicateCmd> result = new List<PredicateCmd>();
- foreach (PredicateCmd p in originalInvariants)
- {
- {
- PredicateCmd newP = new AssertCmd(p.tok,
- Dualise(p.Expr, 1));
- newP.Attributes = p.Attributes;
- result.Add(newP);
- }
- if (!ContainsAsymmetricExpression(p.Expr)
- && !verifier.uniformityAnalyser.IsUniform(procName, p.Expr))
- {
- PredicateCmd newP = new AssertCmd(p.tok, Dualise(p.Expr, 2));
- newP.Attributes = p.Attributes;
- result.Add(newP);
- }
- }
-
- return result;
+ if (bb.ec is WhileCmd) {
+ Expr NewGuard;
+ if (verifier.uniformityAnalyser.IsUniform(procName, (bb.ec as WhileCmd).Guard)) {
+ NewGuard = (bb.ec as WhileCmd).Guard;
}
-
- private void MakeDualLocalVariables(Implementation impl)
- {
- VariableSeq NewLocalVars = new VariableSeq();
-
- foreach (LocalVariable v in impl.LocVars)
- {
- if (verifier.uniformityAnalyser.IsUniform(procName, v.Name))
- {
- NewLocalVars.Add (v);
- }
- else
- {
- NewLocalVars.Add(
- new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitVariable(v.Clone() as Variable));
- NewLocalVars.Add(
- new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitVariable(v.Clone() as Variable));
- }
- }
-
- impl.LocVars = NewLocalVars;
+ else {
+ NewGuard = Expr.Or(Dualise((bb.ec as WhileCmd).Guard, 1),
+ Dualise((bb.ec as WhileCmd).Guard, 2)
+ );
}
+ result.ec = new WhileCmd(bb.ec.tok,
+ NewGuard,
+ MakeDualInvariants((bb.ec as WhileCmd).Invariants), MakeDual((bb.ec as WhileCmd).Body));
+ }
+ else if (bb.ec is IfCmd) {
+ Debug.Assert(verifier.uniformityAnalyser.IsUniform(procName, (bb.ec as IfCmd).Guard));
+ result.ec = new IfCmd(bb.ec.tok,
+ (bb.ec as IfCmd).Guard,
+ MakeDual((bb.ec as IfCmd).thn),
+ null,
+ (bb.ec as IfCmd).elseBlock == null ? null : MakeDual((bb.ec as IfCmd).elseBlock));
+
+ }
+ else if (bb.ec is BreakCmd) {
+ result.ec = bb.ec;
+ }
+ else {
+ Debug.Assert(bb.ec == null);
+ }
+
+ return result;
+
+ }
- private bool ContainsAsymmetricExpression(Expr expr)
+ private Block MakeDual(Block b) {
+ var newCmds = new CmdSeq();
+ foreach (Cmd c in b.Cmds) {
+ MakeDual(newCmds, c);
+ }
+ b.Cmds = newCmds;
+ return b;
+ }
+
+ private List<PredicateCmd> MakeDualInvariants(List<PredicateCmd> originalInvariants) {
+ List<PredicateCmd> result = new List<PredicateCmd>();
+ foreach (PredicateCmd p in originalInvariants) {
{
- AsymmetricExpressionFinder finder = new AsymmetricExpressionFinder();
- finder.VisitExpr(expr);
- return finder.foundAsymmetricExpr();
+ PredicateCmd newP = new AssertCmd(p.tok,
+ Dualise(p.Expr, 1));
+ newP.Attributes = p.Attributes;
+ result.Add(newP);
}
+ if (!ContainsAsymmetricExpression(p.Expr)
+ && !verifier.uniformityAnalyser.IsUniform(procName, p.Expr)) {
+ PredicateCmd newP = new AssertCmd(p.tok, Dualise(p.Expr, 2));
+ newP.Attributes = p.Attributes;
+ result.Add(newP);
+ }
+ }
- private VariableSeq DualiseVariableSequence(VariableSeq seq)
- {
- VariableSeq uniform = new VariableSeq();
- VariableSeq nonuniform = new VariableSeq();
-
- foreach (Variable v in seq)
- {
- if (verifier.uniformityAnalyser.IsUniform(procName, v.Name))
- {
- uniform.Add(v);
- }
- else
- {
- nonuniform.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitVariable((Variable)v.Clone()));
- }
- }
-
- foreach (Variable v in seq)
- {
- if (!verifier.uniformityAnalyser.IsUniform(procName, v.Name))
- {
- nonuniform.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitVariable((Variable)v.Clone()));
- }
- }
-
- VariableSeq result = uniform;
- result.AddRange(nonuniform);
- return result;
+ return result;
+ }
+
+ private void MakeDualLocalVariables(Implementation impl) {
+ VariableSeq NewLocalVars = new VariableSeq();
+
+ foreach (LocalVariable v in impl.LocVars) {
+ if (verifier.uniformityAnalyser.IsUniform(procName, v.Name)) {
+ NewLocalVars.Add(v);
+ }
+ else {
+ NewLocalVars.Add(
+ new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitVariable(v.Clone() as Variable));
+ NewLocalVars.Add(
+ new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitVariable(v.Clone() as Variable));
}
+ }
+ impl.LocVars = NewLocalVars;
+ }
- internal void DualiseImplementation(Implementation impl, bool unstructured)
- {
- procName = impl.Name;
+ private bool ContainsAsymmetricExpression(Expr expr) {
+ AsymmetricExpressionFinder finder = new AsymmetricExpressionFinder();
+ finder.VisitExpr(expr);
+ return finder.foundAsymmetricExpr();
+ }
- impl.InParams = DualiseVariableSequence(impl.InParams);
- impl.OutParams = DualiseVariableSequence(impl.OutParams);
- MakeDualLocalVariables(impl);
- if (unstructured)
- impl.Blocks = new List<Block>(impl.Blocks.Select(MakeDual));
- else
- impl.StructuredStmts = MakeDual(impl.StructuredStmts);
+ private VariableSeq DualiseVariableSequence(VariableSeq seq) {
+ VariableSeq uniform = new VariableSeq();
+ VariableSeq nonuniform = new VariableSeq();
- procName = null;
+ foreach (Variable v in seq) {
+ if (verifier.uniformityAnalyser.IsUniform(procName, v.Name)) {
+ uniform.Add(v);
+ }
+ else {
+ nonuniform.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitVariable((Variable)v.Clone()));
}
+ }
- private Expr Dualise(Expr expr, int thread)
- {
- return new VariableDualiser(thread, verifier.uniformityAnalyser, procName).VisitExpr(expr.Clone() as Expr);
+ foreach (Variable v in seq) {
+ if (!verifier.uniformityAnalyser.IsUniform(procName, v.Name)) {
+ nonuniform.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitVariable((Variable)v.Clone()));
}
+ }
+
+ VariableSeq result = uniform;
+ result.AddRange(nonuniform);
+ return result;
+ }
+
+
+ internal void DualiseImplementation(Implementation impl, bool unstructured) {
+ procName = impl.Name;
+
+ impl.InParams = DualiseVariableSequence(impl.InParams);
+ impl.OutParams = DualiseVariableSequence(impl.OutParams);
+ MakeDualLocalVariables(impl);
+ if (unstructured)
+ impl.Blocks = new List<Block>(impl.Blocks.Select(MakeDual));
+ else
+ impl.StructuredStmts = MakeDual(impl.StructuredStmts);
+
+ procName = null;
+ }
+ private Expr Dualise(Expr expr, int thread) {
+ return new VariableDualiser(thread, verifier.uniformityAnalyser, procName).VisitExpr(expr.Clone() as Expr);
}
+ }
}
diff --git a/Source/GPUVerify/LoopInvariantGenerator.cs b/Source/GPUVerify/LoopInvariantGenerator.cs
index 300089eb..a465a98a 100644
--- a/Source/GPUVerify/LoopInvariantGenerator.cs
+++ b/Source/GPUVerify/LoopInvariantGenerator.cs
@@ -1,232 +1,258 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.Boogie;
-using Microsoft.Basetypes;
-using System.Diagnostics;
-
-using GPUVerify.InvariantGenerationRules;
-
-namespace GPUVerify
-{
- class LoopInvariantGenerator
- {
- private GPUVerifier verifier;
- private Implementation Impl;
-
- private List<InvariantGenerationRule> invariantGenerationRules;
-
- LoopInvariantGenerator(GPUVerifier verifier, Implementation Impl)
- {
- this.verifier = verifier;
- this.Impl = Impl;
-
- invariantGenerationRules = new List<InvariantGenerationRule>();
- invariantGenerationRules.Add(new PowerOfTwoInvariantGenerator(verifier));
- invariantGenerationRules.Add(new LoopVariableBoundsInvariantGenerator(verifier));
- }
-
- public static void PreInstrument(GPUVerifier verifier, Implementation impl)
- {
- foreach (var region in verifier.RootRegion(impl).SubRegions())
- {
- GenerateCandidateForReducedStrengthStrideVariables(verifier, impl, region);
- }
- }
-
- private static void GenerateCandidateForReducedStrengthStrideVariables(GPUVerifier verifier, Implementation impl, IRegion region)
- {
- var rsa = verifier.reducedStrengthAnalyses[impl];
- foreach (string lc in rsa.StridedLoopCounters(region.Identifier()))
- {
- var sc = rsa.GetStrideConstraint(lc);
- Variable lcVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, lc,
- Microsoft.Boogie.Type.GetBvType(32)));
- var lcExpr = new IdentifierExpr(Token.NoToken, lcVariable);
- var lcPred = sc.MaybeBuildPredicate(verifier, lcExpr);
-
- if (lcPred != null)
- {
- verifier.AddCandidateInvariant(region, lcPred, "variable " + lc + " is strided");
- }
- }
- }
-
- public static void PostInstrument(GPUVerifier verifier, Implementation Impl, List<Expr> UserSuppliedInvariants)
- {
- new LoopInvariantGenerator(verifier, Impl).PostInstrument(UserSuppliedInvariants);
- }
-
- internal void PostInstrument(List<Expr> UserSuppliedInvariants)
- {
- HashSet<Variable> LocalVars = new HashSet<Variable>();
- foreach (Variable v in Impl.LocVars)
- {
- LocalVars.Add(v);
- }
- foreach (Variable v in Impl.InParams)
- {
- LocalVars.Add(v);
- }
- foreach (Variable v in Impl.OutParams)
- {
- LocalVars.Add(v);
- }
-
- AddCandidateInvariants(verifier.RootRegion(Impl), LocalVars, UserSuppliedInvariants, Impl);
-
- }
-
- private void AddEqualityCandidateInvariant(IRegion region, string LoopPredicate, Variable v)
- {
- verifier.AddCandidateInvariant(region,
- Expr.Eq(
- new IdentifierExpr(Token.NoToken, new VariableDualiser(1, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable)),
- new IdentifierExpr(Token.NoToken, new VariableDualiser(2, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable))
- ), "equality");
- }
-
- private void AddPredicatedEqualityCandidateInvariant(IRegion region, string LoopPredicate, Variable v)
- {
- verifier.AddCandidateInvariant(region, Expr.Imp(
- Expr.And(
- new IdentifierExpr(Token.NoToken, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, LoopPredicate + "$1", Microsoft.Boogie.Type.Int))),
- new IdentifierExpr(Token.NoToken, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, LoopPredicate + "$2", Microsoft.Boogie.Type.Int)))
- ),
- Expr.Eq(
- new IdentifierExpr(Token.NoToken, new VariableDualiser(1, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable)),
- new IdentifierExpr(Token.NoToken, new VariableDualiser(2, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable))
- )), "predicated equality");
- }
-
-
- private void AddBarrierDivergenceCandidates(HashSet<Variable> LocalVars, Implementation Impl, IRegion region)
- {
-
- if (CommandLineOptions.AddDivergenceCandidatesOnlyToBarrierLoops)
- {
- if (!verifier.ContainsBarrierCall(region))
- {
- return;
- }
- }
-
- Expr guard = region.Guard();
- if (verifier.uniformityAnalyser.IsUniform(Impl.Name, guard))
- {
- return;
- }
-
- if (guard is NAryExpr &&
- (guard as NAryExpr).Args.Length == 2 &&
- (guard as NAryExpr).Args[0] is IdentifierExpr)
- {
- string LoopPredicate = ((guard as NAryExpr).Args[0] as IdentifierExpr).Name;
-
- LoopPredicate = LoopPredicate.Substring(0, LoopPredicate.IndexOf('$'));
-
- verifier.AddCandidateInvariant(region, Expr.Eq(
- // Int type used here, but it doesn't matter as we will print and then re-parse the program
- new IdentifierExpr(Token.NoToken, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, LoopPredicate + "$1", Microsoft.Boogie.Type.Int))),
- new IdentifierExpr(Token.NoToken, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, LoopPredicate + "$2", Microsoft.Boogie.Type.Int)))
- ), "loop predicate equality");
-
- foreach (Variable v in LocalVars)
- {
-
- if (verifier.uniformityAnalyser.IsUniform(Impl.Name, v.Name))
- {
- continue;
- }
-
- string lv = GPUVerifier.StripThreadIdentifier(v.Name);
-
- if (GPUVerifier.IsPredicateOrTemp(lv))
- {
- continue;
- }
-
- if (CommandLineOptions.AddDivergenceCandidatesOnlyIfModified)
- {
- if (!verifier.ContainsNamedVariable(GetModifiedVariables(region),
- GPUVerifier.StripThreadIdentifier(v.Name)))
- {
- continue;
- }
- }
-
- AddEqualityCandidateInvariant(region, LoopPredicate, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, lv, Microsoft.Boogie.Type.Int)));
-
- if (Impl != verifier.KernelImplementation)
- {
- AddPredicatedEqualityCandidateInvariant(region, LoopPredicate, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, lv, Microsoft.Boogie.Type.Int)));
- }
- }
-
- if (CommandLineOptions.ArrayEqualities)
- {
- foreach (Variable v in verifier.KernelArrayInfo.getAllNonLocalArrays())
- {
- if (!verifier.ArrayModelledAdversarially(v))
- {
- AddEqualityCandidateInvariant(region, LoopPredicate, v);
- }
- }
- }
- }
- }
-
- private void AddCandidateInvariants(IRegion region, HashSet<Variable> LocalVars, List<Expr> UserSuppliedInvariants, Implementation Impl)
- {
- foreach (IRegion subregion in region.SubRegions())
- {
- foreach (InvariantGenerationRule r in invariantGenerationRules)
- {
- r.GenerateCandidates(Impl, subregion);
- }
-
- AddBarrierDivergenceCandidates(LocalVars, Impl, subregion);
-
- verifier.RaceInstrumenter.AddRaceCheckingCandidateInvariants(Impl, subregion);
-
- AddUserSuppliedInvariants(subregion, UserSuppliedInvariants, Impl);
- }
- }
-
- private void AddUserSuppliedInvariants(IRegion region, List<Expr> UserSuppliedInvariants, Implementation Impl)
- {
- foreach (Expr e in UserSuppliedInvariants)
- {
- /*
- wc.Invariants.Add(new AssertCmd(wc.tok, e));
- bool OK = verifier.ProgramIsOK(Impl);
- wc.Invariants.RemoveAt(wc.Invariants.Count - 1);
- if (OK)
- {
- verifier.AddCandidateInvariant(wc, e, "user supplied");
- }
- */
- verifier.AddCandidateInvariant(region, e, "user supplied");
- }
- }
-
- internal static HashSet<Variable> GetModifiedVariables(IRegion region)
- {
- HashSet<Variable> result = new HashSet<Variable>();
-
- foreach (Cmd c in region.Cmds())
- {
- VariableSeq vars = new VariableSeq();
- c.AddAssignedVariables(vars);
- foreach (Variable v in vars)
- {
- result.Add(v);
- }
- }
-
- return result;
- }
-
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using Microsoft.Basetypes;
+using System.Diagnostics;
+
+using GPUVerify.InvariantGenerationRules;
+
+namespace GPUVerify {
+ class LoopInvariantGenerator {
+ private GPUVerifier verifier;
+ private Implementation Impl;
+
+ private List<InvariantGenerationRule> invariantGenerationRules;
+
+ LoopInvariantGenerator(GPUVerifier verifier, Implementation Impl) {
+ this.verifier = verifier;
+ this.Impl = Impl;
+
+ invariantGenerationRules = new List<InvariantGenerationRule>();
+ invariantGenerationRules.Add(new PowerOfTwoInvariantGenerator(verifier));
+ invariantGenerationRules.Add(new LoopVariableBoundsInvariantGenerator(verifier));
+ }
+
+ public static void PreInstrument(GPUVerifier verifier, Implementation impl) {
+ foreach (var region in verifier.RootRegion(impl).SubRegions()) {
+ GenerateCandidateForReducedStrengthStrideVariables(verifier, impl, region);
+ }
+ }
+
+ private static void GenerateCandidateForReducedStrengthStrideVariables(GPUVerifier verifier, Implementation impl, IRegion region) {
+ var rsa = verifier.reducedStrengthAnalyses[impl];
+ foreach (string lc in rsa.StridedLoopCounters(region.Identifier())) {
+ var sc = rsa.GetStrideConstraint(lc);
+ Variable lcVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, lc,
+ Microsoft.Boogie.Type.GetBvType(32)));
+ var lcExpr = new IdentifierExpr(Token.NoToken, lcVariable);
+ var lcPred = sc.MaybeBuildPredicate(verifier, lcExpr);
+
+ if (lcPred != null) {
+ verifier.AddCandidateInvariant(region, lcPred, "variable " + lc + " is strided");
+ }
+ }
+ }
+
+ public static void PostInstrument(GPUVerifier verifier, Implementation Impl, List<Expr> UserSuppliedInvariants) {
+ new LoopInvariantGenerator(verifier, Impl).PostInstrument(UserSuppliedInvariants);
+ }
+
+ internal void PostInstrument(List<Expr> UserSuppliedInvariants) {
+ HashSet<Variable> LocalVars = new HashSet<Variable>();
+ foreach (Variable v in Impl.LocVars) {
+ LocalVars.Add(v);
+ }
+ foreach (Variable v in Impl.InParams) {
+ LocalVars.Add(v);
+ }
+ foreach (Variable v in Impl.OutParams) {
+ LocalVars.Add(v);
+ }
+
+ AddCandidateInvariants(verifier.RootRegion(Impl), LocalVars, UserSuppliedInvariants, Impl);
+
+ }
+
+ private void AddEqualityCandidateInvariant(IRegion region, string LoopPredicate, Variable v) {
+ verifier.AddCandidateInvariant(region,
+ Expr.Eq(
+ new IdentifierExpr(Token.NoToken, new VariableDualiser(1, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable)),
+ new IdentifierExpr(Token.NoToken, new VariableDualiser(2, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable))
+ ), "equality");
+ }
+
+ private void AddPredicatedEqualityCandidateInvariant(IRegion region, string LoopPredicate, Variable v) {
+ verifier.AddCandidateInvariant(region, Expr.Imp(
+ Expr.And(
+ new IdentifierExpr(Token.NoToken, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, LoopPredicate + "$1", Microsoft.Boogie.Type.Int))),
+ new IdentifierExpr(Token.NoToken, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, LoopPredicate + "$2", Microsoft.Boogie.Type.Int)))
+ ),
+ Expr.Eq(
+ new IdentifierExpr(Token.NoToken, new VariableDualiser(1, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable)),
+ new IdentifierExpr(Token.NoToken, new VariableDualiser(2, verifier.uniformityAnalyser, Impl.Name).VisitVariable(v.Clone() as Variable))
+ )), "predicated equality");
+ }
+
+ private Dictionary<string, int> GetAssignmentCounts(Implementation impl) {
+
+ Dictionary<string, int> result = new Dictionary<string, int>();
+
+ foreach (var c in verifier.RootRegion(impl).Cmds()) {
+ if (c is AssignCmd) {
+ var aCmd = (AssignCmd)c;
+ HashSet<string> alreadySeenInThisAssignment = new HashSet<string>();
+ foreach (var a in aCmd.Lhss) {
+ if (a is SimpleAssignLhs) {
+ var v = GPUVerifier.StripThreadIdentifier(
+ ((SimpleAssignLhs)a).AssignedVariable.Name);
+ if (!alreadySeenInThisAssignment.Contains(v)) {
+ if (result.ContainsKey(v)) {
+ result[v]++;
+ }
+ else {
+ result[v] = 1;
+ }
+ alreadySeenInThisAssignment.Add(v);
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+
+ private void AddBarrierDivergenceCandidates(HashSet<Variable> LocalVars, Implementation Impl, IRegion region)
+ {
+
+ if (!verifier.ContainsBarrierCall(region))
+ {
+ return;
+ }
+
+ Expr guard = region.Guard();
+ if (guard != null && verifier.uniformityAnalyser.IsUniform(Impl.Name, guard))
+ {
+ return;
+ }
+
+ if (IsDisjunctionOfPredicates(guard))
+ {
+ string LoopPredicate = ((guard as NAryExpr).Args[0] as IdentifierExpr).Name;
+ LoopPredicate = LoopPredicate.Substring(0, LoopPredicate.IndexOf('$'));
+
+ verifier.AddCandidateInvariant(region, Expr.Eq(
+ // Int type used here, but it doesn't matter as we will print and then re-parse the program
+ new IdentifierExpr(Token.NoToken, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, LoopPredicate + "$1", Microsoft.Boogie.Type.Int))),
+ new IdentifierExpr(Token.NoToken, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, LoopPredicate + "$2", Microsoft.Boogie.Type.Int)))
+ ), "loop predicate equality");
+
+ Dictionary<string, int> assignmentCounts = GetAssignmentCounts(Impl);
+
+ HashSet<string> alreadyConsidered = new HashSet<String>();
+
+ foreach (var v in LocalVars)
+ {
+ string lv = GPUVerifier.StripThreadIdentifier(v.Name);
+ if (alreadyConsidered.Contains(lv)) {
+ continue;
+ }
+ alreadyConsidered.Add(lv);
+
+ if (verifier.uniformityAnalyser.IsUniform(Impl.Name, v.Name))
+ {
+ continue;
+ }
+
+ if (GPUVerifier.IsPredicate(lv))
+ {
+ continue;
+ }
+
+ if (!assignmentCounts.ContainsKey(lv) || assignmentCounts[lv] <= 1) {
+ continue;
+ }
+
+ if (!verifier.ContainsNamedVariable(
+ GetModifiedVariables(region), lv))
+ {
+ continue;
+ }
+
+ AddPredicatedEqualityCandidateInvariant(region, LoopPredicate, new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, lv, Microsoft.Boogie.Type.Int)));
+ }
+
+ if (CommandLineOptions.ArrayEqualities)
+ {
+ foreach (Variable v in verifier.KernelArrayInfo.getAllNonLocalArrays())
+ {
+ if (!verifier.ArrayModelledAdversarially(v))
+ {
+ AddEqualityCandidateInvariant(region, LoopPredicate, v);
+ }
+ }
+ }
+ }
+ }
+
+ private static bool IsDisjunctionOfPredicates(Expr guard) {
+ if (!(guard is NAryExpr)) {
+ return false;
+ }
+ NAryExpr nary = (NAryExpr)guard;
+ if(nary.Args.Length != 2) {
+ return false;
+ }
+ if(!(nary.Fun is BinaryOperator)) {
+ return false;
+ }
+ BinaryOperator binOp = (BinaryOperator)nary.Fun;
+ if(binOp.Op != BinaryOperator.Opcode.Or) {
+ return false;
+ }
+ if(!(nary.Args[0] is IdentifierExpr && nary.Args[1] is IdentifierExpr)) {
+ return false;
+ }
+ return GPUVerifier.IsPredicate(GPUVerifier.StripThreadIdentifier(
+ ((IdentifierExpr)nary.Args[0]).Name)) &&
+ GPUVerifier.IsPredicate(GPUVerifier.StripThreadIdentifier(
+ ((IdentifierExpr)nary.Args[1]).Name));
+ }
+
+ private void AddCandidateInvariants(IRegion region, HashSet<Variable> LocalVars, List<Expr> UserSuppliedInvariants, Implementation Impl) {
+ foreach (IRegion subregion in region.SubRegions()) {
+ foreach (InvariantGenerationRule r in invariantGenerationRules) {
+ r.GenerateCandidates(Impl, subregion);
+ }
+
+ AddBarrierDivergenceCandidates(LocalVars, Impl, subregion);
+
+ verifier.RaceInstrumenter.AddRaceCheckingCandidateInvariants(Impl, subregion);
+
+ AddUserSuppliedInvariants(subregion, UserSuppliedInvariants, Impl);
+ }
+ }
+
+ private void AddUserSuppliedInvariants(IRegion region, List<Expr> UserSuppliedInvariants, Implementation Impl) {
+ foreach (Expr e in UserSuppliedInvariants) {
+ /*
+ wc.Invariants.Add(new AssertCmd(wc.tok, e));
+ bool OK = verifier.ProgramIsOK(Impl);
+ wc.Invariants.RemoveAt(wc.Invariants.Count - 1);
+ if (OK)
+ {
+ verifier.AddCandidateInvariant(wc, e, "user supplied");
+ }
+ */
+ verifier.AddCandidateInvariant(region, e, "user supplied");
+ }
+ }
+
+ internal static HashSet<Variable> GetModifiedVariables(IRegion region) {
+ HashSet<Variable> result = new HashSet<Variable>();
+
+ foreach (Cmd c in region.Cmds()) {
+ VariableSeq vars = new VariableSeq();
+ c.AddAssignedVariables(vars);
+ foreach (Variable v in vars) {
+ result.Add(v);
+ }
+ }
+
+ return result;
+ }
+
+ }
+}
diff --git a/Source/GPUVerify/Main.cs b/Source/GPUVerify/Main.cs
index e5a094d5..b11dfc6f 100644
--- a/Source/GPUVerify/Main.cs
+++ b/Source/GPUVerify/Main.cs
@@ -88,7 +88,7 @@ namespace GPUVerify
return null;
}
- public static bool doit(string filename, Variable v, int a1, int a2)
+/* public static bool doit(string filename, Variable v, int a1, int a2)
{
ResolutionContext rc;
Program newProgram = parse(out rc);
@@ -121,8 +121,9 @@ namespace GPUVerify
return !ri.failedToFindSecondAccess;
}
+ */
- public static IList<GPUVerifier> parseProcessOutput()
+ public static void parseProcessOutput()
{
string fn = "temp";
if (CommandLineOptions.outputFile != null)
@@ -137,72 +138,16 @@ namespace GPUVerify
}
ResolutionContext rc;
Program program = parse(out rc);
- IList<GPUVerifier> result = new List<GPUVerifier>();
GPUVerifier g = new GPUVerifier(fn, program, rc, new NullRaceInstrumenter());
- if (CommandLineOptions.DividedArray)
+ if (!CommandLineOptions.OnlyDivergence)
{
- bool FoundArray = CommandLineOptions.ArrayToCheck == null;
-
- foreach (Variable v in g.KernelArrayInfo.getAllNonLocalArrays())
- {
- if (CommandLineOptions.DividedAccesses)
- {
- int i = 0;
- int j = 0;
- while (true)
- {
- bool res = doit(fn + "." + v.Name + "." + i + "." + (i + j), v, i, j);
- if (!res)
- {
- if (j == 0)
- {
- break;
- }
- else
- {
- i++;
- j = 0;
- }
- }
- else
- {
- j++;
- }
- }
- }
- else
- {
- if (CommandLineOptions.ArrayToCheck == null || CommandLineOptions.ArrayToCheck.Equals(v.Name))
- {
- FoundArray = true;
- doit("temp_" + v.Name, v, -1, -1);
- }
- }
- }
-
- if (!FoundArray)
- {
- Console.WriteLine("Did not find a non-local array named " + CommandLineOptions.ArrayToCheck);
- Environment.Exit(1);
- }
-
- }
- else
- {
- if (!CommandLineOptions.OnlyDivergence)
- {
- RaceInstrumenter ri = new RaceInstrumenter();
- ri.setVerifier(g);
- g.setRaceInstrumenter(ri);
- }
-
- g.doit();
- result.Add(g);
-
+ RaceInstrumenter ri = new RaceInstrumenter();
+ ri.setVerifier(g);
+ g.setRaceInstrumenter(ri);
}
- return result;
+ g.doit();
}
diff --git a/Source/GPUVerify/NoConflictingAccessOptimiser.cs b/Source/GPUVerify/NoConflictingAccessOptimiser.cs
deleted file mode 100644
index f003a3a9..00000000
--- a/Source/GPUVerify/NoConflictingAccessOptimiser.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.Boogie;
-using System.Diagnostics.Contracts;
-
-namespace GPUVerify
-{
- class NoConflictingAccessOptimiser
- {
- private Implementation impl;
- private IList<CallCmdPos> ccs;
-
- public NoConflictingAccessOptimiser(Implementation impl)
- {
- this.impl = impl;
- ccs = new List<CallCmdPos>();
- FindCallCmds();
- }
-
- private class CallCmdPos
- {
- public Block block;
- public int cmdIndex;
- public CallCmd cc;
-
- public CallCmdPos(Block block, int cmdIndex, CallCmd cc)
- {
- this.block = block;
- this.cmdIndex = cmdIndex;
- this.cc = cc;
- }
- }
-
- public int NumLogCalls()
- {
- return ccs.Count;
- }
-
- private void FindCallCmds()
- {
- foreach (Block b in impl.Blocks)
- {
- for(int i=0; i < b.Cmds.Length; i++)
- {
- Cmd c = b.Cmds[i];
- CallCmd cc = c as CallCmd;
- if (cc != null)
- {
- if (cc.Proc.Name.Contains("_LOG"))
- {
- ccs.Add(new CallCmdPos(b, i, cc));
- }
- }
- }
- }
- }
-
- public bool HasConflicting()
- {
- Contract.Assert(ccs.Count == 2);
-
- return
- Reachable(ccs[0].block, ccs[0].cmdIndex, ccs[1].cc, new HashSet<Block>()) ||
- Reachable(ccs[1].block, ccs[1].cmdIndex, ccs[0].cc, new HashSet<Block>());
- }
-
- public bool Reachable(Block startBlock, int cmdStartIndex, CallCmd target, ISet<Block> visited)
- {
- Block currBlock = startBlock;
- int i = cmdStartIndex;
-
- if(i == 0)
- {
- visited.Add(currBlock);
- }
-
- while (i < currBlock.Cmds.Length)
- {
- CallCmd cc = currBlock.Cmds[i] as CallCmd;
- if (cc != null)
- {
- if (cc.Proc.Name.Equals("BARRIER"))
- {
- return false;
- }
-
- if (target == cc)
- {
- return true;
- }
- }
- i++;
- }
-
-
- //end of block
-
- GotoCmd gc = currBlock.TransferCmd as GotoCmd;
- Contract.Assert(gc != null);
- foreach (Block t in gc.labelTargets)
- {
- if(visited.Contains(t))
- continue;
-
- if (Reachable(t, 0, target, visited))
- return true;
- }
-
- return false;
-
- }
-
- }
-}
diff --git a/Source/GPUVerify/NullRaceInstrumenter.cs b/Source/GPUVerify/NullRaceInstrumenter.cs
index acba7ca6..fae08aa3 100644
--- a/Source/GPUVerify/NullRaceInstrumenter.cs
+++ b/Source/GPUVerify/NullRaceInstrumenter.cs
@@ -1,48 +1,67 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.Boogie;
-
-namespace GPUVerify
-{
- class NullRaceInstrumenter : IRaceInstrumenter
- {
-
- public void AddRaceCheckingCandidateInvariants(Implementation impl, IRegion region)
- {
-
- }
-
- public void AddKernelPrecondition()
- {
-
- }
-
- public bool AddRaceCheckingInstrumentation()
- {
- return true;
- }
-
- public Microsoft.Boogie.BigBlock MakeResetReadWriteSetStatements(Variable v, int Thread)
- {
- return new BigBlock(Token.NoToken, null, new CmdSeq(), null, null);
- }
-
- public void AddRaceCheckingCandidateRequires(Procedure Proc)
- {
-
- }
-
- public void AddRaceCheckingCandidateEnsures(Procedure Proc)
- {
-
- }
-
- public void AddRaceCheckingDeclarations()
- {
-
- }
-
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+
+namespace GPUVerify
+{
+ class NullRaceInstrumenter : IRaceInstrumenter
+ {
+
+ public void AddRaceCheckingCandidateInvariants(Implementation impl, IRegion region)
+ {
+
+ }
+
+ public void AddKernelPrecondition()
+ {
+
+ }
+
+ public void AddRaceCheckingInstrumentation()
+ {
+
+ }
+
+ public Microsoft.Boogie.BigBlock MakeResetReadWriteSetStatements(Variable v, int Thread)
+ {
+ return new BigBlock(Token.NoToken, null, new CmdSeq(), null, null);
+ }
+
+ public void AddRaceCheckingCandidateRequires(Procedure Proc)
+ {
+
+ }
+
+ public void AddRaceCheckingCandidateEnsures(Procedure Proc)
+ {
+
+ }
+
+ public void AddRaceCheckingDeclarations()
+ {
+
+ }
+
+ public void AddSourceLocationLoopInvariants(Implementation impl, IRegion region)
+ {
+
+ }
+
+ public void DoHoudiniPointerAnalysis(Procedure Proc)
+ {
+
+ }
+
+ public void AddStandardSourceVariablePreconditions()
+ {
+
+ }
+
+ public void AddStandardSourceVariablePostconditions()
+ {
+
+ }
+ }
+}
diff --git a/Source/GPUVerify/RaceInstrumenter.cs b/Source/GPUVerify/RaceInstrumenter.cs
index 1bf64023..c73b9b13 100644
--- a/Source/GPUVerify/RaceInstrumenter.cs
+++ b/Source/GPUVerify/RaceInstrumenter.cs
@@ -1,1109 +1,1131 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie;
-using Microsoft.Basetypes;
-
-namespace GPUVerify
-{
- class RaceInstrumenter : IRaceInstrumenter
- {
- protected GPUVerifier verifier;
-
- public IKernelArrayInfo NonLocalStateToCheck;
-
- public int onlyLog1;
- public int onlyLog2;
- public bool failedToFindSecondAccess;
- public bool addedLogWrite;
- private int logAddCount;
-
- private Dictionary<string, Procedure> logAccessProcedures = new Dictionary<string, Procedure>();
-
- public RaceInstrumenter()
- {
- onlyLog1 = -1;
- onlyLog2 = -1;
- failedToFindSecondAccess = false;
- addedLogWrite = false;
- logAddCount = 0;
- }
-
- public void setVerifier(GPUVerifier verifier)
- {
- this.verifier = verifier;
- NonLocalStateToCheck = new KernelArrayInfoLists();
- foreach(Variable v in verifier.KernelArrayInfo.getGlobalArrays())
- {
- NonLocalStateToCheck.getGlobalArrays().Add(v);
- }
- foreach(Variable v in verifier.KernelArrayInfo.getGroupSharedArrays())
- {
- NonLocalStateToCheck.getGroupSharedArrays().Add(v);
- }
- }
-
- private void AddNoReadOrWriteCandidateInvariants(IRegion region, Variable v)
- {
- // Reasoning: if READ_HAS_OCCURRED_v is not in the modifies set for the
- // loop then there is no point adding an invariant
- //
- // If READ_HAS_OCCURRED_v is in the modifies set, but the loop does not
- // contain a barrier, then it is almost certain that a read CAN be
- // pending at the loop head, so the invariant will not hold
- //
- // If there is a barrier in the loop body then READ_HAS_OCCURRED_v will
- // be in the modifies set, but there may not be a live read at the loop
- // head, so it is worth adding the loop invariant candidate.
- //
- // The same reasoning applies for WRITE
-
- if (verifier.ContainsBarrierCall(region))
- {
- if (verifier.ContainsNamedVariable(
- LoopInvariantGenerator.GetModifiedVariables(region), GPUVerifier.MakeAccessHasOccurredVariableName(v.Name, "READ")))
- {
- AddNoReadOrWriteCandidateInvariant(region, v, "READ");
- }
-
- if (verifier.ContainsNamedVariable(
- LoopInvariantGenerator.GetModifiedVariables(region), GPUVerifier.MakeAccessHasOccurredVariableName(v.Name, "WRITE")))
- {
- AddNoReadOrWriteCandidateInvariant(region, v, "WRITE");
- }
- }
- }
-
- private void AddNoReadOrWriteCandidateRequires(Procedure Proc, Variable v)
- {
- AddNoReadOrWriteCandidateRequires(Proc, v, "READ", "1");
- AddNoReadOrWriteCandidateRequires(Proc, v, "WRITE", "1");
- }
-
- private void AddNoReadOrWriteCandidateEnsures(Procedure Proc, Variable v)
- {
- AddNoReadOrWriteCandidateEnsures(Proc, v, "READ", "1");
- AddNoReadOrWriteCandidateEnsures(Proc, v, "WRITE", "1");
- }
-
- private void AddNoReadOrWriteCandidateInvariant(IRegion region, Variable v, string ReadOrWrite)
- {
- Expr candidate = NoReadOrWriteExpr(v, ReadOrWrite, "1");
- verifier.AddCandidateInvariant(region, candidate, "no " + ReadOrWrite.ToLower());
- }
-
- public void AddRaceCheckingCandidateInvariants(Implementation impl, IRegion region)
- {
- foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays())
- {
- AddNoReadOrWriteCandidateInvariants(region, v);
- AddReadOrWrittenOffsetIsThreadIdCandidateInvariants(impl, region, v, "READ");
- AddReadOrWrittenOffsetIsThreadIdCandidateInvariants(impl, region, v, "WRITE");
- AddOffsetsSatisfyPredicatesCandidateInvariant(region, v, "READ", CollectOffsetPredicates(impl, region, v, "READ"));
- AddOffsetsSatisfyPredicatesCandidateInvariant(region, v, "WRITE", CollectOffsetPredicates(impl, region, v, "WRITE"));
- }
- }
-
- private void AddAccessRelatedCandidateInvariant(IRegion region, string accessKind, Expr candidateInvariantExpr, string procName, string tag)
- {
- Expr candidate = new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(candidateInvariantExpr.Clone() as Expr);
- verifier.AddCandidateInvariant(region, candidate, tag);
- }
-
- private bool DoesNotReferTo(Expr expr, string v)
- {
- FindReferencesToNamedVariableVisitor visitor = new FindReferencesToNamedVariableVisitor(v);
- visitor.VisitExpr(expr);
- return !visitor.found;
- }
-
- private List<Expr> CollectOffsetPredicates(Implementation impl, IRegion region, Variable v, string accessType)
- {
- var offsetVar = new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeOffsetVariable(v, accessType));
- var offsetExpr = new IdentifierExpr(Token.NoToken, offsetVar);
- var offsetPreds = new List<Expr>();
-
- foreach (var offset in GetOffsetsAccessed(region, v, accessType))
- {
- bool isConstant;
- var def = verifier.varDefAnalyses[impl].SubstDefinitions(offset, impl.Name, out isConstant);
- if (def == null)
- continue;
-
- if (isConstant)
- {
- offsetPreds.Add(Expr.Eq(offsetExpr, def));
- }
- else
- {
- var sc = StrideConstraint.FromExpr(verifier, impl, def);
- var pred = sc.MaybeBuildPredicate(verifier, offsetExpr);
- if (pred != null)
- offsetPreds.Add(pred);
- }
- }
-
- return offsetPreds;
- }
-
- private void AddReadOrWrittenOffsetIsThreadIdCandidateInvariants(Implementation impl, IRegion region, Variable v, string accessType)
- {
- KeyValuePair<IdentifierExpr, Expr> iLessThanC = GetILessThanC(region.Guard());
- if (iLessThanC.Key != null)
- {
- foreach (Expr e in GetOffsetsAccessed(region, v, accessType))
- {
- if(HasFormIPlusLocalIdTimesC(e, iLessThanC, impl))
- {
- AddAccessedOffsetInRangeCTimesLocalIdToCTimesLocalIdPlusC(region, v, iLessThanC.Value, accessType);
- break;
- }
- }
-
- foreach (Expr e in GetOffsetsAccessed(region, v, accessType))
- {
- if (HasFormIPlusGlobalIdTimesC(e, iLessThanC, impl))
- {
- AddAccessedOffsetInRangeCTimesGlobalIdToCTimesGlobalIdPlusC(region, v, iLessThanC.Value, accessType);
- break;
- }
- }
-
- }
-
-
- }
-
- private bool HasFormIPlusLocalIdTimesC(Expr e, KeyValuePair<IdentifierExpr, Expr> iLessThanC, Implementation impl)
- {
- if (!(e is NAryExpr))
- {
- return false;
- }
-
- NAryExpr nary = e as NAryExpr;
-
- if (!nary.Fun.FunctionName.Equals("BV32_ADD"))
- {
- return false;
- }
-
- return (SameIdentifierExpression(nary.Args[0], iLessThanC.Key) &&
- IsLocalIdTimesConstant(nary.Args[1], iLessThanC.Value, impl)) ||
- (SameIdentifierExpression(nary.Args[1], iLessThanC.Key) &&
- IsLocalIdTimesConstant(nary.Args[0], iLessThanC.Value, impl));
- }
-
- private bool IsLocalIdTimesConstant(Expr maybeLocalIdTimesConstant, Expr constant, Implementation impl)
- {
- if (!(maybeLocalIdTimesConstant is NAryExpr))
- {
- return false;
- }
- NAryExpr nary = maybeLocalIdTimesConstant as NAryExpr;
- if(!nary.Fun.FunctionName.Equals("BV32_MUL"))
- {
- return false;
- }
-
- return
- (SameConstant(nary.Args[0], constant) && verifier.IsLocalId(nary.Args[1], 0, impl)) ||
- (SameConstant(nary.Args[1], constant) && verifier.IsLocalId(nary.Args[0], 0, impl));
- }
-
-
- private bool HasFormIPlusGlobalIdTimesC(Expr e, KeyValuePair<IdentifierExpr, Expr> iLessThanC, Implementation impl)
- {
- if (!(e is NAryExpr))
- {
- return false;
- }
-
- NAryExpr nary = e as NAryExpr;
-
- if (!nary.Fun.FunctionName.Equals("BV32_ADD"))
- {
- return false;
- }
-
- return (SameIdentifierExpression(nary.Args[0], iLessThanC.Key) &&
- IsGlobalIdTimesConstant(nary.Args[1], iLessThanC.Value, impl)) ||
- (SameIdentifierExpression(nary.Args[1], iLessThanC.Key) &&
- IsGlobalIdTimesConstant(nary.Args[0], iLessThanC.Value, impl));
- }
-
- private bool IsGlobalIdTimesConstant(Expr maybeGlobalIdTimesConstant, Expr constant, Implementation impl)
- {
- if (!(maybeGlobalIdTimesConstant is NAryExpr))
- {
- return false;
- }
- NAryExpr nary = maybeGlobalIdTimesConstant as NAryExpr;
- if (!nary.Fun.FunctionName.Equals("BV32_MUL"))
- {
- return false;
- }
-
- return
- (SameConstant(nary.Args[0], constant) && verifier.IsGlobalId(nary.Args[1], 0, impl)) ||
- (SameConstant(nary.Args[1], constant) && verifier.IsGlobalId(nary.Args[0], 0, impl));
- }
-
-
- private bool SameConstant(Expr expr, Expr constant)
- {
- if (constant is IdentifierExpr)
- {
- IdentifierExpr identifierExpr = constant as IdentifierExpr;
- Debug.Assert(identifierExpr.Decl is Constant);
- return expr is IdentifierExpr && (expr as IdentifierExpr).Decl is Constant && (expr as IdentifierExpr).Decl.Name.Equals(identifierExpr.Decl.Name);
- }
- else
- {
- Debug.Assert(constant is LiteralExpr);
- LiteralExpr literalExpr = constant as LiteralExpr;
- if (!(expr is LiteralExpr))
- {
- return false;
- }
- if (!(literalExpr.Val is BvConst) || !((expr as LiteralExpr).Val is BvConst))
- {
- return false;
- }
-
- return (literalExpr.Val as BvConst).Value.ToInt == ((expr as LiteralExpr).Val as BvConst).Value.ToInt;
- }
- }
-
- private bool SameIdentifierExpression(Expr expr, IdentifierExpr identifierExpr)
- {
- if (!(expr is IdentifierExpr))
- {
- return false;
- }
- return (expr as IdentifierExpr).Decl.Name.Equals(identifierExpr.Name);
- }
-
- private KeyValuePair<IdentifierExpr, Expr> GetILessThanC(Expr expr)
- {
-
- if (expr is NAryExpr && (expr as NAryExpr).Fun.FunctionName.Equals("bv32_to_bool"))
- {
- expr = (expr as NAryExpr).Args[0];
- }
-
- if (!(expr is NAryExpr))
- {
- return new KeyValuePair<IdentifierExpr, Expr>(null, null);
- }
-
- NAryExpr nary = expr as NAryExpr;
-
- if (!(nary.Fun.FunctionName.Equals("BV32_C_LT") || nary.Fun.FunctionName.Equals("BV32_LT")))
- {
- return new KeyValuePair<IdentifierExpr, Expr>(null, null);
- }
-
- if (!(nary.Args[0] is IdentifierExpr))
- {
- return new KeyValuePair<IdentifierExpr, Expr>(null, null);
- }
-
- if (!IsConstant(nary.Args[1]))
- {
- return new KeyValuePair<IdentifierExpr, Expr>(null, null);
- }
-
- return new KeyValuePair<IdentifierExpr, Expr>(nary.Args[0] as IdentifierExpr, nary.Args[1]);
-
- }
-
- private static bool IsConstant(Expr e)
- {
- return ((e is IdentifierExpr && (e as IdentifierExpr).Decl is Constant) || e is LiteralExpr);
- }
-
- private void AddReadOrWrittenOffsetIsThreadIdCandidateRequires(Procedure Proc, Variable v)
- {
- AddAccessedOffsetIsThreadLocalIdCandidateRequires(Proc, v, "WRITE", 1);
- AddAccessedOffsetIsThreadLocalIdCandidateRequires(Proc, v, "READ", 1);
- }
-
- private void AddReadOrWrittenOffsetIsThreadIdCandidateEnsures(Procedure Proc, Variable v)
- {
- AddAccessedOffsetIsThreadLocalIdCandidateEnsures(Proc, v, "WRITE", 1);
- AddAccessedOffsetIsThreadLocalIdCandidateEnsures(Proc, v, "READ", 1);
- }
-
- public void AddKernelPrecondition()
- {
- foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays())
- {
- AddRequiresNoPendingAccess(v);
-
- if (!verifier.ArrayModelledAdversarially(v))
- {
- IdentifierExpr v1 = new IdentifierExpr(Token.NoToken, new VariableDualiser(1, null, null).VisitVariable(v.Clone() as Variable));
- IdentifierExpr v2 = new IdentifierExpr(Token.NoToken, new VariableDualiser(2, null, null).VisitVariable(v.Clone() as Variable));
- verifier.KernelProcedure.Requires.Add(new Requires(false, Expr.Eq(v1, v2)));
- }
- }
- }
-
- public bool AddRaceCheckingInstrumentation()
- {
-
- if (onlyLog1 != -1)
- {
- addedLogWrite = false;
- failedToFindSecondAccess = true;
- }
- else
- {
- addedLogWrite = true;
- failedToFindSecondAccess = false;
- }
-
- foreach (Declaration d in verifier.Program.TopLevelDeclarations)
- {
- if (d is Implementation)
- {
- AddRaceCheckCalls(d as Implementation);
- }
- }
-
- if (failedToFindSecondAccess || !addedLogWrite)
- return false;
-
- return true;
-
- }
-
- private void AddRaceCheckingDecsAndProcsForVar(Variable v)
- {
- AddLogRaceDeclarations(v, "READ");
- AddLogRaceDeclarations(v, "WRITE");
- AddLogAccessProcedure(v, "READ");
- AddLogAccessProcedure(v, "WRITE");
-
- }
-
- private StmtList AddRaceCheckCalls(StmtList stmtList)
- {
- Contract.Requires(stmtList != null);
-
- StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
-
- foreach (BigBlock bodyBlock in stmtList.BigBlocks)
- {
- result.BigBlocks.Add(AddRaceCheckCalls(bodyBlock));
- }
- return result;
- }
-
- private Block AddRaceCheckCalls(Block b)
- {
- b.Cmds = AddRaceCheckCalls(b.Cmds);
- return b;
- }
-
- private void AddRaceCheckCalls(Implementation impl)
- {
- if (CommandLineOptions.Unstructured)
- impl.Blocks = impl.Blocks.Select(AddRaceCheckCalls).ToList();
- else
- impl.StructuredStmts = AddRaceCheckCalls(impl.StructuredStmts);
- }
-
- private bool shouldAddLogCallAndIncr()
- {
- Contract.Assert(onlyLog1 >= -1);
- int oldLogAddCount = logAddCount;
- ++logAddCount;
-
- if (onlyLog1 == -1)
- {
- return true;
- }
-
- if(onlyLog1 + onlyLog2 == oldLogAddCount)
- {
- failedToFindSecondAccess = false;
- return true;
- }
-
- if (onlyLog1 == oldLogAddCount)
- {
- return true;
- }
-
- return false;
- }
-
- private CmdSeq AddRaceCheckCalls(CmdSeq cs)
- {
- var result = new CmdSeq();
- foreach (Cmd c in cs)
- {
- result.Add(c);
- if (c is AssignCmd)
- {
- AssignCmd assign = c as AssignCmd;
-
- ReadCollector rc = new ReadCollector(NonLocalStateToCheck);
- foreach (var rhs in assign.Rhss)
- rc.Visit(rhs);
- if (rc.accesses.Count > 0)
- {
- foreach (AccessRecord ar in rc.accesses)
- {
- if (shouldAddLogCallAndIncr())
- {
-
- ExprSeq inParams = new ExprSeq();
- if (ar.IndexZ != null)
- {
- inParams.Add(ar.IndexZ);
- }
- if (ar.IndexY != null)
- {
- inParams.Add(ar.IndexY);
- }
- if (ar.IndexX != null)
- {
- inParams.Add(ar.IndexX);
- }
-
- Procedure logProcedure = GetLogAccessProcedure(c.tok, "_LOG_READ_" + ar.v.Name);
-
- CallCmd logAccessCallCmd = new CallCmd(c.tok, logProcedure.Name, inParams, new IdentifierExprSeq());
-
- logAccessCallCmd.Proc = logProcedure;
-
- result.Add(logAccessCallCmd);
-
- }
- }
- }
-
- foreach (var lhs in assign.Lhss)
- {
- WriteCollector wc = new WriteCollector(NonLocalStateToCheck);
- wc.Visit(lhs);
- if (wc.GetAccess() != null)
- {
- AccessRecord ar = wc.GetAccess();
-
- if (shouldAddLogCallAndIncr())
- {
-
- ExprSeq inParams = new ExprSeq();
- if (ar.IndexZ != null)
- {
- inParams.Add(ar.IndexZ);
- }
- if (ar.IndexY != null)
- {
- inParams.Add(ar.IndexY);
- }
- if (ar.IndexX != null)
- {
- inParams.Add(ar.IndexX);
- }
-
- Procedure logProcedure = GetLogAccessProcedure(c.tok, "_LOG_WRITE_" + ar.v.Name);
-
- CallCmd logAccessCallCmd = new CallCmd(c.tok, logProcedure.Name, inParams, new IdentifierExprSeq());
-
- logAccessCallCmd.Proc = logProcedure;
-
- result.Add(logAccessCallCmd);
-
- addedLogWrite = true;
-
- }
- }
- }
- }
- }
- return result;
- }
-
- private BigBlock AddRaceCheckCalls(BigBlock bb)
- {
- BigBlock result = new BigBlock(bb.tok, bb.LabelName, AddRaceCheckCalls(bb.simpleCmds), null, bb.tc);
-
- if (bb.ec is WhileCmd)
- {
- WhileCmd WhileCommand = bb.ec as WhileCmd;
- result.ec = new WhileCmd(WhileCommand.tok, WhileCommand.Guard,
- WhileCommand.Invariants, AddRaceCheckCalls(WhileCommand.Body));
- }
- else if (bb.ec is IfCmd)
- {
- IfCmd IfCommand = bb.ec as IfCmd;
- Debug.Assert(IfCommand.elseIf == null); // We don't handle else if yet
- result.ec = new IfCmd(IfCommand.tok, IfCommand.Guard, AddRaceCheckCalls(IfCommand.thn), IfCommand.elseIf, IfCommand.elseBlock != null ? AddRaceCheckCalls(IfCommand.elseBlock) : null);
- }
- else if (bb.ec is BreakCmd)
- {
- result.ec = bb.ec;
- }
- else
- {
- Debug.Assert(bb.ec == null);
- }
-
- return result;
- }
-
- private Procedure GetLogAccessProcedure(IToken tok, string name)
- {
- if (logAccessProcedures.ContainsKey(name))
- {
- return logAccessProcedures[name];
- }
- Procedure newProcedure = new Procedure(tok, name, new TypeVariableSeq(), new VariableSeq(), new VariableSeq(), new RequiresSeq(), new IdentifierExprSeq(), new EnsuresSeq());
- logAccessProcedures[name] = newProcedure;
- return newProcedure;
- }
-
-
- public BigBlock MakeResetReadWriteSetStatements(Variable v, int Thread)
- {
- BigBlock result = new BigBlock(Token.NoToken, null, new CmdSeq(), null, null);
- if (Thread == 2)
- {
- return result;
- }
-
- Expr ResetReadAssumeGuard = Expr.Not(new IdentifierExpr(Token.NoToken,
- new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "READ"))));
- Expr ResetWriteAssumeGuard = Expr.Not(new IdentifierExpr(Token.NoToken,
- new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "WRITE"))));
-
- if (verifier.KernelArrayInfo.getGlobalArrays().Contains(v))
- {
- ResetReadAssumeGuard = Expr.Imp(verifier.ThreadsInSameGroup(), ResetReadAssumeGuard);
- ResetWriteAssumeGuard = Expr.Imp(verifier.ThreadsInSameGroup(), ResetWriteAssumeGuard);
- }
-
- result.simpleCmds.Add(new AssumeCmd(Token.NoToken, ResetReadAssumeGuard));
- result.simpleCmds.Add(new AssumeCmd(Token.NoToken, ResetWriteAssumeGuard));
- return result;
- }
-
- protected Procedure MakeLogAccessProcedureHeader(Variable v, string ReadOrWrite)
- {
- VariableSeq inParams = new VariableSeq();
-
- Variable PredicateParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_P", Microsoft.Boogie.Type.Bool));
-
- Debug.Assert(v.TypedIdent.Type is MapType);
- MapType mt = v.TypedIdent.Type as MapType;
- Debug.Assert(mt.Arguments.Length == 1);
- Variable OffsetParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_offset", mt.Arguments[0]));
- Debug.Assert(!(mt.Result is MapType));
-
- inParams.Add(new VariableDualiser(1, null, null).VisitVariable(PredicateParameter.Clone() as Variable));
- inParams.Add(new VariableDualiser(1, null, null).VisitVariable(OffsetParameter.Clone() as Variable));
-
- inParams.Add(new VariableDualiser(2, null, null).VisitVariable(PredicateParameter.Clone() as Variable));
- inParams.Add(new VariableDualiser(2, null, null).VisitVariable(OffsetParameter.Clone() as Variable));
-
- string LogProcedureName = "_LOG_" + ReadOrWrite + "_" + v.Name;
-
- Procedure result = GetLogAccessProcedure(v.tok, LogProcedureName);
-
- result.InParams = inParams;
-
- result.AddAttribute("inline", new object[] { new LiteralExpr(v.tok, BigNum.FromInt(1)) });
-
- return result;
- }
-
- public void AddRaceCheckingCandidateRequires(Procedure Proc)
- {
- foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays())
- {
- AddNoReadOrWriteCandidateRequires(Proc, v);
- AddReadOrWrittenOffsetIsThreadIdCandidateRequires(Proc, v);
- }
-
- DoHoudiniPointerAnalysis(Proc);
-
- }
-
- private void DoHoudiniPointerAnalysis(Procedure Proc)
- {
- HashSet<string> alreadyConsidered = new HashSet<string>();
-
- foreach (Variable v in Proc.InParams)
- {
- string strippedVarName = GPUVerifier.StripThreadIdentifier(v.Name);
- if (alreadyConsidered.Contains(strippedVarName))
- {
- continue;
- }
- alreadyConsidered.Add(strippedVarName);
- if (v.TypedIdent.Type is CtorType)
- {
- CtorType ct = v.TypedIdent.Type as CtorType;
- if (ct.Decl.Name.Equals("ptr"))
- {
- foreach (var arrayCollection in new ICollection<Variable>[] {
- verifier.KernelArrayInfo.getGlobalArrays(), verifier.KernelArrayInfo.getGroupSharedArrays(),
- verifier.KernelArrayInfo.getPrivateArrays() })
- {
- if (arrayCollection.Count == 0)
- {
- continue;
- }
-
- // This will need to be adapted to work with uniformity analysis
- foreach (string thread in new string[] { "1", "2" })
- {
- Expr DisjunctionOverPointerSet = null;
- foreach (var array in arrayCollection)
- {
- Expr PointerSetDisjunct = Expr.Eq(MakePtrBaseExpr(v, strippedVarName, thread), MakeArrayIdExpr(array));
- DisjunctionOverPointerSet = (DisjunctionOverPointerSet == null ? PointerSetDisjunct : Expr.Or(DisjunctionOverPointerSet, PointerSetDisjunct));
- verifier.AddCandidateRequires(Proc,
- Expr.Imp(new IdentifierExpr(Token.NoToken, "_P$" + thread, Microsoft.Boogie.Type.Bool),
- Expr.Neq(MakePtrBaseExpr(v, strippedVarName, thread), MakeArrayIdExpr(array))));
- }
- Debug.Assert(DisjunctionOverPointerSet != null);
- verifier.AddCandidateRequires(Proc,
- Expr.Imp(new IdentifierExpr(Token.NoToken, "_P$" + thread, Microsoft.Boogie.Type.Bool),
- DisjunctionOverPointerSet));
- verifier.AddCandidateRequires(Proc,
- Expr.Imp(new IdentifierExpr(Token.NoToken, "_P$" + thread, Microsoft.Boogie.Type.Bool),
- Expr.Eq(MakePtrOffsetExpr(v, strippedVarName, thread), GPUVerifier.ZeroBV())));
- }
- }
- }
- }
- }
- }
-
- private static IdentifierExpr MakeArrayIdExpr(Variable array)
- {
- return new IdentifierExpr(Token.NoToken, "$arrayId" + array.Name, null);
- }
-
- private static NAryExpr MakePtrBaseExpr(Variable v, string strippedVarName, string thread)
- {
- return new NAryExpr(Token.NoToken, new FunctionCall(new IdentifierExpr(Token.NoToken, "base#MKPTR", v.TypedIdent.Type)),
- new ExprSeq(new Expr[] { new IdentifierExpr(Token.NoToken, strippedVarName + "$" + thread, v.TypedIdent.Type) }));
- }
-
- private static NAryExpr MakePtrOffsetExpr(Variable v, string strippedVarName, string thread)
- {
- return new NAryExpr(Token.NoToken, new FunctionCall(new IdentifierExpr(Token.NoToken, "offset#MKPTR", v.TypedIdent.Type)),
- new ExprSeq(new Expr[] { new IdentifierExpr(Token.NoToken, strippedVarName + "$" + thread, v.TypedIdent.Type) }));
- }
-
- public void AddRaceCheckingCandidateEnsures(Procedure Proc)
- {
- foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays())
- {
- AddNoReadOrWriteCandidateEnsures(Proc, v);
- AddReadOrWrittenOffsetIsThreadIdCandidateEnsures(Proc, v);
- }
- }
-
- private void AddNoReadOrWriteCandidateRequires(Procedure Proc, Variable v, string ReadOrWrite, string OneOrTwo)
- {
- verifier.AddCandidateRequires(Proc, NoReadOrWriteExpr(v, ReadOrWrite, OneOrTwo));
- }
-
- private void AddNoReadOrWriteCandidateEnsures(Procedure Proc, Variable v, string ReadOrWrite, string OneOrTwo)
- {
- verifier.AddCandidateEnsures(Proc, NoReadOrWriteExpr(v, ReadOrWrite, OneOrTwo));
- }
-
- private HashSet<Expr> GetOffsetsAccessed(IRegion region, Variable v, string AccessType)
- {
- HashSet<Expr> result = new HashSet<Expr>();
-
- foreach (Cmd c in region.Cmds())
- {
- if (c is CallCmd)
- {
- CallCmd call = c as CallCmd;
-
- if (call.callee == "_LOG_" + AccessType + "_" + v.Name)
- {
- // Ins[0] is thread 1's predicate,
- // Ins[1] is the offset to be read
- // If Ins[1] has the form BV32_ADD(offset#construct...(P), offset),
- // we are looking for the second parameter to this BV32_ADD
- Expr offset = call.Ins[1];
- if (offset is NAryExpr)
- {
- var nExpr = (NAryExpr)offset;
- if (nExpr.Fun.FunctionName == "BV32_ADD" &&
- nExpr.Args[0] is NAryExpr)
- {
- var n0Expr = (NAryExpr)nExpr.Args[0];
- if (n0Expr.Fun.FunctionName.StartsWith("offset#"))
- offset = nExpr.Args[1];
- }
- }
- result.Add(offset);
- }
-
- }
-
- }
-
- return result;
- }
-
- public void AddRaceCheckingDeclarations()
- {
- foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays())
- {
- AddRaceCheckingDecsAndProcsForVar(v);
- }
- }
-
- protected void AddLogAccessProcedure(Variable v, string Access)
- {
- Procedure LogAccessProcedure = MakeLogAccessProcedureHeader(v, Access);
-
- Variable AccessHasOccurredVariable = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, Access);
- Variable AccessOffsetXVariable = GPUVerifier.MakeOffsetVariable(v, Access);
-
- Variable PredicateParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_P", Microsoft.Boogie.Type.Bool));
-
- Debug.Assert(v.TypedIdent.Type is MapType);
- MapType mt = v.TypedIdent.Type as MapType;
- Debug.Assert(mt.Arguments.Length == 1);
- Variable OffsetParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_offset", mt.Arguments[0]));
- Debug.Assert(!(mt.Result is MapType));
-
- VariableSeq locals = new VariableSeq();
- Variable TrackVariable = new LocalVariable(v.tok, new TypedIdent(v.tok, "track", Microsoft.Boogie.Type.Bool));
- locals.Add(TrackVariable);
-
- List<BigBlock> bigblocks = new List<BigBlock>();
-
- CmdSeq simpleCmds = new CmdSeq();
-
- simpleCmds.Add(new HavocCmd(v.tok, new IdentifierExprSeq(new IdentifierExpr[] { new IdentifierExpr(v.tok, TrackVariable) })));
-
- simpleCmds.Add(MakeConditionalAssignment(VariableForThread(1, AccessHasOccurredVariable),
- Expr.And(new IdentifierExpr(v.tok, VariableForThread(1, PredicateParameter)), new IdentifierExpr(v.tok, TrackVariable)), Expr.True));
- simpleCmds.Add(MakeConditionalAssignment(VariableForThread(1, AccessOffsetXVariable),
- Expr.And(new IdentifierExpr(v.tok, VariableForThread(1, PredicateParameter)), new IdentifierExpr(v.tok, TrackVariable)),
- new IdentifierExpr(v.tok, VariableForThread(1, OffsetParameter))));
-
- if (Access.Equals("READ"))
- {
- // Check read by thread 2 does not conflict with write by thread 1
- Variable WriteHasOccurredVariable = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "WRITE");
- Variable WriteOffsetVariable = GPUVerifier.MakeOffsetVariable(v, "WRITE");
- Expr WriteReadGuard = new IdentifierExpr(Token.NoToken, VariableForThread(2, PredicateParameter));
- WriteReadGuard = Expr.And(WriteReadGuard, new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteHasOccurredVariable)));
- WriteReadGuard = Expr.And(WriteReadGuard, Expr.Eq(new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteOffsetVariable)),
- new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter))));
- if (!verifier.ArrayModelledAdversarially(v))
- {
- WriteReadGuard = Expr.And(WriteReadGuard, Expr.Neq(
- MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteOffsetVariable)), 1, "WRITE"),
- MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter)), 2, "READ")
- ));
- }
-
- if (verifier.KernelArrayInfo.getGroupSharedArrays().Contains(v))
- {
- WriteReadGuard = Expr.And(WriteReadGuard, verifier.ThreadsInSameGroup());
- }
-
- WriteReadGuard = Expr.Not(WriteReadGuard);
- simpleCmds.Add(new AssertCmd(Token.NoToken, WriteReadGuard));
- }
- else
- {
- Debug.Assert(Access.Equals("WRITE"));
-
- // Check write by thread 2 does not conflict with write by thread 1
- Variable WriteHasOccurredVariable = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "WRITE");
- Variable WriteOffsetVariable = GPUVerifier.MakeOffsetVariable(v, "WRITE");
-
- Expr WriteWriteGuard = new IdentifierExpr(Token.NoToken, VariableForThread(2, PredicateParameter));
- WriteWriteGuard = Expr.And(WriteWriteGuard, new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteHasOccurredVariable)));
- WriteWriteGuard = Expr.And(WriteWriteGuard, Expr.Eq(new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteOffsetVariable)),
- new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter))));
- if (!verifier.ArrayModelledAdversarially(v))
- {
- WriteWriteGuard = Expr.And(WriteWriteGuard, Expr.Neq(
- MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteOffsetVariable)), 1, "WRITE"),
- MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter)), 2, "WRITE")
- ));
- }
-
- if (verifier.KernelArrayInfo.getGroupSharedArrays().Contains(v))
- {
- WriteWriteGuard = Expr.And(WriteWriteGuard, verifier.ThreadsInSameGroup());
- }
-
- WriteWriteGuard = Expr.Not(WriteWriteGuard);
- simpleCmds.Add(new AssertCmd(Token.NoToken, WriteWriteGuard));
-
- // Check write by thread 2 does not conflict with read by thread 1
- Variable ReadHasOccurredVariable = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "READ");
- Variable ReadOffsetVariable = GPUVerifier.MakeOffsetVariable(v, "READ");
-
- Expr ReadWriteGuard = new IdentifierExpr(Token.NoToken, VariableForThread(2, PredicateParameter));
- ReadWriteGuard = Expr.And(ReadWriteGuard, new IdentifierExpr(Token.NoToken, VariableForThread(1, ReadHasOccurredVariable)));
- ReadWriteGuard = Expr.And(ReadWriteGuard, Expr.Eq(new IdentifierExpr(Token.NoToken, VariableForThread(1, ReadOffsetVariable)),
- new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter))));
- if (!verifier.ArrayModelledAdversarially(v))
- {
- ReadWriteGuard = Expr.And(ReadWriteGuard, Expr.Neq(
- MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(1, ReadOffsetVariable)), 1, "WRITE"),
- MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter)), 2, "READ")
- ));
- }
-
- if (verifier.KernelArrayInfo.getGroupSharedArrays().Contains(v))
- {
- ReadWriteGuard = Expr.And(ReadWriteGuard, verifier.ThreadsInSameGroup());
- }
-
- ReadWriteGuard = Expr.Not(ReadWriteGuard);
- simpleCmds.Add(new AssertCmd(Token.NoToken, ReadWriteGuard));
-
- }
-
- bigblocks.Add(new BigBlock(v.tok, "_LOG_" + Access + "", simpleCmds, null, null));
-
- LogAccessProcedure.Modifies.Add(new IdentifierExpr(Token.NoToken, VariableForThread(1, AccessHasOccurredVariable)));
- LogAccessProcedure.Modifies.Add(new IdentifierExpr(Token.NoToken, VariableForThread(1, AccessOffsetXVariable)));
-
- Implementation LogAccessImplementation = new Implementation(v.tok, "_LOG_" + Access + "_" + v.Name, new TypeVariableSeq(), LogAccessProcedure.InParams, new VariableSeq(), locals, new StmtList(bigblocks, v.tok));
- LogAccessImplementation.AddAttribute("inline", new object[] { new LiteralExpr(v.tok, BigNum.FromInt(1)) });
-
- LogAccessImplementation.Proc = LogAccessProcedure;
-
- verifier.Program.TopLevelDeclarations.Add(LogAccessProcedure);
- verifier.Program.TopLevelDeclarations.Add(LogAccessImplementation);
- }
-
- private Variable VariableForThread(int thread, Variable v)
- {
- return new VariableDualiser(thread, null, null).VisitVariable(v.Clone() as Variable);
- }
-
- protected void AddLogRaceDeclarations(Variable v, String ReadOrWrite)
- {
- verifier.FindOrCreateAccessHasOccurredVariable(v.Name, ReadOrWrite);
-
- Debug.Assert(v.TypedIdent.Type is MapType);
- MapType mt = v.TypedIdent.Type as MapType;
- Debug.Assert(mt.Arguments.Length == 1);
-
- verifier.FindOrCreateOffsetVariable(v, ReadOrWrite);
-
- }
-
-
- private static AssignCmd MakeConditionalAssignment(Variable lhs, Expr condition, Expr rhs)
- {
- List<AssignLhs> lhss = new List<AssignLhs>();
- List<Expr> rhss = new List<Expr>();
- lhss.Add(new SimpleAssignLhs(lhs.tok, new IdentifierExpr(lhs.tok, lhs)));
- rhss.Add(new NAryExpr(rhs.tok, new IfThenElse(rhs.tok), new ExprSeq(new Expr[] { condition, rhs, new IdentifierExpr(lhs.tok, lhs) })));
- return new AssignCmd(lhs.tok, lhss, rhss);
- }
-
- private Expr MakeAccessedIndex(Variable v, Expr offsetExpr, int Thread, string AccessType)
- {
- Expr result = new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(v.Clone() as Variable));
- Debug.Assert(v.TypedIdent.Type is MapType);
- MapType mt = v.TypedIdent.Type as MapType;
- Debug.Assert(mt.Arguments.Length == 1);
-
- result = Expr.Select(result,
- new Expr[] { offsetExpr });
- Debug.Assert(!(mt.Result is MapType));
- return result;
- }
-
- protected void AddRequiresNoPendingAccess(Variable v)
- {
- IdentifierExpr ReadAccessOccurred1 = new IdentifierExpr(v.tok, new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "READ")));
- IdentifierExpr WriteAccessOccurred1 = new IdentifierExpr(v.tok, new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "WRITE")));
-
- verifier.KernelProcedure.Requires.Add(new Requires(false, Expr.And(Expr.Not(ReadAccessOccurred1), Expr.Not(WriteAccessOccurred1))));
- }
-
- protected Expr NoReadOrWriteExpr(Variable v, string ReadOrWrite, string OneOrTwo)
- {
- Variable ReadOrWriteHasOccurred = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, ReadOrWrite);
- ReadOrWriteHasOccurred.Name = ReadOrWriteHasOccurred.Name + "$" + OneOrTwo;
- ReadOrWriteHasOccurred.TypedIdent.Name = ReadOrWriteHasOccurred.TypedIdent.Name + "$" + OneOrTwo;
- Expr expr = Expr.Not(new IdentifierExpr(v.tok, ReadOrWriteHasOccurred));
- return expr;
- }
-
-
- protected void AddOffsetsSatisfyPredicatesCandidateInvariant(IRegion region, Variable v, string ReadOrWrite, List<Expr> preds)
- {
- if (preds.Count != 0)
- {
- Expr expr = AccessedOffsetsSatisfyPredicatesExpr(v, preds, ReadOrWrite, 1);
- verifier.AddCandidateInvariant(region, expr, "accessed offsets satisfy predicates");
- }
- }
-
- private Expr AccessedOffsetsSatisfyPredicatesExpr(Variable v, IEnumerable<Expr> offsets, string ReadOrWrite, int Thread) {
- return Expr.Imp(
- new IdentifierExpr(Token.NoToken, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, ReadOrWrite))),
- offsets.Aggregate(Expr.Or));
- }
-
- private Expr AccessedOffsetIsThreadLocalIdExpr(Variable v, string ReadOrWrite, int Thread)
- {
- Expr expr = null;
- if (GPUVerifier.IndexType(v).Equals(verifier.GetTypeOfIdX()))
- {
- expr = Expr.Imp(
- new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, ReadOrWrite))),
- Expr.Eq(new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeOffsetVariable(v, ReadOrWrite))), new IdentifierExpr(v.tok, verifier.MakeThreadId(v.tok, "X", Thread))));
- }
- return expr;
- }
-
- private Expr AccessedOffsetIsThreadGlobalIdExpr(Variable v, string ReadOrWrite, int Thread)
- {
- Expr expr = null;
- if (GPUVerifier.IndexType(v).Equals(verifier.GetTypeOfIdX()))
- {
- expr = Expr.Imp(
- new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, ReadOrWrite))),
- Expr.Eq(
- new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeOffsetVariable(v, ReadOrWrite))),
- GlobalIdExpr("X", Thread)
- )
- );
- }
- return expr;
- }
-
- private Expr GlobalIdExpr(string dimension, int Thread)
- {
- return new VariableDualiser(Thread, null, null).VisitExpr(verifier.GlobalIdExpr(dimension).Clone() as Expr);
- }
-
- protected void AddAccessedOffsetInRangeCTimesLocalIdToCTimesLocalIdPlusC(IRegion region, Variable v, Expr constant, string ReadOrWrite)
- {
- Expr expr = MakeCTimesLocalIdRangeExpression(v, constant, ReadOrWrite, 1);
- verifier.AddCandidateInvariant(region,
- expr, "accessed offset in range [ C*local_id, (C+1)*local_id )");
- }
-
- private Expr MakeCTimesLocalIdRangeExpression(Variable v, Expr constant, string ReadOrWrite, int Thread)
- {
- Expr CTimesLocalId = verifier.MakeBVMul(constant.Clone() as Expr,
- new IdentifierExpr(Token.NoToken, verifier.MakeThreadId(Token.NoToken, "X", Thread)));
-
- Expr CTimesLocalIdPlusC = verifier.MakeBVAdd(verifier.MakeBVMul(constant.Clone() as Expr,
- new IdentifierExpr(Token.NoToken, verifier.MakeThreadId(Token.NoToken, "X", Thread))), constant.Clone() as Expr);
-
- Expr CTimesLocalIdLeqAccessedOffset = GPUVerifier.MakeBitVectorBinaryBoolean("BV32_LEQ", CTimesLocalId, OffsetXExpr(v, ReadOrWrite, Thread));
-
- Expr AccessedOffsetLtCTimesLocalIdPlusC = verifier.MakeBVSlt(OffsetXExpr(v, ReadOrWrite, Thread), CTimesLocalIdPlusC);
-
- return Expr.Imp(
- AccessHasOccurred(v, ReadOrWrite, Thread),
- Expr.And(CTimesLocalIdLeqAccessedOffset, AccessedOffsetLtCTimesLocalIdPlusC));
- }
-
- private static IdentifierExpr AccessHasOccurred(Variable v, string ReadOrWrite, int Thread)
- {
- return new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, ReadOrWrite)));
- }
-
- private static IdentifierExpr OffsetXExpr(Variable v, string ReadOrWrite, int Thread)
- {
- return new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeOffsetVariable(v, ReadOrWrite)));
- }
-
- protected void AddAccessedOffsetInRangeCTimesGlobalIdToCTimesGlobalIdPlusC(IRegion region, Variable v, Expr constant, string ReadOrWrite)
- {
- Expr expr = MakeCTimesGloalIdRangeExpr(v, constant, ReadOrWrite, 1);
- verifier.AddCandidateInvariant(region,
- expr, "accessed offset in range [ C*global_id, (C+1)*global_id )");
- }
-
- private Expr MakeCTimesGloalIdRangeExpr(Variable v, Expr constant, string ReadOrWrite, int Thread)
- {
- Expr CTimesGlobalId = verifier.MakeBVMul(constant.Clone() as Expr,
- GlobalIdExpr("X", Thread));
-
- Expr CTimesGlobalIdPlusC = verifier.MakeBVAdd(verifier.MakeBVMul(constant.Clone() as Expr,
- GlobalIdExpr("X", Thread)), constant.Clone() as Expr);
-
- Expr CTimesGlobalIdLeqAccessedOffset = GPUVerifier.MakeBitVectorBinaryBoolean("BV32_LEQ", CTimesGlobalId, OffsetXExpr(v, ReadOrWrite, Thread));
-
- Expr AccessedOffsetLtCTimesGlobalIdPlusC = verifier.MakeBVSlt(OffsetXExpr(v, ReadOrWrite, Thread), CTimesGlobalIdPlusC);
-
- Expr implication = Expr.Imp(
- AccessHasOccurred(v, ReadOrWrite, Thread),
- Expr.And(CTimesGlobalIdLeqAccessedOffset, AccessedOffsetLtCTimesGlobalIdPlusC));
- return implication;
- }
-
- protected void AddAccessedOffsetIsThreadLocalIdCandidateRequires(Procedure Proc, Variable v, string ReadOrWrite, int Thread)
- {
- Expr expr = AccessedOffsetIsThreadLocalIdExpr(v, ReadOrWrite, Thread);
- if (expr != null)
- {
- verifier.AddCandidateRequires(Proc, expr);
- }
- }
-
- protected void AddAccessedOffsetIsThreadLocalIdCandidateEnsures(Procedure Proc, Variable v, string ReadOrWrite, int Thread)
- {
- Expr expr = AccessedOffsetIsThreadLocalIdExpr(v, ReadOrWrite, Thread);
- if (expr != null)
- {
- verifier.AddCandidateEnsures(Proc, expr);
- }
- }
-
-
-
- }
-
-
-
- class FindReferencesToNamedVariableVisitor : StandardVisitor
- {
- internal bool found = false;
- private string name;
-
- internal FindReferencesToNamedVariableVisitor(string name)
- {
- this.name = name;
- }
-
- public override Variable VisitVariable(Variable node)
- {
- if (GPUVerifier.StripThreadIdentifier(node.Name).Equals(name))
- {
- found = true;
- }
- return base.VisitVariable(node);
- }
- }
-
-
-
-}
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using Microsoft.Boogie;
+using Microsoft.Basetypes;
+
+namespace GPUVerify {
+ class RaceInstrumenter : IRaceInstrumenter {
+ protected GPUVerifier verifier;
+
+ private QKeyValue SourceLocationAttributes = null;
+
+ private int CurrStmtNo = 1;
+
+ private Dictionary<string, List<int>> ReadAccessSourceLocations = new Dictionary<string, List<int>>();
+
+ private Dictionary<string, List<int>> WriteAccessSourceLocations = new Dictionary<string, List<int>>();
+
+ public IKernelArrayInfo NonLocalStateToCheck;
+
+ private Dictionary<string, Procedure> RaceCheckingProcedures = new Dictionary<string, Procedure>();
+
+ public void setVerifier(GPUVerifier verifier) {
+ this.verifier = verifier;
+ NonLocalStateToCheck = new KernelArrayInfoLists();
+ foreach (Variable v in verifier.KernelArrayInfo.getGlobalArrays()) {
+ NonLocalStateToCheck.getGlobalArrays().Add(v);
+ }
+ foreach (Variable v in verifier.KernelArrayInfo.getGroupSharedArrays()) {
+ NonLocalStateToCheck.getGroupSharedArrays().Add(v);
+ }
+ }
+
+ private void AddNoReadOrWriteCandidateInvariants(IRegion region, Variable v) {
+ // Reasoning: if READ_HAS_OCCURRED_v is not in the modifies set for the
+ // loop then there is no point adding an invariant
+ //
+ // If READ_HAS_OCCURRED_v is in the modifies set, but the loop does not
+ // contain a barrier, then it is almost certain that a read CAN be
+ // pending at the loop head, so the invariant will not hold
+ //
+ // If there is a barrier in the loop body then READ_HAS_OCCURRED_v will
+ // be in the modifies set, but there may not be a live read at the loop
+ // head, so it is worth adding the loop invariant candidate.
+ //
+ // The same reasoning applies for WRITE
+
+ if (verifier.ContainsBarrierCall(region)) {
+ if (verifier.ContainsNamedVariable(
+ LoopInvariantGenerator.GetModifiedVariables(region), GPUVerifier.MakeAccessHasOccurredVariableName(v.Name, "READ"))) {
+ AddNoReadOrWriteCandidateInvariant(region, v, "READ");
+ }
+
+ if (verifier.ContainsNamedVariable(
+ LoopInvariantGenerator.GetModifiedVariables(region), GPUVerifier.MakeAccessHasOccurredVariableName(v.Name, "WRITE"))) {
+ AddNoReadOrWriteCandidateInvariant(region, v, "WRITE");
+ }
+ }
+ }
+
+ private void AddNoReadOrWriteCandidateRequires(Procedure Proc, Variable v) {
+ AddNoReadOrWriteCandidateRequires(Proc, v, "READ", "1");
+ AddNoReadOrWriteCandidateRequires(Proc, v, "WRITE", "1");
+ }
+
+ private void AddNoReadOrWriteCandidateEnsures(Procedure Proc, Variable v) {
+ AddNoReadOrWriteCandidateEnsures(Proc, v, "READ", "1");
+ AddNoReadOrWriteCandidateEnsures(Proc, v, "WRITE", "1");
+ }
+
+ private void AddNoReadOrWriteCandidateInvariant(IRegion region, Variable v, string ReadOrWrite) {
+ Expr candidate = NoReadOrWriteExpr(v, ReadOrWrite, "1");
+ verifier.AddCandidateInvariant(region, candidate, "no " + ReadOrWrite.ToLower());
+ }
+
+ public void AddRaceCheckingCandidateInvariants(Implementation impl, IRegion region) {
+ List<Expr> offsetPredicatesRead = new List<Expr>();
+ List<Expr> offsetPredicatesWrite = new List<Expr>();
+ foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays()) {
+ AddNoReadOrWriteCandidateInvariants(region, v);
+ AddReadOrWrittenOffsetIsThreadIdCandidateInvariants(impl, region, v, "READ");
+ AddReadOrWrittenOffsetIsThreadIdCandidateInvariants(impl, region, v, "WRITE");
+ offsetPredicatesRead = CollectOffsetPredicates(impl, region, v, "READ");
+ offsetPredicatesWrite = CollectOffsetPredicates(impl, region, v, "WRITE");
+ AddOffsetsSatisfyPredicatesCandidateInvariant(region, v, "READ", offsetPredicatesRead);
+ AddOffsetsSatisfyPredicatesCandidateInvariant(region, v, "WRITE", offsetPredicatesWrite);
+ AddOffsetsSatisfyPredicatesCandidateInvariant(region, v, "READ", new List<Expr>(offsetPredicatesRead.Zip(CollectSourceLocPredicates(region, v, "READ"), Expr.And)));
+ AddOffsetsSatisfyPredicatesCandidateInvariant(region, v, "WRITE", new List<Expr>(offsetPredicatesWrite.Zip(CollectSourceLocPredicates(region, v, "WRITE"), Expr.And)));
+ }
+ }
+
+ private void AddAccessRelatedCandidateInvariant(IRegion region, string accessKind, Expr candidateInvariantExpr, string procName, string tag) {
+ Expr candidate = new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(candidateInvariantExpr.Clone() as Expr);
+ verifier.AddCandidateInvariant(region, candidate, tag);
+ }
+
+ private bool DoesNotReferTo(Expr expr, string v) {
+ FindReferencesToNamedVariableVisitor visitor = new FindReferencesToNamedVariableVisitor(v);
+ visitor.VisitExpr(expr);
+ return !visitor.found;
+ }
+
+ private List<Expr> CollectSourceLocPredicates(IRegion region, Variable v, string accessType) {
+ var sourceVar = verifier.FindOrCreateSourceVariable(v.Name, accessType);
+ var sourceExpr = new IdentifierExpr(Token.NoToken, sourceVar);
+ var sourcePreds = new List<Expr>();
+
+ foreach (Cmd c in region.Cmds()) {
+ if (c is CallCmd) {
+ CallCmd call = c as CallCmd;
+ if (call.callee == "_LOG_" + accessType + "_" + v.Name) {
+ sourcePreds.Add(Expr.Eq(sourceExpr, call.Ins[2]));
+ }
+ }
+ }
+
+ return sourcePreds;
+ }
+ private List<Expr> CollectOffsetPredicates(Implementation impl, IRegion region, Variable v, string accessType) {
+ var offsetVar = new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeOffsetVariable(v.Name, accessType));
+ var offsetExpr = new IdentifierExpr(Token.NoToken, offsetVar);
+ var offsetPreds = new List<Expr>();
+
+ foreach (var offset in GetOffsetsAccessed(region, v, accessType)) {
+ bool isConstant;
+ var def = verifier.varDefAnalyses[impl].SubstDefinitions(offset, impl.Name, out isConstant);
+ if (def == null)
+ continue;
+
+ if (isConstant) {
+ offsetPreds.Add(Expr.Eq(offsetExpr, def));
+ }
+ else {
+ var sc = StrideConstraint.FromExpr(verifier, impl, def);
+ var pred = sc.MaybeBuildPredicate(verifier, offsetExpr);
+ if (pred != null)
+ offsetPreds.Add(pred);
+ }
+ }
+
+ return offsetPreds;
+ }
+
+ private void AddReadOrWrittenOffsetIsThreadIdCandidateInvariants(Implementation impl, IRegion region, Variable v, string accessType) {
+ KeyValuePair<IdentifierExpr, Expr> iLessThanC = GetILessThanC(region.Guard());
+ if (iLessThanC.Key != null) {
+ foreach (Expr e in GetOffsetsAccessed(region, v, accessType)) {
+ if (HasFormIPlusLocalIdTimesC(e, iLessThanC, impl)) {
+ AddAccessedOffsetInRangeCTimesLocalIdToCTimesLocalIdPlusC(region, v, iLessThanC.Value, accessType);
+ break;
+ }
+ }
+
+ foreach (Expr e in GetOffsetsAccessed(region, v, accessType)) {
+ if (HasFormIPlusGlobalIdTimesC(e, iLessThanC, impl)) {
+ AddAccessedOffsetInRangeCTimesGlobalIdToCTimesGlobalIdPlusC(region, v, iLessThanC.Value, accessType);
+ break;
+ }
+ }
+
+ }
+
+
+ }
+
+ private bool HasFormIPlusLocalIdTimesC(Expr e, KeyValuePair<IdentifierExpr, Expr> iLessThanC, Implementation impl) {
+ if (!(e is NAryExpr)) {
+ return false;
+ }
+
+ NAryExpr nary = e as NAryExpr;
+
+ if (!nary.Fun.FunctionName.Equals("BV32_ADD")) {
+ return false;
+ }
+
+ return (SameIdentifierExpression(nary.Args[0], iLessThanC.Key) &&
+ IsLocalIdTimesConstant(nary.Args[1], iLessThanC.Value, impl)) ||
+ (SameIdentifierExpression(nary.Args[1], iLessThanC.Key) &&
+ IsLocalIdTimesConstant(nary.Args[0], iLessThanC.Value, impl));
+ }
+
+ private bool IsLocalIdTimesConstant(Expr maybeLocalIdTimesConstant, Expr constant, Implementation impl) {
+ if (!(maybeLocalIdTimesConstant is NAryExpr)) {
+ return false;
+ }
+ NAryExpr nary = maybeLocalIdTimesConstant as NAryExpr;
+ if (!nary.Fun.FunctionName.Equals("BV32_MUL")) {
+ return false;
+ }
+
+ return
+ (SameConstant(nary.Args[0], constant) && verifier.IsLocalId(nary.Args[1], 0, impl)) ||
+ (SameConstant(nary.Args[1], constant) && verifier.IsLocalId(nary.Args[0], 0, impl));
+ }
+
+
+ private bool HasFormIPlusGlobalIdTimesC(Expr e, KeyValuePair<IdentifierExpr, Expr> iLessThanC, Implementation impl) {
+ if (!(e is NAryExpr)) {
+ return false;
+ }
+
+ NAryExpr nary = e as NAryExpr;
+
+ if (!nary.Fun.FunctionName.Equals("BV32_ADD")) {
+ return false;
+ }
+
+ return (SameIdentifierExpression(nary.Args[0], iLessThanC.Key) &&
+ IsGlobalIdTimesConstant(nary.Args[1], iLessThanC.Value, impl)) ||
+ (SameIdentifierExpression(nary.Args[1], iLessThanC.Key) &&
+ IsGlobalIdTimesConstant(nary.Args[0], iLessThanC.Value, impl));
+ }
+
+ private bool IsGlobalIdTimesConstant(Expr maybeGlobalIdTimesConstant, Expr constant, Implementation impl) {
+ if (!(maybeGlobalIdTimesConstant is NAryExpr)) {
+ return false;
+ }
+ NAryExpr nary = maybeGlobalIdTimesConstant as NAryExpr;
+ if (!nary.Fun.FunctionName.Equals("BV32_MUL")) {
+ return false;
+ }
+
+ return
+ (SameConstant(nary.Args[0], constant) && verifier.IsGlobalId(nary.Args[1], 0, impl)) ||
+ (SameConstant(nary.Args[1], constant) && verifier.IsGlobalId(nary.Args[0], 0, impl));
+ }
+
+
+ private bool SameConstant(Expr expr, Expr constant) {
+ if (constant is IdentifierExpr) {
+ IdentifierExpr identifierExpr = constant as IdentifierExpr;
+ Debug.Assert(identifierExpr.Decl is Constant);
+ return expr is IdentifierExpr && (expr as IdentifierExpr).Decl is Constant && (expr as IdentifierExpr).Decl.Name.Equals(identifierExpr.Decl.Name);
+ }
+ else {
+ Debug.Assert(constant is LiteralExpr);
+ LiteralExpr literalExpr = constant as LiteralExpr;
+ if (!(expr is LiteralExpr)) {
+ return false;
+ }
+ if (!(literalExpr.Val is BvConst) || !((expr as LiteralExpr).Val is BvConst)) {
+ return false;
+ }
+
+ return (literalExpr.Val as BvConst).Value.ToInt == ((expr as LiteralExpr).Val as BvConst).Value.ToInt;
+ }
+ }
+
+ private bool SameIdentifierExpression(Expr expr, IdentifierExpr identifierExpr) {
+ if (!(expr is IdentifierExpr)) {
+ return false;
+ }
+ return (expr as IdentifierExpr).Decl.Name.Equals(identifierExpr.Name);
+ }
+
+ private KeyValuePair<IdentifierExpr, Expr> GetILessThanC(Expr expr) {
+
+ if (expr is NAryExpr && (expr as NAryExpr).Fun.FunctionName.Equals("bv32_to_bool")) {
+ expr = (expr as NAryExpr).Args[0];
+ }
+
+ if (!(expr is NAryExpr)) {
+ return new KeyValuePair<IdentifierExpr, Expr>(null, null);
+ }
+
+ NAryExpr nary = expr as NAryExpr;
+
+ if (!(nary.Fun.FunctionName.Equals("BV32_C_LT") || nary.Fun.FunctionName.Equals("BV32_LT"))) {
+ return new KeyValuePair<IdentifierExpr, Expr>(null, null);
+ }
+
+ if (!(nary.Args[0] is IdentifierExpr)) {
+ return new KeyValuePair<IdentifierExpr, Expr>(null, null);
+ }
+
+ if (!IsConstant(nary.Args[1])) {
+ return new KeyValuePair<IdentifierExpr, Expr>(null, null);
+ }
+
+ return new KeyValuePair<IdentifierExpr, Expr>(nary.Args[0] as IdentifierExpr, nary.Args[1]);
+
+ }
+
+ private static bool IsConstant(Expr e) {
+ return ((e is IdentifierExpr && (e as IdentifierExpr).Decl is Constant) || e is LiteralExpr);
+ }
+
+ private void AddReadOrWrittenOffsetIsThreadIdCandidateRequires(Procedure Proc, Variable v) {
+ AddAccessedOffsetIsThreadLocalIdCandidateRequires(Proc, v, "WRITE", 1);
+ AddAccessedOffsetIsThreadLocalIdCandidateRequires(Proc, v, "READ", 1);
+ }
+
+ private void AddReadOrWrittenOffsetIsThreadIdCandidateEnsures(Procedure Proc, Variable v) {
+ AddAccessedOffsetIsThreadLocalIdCandidateEnsures(Proc, v, "WRITE", 1);
+ AddAccessedOffsetIsThreadLocalIdCandidateEnsures(Proc, v, "READ", 1);
+ }
+
+ public void AddKernelPrecondition() {
+ foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays()) {
+ AddRequiresNoPendingAccess(v);
+ AddRequiresSourceAccessZero(v);
+ }
+ }
+
+ public void AddRaceCheckingInstrumentation() {
+
+ foreach (Declaration d in verifier.Program.TopLevelDeclarations) {
+ if (d is Implementation) {
+ AddRaceCheckCalls(d as Implementation);
+ }
+ }
+
+ }
+
+ private void AddRaceCheckingDecsAndProcsForVar(Variable v) {
+ AddLogRaceDeclarations(v, "READ");
+ AddLogRaceDeclarations(v, "WRITE");
+ AddLogAccessProcedure(v, "READ");
+ AddCheckAccessProcedure(v, "READ");
+ AddLogAccessProcedure(v, "WRITE");
+ AddCheckAccessProcedure(v, "WRITE");
+ }
+
+ private StmtList AddRaceCheckCalls(StmtList stmtList) {
+ Contract.Requires(stmtList != null);
+
+ StmtList result = new StmtList(new List<BigBlock>(), stmtList.EndCurly);
+
+ foreach (BigBlock bodyBlock in stmtList.BigBlocks) {
+ result.BigBlocks.Add(AddRaceCheckCalls(bodyBlock));
+ }
+ return result;
+ }
+
+ private Block AddRaceCheckCalls(Block b) {
+ b.Cmds = AddRaceCheckCalls(b.Cmds);
+ return b;
+ }
+
+ private void AddRaceCheckCalls(Implementation impl) {
+ if (CommandLineOptions.Unstructured)
+ impl.Blocks = impl.Blocks.Select(AddRaceCheckCalls).ToList();
+ else
+ impl.StructuredStmts = AddRaceCheckCalls(impl.StructuredStmts);
+ }
+
+ private CmdSeq AddRaceCheckCalls(CmdSeq cs) {
+ var result = new CmdSeq();
+ foreach (Cmd c in cs) {
+ result.Add(c);
+
+ if (c is AssertCmd) {
+ AssertCmd assertion = c as AssertCmd;
+ if (QKeyValue.FindBoolAttribute(assertion.Attributes, "sourceloc")) {
+ SourceLocationAttributes = assertion.Attributes;
+ }
+ }
+
+ if (c is AssignCmd) {
+ AssignCmd assign = c as AssignCmd;
+
+ ReadCollector rc = new ReadCollector(NonLocalStateToCheck);
+ foreach (var rhs in assign.Rhss)
+ rc.Visit(rhs);
+ if (rc.accesses.Count > 0) {
+ foreach (AccessRecord ar in rc.accesses) {
+ AddLogAndCheckCalls(result, ar, "READ");
+ }
+ }
+
+ foreach (var lhs in assign.Lhss) {
+ WriteCollector wc = new WriteCollector(NonLocalStateToCheck);
+ wc.Visit(lhs);
+ if (wc.GetAccess() != null) {
+ AccessRecord ar = wc.GetAccess();
+ AddLogAndCheckCalls(result, ar, "WRITE");
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ private void AddLogAndCheckCalls(CmdSeq result, AccessRecord ar, string Access) {
+ ExprSeq inParamsLog = new ExprSeq();
+ ExprSeq inParamsChk = new ExprSeq();
+ inParamsChk.Add(ar.Index);
+ inParamsLog.Add(ar.Index);
+ inParamsLog.Add(new LiteralExpr(Token.NoToken, BigNum.FromInt(CurrStmtNo), 32));
+
+ Procedure logProcedure = GetRaceCheckingProcedure(Token.NoToken, "_LOG_" + Access + "_" + ar.v.Name);
+ Procedure checkProcedure = GetRaceCheckingProcedure(Token.NoToken, "_CHECK_" + Access + "_" + ar.v.Name);
+
+ verifier.OnlyThread1.Add(logProcedure.Name);
+ verifier.OnlyThread2.Add(checkProcedure.Name);
+
+ CallCmd logAccessCallCmd = new CallCmd(Token.NoToken, logProcedure.Name, inParamsLog, new IdentifierExprSeq());
+ logAccessCallCmd.Proc = logProcedure;
+
+ CallCmd checkAccessCallCmd = new CallCmd(Token.NoToken, checkProcedure.Name, inParamsChk, new IdentifierExprSeq());
+ checkAccessCallCmd.Proc = checkProcedure;
+ checkAccessCallCmd.Attributes = SourceLocationAttributes;
+
+ result.Add(logAccessCallCmd);
+ result.Add(checkAccessCallCmd);
+
+ string fname = QKeyValue.FindStringAttribute(SourceLocationAttributes, "fname");
+
+ string Key = ar.v.Name;
+ if (Access == "WRITE")
+ {
+ if (!WriteAccessSourceLocations.ContainsKey(Key))
+ {
+ WriteAccessSourceLocations.Add(Key, new List<int>());
+ }
+ WriteAccessSourceLocations[Key].Add(CurrStmtNo);
+ }
+ else if (Access == "READ")
+ {
+ if (!ReadAccessSourceLocations.ContainsKey(Key))
+ {
+ ReadAccessSourceLocations.Add(Key, new List<int>());
+ }
+ ReadAccessSourceLocations[Key].Add(CurrStmtNo);
+ }
+
+ if (fname != null)
+ {
+ writeSourceLocToFile(SourceLocationAttributes, Path.GetFileNameWithoutExtension(CommandLineOptions.inputFiles[0]) + ".loc");
+ }
+ else
+ {
+ Debug.Assert(false, "RaceInstrumenter.AddLogAndCheckCalls: Could not write sourceloc to file as filename could not be found.\n");
+ }
+ CurrStmtNo++;
+ }
+
+ private BigBlock AddRaceCheckCalls(BigBlock bb) {
+ BigBlock result = new BigBlock(bb.tok, bb.LabelName, AddRaceCheckCalls(bb.simpleCmds), null, bb.tc);
+
+ if (bb.ec is WhileCmd) {
+ WhileCmd WhileCommand = bb.ec as WhileCmd;
+ result.ec = new WhileCmd(WhileCommand.tok, WhileCommand.Guard,
+ WhileCommand.Invariants, AddRaceCheckCalls(WhileCommand.Body));
+ }
+ else if (bb.ec is IfCmd) {
+ IfCmd IfCommand = bb.ec as IfCmd;
+ Debug.Assert(IfCommand.elseIf == null); // We don't handle else if yet
+ result.ec = new IfCmd(IfCommand.tok, IfCommand.Guard, AddRaceCheckCalls(IfCommand.thn), IfCommand.elseIf, IfCommand.elseBlock != null ? AddRaceCheckCalls(IfCommand.elseBlock) : null);
+ }
+ else if (bb.ec is BreakCmd) {
+ result.ec = bb.ec;
+ }
+ else {
+ Debug.Assert(bb.ec == null);
+ }
+
+ return result;
+ }
+
+ private Procedure GetRaceCheckingProcedure(IToken tok, string name) {
+ if (RaceCheckingProcedures.ContainsKey(name)) {
+ return RaceCheckingProcedures[name];
+ }
+ Procedure newProcedure = new Procedure(tok, name, new TypeVariableSeq(), new VariableSeq(), new VariableSeq(), new RequiresSeq(), new IdentifierExprSeq(), new EnsuresSeq());
+ RaceCheckingProcedures[name] = newProcedure;
+ return newProcedure;
+ }
+
+
+ public BigBlock MakeResetReadWriteSetStatements(Variable v, int Thread) {
+ BigBlock result = new BigBlock(Token.NoToken, null, new CmdSeq(), null, null);
+ if (Thread == 2) {
+ return result;
+ }
+
+ Expr ResetReadAssumeGuard = Expr.Not(new IdentifierExpr(Token.NoToken,
+ new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "READ"))));
+ Expr ResetWriteAssumeGuard = Expr.Not(new IdentifierExpr(Token.NoToken,
+ new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "WRITE"))));
+
+ if (verifier.KernelArrayInfo.getGlobalArrays().Contains(v)) {
+ ResetReadAssumeGuard = Expr.Imp(GPUVerifier.ThreadsInSameGroup(), ResetReadAssumeGuard);
+ ResetWriteAssumeGuard = Expr.Imp(GPUVerifier.ThreadsInSameGroup(), ResetWriteAssumeGuard);
+ }
+
+ result.simpleCmds.Add(new AssumeCmd(Token.NoToken, ResetReadAssumeGuard));
+ result.simpleCmds.Add(new AssumeCmd(Token.NoToken, ResetWriteAssumeGuard));
+ return result;
+ }
+
+ protected Procedure MakeLogAccessProcedureHeader(Variable v, string ReadOrWrite) {
+ VariableSeq inParams = new VariableSeq();
+
+ Variable PredicateParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_P", Microsoft.Boogie.Type.Bool));
+
+ Debug.Assert(v.TypedIdent.Type is MapType);
+ MapType mt = v.TypedIdent.Type as MapType;
+ Debug.Assert(mt.Arguments.Length == 1);
+ Variable OffsetParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_offset", mt.Arguments[0]));
+ Variable SourceParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_source", mt.Arguments[0]));
+ Debug.Assert(!(mt.Result is MapType));
+
+ inParams.Add(new VariableDualiser(1, null, null).VisitVariable(PredicateParameter.Clone() as Variable));
+ inParams.Add(new VariableDualiser(1, null, null).VisitVariable(OffsetParameter.Clone() as Variable));
+ inParams.Add(new VariableDualiser(1, null, null).VisitVariable(SourceParameter.Clone() as Variable));
+
+ string LogProcedureName = "_LOG_" + ReadOrWrite + "_" + v.Name;
+
+ Procedure result = GetRaceCheckingProcedure(v.tok, LogProcedureName);
+
+ result.InParams = inParams;
+
+ result.AddAttribute("inline", new object[] { new LiteralExpr(v.tok, BigNum.FromInt(1)) });
+
+ return result;
+ }
+
+ protected Procedure MakeCheckAccessProcedureHeader(Variable v, string ReadOrWrite) {
+ VariableSeq inParams = new VariableSeq();
+
+ Variable PredicateParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_P", Microsoft.Boogie.Type.Bool));
+
+ Debug.Assert(v.TypedIdent.Type is MapType);
+ MapType mt = v.TypedIdent.Type as MapType;
+ Debug.Assert(mt.Arguments.Length == 1);
+ Variable OffsetParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_offset", mt.Arguments[0]));
+ Debug.Assert(!(mt.Result is MapType));
+
+ inParams.Add(new VariableDualiser(2, null, null).VisitVariable(PredicateParameter.Clone() as Variable));
+ inParams.Add(new VariableDualiser(2, null, null).VisitVariable(OffsetParameter.Clone() as Variable));
+
+ string CheckProcedureName = "_CHECK_" + ReadOrWrite + "_" + v.Name;
+
+ Procedure result = GetRaceCheckingProcedure(v.tok, CheckProcedureName);
+
+ result.InParams = inParams;
+
+ result.AddAttribute("inline", new object[] { new LiteralExpr(v.tok, BigNum.FromInt(1)) });
+
+ return result;
+ }
+
+ public void AddRaceCheckingCandidateRequires(Procedure Proc) {
+ foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays()) {
+ AddNoReadOrWriteCandidateRequires(Proc, v);
+ AddReadOrWrittenOffsetIsThreadIdCandidateRequires(Proc, v);
+ }
+ }
+
+ public void DoHoudiniPointerAnalysis(Procedure Proc) {
+ foreach (Variable v in Proc.InParams) {
+ if (v.TypedIdent.Type is CtorType) {
+ CtorType ct = v.TypedIdent.Type as CtorType;
+ if (ct.Decl.Name.Equals("ptr")) {
+ foreach (var arrayCollection in new ICollection<Variable>[] {
+ verifier.KernelArrayInfo.getGlobalArrays(), verifier.KernelArrayInfo.getGroupSharedArrays(),
+ verifier.KernelArrayInfo.getPrivateArrays() }) {
+ if (arrayCollection.Count == 0) {
+ continue;
+ }
+
+ Expr DisjunctionOverPointerSet = null;
+ foreach (var array in arrayCollection) {
+ Expr PointerSetDisjunct = Expr.Eq(MakePtrBaseExpr(v), MakeArrayIdExpr(array));
+ DisjunctionOverPointerSet = (DisjunctionOverPointerSet == null ? PointerSetDisjunct : Expr.Or(DisjunctionOverPointerSet, PointerSetDisjunct));
+ verifier.AddCandidateRequires(Proc,
+ Expr.Neq(MakePtrBaseExpr(v), MakeArrayIdExpr(array)));
+ }
+ Debug.Assert(DisjunctionOverPointerSet != null);
+ verifier.AddCandidateRequires(Proc, DisjunctionOverPointerSet);
+ verifier.AddCandidateRequires(Proc, Expr.Eq(MakePtrOffsetExpr(v), GPUVerifier.ZeroBV()));
+ }
+ }
+ }
+ }
+ }
+
+ private IdentifierExpr MakeArrayIdExpr(Variable array) {
+ var arrayId = verifier.ResContext.LookUpVariable("$arrayId" + array.Name);
+ return new IdentifierExpr(Token.NoToken, arrayId);
+ }
+
+ private NAryExpr MakePtrBaseExpr(Variable v) {
+ var baseSel = (Function)verifier.ResContext.LookUpProcedure("base#MKPTR");
+ return new NAryExpr(Token.NoToken, new FunctionCall(baseSel),
+ new ExprSeq(new Expr[] { Expr.Ident(v) }));
+ }
+
+ private NAryExpr MakePtrOffsetExpr(Variable v) {
+ var offsetSel = (Function)verifier.ResContext.LookUpProcedure("offset#MKPTR");
+ return new NAryExpr(Token.NoToken, new FunctionCall(offsetSel),
+ new ExprSeq(new Expr[] { Expr.Ident(v) }));
+ }
+
+ public void AddRaceCheckingCandidateEnsures(Procedure Proc) {
+ foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays()) {
+ AddNoReadOrWriteCandidateEnsures(Proc, v);
+ AddReadOrWrittenOffsetIsThreadIdCandidateEnsures(Proc, v);
+ }
+ }
+
+ private void AddNoReadOrWriteCandidateRequires(Procedure Proc, Variable v, string ReadOrWrite, string OneOrTwo) {
+ verifier.AddCandidateRequires(Proc, NoReadOrWriteExpr(v, ReadOrWrite, OneOrTwo));
+ }
+
+ private void AddNoReadOrWriteCandidateEnsures(Procedure Proc, Variable v, string ReadOrWrite, string OneOrTwo) {
+ verifier.AddCandidateEnsures(Proc, NoReadOrWriteExpr(v, ReadOrWrite, OneOrTwo));
+ }
+
+ private HashSet<Expr> GetOffsetsAccessed(IRegion region, Variable v, string AccessType) {
+ HashSet<Expr> result = new HashSet<Expr>();
+
+ foreach (Cmd c in region.Cmds()) {
+ if (c is CallCmd) {
+ CallCmd call = c as CallCmd;
+
+ if (call.callee == "_LOG_" + AccessType + "_" + v.Name) {
+ // Ins[0] is thread 1's predicate,
+ // Ins[1] is the offset to be read
+ // If Ins[1] has the form BV32_ADD(offset#construct...(P), offset),
+ // we are looking for the second parameter to this BV32_ADD
+ Expr offset = call.Ins[1];
+ if (offset is NAryExpr) {
+ var nExpr = (NAryExpr)offset;
+ if (nExpr.Fun.FunctionName == "BV32_ADD" &&
+ nExpr.Args[0] is NAryExpr) {
+ var n0Expr = (NAryExpr)nExpr.Args[0];
+ if (n0Expr.Fun.FunctionName.StartsWith("offset#"))
+ offset = nExpr.Args[1];
+ }
+ }
+ result.Add(offset);
+ }
+
+ }
+
+ }
+
+ return result;
+ }
+
+ public void AddRaceCheckingDeclarations() {
+ foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays()) {
+ AddRaceCheckingDecsAndProcsForVar(v);
+ }
+ }
+
+ protected void AddLogAccessProcedure(Variable v, string Access) {
+ Procedure LogAccessProcedure = MakeLogAccessProcedureHeader(v, Access);
+
+ Variable AccessHasOccurredVariable = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, Access);
+ Variable AccessOffsetXVariable = GPUVerifier.MakeOffsetVariable(v.Name, Access);
+ Variable AccessSourceVariable = GPUVerifier.MakeSourceVariable(v.Name, Access);
+
+ Variable PredicateParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_P", Microsoft.Boogie.Type.Bool));
+
+ Debug.Assert(v.TypedIdent.Type is MapType);
+ MapType mt = v.TypedIdent.Type as MapType;
+ Debug.Assert(mt.Arguments.Length == 1);
+ Variable OffsetParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_offset", mt.Arguments[0]));
+ Variable SourceParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_source", mt.Arguments[0]));
+ Debug.Assert(!(mt.Result is MapType));
+
+ VariableSeq locals = new VariableSeq();
+ Variable TrackVariable = new LocalVariable(v.tok, new TypedIdent(v.tok, "track", Microsoft.Boogie.Type.Bool));
+ locals.Add(TrackVariable);
+
+ List<BigBlock> bigblocks = new List<BigBlock>();
+
+ CmdSeq simpleCmds = new CmdSeq();
+
+ simpleCmds.Add(new HavocCmd(v.tok, new IdentifierExprSeq(new IdentifierExpr[] { new IdentifierExpr(v.tok, TrackVariable) })));
+
+ simpleCmds.Add(MakeConditionalAssignment(VariableForThread(1, AccessHasOccurredVariable),
+ Expr.And(new IdentifierExpr(v.tok, VariableForThread(1, PredicateParameter)), new IdentifierExpr(v.tok, TrackVariable)), Expr.True));
+ simpleCmds.Add(MakeConditionalAssignment(VariableForThread(1, AccessOffsetXVariable),
+ Expr.And(new IdentifierExpr(v.tok, VariableForThread(1, PredicateParameter)), new IdentifierExpr(v.tok, TrackVariable)),
+ new IdentifierExpr(v.tok, VariableForThread(1, OffsetParameter))));
+ simpleCmds.Add(MakeConditionalAssignment(VariableForThread(1, AccessSourceVariable),
+ Expr.And(new IdentifierExpr(v.tok, VariableForThread(1, PredicateParameter)), new IdentifierExpr(v.tok, TrackVariable)),
+ new IdentifierExpr(v.tok, VariableForThread(1, SourceParameter))));
+
+ bigblocks.Add(new BigBlock(v.tok, "_LOG_" + Access + "", simpleCmds, null, null));
+
+ LogAccessProcedure.Modifies.Add(new IdentifierExpr(Token.NoToken, VariableForThread(1, AccessHasOccurredVariable)));
+ LogAccessProcedure.Modifies.Add(new IdentifierExpr(Token.NoToken, VariableForThread(1, AccessOffsetXVariable)));
+
+ Implementation LogAccessImplementation = new Implementation(v.tok, "_LOG_" + Access + "_" + v.Name, new TypeVariableSeq(), LogAccessProcedure.InParams, new VariableSeq(), locals, new StmtList(bigblocks, v.tok));
+ LogAccessImplementation.AddAttribute("inline", new object[] { new LiteralExpr(v.tok, BigNum.FromInt(1)) });
+
+ LogAccessImplementation.Proc = LogAccessProcedure;
+
+ verifier.Program.TopLevelDeclarations.Add(LogAccessProcedure);
+ verifier.Program.TopLevelDeclarations.Add(LogAccessImplementation);
+ }
+
+
+ protected void AddCheckAccessProcedure(Variable v, string Access) {
+ Procedure CheckAccessProcedure = MakeCheckAccessProcedureHeader(v, Access);
+
+ Variable AccessHasOccurredVariable = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, Access);
+ Variable AccessOffsetXVariable = GPUVerifier.MakeOffsetVariable(v.Name, Access);
+
+ Variable PredicateParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_P", Microsoft.Boogie.Type.Bool));
+
+ Debug.Assert(v.TypedIdent.Type is MapType);
+ MapType mt = v.TypedIdent.Type as MapType;
+ Debug.Assert(mt.Arguments.Length == 1);
+ Variable OffsetParameter = new LocalVariable(v.tok, new TypedIdent(v.tok, "_offset", mt.Arguments[0]));
+ Debug.Assert(!(mt.Result is MapType));
+
+ if (Access.Equals("READ")) {
+ // Check read by thread 2 does not conflict with write by thread 1
+ Variable WriteHasOccurredVariable = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "WRITE");
+ Variable WriteOffsetVariable = GPUVerifier.MakeOffsetVariable(v.Name, "WRITE");
+ Expr WriteReadGuard = new IdentifierExpr(Token.NoToken, VariableForThread(2, PredicateParameter));
+ WriteReadGuard = Expr.And(WriteReadGuard, new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteHasOccurredVariable)));
+ WriteReadGuard = Expr.And(WriteReadGuard, Expr.Eq(new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteOffsetVariable)),
+ new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter))));
+
+ if (!verifier.ArrayModelledAdversarially(v)) {
+ WriteReadGuard = Expr.And(WriteReadGuard, Expr.Neq(
+ new VariableDualiser(1, null, null).VisitExpr(
+ MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, WriteOffsetVariable), "WRITE")),
+ new VariableDualiser(2, null, null).VisitExpr(
+ MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, OffsetParameter), "READ"))
+ ));
+ }
+
+ if (verifier.KernelArrayInfo.getGroupSharedArrays().Contains(v)) {
+ WriteReadGuard = Expr.And(WriteReadGuard, GPUVerifier.ThreadsInSameGroup());
+ }
+
+ WriteReadGuard = Expr.Not(WriteReadGuard);
+
+ Requires NoWriteReadRaceRequires = new Requires(false, WriteReadGuard);
+ QKeyValue kv = new QKeyValue(Token.NoToken, "write_read", new List<object>(), null);
+ NoWriteReadRaceRequires.Attributes = new QKeyValue(Token.NoToken, "race", new List<object>(), kv);
+ CheckAccessProcedure.Requires.Add(NoWriteReadRaceRequires);
+ }
+ else {
+ Debug.Assert(Access.Equals("WRITE"));
+
+ // Check write by thread 2 does not conflict with write by thread 1
+ Variable WriteHasOccurredVariable = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "WRITE");
+ Variable WriteOffsetVariable = GPUVerifier.MakeOffsetVariable(v.Name, "WRITE");
+
+ Expr WriteWriteGuard = new IdentifierExpr(Token.NoToken, VariableForThread(2, PredicateParameter));
+ WriteWriteGuard = Expr.And(WriteWriteGuard, new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteHasOccurredVariable)));
+ WriteWriteGuard = Expr.And(WriteWriteGuard, Expr.Eq(new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteOffsetVariable)),
+ new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter))));
+ if (!verifier.ArrayModelledAdversarially(v)) {
+ WriteWriteGuard = Expr.And(WriteWriteGuard, Expr.Neq(
+ new VariableDualiser(1, null, null).VisitExpr(
+ MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, WriteOffsetVariable), "WRITE")),
+ new VariableDualiser(2, null, null).VisitExpr(
+ MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, OffsetParameter), "WRITE"))
+ ));
+ }
+
+ if (verifier.KernelArrayInfo.getGroupSharedArrays().Contains(v)) {
+ WriteWriteGuard = Expr.And(WriteWriteGuard, GPUVerifier.ThreadsInSameGroup());
+ }
+
+ WriteWriteGuard = Expr.Not(WriteWriteGuard);
+ Requires NoWriteWriteRaceRequires = new Requires(false, WriteWriteGuard);
+ QKeyValue kv = new QKeyValue(Token.NoToken, "write_write", new List<object>(), null);
+ NoWriteWriteRaceRequires.Attributes = new QKeyValue(Token.NoToken, "race", new List<object>(), kv);
+ CheckAccessProcedure.Requires.Add(NoWriteWriteRaceRequires);
+
+ // Check write by thread 2 does not conflict with read by thread 1
+ Variable ReadHasOccurredVariable = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "READ");
+ Variable ReadOffsetVariable = GPUVerifier.MakeOffsetVariable(v.Name, "READ");
+
+ Expr ReadWriteGuard = new IdentifierExpr(Token.NoToken, VariableForThread(2, PredicateParameter));
+ ReadWriteGuard = Expr.And(ReadWriteGuard, new IdentifierExpr(Token.NoToken, VariableForThread(1, ReadHasOccurredVariable)));
+ ReadWriteGuard = Expr.And(ReadWriteGuard, Expr.Eq(new IdentifierExpr(Token.NoToken, VariableForThread(1, ReadOffsetVariable)),
+ new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter))));
+ if (!verifier.ArrayModelledAdversarially(v)) {
+ ReadWriteGuard = Expr.And(ReadWriteGuard, Expr.Neq(
+ new VariableDualiser(1, null, null).VisitExpr(
+ MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, ReadOffsetVariable), "WRITE")),
+ new VariableDualiser(2, null, null).VisitExpr(
+ MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, OffsetParameter), "READ"))
+ ));
+ }
+
+ if (verifier.KernelArrayInfo.getGroupSharedArrays().Contains(v)) {
+ ReadWriteGuard = Expr.And(ReadWriteGuard, GPUVerifier.ThreadsInSameGroup());
+ }
+
+ ReadWriteGuard = Expr.Not(ReadWriteGuard);
+ Requires NoReadWriteRaceRequires = new Requires(false, ReadWriteGuard);
+ kv = new QKeyValue(Token.NoToken, "read_write", new List<object>(), null);
+ NoReadWriteRaceRequires.Attributes = new QKeyValue(Token.NoToken, "race", new List<object>(), kv);
+ CheckAccessProcedure.Requires.Add(NoReadWriteRaceRequires);
+
+ }
+ verifier.Program.TopLevelDeclarations.Add(CheckAccessProcedure);
+ }
+
+
+
+ private Variable VariableForThread(int thread, Variable v) {
+ return new VariableDualiser(thread, null, null).VisitVariable(v.Clone() as Variable);
+ }
+
+ protected void AddLogRaceDeclarations(Variable v, String ReadOrWrite) {
+ verifier.FindOrCreateAccessHasOccurredVariable(v.Name, ReadOrWrite);
+
+ Debug.Assert(v.TypedIdent.Type is MapType);
+ MapType mt = v.TypedIdent.Type as MapType;
+ Debug.Assert(mt.Arguments.Length == 1);
+
+ verifier.FindOrCreateOffsetVariable(v.Name, ReadOrWrite);
+ verifier.FindOrCreateSourceVariable(v.Name, ReadOrWrite);
+
+ }
+
+
+ private static AssignCmd MakeConditionalAssignment(Variable lhs, Expr condition, Expr rhs) {
+ List<AssignLhs> lhss = new List<AssignLhs>();
+ List<Expr> rhss = new List<Expr>();
+ lhss.Add(new SimpleAssignLhs(lhs.tok, new IdentifierExpr(lhs.tok, lhs)));
+ rhss.Add(new NAryExpr(rhs.tok, new IfThenElse(rhs.tok), new ExprSeq(new Expr[] { condition, rhs, new IdentifierExpr(lhs.tok, lhs) })));
+ return new AssignCmd(lhs.tok, lhss, rhss);
+ }
+
+ private Expr MakeAccessedIndex(Variable v, Expr offsetExpr, string AccessType) {
+ Expr result = new IdentifierExpr(v.tok, v.Clone() as Variable);
+ Debug.Assert(v.TypedIdent.Type is MapType);
+ MapType mt = v.TypedIdent.Type as MapType;
+ Debug.Assert(mt.Arguments.Length == 1);
+
+ result = Expr.Select(result,
+ new Expr[] { offsetExpr });
+ Debug.Assert(!(mt.Result is MapType));
+ return result;
+ }
+
+ protected void AddRequiresNoPendingAccess(Variable v) {
+ IdentifierExpr ReadAccessOccurred1 = new IdentifierExpr(v.tok, new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "READ")));
+ IdentifierExpr WriteAccessOccurred1 = new IdentifierExpr(v.tok, new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "WRITE")));
+
+ verifier.KernelProcedure.Requires.Add(new Requires(false, Expr.And(Expr.Not(ReadAccessOccurred1), Expr.Not(WriteAccessOccurred1))));
+ }
+
+ private void AddRequiresSourceAccessZero(Variable v)
+ {
+ verifier.KernelProcedure.Requires.Add(new Requires(false, Expr.Eq(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateSourceVariable(v.Name, "READ")),
+ GPUVerifier.ZeroBV())));
+ verifier.KernelProcedure.Requires.Add(new Requires(false, Expr.Eq(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateSourceVariable(v.Name, "WRITE")),
+ GPUVerifier.ZeroBV())));
+ }
+
+ public void AddSourceLocationLoopInvariants(Implementation impl, IRegion region)
+ {
+ foreach (string key in WriteAccessSourceLocations.Keys.Union(ReadAccessSourceLocations.Keys))
+ {
+ region.AddInvariant(BuildNoAccessInvariant(key, "WRITE"));
+ region.AddInvariant(BuildNoAccessInvariant(key, "READ"));
+
+ if (WriteAccessSourceLocations.ContainsKey(key))
+ {
+ region.AddInvariant(BuildPossibleSourceLocationsInvariant(key, "WRITE"));
+ }
+ else
+ {
+ region.AddInvariant(BuildAccessOccurredFalseInvariant(key, "WRITE"));
+ }
+
+ if (ReadAccessSourceLocations.ContainsKey(key))
+ {
+ region.AddInvariant(BuildPossibleSourceLocationsInvariant(key, "READ"));
+ }
+ else
+ {
+ region.AddInvariant(BuildAccessOccurredFalseInvariant(key, "READ"));
+ }
+ }
+ }
+
+ public void AddStandardSourceVariablePreconditions()
+ {
+ foreach (Declaration D in verifier.Program.TopLevelDeclarations.ToList())
+ {
+ if (!(D is Procedure))
+ {
+ continue;
+ }
+ Procedure Proc = D as Procedure;
+ foreach (string key in WriteAccessSourceLocations.Keys.Union(ReadAccessSourceLocations.Keys))
+ {
+ Proc.Requires.Add(new Requires(false, BuildNoAccessExpr(key, "WRITE")));
+ Proc.Requires.Add(new Requires(false, BuildNoAccessExpr(key, "READ")));
+
+ if (WriteAccessSourceLocations.ContainsKey(key))
+ {
+ Proc.Requires.Add(new Requires(false, BuildPossibleSourceLocationsExpr(key, "WRITE")));
+ }
+ else
+ {
+ Proc.Requires.Add(new Requires(false, BuildAccessOccurredFalseExpr(key, "WRITE")));
+ }
+
+ if (ReadAccessSourceLocations.ContainsKey(key))
+ {
+ Proc.Requires.Add(new Requires(false, BuildPossibleSourceLocationsExpr(key, "READ")));
+ }
+ else
+ {
+ Proc.Requires.Add(new Requires(false, BuildAccessOccurredFalseExpr(key, "READ")));
+ }
+ }
+ }
+ }
+
+ public void AddStandardSourceVariablePostconditions()
+ {
+ foreach (Declaration D in verifier.Program.TopLevelDeclarations.ToList())
+ {
+ if (!(D is Procedure))
+ {
+ continue;
+ }
+ Procedure Proc = D as Procedure;
+ foreach (string key in WriteAccessSourceLocations.Keys.Union(ReadAccessSourceLocations.Keys))
+ {
+ Proc.Ensures.Add(new Ensures(false, BuildNoAccessExpr(key, "WRITE")));
+ Proc.Ensures.Add(new Ensures(false, BuildNoAccessExpr(key, "READ")));
+
+ if (WriteAccessSourceLocations.ContainsKey(key))
+ {
+ Proc.Ensures.Add(new Ensures(false, BuildPossibleSourceLocationsExpr(key, "WRITE")));
+ }
+ else
+ {
+ Proc.Ensures.Add(new Ensures(false, BuildAccessOccurredFalseExpr(key, "WRITE")));
+ }
+
+ if (ReadAccessSourceLocations.ContainsKey(key))
+ {
+ Proc.Ensures.Add(new Ensures(false, BuildPossibleSourceLocationsExpr(key, "READ")));
+ }
+ else
+ {
+ Proc.Ensures.Add(new Ensures(false, BuildAccessOccurredFalseExpr(key, "READ")));
+ }
+ }
+ }
+ }
+
+ private Expr BuildAccessOccurredFalseExpr(string name, string AccessType)
+ {
+ return Expr.Imp(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateAccessHasOccurredVariable(name, AccessType)),
+ Expr.False);
+ }
+
+ private AssertCmd BuildAccessOccurredFalseInvariant(string name, string AccessType)
+ {
+ return new AssertCmd(Token.NoToken, BuildAccessOccurredFalseExpr(name, AccessType));
+ }
+
+ private Expr BuildNoAccessExpr(string name, string AccessType)
+ {
+ return Expr.Imp(Expr.Not(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateAccessHasOccurredVariable(name, AccessType))),
+ Expr.Eq(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateSourceVariable(name, AccessType)),
+ new LiteralExpr(Token.NoToken, BigNum.FromInt(0), 32)));
+ }
+
+ private AssertCmd BuildNoAccessInvariant(string name, string AccessType)
+ {
+ return new AssertCmd(Token.NoToken, BuildNoAccessExpr(name, AccessType));
+ }
+
+ private Expr BuildPossibleSourceLocationsExpr(string name, string AccessType)
+ {
+ return Expr.Imp(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateAccessHasOccurredVariable(name, AccessType)),
+ BuildDisjunctionFromAccessSourceLocations(name, AccessType));
+ }
+
+ private AssertCmd BuildPossibleSourceLocationsInvariant(string name, string AccessType)
+ {
+ return new AssertCmd(Token.NoToken, BuildPossibleSourceLocationsExpr(name, AccessType));
+ }
+
+ private Expr BuildDisjunctionFromAccessSourceLocations(string key, string AccessType)
+ {
+ List<Expr> sourceLocExprs = new List<Expr>();
+ Dictionary<string, List<int>> AccessSourceLocations = (AccessType.Equals("WRITE")) ? WriteAccessSourceLocations : ReadAccessSourceLocations;
+ foreach (int loc in AccessSourceLocations[key])
+ {
+ sourceLocExprs.Add(Expr.Eq(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateSourceVariable(key, AccessType)),
+ new LiteralExpr(Token.NoToken, BigNum.FromInt(loc), 32)));
+ }
+ return sourceLocExprs.Aggregate(Expr.Or);
+ }
+
+ protected Expr NoReadOrWriteExpr(Variable v, string ReadOrWrite, string OneOrTwo) {
+ Variable ReadOrWriteHasOccurred = GPUVerifier.MakeAccessHasOccurredVariable(v.Name, ReadOrWrite);
+ ReadOrWriteHasOccurred.Name = ReadOrWriteHasOccurred.Name + "$" + OneOrTwo;
+ ReadOrWriteHasOccurred.TypedIdent.Name = ReadOrWriteHasOccurred.TypedIdent.Name + "$" + OneOrTwo;
+ Expr expr = Expr.Not(new IdentifierExpr(v.tok, ReadOrWriteHasOccurred));
+ return expr;
+ }
+
+
+ protected void AddOffsetsSatisfyPredicatesCandidateInvariant(IRegion region, Variable v, string ReadOrWrite, List<Expr> preds) {
+ if (preds.Count != 0) {
+ Expr expr = AccessedOffsetsSatisfyPredicatesExpr(v, preds, ReadOrWrite, 1);
+ verifier.AddCandidateInvariant(region, expr, "accessed offsets satisfy predicates");
+ }
+ }
+
+ private Expr AccessedOffsetsSatisfyPredicatesExpr(Variable v, IEnumerable<Expr> offsets, string ReadOrWrite, int Thread) {
+ return Expr.Imp(
+ new IdentifierExpr(Token.NoToken, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, ReadOrWrite))),
+ offsets.Aggregate(Expr.Or));
+ }
+
+ private Expr AccessedOffsetIsThreadLocalIdExpr(Variable v, string ReadOrWrite, int Thread) {
+ return Expr.Imp(
+ new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, ReadOrWrite))),
+ Expr.Eq(new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeOffsetVariable(v.Name, ReadOrWrite))), new IdentifierExpr(v.tok, verifier.MakeThreadId(v.tok, "X", Thread))));
+ }
+
+ private Expr GlobalIdExpr(string dimension, int Thread) {
+ return new VariableDualiser(Thread, null, null).VisitExpr(verifier.GlobalIdExpr(dimension).Clone() as Expr);
+ }
+
+ protected void AddAccessedOffsetInRangeCTimesLocalIdToCTimesLocalIdPlusC(IRegion region, Variable v, Expr constant, string ReadOrWrite) {
+ Expr expr = MakeCTimesLocalIdRangeExpression(v, constant, ReadOrWrite, 1);
+ verifier.AddCandidateInvariant(region,
+ expr, "accessed offset in range [ C*local_id, (C+1)*local_id )");
+ }
+
+ private Expr MakeCTimesLocalIdRangeExpression(Variable v, Expr constant, string ReadOrWrite, int Thread) {
+ Expr CTimesLocalId = verifier.MakeBVMul(constant.Clone() as Expr,
+ new IdentifierExpr(Token.NoToken, verifier.MakeThreadId(Token.NoToken, "X", Thread)));
+
+ Expr CTimesLocalIdPlusC = verifier.MakeBVAdd(verifier.MakeBVMul(constant.Clone() as Expr,
+ new IdentifierExpr(Token.NoToken, verifier.MakeThreadId(Token.NoToken, "X", Thread))), constant.Clone() as Expr);
+
+ Expr CTimesLocalIdLeqAccessedOffset = GPUVerifier.MakeBitVectorBinaryBoolean("BV32_LEQ", CTimesLocalId, OffsetXExpr(v, ReadOrWrite, Thread));
+
+ Expr AccessedOffsetLtCTimesLocalIdPlusC = verifier.MakeBVSlt(OffsetXExpr(v, ReadOrWrite, Thread), CTimesLocalIdPlusC);
+
+ return Expr.Imp(
+ AccessHasOccurred(v, ReadOrWrite, Thread),
+ Expr.And(CTimesLocalIdLeqAccessedOffset, AccessedOffsetLtCTimesLocalIdPlusC));
+ }
+
+ private static IdentifierExpr AccessHasOccurred(Variable v, string ReadOrWrite, int Thread) {
+ return new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, ReadOrWrite)));
+ }
+
+ private static IdentifierExpr OffsetXExpr(Variable v, string ReadOrWrite, int Thread) {
+ return new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeOffsetVariable(v.Name, ReadOrWrite)));
+ }
+
+ protected void AddAccessedOffsetInRangeCTimesGlobalIdToCTimesGlobalIdPlusC(IRegion region, Variable v, Expr constant, string ReadOrWrite) {
+ Expr expr = MakeCTimesGloalIdRangeExpr(v, constant, ReadOrWrite, 1);
+ verifier.AddCandidateInvariant(region,
+ expr, "accessed offset in range [ C*global_id, (C+1)*global_id )");
+ }
+
+ private Expr MakeCTimesGloalIdRangeExpr(Variable v, Expr constant, string ReadOrWrite, int Thread) {
+ Expr CTimesGlobalId = verifier.MakeBVMul(constant.Clone() as Expr,
+ GlobalIdExpr("X", Thread));
+
+ Expr CTimesGlobalIdPlusC = verifier.MakeBVAdd(verifier.MakeBVMul(constant.Clone() as Expr,
+ GlobalIdExpr("X", Thread)), constant.Clone() as Expr);
+
+ Expr CTimesGlobalIdLeqAccessedOffset = GPUVerifier.MakeBitVectorBinaryBoolean("BV32_LEQ", CTimesGlobalId, OffsetXExpr(v, ReadOrWrite, Thread));
+
+ Expr AccessedOffsetLtCTimesGlobalIdPlusC = verifier.MakeBVSlt(OffsetXExpr(v, ReadOrWrite, Thread), CTimesGlobalIdPlusC);
+
+ Expr implication = Expr.Imp(
+ AccessHasOccurred(v, ReadOrWrite, Thread),
+ Expr.And(CTimesGlobalIdLeqAccessedOffset, AccessedOffsetLtCTimesGlobalIdPlusC));
+ return implication;
+ }
+
+ private void writeSourceLocToFile(QKeyValue kv, string path) {
+ TextWriter tw = new StreamWriter(path, true);
+ tw.Write("\n" + QKeyValue.FindIntAttribute(SourceLocationAttributes, "line", -1)
+ + "#" + QKeyValue.FindIntAttribute(SourceLocationAttributes, "col", -1)
+ + "#" + QKeyValue.FindStringAttribute(SourceLocationAttributes, "fname")
+ + "#" + QKeyValue.FindStringAttribute(SourceLocationAttributes, "dir"));
+ tw.Close();
+ }
+
+ protected void AddAccessedOffsetIsThreadLocalIdCandidateRequires(Procedure Proc, Variable v, string ReadOrWrite, int Thread) {
+ verifier.AddCandidateRequires(Proc, AccessedOffsetIsThreadLocalIdExpr(v, ReadOrWrite, Thread));
+ }
+
+ protected void AddAccessedOffsetIsThreadLocalIdCandidateEnsures(Procedure Proc, Variable v, string ReadOrWrite, int Thread) {
+ verifier.AddCandidateEnsures(Proc, AccessedOffsetIsThreadLocalIdExpr(v, ReadOrWrite, Thread));
+ }
+
+
+
+ }
+
+
+
+ class FindReferencesToNamedVariableVisitor : StandardVisitor {
+ internal bool found = false;
+ private string name;
+
+ internal FindReferencesToNamedVariableVisitor(string name) {
+ this.name = name;
+ }
+
+ public override Variable VisitVariable(Variable node) {
+ if (GPUVerifier.StripThreadIdentifier(node.Name).Equals(name)) {
+ found = true;
+ }
+ return base.VisitVariable(node);
+ }
+ }
+
+
+
+}
diff --git a/Source/GPUVerify/ReadCollector.cs b/Source/GPUVerify/ReadCollector.cs
index c569b97e..6a94df73 100644
--- a/Source/GPUVerify/ReadCollector.cs
+++ b/Source/GPUVerify/ReadCollector.cs
@@ -36,56 +36,14 @@ namespace GPUVerify
MultiDimensionalMapError();
}
- Variable ReadVariable = null;
- Expr IndexX = node.Args[1];
- Expr IndexY = null;
- Expr IndexZ = null;
-
- if (node.Args[0] is NAryExpr)
- {
- NAryExpr nestedMap = node.Args[0] as NAryExpr;
- Debug.Assert(nestedMap.Fun is MapSelect);
- if ((nestedMap.Fun as MapSelect).Arity > 1)
- {
- MultiDimensionalMapError();
- }
- IndexY = nestedMap.Args[1];
- if (nestedMap.Args[0] is NAryExpr)
- {
- NAryExpr nestedNestedMap = nestedMap.Args[0] as NAryExpr;
- Debug.Assert(nestedNestedMap.Fun is MapSelect);
- if ((nestedNestedMap.Fun as MapSelect).Arity > 1)
- {
- MultiDimensionalMapError();
- }
- IndexZ = nestedMap.Args[1];
- if (!(nestedNestedMap.Args[0] is IdentifierExpr))
- {
- Console.WriteLine("*** Error - maps with more than three levels of nesting are not supported");
- Environment.Exit(1);
- }
- ReadVariable = (nestedNestedMap.Args[0] as IdentifierExpr).Decl;
- this.VisitExpr(nestedNestedMap.Args[1]);
- }
- else
- {
- Debug.Assert(nestedMap.Args[0] is IdentifierExpr);
- ReadVariable = (nestedMap.Args[0] as IdentifierExpr).Decl;
- }
- this.VisitExpr(nestedMap.Args[1]);
-
- }
- else
- {
- Debug.Assert(node.Args[0] is IdentifierExpr);
- ReadVariable = (node.Args[0] as IdentifierExpr).Decl;
- }
+ Debug.Assert(node.Args[0] is IdentifierExpr);
+ var ReadVariable = (node.Args[0] as IdentifierExpr).Decl;
+ var Index = node.Args[1];
this.VisitExpr(node.Args[1]);
-
if (NonLocalState.Contains(ReadVariable))
{
- accesses.Add(new AccessRecord(ReadVariable, IndexZ, IndexY, IndexX));
+ accesses.Add(new AccessRecord(ReadVariable, Index));
}
return node;
@@ -97,19 +55,5 @@ namespace GPUVerify
}
-
- public override Variable VisitVariable(Variable node)
- {
- if (!NonLocalState.Contains(node))
- {
- return node;
- }
-
- accesses.Add(new AccessRecord(node, null, null, null));
-
- return node;
- }
-
-
}
}
diff --git a/Source/GPUVerify/StrideConstraint.cs b/Source/GPUVerify/StrideConstraint.cs
index 948786b7..da970365 100644
--- a/Source/GPUVerify/StrideConstraint.cs
+++ b/Source/GPUVerify/StrideConstraint.cs
@@ -99,7 +99,7 @@ class StrideConstraint {
var ie = e as IdentifierExpr;
if (ie != null) {
- if (ie.Decl is Constant)
+ if(GPUVerifier.IsConstantInCurrentRegion(ie))
return new EqStrideConstraint(e);
var rsa = verifier.reducedStrengthAnalyses[impl];
diff --git a/Source/GPUVerify/UniformExpressionAnalysisVisitor.cs b/Source/GPUVerify/UniformExpressionAnalysisVisitor.cs
deleted file mode 100644
index 76f6b5de..00000000
--- a/Source/GPUVerify/UniformExpressionAnalysisVisitor.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.Boogie;
-
-namespace GPUVerify
-{
- class UniformExpressionAnalysisVisitor : StandardVisitor
- {
-
- private bool isUniform = true;
- private Dictionary<string, bool> uniformityInfo;
-
- public UniformExpressionAnalysisVisitor(Dictionary<string, bool> uniformityInfo)
- {
- this.uniformityInfo = uniformityInfo;
- }
-
- public override Variable VisitVariable(Variable v)
- {
- if (!uniformityInfo.ContainsKey(v.Name))
- {
- isUniform = isUniform && (v is Constant);
- }
- else if (!uniformityInfo[v.Name])
- {
- isUniform = false;
- }
-
- return v;
- }
-
- internal bool IsUniform()
- {
- return isUniform;
- }
- }
-}
diff --git a/Source/GPUVerify/VariableDefinitionAnalysis.cs b/Source/GPUVerify/VariableDefinitionAnalysis.cs
index ded3fb7a..824c1b17 100644
--- a/Source/GPUVerify/VariableDefinitionAnalysis.cs
+++ b/Source/GPUVerify/VariableDefinitionAnalysis.cs
@@ -2,6 +2,7 @@ using System;
using Microsoft.Boogie;
using System.Collections.Generic;
using System.Linq;
+using System.Diagnostics;
namespace GPUVerify {
@@ -43,7 +44,7 @@ class VariableDefinitionAnalysis {
}
public override Expr VisitIdentifierExpr(IdentifierExpr expr) {
- if (expr.Decl is Constant)
+ if (GPUVerifier.IsConstantInCurrentRegion(expr))
return expr;
if (!analysis.defMap.ContainsKey(expr.Decl) || !analysis.defMap[expr.Decl].Item2)
isDerivedFromConstants = false;
@@ -101,8 +102,8 @@ class VariableDefinitionAnalysis {
}
if (c is HavocCmd) {
var hCmd = (HavocCmd)c;
- foreach (Variable v in hCmd.Vars)
- UpdateDefMap(v, null, false);
+ foreach (IdentifierExpr iExpr in hCmd.Vars)
+ UpdateDefMap(iExpr.Decl, null, false);
}
}
} while (changed);
@@ -117,7 +118,7 @@ class VariableDefinitionAnalysis {
}
public override Expr VisitIdentifierExpr(IdentifierExpr expr) {
- if (expr.Decl is Constant)
+ if (GPUVerifier.IsConstantInCurrentRegion(expr))
return expr;
var def = analysis.BuildNamedDefFor(expr.Decl, expr);
if (def == null)
@@ -178,7 +179,7 @@ class VariableDefinitionAnalysis {
}
public override Expr VisitIdentifierExpr(IdentifierExpr expr) {
- if (expr.Decl is Constant)
+ if (GPUVerifier.IsConstantInCurrentRegion(expr))
return expr;
int id;
var varName = GPUVerifier.StripThreadIdentifier(expr.Decl.Name, out id);
diff --git a/Source/GPUVerify/VariableDualiser.cs b/Source/GPUVerify/VariableDualiser.cs
index 6e375945..ce5f78ee 100644
--- a/Source/GPUVerify/VariableDualiser.cs
+++ b/Source/GPUVerify/VariableDualiser.cs
@@ -10,6 +10,9 @@ namespace GPUVerify
{
class VariableDualiser : Duplicator
{
+ static HashSet<string> otherFunctionNames =
+ new HashSet<string>(new string[] { "__other_bool", "__other_bv32", "__other_arrayId" });
+
private int id;
private UniformityAnalyser uniformityAnalyser;
private string procName;
@@ -26,33 +29,43 @@ namespace GPUVerify
public override Expr VisitIdentifierExpr(IdentifierExpr node)
{
- if (!(node.Decl is Constant))
- {
- return new IdentifierExpr(node.tok, new LocalVariable(node.tok, DualiseTypedIdent(node.Decl)));
- }
-
- if (GPUVerifier.IsThreadLocalIdConstant(node.Decl))
- {
- return new IdentifierExpr(node.tok, new Constant(node.tok, DualiseTypedIdent(node.Decl)));
- }
-
- if (GPUVerifier.IsGroupIdConstant(node.Decl))
- {
- return new IdentifierExpr(node.tok, new Constant(node.tok, DualiseTypedIdent(node.Decl)));
- }
-
- return node;
+ if (node.Decl is Formal) {
+ return new IdentifierExpr(node.tok, new Formal(node.tok, DualiseTypedIdent(node.Decl),
+ (node.Decl as Formal).InComing));
+ }
+
+ if (!(node.Decl is Constant))
+ {
+ return new IdentifierExpr(node.tok, new LocalVariable(node.tok, DualiseTypedIdent(node.Decl)));
+ }
+
+ if (GPUVerifier.IsThreadLocalIdConstant(node.Decl))
+ {
+ return new IdentifierExpr(node.tok, new Constant(node.tok, DualiseTypedIdent(node.Decl)));
+ }
+
+ if (GPUVerifier.IsGroupIdConstant(node.Decl))
+ {
+ return new IdentifierExpr(node.tok, new Constant(node.tok, DualiseTypedIdent(node.Decl)));
+ }
+
+ return node;
}
private TypedIdent DualiseTypedIdent(Variable v)
{
+ if (QKeyValue.FindBoolAttribute(v.Attributes, "global") ||
+ QKeyValue.FindBoolAttribute(v.Attributes, "group_shared")) {
+ return new TypedIdent(v.tok, v.Name, v.TypedIdent.Type);
+ }
- if (uniformityAnalyser == null || !uniformityAnalyser.IsUniform(procName, v.Name))
- {
- return new TypedIdent(v.tok, v.Name + "$" + id, v.TypedIdent.Type);
- }
-
+ if (uniformityAnalyser != null && uniformityAnalyser.IsUniform(procName, v.Name))
+ {
return new TypedIdent(v.tok, v.Name, v.TypedIdent.Type);
+ }
+
+ return new TypedIdent(v.tok, v.Name + "$" + id, v.TypedIdent.Type);
+
}
public override Variable VisitVariable(Variable node)
@@ -71,26 +84,50 @@ namespace GPUVerify
public override Expr VisitNAryExpr(NAryExpr node)
{
- // The point of this override is to avoid dualisation of certain special
- // intrinsics that are cross-thread
+ if (node.Fun is MapSelect) {
+ Debug.Assert((node.Fun as MapSelect).Arity == 1);
+ Debug.Assert(node.Args[0] is IdentifierExpr);
+ var v = (node.Args[0] as IdentifierExpr).Decl;
+ if (QKeyValue.FindBoolAttribute(v.Attributes, "group_shared")) {
+ return new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1),
+ new ExprSeq(new Expr[] { new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1),
+ new ExprSeq(new Expr[] { node.Args[0], GroupSharedIndexingExpr() })), VisitExpr(node.Args[1]) }));
+ }
+ }
+
+ // Avoid dualisation of certain special builtin functions that are cross-thread
+ if (node.Fun is FunctionCall)
+ {
+ FunctionCall call = node.Fun as FunctionCall;
- if (node.Fun is FunctionCall)
+ if (otherFunctionNames.Contains(call.Func.Name))
{
- FunctionCall call = node.Fun as FunctionCall;
+ Debug.Assert(id == 1 || id == 2);
+ int otherId = id == 1 ? 2 : 1;
+ return new VariableDualiser(otherId, uniformityAnalyser, procName).VisitExpr(
+ node.Args[0]);
+ }
- if (call.Func.Name.Equals("__other_bool") || call.Func.Name.Equals("__other_bv32"))
- {
- Debug.Assert(id == 1 || id == 2);
- int otherId = id == 1 ? 2 : 1;
- return new VariableDualiser(otherId, uniformityAnalyser, procName).VisitExpr(
- node.Args[0]);
- }
+ }
+
+ return base.VisitNAryExpr(node);
+ }
- }
- return base.VisitNAryExpr(node);
+ public override AssignLhs VisitMapAssignLhs(MapAssignLhs node) {
+
+ var v = node.DeepAssignedVariable;
+ if(QKeyValue.FindBoolAttribute(v.Attributes, "group_shared")) {
+ return new MapAssignLhs(Token.NoToken, new MapAssignLhs(Token.NoToken, node.Map,
+ new List<Expr>(new Expr[] { GroupSharedIndexingExpr() })), node.Indexes.Select(idx => this.VisitExpr(idx)).ToList());
+
+ }
+ return base.VisitMapAssignLhs(node);
}
+ private Expr GroupSharedIndexingExpr() {
+ return id == 1 ? Expr.True : GPUVerifier.ThreadsInSameGroup();
+ }
}
diff --git a/Source/GPUVerify/WriteCollector.cs b/Source/GPUVerify/WriteCollector.cs
index 00ca63c5..f9633092 100644
--- a/Source/GPUVerify/WriteCollector.cs
+++ b/Source/GPUVerify/WriteCollector.cs
@@ -18,16 +18,6 @@ namespace GPUVerify
{
}
- public override AssignLhs VisitSimpleAssignLhs(SimpleAssignLhs node)
- {
- Debug.Assert(NoWrittenVariable());
- if (NonLocalState.Contains(node.DeepAssignedVariable))
- {
- access = new AccessRecord(node.DeepAssignedVariable, null, null, null);
- }
- return node;
- }
-
private bool NoWrittenVariable()
{
return access == null;
@@ -44,42 +34,12 @@ namespace GPUVerify
Variable WrittenVariable = node.DeepAssignedVariable;
- MapAssignLhs MapAssignX = node;
+ CheckMapIndex(node);
+ Debug.Assert(!(node.Map is MapAssignLhs));
- CheckMapIndex(MapAssignX);
- Expr IndexX = MapAssignX.Indexes[0];
- Expr IndexY = null;
- Expr IndexZ = null;
+ access = new AccessRecord(WrittenVariable, node.Indexes[0]);
- if (MapAssignX.Map is MapAssignLhs)
- {
- MapAssignLhs MapAssignY = MapAssignX.Map as MapAssignLhs;
- CheckMapIndex(MapAssignY);
- IndexY = MapAssignY.Indexes[0];
- if (MapAssignY.Map is MapAssignLhs)
- {
- MapAssignLhs MapAssignZ = MapAssignY.Map as MapAssignLhs;
- CheckMapIndex(MapAssignZ);
- IndexZ = MapAssignZ.Indexes[0];
- if (!(MapAssignZ.Map is SimpleAssignLhs))
- {
- Console.WriteLine("*** Error - maps with more than three levels of nesting are not supported");
- Environment.Exit(1);
- }
- }
- else
- {
- Debug.Assert(MapAssignY.Map is SimpleAssignLhs);
- }
- }
- else
- {
- Debug.Assert(MapAssignX.Map is SimpleAssignLhs);
- }
-
- access = new AccessRecord(WrittenVariable, IndexZ, IndexY, IndexX);
-
- return MapAssignX;
+ return node;
}
private void CheckMapIndex(MapAssignLhs node)
diff --git a/Source/GPUVerifyBoogieDriver/GPUVerifyBoogieDriver.cs b/Source/GPUVerifyBoogieDriver/GPUVerifyBoogieDriver.cs
new file mode 100644
index 00000000..25549f71
--- /dev/null
+++ b/Source/GPUVerifyBoogieDriver/GPUVerifyBoogieDriver.cs
@@ -0,0 +1,1486 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------
+// OnlyBoogie OnlyBoogie.ssc
+// - main program for taking a BPL program and verifying it
+//---------------------------------------------------------------------------------------------
+
+namespace Microsoft.Boogie
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text.RegularExpressions;
+ using PureCollections;
+ using Microsoft.Basetypes;
+ using Microsoft.Boogie;
+ using Microsoft.Boogie.AbstractInterpretation;
+ using System.Diagnostics.Contracts;
+ using System.Diagnostics;
+ using System.Linq;
+ using VC;
+ using AI = Microsoft.AbstractInterpretationFramework;
+ using BoogiePL = Microsoft.Boogie;
+
+ /*
+ The following assemblies are referenced because they are needed at runtime, not at compile time:
+ BaseTypes
+ Provers.Z3
+ System.Compiler.Framework
+ */
+
+ public class GPUVerifyBoogieDriver
+ {
+ // ------------------------------------------------------------------------
+ // Main
+
+ public static void Main(string[] args)
+ {
+ Contract.Requires(cce.NonNullElements(args));
+ CommandLineOptions.Install(new CommandLineOptions());
+
+ CommandLineOptions.Clo.RunningBoogieFromCommandLine = true;
+ if (!CommandLineOptions.Clo.Parse(args))
+ {
+ goto END;
+ }
+ if (CommandLineOptions.Clo.Files.Count == 0)
+ {
+ ErrorWriteLine("*** Error: No input files were specified.");
+ goto END;
+ }
+ if (CommandLineOptions.Clo.XmlSink != null)
+ {
+ string errMsg = CommandLineOptions.Clo.XmlSink.Open();
+ if (errMsg != null)
+ {
+ ErrorWriteLine("*** Error: " + errMsg);
+ goto END;
+ }
+ }
+ if (!CommandLineOptions.Clo.DontShowLogo)
+ {
+ Console.WriteLine(CommandLineOptions.Clo.Version);
+ }
+ if (CommandLineOptions.Clo.ShowEnv == CommandLineOptions.ShowEnvironment.Always)
+ {
+ Console.WriteLine("---Command arguments");
+ foreach (string arg in args)
+ {
+ Contract.Assert(arg != null);
+ Console.WriteLine(arg);
+ }
+
+ Console.WriteLine("--------------------");
+ }
+
+ Helpers.ExtraTraceInformation("Becoming sentient");
+
+ List<string> fileList = new List<string>();
+ foreach (string file in CommandLineOptions.Clo.Files)
+ {
+ string extension = Path.GetExtension(file);
+ if (extension != null)
+ {
+ extension = extension.ToLower();
+ }
+ if (extension == ".txt")
+ {
+ StreamReader stream = new StreamReader(file);
+ string s = stream.ReadToEnd();
+ fileList.AddRange(s.Split(new char[3] { ' ', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries));
+ }
+ else
+ {
+ fileList.Add(file);
+ }
+ }
+ foreach (string file in fileList)
+ {
+ Contract.Assert(file != null);
+ string extension = Path.GetExtension(file);
+ if (extension != null)
+ {
+ extension = extension.ToLower();
+ }
+ if (extension != ".bpl")
+ {
+ ErrorWriteLine("*** Error: '{0}': Filename extension '{1}' is not supported. Input files must be BoogiePL programs (.bpl).", file,
+ extension == null ? "" : extension);
+ goto END;
+ }
+ }
+ ProcessFiles(fileList);
+
+ END:
+ if (CommandLineOptions.Clo.XmlSink != null)
+ {
+ CommandLineOptions.Clo.XmlSink.Close();
+ }
+ if (CommandLineOptions.Clo.Wait)
+ {
+ Console.WriteLine("Press Enter to exit.");
+ Console.ReadLine();
+ }
+ }
+
+ public static void ErrorWriteLine(string s)
+ {
+ Contract.Requires(s != null);
+ ConsoleColor col = Console.ForegroundColor;
+ Console.ForegroundColor = ConsoleColor.DarkGray;
+ Console.WriteLine(s);
+ Console.ForegroundColor = col;
+ }
+
+ private static void ErrorWriteLine(string locInfo, string message, ErrorMsgType msgtype)
+ {
+ Contract.Requires(message != null);
+ ConsoleColor col = Console.ForegroundColor;
+ if (!String.IsNullOrEmpty(locInfo))
+ {
+ Console.Write(locInfo + " ");
+ }
+
+ switch (msgtype)
+ {
+ case ErrorMsgType.Error:
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.Write("error: ");
+ break;
+ case ErrorMsgType.Note:
+ Console.ForegroundColor = ConsoleColor.DarkYellow;
+ Console.Write("note: ");
+ break;
+ case ErrorMsgType.NoError:
+ default:
+ break;
+ }
+
+
+ Console.ForegroundColor = col;
+ Console.WriteLine(message);
+ }
+
+ public static void ErrorWriteLine(string format, params object[] args)
+ {
+ Contract.Requires(format != null);
+ string s = string.Format(format, args);
+ ErrorWriteLine(s);
+ }
+
+ public static void AdvisoryWriteLine(string format, params object[] args)
+ {
+ Contract.Requires(format != null);
+ ConsoleColor col = Console.ForegroundColor;
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine(format, args);
+ Console.ForegroundColor = col;
+ }
+
+ enum FileType
+ {
+ Unknown,
+ Cil,
+ Bpl,
+ Dafny
+ };
+
+ enum ErrorMsgType
+ {
+ Error,
+ Note,
+ NoError
+ };
+
+ enum RaceType
+ {
+ WW,
+ RW,
+ WR
+ };
+
+ static void ProcessFiles(List<string> fileNames)
+ {
+ Contract.Requires(cce.NonNullElements(fileNames));
+ using (XmlFileScope xf = new XmlFileScope(CommandLineOptions.Clo.XmlSink, fileNames[fileNames.Count - 1]))
+ {
+ //BoogiePL.Errors.count = 0;
+ Program program = ParseBoogieProgram(fileNames, false);
+ if (program == null)
+ return;
+ if (CommandLineOptions.Clo.PrintFile != null)
+ {
+ PrintBplFile(CommandLineOptions.Clo.PrintFile, program, false);
+ }
+
+ PipelineOutcome oc = ResolveAndTypecheck(program, fileNames[fileNames.Count - 1]);
+ if (oc != PipelineOutcome.ResolvedAndTypeChecked)
+ return;
+ //BoogiePL.Errors.count = 0;
+
+ // Do bitvector analysis
+ if (CommandLineOptions.Clo.DoBitVectorAnalysis)
+ {
+ Microsoft.Boogie.BitVectorAnalysis.DoBitVectorAnalysis(program);
+ PrintBplFile(CommandLineOptions.Clo.BitVectorAnalysisOutputBplFile, program, false);
+ return;
+ }
+
+ if (CommandLineOptions.Clo.PrintCFGPrefix != null)
+ {
+ foreach (var impl in program.TopLevelDeclarations.OfType<Implementation>())
+ {
+ using (StreamWriter sw = new StreamWriter(CommandLineOptions.Clo.PrintCFGPrefix + "." + impl.Name + ".dot"))
+ {
+ sw.Write(program.ProcessLoops(impl).ToDot());
+ }
+ }
+ }
+
+ EliminateDeadVariablesAndInline(program);
+
+ int errorCount, verified, inconclusives, timeOuts, outOfMemories;
+ oc = InferAndVerify(program, out errorCount, out verified, out inconclusives, out timeOuts, out outOfMemories);
+ switch (oc)
+ {
+ case PipelineOutcome.Done:
+ case PipelineOutcome.VerificationCompleted:
+ WriteTrailer(verified, errorCount, inconclusives, timeOuts, outOfMemories);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+
+ static void PrintBplFile(string filename, Program program, bool allowPrintDesugaring)
+ {
+ Contract.Requires(program != null);
+ Contract.Requires(filename != null);
+ bool oldPrintDesugaring = CommandLineOptions.Clo.PrintDesugarings;
+ if (!allowPrintDesugaring)
+ {
+ CommandLineOptions.Clo.PrintDesugarings = false;
+ }
+ using (TokenTextWriter writer = filename == "-" ?
+ new TokenTextWriter("<console>", Console.Out) :
+ new TokenTextWriter(filename))
+ {
+ if (CommandLineOptions.Clo.ShowEnv != CommandLineOptions.ShowEnvironment.Never)
+ {
+ writer.WriteLine("// " + CommandLineOptions.Clo.Version);
+ writer.WriteLine("// " + CommandLineOptions.Clo.Environment);
+ }
+ writer.WriteLine();
+ program.Emit(writer);
+ }
+ CommandLineOptions.Clo.PrintDesugarings = oldPrintDesugaring;
+ }
+
+
+ static bool ProgramHasDebugInfo(Program program)
+ {
+ Contract.Requires(program != null);
+ // We inspect the last declaration because the first comes from the prelude and therefore always has source context.
+ return program.TopLevelDeclarations.Count > 0 &&
+ ((cce.NonNull(program.TopLevelDeclarations)[program.TopLevelDeclarations.Count - 1]).tok.IsValid);
+ }
+
+ static QKeyValue GetAttributes(Absy a)
+ {
+ if (a is PredicateCmd)
+ {
+ return (a as PredicateCmd).Attributes;
+ }
+ else if (a is Requires)
+ {
+ return (a as Requires).Attributes;
+ }
+ else if (a is Ensures)
+ {
+ return (a as Ensures).Attributes;
+ }
+ else if (a is CallCmd)
+ {
+ return (a as CallCmd).Attributes;
+ }
+ //Debug.Assert(false);
+ return null;
+ }
+
+ /// <summary>
+ /// Inform the user about something and proceed with translation normally.
+ /// Print newline after the message.
+ /// </summary>
+ public static void Inform(string s)
+ {
+ if (!CommandLineOptions.Clo.Trace)
+ {
+ return;
+ }
+ Console.WriteLine(s);
+ }
+
+ private static void AddPadding(ref string string1, ref string string2)
+ {
+ if (string1.Length < string2.Length)
+ {
+ for (int i = (string2.Length - string1.Length); i > 0; --i)
+ {
+ string1 += " ";
+ }
+ }
+ else
+ {
+ for (int i = (string1.Length - string2.Length); i > 0; --i)
+ {
+ string2 += " ";
+ }
+ }
+ }
+
+ private static string TrimLeadingSpaces(string s1, int noOfSpaces)
+ {
+ if (String.IsNullOrWhiteSpace(s1))
+ {
+ return s1;
+ }
+
+ int index;
+ for (index = 0; (index + 1) < s1.Length && Char.IsWhiteSpace(s1[index]); ++index);
+ string returnString = s1.Substring(index);
+ for (int i = noOfSpaces; i > 0; --i)
+ {
+ returnString = " " + returnString;
+ }
+ return returnString;
+ }
+
+ static void WriteTrailer(int verified, int errors, int inconclusives, int timeOuts, int outOfMemories)
+ {
+ Contract.Requires(0 <= errors && 0 <= inconclusives && 0 <= timeOuts && 0 <= outOfMemories);
+ Console.WriteLine();
+ if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed)
+ {
+ Console.Write("{0} finished with {1} credible, {2} doomed{3}", "GPUVerify", verified, errors, errors == 1 ? "" : "s");
+ }
+ else
+ {
+ Console.Write("{0} finished with {1} verified, {2} error{3}", "GPUVerify", verified, errors, errors == 1 ? "" : "s");
+ }
+ if (inconclusives != 0)
+ {
+ Console.Write(", {0} inconclusive{1}", inconclusives, inconclusives == 1 ? "" : "s");
+ }
+ if (timeOuts != 0)
+ {
+ Console.Write(", {0} time out{1}", timeOuts, timeOuts == 1 ? "" : "s");
+ }
+ if (outOfMemories != 0)
+ {
+ Console.Write(", {0} out of memory", outOfMemories);
+ }
+ Console.WriteLine();
+ Console.Out.Flush();
+ }
+
+
+
+ static void ReportBplError(Absy node, string message, bool error, bool showBplLocation)
+ {
+ int failLine = -1, failCol = -1;
+ string failFile = null, locinfo = null;
+
+ QKeyValue attrs = GetAttributes(node);
+ if (node != null)
+ {
+ GetLocInfoFromAttrs(attrs, out failLine, out failCol, out failFile);
+ }
+
+ if (showBplLocation && failLine != -1 && failCol != -1 && failFile != null)
+ {
+ locinfo = "File: \t" + failFile +
+ "\nLine:\t" + failLine +
+ "\nCol:\t" + failCol + "\n";
+ }
+ Contract.Requires(message != null);
+ Contract.Requires(node != null);
+ IToken tok = node.tok;
+ if (error)
+ {
+ ErrorWriteLine(message);
+ }
+ else
+ {
+ Console.WriteLine(message);
+ }
+ if (!string.IsNullOrEmpty(locinfo))
+ {
+ ErrorWriteLine(locinfo);
+ }
+ else
+ {
+ ErrorWriteLine("Sourceloc info not found for: {0}({1},{2})\n", tok.filename, tok.line, tok.col);
+ }
+ }
+
+ /// <summary>
+ /// Parse the given files into one Boogie program. If an I/O or parse error occurs, an error will be printed
+ /// and null will be returned. On success, a non-null program is returned.
+ /// </summary>
+ static Program ParseBoogieProgram(List<string> fileNames, bool suppressTraceOutput)
+ {
+ Contract.Requires(cce.NonNullElements(fileNames));
+ //BoogiePL.Errors.count = 0;
+ Program program = null;
+ bool okay = true;
+ for (int fileId = 0; fileId < fileNames.Count; fileId++)
+ {
+ string bplFileName = fileNames[fileId];
+ if (!suppressTraceOutput)
+ {
+ if (CommandLineOptions.Clo.XmlSink != null)
+ {
+ CommandLineOptions.Clo.XmlSink.WriteFileFragment(bplFileName);
+ }
+ if (CommandLineOptions.Clo.Trace)
+ {
+ Console.WriteLine("Parsing " + bplFileName);
+ }
+ }
+
+ Program programSnippet;
+ int errorCount;
+ try
+ {
+ var defines = new List<string>() { "FILE_" + fileId };
+ errorCount = BoogiePL.Parser.Parse(bplFileName, defines, out programSnippet);
+ if (programSnippet == null || errorCount != 0)
+ {
+ Console.WriteLine("{0} parse errors detected in {1}", errorCount, bplFileName);
+ okay = false;
+ continue;
+ }
+ }
+ catch (IOException e)
+ {
+ ErrorWriteLine("Error opening file \"{0}\": {1}", bplFileName, e.Message);
+ okay = false;
+ continue;
+ }
+ if (program == null)
+ {
+ program = programSnippet;
+ }
+ else if (programSnippet != null)
+ {
+ program.TopLevelDeclarations.AddRange(programSnippet.TopLevelDeclarations);
+ }
+ }
+ if (!okay)
+ {
+ return null;
+ }
+ else if (program == null)
+ {
+ return new Program();
+ }
+ else
+ {
+ return program;
+ }
+ }
+
+
+ enum PipelineOutcome
+ {
+ Done,
+ ResolutionError,
+ TypeCheckingError,
+ ResolvedAndTypeChecked,
+ FatalError,
+ VerificationCompleted
+ }
+
+ /// <summary>
+ /// Resolves and type checks the given Boogie program. Any errors are reported to the
+ /// console. Returns:
+ /// - Done if no errors occurred, and command line specified no resolution or no type checking.
+ /// - ResolutionError if a resolution error occurred
+ /// - TypeCheckingError if a type checking error occurred
+ /// - ResolvedAndTypeChecked if both resolution and type checking succeeded
+ /// </summary>
+ static PipelineOutcome ResolveAndTypecheck(Program program, string bplFileName)
+ {
+ Contract.Requires(program != null);
+ Contract.Requires(bplFileName != null);
+ // ---------- Resolve ------------------------------------------------------------
+
+ if (CommandLineOptions.Clo.NoResolve)
+ {
+ return PipelineOutcome.Done;
+ }
+
+ int errorCount = program.Resolve();
+ if (errorCount != 0)
+ {
+ Console.WriteLine("{0} name resolution errors detected in {1}", errorCount, bplFileName);
+ return PipelineOutcome.ResolutionError;
+ }
+
+ // ---------- Type check ------------------------------------------------------------
+
+ if (CommandLineOptions.Clo.NoTypecheck)
+ {
+ return PipelineOutcome.Done;
+ }
+
+ errorCount = program.Typecheck();
+ if (errorCount != 0)
+ {
+ Console.WriteLine("{0} type checking errors detected in {1}", errorCount, bplFileName);
+ return PipelineOutcome.TypeCheckingError;
+ }
+
+ if (CommandLineOptions.Clo.PrintFile != null && CommandLineOptions.Clo.PrintDesugarings)
+ {
+ // if PrintDesugaring option is engaged, print the file here, after resolution and type checking
+ PrintBplFile(CommandLineOptions.Clo.PrintFile, program, true);
+ }
+
+ return PipelineOutcome.ResolvedAndTypeChecked;
+ }
+
+ static void EliminateDeadVariablesAndInline(Program program)
+ {
+ Contract.Requires(program != null);
+ // Eliminate dead variables
+ Microsoft.Boogie.UnusedVarEliminator.Eliminate(program);
+
+ // Collect mod sets
+ if (CommandLineOptions.Clo.DoModSetAnalysis)
+ {
+ Microsoft.Boogie.ModSetCollector.DoModSetAnalysis(program);
+ }
+
+ // Coalesce blocks
+ if (CommandLineOptions.Clo.CoalesceBlocks)
+ {
+ if (CommandLineOptions.Clo.Trace)
+ Console.WriteLine("Coalescing blocks...");
+ Microsoft.Boogie.BlockCoalescer.CoalesceBlocks(program);
+ }
+
+ // Inline
+ var TopLevelDeclarations = cce.NonNull(program.TopLevelDeclarations);
+
+ if (CommandLineOptions.Clo.ProcedureInlining != CommandLineOptions.Inlining.None)
+ {
+ bool inline = false;
+ foreach (var d in TopLevelDeclarations)
+ {
+ if (d.FindExprAttribute("inline") != null)
+ {
+ inline = true;
+ }
+ }
+ if (inline)
+ {
+ foreach (var d in TopLevelDeclarations)
+ {
+ var impl = d as Implementation;
+ if (impl != null)
+ {
+ impl.OriginalBlocks = impl.Blocks;
+ impl.OriginalLocVars = impl.LocVars;
+ }
+ }
+ foreach (var d in TopLevelDeclarations)
+ {
+ var impl = d as Implementation;
+ if (impl != null && !impl.SkipVerification)
+ {
+ Inliner.ProcessImplementation(program, impl);
+ }
+ }
+ foreach (var d in TopLevelDeclarations)
+ {
+ var impl = d as Implementation;
+ if (impl != null)
+ {
+ impl.OriginalBlocks = null;
+ impl.OriginalLocVars = null;
+ }
+ }
+ }
+ }
+ }
+
+ static Model.Func ExtractIncarnationFromModel(Model m, string varName)
+ {
+ Model.Func lastFunc = null;
+ Model.Func penulFunc = null;
+ int currIncarnationNo = -1;
+ foreach (Model.Func f in m.Functions)
+ {
+ if(f.Name.Contains(varName))
+ {
+ string[] tokens = Regex.Split(f.Name, "@");
+ if (tokens.Length == 2 && System.Convert.ToInt32(tokens[1]) > currIncarnationNo)
+ {
+ penulFunc = lastFunc;
+ lastFunc = f;
+ }
+ }
+ }
+ return (penulFunc == null) ? lastFunc : penulFunc;
+ }
+
+ static QKeyValue ExtractAsertSourceLocFromTrace(BlockSeq s)
+ {
+ foreach (Block b in s)
+ {
+ foreach (Cmd c in b.Cmds)
+ {
+ if (c is AssertCmd)
+ {
+ if (QKeyValue.FindBoolAttribute(((AssertCmd)c).Attributes, "sourceloc"))
+ {
+ return ((AssertCmd)c).Attributes;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ static QKeyValue CreateSourceLocQKV(int line, int col, string fname, string dir)
+ {
+ QKeyValue dirkv = new QKeyValue(Token.NoToken, "dir", new List<object>(new object[] { dir }), null);
+ QKeyValue fnamekv = new QKeyValue(Token.NoToken, "fname", new List<object>(new object[] { fname }), dirkv);
+ QKeyValue colkv = new QKeyValue(Token.NoToken, "col", new List<object>(new object[] { new LiteralExpr(Token.NoToken, BigNum.FromInt(col)) }), fnamekv);
+ QKeyValue linekv = new QKeyValue(Token.NoToken, "line", new List<object>(new object[] { new LiteralExpr(Token.NoToken, BigNum.FromInt(line)) }), colkv);
+ return linekv;
+ }
+
+ static QKeyValue GetSourceLocInfo(Counterexample error, string AccessType) {
+ string sourceVarName = null;
+ int sourceLocLineNo = -1;
+ string directoryName = Path.GetDirectoryName(CommandLineOptions.Clo.Files[0]);
+ string sourceLocFileName = ((!String.IsNullOrEmpty(directoryName) && directoryName != ".") ? (directoryName + Path.DirectorySeparatorChar) : "") + Path.GetFileNameWithoutExtension(CommandLineOptions.Clo.Files[0]) + ".loc";
+
+ TextReader tr = new StreamReader(sourceLocFileName);
+
+ foreach (Block b in error.Trace)
+ {
+ foreach (Cmd c in b.Cmds)
+ {
+ if (b.tok.val.Equals("_LOG_" + AccessType) && c.ToString().Contains(AccessType + "_SOURCE_"))
+ {
+ sourceVarName = Regex.Split(c.ToString(), " ")[1];
+ }
+ }
+ }
+ if (sourceVarName != null)
+ {
+ Model.Func f = error.Model.TryGetFunc(sourceVarName);
+ if (f != null)
+ {
+ sourceLocLineNo = f.GetConstant().AsInt();
+ }
+ }
+
+ if (sourceLocLineNo > 0)
+ {
+ // TODO: Make lines in .loc file be indexed from 1 for consistency.
+ string fileLine = FetchCodeLine(sourceLocFileName, sourceLocLineNo + 1);
+ if (fileLine != null)
+ {
+ string[] slocTokens = Regex.Split(fileLine, "#");
+ return CreateSourceLocQKV(
+ System.Convert.ToInt32(slocTokens[0]),
+ System.Convert.ToInt32(slocTokens[1]),
+ slocTokens[2],
+ slocTokens[3]);
+ }
+ }
+ else
+ {
+ Console.WriteLine("sourceLocLineNo is {0}. No sourceloc at that location.\n", sourceLocLineNo);
+ return null;
+ }
+ tr.Close();
+ return null;
+ }
+
+ static bool IsRepeatedKV(QKeyValue attrs, List<QKeyValue> alreadySeen)
+ {
+ return false;
+ /*
+ if (attrs == null)
+ {
+ return false;
+ }
+ string key = null;
+ foreach (QKeyValue qkv in alreadySeen)
+ {
+ QKeyValue kv = qkv.Clone() as QKeyValue;
+ if (kv.Params.Count != attrs.Params.Count)
+ {
+ return false;
+ }
+ for (; kv != null; kv = kv.Next) {
+ key = kv.Key;
+ if (key != "thread") {
+ if (kv.Params.Count == 0)
+ {
+ if (QKeyValue.FindBoolAttribute(attrs, key))
+ {
+ continue;
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+ else if (kv.Params[0] is LiteralExpr)
+ { // int
+ LiteralExpr l = kv.Params[0] as LiteralExpr;
+ int i = l.asBigNum.ToIntSafe;
+ if (QKeyValue.FindIntAttribute(attrs, key, -1) == i)
+ {
+ continue;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (kv.Params[0] is string)
+ { // string
+ string s = kv.Params[0] as string;
+ if (QKeyValue.FindStringAttribute(attrs, key) == s)
+ {
+ continue;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ Debug.Assert(false);
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+ */
+ }
+
+ static void ProcessOutcome(VC.VCGen.Outcome outcome, List<Counterexample> errors, string timeIndication,
+ ref int errorCount, ref int verified, ref int inconclusives, ref int timeOuts, ref int outOfMemories)
+ {
+ switch (outcome)
+ {
+ default:
+ Contract.Assert(false); // unexpected outcome
+ throw new cce.UnreachableException();
+ case VCGen.Outcome.ReachedBound:
+ Inform(String.Format("{0}verified", timeIndication));
+ Console.WriteLine(string.Format("Stratified Inlining: Reached recursion bound of {0}", CommandLineOptions.Clo.RecursionBound));
+ verified++;
+ break;
+ case VCGen.Outcome.Correct:
+ if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed)
+ {
+ Inform(String.Format("{0}credible", timeIndication));
+ verified++;
+ }
+ else
+ {
+ Inform(String.Format("{0}verified", timeIndication));
+ verified++;
+ }
+ break;
+ case VCGen.Outcome.TimedOut:
+ timeOuts++;
+ Inform(String.Format("{0}timed out", timeIndication));
+ break;
+ case VCGen.Outcome.OutOfMemory:
+ outOfMemories++;
+ Inform(String.Format("{0}out of memory", timeIndication));
+ break;
+ case VCGen.Outcome.Inconclusive:
+ inconclusives++;
+ Inform(String.Format("{0}inconclusive", timeIndication));
+ break;
+ case VCGen.Outcome.Errors:
+ if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed)
+ {
+ Inform(String.Format("{0}doomed", timeIndication));
+ errorCount++;
+ } //else {
+ Contract.Assert(errors != null); // guaranteed by postcondition of VerifyImplementation
+ {
+ // BP1xxx: Parsing errors
+ // BP2xxx: Name resolution errors
+ // BP3xxx: Typechecking errors
+ // BP4xxx: Abstract interpretation errors (Is there such a thing?)
+ // BP5xxx: Verification errors
+
+ errors.Sort(new CounterexampleComparer());
+ foreach (Counterexample error in errors)
+ {
+ if (error is CallCounterexample)
+ {
+ CallCounterexample err = (CallCounterexample)error;
+ if (QKeyValue.FindBoolAttribute(err.FailingRequires.Attributes, "barrier_divergence"))
+ {
+ ReportBarrierDivergence(err.FailingCall, true);
+ }
+ else if (QKeyValue.FindBoolAttribute(err.FailingRequires.Attributes, "race"))
+ {
+ int byteOffset = -1, elemWidth = -1, elemOffset = -1;
+ int lidx1 = -1, lidy1 = -1, lidz1 = -1, lidx2 = -1, lidy2 = -1, lidz2 = -1;
+ int gidx1 = -1, gidy1 = -1, gidz1 = -1, gidx2 = -1, gidy2 = -1, gidz2 = -1;
+ string thread1 = null, thread2 = null, group1 = null, group2 = null, arrName = null;
+
+ Variable offsetVar = ExtractOffsetVar(err.FailingRequires.Condition as NAryExpr);
+ Model.Func offsetFunc = ExtractIncarnationFromModel(error.Model, offsetVar.Name);
+ Debug.Assert(offsetFunc != null, "ProcessOutcome(): Could not extract incarnation.");
+ GetInfoFromVarAndFunc(offsetVar.Attributes, offsetFunc, out byteOffset, out elemWidth, out elemOffset, out arrName);
+
+ Debug.Assert(error.Model != null, "ProcessOutcome(): null model");
+ GetIdsFromModel(error.Model, out lidx1, out lidy1, out lidz1, out lidx2, out lidy2, out lidz2,
+ out gidx1, out gidy1, out gidz1, out gidx2, out gidy2, out gidz2);
+
+ thread1 = "(" + lidx1 + ", " + lidy1 + ", " + lidz1 + ")";
+ thread2 = "(" + lidx2 + ", " + lidy2 + ", " + lidz2 + ")";
+
+ group1 = "(" + gidx1 + ", " + gidy1 + ", " + gidz1 + ")";
+ group2 = "(" + gidx2 + ", " + gidy2 + ", " + gidz2 + ")";
+
+ if (QKeyValue.FindBoolAttribute(err.FailingRequires.Attributes, "write_read"))
+ {
+ err.FailingRequires.Attributes = GetSourceLocInfo(error, "WRITE");
+ ReportRace(err.FailingCall, err.FailingRequires, thread1, thread2, group1, group2, arrName, byteOffset, elemOffset, RaceType.WR, true);
+ }
+ else if (QKeyValue.FindBoolAttribute(err.FailingRequires.Attributes, "read_write"))
+ {
+ err.FailingRequires.Attributes = GetSourceLocInfo(error, "READ");
+ ReportRace(err.FailingCall, err.FailingRequires, thread1, thread2, group1, group2, arrName, byteOffset, elemOffset, RaceType.RW, true);
+
+ }
+ else if (QKeyValue.FindBoolAttribute(err.FailingRequires.Attributes, "write_write"))
+ {
+ err.FailingRequires.Attributes = GetSourceLocInfo(error, "WRITE");
+ ReportRace(err.FailingCall, err.FailingRequires, thread1, thread2, group1, group2, arrName, byteOffset, elemOffset, RaceType.WW, true);
+ }
+ }
+ else
+ {
+ ReportRequiresFailure(err.FailingCall, err.FailingRequires, true);
+ }
+ }
+ else if (error is ReturnCounterexample)
+ {
+ ReturnCounterexample err = (ReturnCounterexample)error;
+ ReportEnsuresFailure(err.FailingEnsures, true);
+ }
+ else
+ {
+ AssertCounterexample err = (AssertCounterexample)error;
+ if (err.FailingAssert is LoopInitAssertCmd)
+ {
+ ReportInvariantEntryFailure(err.FailingAssert, true);
+ }
+ else if (err.FailingAssert is LoopInvMaintainedAssertCmd)
+ {
+ ReportInvariantMaintedFailure(err.FailingAssert, true);
+ }
+ else
+ {
+ ReportFailingAssert(err.FailingAssert, true);
+ }
+ }
+ errorCount++;
+ }
+ //}
+ Inform(String.Format("{0}error{1}", timeIndication, errors.Count == 1 ? "" : "s"));
+ }
+ break;
+ }
+ }
+
+ private static void ReportFailingAssert(Absy node, bool displayCode)
+ {
+ Console.WriteLine("");
+
+ int failLine = -1, failCol = -1;
+ string failFile = null, locinfo = null;
+
+ QKeyValue attrs = GetAttributes(node);
+ Debug.Assert(attrs != null, "ReportFailingAssert(): null attributes.");
+
+ GetLocInfoFromAttrs(attrs, out failLine, out failCol, out failFile);
+
+ Debug.Assert(failLine != -1 && failCol != -1 && failFile != null, "ReportFailingAssert(): could not get source location.",
+ "Sourceloc info not found for {0}:{1}:{2}\n", node.tok.filename, node.tok.line, node.tok.col);
+
+ locinfo = failFile + ":" + failLine + ":" + failCol + ":";
+
+ ErrorWriteLine(locinfo, "this assertion might not hold", ErrorMsgType.Error);
+ if (displayCode)
+ {
+ ErrorWriteLine(FetchCodeLine(failFile, failLine));
+ }
+ }
+
+ private static void ReportInvariantMaintedFailure(Absy node, bool displayCode)
+ {
+ Console.WriteLine("");
+
+ int failLine = -1, failCol = -1;
+ string failFile = null, locinfo = null;
+
+ QKeyValue attrs = GetAttributes(node);
+ Debug.Assert(attrs != null, "ReportInvariantMaintedFailure(): null attributes.");
+
+ GetLocInfoFromAttrs(attrs, out failLine, out failCol, out failFile);
+
+ Debug.Assert(failLine != -1 && failCol != -1 && failFile != null, "ReportInvariantMaintedFailure(): could not get source location.",
+ "Sourceloc info not found for {0}:{1}:{2}\n", node.tok.filename, node.tok.line, node.tok.col);
+
+ locinfo = failFile + ":" + failLine + ":" + failCol + ":";
+
+ ErrorWriteLine(locinfo, "loop invariant might not be maintained by the loop", ErrorMsgType.Error);
+ if (displayCode)
+ {
+ ErrorWriteLine(FetchCodeLine(failFile, failLine));
+ }
+ }
+
+ private static void ReportInvariantEntryFailure(Absy node, bool displayCode)
+ {
+ Console.WriteLine("");
+
+ int failLine = -1, failCol = -1;
+ string failFile = null, locinfo = null;
+
+ QKeyValue attrs = GetAttributes(node);
+ Debug.Assert(attrs != null, "ReportInvariantEntryFailure(): null attributes.");
+
+ GetLocInfoFromAttrs(attrs, out failLine, out failCol, out failFile);
+
+ Debug.Assert(failLine != -1 && failCol != -1 && failFile != null, "ReportInvariantEntryFailure(): could not get source location.",
+ "Sourceloc info not found for {0}:{1}:{2}\n", node.tok.filename, node.tok.line, node.tok.col);
+
+ locinfo = failFile + ":" + failLine + ":" + failCol + ":";
+
+ ErrorWriteLine(locinfo, "loop invariant might not hold on entry", ErrorMsgType.Error);
+ if (displayCode)
+ {
+ ErrorWriteLine(FetchCodeLine(failFile, failLine));
+ }
+ }
+
+ private static void ReportEnsuresFailure(Absy node, bool displayCode)
+ {
+ Console.WriteLine("");
+
+ int failLine = -1, failCol = -1;
+ string failFile = null, locinfo = null;
+
+ QKeyValue attrs = GetAttributes(node);
+ Debug.Assert(attrs != null, "ReportEnsuresFailure(): null attributes.");
+
+ GetLocInfoFromAttrs(attrs, out failLine, out failCol, out failFile);
+
+ Debug.Assert(failLine != -1 && failCol != -1 && failFile != null, "ReportEnsuresFailure(): could not get source location.",
+ "Sourceloc info not found for {0}:{1}:{2}\n", node.tok.filename, node.tok.line, node.tok.col);
+
+ locinfo = failFile + ":" + failLine + ":" + failCol + ":";
+
+ ErrorWriteLine(locinfo, "postcondition might not hold on all return paths", ErrorMsgType.Error);
+ if (displayCode)
+ {
+ ErrorWriteLine(FetchCodeLine(failFile, failLine));
+ }
+ }
+
+ private static void ReportRace(Absy callNode, Absy reqNode, string thread1, string thread2, string group1, string group2, string arrName, int byteOffset, int elemOffset, RaceType raceType, bool displayCode)
+ {
+ Console.WriteLine("");
+ int failLine1 = -1, failCol1 = -1, failLine2 = -1, failCol2 = -1;
+ string failFile1 = null, locinfo1 = null, failFile2 = null, locinfo2 = null, raceName, access1, access2;
+
+ QKeyValue callAttrs = GetAttributes(callNode);
+ QKeyValue reqAttrs = GetAttributes(reqNode);
+
+ Debug.Assert(callAttrs != null, "ReportRace(): null call attributes.");
+ Debug.Assert(reqAttrs != null, "ReportRace(): null req attributes.");
+
+ GetLocInfoFromAttrs(callAttrs, out failLine1, out failCol1, out failFile1);
+ GetLocInfoFromAttrs(reqAttrs, out failLine2, out failCol2, out failFile2);
+
+ Debug.Assert(failLine1 != -1 && failCol1 != -1 && failFile1 != null, "ReportRace(): could not get source location for thread 1",
+ "Sourceloc info not found for {0}:{1}:{2}\n", callNode.tok.filename, callNode.tok.line, callNode.tok.col);
+ Debug.Assert(failLine2 != -1 && failCol2 != -1 && failFile2 != null, "ReportRace(): could not get source location for thread 2",
+ "Sourceloc info not found for {0}:{1}:{2}\n", reqNode.tok.filename, reqNode.tok.line, reqNode.tok.col);
+
+ switch (raceType)
+ {
+ case RaceType.RW:
+ raceName = "read-write";
+ access1 = "read from";
+ access2 = "wrote to";
+ break;
+ case RaceType.WR:
+ raceName = "write-read";
+ access1 = "wrote to";
+ access2 = "read from";
+ break;
+ case RaceType.WW:
+ raceName = "write-write";
+ access1 = "wrote to";
+ access2 = "wrote to";
+ break;
+ default:
+ raceName = null;
+ access1 = null;
+ access2 = null;
+ Debug.Assert(false, "ReportRace(): Reached default case in switch over raceType.");
+ break;
+ }
+ ErrorWriteLine(failFile1 + ":", "possible " + raceName + " race:\n", ErrorMsgType.Error);
+
+ locinfo1 = failFile1 + ":" + failLine1 + ":" + failCol1 + ":";
+ locinfo2 = failFile2 + ":" + failLine2 + ":" + failCol2 + ":";
+
+ AddPadding(ref locinfo1, ref locinfo2);
+ AddPadding(ref access1, ref access2);
+
+ ErrorWriteLine(locinfo1, "thread " + thread2 + " group " + group2 + " " + access2 + " " + arrName + "[" + byteOffset + "] (" + elemOffset + ")", ErrorMsgType.NoError);
+ if (displayCode)
+ {
+ ErrorWriteLine(TrimLeadingSpaces(FetchCodeLine(failFile1, failLine1) + "\n", 2));
+ }
+
+ ErrorWriteLine(locinfo2, "thread " + thread1 + " group " + group1 + " " + access1 + " " + arrName + "[" + byteOffset + "] (" + elemOffset + ")", ErrorMsgType.NoError);
+ if (displayCode)
+ {
+ ErrorWriteLine(TrimLeadingSpaces(FetchCodeLine(failFile2, failLine2) + "\n", 2));
+ }
+ }
+
+ private static void ReportBarrierDivergence(Absy node, bool displayCode)
+ {
+ Console.WriteLine("");
+
+ int failLine = -1, failCol = -1;
+ string failFile = null, locinfo = null;
+
+ QKeyValue attrs = GetAttributes(node);
+ Debug.Assert(attrs != null, "ReportBarrierDivergendce(): null attributes.");
+
+ GetLocInfoFromAttrs(attrs, out failLine, out failCol, out failFile);
+
+ Debug.Assert(failLine != -1 && failCol != -1 && failFile != null, "ReportBarrierDivergence(): could not get source location.",
+ "Sourceloc info not found for {0}:{1}:{2}\n", node.tok.filename, node.tok.line, node.tok.col);
+
+ locinfo = failFile + ":" + failLine + ":" + failCol + ":";
+
+ ErrorWriteLine(locinfo, "barrier may be reached by non-uniform control flow", ErrorMsgType.Error);
+ if (displayCode)
+ {
+ ErrorWriteLine(FetchCodeLine(failFile, failLine));
+ }
+ }
+
+ private static void ReportRequiresFailure(Absy callNode, Absy reqNode, bool displayCode)
+ {
+ // TODO: Remove code duplication below.
+ // bad_pre.cl:16:7: error: a precondition for this call might not hold
+ // [codeline]
+ // bad_pre.cl:8:24: note: this is the precondition that might not hold
+ // [codeline]
+ Console.WriteLine("");
+
+ int failLine1 = -1, failCol1 = -1, failLine2 = -1, failCol2 = -1;
+ string failFile1 = null, locinfo1 = null, failFile2 = null, locinfo2 = null;
+
+ QKeyValue callAttrs = GetAttributes(callNode);
+ QKeyValue reqAttrs = GetAttributes(reqNode);
+
+ Debug.Assert(callAttrs != null, "ReportRace(): null call attributes.");
+ Debug.Assert(reqAttrs != null, "ReportRace(): null req attributes.");
+
+ GetLocInfoFromAttrs(callAttrs, out failLine1, out failCol1, out failFile1);
+ GetLocInfoFromAttrs(reqAttrs, out failLine2, out failCol2, out failFile2);
+
+ Debug.Assert(failLine1 != -1 && failCol1 != -1 && failFile1 != null, "ReportRequiresFailure(): could not get source location from call",
+ "Sourceloc info not found for {0}:{1}:{2}\n", callNode.tok.filename, callNode.tok.line, callNode.tok.col);
+ Debug.Assert(failLine2 != -1 && failCol2 != -1 && failFile2 != null, "ReportRequiresFailure(): could not get source location from requires",
+ "Sourceloc info not found for {0}:{1}:{2}\n", reqNode.tok.filename, reqNode.tok.line, reqNode.tok.col);
+
+ locinfo1 = failFile1 + ":" + failLine1 + ":" + failCol1 + ":";
+ locinfo2 = failFile2 + ":" + failLine2 + ":" + failCol2 + ":";
+
+ ErrorWriteLine(locinfo1, "a precondition for this call might not hold", ErrorMsgType.Error);
+ if (displayCode)
+ {
+ ErrorWriteLine(TrimLeadingSpaces(FetchCodeLine(failFile1, failLine1), 2));
+ }
+
+ ErrorWriteLine(locinfo2, "this is the precondition that might not hold", ErrorMsgType.Note);
+ if (displayCode)
+ {
+ ErrorWriteLine(TrimLeadingSpaces(FetchCodeLine(failFile2, failLine2), 2));
+ }
+
+ }
+
+ private static string FetchCodeLine(string path, int lineNo)
+ {
+ TextReader tr = new StreamReader(path);
+ string line = null;
+
+ for (int currLineNo = 1; ((line = tr.ReadLine()) != null); currLineNo++)
+ {
+ if (currLineNo == lineNo)
+ {
+ break;
+ }
+ }
+ if (line != null)
+ {
+ return line;
+ }
+ else
+ {
+ Console.WriteLine("FetchCodeLine(): could not get line {0} from {1}\n", lineNo, path);
+ return null;
+ }
+ }
+
+ private static void GetLocInfoFromAttrs(QKeyValue attrs, out int failLine, out int failCol, out string failFile)
+ {
+ failLine = QKeyValue.FindIntAttribute(attrs, "line", -1);
+ failCol = QKeyValue.FindIntAttribute(attrs, "col", -1);
+ failFile = QKeyValue.FindStringAttribute(attrs, "fname");
+ string directoryName = Path.GetDirectoryName(CommandLineOptions.Clo.Files[0]);
+ failFile = ((!String.IsNullOrEmpty(directoryName) && directoryName != ".") ? (directoryName + Path.DirectorySeparatorChar) : "") + failFile;
+ }
+
+ private static void GetIdsFromModel(Model model, out int lidx1, out int lidy1, out int lidz1, out int lidx2, out int lidy2, out int lidz2,
+ out int gidx1, out int gidy1, out int gidz1, out int gidx2, out int gidy2, out int gidz2)
+ {
+ lidx1 = model.TryGetFunc("local_id_x$1").GetConstant().AsInt();
+ lidy1 = model.TryGetFunc("local_id_y$1").GetConstant().AsInt();
+ lidz1 = model.TryGetFunc("local_id_z$1").GetConstant().AsInt();
+ lidx2 = model.TryGetFunc("local_id_x$2").GetConstant().AsInt();
+ lidy2 = model.TryGetFunc("local_id_y$2").GetConstant().AsInt();
+ lidz2 = model.TryGetFunc("local_id_z$2").GetConstant().AsInt();
+
+ gidx1 = model.TryGetFunc("group_id_x$1").GetConstant().AsInt();
+ gidy1 = model.TryGetFunc("group_id_y$1").GetConstant().AsInt();
+ gidz1 = model.TryGetFunc("group_id_z$1").GetConstant().AsInt();
+ gidx2 = model.TryGetFunc("group_id_x$2").GetConstant().AsInt();
+ gidy2 = model.TryGetFunc("group_id_y$2").GetConstant().AsInt();
+ gidz2 = model.TryGetFunc("group_id_z$2").GetConstant().AsInt();
+ }
+
+ private static void GetInfoFromVarAndFunc(QKeyValue attrs, Model.Func f, out int byteOffset, out int elemWidth, out int elemOffset, out string arrName)
+ {
+ Debug.Assert(f != null && f.AppCount == 1);
+ elemOffset = f.Apps.FirstOrDefault().Result.AsInt();
+ arrName = ExtractArrName(f.Name);
+ elemWidth = QKeyValue.FindIntAttribute(attrs, "elem_width", -1);
+ Debug.Assert(elemWidth != -1, "GetInfoFromVarAndFunc: Could not find \"elem_width\" attribute.");
+ byteOffset = CalculateByteOffset(elemOffset, elemWidth);
+ }
+
+ private static int CalculateByteOffset(int elemOffset, int elemWidth)
+ {
+ return (elemOffset * elemWidth) / 8;
+ }
+
+ private static string ExtractArrName(string varName)
+ {
+ return Regex.Split(varName, "[$]+")[1];
+ }
+
+ private static Variable ExtractOffsetVar(NAryExpr expr)
+ {
+ foreach (Expr e in expr.Args)
+ {
+ if (e is NAryExpr && e.ToString().Contains("_OFFSET_"))
+ {
+ return ExtractOffsetVar(e as NAryExpr);
+ }
+ else if (e is IdentifierExpr && (e as IdentifierExpr).Name.Contains("_OFFSET_"))
+ {
+ return (e as IdentifierExpr).Decl;
+ }
+ else continue;
+ }
+ Debug.Assert(false, "GPUVerifyBoogieDriver: ExtractOffsetExpr() could not find _OFFSET expr.");
+ return null;
+ }
+
+ /// <summary>
+ /// Given a resolved and type checked Boogie program, infers invariants for the program
+ /// and then attempts to verify it. Returns:
+ /// - Done if command line specified no verification
+ /// - FatalError if a fatal error occurred, in which case an error has been printed to console
+ /// - VerificationCompleted if inference and verification completed, in which the out
+ /// parameters contain meaningful values
+ /// </summary>
+ static PipelineOutcome InferAndVerify(Program program,
+ out int errorCount, out int verified, out int inconclusives, out int timeOuts, out int outOfMemories)
+ {
+ Contract.Requires(program != null);
+ Contract.Ensures(0 <= Contract.ValueAtReturn(out inconclusives) && 0 <= Contract.ValueAtReturn(out timeOuts));
+
+ errorCount = verified = inconclusives = timeOuts = outOfMemories = 0;
+
+ // ---------- Infer invariants --------------------------------------------------------
+
+ // Abstract interpretation -> Always use (at least) intervals, if not specified otherwise (e.g. with the "/noinfer" switch)
+ if (CommandLineOptions.Clo.Ai.J_Intervals || CommandLineOptions.Clo.Ai.J_Trivial)
+ {
+ Microsoft.Boogie.AbstractInterpretation.NativeAbstractInterpretation.RunAbstractInterpretation(program);
+ }
+ else
+ {
+ Microsoft.Boogie.AbstractInterpretation.AbstractInterpretation.RunAbstractInterpretation(program);
+ }
+
+ if (CommandLineOptions.Clo.LoopUnrollCount != -1)
+ {
+ program.UnrollLoops(CommandLineOptions.Clo.LoopUnrollCount);
+ }
+
+ if (CommandLineOptions.Clo.DoPredication && CommandLineOptions.Clo.StratifiedInlining > 0)
+ {
+ BlockPredicator.Predicate(program, false, false);
+ if (CommandLineOptions.Clo.PrintInstrumented)
+ {
+ using (TokenTextWriter writer = new TokenTextWriter(Console.Out))
+ {
+ program.Emit(writer);
+ }
+ }
+ }
+
+ Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo = null;
+ if (CommandLineOptions.Clo.ExtractLoops)
+ {
+ extractLoopMappingInfo = program.ExtractLoops();
+ }
+
+ if (CommandLineOptions.Clo.PrintInstrumented)
+ {
+ program.Emit(new TokenTextWriter(Console.Out));
+ }
+
+ if (CommandLineOptions.Clo.ExpandLambdas)
+ {
+ LambdaHelper.ExpandLambdas(program);
+ //PrintBplFile ("-", program, true);
+ }
+
+ // ---------- Verify ------------------------------------------------------------
+
+ if (!CommandLineOptions.Clo.Verify)
+ {
+ return PipelineOutcome.Done;
+ }
+
+ #region Run Houdini and verify
+ if (CommandLineOptions.Clo.ContractInfer)
+ {
+ Houdini.Houdini houdini = new Houdini.Houdini(program);
+ Houdini.HoudiniOutcome outcome = houdini.PerformHoudiniInference();
+ if (CommandLineOptions.Clo.PrintAssignment)
+ {
+ Console.WriteLine("Assignment computed by Houdini:");
+ foreach (var x in outcome.assignment)
+ {
+ Console.WriteLine(x.Key + " = " + x.Value);
+ }
+ }
+ if (CommandLineOptions.Clo.Trace)
+ {
+ int numTrueAssigns = 0;
+ foreach (var x in outcome.assignment)
+ {
+ if (x.Value)
+ numTrueAssigns++;
+ }
+ Console.WriteLine("Number of true assignments = " + numTrueAssigns);
+ Console.WriteLine("Number of false assignments = " + (outcome.assignment.Count - numTrueAssigns));
+ Console.WriteLine("Prover time = " + Houdini.HoudiniSession.proverTime);
+ Console.WriteLine("Unsat core prover time = " + Houdini.HoudiniSession.unsatCoreProverTime);
+ Console.WriteLine("Number of prover queries = " + Houdini.HoudiniSession.numProverQueries);
+ Console.WriteLine("Number of unsat core prover queries = " + Houdini.HoudiniSession.numUnsatCoreProverQueries);
+ Console.WriteLine("Number of unsat core prunings = " + Houdini.HoudiniSession.numUnsatCorePrunings);
+ }
+
+ foreach (Houdini.VCGenOutcome x in outcome.implementationOutcomes.Values)
+ {
+ ProcessOutcome(x.outcome, x.errors, "", ref errorCount, ref verified, ref inconclusives, ref timeOuts, ref outOfMemories);
+ }
+ //errorCount = outcome.ErrorCount;
+ //verified = outcome.Verified;
+ //inconclusives = outcome.Inconclusives;
+ //timeOuts = outcome.TimeOuts;
+ //outOfMemories = 0;
+ return PipelineOutcome.Done;
+ }
+ #endregion
+
+ #region Verify each implementation
+
+ ConditionGeneration vcgen = null;
+ try
+ {
+ if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed)
+ {
+ vcgen = new DCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend);
+ }
+ else if (CommandLineOptions.Clo.StratifiedInlining > 0)
+ {
+ vcgen = new StratifiedVCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend);
+ }
+ else
+ {
+ vcgen = new VCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend);
+ }
+ }
+ catch (ProverException e)
+ {
+ ErrorWriteLine("Fatal Error: ProverException: {0}", e);
+ return PipelineOutcome.FatalError;
+ }
+
+ // operate on a stable copy, in case it gets updated while we're running
+ var decls = program.TopLevelDeclarations.ToArray();
+ foreach (Declaration decl in decls)
+ {
+ Contract.Assert(decl != null);
+ int prevAssertionCount = vcgen.CumulativeAssertionCount;
+ Implementation impl = decl as Implementation;
+ if (impl != null && CommandLineOptions.Clo.UserWantsToCheckRoutine(cce.NonNull(impl.Name)) && !impl.SkipVerification)
+ {
+ List<Counterexample/*!*/>/*?*/ errors;
+
+ DateTime start = new DateTime(); // to please compiler's definite assignment rules
+ if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.XmlSink != null)
+ {
+ start = DateTime.UtcNow;
+ if (CommandLineOptions.Clo.Trace)
+ {
+ Console.WriteLine();
+ Console.WriteLine("Verifying {0} ...", impl.Name);
+ }
+ if (CommandLineOptions.Clo.XmlSink != null)
+ {
+ CommandLineOptions.Clo.XmlSink.WriteStartMethod(impl.Name, start);
+ }
+ }
+
+ VCGen.Outcome outcome;
+ try
+ {
+ if (CommandLineOptions.Clo.inferLeastForUnsat != null)
+ {
+ var svcgen = vcgen as VC.StratifiedVCGen;
+ Contract.Assert(svcgen != null);
+ var ss = new HashSet<string>();
+ foreach (var tdecl in program.TopLevelDeclarations)
+ {
+ var c = tdecl as Constant;
+ if (c == null || !c.Name.StartsWith(CommandLineOptions.Clo.inferLeastForUnsat)) continue;
+ ss.Add(c.Name);
+ }
+ outcome = svcgen.FindLeastToVerify(impl, ref ss);
+ errors = new List<Counterexample>();
+ Console.Write("Result: ");
+ foreach (var s in ss)
+ {
+ Console.Write("{0} ", s);
+ }
+ Console.WriteLine();
+ }
+ else
+ {
+ outcome = vcgen.VerifyImplementation(impl, out errors);
+ if (CommandLineOptions.Clo.ExtractLoops && vcgen is VCGen && errors != null)
+ {
+ for (int i = 0; i < errors.Count; i++)
+ {
+ errors[i] = (vcgen as VCGen).extractLoopTrace(errors[i], impl.Name, program, extractLoopMappingInfo);
+ }
+ }
+ }
+ }
+ catch (VCGenException e)
+ {
+ ReportBplError(impl, String.Format("Error BP5010: {0} Encountered in implementation {1}.", e.Message, impl.Name), true, true);
+ errors = null;
+ outcome = VCGen.Outcome.Inconclusive;
+ }
+ catch (UnexpectedProverOutputException upo)
+ {
+ AdvisoryWriteLine("Advisory: {0} SKIPPED because of internal error: unexpected prover output: {1}", impl.Name, upo.Message);
+ errors = null;
+ outcome = VCGen.Outcome.Inconclusive;
+ }
+
+ string timeIndication = "";
+ DateTime end = DateTime.UtcNow;
+ TimeSpan elapsed = end - start;
+ if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.XmlSink != null)
+ {
+ if (CommandLineOptions.Clo.Trace)
+ {
+ int poCount = vcgen.CumulativeAssertionCount - prevAssertionCount;
+ timeIndication = string.Format(" [{0} s, {1} proof obligation{2}] ", elapsed.ToString("%s\\.fff"), poCount, poCount == 1 ? "" : "s");
+ }
+ }
+
+ ProcessOutcome(outcome, errors, timeIndication, ref errorCount, ref verified, ref inconclusives, ref timeOuts, ref outOfMemories);
+
+ if (CommandLineOptions.Clo.XmlSink != null)
+ {
+ CommandLineOptions.Clo.XmlSink.WriteEndMethod(outcome.ToString().ToLowerInvariant(), end, elapsed);
+ }
+ if (outcome == VCGen.Outcome.Errors || CommandLineOptions.Clo.Trace)
+ {
+ Console.Out.Flush();
+ }
+ }
+ }
+
+ vcgen.Close();
+ cce.NonNull(CommandLineOptions.Clo.TheProverFactory).Close();
+
+
+ #endregion
+
+ return PipelineOutcome.VerificationCompleted;
+ }
+ }
+}
diff --git a/Source/GPUVerifyBoogieDriver/GPUVerifyBoogieDriver.csproj b/Source/GPUVerifyBoogieDriver/GPUVerifyBoogieDriver.csproj
new file mode 100644
index 00000000..6f616936
--- /dev/null
+++ b/Source/GPUVerifyBoogieDriver/GPUVerifyBoogieDriver.csproj
@@ -0,0 +1,99 @@
+<?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)' == '' ">x86</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{FD2A2C67-1BD6-4A1A-B65B-B057267E24A3}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>GPUVerifyBoogieDriver</RootNamespace>
+ <AssemblyName>GPUVerifyBoogieDriver</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\Binaries\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="GPUVerifyBoogieDriver.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\AbsInt\AbsInt.csproj">
+ <Project>{0EFA3E43-690B-48DC-A72C-384A3EA7F31F}</Project>
+ <Name>AbsInt</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\AIFramework\AIFramework.csproj">
+ <Project>{39B0658D-C955-41C5-9A43-48C97A1EF5FD}</Project>
+ <Name>AIFramework</Name>
+ </ProjectReference>
+ <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="..\Houdini\Houdini.csproj">
+ <Project>{CF41E903-78EB-43BA-A355-E5FEB5ECECD4}</Project>
+ <Name>Houdini</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="..\VCGeneration\VCGeneration.csproj">
+ <Project>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</Project>
+ <Name>VCGeneration</Name>
+ </ProjectReference>
+ </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> \ No newline at end of file
diff --git a/Source/GPUVerifyBoogieDriver/Properties/AssemblyInfo.cs b/Source/GPUVerifyBoogieDriver/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..ef014dd1
--- /dev/null
+++ b/Source/GPUVerifyBoogieDriver/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("GPUVerifyBoogieDriver")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("GPUVerifyBoogieDriver")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("d7726f3b-aa69-4a39-a821-9503db2ab23b")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Source/Graph/Graph.cs b/Source/Graph/Graph.cs
index b5590865..2d2eb90b 100644
--- a/Source/Graph/Graph.cs
+++ b/Source/Graph/Graph.cs
@@ -1,948 +1,965 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections.Generic;
-using System.Text; // for StringBuilder
-using System.Diagnostics.Contracts;
-namespace Graphing {
-
- internal static class Util {
- private static string/*!*/ ListToString<T>(IEnumerable<T> xs) {
- Contract.Ensures(Contract.Result<string>() != null);
- StringBuilder sb = new StringBuilder();
- sb.Append("[");
- bool first = true;
- foreach (T/*!*/ x in xs) {
- Contract.Assert(x != null);
- if (!first)
- sb.Append(", ");
- sb.Append(x.ToString());
- first = false;
- }
- sb.Append("]");
- return sb.ToString();
- }
- public static string/*!*/ MapToString<Node>(Dictionary<Node, List<Node>> d) {
- Contract.Ensures(Contract.Result<string>() != null);
- StringBuilder sb = new StringBuilder();
- sb.Append("{");
- bool first = true;
- foreach (KeyValuePair<Node, List<Node>> de in d) {
- if (!first)
- sb.Append(", ");
- Contract.Assert(!object.Equals(de.Key,default(Node)));
- sb.Append(de.Key.ToString());
- sb.Append("~>");
- sb.Append(ListToString(de.Value));
- first = false;
- }
- sb.Append("}");
- return sb.ToString();
- }
- }
-
- // own struct to represent possibly undefined values, because Mono does
- // not like arrays with element type T! or T?
- public struct Maybe<T> {
- private T Value;
- public bool IsSet; // initialised with false by the default ctor
- public T Val {
- get {
- Contract.Assume(IsSet);
- return Value;
- }
- set {
- Value = value;
- IsSet = true;
- }
- }
- public void UnSet() {
- IsSet = false;
- }
- }
-
- internal class DomRelation<Node> {
- // doms maps (unique) node numbers to the node numbers of the immediate dominator
- // to use it on Nodes, one needs the two way mapping between nodes and their numbers.
- private int[] doms; // 0 is unused: means undefined
- // here are the two mappings
- private Maybe<Node>[] postOrderNumberToNode;
- private Dictionary<Node, int> nodeToPostOrderNumber;
- private int sourceNum; // (number for) root of the graph
- private Node source; // root of the graph
- private Graph<Node> graph;
- private Dictionary<Node, List<Node>> immediateDominatorMap;
-
- [NotDelayed]
- internal DomRelation(Graph<Node> g, Node source) {
- this.graph = g;
- // slot 0 not used: nodes are numbered from 1 to n so zero
- // can represent undefined.
- this.source = source;
- //:base();
- this.NewComputeDominators();
- }
- public Dictionary<Node, List<Node>> ImmediateDominatorMap {
- get {
- Contract.Assume(this.immediateDominatorMap != null);
- return this.immediateDominatorMap;
- }
- }
- public bool DominatedBy(Node dominee, Node dominator) {
- Contract.Assume(this.nodeToPostOrderNumber != null);
- Contract.Assume(this.doms != null);
- int domineeNum = this.nodeToPostOrderNumber[dominee];
- int dominatorNum = this.nodeToPostOrderNumber[dominator];
- if (domineeNum == dominatorNum)
- return true;
- int currentNodeNum = this.doms[domineeNum];
- while (true) {
- if (currentNodeNum == dominatorNum)
- return true;
- if (currentNodeNum == this.sourceNum)
- return false;
- currentNodeNum = this.doms[currentNodeNum];
- }
- }
- private Dictionary<Node, List<Node>> domMap = null;
- [Pure]
- public override string ToString() {
- Contract.Assume(this.doms != null);
- int[] localDoms = this.doms;
- Contract.Assume(this.postOrderNumberToNode != null);
- if (domMap == null) {
- domMap = new Dictionary<Node, List<Node>>();
- for (int i = 1; i < localDoms.Length; i++) { // 0 slot is not used
- int domineeNum = i;
- int currentNodeNum = domineeNum;
- List<Node> dominators = new List<Node>();
- while (currentNodeNum != this.sourceNum) {
- dominators.Add(this.postOrderNumberToNode[currentNodeNum].Val);
- currentNodeNum = this.doms[currentNodeNum];
- }
- dominators.Add(this.postOrderNumberToNode[this.sourceNum].Val);
- domMap.Add(this.postOrderNumberToNode[i].Val, dominators);
- }
- }
- StringBuilder sb = new StringBuilder();
- sb.Append("{");
- bool first = true;
- foreach (KeyValuePair<Node, List<Node>> de in domMap) {
- if (!first)
- sb.Append(", ");
- Contract.Assert(!object.Equals(de.Key, default(Node)));
- sb.Append(de.Key.ToString());
- sb.Append("~>");
- sb.Append(ListToString(de.Value));
- first = false;
- }
- sb.Append("}");
- return sb.ToString();
- }
- private void PrintIntArray(int[] xs) {
- Console.Write("[");
- for (int i = 0; i < xs.Length; i++) {
- if (0 < i)
- Console.Write(", ");
- Console.Write(xs[i]);
- }
- Console.WriteLine("]");
- }
- public void PrintList<T>(IEnumerable<T> xs) {
- Console.Write("[");
- int i = 0;
- foreach (T/*!*/ x in xs) {
- Contract.Assert(x != null);
- if (0 < i)
- Console.Write(", ");
- Console.Write(x.ToString());
- i++;
- }
- Console.WriteLine("]");
- }
- public string/*!*/ ListToString<T>(IEnumerable<T> xs) {
- Contract.Ensures(Contract.Result<string>() != null);
- StringBuilder sb = new StringBuilder();
- sb.Append("[");
- bool first = true;
- foreach (T/*!*/ x in xs) {
- Contract.Assert(x != null);
- if (!first)
- sb.Append(", ");
- sb.Append(x.ToString());
- first = false;
- }
- sb.Append("]");
- return sb.ToString();
- }
-
- // Keith D. Cooper, Timothy J. Harvey, Ken Kennedy, "A Simple, Fast Dominance Algorithm ", Software Practice and Experience, 2001.
- // http://citeseer.ist.psu.edu/cooper01simple.html
- private void NewComputeDominators() {
- int n = this.graph.Nodes.Count;
- this.postOrderNumberToNode = new Maybe<Node>[n + 1];
- this.nodeToPostOrderNumber = new Dictionary<Node, int>();
- //HashSet<Node> visited = new HashSet<Node>();
- //int currentNumber = 1;
- Contract.Assume(this.source != null);
- //this.PostOrderVisit(this.source, visited, ref currentNumber);
- this.PostOrderVisitIterative(this.source);
- this.sourceNum = this.nodeToPostOrderNumber[source];
- // for (int i = 1; i <= n; i++){ Console.WriteLine(postOrderNumberToNode[i]); }
- this.doms = new int[n + 1]; // 0 is unused: means undefined
- Node start_node = this.source;
- this.doms[this.nodeToPostOrderNumber[start_node]] = this.nodeToPostOrderNumber[start_node];
- bool changed = true;
- // PrintIntArray(doms);
- while (changed) {
- changed = false;
- // for all nodes, b, in reverse postorder (except start_node)
- for (int nodeNum = n - 1; 1 <= nodeNum; nodeNum--) {
- Node b = this.postOrderNumberToNode[nodeNum].Val;
- IEnumerable<Node> predecessors = this.graph.Predecessors(b);
- // find a predecessor (i.e., a higher number) for which
- // the doms array has been set
- int new_idom = 0;
- int first_processed_predecessor = 0;
- #region new_idom <- number of first (processed) predecessor of b (pick one)
- foreach (Node p in predecessors) {
- if (this.doms[this.nodeToPostOrderNumber[p]] != 0) {
- int x = this.nodeToPostOrderNumber[p];
- new_idom = x;
- first_processed_predecessor = x;
- break;
- }
- }
- #endregion
- #region for all other predecessors, p, of b
- foreach (Node p in predecessors) {
- if (this.nodeToPostOrderNumber[p] == first_processed_predecessor) {
- continue;
- }
- if (this.doms[this.nodeToPostOrderNumber[p]] != 0)
- new_idom = intersect(this.nodeToPostOrderNumber[p], new_idom, this.doms);
- }
- #endregion
- if (this.doms[this.nodeToPostOrderNumber[b]] != new_idom) {
- this.doms[this.nodeToPostOrderNumber[b]] = new_idom;
- changed = true;
- }
- }
- }
- #region Populate the Immediate Dominator Map
- int sourceNum = this.nodeToPostOrderNumber[this.source];
- immediateDominatorMap = new Dictionary<Node, List<Node>>();
- for (int i = 1; i <= n; i++) {
- Node node = this.postOrderNumberToNode[i].Val;
- Node idomNode = this.postOrderNumberToNode[this.doms[i]].Val;
- if (i == sourceNum && this.doms[i] == sourceNum) {
- continue;
- }
- if (immediateDominatorMap.ContainsKey(idomNode)) {
- immediateDominatorMap[idomNode].Add(node);
- } else {
- List<Node> l = new List<Node>();
- l.Add(node);
- immediateDominatorMap.Add(idomNode, l);
- }
- }
- #endregion
- }
- private int intersect(int b1, int b2, int[] doms) {
- int finger1 = b1;
- int finger2 = b2;
- while (finger1 != finger2) {
- while (finger1 < finger2) {
- finger1 = doms[finger1];
- }
- while (finger2 < finger1) {
- finger2 = doms[finger2];
- }
- }
- return finger1;
- }
- private void PostOrderVisit(Node/*!*/ n, HashSet<Node> visited, ref int currentNumber) {
- Contract.Requires(n != null);
- if (visited.Contains(n))
- return;
- visited.Add(n);
- foreach (Node/*!*/ child in this.graph.Successors(n)) {
- Contract.Assert(child != null);
- PostOrderVisit(child, visited, ref currentNumber);
- }
- Contract.Assume(this.postOrderNumberToNode != null);
- Contract.Assume(this.nodeToPostOrderNumber != null);
- this.postOrderNumberToNode[currentNumber].Val = n;
- this.nodeToPostOrderNumber[n] = currentNumber;
- currentNumber++;
- return;
- }
- // Iterative version: mimics the above recursive procedure
- private void PostOrderVisitIterative(Node n)
- {
- Contract.Requires(n != null);
- var visited = new HashSet<Node>();
- var grey = new HashSet<Node>();
- var stack = new Stack<Node>();
-
- int currentNumber = 1;
-
- stack.Push(n);
- visited.Add(n);
-
- while (stack.Count != 0)
- {
- var curr = stack.Pop();
-
- if (grey.Contains(curr))
- {
- Contract.Assume(this.postOrderNumberToNode != null);
- Contract.Assume(this.nodeToPostOrderNumber != null);
- this.postOrderNumberToNode[currentNumber].Val = curr;
- this.nodeToPostOrderNumber[curr] = currentNumber;
- currentNumber++;
- }
- else
- {
- grey.Add(curr);
- stack.Push(curr);
- foreach (Node/*!*/ child in this.graph.Successors(curr))
- {
- Contract.Assert(child != null);
- if (!visited.Contains(child))
- {
- visited.Add(child);
- stack.Push(child);
- }
- }
- }
-
- }
-
-
- }
- }
-
- public class Graph<Node> {
- private HashSet<Tuple<Node/*!*/, Node/*!*/>> es;
- private HashSet<Node> ns;
- private Node source;
- private bool reducible;
- private HashSet<Node> headers;
- private Dictionary<Node, HashSet<Node>> backEdgeNodes;
- private Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>> naturalLoops;
- private HashSet<Node> splitCandidates;
-
- private DomRelation<Node> dominatorMap = null;
- private Dictionary<Node, HashSet<Node>> predCache = new Dictionary<Node, HashSet<Node>>();
- private Dictionary<Node, HashSet<Node>> succCache = new Dictionary<Node, HashSet<Node>>();
- private bool predComputed;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(es == null || Contract.ForAll(es, p => p.Item1 != null && p.Item2 != null));
- Contract.Invariant(naturalLoops == null || Contract.ForAll(naturalLoops.Keys, p => p.Item2 != null && p.Item1 != null));
- }
-
- private class PreHeader {
- Node/*!*/ myHeader;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(myHeader != null);
- }
-
- internal PreHeader(Node/*!*/ h) {
- Contract.Requires(h != null);
- myHeader = h;
- }
-
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- return "#" + myHeader.ToString();
- }
- }
-
- public Graph(HashSet<Tuple<Node/*!*/, Node/*!*/>> edges) {
-
- Contract.Requires(cce.NonNullElements(edges) && Contract.ForAll(edges, p => p.Item1 != null && p.Item2 != null));
- es = edges;
-
- // original A#
- //ns = Set<Node>{ x : <x,y> in es } + Set<Node>{ y : <x,y> in es };
-
- // closest Spec#
- //ns = new Set<Node>{ Tuple<Node,Node> p in edges; p.Item1 } + new Set<Node>{ Tuple<Node,Node> p in edges; p.Item2 };
-
- //
- HashSet<Node> temp = new HashSet<Node>();
- foreach (Tuple<Node/*!*/, Node/*!*/> p in edges) {
- Contract.Assert(p.Item1 != null);
- temp.Add(p.Item1);
- Contract.Assert(p.Item2 != null);
- temp.Add(p.Item2);
- }
- ns = temp;
- }
- public Graph() {
- es = new HashSet<Tuple<Node/*!*/, Node/*!*/>>();
- ns = new HashSet<Node>();
- }
-
- // BUGBUG: Set<T>.ToString() should return a non-null string
- [Pure]
- public override string/*!*/ ToString() {
- return "" + es.ToString();
- }
-
- public void AddSource(Node/*!*/ x) {
- Contract.Requires(x != null);
- // BUGBUG: This generates bad code in the compiler
- //ns += new Set<Node>{x};
- ns.Add(x);
- source = x;
- }
-
- public void AddEdge(Node/*!*/ source, Node/*!*/ dest) {
- Contract.Requires(source != null);
- Contract.Requires(dest != null);
- //es += Set<Edge>{<source,dest>};
- //ns += Set<Node>{source, dest};
- es.Add(new Tuple<Node/*!*/, Node/*!*/>(source, dest));
- ns.Add(source);
- ns.Add(dest);
- predComputed = false;
- }
-
- public HashSet<Node> Nodes {
- get {
- return ns;
- }
- }
- public IEnumerable<Tuple<Node/*!*/, Node/*!*/>> Edges {
- get {
- Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<Tuple<Node, Node>>>())
- && Contract.ForAll(Contract.Result<IEnumerable<Tuple<Node, Node>>>(), n =>
- n.Item1 != null && n.Item2 != null));
- return es;
- }
- }
-
- public bool Edge(Node/*!*/ x, Node/*!*/ y) {
- Contract.Requires(x != null);
- Contract.Requires(y != null);
- // original A#
- // return <x,y> in es;
- return es.Contains(new Tuple<Node/*!*/, Node/*!*/>(x, y));
- }
-
- private void ComputePredSuccCaches() {
- if (predComputed)
- return;
- predComputed = true;
- predCache = new Dictionary<Node, HashSet<Node>>();
- succCache = new Dictionary<Node, HashSet<Node>>();
-
- foreach (Node n in Nodes) {
- predCache[n] = new HashSet<Node>();
- succCache[n] = new HashSet<Node>();
- }
-
- foreach (Tuple<Node/*!*/, Node/*!*/> p in Edges) {
- Contract.Assert(p.Item1 != null);
- Contract.Assert(p.Item2 != null);
- HashSet<Node> tmp;
-
- tmp = predCache[p.Item2];
- tmp.Add(p.Item1);
- predCache[p.Item2] = tmp;
-
- tmp = succCache[p.Item1];
- tmp.Add(p.Item2);
- succCache[p.Item1] = tmp;
- }
- }
-
- public IEnumerable<Node> Predecessors(Node n) {
- // original A#
- //Set<Node> result = Set{ x : x in Nodes, Edge(x,n) };
-
- ComputePredSuccCaches();
- return predCache[n];
- }
-
- public IEnumerable<Node> Successors(Node n) {
- ComputePredSuccCaches();
- return succCache[n];
- }
-
- public List<Node> SuccessorsAsList(Node n) {
- ComputePredSuccCaches();
- List<Node> ret = new List<Node>();
- foreach (Node s in succCache[n])
- ret.Add(s);
- return ret;
- }
-
- internal DomRelation<Node> /*Map<Node,Set<Node>>*/ DominatorMap {
- get {
- Contract.Assert(source != null);
- if (this.dominatorMap == null) {
- this.dominatorMap = new DomRelation<Node>(this, this.source);
- }
- return this.dominatorMap;
- }
- }
-
- public Dictionary<Node, List<Node>> ImmediateDominatorMap {
- get {
- Contract.Assert(source != null);
- if (this.dominatorMap == null) {
- this.dominatorMap = new DomRelation<Node>(this, this.source);
- }
- return this.dominatorMap.ImmediateDominatorMap;
- }
- }
- public List<Node> ImmediatelyDominatedBy(Node/*!*/ n) {
- Contract.Requires(n != null);
- List<Node> dominees;
- this.ImmediateDominatorMap.TryGetValue(n, out dominees);
- return dominees == null ? new List<Node>() : dominees;
- }
-
- public IEnumerable<Node/*?*/> TopologicalSort() {
- bool acyclic;
- List<Node> sortedList;
- this.TarjanTopSort(out acyclic, out sortedList);
- return acyclic ? sortedList : new List<Node>();
- }
- // From Tarjan 1972
- public void TarjanTopSort(out bool acyclic, out List<Node> sortedNodes) {
- int n = this.Nodes.Count;
- if (n == 0) {
- acyclic = true;
- sortedNodes = new List<Node>();
- return;
- }
- int[] incomingEdges = new int[n];
- // need an arbitrary numbering for the nodes to use as indices into
- // the arrays used within this algorithm
- Dictionary<Node, int> nodeToNumber = new Dictionary<Node, int>(n);
- Maybe<Node>[] numberToNode = new Maybe<Node>[n];
- int counter = 0;
- foreach (Node node in this.Nodes) {
- numberToNode[counter].Val = node;
- nodeToNumber[node] = counter;
- counter++;
- }
- foreach (Tuple<Node/*!*/, Node/*!*/> e in this.Edges) {
- Contract.Assert(e.Item1 != null);
- Contract.Assert(e.Item2 != null);
- Node/*!*/ target = e.Item2;
- incomingEdges[nodeToNumber[target]]++;
- }
- List<Node> sorted = new List<Node>();
- int sortedIndex = 0;
- while (sortedIndex < n) {
- // find a root (i.e., its index)
- int rootIndex = -1;
- for (int i = 0; i < n; i++) {
- if (incomingEdges[i] == 0) {
- rootIndex = i;
- break;
- }
- }
- if (rootIndex == -1) {
- acyclic = false;
- sortedNodes = new List<Node>();
- return;
- }
- // mark root so it won't be used again
- incomingEdges[rootIndex] = -1;
- Node root = numberToNode[rootIndex].Val;
- sorted.Add(root);
- ++sortedIndex;
- foreach (Node s in this.Successors(root)) {
- incomingEdges[nodeToNumber[s]]--;
- }
- }
- acyclic = true;
- sortedNodes = sorted;
- return;
- }
- private IEnumerable<Node> OldTopologicalSort() {
- Tuple<bool, List<Node>> result = this.TopSort();
- return result.Item1 ? result.Item2 : (IEnumerable<Node>)new List<Node>();
- }
- // From AsmL distribution example
- private Tuple<bool, List<Node>> TopSort()
- {
- List<Node> S = new List<Node>();
- HashSet<Node> V = this.Nodes;
- HashSet<Node> X = new HashSet<Node>();
- foreach (Node/*!*/ n in V) {
- Contract.Assert(n != null);
- X.Add(n);
- }
- bool change = true;
- while (change)
- // invariant: X = V - S
- {
- change = false;
- if (X.Count > 0) {
- foreach (Node/*!*/ n in X) {
- Contract.Assert(n != null);
- // see if n has any incoming edges from any other node in X
- bool inDegreeZero = true;
- foreach (Node/*!*/ u in X) {
- Contract.Assert(u != null);
- if (this.Edge(u, n)) {
- inDegreeZero = false;
- break; // no point looking further
- }
- }
- if (inDegreeZero) {
- S.Add(n);
- X.Remove(n);
- change = true;
- break; // might as well go back and start looking through X from the beginning
- }
- }
- // Then we made it all the way through X without finding a source node
- if (!change) {
- return new Tuple<bool, List<Node>>(false, new List<Node>());
- }
- }
- }
- return new Tuple<bool, List<Node>>(true, S);
- }
-
- public static bool Acyclic(Graph<Node> g, Node source) {
- bool acyclic;
- List<Node> sortedList;
- g.TarjanTopSort(out acyclic, out sortedList);
- return acyclic;
- }
-
- // [Dragon, Fig. 10.15, p. 604. Algorithm for constructing the natural loop.]
- static HashSet<Node> NaturalLoop(Graph<Node> g, Tuple<Node/*!*/, Node/*!*/> backEdge)
- {
- Contract.Requires(backEdge.Item1 != null && backEdge.Item2 != null);
- Node/*!*/ n = backEdge.Item1;
- Node/*!*/ d = backEdge.Item2;
- Stack<Node> stack = new Stack<Node>();
- HashSet<Node> loop = new HashSet<Node>();
- loop.Add(d);
- if (!n.Equals(d)) // then n is not in loop
- {
- loop.Add(n);
- stack.Push(n); // push n onto stack
- }
- while (stack.Count > 0) // not empty
- {
- Node m = stack.Peek();
- stack.Pop(); // pop stack
- foreach (Node/*!*/ p in g.Predecessors(m)) {
- Contract.Assert(p != null);
- if (!(loop.Contains(p))) {
- loop.Add(p);
- stack.Push(p); // push p onto stack
- }
- }
- }
- return loop;
- }
-
- internal struct ReducibleResult {
- internal bool reducible;
- internal HashSet<Node> headers;
- internal Dictionary<Node, HashSet<Node>> backEdgeNodes;
- internal Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>> naturalLoops;
- internal HashSet<Node> splitCandidates;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Contract.ForAll(naturalLoops.Keys, p => p.Item1 != null && p.Item2 != null));
- }
-
- internal ReducibleResult(bool b, HashSet<Node> headers, Dictionary<Node, HashSet<Node>> backEdgeNodes, Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>> naturalLoops, HashSet<Node> splitCandidates)
- {
- Contract.Requires(naturalLoops == null || Contract.ForAll(naturalLoops.Keys, Key => Key.Item1 != null && Key.Item2 != null));
- this.reducible = b;
- this.headers = headers;
- this.backEdgeNodes = backEdgeNodes;
- this.naturalLoops = naturalLoops;
- this.splitCandidates = splitCandidates;
- }
-
- }
-
- // [Dragon, p. 606]
- static ReducibleResult ComputeReducible(Graph<Node> g, Node source) {
- // first, compute the dom relation
- DomRelation<Node> /*Map<Node,Set<Node>>*/ D = g.DominatorMap;
- return ComputeReducible(g, source, D);
- }
-
- static HashSet<Node> FindCycle(Graph<Node> g, Node source) {
- Stack<Tuple<Node, List<Node>>> stack = new Stack<Tuple<Node, List<Node>>>();
- HashSet<Node> stackAsSet = new HashSet<Node>();
- HashSet<Node> visited = new HashSet<Node>();
- stack.Push(new Tuple<Node, List<Node>>(source, g.SuccessorsAsList(source)));
- stackAsSet.Add(source);
- while (stack.Count > 0) {
- Tuple<Node, List<Node>> tuple = stack.Peek();
- List<Node> children = tuple.Item2;
- if (children.Count == 0) {
- stack.Pop();
- stackAsSet.Remove(tuple.Item1);
- continue;
- }
- Node n = children[0];
- children.RemoveAt(0);
- if (stackAsSet.Contains(n)) {
- HashSet<Node> ret = new HashSet<Node>();
- ret.Add(n);
- while (true) {
- Node x = stack.Pop().Item1;
- if (x.Equals(n))
- return ret;
- }
- }
- if (visited.Contains(n))
- continue;
- stack.Push(new Tuple<Node, List<Node>>(n, g.SuccessorsAsList(n)));
- visited.Add(n);
- stackAsSet.Add(n);
- System.Diagnostics.Debug.Assert(stack.Count == stackAsSet.Count);
- }
- return new HashSet<Node>();
- }
-
- // [Dragon, p. 606]
- static ReducibleResult ComputeReducible(Graph<Node> g,
- Node source,
- DomRelation<Node>/*!*/ DomRelation) {
- Contract.Requires(DomRelation != null);
-
- //Console.WriteLine("[" + DateTime.Now +"]: begin ComputeReducible");
- IEnumerable<Tuple<Node/*!*/, Node/*!*/>> edges = g.Edges;
- Contract.Assert(Contract.ForAll(edges, n => n.Item1 != null && n.Item2 != null));
- HashSet<Tuple<Node/*!*/, Node/*!*/>> backEdges = new HashSet<Tuple<Node/*!*/, Node/*!*/>>();
- HashSet<Tuple<Node/*!*/, Node/*!*/>> nonBackEdges = new HashSet<Tuple<Node/*!*/, Node/*!*/>>();
- foreach (Tuple<Node/*!*/, Node/*!*/> e in edges) {
- Contract.Assert(e.Item1 != null);
- Contract.Assert(e.Item2 != null);
- Node x = e.Item1;
- Node y = e.Item2; // so there is an edge from x to y
- if (DomRelation.DominatedBy(x, y)) { // y dom x: which means y dominates x
- backEdges.Add(e);
- } else {
- nonBackEdges.Add(e);
- }
- }
- Graph<Node> withoutBackEdges = new Graph<Node>(nonBackEdges);
- if (!Acyclic(withoutBackEdges, source)) {
- return new ReducibleResult(false,
- new HashSet<Node>(),
- new Dictionary<Node, HashSet<Node>>(),
- new Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>>(),
- FindCycle(withoutBackEdges, source));
- } else {
- // original A#:
- //Set<Node> headers = Set{ d : <n,d> in backEdges };
- HashSet<Node> headers = new HashSet<Node>();
- foreach (Tuple<Node/*!*/, Node/*!*/> e in backEdges) {
-
- Contract.Assert(e.Item1 != null);
- Contract.Assert(e.Item2 != null);
- headers.Add(e.Item2);
- }
- // original A#:
- //Map<Node,Set<Node>> backEdgeNodes = Map{ h -> bs : h in headers, bs = Set<Node>{ b : <b,x> in backEdges, x == h } };
- Dictionary<Node, HashSet<Node>> backEdgeNodes = new Dictionary<Node, HashSet<Node>>();
- foreach (Node/*!*/ h in headers) {
- Contract.Assert(h != null);
- HashSet<Node> bs = new HashSet<Node>();
- foreach (Tuple<Node, Node> backedge in backEdges) {
- Contract.Assert(backedge.Item1 != null);
- Contract.Assert(backedge.Item2 != null);
- if (backedge.Item2.Equals(h)) {
- bs.Add(backedge.Item1);
- }
- }
- backEdgeNodes.Add(h, bs);
- }
-
- // original A#:
- //Map<Tuple<Node,Node>,Set<Node>> naturalLoops = Map{ e -> NaturalLoop(g,e) : e in backEdges };
- Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>> naturalLoops = new Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>>();
- foreach (Tuple<Node/*!*/, Node/*!*/> e in backEdges) {
- Contract.Assert(e.Item1 != null && e.Item2 != null);
- naturalLoops.Add(e, NaturalLoop(g, e));
- }
-
- //Console.WriteLine("[" + DateTime.Now +"]: end ComputeReducible");
- return new ReducibleResult(true, headers, backEdgeNodes, naturalLoops, new HashSet<Node>());
- }
- }
-
- public bool Reducible {
- get {
- return reducible;
- }
- }
- public IEnumerable<Node> Headers {
- get {
- return headers;
- }
- }
- public IEnumerable<Node> BackEdgeNodes(Node/*!*/ h) {
- Contract.Requires(h != null);
- // original A#:
- //return h in backEdgeNodes ? backEdgeNodes[h] : null;
- return (backEdgeNodes.ContainsKey(h) ? backEdgeNodes[h] : (IEnumerable<Node>)new List<Node>());
- }
- public IEnumerable<Node> NaturalLoops(Node/*!*/ header, Node/*!*/ backEdgeNode) {
- Contract.Requires(header != null);
- Contract.Requires(backEdgeNode != null);
- Tuple<Node/*!*/, Node/*!*/> e = new Tuple<Node/*!*/, Node/*!*/>(backEdgeNode, header);
- return naturalLoops.ContainsKey(e) ? naturalLoops[e] : (IEnumerable<Node>)new List<Node>();
- }
- public HashSet<Node> SplitCandidates {
- get {
- return splitCandidates;
- }
- }
- public void ComputeLoops() {
- ReducibleResult r = ComputeReducible(this, this.source);
- this.reducible = r.reducible;
- this.headers = r.headers;
- this.backEdgeNodes = r.backEdgeNodes;
- this.naturalLoops = r.naturalLoops;
- this.splitCandidates = r.splitCandidates;
- return;
- }
-
- public IEnumerable<Node> SortHeadersByDominance()
- {
- Graph<Node> dag = new Graph<Node>();
- foreach (Node b in headers)
- {
- dag.AddSource(b);
- foreach (Node c in headers)
- {
- if (b.Equals(c)) continue;
- if (DominatorMap.DominatedBy(b, c))
- {
- System.Diagnostics.Debug.Assert(!DominatorMap.DominatedBy(c, b));
- dag.AddEdge(b, c);
- }
- }
- }
- return dag.TopologicalSort();
- }
-
- public string ToDot(Func<Node, string> NodeLabel = null, Func<Node, string> NodeStyle = null) {
- NodeLabel = NodeLabel ?? (n => n.ToString());
- NodeStyle = NodeStyle ?? (n => "[shape=box]");
- var s = new StringBuilder();
- s.AppendLine("digraph G {");
- foreach (var n in Nodes)
- s.AppendLine(" \"" + NodeLabel(n) + "\" " + NodeStyle(n) + ";");
- foreach (var e in Edges)
- s.AppendLine(" \"" + NodeLabel(e.Item1) + "\" -> \"" + NodeLabel(e.Item2) + "\";");
- s.AppendLine("}");
- return s.ToString();
- }
- } // end: class Graph
-
- public class GraphProgram {
- static void TestGraph<T>(T/*!*/ source, params Tuple<T/*!*/, T/*!*/>[] edges) {
- Contract.Requires(source != null);
- Contract.Requires(Contract.ForAll(edges, pair => pair.Item1 != null && pair.Item2 != null));
- HashSet<Tuple<T/*!*/, T/*!*/>> es = new HashSet<Tuple<T/*!*/, T/*!*/>>();
- foreach (Tuple<T/*!*/, T/*!*/> e in edges) {
- Contract.Assert(e.Item1 != null && e.Item2 != null);
- es.Add(e);
- }
- Graph<T> g = new Graph<T>(es);
- g.AddSource(source);
- Console.WriteLine("G = " + g);
- g.ComputeLoops();
- Console.WriteLine("G's Dominator Map = " + g.DominatorMap);
- Console.WriteLine("G's Immediate Dominator Map = " + Util.MapToString(g.ImmediateDominatorMap));
- Console.WriteLine("G is reducible: " + (g.Reducible ? "yes" : "no"));
- }
-
- static void Main(string[] args)
- //requires forall{string s in args; s != null};
- {
- Console.WriteLine("Spec# says hello!");
- // This generates bad IL -- need to fix a bug in the compiler
- //Graph<int> g = new Graph<int>(new Set<Tuple<int,int>>{ new Tuple<int,int>(1,2), new Tuple<int,int>(1,3), new Tuple<int,int>(2,3) });
-
- Console.WriteLine("");
- TestGraph<char>('a',
- new Tuple<char, char>('a', 'b'),
- new Tuple<char, char>('a', 'c'),
- new Tuple<char, char>('b', 'c')
- );
-
- Console.WriteLine("");
- TestGraph<char>('a',
- new Tuple<char, char>('a', 'b'),
- new Tuple<char, char>('a', 'c'),
- new Tuple<char, char>('b', 'd'),
- new Tuple<char, char>('c', 'e'),
- new Tuple<char, char>('c', 'f'),
- new Tuple<char, char>('d', 'e'),
- new Tuple<char, char>('e', 'd'),
- new Tuple<char, char>('e', 'f'),
- new Tuple<char, char>('f', 'e')
- );
-
- Console.WriteLine("");
- TestGraph<char>('a',
- new Tuple<char, char>('a', 'b'),
- new Tuple<char, char>('a', 'c'),
- new Tuple<char, char>('b', 'c'),
- new Tuple<char, char>('c', 'b')
- );
-
- Console.WriteLine("");
- TestGraph<int>(1,
- new Tuple<int, int>(1, 2),
- new Tuple<int, int>(1, 3),
- new Tuple<int, int>(2, 3)
- );
-
- Console.WriteLine("");
- TestGraph<int>(1,
- new Tuple<int, int>(1, 2),
- new Tuple<int, int>(1, 3),
- new Tuple<int, int>(2, 3),
- new Tuple<int, int>(3, 2)
- );
-
- Console.WriteLine("");
- TestGraph<int>(2,
- new Tuple<int, int>(2, 3),
- new Tuple<int, int>(2, 4),
- new Tuple<int, int>(3, 2)
- );
-
- Console.WriteLine("");
- TestGraph<char>('a',
- new Tuple<char, char>('a', 'b'),
- new Tuple<char, char>('a', 'c'),
- new Tuple<char, char>('b', 'c'),
- new Tuple<char, char>('b', 'b')
- );
-
-
- }
- }
-
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Collections.Generic;
+using System.Text; // for StringBuilder
+using System.Diagnostics.Contracts;
+namespace Graphing {
+
+ internal static class Util {
+ private static string/*!*/ ListToString<T>(IEnumerable<T> xs) {
+ Contract.Ensures(Contract.Result<string>() != null);
+ StringBuilder sb = new StringBuilder();
+ sb.Append("[");
+ bool first = true;
+ foreach (T/*!*/ x in xs) {
+ Contract.Assert(x != null);
+ if (!first)
+ sb.Append(", ");
+ sb.Append(x.ToString());
+ first = false;
+ }
+ sb.Append("]");
+ return sb.ToString();
+ }
+ public static string/*!*/ MapToString<Node>(Dictionary<Node, List<Node>> d) {
+ Contract.Ensures(Contract.Result<string>() != null);
+ StringBuilder sb = new StringBuilder();
+ sb.Append("{");
+ bool first = true;
+ foreach (KeyValuePair<Node, List<Node>> de in d) {
+ if (!first)
+ sb.Append(", ");
+ Contract.Assert(!object.Equals(de.Key,default(Node)));
+ sb.Append(de.Key.ToString());
+ sb.Append("~>");
+ sb.Append(ListToString(de.Value));
+ first = false;
+ }
+ sb.Append("}");
+ return sb.ToString();
+ }
+ }
+
+ // own struct to represent possibly undefined values, because Mono does
+ // not like arrays with element type T! or T?
+ public struct Maybe<T> {
+ private T Value;
+ public bool IsSet; // initialised with false by the default ctor
+ public T Val {
+ get {
+ Contract.Assume(IsSet);
+ return Value;
+ }
+ set {
+ Value = value;
+ IsSet = true;
+ }
+ }
+ public void UnSet() {
+ IsSet = false;
+ }
+ }
+
+ public class DomRelation<Node> {
+ // doms maps (unique) node numbers to the node numbers of the immediate dominator
+ // to use it on Nodes, one needs the two way mapping between nodes and their numbers.
+ private int[] doms; // 0 is unused: means undefined
+ // here are the two mappings
+ private Maybe<Node>[] postOrderNumberToNode;
+ private Dictionary<Node, int> nodeToPostOrderNumber;
+ private int sourceNum; // (number for) root of the graph
+ private Node source; // root of the graph
+ private Graph<Node> graph;
+ private Dictionary<Node, List<Node>> immediateDominatorMap;
+
+ [NotDelayed]
+ internal DomRelation(Graph<Node> g, Node source) {
+ this.graph = g;
+ // slot 0 not used: nodes are numbered from 1 to n so zero
+ // can represent undefined.
+ this.source = source;
+ //:base();
+ this.NewComputeDominators();
+ }
+ public Dictionary<Node, List<Node>> ImmediateDominatorMap {
+ get {
+ Contract.Assume(this.immediateDominatorMap != null);
+ return this.immediateDominatorMap;
+ }
+ }
+ public bool DominatedBy(Node dominee, Node dominator, List<Node> path = null) {
+ Contract.Assume(this.nodeToPostOrderNumber != null);
+ Contract.Assume(this.doms != null);
+ int domineeNum = this.nodeToPostOrderNumber[dominee];
+ int dominatorNum = this.nodeToPostOrderNumber[dominator];
+ if (domineeNum == dominatorNum)
+ return true;
+ int currentNodeNum = this.doms[domineeNum];
+ while (true) {
+ if (currentNodeNum == dominatorNum)
+ return true;
+ if (currentNodeNum == this.sourceNum)
+ return false;
+ if (path != null)
+ path.Add(postOrderNumberToNode[currentNodeNum].Val);
+ currentNodeNum = this.doms[currentNodeNum];
+ }
+ }
+ private Dictionary<Node, List<Node>> domMap = null;
+ [Pure]
+ public override string ToString() {
+ Contract.Assume(this.doms != null);
+ int[] localDoms = this.doms;
+ Contract.Assume(this.postOrderNumberToNode != null);
+ if (domMap == null) {
+ domMap = new Dictionary<Node, List<Node>>();
+ for (int i = 1; i < localDoms.Length; i++) { // 0 slot is not used
+ int domineeNum = i;
+ int currentNodeNum = domineeNum;
+ List<Node> dominators = new List<Node>();
+ while (currentNodeNum != this.sourceNum) {
+ dominators.Add(this.postOrderNumberToNode[currentNodeNum].Val);
+ currentNodeNum = this.doms[currentNodeNum];
+ }
+ dominators.Add(this.postOrderNumberToNode[this.sourceNum].Val);
+ domMap.Add(this.postOrderNumberToNode[i].Val, dominators);
+ }
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.Append("{");
+ bool first = true;
+ foreach (KeyValuePair<Node, List<Node>> de in domMap) {
+ if (!first)
+ sb.Append(", ");
+ Contract.Assert(!object.Equals(de.Key, default(Node)));
+ sb.Append(de.Key.ToString());
+ sb.Append("~>");
+ sb.Append(ListToString(de.Value));
+ first = false;
+ }
+ sb.Append("}");
+ return sb.ToString();
+ }
+ private void PrintIntArray(int[] xs) {
+ Console.Write("[");
+ for (int i = 0; i < xs.Length; i++) {
+ if (0 < i)
+ Console.Write(", ");
+ Console.Write(xs[i]);
+ }
+ Console.WriteLine("]");
+ }
+ public void PrintList<T>(IEnumerable<T> xs) {
+ Console.Write("[");
+ int i = 0;
+ foreach (T/*!*/ x in xs) {
+ Contract.Assert(x != null);
+ if (0 < i)
+ Console.Write(", ");
+ Console.Write(x.ToString());
+ i++;
+ }
+ Console.WriteLine("]");
+ }
+ public string/*!*/ ListToString<T>(IEnumerable<T> xs) {
+ Contract.Ensures(Contract.Result<string>() != null);
+ StringBuilder sb = new StringBuilder();
+ sb.Append("[");
+ bool first = true;
+ foreach (T/*!*/ x in xs) {
+ Contract.Assert(x != null);
+ if (!first)
+ sb.Append(", ");
+ sb.Append(x.ToString());
+ first = false;
+ }
+ sb.Append("]");
+ return sb.ToString();
+ }
+
+ // Keith D. Cooper, Timothy J. Harvey, Ken Kennedy, "A Simple, Fast Dominance Algorithm ", Software Practice and Experience, 2001.
+ // http://citeseer.ist.psu.edu/cooper01simple.html
+ private void NewComputeDominators() {
+ int n = this.graph.Nodes.Count;
+ this.postOrderNumberToNode = new Maybe<Node>[n + 1];
+ this.nodeToPostOrderNumber = new Dictionary<Node, int>();
+ //HashSet<Node> visited = new HashSet<Node>();
+ //int currentNumber = 1;
+ Contract.Assume(this.source != null);
+ //this.PostOrderVisit(this.source, visited, ref currentNumber);
+ this.PostOrderVisitIterative(this.source);
+ this.sourceNum = this.nodeToPostOrderNumber[source];
+ // for (int i = 1; i <= n; i++){ Console.WriteLine(postOrderNumberToNode[i]); }
+ this.doms = new int[n + 1]; // 0 is unused: means undefined
+ Node start_node = this.source;
+ this.doms[this.nodeToPostOrderNumber[start_node]] = this.nodeToPostOrderNumber[start_node];
+ bool changed = true;
+ // PrintIntArray(doms);
+ while (changed) {
+ changed = false;
+ // for all nodes, b, in reverse postorder (except start_node)
+ for (int nodeNum = n - 1; 1 <= nodeNum; nodeNum--) {
+ Node b = this.postOrderNumberToNode[nodeNum].Val;
+ IEnumerable<Node> predecessors = this.graph.Predecessors(b);
+ // find a predecessor (i.e., a higher number) for which
+ // the doms array has been set
+ int new_idom = 0;
+ int first_processed_predecessor = 0;
+ #region new_idom <- number of first (processed) predecessor of b (pick one)
+ foreach (Node p in predecessors) {
+ if (this.doms[this.nodeToPostOrderNumber[p]] != 0) {
+ int x = this.nodeToPostOrderNumber[p];
+ new_idom = x;
+ first_processed_predecessor = x;
+ break;
+ }
+ }
+ #endregion
+ #region for all other predecessors, p, of b
+ foreach (Node p in predecessors) {
+ if (this.nodeToPostOrderNumber[p] == first_processed_predecessor) {
+ continue;
+ }
+ if (this.doms[this.nodeToPostOrderNumber[p]] != 0)
+ new_idom = intersect(this.nodeToPostOrderNumber[p], new_idom, this.doms);
+ }
+ #endregion
+ if (this.doms[this.nodeToPostOrderNumber[b]] != new_idom) {
+ this.doms[this.nodeToPostOrderNumber[b]] = new_idom;
+ changed = true;
+ }
+ }
+ }
+ #region Populate the Immediate Dominator Map
+ int sourceNum = this.nodeToPostOrderNumber[this.source];
+ immediateDominatorMap = new Dictionary<Node, List<Node>>();
+ for (int i = 1; i <= n; i++) {
+ Node node = this.postOrderNumberToNode[i].Val;
+ Node idomNode = this.postOrderNumberToNode[this.doms[i]].Val;
+ if (i == sourceNum && this.doms[i] == sourceNum) {
+ continue;
+ }
+ if (immediateDominatorMap.ContainsKey(idomNode)) {
+ immediateDominatorMap[idomNode].Add(node);
+ } else {
+ List<Node> l = new List<Node>();
+ l.Add(node);
+ immediateDominatorMap.Add(idomNode, l);
+ }
+ }
+ #endregion
+ }
+ private int intersect(int b1, int b2, int[] doms) {
+ int finger1 = b1;
+ int finger2 = b2;
+ while (finger1 != finger2) {
+ while (finger1 < finger2) {
+ finger1 = doms[finger1];
+ }
+ while (finger2 < finger1) {
+ finger2 = doms[finger2];
+ }
+ }
+ return finger1;
+ }
+ private void PostOrderVisit(Node/*!*/ n, HashSet<Node> visited, ref int currentNumber) {
+ Contract.Requires(n != null);
+ if (visited.Contains(n))
+ return;
+ visited.Add(n);
+ foreach (Node/*!*/ child in this.graph.Successors(n)) {
+ Contract.Assert(child != null);
+ PostOrderVisit(child, visited, ref currentNumber);
+ }
+ Contract.Assume(this.postOrderNumberToNode != null);
+ Contract.Assume(this.nodeToPostOrderNumber != null);
+ this.postOrderNumberToNode[currentNumber].Val = n;
+ this.nodeToPostOrderNumber[n] = currentNumber;
+ currentNumber++;
+ return;
+ }
+ // Iterative version: mimics the above recursive procedure
+ private void PostOrderVisitIterative(Node n)
+ {
+ Contract.Requires(n != null);
+ var visited = new HashSet<Node>();
+ var grey = new HashSet<Node>();
+ var stack = new Stack<Node>();
+
+ int currentNumber = 1;
+
+ stack.Push(n);
+ visited.Add(n);
+
+ while (stack.Count != 0)
+ {
+ var curr = stack.Pop();
+
+ if (grey.Contains(curr))
+ {
+ Contract.Assume(this.postOrderNumberToNode != null);
+ Contract.Assume(this.nodeToPostOrderNumber != null);
+ this.postOrderNumberToNode[currentNumber].Val = curr;
+ this.nodeToPostOrderNumber[curr] = currentNumber;
+ currentNumber++;
+ }
+ else
+ {
+ grey.Add(curr);
+ stack.Push(curr);
+ foreach (Node/*!*/ child in this.graph.Successors(curr))
+ {
+ Contract.Assert(child != null);
+ if (!visited.Contains(child))
+ {
+ visited.Add(child);
+ stack.Push(child);
+ }
+ }
+ }
+
+ }
+
+
+ }
+
+ public Node LeastCommonAncestor(Node n1, Node n2)
+ {
+ var nums = new HashSet<int>();
+ int num1 = nodeToPostOrderNumber[n1], num2 = nodeToPostOrderNumber[n2];
+
+ while (true)
+ {
+ if (!nums.Add(num1))
+ return postOrderNumberToNode[num1].Val;
+ if (!nums.Add(num2))
+ return postOrderNumberToNode[num2].Val;
+ num1 = doms[num1]; num2 = doms[num2];
+ }
+ }
+ }
+
+ public class Graph<Node> {
+ private HashSet<Tuple<Node/*!*/, Node/*!*/>> es;
+ private HashSet<Node> ns;
+ private Node source;
+ private bool reducible;
+ private HashSet<Node> headers;
+ private Dictionary<Node, HashSet<Node>> backEdgeNodes;
+ private Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>> naturalLoops;
+ private HashSet<Node> splitCandidates;
+
+ private DomRelation<Node> dominatorMap = null;
+ private Dictionary<Node, HashSet<Node>> predCache = new Dictionary<Node, HashSet<Node>>();
+ private Dictionary<Node, HashSet<Node>> succCache = new Dictionary<Node, HashSet<Node>>();
+ private bool predComputed;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(es == null || Contract.ForAll(es, p => p.Item1 != null && p.Item2 != null));
+ Contract.Invariant(naturalLoops == null || Contract.ForAll(naturalLoops.Keys, p => p.Item2 != null && p.Item1 != null));
+ }
+
+ private class PreHeader {
+ Node/*!*/ myHeader;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(myHeader != null);
+ }
+
+ internal PreHeader(Node/*!*/ h) {
+ Contract.Requires(h != null);
+ myHeader = h;
+ }
+
+ [Pure]
+ public override string/*!*/ ToString() {
+ Contract.Ensures(Contract.Result<string>() != null);
+ return "#" + myHeader.ToString();
+ }
+ }
+
+ public Graph(HashSet<Tuple<Node/*!*/, Node/*!*/>> edges) {
+
+ Contract.Requires(cce.NonNullElements(edges) && Contract.ForAll(edges, p => p.Item1 != null && p.Item2 != null));
+ es = edges;
+
+ // original A#
+ //ns = Set<Node>{ x : <x,y> in es } + Set<Node>{ y : <x,y> in es };
+
+ // closest Spec#
+ //ns = new Set<Node>{ Tuple<Node,Node> p in edges; p.Item1 } + new Set<Node>{ Tuple<Node,Node> p in edges; p.Item2 };
+
+ //
+ HashSet<Node> temp = new HashSet<Node>();
+ foreach (Tuple<Node/*!*/, Node/*!*/> p in edges) {
+ Contract.Assert(p.Item1 != null);
+ temp.Add(p.Item1);
+ Contract.Assert(p.Item2 != null);
+ temp.Add(p.Item2);
+ }
+ ns = temp;
+ }
+ public Graph() {
+ es = new HashSet<Tuple<Node/*!*/, Node/*!*/>>();
+ ns = new HashSet<Node>();
+ }
+
+ // BUGBUG: Set<T>.ToString() should return a non-null string
+ [Pure]
+ public override string/*!*/ ToString() {
+ return "" + es.ToString();
+ }
+
+ public void AddSource(Node/*!*/ x) {
+ Contract.Requires(x != null);
+ // BUGBUG: This generates bad code in the compiler
+ //ns += new Set<Node>{x};
+ ns.Add(x);
+ source = x;
+ }
+
+ public void AddEdge(Node/*!*/ source, Node/*!*/ dest) {
+ Contract.Requires(source != null);
+ Contract.Requires(dest != null);
+ //es += Set<Edge>{<source,dest>};
+ //ns += Set<Node>{source, dest};
+ es.Add(new Tuple<Node/*!*/, Node/*!*/>(source, dest));
+ ns.Add(source);
+ ns.Add(dest);
+ predComputed = false;
+ }
+
+ public HashSet<Node> Nodes {
+ get {
+ return ns;
+ }
+ }
+ public IEnumerable<Tuple<Node/*!*/, Node/*!*/>> Edges {
+ get {
+ Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<Tuple<Node, Node>>>())
+ && Contract.ForAll(Contract.Result<IEnumerable<Tuple<Node, Node>>>(), n =>
+ n.Item1 != null && n.Item2 != null));
+ return es;
+ }
+ }
+
+ public bool Edge(Node/*!*/ x, Node/*!*/ y) {
+ Contract.Requires(x != null);
+ Contract.Requires(y != null);
+ // original A#
+ // return <x,y> in es;
+ return es.Contains(new Tuple<Node/*!*/, Node/*!*/>(x, y));
+ }
+
+ private void ComputePredSuccCaches() {
+ if (predComputed)
+ return;
+ predComputed = true;
+ predCache = new Dictionary<Node, HashSet<Node>>();
+ succCache = new Dictionary<Node, HashSet<Node>>();
+
+ foreach (Node n in Nodes) {
+ predCache[n] = new HashSet<Node>();
+ succCache[n] = new HashSet<Node>();
+ }
+
+ foreach (Tuple<Node/*!*/, Node/*!*/> p in Edges) {
+ Contract.Assert(p.Item1 != null);
+ Contract.Assert(p.Item2 != null);
+ HashSet<Node> tmp;
+
+ tmp = predCache[p.Item2];
+ tmp.Add(p.Item1);
+ predCache[p.Item2] = tmp;
+
+ tmp = succCache[p.Item1];
+ tmp.Add(p.Item2);
+ succCache[p.Item1] = tmp;
+ }
+ }
+
+ public IEnumerable<Node> Predecessors(Node n) {
+ // original A#
+ //Set<Node> result = Set{ x : x in Nodes, Edge(x,n) };
+
+ ComputePredSuccCaches();
+ return predCache[n];
+ }
+
+ public IEnumerable<Node> Successors(Node n) {
+ ComputePredSuccCaches();
+ return succCache[n];
+ }
+
+ public List<Node> SuccessorsAsList(Node n) {
+ ComputePredSuccCaches();
+ List<Node> ret = new List<Node>();
+ foreach (Node s in succCache[n])
+ ret.Add(s);
+ return ret;
+ }
+
+ public DomRelation<Node> /*Map<Node,Set<Node>>*/ DominatorMap {
+ get {
+ Contract.Assert(source != null);
+ if (this.dominatorMap == null) {
+ this.dominatorMap = new DomRelation<Node>(this, this.source);
+ }
+ return this.dominatorMap;
+ }
+ }
+
+ public Dictionary<Node, List<Node>> ImmediateDominatorMap {
+ get {
+ Contract.Assert(source != null);
+ if (this.dominatorMap == null) {
+ this.dominatorMap = new DomRelation<Node>(this, this.source);
+ }
+ return this.dominatorMap.ImmediateDominatorMap;
+ }
+ }
+ public List<Node> ImmediatelyDominatedBy(Node/*!*/ n) {
+ Contract.Requires(n != null);
+ List<Node> dominees;
+ this.ImmediateDominatorMap.TryGetValue(n, out dominees);
+ return dominees == null ? new List<Node>() : dominees;
+ }
+
+ public IEnumerable<Node/*?*/> TopologicalSort() {
+ bool acyclic;
+ List<Node> sortedList;
+ this.TarjanTopSort(out acyclic, out sortedList);
+ return acyclic ? sortedList : new List<Node>();
+ }
+ // From Tarjan 1972
+ public void TarjanTopSort(out bool acyclic, out List<Node> sortedNodes) {
+ int n = this.Nodes.Count;
+ if (n == 0) {
+ acyclic = true;
+ sortedNodes = new List<Node>();
+ return;
+ }
+ int[] incomingEdges = new int[n];
+ // need an arbitrary numbering for the nodes to use as indices into
+ // the arrays used within this algorithm
+ Dictionary<Node, int> nodeToNumber = new Dictionary<Node, int>(n);
+ Maybe<Node>[] numberToNode = new Maybe<Node>[n];
+ int counter = 0;
+ foreach (Node node in this.Nodes) {
+ numberToNode[counter].Val = node;
+ nodeToNumber[node] = counter;
+ counter++;
+ }
+ foreach (Tuple<Node/*!*/, Node/*!*/> e in this.Edges) {
+ Contract.Assert(e.Item1 != null);
+ Contract.Assert(e.Item2 != null);
+ Node/*!*/ target = e.Item2;
+ incomingEdges[nodeToNumber[target]]++;
+ }
+ List<Node> sorted = new List<Node>();
+ int sortedIndex = 0;
+ while (sortedIndex < n) {
+ // find a root (i.e., its index)
+ int rootIndex = -1;
+ for (int i = 0; i < n; i++) {
+ if (incomingEdges[i] == 0) {
+ rootIndex = i;
+ break;
+ }
+ }
+ if (rootIndex == -1) {
+ acyclic = false;
+ sortedNodes = new List<Node>();
+ return;
+ }
+ // mark root so it won't be used again
+ incomingEdges[rootIndex] = -1;
+ Node root = numberToNode[rootIndex].Val;
+ sorted.Add(root);
+ ++sortedIndex;
+ foreach (Node s in this.Successors(root)) {
+ incomingEdges[nodeToNumber[s]]--;
+ }
+ }
+ acyclic = true;
+ sortedNodes = sorted;
+ return;
+ }
+ private IEnumerable<Node> OldTopologicalSort() {
+ Tuple<bool, List<Node>> result = this.TopSort();
+ return result.Item1 ? result.Item2 : (IEnumerable<Node>)new List<Node>();
+ }
+ // From AsmL distribution example
+ private Tuple<bool, List<Node>> TopSort()
+ {
+ List<Node> S = new List<Node>();
+ HashSet<Node> V = this.Nodes;
+ HashSet<Node> X = new HashSet<Node>();
+ foreach (Node/*!*/ n in V) {
+ Contract.Assert(n != null);
+ X.Add(n);
+ }
+ bool change = true;
+ while (change)
+ // invariant: X = V - S
+ {
+ change = false;
+ if (X.Count > 0) {
+ foreach (Node/*!*/ n in X) {
+ Contract.Assert(n != null);
+ // see if n has any incoming edges from any other node in X
+ bool inDegreeZero = true;
+ foreach (Node/*!*/ u in X) {
+ Contract.Assert(u != null);
+ if (this.Edge(u, n)) {
+ inDegreeZero = false;
+ break; // no point looking further
+ }
+ }
+ if (inDegreeZero) {
+ S.Add(n);
+ X.Remove(n);
+ change = true;
+ break; // might as well go back and start looking through X from the beginning
+ }
+ }
+ // Then we made it all the way through X without finding a source node
+ if (!change) {
+ return new Tuple<bool, List<Node>>(false, new List<Node>());
+ }
+ }
+ }
+ return new Tuple<bool, List<Node>>(true, S);
+ }
+
+ public static bool Acyclic(Graph<Node> g, Node source) {
+ bool acyclic;
+ List<Node> sortedList;
+ g.TarjanTopSort(out acyclic, out sortedList);
+ return acyclic;
+ }
+
+ // [Dragon, Fig. 10.15, p. 604. Algorithm for constructing the natural loop.]
+ static HashSet<Node> NaturalLoop(Graph<Node> g, Tuple<Node/*!*/, Node/*!*/> backEdge)
+ {
+ Contract.Requires(backEdge.Item1 != null && backEdge.Item2 != null);
+ Node/*!*/ n = backEdge.Item1;
+ Node/*!*/ d = backEdge.Item2;
+ Stack<Node> stack = new Stack<Node>();
+ HashSet<Node> loop = new HashSet<Node>();
+ loop.Add(d);
+ if (!n.Equals(d)) // then n is not in loop
+ {
+ loop.Add(n);
+ stack.Push(n); // push n onto stack
+ }
+ while (stack.Count > 0) // not empty
+ {
+ Node m = stack.Peek();
+ stack.Pop(); // pop stack
+ foreach (Node/*!*/ p in g.Predecessors(m)) {
+ Contract.Assert(p != null);
+ if (!(loop.Contains(p))) {
+ loop.Add(p);
+ stack.Push(p); // push p onto stack
+ }
+ }
+ }
+ return loop;
+ }
+
+ internal struct ReducibleResult {
+ internal bool reducible;
+ internal HashSet<Node> headers;
+ internal Dictionary<Node, HashSet<Node>> backEdgeNodes;
+ internal Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>> naturalLoops;
+ internal HashSet<Node> splitCandidates;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Contract.ForAll(naturalLoops.Keys, p => p.Item1 != null && p.Item2 != null));
+ }
+
+ internal ReducibleResult(bool b, HashSet<Node> headers, Dictionary<Node, HashSet<Node>> backEdgeNodes, Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>> naturalLoops, HashSet<Node> splitCandidates)
+ {
+ Contract.Requires(naturalLoops == null || Contract.ForAll(naturalLoops.Keys, Key => Key.Item1 != null && Key.Item2 != null));
+ this.reducible = b;
+ this.headers = headers;
+ this.backEdgeNodes = backEdgeNodes;
+ this.naturalLoops = naturalLoops;
+ this.splitCandidates = splitCandidates;
+ }
+
+ }
+
+ // [Dragon, p. 606]
+ static ReducibleResult ComputeReducible(Graph<Node> g, Node source) {
+ // first, compute the dom relation
+ DomRelation<Node> /*Map<Node,Set<Node>>*/ D = g.DominatorMap;
+ return ComputeReducible(g, source, D);
+ }
+
+ static HashSet<Node> FindCycle(Graph<Node> g, Node source) {
+ Stack<Tuple<Node, List<Node>>> stack = new Stack<Tuple<Node, List<Node>>>();
+ HashSet<Node> stackAsSet = new HashSet<Node>();
+ HashSet<Node> visited = new HashSet<Node>();
+ stack.Push(new Tuple<Node, List<Node>>(source, g.SuccessorsAsList(source)));
+ stackAsSet.Add(source);
+ while (stack.Count > 0) {
+ Tuple<Node, List<Node>> tuple = stack.Peek();
+ List<Node> children = tuple.Item2;
+ if (children.Count == 0) {
+ stack.Pop();
+ stackAsSet.Remove(tuple.Item1);
+ continue;
+ }
+ Node n = children[0];
+ children.RemoveAt(0);
+ if (stackAsSet.Contains(n)) {
+ HashSet<Node> ret = new HashSet<Node>();
+ ret.Add(n);
+ while (true) {
+ Node x = stack.Pop().Item1;
+ if (x.Equals(n))
+ return ret;
+ }
+ }
+ if (visited.Contains(n))
+ continue;
+ stack.Push(new Tuple<Node, List<Node>>(n, g.SuccessorsAsList(n)));
+ visited.Add(n);
+ stackAsSet.Add(n);
+ System.Diagnostics.Debug.Assert(stack.Count == stackAsSet.Count);
+ }
+ return new HashSet<Node>();
+ }
+
+ // [Dragon, p. 606]
+ static ReducibleResult ComputeReducible(Graph<Node> g,
+ Node source,
+ DomRelation<Node>/*!*/ DomRelation) {
+ Contract.Requires(DomRelation != null);
+
+ //Console.WriteLine("[" + DateTime.Now +"]: begin ComputeReducible");
+ IEnumerable<Tuple<Node/*!*/, Node/*!*/>> edges = g.Edges;
+ Contract.Assert(Contract.ForAll(edges, n => n.Item1 != null && n.Item2 != null));
+ HashSet<Tuple<Node/*!*/, Node/*!*/>> backEdges = new HashSet<Tuple<Node/*!*/, Node/*!*/>>();
+ HashSet<Tuple<Node/*!*/, Node/*!*/>> nonBackEdges = new HashSet<Tuple<Node/*!*/, Node/*!*/>>();
+ foreach (Tuple<Node/*!*/, Node/*!*/> e in edges) {
+ Contract.Assert(e.Item1 != null);
+ Contract.Assert(e.Item2 != null);
+ Node x = e.Item1;
+ Node y = e.Item2; // so there is an edge from x to y
+ if (DomRelation.DominatedBy(x, y)) { // y dom x: which means y dominates x
+ backEdges.Add(e);
+ } else {
+ nonBackEdges.Add(e);
+ }
+ }
+ Graph<Node> withoutBackEdges = new Graph<Node>(nonBackEdges);
+ if (!Acyclic(withoutBackEdges, source)) {
+ return new ReducibleResult(false,
+ new HashSet<Node>(),
+ new Dictionary<Node, HashSet<Node>>(),
+ new Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>>(),
+ FindCycle(withoutBackEdges, source));
+ } else {
+ // original A#:
+ //Set<Node> headers = Set{ d : <n,d> in backEdges };
+ HashSet<Node> headers = new HashSet<Node>();
+ foreach (Tuple<Node/*!*/, Node/*!*/> e in backEdges) {
+
+ Contract.Assert(e.Item1 != null);
+ Contract.Assert(e.Item2 != null);
+ headers.Add(e.Item2);
+ }
+ // original A#:
+ //Map<Node,Set<Node>> backEdgeNodes = Map{ h -> bs : h in headers, bs = Set<Node>{ b : <b,x> in backEdges, x == h } };
+ Dictionary<Node, HashSet<Node>> backEdgeNodes = new Dictionary<Node, HashSet<Node>>();
+ foreach (Node/*!*/ h in headers) {
+ Contract.Assert(h != null);
+ HashSet<Node> bs = new HashSet<Node>();
+ foreach (Tuple<Node, Node> backedge in backEdges) {
+ Contract.Assert(backedge.Item1 != null);
+ Contract.Assert(backedge.Item2 != null);
+ if (backedge.Item2.Equals(h)) {
+ bs.Add(backedge.Item1);
+ }
+ }
+ backEdgeNodes.Add(h, bs);
+ }
+
+ // original A#:
+ //Map<Tuple<Node,Node>,Set<Node>> naturalLoops = Map{ e -> NaturalLoop(g,e) : e in backEdges };
+ Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>> naturalLoops = new Dictionary<Tuple<Node/*!*/, Node/*!*/>, HashSet<Node>>();
+ foreach (Tuple<Node/*!*/, Node/*!*/> e in backEdges) {
+ Contract.Assert(e.Item1 != null && e.Item2 != null);
+ naturalLoops.Add(e, NaturalLoop(g, e));
+ }
+
+ //Console.WriteLine("[" + DateTime.Now +"]: end ComputeReducible");
+ return new ReducibleResult(true, headers, backEdgeNodes, naturalLoops, new HashSet<Node>());
+ }
+ }
+
+ public bool Reducible {
+ get {
+ return reducible;
+ }
+ }
+ public IEnumerable<Node> Headers {
+ get {
+ return headers;
+ }
+ }
+ public IEnumerable<Node> BackEdgeNodes(Node/*!*/ h) {
+ Contract.Requires(h != null);
+ // original A#:
+ //return h in backEdgeNodes ? backEdgeNodes[h] : null;
+ return (backEdgeNodes.ContainsKey(h) ? backEdgeNodes[h] : (IEnumerable<Node>)new List<Node>());
+ }
+ public IEnumerable<Node> NaturalLoops(Node/*!*/ header, Node/*!*/ backEdgeNode) {
+ Contract.Requires(header != null);
+ Contract.Requires(backEdgeNode != null);
+ Tuple<Node/*!*/, Node/*!*/> e = new Tuple<Node/*!*/, Node/*!*/>(backEdgeNode, header);
+ return naturalLoops.ContainsKey(e) ? naturalLoops[e] : (IEnumerable<Node>)new List<Node>();
+ }
+ public HashSet<Node> SplitCandidates {
+ get {
+ return splitCandidates;
+ }
+ }
+ public void ComputeLoops() {
+ ReducibleResult r = ComputeReducible(this, this.source);
+ this.reducible = r.reducible;
+ this.headers = r.headers;
+ this.backEdgeNodes = r.backEdgeNodes;
+ this.naturalLoops = r.naturalLoops;
+ this.splitCandidates = r.splitCandidates;
+ return;
+ }
+
+ public IEnumerable<Node> SortHeadersByDominance()
+ {
+ Graph<Node> dag = new Graph<Node>();
+ foreach (Node b in headers)
+ {
+ dag.AddSource(b);
+ foreach (Node c in headers)
+ {
+ if (b.Equals(c)) continue;
+ if (DominatorMap.DominatedBy(b, c))
+ {
+ System.Diagnostics.Debug.Assert(!DominatorMap.DominatedBy(c, b));
+ dag.AddEdge(b, c);
+ }
+ }
+ }
+ return dag.TopologicalSort();
+ }
+
+ public string ToDot(Func<Node, string> NodeLabel = null, Func<Node, string> NodeStyle = null) {
+ NodeLabel = NodeLabel ?? (n => n.ToString());
+ NodeStyle = NodeStyle ?? (n => "[shape=box]");
+ var s = new StringBuilder();
+ s.AppendLine("digraph G {");
+ foreach (var n in Nodes)
+ s.AppendLine(" \"" + NodeLabel(n) + "\" " + NodeStyle(n) + ";");
+ foreach (var e in Edges)
+ s.AppendLine(" \"" + NodeLabel(e.Item1) + "\" -> \"" + NodeLabel(e.Item2) + "\";");
+ s.AppendLine("}");
+ return s.ToString();
+ }
+ } // end: class Graph
+
+ public class GraphProgram {
+ static void TestGraph<T>(T/*!*/ source, params Tuple<T/*!*/, T/*!*/>[] edges) {
+ Contract.Requires(source != null);
+ Contract.Requires(Contract.ForAll(edges, pair => pair.Item1 != null && pair.Item2 != null));
+ HashSet<Tuple<T/*!*/, T/*!*/>> es = new HashSet<Tuple<T/*!*/, T/*!*/>>();
+ foreach (Tuple<T/*!*/, T/*!*/> e in edges) {
+ Contract.Assert(e.Item1 != null && e.Item2 != null);
+ es.Add(e);
+ }
+ Graph<T> g = new Graph<T>(es);
+ g.AddSource(source);
+ Console.WriteLine("G = " + g);
+ g.ComputeLoops();
+ Console.WriteLine("G's Dominator Map = " + g.DominatorMap);
+ Console.WriteLine("G's Immediate Dominator Map = " + Util.MapToString(g.ImmediateDominatorMap));
+ Console.WriteLine("G is reducible: " + (g.Reducible ? "yes" : "no"));
+ }
+
+ static void Main(string[] args)
+ //requires forall{string s in args; s != null};
+ {
+ Console.WriteLine("Spec# says hello!");
+ // This generates bad IL -- need to fix a bug in the compiler
+ //Graph<int> g = new Graph<int>(new Set<Tuple<int,int>>{ new Tuple<int,int>(1,2), new Tuple<int,int>(1,3), new Tuple<int,int>(2,3) });
+
+ Console.WriteLine("");
+ TestGraph<char>('a',
+ new Tuple<char, char>('a', 'b'),
+ new Tuple<char, char>('a', 'c'),
+ new Tuple<char, char>('b', 'c')
+ );
+
+ Console.WriteLine("");
+ TestGraph<char>('a',
+ new Tuple<char, char>('a', 'b'),
+ new Tuple<char, char>('a', 'c'),
+ new Tuple<char, char>('b', 'd'),
+ new Tuple<char, char>('c', 'e'),
+ new Tuple<char, char>('c', 'f'),
+ new Tuple<char, char>('d', 'e'),
+ new Tuple<char, char>('e', 'd'),
+ new Tuple<char, char>('e', 'f'),
+ new Tuple<char, char>('f', 'e')
+ );
+
+ Console.WriteLine("");
+ TestGraph<char>('a',
+ new Tuple<char, char>('a', 'b'),
+ new Tuple<char, char>('a', 'c'),
+ new Tuple<char, char>('b', 'c'),
+ new Tuple<char, char>('c', 'b')
+ );
+
+ Console.WriteLine("");
+ TestGraph<int>(1,
+ new Tuple<int, int>(1, 2),
+ new Tuple<int, int>(1, 3),
+ new Tuple<int, int>(2, 3)
+ );
+
+ Console.WriteLine("");
+ TestGraph<int>(1,
+ new Tuple<int, int>(1, 2),
+ new Tuple<int, int>(1, 3),
+ new Tuple<int, int>(2, 3),
+ new Tuple<int, int>(3, 2)
+ );
+
+ Console.WriteLine("");
+ TestGraph<int>(2,
+ new Tuple<int, int>(2, 3),
+ new Tuple<int, int>(2, 4),
+ new Tuple<int, int>(3, 2)
+ );
+
+ Console.WriteLine("");
+ TestGraph<char>('a',
+ new Tuple<char, char>('a', 'b'),
+ new Tuple<char, char>('a', 'c'),
+ new Tuple<char, char>('b', 'c'),
+ new Tuple<char, char>('b', 'b')
+ );
+
+
+ }
+ }
+
+}
diff --git a/Source/Houdini/Houdini.cs b/Source/Houdini/Houdini.cs
index ab2fa74f..b47512bd 100644
--- a/Source/Houdini/Houdini.cs
+++ b/Source/Houdini/Houdini.cs
@@ -485,14 +485,18 @@ namespace Microsoft.Boogie.Houdini {
public bool MatchCandidate(Expr boogieExpr, out Variable candidateConstant) {
candidateConstant = null;
- IExpr antecedent;
+ IExpr antecedent, consequent;
IExpr expr = boogieExpr as IExpr;
- if (expr != null && ExprUtil.Match(expr, Prop.Implies, out antecedent)) {
+ if (expr != null && ExprUtil.Match(expr, Prop.Implies, out antecedent, out consequent)) {
IdentifierExpr.ConstantFunApp constantFunApp = antecedent as IdentifierExpr.ConstantFunApp;
if (constantFunApp != null && houdiniConstants.Contains(constantFunApp.IdentifierExpr.Decl)) {
candidateConstant = constantFunApp.IdentifierExpr.Decl;
return true;
}
+
+ var e = consequent as Expr;
+ if (e != null && MatchCandidate(e, out candidateConstant))
+ return true;
}
return false;
}
@@ -564,6 +568,8 @@ namespace Microsoft.Boogie.Houdini {
private void UpdateAssignment(RefutedAnnotation refAnnot) {
if (CommandLineOptions.Clo.Trace) {
Console.WriteLine("Removing " + refAnnot.Constant);
+ using (var cexWriter = new System.IO.StreamWriter("houdiniCexTrace.bpl", true))
+ cexWriter.WriteLine("Removing " + refAnnot.Constant);
}
currentHoudiniState.Assignment.Remove(refAnnot.Constant);
currentHoudiniState.Assignment.Add(refAnnot.Constant, false);
@@ -599,6 +605,22 @@ namespace Microsoft.Boogie.Houdini {
AddRelatedToWorkList(refutedAnnotation);
UpdateAssignment(refutedAnnotation);
dequeue = false;
+ #region Extra debugging output
+ if (CommandLineOptions.Clo.Trace)
+ {
+ using (var cexWriter = new System.IO.StreamWriter("houdiniCexTrace.bpl", true))
+ {
+ cexWriter.WriteLine("Counter example for " + refutedAnnotation.Constant);
+ cexWriter.Write(error.ToString());
+ cexWriter.WriteLine();
+ using (var writer = new Microsoft.Boogie.TokenTextWriter(cexWriter))
+ foreach (Microsoft.Boogie.Block blk in error.Trace)
+ blk.Emit(writer, 15);
+ //cexWriter.WriteLine();
+ }
+ }
+ #endregion
+
}
}
break;
diff --git a/Source/Provers/SMTLib/ProverInterface.cs b/Source/Provers/SMTLib/ProverInterface.cs
index 8c6ad875..89bd9d6e 100644
--- a/Source/Provers/SMTLib/ProverInterface.cs
+++ b/Source/Provers/SMTLib/ProverInterface.cs
@@ -94,17 +94,33 @@ namespace Microsoft.Boogie.SMTLib
}
}
- void SetupProcess()
+ ProcessStartInfo ComputeProcessStartInfo()
{
- if (!this.options.UseZ3)
- return;
+ var path = this.options.ProverPath;
+ switch (options.Solver) {
+ case SolverKind.Z3:
+ if (path == null)
+ path = Z3.ExecutablePath();
+ return SMTLibProcess.ComputerProcessStartInfo(path, "AUTO_CONFIG=false -smt2 -in");
+ case SolverKind.CVC3:
+ if (path == null)
+ path = "cvc3";
+ return SMTLibProcess.ComputerProcessStartInfo(path, "-lang smt2 +interactive -showPrompt");
+ case SolverKind.CVC4:
+ if (path == null)
+ path = "cvc4";
+ return SMTLibProcess.ComputerProcessStartInfo(path, "--smtlib2 --no-strict-parsing");
+ default:
+ Debug.Assert(false);
+ return null;
+ }
+ }
+ void SetupProcess()
+ {
if (Process != null) return;
- var path = this.options.ProverPath;
- if (path == null)
- path = Z3.ExecutablePath();
- var psi = SMTLibProcess.ComputerProcessStartInfo(path, "AUTO_CONFIG=false -smt2 -in");
+ var psi = ComputeProcessStartInfo();
Process = new SMTLibProcess(psi, this.options);
Process.ErrorHandler += this.HandleProverError;
}
@@ -197,6 +213,10 @@ namespace Microsoft.Boogie.SMTLib
SendCommon("; done setting options\n");
SendCommon(_backgroundPredicates);
+ if (options.UseTickleBool) {
+ SendCommon("(declare-fun tickleBool (Bool) Bool)");
+ SendCommon("(assert (and (tickleBool true) (tickleBool false)))");
+ }
if (ctx.KnownDatatypeConstructors.Count > 0) {
string datatypeString = "";
@@ -986,7 +1006,7 @@ namespace Microsoft.Boogie.SMTLib
List<string>/*!>!*/ proverCommands = new List<string/*!*/>();
proverCommands.Add("smtlib");
var opts = (SMTLibProverOptions)options ;
- if (opts.UseZ3)
+ if (opts.Solver == SolverKind.Z3)
proverCommands.Add("z3");
else
proverCommands.Add("external");
@@ -1010,5 +1030,10 @@ namespace Microsoft.Boogie.SMTLib
return new SMTLibProcessTheoremProver(options, gen, ctx);
}
+
+ public override bool SupportsLabels(ProverOptions options)
+ {
+ return ((SMTLibProverOptions)options).SupportsLabels;
+ }
}
}
diff --git a/Source/Provers/SMTLib/SMTLibLineariser.cs b/Source/Provers/SMTLib/SMTLibLineariser.cs
index 0a0e37a2..6a2cbb6a 100644
--- a/Source/Provers/SMTLib/SMTLibLineariser.cs
+++ b/Source/Provers/SMTLib/SMTLibLineariser.cs
@@ -416,14 +416,7 @@ namespace Microsoft.Boogie.SMTLib
Contract.Requires(node != null);
Contract.Requires(options != null);
- // not sure if this is needed
- if (node[0].Type.IsBool) {
- Contract.Assert(node[1].Type.IsBool);
- // use equivalence
- WriteApplication("iff", node, options);
- } else {
- WriteApplication("=", node, options);
- }
+ WriteApplication("=", node, options);
return true;
}
@@ -470,7 +463,10 @@ namespace Microsoft.Boogie.SMTLib
public bool VisitCustomOp(VCExprNAry node, LineariserOptions options)
{
VCExprCustomOp op = (VCExprCustomOp)node.Op;
- WriteApplication(op.Name, node, options);
+ if (!ExprLineariser.ProverOptions.UseTickleBool && op.Name == "tickleBool")
+ ExprLineariser.Linearise(VCExpressionGenerator.True, options);
+ else
+ WriteApplication(op.Name, node, options);
return true;
}
@@ -517,7 +513,7 @@ namespace Microsoft.Boogie.SMTLib
}
var op = (VCExprLabelOp)node.Op;
- if (ExprLineariser.ProverOptions.UseLabels) {
+ if (CommandLineOptions.Clo.UseLabels) {
// Z3 extension
//wr.Write("({0} {1} ", op.pos ? "lblpos" : "lblneg", SMTLibNamer.QuoteId(op.label));
wr.Write("(! ");
@@ -529,7 +525,7 @@ namespace Microsoft.Boogie.SMTLib
wr.Write(")");
- if (ExprLineariser.ProverOptions.UseLabels)
+ if (CommandLineOptions.Clo.UseLabels)
wr.Write(" :{0} {1})", op.pos ? "lblpos" : "lblneg", SMTLibNamer.QuoteId(op.label));
return true;
diff --git a/Source/Provers/SMTLib/SMTLibProcess.cs b/Source/Provers/SMTLib/SMTLibProcess.cs
index 1dcfdbff..f4fa5e75 100644
--- a/Source/Provers/SMTLib/SMTLibProcess.cs
+++ b/Source/Provers/SMTLib/SMTLibProcess.cs
@@ -162,6 +162,11 @@ namespace Microsoft.Boogie.SMTLib
sb.Clear();
}
}
+ } else if (resp.Name == "unsupported") {
+ // Skip -- this may be a benign "unsupported" from a previous command.
+ // Of course, this is suboptimal. We should really be using
+ // print-success to identify the errant command and determine whether
+ // the response is benign.
} else {
return resp;
}
diff --git a/Source/Provers/SMTLib/SMTLibProverOptions.cs b/Source/Provers/SMTLib/SMTLibProverOptions.cs
index 8aea84c5..4d002956 100644
--- a/Source/Provers/SMTLib/SMTLibProverOptions.cs
+++ b/Source/Provers/SMTLib/SMTLibProverOptions.cs
@@ -27,17 +27,20 @@ namespace Microsoft.Boogie.SMTLib
}
}
+ public enum SolverKind { Z3, CVC3, CVC4 };
+
public class SMTLibProverOptions : ProverOptions
{
public bool UseWeights = true;
- public bool UseLabels { get { return UseZ3; } }
+ public bool SupportsLabels { get { return Solver == SolverKind.Z3; } }
+ public bool UseTickleBool { get { return Solver == SolverKind.Z3; } }
+ public SolverKind Solver = SolverKind.Z3;
public List<OptionValue> SmtOptions = new List<OptionValue>();
public List<string> SolverArguments = new List<string>();
public bool MultiTraces = false;
public string Logic = "";
// Z3 specific (at the moment; some of them make sense also for other provers)
- public bool UseZ3 = true;
public string Inspector = null;
public bool OptimizeForBv = false;
@@ -80,6 +83,27 @@ namespace Microsoft.Boogie.SMTLib
protected override bool Parse(string opt)
{
+ string SolverStr = null;
+ if (ParseString(opt, "SOLVER", ref SolverStr)) {
+ switch (SolverStr) {
+ case "z3":
+ Solver = SolverKind.Z3;
+ break;
+ case "cvc3":
+ Solver = SolverKind.CVC3;
+ Logic = "ALL";
+ break;
+ case "cvc4":
+ Solver = SolverKind.CVC4;
+ Logic = "ALL_SUPPORTED";
+ break;
+ default:
+ ReportError("Invalid SOLVER value; must be 'z3', 'cvc3' or 'cvc4'");
+ return false;
+ }
+ return true;
+ }
+
if (opt.StartsWith("O:")) {
AddSmtOption(opt.Substring(2));
return true;
@@ -93,7 +117,6 @@ namespace Microsoft.Boogie.SMTLib
return
ParseBool(opt, "MULTI_TRACES", ref MultiTraces) ||
ParseBool(opt, "USE_WEIGHTS", ref UseWeights) ||
- ParseBool(opt, "USE_Z3", ref UseZ3) ||
ParseString(opt, "INSPECTOR", ref Inspector) ||
ParseBool(opt, "OPTIMIZE_FOR_BV", ref OptimizeForBv) ||
ParseString(opt, "LOGIC", ref Logic) ||
@@ -103,7 +126,7 @@ namespace Microsoft.Boogie.SMTLib
public override void PostParse()
{
base.PostParse();
- if (UseZ3)
+ if (Solver == SolverKind.Z3)
Z3.SetupOptions(this);
}
@@ -115,18 +138,18 @@ namespace Microsoft.Boogie.SMTLib
@"
SMT-specific options:
~~~~~~~~~~~~~~~~~~~~~
+SOLVER=<string> Use the given SMT solver (z3, cvc3, cvc4; default: z3)
USE_WEIGHTS=<bool> Pass :weight annotations on quantified formulas (default: true)
VERBOSITY=<int> 1 - print prover output (default: 0)
O:<name>=<value> Pass (set-option :<name> <value>) to the SMT solver.
C:<string> Pass <string> to the SMT on the command line.
-LOGIC=<string> Pass (set-logic <string>) to the prover (default: empty)
+LOGIC=<string> Pass (set-logic <string>) to the prover (default: empty, 'ALL' for CVC3 or 'ALL_SUPPORTED' for CVC4)
Z3-specific options:
~~~~~~~~~~~~~~~~~~~~
MULTI_TRACES=<bool> Report errors with multiple paths leading to the same assertion.
INSPECTOR=<string> Use the specified Z3Inspector binary.
OPTIMIZE_FOR_BV=<bool> Optimize Z3 options for bitvector reasoning, and not quantifier instantiation. Defaults to false.
-USE_Z3=<bool> Use z3.exe as the prover, and use Z3 extensions (default: true)
" + base.Help;
}
}
diff --git a/Source/VCGeneration/GraphAlgorithms.cs b/Source/VCGeneration/GraphAlgorithms.cs
index def77485..006a923f 100644
--- a/Source/VCGeneration/GraphAlgorithms.cs
+++ b/Source/VCGeneration/GraphAlgorithms.cs
@@ -8,6 +8,21 @@ namespace Microsoft.Boogie {
public static class GraphAlgorithms {
+ public static Graph<Node> Dual<Node>(this Graph<Node> g, Node dummySource) {
+ var exits = g.Nodes.Where(n => g.Successors(n).Count() == 0).ToList();
+ if (exits.Count == 0)
+ return null;
+ var dual = new Graph<Node>(new HashSet<Tuple<Node, Node>>(g.Edges.Select(e => new Tuple<Node, Node>(e.Item2, e.Item1))));
+ if (exits.Count == 1)
+ dual.AddSource(exits[0]);
+ else {
+ dual.AddSource(dummySource);
+ foreach (var exit in exits)
+ dual.AddEdge(dummySource, exit);
+ }
+ return dual;
+ }
+
public static List<Tuple<Node, bool>> LoopyTopSort<Node>(this Graph<Node> g) {
Contract.Assert(g.Reducible);
@@ -78,6 +93,34 @@ public static class GraphAlgorithms {
return sortedNodes;
}
+
+ // Algorithm from Jeanne Ferrante, Karl J. Ottenstein, Joe D. Warren,
+ // "The Program Dependence Graph and Its Use in Optimization"
+ public static Dictionary<Node, HashSet<Node>> ControlDependence<Node>(this Graph<Node> g) where Node : class, new() {
+ Graph<Node> dual = g.Dual(new Node());
+ DomRelation<Node> pdom = dual.DominatorMap;
+ var result = new Dictionary<Node, HashSet<Node>>();
+
+ var S = g.Edges.Where(e => !pdom.DominatedBy(e.Item1, e.Item2));
+ foreach (var edge in S) {
+ var L = pdom.LeastCommonAncestor(edge.Item1, edge.Item2);
+ var deps = new List<Node>();
+ if (L == edge.Item1) {
+ pdom.DominatedBy(edge.Item2, edge.Item1, deps);
+ deps.Add(edge.Item2);
+ deps.Add(edge.Item1);
+ } else {
+ pdom.DominatedBy(edge.Item2, L, deps);
+ deps.Add(edge.Item2);
+ }
+ if (result.ContainsKey(edge.Item1)) {
+ result[edge.Item1].UnionWith(deps);
+ } else {
+ result[edge.Item1] = new HashSet<Node>(deps);
+ }
+ }
+ return result;
+ }
}
diff --git a/Source/VCGeneration/SmartBlockPredicator.cs b/Source/VCGeneration/SmartBlockPredicator.cs
new file mode 100644
index 00000000..9dada1a5
--- /dev/null
+++ b/Source/VCGeneration/SmartBlockPredicator.cs
@@ -0,0 +1,523 @@
+using Graphing;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using System.Linq;
+
+namespace Microsoft.Boogie {
+
+public class SmartBlockPredicator {
+
+ Program prog;
+ Implementation impl;
+ Graph<Block> blockGraph;
+ List<Tuple<Block, bool>> sortedBlocks;
+
+ Func<Procedure, bool> useProcedurePredicates;
+
+ Dictionary<Block, Variable> predMap, defMap;
+ Dictionary<Block, HashSet<Variable>> ownedMap;
+ Dictionary<Block, Block> parentMap;
+ Dictionary<Block, PartInfo> partInfo;
+
+ IdentifierExpr fp;
+ Dictionary<Microsoft.Boogie.Type, IdentifierExpr> havocVars =
+ new Dictionary<Microsoft.Boogie.Type, IdentifierExpr>();
+ Dictionary<Block, Expr> blockIds = new Dictionary<Block, Expr>();
+ HashSet<Block> doneBlocks = new HashSet<Block>();
+ bool myUseProcedurePredicates;
+ UniformityAnalyser uni;
+
+ SmartBlockPredicator(Program p, Implementation i, Func<Procedure, bool> upp, UniformityAnalyser u) {
+ prog = p;
+ impl = i;
+ useProcedurePredicates = upp;
+ myUseProcedurePredicates = useProcedurePredicates(i.Proc);
+ uni = u;
+ }
+
+ void PredicateCmd(Expr p, List<Block> blocks, Block block, Cmd cmd, out Block nextBlock) {
+ var cCmd = cmd as CallCmd;
+ if (cCmd != null && !useProcedurePredicates(cCmd.Proc)) {
+ if (p == null) {
+ block.Cmds.Add(cmd);
+ nextBlock = block;
+ return;
+ }
+
+ var trueBlock = new Block();
+ blocks.Add(trueBlock);
+ trueBlock.Label = block.Label + ".call.true";
+ trueBlock.Cmds.Add(new AssumeCmd(Token.NoToken, p));
+ trueBlock.Cmds.Add(cmd);
+
+ var falseBlock = new Block();
+ blocks.Add(falseBlock);
+ falseBlock.Label = block.Label + ".call.false";
+ falseBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.Not(p)));
+
+ var contBlock = new Block();
+ blocks.Add(contBlock);
+ contBlock.Label = block.Label + ".call.cont";
+
+ block.TransferCmd =
+ new GotoCmd(Token.NoToken, new BlockSeq(trueBlock, falseBlock));
+ trueBlock.TransferCmd = falseBlock.TransferCmd =
+ new GotoCmd(Token.NoToken, new BlockSeq(contBlock));
+ nextBlock = contBlock;
+ } else {
+ PredicateCmd(p, block.Cmds, cmd);
+ nextBlock = block;
+ }
+ }
+
+ void PredicateCmd(Expr p, CmdSeq cmdSeq, Cmd cmd) {
+ if (cmd is CallCmd) {
+ var cCmd = (CallCmd)cmd;
+ Debug.Assert(useProcedurePredicates(cCmd.Proc));
+ cCmd.Ins.Insert(0, p != null ? p : Expr.True);
+ cmdSeq.Add(cCmd);
+ } else if (p == null) {
+ cmdSeq.Add(cmd);
+ } else if (cmd is AssignCmd) {
+ var aCmd = (AssignCmd)cmd;
+ cmdSeq.Add(new AssignCmd(Token.NoToken, aCmd.Lhss,
+ new List<Expr>(aCmd.Lhss.Zip(aCmd.Rhss, (lhs, rhs) =>
+ new NAryExpr(Token.NoToken,
+ new IfThenElse(Token.NoToken),
+ new ExprSeq(p, rhs, lhs.AsExpr))))));
+ } else if (cmd is AssertCmd) {
+ var aCmd = (AssertCmd)cmd;
+ Expr newExpr = new EnabledReplacementVisitor(p).VisitExpr(aCmd.Expr);
+ aCmd.Expr = QKeyValue.FindBoolAttribute(aCmd.Attributes, "do_not_predicate") ? newExpr : Expr.Imp(p, newExpr);
+ cmdSeq.Add(aCmd);
+ } else if (cmd is AssumeCmd) {
+ var aCmd = (AssumeCmd)cmd;
+ cmdSeq.Add(new AssumeCmd(Token.NoToken, Expr.Imp(p, aCmd.Expr)));
+ } else if (cmd is HavocCmd) {
+ var hCmd = (HavocCmd)cmd;
+ foreach (IdentifierExpr v in hCmd.Vars) {
+ Microsoft.Boogie.Type type = v.Decl.TypedIdent.Type;
+ Contract.Assert(type != null);
+
+ IdentifierExpr havocTempExpr;
+ if (havocVars.ContainsKey(type)) {
+ havocTempExpr = havocVars[type];
+ } else {
+ var havocVar = new LocalVariable(Token.NoToken,
+ new TypedIdent(Token.NoToken,
+ "_HAVOC_" + type.ToString(), type));
+ impl.LocVars.Add(havocVar);
+ havocVars[type] = havocTempExpr =
+ new IdentifierExpr(Token.NoToken, havocVar);
+ }
+ cmdSeq.Add(new HavocCmd(Token.NoToken,
+ new IdentifierExprSeq(havocTempExpr)));
+ cmdSeq.Add(Cmd.SimpleAssign(Token.NoToken, v,
+ new NAryExpr(Token.NoToken,
+ new IfThenElse(Token.NoToken),
+ new ExprSeq(p, havocTempExpr, v))));
+ }
+ } else if (cmd is CommentCmd) {
+ // skip
+ } else if (cmd is StateCmd) {
+ var sCmd = (StateCmd)cmd;
+ var newCmdSeq = new CmdSeq();
+ foreach (Cmd c in sCmd.Cmds)
+ PredicateCmd(p, newCmdSeq, c);
+ sCmd.Cmds = newCmdSeq;
+ cmdSeq.Add(sCmd);
+ } else {
+ Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString());
+ }
+ }
+
+ // hasPredicatedRegion is true iff the block or its targets are predicated
+ // (i.e. we enter, stay within or exit a predicated region).
+ void PredicateTransferCmd(Expr p, Block src, CmdSeq cmdSeq, TransferCmd cmd, out bool hasPredicatedRegion) {
+ hasPredicatedRegion = predMap.ContainsKey(src);
+
+ if (cmd is GotoCmd) {
+ var gCmd = (GotoCmd)cmd;
+
+ hasPredicatedRegion = hasPredicatedRegion ||
+ gCmd.labelTargets.Cast<Block>().Any(b => predMap.ContainsKey(b));
+
+ if (gCmd.labelTargets.Length == 1) {
+ if (defMap.ContainsKey(gCmd.labelTargets[0]))
+ PredicateCmd(p, cmdSeq,
+ Cmd.SimpleAssign(Token.NoToken,
+ Expr.Ident(predMap[gCmd.labelTargets[0]]), Expr.True));
+ } else {
+ Debug.Assert(gCmd.labelTargets.Length > 1);
+ Debug.Assert(gCmd.labelTargets.Cast<Block>().All(t => uni.IsUniform(impl.Name, t) ||
+ partInfo.ContainsKey(t)));
+ foreach (Block target in gCmd.labelTargets) {
+ if (!partInfo.ContainsKey(target))
+ continue;
+
+ var part = partInfo[target];
+ if (defMap.ContainsKey(part.realDest))
+ PredicateCmd(p, cmdSeq,
+ Cmd.SimpleAssign(Token.NoToken,
+ Expr.Ident(predMap[part.realDest]), part.pred));
+ var predsExitingLoop = new Dictionary<Block, List<Expr>>();
+ foreach (Block exit in LoopsExited(src, target)) {
+ List<Expr> predList;
+ if (!predsExitingLoop.ContainsKey(exit))
+ predList = predsExitingLoop[exit] = new List<Expr>();
+ else
+ predList = predsExitingLoop[exit];
+ predList.Add(part.pred);
+ }
+ foreach (var pred in predsExitingLoop) {
+ PredicateCmd(p, cmdSeq,
+ Cmd.SimpleAssign(Token.NoToken,
+ Expr.Ident(predMap[pred.Key]),
+ Expr.Not(pred.Value.Aggregate(Expr.Or))));
+ }
+ }
+ }
+ } else if (cmd is ReturnCmd) {
+ // Blocks which end in a return will never share a predicate with a block
+ // which appears after it. Furthermore, such a block cannot be part of a
+ // loop. So it is safe to do nothing here.
+ } else {
+ Console.WriteLine("Unsupported cmd: " + cmd.GetType().ToString());
+ }
+ }
+
+ Variable FreshPredicate(ref int predCount) {
+ var pVar = new LocalVariable(Token.NoToken,
+ new TypedIdent(Token.NoToken,
+ "p" + predCount++,
+ Microsoft.Boogie.Type.Bool));
+ impl.LocVars.Add(pVar);
+ return pVar;
+ }
+
+ void AssignPredicates(Graph<Block> blockGraph,
+ DomRelation<Block> dom,
+ DomRelation<Block> pdom,
+ IEnumerator<Tuple<Block, bool>> i,
+ Variable headPredicate,
+ ref int predCount) {
+ var header = i.Current.Item1;
+ var regionPreds = new List<Tuple<Block, Variable>>();
+ var ownedPreds = new HashSet<Variable>();
+ ownedMap[header] = ownedPreds;
+
+ if (headPredicate != null) {
+ predMap[header] = headPredicate;
+ defMap[header] = headPredicate;
+ regionPreds.Add(new Tuple<Block, Variable>(header, headPredicate));
+ }
+
+ while (i.MoveNext()) {
+ var block = i.Current;
+ if (uni != null && uni.IsUniform(impl.Name, block.Item1))
+ continue;
+ if (block.Item2) {
+ if (block.Item1 == header)
+ return;
+ } else {
+ if (blockGraph.Headers.Contains(block.Item1)) {
+ parentMap[block.Item1] = header;
+ var loopPred = FreshPredicate(ref predCount);
+ ownedPreds.Add(loopPred);
+ AssignPredicates(blockGraph, dom, pdom, i, loopPred, ref predCount);
+ } else {
+ bool foundExisting = false;
+ foreach (var regionPred in regionPreds) {
+ if (dom.DominatedBy(block.Item1, regionPred.Item1) &&
+ pdom.DominatedBy(regionPred.Item1, block.Item1)) {
+ predMap[block.Item1] = regionPred.Item2;
+ foundExisting = true;
+ break;
+ }
+ }
+ if (!foundExisting) {
+ var condPred = FreshPredicate(ref predCount);
+ predMap[block.Item1] = condPred;
+ defMap[block.Item1] = condPred;
+ ownedPreds.Add(condPred);
+ regionPreds.Add(new Tuple<Block, Variable>(block.Item1, condPred));
+ }
+ }
+ }
+ }
+ }
+
+ void AssignPredicates() {
+ DomRelation<Block> dom = blockGraph.DominatorMap;
+
+ Graph<Block> dualGraph = blockGraph.Dual(new Block());
+ DomRelation<Block> pdom = dualGraph.DominatorMap;
+
+ var iter = sortedBlocks.GetEnumerator();
+ if (!iter.MoveNext()) {
+ predMap = defMap = null;
+ ownedMap = null;
+ return;
+ }
+
+ int predCount = 0;
+ predMap = new Dictionary<Block, Variable>();
+ defMap = new Dictionary<Block, Variable>();
+ ownedMap = new Dictionary<Block, HashSet<Variable>>();
+ parentMap = new Dictionary<Block, Block>();
+ AssignPredicates(blockGraph, dom, pdom, iter,
+ myUseProcedurePredicates ? impl.InParams[0] : null,
+ ref predCount);
+ }
+
+ IEnumerable<Block> LoopsExited(Block src, Block dest) {
+ var i = sortedBlocks.GetEnumerator();
+ while (i.MoveNext()) {
+ var b = i.Current;
+ if (b.Item1 == src) {
+ return LoopsExitedForwardEdge(dest, i);
+ } else if (b.Item1 == dest) {
+ return LoopsExitedBackEdge(src, i);
+ }
+ }
+ Debug.Assert(false);
+ return null;
+ }
+
+ private IEnumerable<Block> LoopsExitedBackEdge(Block src, IEnumerator<Tuple<Block, bool>> i) {
+ var headsSeen = new HashSet<Block>();
+ while (i.MoveNext()) {
+ var b = i.Current;
+ if (!b.Item2 && blockGraph.Headers.Contains(b.Item1))
+ headsSeen.Add(b.Item1);
+ else if (b.Item2)
+ headsSeen.Remove(b.Item1);
+ if (b.Item1 == src)
+ return headsSeen;
+ }
+ Debug.Assert(false);
+ return null;
+ }
+
+ private IEnumerable<Block> LoopsExitedForwardEdge(Block dest, IEnumerator<Tuple<Block, bool>> i) {
+ var headsSeen = new HashSet<Block>();
+ while (i.MoveNext()) {
+ var b = i.Current;
+ if (b.Item1 == dest)
+ yield break;
+ else if (!b.Item2 && blockGraph.Headers.Contains(b.Item1))
+ headsSeen.Add(b.Item1);
+ else if (b.Item2 && !headsSeen.Contains(b.Item1))
+ yield return b.Item1;
+ }
+ Debug.Assert(false);
+ }
+
+ class PartInfo {
+ public PartInfo(Expr p, Block r) { pred = p; realDest = r; }
+ public Expr pred;
+ public Block realDest;
+ }
+
+ Dictionary<Block, PartInfo> BuildPartitionInfo() {
+ var partInfo = new Dictionary<Block, PartInfo>();
+ foreach (var block in blockGraph.Nodes) {
+ if (uni.IsUniform(impl.Name, block))
+ continue;
+
+ var parts = block.Cmds.Cast<Cmd>().TakeWhile(
+ c => c is AssumeCmd &&
+ QKeyValue.FindBoolAttribute(((AssumeCmd)c).Attributes, "partition"));
+
+ Expr pred = null;
+ if (parts.Count() > 0) {
+ pred = parts.Select(a => ((AssumeCmd)a).Expr).Aggregate(Expr.And);
+ block.Cmds =
+ new CmdSeq(block.Cmds.Cast<Cmd>().Skip(parts.Count()).ToArray());
+ } else {
+ continue;
+ }
+
+ Block realDest = block;
+ if (block.Cmds.Length == 0) {
+ var gc = block.TransferCmd as GotoCmd;
+ if (gc != null && gc.labelTargets.Length == 1)
+ realDest = gc.labelTargets[0];
+ }
+ partInfo[block] = new PartInfo(pred, realDest);
+ }
+
+ return partInfo;
+ }
+
+ void PredicateImplementation() {
+ blockGraph = prog.ProcessLoops(impl);
+ sortedBlocks = blockGraph.LoopyTopSort();
+
+ AssignPredicates();
+ partInfo = BuildPartitionInfo();
+
+ if (myUseProcedurePredicates)
+ fp = Expr.Ident(impl.InParams[0]);
+
+ var newBlocks = new List<Block>();
+ Block prevBlock = null;
+ foreach (var n in sortedBlocks) {
+ if (predMap.ContainsKey(n.Item1)) {
+ var p = predMap[n.Item1];
+ var pExpr = Expr.Ident(p);
+
+ if (n.Item2) {
+ var backedgeBlock = new Block();
+ newBlocks.Add(backedgeBlock);
+
+ backedgeBlock.Label = n.Item1.Label + ".backedge";
+ backedgeBlock.Cmds = new CmdSeq(new AssumeCmd(Token.NoToken, pExpr,
+ new QKeyValue(Token.NoToken, "backedge", new List<object>(), null)));
+ backedgeBlock.TransferCmd = new GotoCmd(Token.NoToken,
+ new BlockSeq(n.Item1));
+
+ var tailBlock = new Block();
+ newBlocks.Add(tailBlock);
+
+ tailBlock.Label = n.Item1.Label + ".tail";
+ tailBlock.Cmds = new CmdSeq(new AssumeCmd(Token.NoToken,
+ Expr.Not(pExpr)));
+
+ if (prevBlock != null)
+ prevBlock.TransferCmd = new GotoCmd(Token.NoToken,
+ new BlockSeq(backedgeBlock, tailBlock));
+ prevBlock = tailBlock;
+ } else {
+ PredicateBlock(pExpr, n.Item1, newBlocks, ref prevBlock);
+ }
+ } else {
+ if (!n.Item2) {
+ PredicateBlock(null, n.Item1, newBlocks, ref prevBlock);
+ }
+ }
+ }
+
+ if (prevBlock != null)
+ prevBlock.TransferCmd = new ReturnCmd(Token.NoToken);
+
+ impl.Blocks = newBlocks;
+ }
+
+ private void PredicateBlock(Expr pExpr, Block block, List<Block> newBlocks, ref Block prevBlock) {
+ var firstBlock = block;
+
+ var oldCmdSeq = block.Cmds;
+ block.Cmds = new CmdSeq();
+ newBlocks.Add(block);
+ if (prevBlock != null) {
+ prevBlock.TransferCmd = new GotoCmd(Token.NoToken, new BlockSeq(block));
+ }
+
+ if (parentMap.ContainsKey(block)) {
+ var parent = parentMap[block];
+ if (predMap.ContainsKey(parent)) {
+ var parentPred = predMap[parent];
+ if (parentPred != null) {
+ block.Cmds.Add(new AssertCmd(Token.NoToken,
+ pExpr != null ? (Expr)Expr.Imp(pExpr, Expr.Ident(parentPred))
+ : Expr.Ident(parentPred)));
+ }
+ }
+ }
+
+ var transferCmd = block.TransferCmd;
+ foreach (Cmd cmd in oldCmdSeq)
+ PredicateCmd(pExpr, newBlocks, block, cmd, out block);
+
+ if (ownedMap.ContainsKey(firstBlock)) {
+ var owned = ownedMap[firstBlock];
+ foreach (var v in owned)
+ block.Cmds.Add(Cmd.SimpleAssign(Token.NoToken, Expr.Ident(v), Expr.False));
+ }
+
+ bool hasPredicatedRegion;
+ PredicateTransferCmd(pExpr, block, block.Cmds, transferCmd, out hasPredicatedRegion);
+
+ if (hasPredicatedRegion)
+ prevBlock = block;
+ else
+ prevBlock = null;
+
+ doneBlocks.Add(block);
+ }
+
+ private Expr CreateIfFPThenElse(Expr then, Expr eElse) {
+ if (myUseProcedurePredicates) {
+ return new NAryExpr(Token.NoToken,
+ new IfThenElse(Token.NoToken),
+ new ExprSeq(fp, then, eElse));
+ } else {
+ return then;
+ }
+ }
+
+ public static void Predicate(Program p,
+ Func<Procedure, bool> useProcedurePredicates = null,
+ UniformityAnalyser uni = null) {
+ useProcedurePredicates = useProcedurePredicates ?? (proc => false);
+ if (uni != null) {
+ var oldUPP = useProcedurePredicates;
+ useProcedurePredicates = proc => oldUPP(proc) && !uni.IsUniform(proc.Name);
+ }
+
+ foreach (var decl in p.TopLevelDeclarations.ToList()) {
+ if (decl is Procedure || decl is Implementation) {
+ var proc = decl as Procedure;
+ Implementation impl = null;
+ if (proc == null) {
+ impl = (Implementation)decl;
+ proc = impl.Proc;
+ }
+
+ bool upp = useProcedurePredicates(proc);
+ if (upp) {
+ var dwf = (DeclWithFormals)decl;
+ var fpVar = new Formal(Token.NoToken,
+ new TypedIdent(Token.NoToken, "_P",
+ Microsoft.Boogie.Type.Bool),
+ /*incoming=*/true);
+ dwf.InParams = new VariableSeq(
+ (new Variable[] {fpVar}.Concat(dwf.InParams.Cast<Variable>()))
+ .ToArray());
+
+ if (impl == null) {
+ var newRequires = new RequiresSeq();
+ foreach (Requires r in proc.Requires) {
+ newRequires.Add(new Requires(r.Free,
+ new EnabledReplacementVisitor(new IdentifierExpr(Token.NoToken, fpVar)).VisitExpr(r.Condition)));
+ }
+ var newEnsures = new EnsuresSeq();
+ foreach (Ensures e in proc.Ensures) {
+ newEnsures.Add(new Ensures(e.Free,
+ new EnabledReplacementVisitor(new IdentifierExpr(Token.NoToken, fpVar)).VisitExpr(e.Condition)));
+ }
+ }
+ }
+
+ if (impl != null) {
+ try {
+ new SmartBlockPredicator(p, impl, useProcedurePredicates, uni).PredicateImplementation();
+ } catch (Program.IrreducibleLoopException) { }
+ }
+ }
+ }
+ }
+
+ public static void Predicate(Program p, Implementation impl) {
+ try {
+ new SmartBlockPredicator(p, impl, proc => false, null).PredicateImplementation();
+ }
+ catch (Program.IrreducibleLoopException) { }
+ }
+
+}
+
+}
diff --git a/Source/GPUVerify/UniformityAnalyser.cs b/Source/VCGeneration/UniformityAnalyser.cs
index 35f297ed..e5647a21 100644
--- a/Source/GPUVerify/UniformityAnalyser.cs
+++ b/Source/VCGeneration/UniformityAnalyser.cs
@@ -1,425 +1,539 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Microsoft.Boogie;
-using System.Diagnostics;
-
-namespace GPUVerify
-{
-
- class UniformityAnalyser
- {
- private GPUVerifier verifier;
-
- private bool ProcedureChanged;
-
- private Dictionary<string, KeyValuePair<bool, Dictionary<string, bool>>> uniformityInfo;
-
- private Dictionary<string, HashSet<int>> nonUniformLoops;
-
- private Dictionary<string, HashSet<int>> loopsWithNonuniformReturn;
-
- private Dictionary<string, List<string>> inParameters;
-
- private Dictionary<string, List<string>> outParameters;
-
- private List<WhileCmd> loopStack;
-
- private bool hitNonuniformReturn;
-
- public UniformityAnalyser(GPUVerifier verifier)
- {
- this.verifier = verifier;
- uniformityInfo = new Dictionary<string, KeyValuePair<bool, Dictionary<string, bool>>>();
- nonUniformLoops = new Dictionary<string, HashSet<int>>();
- loopsWithNonuniformReturn = new Dictionary<string, HashSet<int>>();
- inParameters = new Dictionary<string, List<string>>();
- outParameters = new Dictionary<string, List<string>>();
- loopStack = new List<WhileCmd>();
- }
-
- internal void Analyse()
- {
- if (CommandLineOptions.Unstructured)
- return;
-
- foreach (Declaration D in verifier.Program.TopLevelDeclarations)
- {
- if(D is Implementation)
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Boogie;
+using System.Diagnostics;
+using Graphing;
+
+namespace Microsoft.Boogie
+{
+
+ public class UniformityAnalyser
+ {
+ private Program prog;
+
+ private bool doAnalysis, unstructured;
+
+ private ISet<Implementation> entryPoints;
+
+ private IEnumerable<Variable> nonUniformVars;
+
+ private bool ProcedureChanged;
+
+ private Dictionary<string, KeyValuePair<bool, Dictionary<string, bool>>> uniformityInfo;
+
+ private Dictionary<string, HashSet<int>> nonUniformLoops;
+
+ private Dictionary<string, HashSet<Block>> nonUniformBlocks;
+
+ private Dictionary<string, HashSet<int>> loopsWithNonuniformReturn;
+
+ private Dictionary<string, List<string>> inParameters;
+
+ private Dictionary<string, List<string>> outParameters;
+
+ private List<WhileCmd> loopStack;
+
+ private bool hitNonuniformReturn;
+
+ public UniformityAnalyser(Program prog, bool doAnalysis, bool unstructured, ISet<Implementation> entryPoints, IEnumerable<Variable> nonUniformVars)
+ {
+ this.prog = prog;
+ this.doAnalysis = doAnalysis;
+ this.unstructured = unstructured;
+ this.entryPoints = entryPoints;
+ this.nonUniformVars = nonUniformVars;
+ uniformityInfo = new Dictionary<string, KeyValuePair<bool, Dictionary<string, bool>>>();
+ nonUniformLoops = new Dictionary<string, HashSet<int>>();
+ nonUniformBlocks = new Dictionary<string, HashSet<Block>>();
+ loopsWithNonuniformReturn = new Dictionary<string, HashSet<int>>();
+ inParameters = new Dictionary<string, List<string>>();
+ outParameters = new Dictionary<string, List<string>>();
+ loopStack = new List<WhileCmd>();
+ }
+
+ public void Analyse()
+ {
+ var impls = prog.TopLevelDeclarations.OfType<Implementation>();
+
+ foreach (var Impl in impls)
+ {
+ bool uniformProcedure = doAnalysis || entryPoints.Contains(Impl);
+
+ uniformityInfo.Add(Impl.Name, new KeyValuePair<bool, Dictionary<string, bool>>
+ (uniformProcedure, new Dictionary<string, bool> ()));
+
+ nonUniformLoops.Add(Impl.Name, new HashSet<int>());
+ loopsWithNonuniformReturn.Add(Impl.Name, new HashSet<int>());
+
+ foreach (var v in nonUniformVars)
+ SetNonUniform(Impl.Name, v.Name);
+
+ foreach (Variable v in Impl.LocVars)
+ {
+ if (doAnalysis)
+ {
+ SetUniform(Impl.Name, v.Name);
+ }
+ else
+ {
+ SetNonUniform(Impl.Name, v.Name);
+ }
+ }
+
+ inParameters[Impl.Name] = new List<string>();
+
+ foreach (Variable v in Impl.InParams)
+ {
+ inParameters[Impl.Name].Add(v.Name);
+ if (doAnalysis)
+ {
+ SetUniform(Impl.Name, v.Name);
+ }
+ else
+ {
+ SetNonUniform(Impl.Name, v.Name);
+ }
+ }
+
+ outParameters[Impl.Name] = new List<string>();
+ foreach (Variable v in Impl.OutParams)
+ {
+ outParameters[Impl.Name].Add(v.Name);
+ if (doAnalysis)
+ {
+ SetUniform(Impl.Name, v.Name);
+ }
+ else
+ {
+ SetNonUniform(Impl.Name, v.Name);
+ }
+ }
+
+ ProcedureChanged = true;
+ }
+
+ if (doAnalysis)
+ {
+ while (ProcedureChanged)
{
- bool uniformProcedure =
- (D == verifier.KernelImplementation
- || CommandLineOptions.DoUniformityAnalysis);
-
- Implementation Impl = D as Implementation;
- uniformityInfo.Add(Impl.Name, new KeyValuePair<bool, Dictionary<string, bool>>
- (uniformProcedure, new Dictionary<string, bool> ()));
-
- nonUniformLoops.Add(Impl.Name, new HashSet<int>());
- loopsWithNonuniformReturn.Add(Impl.Name, new HashSet<int>());
-
- SetNonUniform(Impl.Name, GPUVerifier._X.Name);
- SetNonUniform(Impl.Name, GPUVerifier._Y.Name);
- SetNonUniform(Impl.Name, GPUVerifier._Z.Name);
-
- SetNonUniform(Impl.Name, GPUVerifier._GROUP_X.Name);
- SetNonUniform(Impl.Name, GPUVerifier._GROUP_Y.Name);
- SetNonUniform(Impl.Name, GPUVerifier._GROUP_Z.Name);
-
- foreach (Variable v in Impl.LocVars)
- {
- if (CommandLineOptions.DoUniformityAnalysis)
- {
- SetUniform(Impl.Name, v.Name);
- }
- else
- {
- SetNonUniform(Impl.Name, v.Name);
- }
- }
-
- inParameters[Impl.Name] = new List<string>();
-
- foreach (Variable v in Impl.InParams)
- {
- inParameters[Impl.Name].Add(v.Name);
- if (CommandLineOptions.DoUniformityAnalysis)
- {
- SetUniform(Impl.Name, v.Name);
- }
- else
- {
- SetNonUniform(Impl.Name, v.Name);
- }
+ ProcedureChanged = false;
+
+ foreach (var Impl in impls)
+ {
+ hitNonuniformReturn = false;
+ Analyse(Impl, uniformityInfo[Impl.Name].Key);
+ }
+ }
+ }
+
+ foreach (var Impl in impls)
+ {
+ if (!IsUniform (Impl.Name))
+ {
+ List<string> newIns = new List<String>();
+ newIns.Add("_P");
+ foreach (string s in inParameters[Impl.Name])
+ {
+ newIns.Add(s);
+ }
+ inParameters[Impl.Name] = newIns;
+ }
+ }
+ }
+
+ private void Analyse(Implementation Impl, bool ControlFlowIsUniform)
+ {
+ if (unstructured)
+ {
+ if (!ControlFlowIsUniform)
+ {
+ nonUniformBlocks[Impl.Name] = new HashSet<Block>(Impl.Blocks);
+
+ foreach (Variable v in Impl.LocVars) {
+ if (IsUniform(Impl.Name, v.Name)) {
+ SetNonUniform(Impl.Name, v.Name);
+ }
}
- outParameters[Impl.Name] = new List<string>();
- foreach (Variable v in Impl.OutParams)
- {
- outParameters[Impl.Name].Add(v.Name);
- if (CommandLineOptions.DoUniformityAnalysis)
- {
- SetUniform(Impl.Name, v.Name);
- }
- else
- {
+ foreach (Variable v in Impl.InParams) {
+ if (IsUniform(Impl.Name, v.Name)) {
SetNonUniform(Impl.Name, v.Name);
}
}
- ProcedureChanged = true;
- }
- }
-
- if (CommandLineOptions.DoUniformityAnalysis)
- {
- while (ProcedureChanged)
- {
- ProcedureChanged = false;
-
- foreach (Declaration D in verifier.Program.TopLevelDeclarations)
- {
- if (D is Implementation)
- {
- hitNonuniformReturn = false;
- Implementation Impl = D as Implementation;
- Analyse(Impl, uniformityInfo[Impl.Name].Key);
- }
+ foreach (Variable v in Impl.OutParams) {
+ if (IsUniform(Impl.Name, v.Name)) {
+ SetNonUniform(Impl.Name, v.Name);
+ }
}
- }
- }
-
- foreach (Declaration D in verifier.Program.TopLevelDeclarations)
- {
- if (D is Implementation)
- {
- Implementation Impl = D as Implementation;
- if (!IsUniform (Impl.Name))
- {
- List<string> newIns = new List<String>();
- newIns.Add("_P");
- foreach (string s in inParameters[Impl.Name])
- {
- newIns.Add(s);
- }
- inParameters[Impl.Name] = newIns;
+
+ return;
+ }
+
+ Graph<Block> blockGraph = prog.ProcessLoops(Impl);
+ var ctrlDep = blockGraph.ControlDependence();
+
+ // Compute transitive closure of control dependence info.
+ bool changed;
+ do
+ {
+ changed = false;
+ foreach (var depEntry in ctrlDep)
+ {
+ var newDepSet = new HashSet<Block>(depEntry.Value);
+ foreach (var dep in depEntry.Value)
+ {
+ if (ctrlDep.ContainsKey(dep))
+ newDepSet.UnionWith(ctrlDep[dep]);
+ }
+ if (newDepSet.Count != depEntry.Value.Count)
+ {
+ depEntry.Value.UnionWith(newDepSet);
+ changed = true;
+ }
+ }
+ } while (changed);
+
+ var nonUniformBlockSet = new HashSet<Block>();
+ nonUniformBlocks[Impl.Name] = nonUniformBlockSet;
+
+ do {
+ changed = false;
+ foreach (var block in Impl.Blocks) {
+ bool uniform = !nonUniformBlockSet.Contains(block);
+ bool newUniform = Analyse(Impl, block.Cmds, uniform);
+ if (uniform && !newUniform) {
+ changed = true;
+ nonUniformBlockSet.Add(block);
+ Block pred = blockGraph.Predecessors(block).Single();
+ if (ctrlDep.ContainsKey(pred))
+ nonUniformBlockSet.UnionWith(ctrlDep[pred]);
}
- }
- }
-
- if (CommandLineOptions.ShowUniformityAnalysis)
- {
- dump();
- }
- }
-
- private void Analyse(Implementation Impl, bool ControlFlowIsUniform)
- {
- Analyse(Impl, Impl.StructuredStmts, ControlFlowIsUniform);
- }
-
-
- private void Analyse(Implementation impl, StmtList stmtList, bool ControlFlowIsUniform)
- {
- ControlFlowIsUniform &= !hitNonuniformReturn;
- foreach (BigBlock bb in stmtList.BigBlocks)
- {
- Analyse(impl, bb, ControlFlowIsUniform);
- }
- }
-
- private void Analyse(Implementation impl, BigBlock bb, bool ControlFlowIsUniform)
- {
- ControlFlowIsUniform &= !hitNonuniformReturn;
- foreach (Cmd c in bb.simpleCmds)
- {
- if (c is AssignCmd)
- {
- AssignCmd assignCmd = c as AssignCmd;
- Debug.Assert(assignCmd.Lhss.Count == 1);
- Debug.Assert(assignCmd.Rhss.Count == 1);
- if (assignCmd.Lhss[0] is SimpleAssignLhs)
+ }
+ } while (changed);
+ }
+ else
+ {
+ Analyse(Impl, Impl.StructuredStmts, ControlFlowIsUniform);
+ }
+ }
+
+
+ private void Analyse(Implementation impl, StmtList stmtList, bool ControlFlowIsUniform)
+ {
+ ControlFlowIsUniform &= !hitNonuniformReturn;
+ foreach (BigBlock bb in stmtList.BigBlocks)
+ {
+ Analyse(impl, bb, ControlFlowIsUniform);
+ }
+ }
+
+ private Implementation GetImplementation(string procedureName)
+ {
+ foreach (Declaration D in prog.TopLevelDeclarations)
+ {
+ if (D is Implementation && ((D as Implementation).Name == procedureName))
+ {
+ return D as Implementation;
+ }
+ }
+ return null;
+ }
+
+ private void Analyse(Implementation impl, BigBlock bb, bool ControlFlowIsUniform)
+ {
+ ControlFlowIsUniform &= !hitNonuniformReturn;
+ Analyse(impl, bb.simpleCmds, ControlFlowIsUniform);
+
+ if (bb.ec is WhileCmd)
+ {
+ WhileCmd wc = bb.ec as WhileCmd;
+ loopStack.Add(wc);
+ Analyse(impl, wc.Body, ControlFlowIsUniform && IsUniform(impl.Name, wc.Guard) &&
+ !nonUniformLoops[impl.Name].Contains(GetLoopId(wc)));
+ loopStack.RemoveAt(loopStack.Count - 1);
+ }
+ else if (bb.ec is IfCmd)
+ {
+ IfCmd ifCmd = bb.ec as IfCmd;
+ Analyse(impl, ifCmd.thn, ControlFlowIsUniform && IsUniform(impl.Name, ifCmd.Guard));
+ if (ifCmd.elseBlock != null)
+ {
+ Analyse(impl, ifCmd.elseBlock, ControlFlowIsUniform && IsUniform(impl.Name, ifCmd.Guard));
+ }
+ Debug.Assert(ifCmd.elseIf == null);
+ }
+ else if (bb.ec is BreakCmd)
+ {
+ if (!ControlFlowIsUniform && !nonUniformLoops[impl.Name].Contains(GetLoopId(loopStack[loopStack.Count - 1])))
+ {
+ SetNonUniform(impl.Name, loopStack[loopStack.Count - 1]);
+ }
+ }
+
+ if (bb.tc is ReturnCmd && !ControlFlowIsUniform)
+ {
+ hitNonuniformReturn = true;
+ if (loopStack.Count > 0 && !nonUniformLoops[impl.Name].Contains(GetLoopId(loopStack[0])))
+ {
+ SetNonUniform(impl.Name, loopStack[0]);
+ loopsWithNonuniformReturn[impl.Name].Add(GetLoopId(loopStack[0]));
+ }
+ }
+
+
+ }
+
+ private bool Analyse(Implementation impl, CmdSeq cmdSeq, bool ControlFlowIsUniform)
+ {
+ foreach (Cmd c in cmdSeq)
+ {
+ if (c is AssignCmd)
+ {
+ AssignCmd assignCmd = c as AssignCmd;
+ foreach (var a in assignCmd.Lhss.Zip(assignCmd.Rhss))
{
- SimpleAssignLhs lhs = assignCmd.Lhss[0] as SimpleAssignLhs;
- Expr rhs = assignCmd.Rhss[0];
-
- if (IsUniform(impl.Name, lhs.AssignedVariable.Name) &&
- (!ControlFlowIsUniform || !IsUniform(impl.Name, rhs)))
- {
- SetNonUniform(impl.Name, lhs.AssignedVariable.Name);
- }
-
- }
- }
- else if (c is CallCmd)
- {
- CallCmd callCmd = c as CallCmd;
-
- if (callCmd.callee != verifier.BarrierProcedure.Name)
- {
-
- if (!ControlFlowIsUniform)
- {
- if (IsUniform(callCmd.callee))
- {
- SetNonUniform(callCmd.callee);
- }
- }
- Implementation CalleeImplementation = verifier.GetImplementation(callCmd.callee);
- for (int i = 0; i < CalleeImplementation.InParams.Length; i++)
- {
- if (IsUniform(callCmd.callee, CalleeImplementation.InParams[i].Name)
- && !IsUniform(impl.Name, callCmd.Ins[i]))
+
+ if (a.Item1 is SimpleAssignLhs)
+ {
+ SimpleAssignLhs lhs = a.Item1 as SimpleAssignLhs;
+ Expr rhs = a.Item2;
+ if (IsUniform(impl.Name, lhs.AssignedVariable.Name) &&
+ (!ControlFlowIsUniform || !IsUniform(impl.Name, rhs)))
{
- SetNonUniform(callCmd.callee, CalleeImplementation.InParams[i].Name);
+ SetNonUniform(impl.Name, lhs.AssignedVariable.Name);
}
- }
-
- for (int i = 0; i < CalleeImplementation.OutParams.Length; i++)
- {
- if (IsUniform(impl.Name, callCmd.Outs[i].Name)
- && !IsUniform(callCmd.callee, CalleeImplementation.OutParams[i].Name))
- {
- SetNonUniform(impl.Name, callCmd.Outs[i].Name);
- }
- }
-
- }
- }
- }
-
- if (bb.ec is WhileCmd)
- {
- WhileCmd wc = bb.ec as WhileCmd;
- loopStack.Add(wc);
- Analyse(impl, wc.Body, ControlFlowIsUniform && IsUniform(impl.Name, wc.Guard) &&
- !nonUniformLoops[impl.Name].Contains(GetLoopId(wc)));
- loopStack.RemoveAt(loopStack.Count - 1);
- }
- else if (bb.ec is IfCmd)
- {
- IfCmd ifCmd = bb.ec as IfCmd;
- Analyse(impl, ifCmd.thn, ControlFlowIsUniform && IsUniform(impl.Name, ifCmd.Guard));
- if (ifCmd.elseBlock != null)
- {
- Analyse(impl, ifCmd.elseBlock, ControlFlowIsUniform && IsUniform(impl.Name, ifCmd.Guard));
- }
- Debug.Assert(ifCmd.elseIf == null);
- }
- else if (bb.ec is BreakCmd)
- {
- if (!ControlFlowIsUniform && !nonUniformLoops[impl.Name].Contains(GetLoopId(loopStack[loopStack.Count - 1])))
- {
- SetNonUniform(impl.Name, loopStack[loopStack.Count - 1]);
- }
- }
-
- if (bb.tc is ReturnCmd && !ControlFlowIsUniform)
- {
- hitNonuniformReturn = true;
- if (loopStack.Count > 0 && !nonUniformLoops[impl.Name].Contains(GetLoopId(loopStack[0])))
- {
- SetNonUniform(impl.Name, loopStack[0]);
- loopsWithNonuniformReturn[impl.Name].Add(GetLoopId(loopStack[0]));
- }
- }
-
-
- }
-
- private int GetLoopId(WhileCmd wc)
- {
- AssertCmd inv = wc.Invariants[0] as AssertCmd;
- Debug.Assert(inv.Attributes.Key.Contains("loophead_"));
- return Convert.ToInt32(inv.Attributes.Key.Substring("loophead_".Length));
- }
-
- private void SetNonUniform(string procedureName)
- {
- uniformityInfo[procedureName] = new KeyValuePair<bool,Dictionary<string,bool>>
- (false, uniformityInfo[procedureName].Value);
- RecordProcedureChanged();
- }
-
- private void SetNonUniform(string procedureName, WhileCmd wc)
- {
- nonUniformLoops[procedureName].Add(GetLoopId(wc));
- RecordProcedureChanged();
- }
-
- internal bool IsUniform(string procedureName)
- {
- if (CommandLineOptions.Unstructured)
- return false;
-
- if (!uniformityInfo.ContainsKey(procedureName))
- {
- return false;
- }
- return uniformityInfo[procedureName].Key;
- }
- internal bool IsUniform(string procedureName, Expr expr)
- {
- if (CommandLineOptions.Unstructured)
- return false;
-
- UniformExpressionAnalysisVisitor visitor = new UniformExpressionAnalysisVisitor(uniformityInfo[procedureName].Value);
- visitor.VisitExpr(expr);
- return visitor.IsUniform();
- }
-
- internal bool IsUniform(string procedureName, string v)
- {
- if (CommandLineOptions.Unstructured)
- return false;
-
- if (!uniformityInfo.ContainsKey(procedureName))
- {
- return false;
- }
-
- if (!uniformityInfo[procedureName].Value.ContainsKey(v))
- {
- return false;
- }
- return uniformityInfo[procedureName].Value[v];
- }
-
- private void SetUniform(string procedureName, string v)
- {
- uniformityInfo[procedureName].Value[v] = true;
- RecordProcedureChanged();
- }
-
- private void RecordProcedureChanged()
- {
- ProcedureChanged = true;
- }
-
- private void SetNonUniform(string procedureName, string v)
- {
- uniformityInfo[procedureName].Value[v] = false;
- RecordProcedureChanged();
- }
-
- private void dump()
- {
- foreach (string p in uniformityInfo.Keys)
- {
- Console.WriteLine("Procedure " + p + ": "
- + (uniformityInfo[p].Key ? "uniform" : "nonuniform"));
- foreach (string v in uniformityInfo[p].Value.Keys)
- {
- Console.WriteLine(" " + v + ": " +
- (uniformityInfo[p].Value[v] ? "uniform" : "nonuniform"));
- }
- Console.Write("Ins [");
- for (int i = 0; i < inParameters[p].Count; i++)
- {
- Console.Write((i == 0 ? "" : ", ") + inParameters[p][i]);
- }
- Console.WriteLine("]");
- Console.Write("Outs [");
- for (int i = 0; i < outParameters[p].Count; i++)
- {
- Console.Write((i == 0 ? "" : ", ") + outParameters[p][i]);
- }
- Console.WriteLine("]");
- Console.Write("Non-uniform loops:");
- foreach (int l in nonUniformLoops[p])
- {
- Console.Write(" " + l);
- }
- Console.WriteLine();
- }
- }
-
-
- internal string GetInParameter(string procName, int i)
- {
- if (CommandLineOptions.Unstructured)
- return null;
-
- return inParameters[procName][i];
- }
-
- internal string GetOutParameter(string procName, int i)
- {
- if (CommandLineOptions.Unstructured)
- return null;
-
- return outParameters[procName][i];
- }
-
-
- internal bool knowsOf(string p)
- {
- return uniformityInfo.ContainsKey(p);
- }
-
- internal void AddNonUniform(string proc, string v)
- {
- if (uniformityInfo.ContainsKey(proc))
- {
- Debug.Assert(!uniformityInfo[proc].Value.ContainsKey(v));
- uniformityInfo[proc].Value[v] = false;
- }
- }
-
- internal bool IsUniform(string proc, WhileCmd wc)
- {
- if (CommandLineOptions.Unstructured)
- return false;
-
- return !nonUniformLoops[proc].Contains(GetLoopId(wc));
- }
-
- internal bool HasNonuniformReturn(string proc, WhileCmd whileCmd)
- {
- return loopsWithNonuniformReturn[proc].Contains(GetLoopId(whileCmd));
- }
- }
-
-}
+ }
+ }
+ }
+ else if (c is CallCmd)
+ {
+ CallCmd callCmd = c as CallCmd;
+ Implementation CalleeImplementation = GetImplementation(callCmd.callee);
+
+ if (CalleeImplementation != null)
+ {
+
+ if (!ControlFlowIsUniform)
+ {
+ if (IsUniform(callCmd.callee))
+ {
+ SetNonUniform(callCmd.callee);
+ }
+ }
+ for (int i = 0; i < CalleeImplementation.InParams.Length; i++)
+ {
+ if (IsUniform(callCmd.callee, CalleeImplementation.InParams[i].Name)
+ && !IsUniform(impl.Name, callCmd.Ins[i]))
+ {
+ SetNonUniform(callCmd.callee, CalleeImplementation.InParams[i].Name);
+ }
+ }
+
+ for (int i = 0; i < CalleeImplementation.OutParams.Length; i++)
+ {
+ if (IsUniform(impl.Name, callCmd.Outs[i].Name)
+ && !IsUniform(callCmd.callee, CalleeImplementation.OutParams[i].Name))
+ {
+ SetNonUniform(impl.Name, callCmd.Outs[i].Name);
+ }
+ }
+
+ }
+ }
+ else if (c is AssumeCmd)
+ {
+ var ac = (AssumeCmd)c;
+ if (ControlFlowIsUniform && QKeyValue.FindBoolAttribute(ac.Attributes, "partition") &&
+ !IsUniform(impl.Name, ac.Expr))
+ {
+ ControlFlowIsUniform = false;
+ }
+ }
+ }
+
+ return ControlFlowIsUniform;
+ }
+
+ private int GetLoopId(WhileCmd wc)
+ {
+ AssertCmd inv = wc.Invariants[0] as AssertCmd;
+ Debug.Assert(inv.Attributes.Key.Contains("loophead_"));
+ return Convert.ToInt32(inv.Attributes.Key.Substring("loophead_".Length));
+ }
+
+ private void SetNonUniform(string procedureName)
+ {
+ uniformityInfo[procedureName] = new KeyValuePair<bool,Dictionary<string,bool>>
+ (false, uniformityInfo[procedureName].Value);
+ RecordProcedureChanged();
+ }
+
+ private void SetNonUniform(string procedureName, WhileCmd wc)
+ {
+ nonUniformLoops[procedureName].Add(GetLoopId(wc));
+ RecordProcedureChanged();
+ }
+
+ public bool IsUniform(string procedureName)
+ {
+ if (!uniformityInfo.ContainsKey(procedureName))
+ {
+ return false;
+ }
+ return uniformityInfo[procedureName].Key;
+ }
+
+ public bool IsUniform(string procedureName, Block b)
+ {
+ if (!nonUniformBlocks.ContainsKey(procedureName))
+ {
+ return false;
+ }
+ return !nonUniformBlocks[procedureName].Contains(b);
+ }
+
+ class UniformExpressionAnalysisVisitor : StandardVisitor {
+
+ private bool isUniform = true;
+ private Dictionary<string, bool> uniformityInfo;
+
+ public UniformExpressionAnalysisVisitor(Dictionary<string, bool> uniformityInfo) {
+ this.uniformityInfo = uniformityInfo;
+ }
+
+ public override Variable VisitVariable(Variable v) {
+ if (!uniformityInfo.ContainsKey(v.Name)) {
+ isUniform = isUniform && (v is Constant);
+ } else if (!uniformityInfo[v.Name]) {
+ isUniform = false;
+ }
+
+ return v;
+ }
+
+ internal bool IsUniform() {
+ return isUniform;
+ }
+ }
+
+ public bool IsUniform(string procedureName, Expr expr)
+ {
+ UniformExpressionAnalysisVisitor visitor = new UniformExpressionAnalysisVisitor(uniformityInfo[procedureName].Value);
+ visitor.VisitExpr(expr);
+ return visitor.IsUniform();
+ }
+
+ public bool IsUniform(string procedureName, string v)
+ {
+ if (!uniformityInfo.ContainsKey(procedureName))
+ {
+ return false;
+ }
+
+ if (!uniformityInfo[procedureName].Value.ContainsKey(v))
+ {
+ return false;
+ }
+ return uniformityInfo[procedureName].Value[v];
+ }
+
+ private void SetUniform(string procedureName, string v)
+ {
+ uniformityInfo[procedureName].Value[v] = true;
+ RecordProcedureChanged();
+ }
+
+ private void RecordProcedureChanged()
+ {
+ ProcedureChanged = true;
+ }
+
+ private void SetNonUniform(string procedureName, string v)
+ {
+ uniformityInfo[procedureName].Value[v] = false;
+ RecordProcedureChanged();
+ }
+
+ public void dump()
+ {
+ foreach (string p in uniformityInfo.Keys)
+ {
+ Console.WriteLine("Procedure " + p + ": "
+ + (uniformityInfo[p].Key ? "uniform" : "nonuniform"));
+ foreach (string v in uniformityInfo[p].Value.Keys)
+ {
+ Console.WriteLine(" " + v + ": " +
+ (uniformityInfo[p].Value[v] ? "uniform" : "nonuniform"));
+ }
+ Console.Write("Ins [");
+ for (int i = 0; i < inParameters[p].Count; i++)
+ {
+ Console.Write((i == 0 ? "" : ", ") + inParameters[p][i]);
+ }
+ Console.WriteLine("]");
+ Console.Write("Outs [");
+ for (int i = 0; i < outParameters[p].Count; i++)
+ {
+ Console.Write((i == 0 ? "" : ", ") + outParameters[p][i]);
+ }
+ Console.WriteLine("]");
+ Console.Write("Non-uniform loops:");
+ foreach (int l in nonUniformLoops[p])
+ {
+ Console.Write(" " + l);
+ }
+ Console.WriteLine();
+ Console.Write("Non-uniform blocks:");
+ foreach (Block b in nonUniformBlocks[p])
+ {
+ Console.Write(" " + b.Label);
+ }
+ Console.WriteLine();
+ }
+ }
+
+
+ public string GetInParameter(string procName, int i)
+ {
+ return inParameters[procName][i];
+ }
+
+ public string GetOutParameter(string procName, int i)
+ {
+ return outParameters[procName][i];
+ }
+
+
+ public bool knowsOf(string p)
+ {
+ return uniformityInfo.ContainsKey(p);
+ }
+
+ public void AddNonUniform(string proc, string v)
+ {
+ if (uniformityInfo.ContainsKey(proc))
+ {
+ Debug.Assert(!uniformityInfo[proc].Value.ContainsKey(v));
+ uniformityInfo[proc].Value[v] = false;
+ }
+ }
+
+ public bool IsUniform(string proc, WhileCmd wc)
+ {
+ if (unstructured)
+ return false;
+
+ return !nonUniformLoops[proc].Contains(GetLoopId(wc));
+ }
+
+ public bool HasNonuniformReturn(string proc, WhileCmd whileCmd)
+ {
+ return loopsWithNonuniformReturn[proc].Contains(GetLoopId(whileCmd));
+ }
+ }
+
+}
diff --git a/Source/VCGeneration/VC.cs b/Source/VCGeneration/VC.cs
index 4fa7f0b7..2ac8dc83 100644
--- a/Source/VCGeneration/VC.cs
+++ b/Source/VCGeneration/VC.cs
@@ -1819,9 +1819,11 @@ namespace VC {
if (a is AssertCmd) {
Bpl.AssertCmd c = (AssertCmd) a;
Bpl.AssertCmd b = new Bpl.LoopInitAssertCmd(c.tok, c.Expr);
+ b.Attributes = c.Attributes;
b.ErrorData = c.ErrorData;
prefixOfPredicateCmdsInit.Add(b);
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);
diff --git a/Source/VCGeneration/VCGeneration.csproj b/Source/VCGeneration/VCGeneration.csproj
index 39da0be6..fe7ddc70 100644
--- a/Source/VCGeneration/VCGeneration.csproj
+++ b/Source/VCGeneration/VCGeneration.csproj
@@ -1,226 +1,228 @@
-<?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>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>
- </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>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="BlockPredicator.cs" />
- <Compile Include="Check.cs" />
- <Compile Include="ConditionGeneration.cs" />
- <Compile Include="Context.cs" />
- <Compile Include="DoomCheck.cs" />
- <Compile Include="DoomedLoopUnrolling.cs" />
- <Compile Include="DoomedStrategy.cs" />
- <Compile Include="DoomErrorHandler.cs" />
- <Compile Include="GraphAlgorithms.cs" />
- <Compile Include="HasseDiagram.cs" />
- <Compile Include="OrderingAxioms.cs" />
- <Compile Include="StratifiedVC.cs" />
- <Compile Include="VC.cs" />
- <Compile Include="VCDoomed.cs" />
- <Compile Include="..\version.cs" />
- <Compile Include="Wlp.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\AIFramework\AIFramework.csproj">
- <Project>{39B0658D-C955-41C5-9A43-48C97A1EF5FD}</Project>
- <Name>AIFramework</Name>
- </ProjectReference>
- <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>
- -->
+<?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>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>
+ </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>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="BlockPredicator.cs" />
+ <Compile Include="Check.cs" />
+ <Compile Include="ConditionGeneration.cs" />
+ <Compile Include="Context.cs" />
+ <Compile Include="DoomCheck.cs" />
+ <Compile Include="DoomedLoopUnrolling.cs" />
+ <Compile Include="DoomedStrategy.cs" />
+ <Compile Include="DoomErrorHandler.cs" />
+ <Compile Include="GraphAlgorithms.cs" />
+ <Compile Include="HasseDiagram.cs" />
+ <Compile Include="OrderingAxioms.cs" />
+ <Compile Include="SmartBlockPredicator.cs" />
+ <Compile Include="StratifiedVC.cs" />
+ <Compile Include="UniformityAnalyser.cs" />
+ <Compile Include="VC.cs" />
+ <Compile Include="VCDoomed.cs" />
+ <Compile Include="..\version.cs" />
+ <Compile Include="Wlp.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\AIFramework\AIFramework.csproj">
+ <Project>{39B0658D-C955-41C5-9A43-48C97A1EF5FD}</Project>
+ <Name>AIFramework</Name>
+ </ProjectReference>
+ <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> \ No newline at end of file
diff --git a/Test/VSComp2010/Problem2-Invert.dfy b/Test/VSComp2010/Problem2-Invert.dfy
index 2a262d70..0f7c50c1 100644
--- a/Test/VSComp2010/Problem2-Invert.dfy
+++ b/Test/VSComp2010/Problem2-Invert.dfy
@@ -43,6 +43,7 @@ method M(N: int, A: array<int>, B: array<int>)
assert (forall i :: 0 <= i && i < N ==> A[i] == old(A[i])); // the elements of A were not changed by the loop
// it now follows from the surjectivity of A that A is the inverse of B:
assert (forall j :: 0 <= j && j < N && inImage(j) ==> 0 <= B[j] && B[j] < N && A[B[j]] == j);
+ assert (forall j,k :: 0 <= j && j < k && k < N ==> B[j] != B[k]);
}
static function inImage(i: int): bool { true } // this function is used to trigger the surjective quantification
diff --git a/Test/VSI-Benchmarks/b4.dfy b/Test/VSI-Benchmarks/b4.dfy
index 76e1ffa7..d5a56df4 100644
--- a/Test/VSI-Benchmarks/b4.dfy
+++ b/Test/VSI-Benchmarks/b4.dfy
@@ -1,6 +1,5 @@
/*
- This test fails with Z3 2.4 (on Win7 x64) and works
- with Z3 2.9 (on Win7 x64). Other versions ... who knows.
+ This test works with Z3 3.2 and Z3 4.1 (on Win7 x64). Other versions ... who knows.
*/
// Note: We are using the built-in equality to compare keys.
@@ -111,8 +110,6 @@ class Map<Key(==),Value> {
if (p != null) {
Keys := Keys[..n] + Keys[n+1..];
Values := Values[..n] + Values[n+1..];
- assert Keys[n..] == old(Keys)[n+1..];
- assert Values[n..] == old(Values)[n+1..];
nodes := nodes[..n] + nodes[n+1..];
if (prev == null) {
@@ -120,6 +117,8 @@ class Map<Key(==),Value> {
} else {
prev.next := p.next;
}
+ assert Keys[n..] == old(Keys)[n+1..];
+ assert Values[n..] == old(Values)[n+1..];
}
}
diff --git a/Test/dafny0/Answer b/Test/dafny0/Answer
index cfa79f1a..b7d48d7e 100644
--- a/Test/dafny0/Answer
+++ b/Test/dafny0/Answer
@@ -190,42 +190,39 @@ Execution trace:
(0,0): anon28_Then
(0,0): anon29_Then
(0,0): anon19
-SmallTests.dfy(199,14): Error: assertion violation
+SmallTests.dfy(195,14): Error: assertion violation
Execution trace:
(0,0): anon0
- (0,0): anon12_Then
-SmallTests.dfy(206,14): Error: assertion violation
+ (0,0): anon6_Then
+SmallTests.dfy(202,14): Error: assertion violation
Execution trace:
(0,0): anon0
- (0,0): anon12_Else
+ (0,0): anon6_Else
(0,0): anon3
- (0,0): anon13_Then
-SmallTests.dfy(226,12): Error: assertion violation
+ (0,0): anon7_Then
+SmallTests.dfy(204,14): Error: assertion violation
Execution trace:
(0,0): anon0
- (0,0): anon12_Else
+ (0,0): anon6_Else
(0,0): anon3
- (0,0): anon13_Else
- (0,0): anon6
- (0,0): anon14_Then
- (0,0): anon11
-SmallTests.dfy(271,24): Error BP5002: A precondition for this call might not hold.
-SmallTests.dfy(249,30): Related location: This is the precondition that might not hold.
+ (0,0): anon7_Else
+SmallTests.dfy(250,24): Error BP5002: A precondition for this call might not hold.
+SmallTests.dfy(228,30): Related location: This is the precondition that might not hold.
Execution trace:
(0,0): anon0
- SmallTests.dfy(266,19): anon3_Else
+ SmallTests.dfy(245,19): anon3_Else
(0,0): anon2
-SmallTests.dfy(376,12): Error: assertion violation
+SmallTests.dfy(355,12): Error: assertion violation
Execution trace:
(0,0): anon0
-SmallTests.dfy(386,12): Error: assertion violation
+SmallTests.dfy(365,12): Error: assertion violation
Execution trace:
(0,0): anon0
-SmallTests.dfy(396,6): Error: cannot prove termination; try supplying a decreases clause
+SmallTests.dfy(375,6): Error: cannot prove termination; try supplying a decreases clause
Execution trace:
(0,0): anon3_Else
-SmallTests.dfy(306,3): Error BP5003: A postcondition might not hold on this return path.
-SmallTests.dfy(300,11): Related location: This is the postcondition that might not hold.
+SmallTests.dfy(285,3): Error BP5003: A postcondition might not hold on this return path.
+SmallTests.dfy(279,11): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon0
(0,0): anon18_Else
@@ -234,27 +231,27 @@ Execution trace:
(0,0): anon24_Then
(0,0): anon15
(0,0): anon25_Else
-SmallTests.dfy(347,12): Error: assertion violation
+SmallTests.dfy(326,12): Error: assertion violation
Execution trace:
(0,0): anon0
(0,0): anon8_Then
(0,0): anon7
-SmallTests.dfy(354,10): Error: assertion violation
+SmallTests.dfy(333,10): Error: assertion violation
Execution trace:
(0,0): anon0
-SmallTests.dfy(364,4): Error: cannot prove termination; try supplying a decreases clause
+SmallTests.dfy(343,4): Error: cannot prove termination; try supplying a decreases clause
Execution trace:
(0,0): anon3_Else
-SmallTests.dfy(408,10): Error BP5003: A postcondition might not hold on this return path.
-SmallTests.dfy(411,41): Related location: This is the postcondition that might not hold.
+SmallTests.dfy(387,10): Error BP5003: A postcondition might not hold on this return path.
+SmallTests.dfy(390,41): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon6_Else
-SmallTests.dfy(561,12): Error: assertion violation
+SmallTests.dfy(540,12): Error: assertion violation
Execution trace:
(0,0): anon0
(0,0): anon3_Then
(0,0): anon2
-SmallTests.dfy(575,20): Error: left-hand sides 0 and 1 may refer to the same location
+SmallTests.dfy(554,20): Error: left-hand sides 0 and 1 may refer to the same location
Execution trace:
(0,0): anon0
(0,0): anon27_Then
@@ -266,11 +263,11 @@ Execution trace:
(0,0): anon31_Then
(0,0): anon32_Then
(0,0): anon12
-SmallTests.dfy(577,15): Error: left-hand sides 1 and 2 may refer to the same location
+SmallTests.dfy(556,15): Error: left-hand sides 1 and 2 may refer to the same location
Execution trace:
(0,0): anon0
(0,0): anon27_Then
- SmallTests.dfy(570,18): anon28_Else
+ SmallTests.dfy(549,18): anon28_Else
(0,0): anon4
(0,0): anon29_Else
(0,0): anon7
@@ -282,14 +279,14 @@ Execution trace:
(0,0): anon37_Then
(0,0): anon22
(0,0): anon38_Then
-SmallTests.dfy(584,25): Error: target object may be null
+SmallTests.dfy(563,25): Error: target object may be null
Execution trace:
(0,0): anon0
-SmallTests.dfy(597,10): Error: assertion violation
+SmallTests.dfy(576,10): Error: assertion violation
Execution trace:
(0,0): anon0
-Dafny program verifier finished with 68 verified, 26 errors
+Dafny program verifier finished with 70 verified, 26 errors
-------------------- Definedness.dfy --------------------
Definedness.dfy(8,7): Error: possible division by zero
@@ -489,8 +486,12 @@ Execution trace:
(0,0): anon0
(0,0): anon9_Then
(0,0): anon3
+FunctionSpecifications.dfy(56,10): Error BP5003: A postcondition might not hold on this return path.
+FunctionSpecifications.dfy(57,22): Related location: This is the postcondition that might not hold.
+Execution trace:
+ (0,0): anon5_Else
-Dafny program verifier finished with 3 verified, 3 errors
+Dafny program verifier finished with 3 verified, 4 errors
-------------------- ResolutionErrors.dfy --------------------
ResolutionErrors.dfy(48,13): Error: 'this' is not allowed in a 'static' context
@@ -760,6 +761,14 @@ Execution trace:
Dafny program verifier finished with 22 verified, 5 errors
+-------------------- Modules2.dfy --------------------
+Modules2.dfy(44,17): Error: The name C ambiguously refers to a type in one of the modules A, B (try qualifying the type name with the module name)
+Modules2.dfy(44,10): Error: new can be applied only to reference types (got C)
+Modules2.dfy(47,14): Error: the name 'E' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, 'D.E')
+Modules2.dfy(48,14): Error: The name D ambiguously refers to a type in one of the modules A, B
+Modules2.dfy(50,11): Error: The name f ambiguously refers to a static member in one of the modules A, B
+5 resolution/type errors detected in Modules2.dfy
+
-------------------- BadFunction.dfy --------------------
BadFunction.dfy(6,3): Error: failure to decrease termination measure
Execution trace:
@@ -1447,12 +1456,12 @@ Refinement.dfy(74,15): Related location: This is the postcondition that might no
Execution trace:
(0,0): anon0
Refinement.dfy(180,5): Error BP5003: A postcondition might not hold on this return path.
-Refinement.dfy(112,15): Related location: This is the postcondition that might not hold.
+Refinement.dfy[IncorrectConcrete](112,15): Related location: This is the postcondition that might not hold.
Refinement.dfy(177,9): Related location: Related location
Execution trace:
(0,0): anon0
Refinement.dfy(184,5): Error BP5003: A postcondition might not hold on this return path.
-Refinement.dfy(120,15): Related location: This is the postcondition that might not hold.
+Refinement.dfy[IncorrectConcrete](120,15): Related location: This is the postcondition that might not hold.
Refinement.dfy(177,9): Related location: Related location
Execution trace:
(0,0): anon0
@@ -1594,10 +1603,65 @@ LiberalEquality.dfy(52,14): Error: arguments must have the same type (got array<
3 resolution/type errors detected in LiberalEquality.dfy
-------------------- RefinementModificationChecking.dfy --------------------
-RefinementModificationChecking.dfy(16,4): Error: cannot assign to variable defined previously
RefinementModificationChecking.dfy(17,4): Error: cannot assign to variable defined previously
-RefinementModificationChecking.dfy(18,4): Error: cannot assign to field defined previously
-3 resolution/type errors detected in RefinementModificationChecking.dfy
+RefinementModificationChecking.dfy(18,4): Error: cannot assign to variable defined previously
+2 resolution/type errors detected in RefinementModificationChecking.dfy
+
+-------------------- TailCalls.dfy --------------------
+TailCalls.dfy(18,15): Error: this recursive call is not recognized as being tail recursive, because it is followed by non-ghost code
+TailCalls.dfy(30,12): Error: 'decreases *' is allowed only on tail-recursive methods
+TailCalls.dfy(37,12): Error: 'decreases *' is allowed only on tail-recursive methods
+TailCalls.dfy(42,12): Error: 'decreases *' is allowed only on tail-recursive methods
+TailCalls.dfy(64,12): Error: 'decreases *' is allowed only on tail-recursive methods
+5 resolution/type errors detected in TailCalls.dfy
+
+-------------------- Superposition.dfy --------------------
+
+Verifying CheckWellformed$$_0_M0.C.M ...
+ [0 proof obligations] verified
+
+Verifying _0_M0.C.M ...
+ [4 proof obligations] verified
+
+Verifying CheckWellformed$$_0_M0.C.P ...
+ [4 proof obligations] verified
+
+Verifying CheckWellformed$$_0_M0.C.Q ...
+Superposition.dfy(24,15): Error BP5003: A postcondition might not hold on this return path.
+Superposition.dfy(25,26): Related location: This is the postcondition that might not hold.
+Execution trace:
+ (0,0): anon5_Else
+ [3 proof obligations] error
+
+Verifying CheckWellformed$$_0_M0.C.R ...
+Superposition.dfy(30,15): Error BP5003: A postcondition might not hold on this return path.
+Superposition.dfy(31,26): Related location: This is the postcondition that might not hold.
+Execution trace:
+ (0,0): anon5_Else
+ [3 proof obligations] error
+
+Verifying CheckWellformed$$_1_M1.C.M ...
+ [0 proof obligations] verified
+
+Verifying RefinementImpl_M1$$_1_M1.C.M ...
+ [0 proof obligations] verified
+
+Verifying CheckWellformed$$_1_M1.C.P ...
+Superposition.dfy(47,15): Error BP5003: A postcondition might not hold on this return path.
+Superposition.dfy[M1](19,26): Related location: This is the postcondition that might not hold.
+Execution trace:
+ (0,0): anon7_Else
+ (0,0): anon9_Then
+ (0,0): anon6
+ [1 proof obligation] error
+
+Verifying CheckWellformed$$_1_M1.C.Q ...
+ [0 proof obligations] verified
+
+Verifying CheckWellformed$$_1_M1.C.R ...
+ [0 proof obligations] verified
+
+Dafny program verifier finished with 7 verified, 3 errors
-------------------- SmallTests.dfy --------------------
SmallTests.dfy(30,11): Error: index out of range
@@ -1648,42 +1712,39 @@ Execution trace:
(0,0): anon28_Then
(0,0): anon29_Then
(0,0): anon19
-SmallTests.dfy(199,14): Error: assertion violation
+SmallTests.dfy(195,14): Error: assertion violation
Execution trace:
(0,0): anon0
- (0,0): anon12_Then
-SmallTests.dfy(206,14): Error: assertion violation
+ (0,0): anon6_Then
+SmallTests.dfy(202,14): Error: assertion violation
Execution trace:
(0,0): anon0
- (0,0): anon12_Else
+ (0,0): anon6_Else
(0,0): anon3
- (0,0): anon13_Then
-SmallTests.dfy(226,12): Error: assertion violation
+ (0,0): anon7_Then
+SmallTests.dfy(204,14): Error: assertion violation
Execution trace:
(0,0): anon0
- (0,0): anon12_Else
+ (0,0): anon6_Else
(0,0): anon3
- (0,0): anon13_Else
- (0,0): anon6
- (0,0): anon14_Then
- (0,0): anon11
-SmallTests.dfy(271,24): Error BP5002: A precondition for this call might not hold.
-SmallTests.dfy(249,30): Related location: This is the precondition that might not hold.
+ (0,0): anon7_Else
+SmallTests.dfy(250,24): Error BP5002: A precondition for this call might not hold.
+SmallTests.dfy(228,30): Related location: This is the precondition that might not hold.
Execution trace:
(0,0): anon0
- SmallTests.dfy(266,19): anon3_Else
+ SmallTests.dfy(245,19): anon3_Else
(0,0): anon2
-SmallTests.dfy(376,12): Error: assertion violation
+SmallTests.dfy(355,12): Error: assertion violation
Execution trace:
(0,0): anon0
-SmallTests.dfy(386,12): Error: assertion violation
+SmallTests.dfy(365,12): Error: assertion violation
Execution trace:
(0,0): anon0
-SmallTests.dfy(396,6): Error: cannot prove termination; try supplying a decreases clause
+SmallTests.dfy(375,6): Error: cannot prove termination; try supplying a decreases clause
Execution trace:
(0,0): anon3_Else
-SmallTests.dfy(306,3): Error BP5003: A postcondition might not hold on this return path.
-SmallTests.dfy(300,11): Related location: This is the postcondition that might not hold.
+SmallTests.dfy(285,3): Error BP5003: A postcondition might not hold on this return path.
+SmallTests.dfy(279,11): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon0
(0,0): anon18_Else
@@ -1692,27 +1753,27 @@ Execution trace:
(0,0): anon24_Then
(0,0): anon15
(0,0): anon25_Else
-SmallTests.dfy(347,12): Error: assertion violation
+SmallTests.dfy(326,12): Error: assertion violation
Execution trace:
(0,0): anon0
(0,0): anon8_Then
(0,0): anon7
-SmallTests.dfy(354,10): Error: assertion violation
+SmallTests.dfy(333,10): Error: assertion violation
Execution trace:
(0,0): anon0
-SmallTests.dfy(364,4): Error: cannot prove termination; try supplying a decreases clause
+SmallTests.dfy(343,4): Error: cannot prove termination; try supplying a decreases clause
Execution trace:
(0,0): anon3_Else
-SmallTests.dfy(408,10): Error BP5003: A postcondition might not hold on this return path.
-SmallTests.dfy(411,41): Related location: This is the postcondition that might not hold.
+SmallTests.dfy(387,10): Error BP5003: A postcondition might not hold on this return path.
+SmallTests.dfy(390,41): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon6_Else
-SmallTests.dfy(561,12): Error: assertion violation
+SmallTests.dfy(540,12): Error: assertion violation
Execution trace:
(0,0): anon0
(0,0): anon3_Then
(0,0): anon2
-SmallTests.dfy(575,20): Error: left-hand sides 0 and 1 may refer to the same location
+SmallTests.dfy(554,20): Error: left-hand sides 0 and 1 may refer to the same location
Execution trace:
(0,0): anon0
(0,0): anon27_Then
@@ -1724,11 +1785,11 @@ Execution trace:
(0,0): anon31_Then
(0,0): anon32_Then
(0,0): anon12
-SmallTests.dfy(577,15): Error: left-hand sides 1 and 2 may refer to the same location
+SmallTests.dfy(556,15): Error: left-hand sides 1 and 2 may refer to the same location
Execution trace:
(0,0): anon0
(0,0): anon27_Then
- SmallTests.dfy(570,18): anon28_Else
+ SmallTests.dfy(549,18): anon28_Else
(0,0): anon4
(0,0): anon29_Else
(0,0): anon7
@@ -1740,14 +1801,14 @@ Execution trace:
(0,0): anon37_Then
(0,0): anon22
(0,0): anon38_Then
-SmallTests.dfy(584,25): Error: target object may be null
+SmallTests.dfy(563,25): Error: target object may be null
Execution trace:
(0,0): anon0
-SmallTests.dfy(597,10): Error: assertion violation
+SmallTests.dfy(576,10): Error: assertion violation
Execution trace:
(0,0): anon0
-Dafny program verifier finished with 68 verified, 26 errors
+Dafny program verifier finished with 70 verified, 26 errors
out.tmp.dfy(33,11): Error: index out of range
Execution trace:
(0,0): anon0
@@ -1796,42 +1857,39 @@ Execution trace:
(0,0): anon28_Then
(0,0): anon29_Then
(0,0): anon19
-out.tmp.dfy(202,14): Error: assertion violation
+out.tmp.dfy(199,14): Error: assertion violation
Execution trace:
(0,0): anon0
- (0,0): anon12_Then
-out.tmp.dfy(208,14): Error: assertion violation
+ (0,0): anon6_Then
+out.tmp.dfy(205,14): Error: assertion violation
Execution trace:
(0,0): anon0
- (0,0): anon12_Else
+ (0,0): anon6_Else
(0,0): anon3
- (0,0): anon13_Then
-out.tmp.dfy(229,12): Error: assertion violation
+ (0,0): anon7_Then
+out.tmp.dfy(207,14): Error: assertion violation
Execution trace:
(0,0): anon0
- (0,0): anon12_Else
+ (0,0): anon6_Else
(0,0): anon3
- (0,0): anon13_Else
- (0,0): anon6
- (0,0): anon14_Then
- (0,0): anon11
-out.tmp.dfy(266,24): Error BP5002: A precondition for this call might not hold.
-out.tmp.dfy(247,30): Related location: This is the precondition that might not hold.
+ (0,0): anon7_Else
+out.tmp.dfy(245,24): Error BP5002: A precondition for this call might not hold.
+out.tmp.dfy(226,30): Related location: This is the precondition that might not hold.
Execution trace:
(0,0): anon0
- out.tmp.dfy(263,19): anon3_Else
+ out.tmp.dfy(242,19): anon3_Else
(0,0): anon2
-out.tmp.dfy(286,12): Error: assertion violation
+out.tmp.dfy(265,12): Error: assertion violation
Execution trace:
(0,0): anon0
-out.tmp.dfy(296,12): Error: assertion violation
+out.tmp.dfy(275,12): Error: assertion violation
Execution trace:
(0,0): anon0
-out.tmp.dfy(306,6): Error: cannot prove termination; try supplying a decreases clause
+out.tmp.dfy(285,6): Error: cannot prove termination; try supplying a decreases clause
Execution trace:
(0,0): anon3_Else
-out.tmp.dfy(422,3): Error BP5003: A postcondition might not hold on this return path.
-out.tmp.dfy(416,11): Related location: This is the postcondition that might not hold.
+out.tmp.dfy(401,3): Error BP5003: A postcondition might not hold on this return path.
+out.tmp.dfy(395,11): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon0
(0,0): anon18_Else
@@ -1840,27 +1898,27 @@ Execution trace:
(0,0): anon24_Then
(0,0): anon15
(0,0): anon25_Else
-out.tmp.dfy(446,12): Error: assertion violation
+out.tmp.dfy(425,12): Error: assertion violation
Execution trace:
(0,0): anon0
(0,0): anon8_Then
(0,0): anon7
-out.tmp.dfy(451,10): Error: assertion violation
+out.tmp.dfy(430,10): Error: assertion violation
Execution trace:
(0,0): anon0
-out.tmp.dfy(461,4): Error: cannot prove termination; try supplying a decreases clause
+out.tmp.dfy(440,4): Error: cannot prove termination; try supplying a decreases clause
Execution trace:
(0,0): anon3_Else
-out.tmp.dfy(469,10): Error BP5003: A postcondition might not hold on this return path.
-out.tmp.dfy(470,41): Related location: This is the postcondition that might not hold.
+out.tmp.dfy(448,10): Error BP5003: A postcondition might not hold on this return path.
+out.tmp.dfy(449,41): Related location: This is the postcondition that might not hold.
Execution trace:
(0,0): anon6_Else
-out.tmp.dfy(507,12): Error: assertion violation
+out.tmp.dfy(486,12): Error: assertion violation
Execution trace:
(0,0): anon0
(0,0): anon3_Then
(0,0): anon2
-out.tmp.dfy(521,20): Error: left-hand sides 0 and 1 may refer to the same location
+out.tmp.dfy(500,20): Error: left-hand sides 0 and 1 may refer to the same location
Execution trace:
(0,0): anon0
(0,0): anon27_Then
@@ -1872,11 +1930,11 @@ Execution trace:
(0,0): anon31_Then
(0,0): anon32_Then
(0,0): anon12
-out.tmp.dfy(523,15): Error: left-hand sides 1 and 2 may refer to the same location
+out.tmp.dfy(502,15): Error: left-hand sides 1 and 2 may refer to the same location
Execution trace:
(0,0): anon0
(0,0): anon27_Then
- out.tmp.dfy(516,18): anon28_Else
+ out.tmp.dfy(495,18): anon28_Else
(0,0): anon4
(0,0): anon29_Else
(0,0): anon7
@@ -1888,14 +1946,14 @@ Execution trace:
(0,0): anon37_Then
(0,0): anon22
(0,0): anon38_Then
-out.tmp.dfy(530,25): Error: target object may be null
+out.tmp.dfy(509,25): Error: target object may be null
Execution trace:
(0,0): anon0
-out.tmp.dfy(543,10): Error: assertion violation
+out.tmp.dfy(522,10): Error: assertion violation
Execution trace:
(0,0): anon0
-Dafny program verifier finished with 68 verified, 26 errors
+Dafny program verifier finished with 70 verified, 26 errors
-------------------- LetExpr.dfy --------------------
LetExpr.dfy(5,12): Error: assertion violation
diff --git a/Test/dafny0/Compilation.dfy b/Test/dafny0/Compilation.dfy
index fe6eda47..c9545c93 100644
--- a/Test/dafny0/Compilation.dfy
+++ b/Test/dafny0/Compilation.dfy
@@ -73,9 +73,9 @@ module T refines S {
}
}
module A {
- module X as S = T;
- module Y as S = T;
- module Z = T;
+ import X as S default T;
+ import Y as S default T;
+ import Z = T;
static method run() {
var x := new X.C;
x.m();
@@ -92,7 +92,7 @@ method NotMain() {
ghost module S1 {
- module B as S = T;
+ import B as S default T;
static method do()
}
@@ -102,7 +102,7 @@ module T1 refines S1 {
}
}
module A1 {
- module X as S1 = T1;
+ import X as S1 default T1;
static method run() {
X.do();
var x := new X.B.C;
diff --git a/Test/dafny0/Datatypes.dfy b/Test/dafny0/Datatypes.dfy
index c4899f38..70177ef4 100644
--- a/Test/dafny0/Datatypes.dfy
+++ b/Test/dafny0/Datatypes.dfy
@@ -92,24 +92,24 @@ method TestAllocatednessAxioms(a: List<Node>, b: List<Node>, c: List<AnotherNode
}
class NestedMatchExpr {
- function Cadr<T>(a: List<T>, default: T): T
+ function Cadr<T>(a: List<T>, Default: T): T
{
match a
- case Nil => default
+ case Nil => Default
case Cons(x,t) =>
match t
- case Nil => default
+ case Nil => Default
case Cons(y,tail) => y
}
// CadrAlt is the same as Cadr, but it writes its two outer cases in the opposite order
- function CadrAlt<T>(a: List<T>, default: T): T
+ function CadrAlt<T>(a: List<T>, Default: T): T
{
match a
case Cons(x,t) => (
match t
- case Nil => default
+ case Nil => Default
case Cons(y,tail) => y)
- case Nil => default
+ case Nil => Default
}
method TestNesting0()
{
diff --git a/Test/dafny0/FunctionSpecifications.dfy b/Test/dafny0/FunctionSpecifications.dfy
index 13171c47..44709ce8 100644
--- a/Test/dafny0/FunctionSpecifications.dfy
+++ b/Test/dafny0/FunctionSpecifications.dfy
@@ -52,3 +52,9 @@ function DivergentPost(n: int): int
if n < 2 then n else
DivergentPost(n-2) + DivergentPost(n-1)
}
+
+function HoldsAtLeastForZero(x: int): bool
+ ensures x == 0 ==> HoldsAtLeastForZero(x);
+{
+ x < -2 // error: this does not hold for 0
+}
diff --git a/Test/dafny0/Modules0.dfy b/Test/dafny0/Modules0.dfy
index 273c88de..2bc3c4be 100644
--- a/Test/dafny0/Modules0.dfy
+++ b/Test/dafny0/Modules0.dfy
@@ -24,15 +24,15 @@ module N {
}
module U {
- module NN = N;
+ import NN = N;
}
module A { // Note, this has the effect of importing two different T's,
// but that's okay as long as the module doesn't try to access
// one of them
- module MM = M;
- module NN = N;
+ import MM = M;
+ import NN = N;
class X {
var t: MM.T; // error: use of the ambiguous name T
function F(x: MM.T): // error: use of the ambiguous name T
@@ -57,7 +57,7 @@ module X0 {
}
module X1 {
- module X0' = X0;
+ import X0' = X0;
class MyClass1 {
method Down(x0: X0'.MyClass0) {
x0.Down();
@@ -213,7 +213,7 @@ module ATr {
}
module BTr {
- module A = ATr;
+ import A = ATr;
class Y {
method N() returns (x: A.X)
ensures x != null;
@@ -224,14 +224,14 @@ module BTr {
}
module CTr {
- module B = BTr;
+ import B = BTr;
class Z {
var b: B.Y; // fine
var a: B.X; // error: imports don't reach name X explicitly
}
}
module CTs {
- module B = BTr;
+ import B = BTr;
method P() {
var y := new B.Y;
var x := y.N(); // this is allowed and will correctly infer the type of x to
@@ -270,8 +270,8 @@ module NonLocalB {
}
module Local {
- module AA = NonLocalA;
- module BB = NonLocalB;
+ import AA = NonLocalA;
+ import BB = NonLocalB;
class MyClass {
method MyMethod()
{
diff --git a/Test/dafny0/Modules1.dfy b/Test/dafny0/Modules1.dfy
index 6fd8560e..1f47f3b1 100644
--- a/Test/dafny0/Modules1.dfy
+++ b/Test/dafny0/Modules1.dfy
@@ -1,5 +1,5 @@
module A {
- module B = Babble;
+ import B = Babble;
class X {
function Fx(z: B.Z): int
requires z != null;
@@ -80,7 +80,7 @@ module A_Visibility {
}
module B_Visibility {
- module A = A_Visibility;
+ import A = A_Visibility;
method Main() {
var y;
if (A.C.P(y)) {
@@ -102,7 +102,7 @@ module Q_Imp {
}
module Q_M {
- module Q = Q_Imp;
+ import Q = Q_Imp;
method MyMethod(root: Q.Node, S: set<Q.Node>)
requires root in S;
{
diff --git a/Test/dafny0/Modules2.dfy b/Test/dafny0/Modules2.dfy
new file mode 100644
index 00000000..2a5b2be7
--- /dev/null
+++ b/Test/dafny0/Modules2.dfy
@@ -0,0 +1,57 @@
+
+module A {
+ class C {
+ var f: int;
+ }
+ datatype D = E(int) | F(int);
+ static function f(n:nat): nat
+}
+module B {
+ class C {
+ var f: int;
+ }
+ datatype D = E(int) | F(int);
+ static function f(n:nat): nat
+}
+module Test {
+ import opened A; // nice shorthand for import opened A = A; (see below)
+ method m() {
+ var c := new C; // fine, as A was opened
+ var c' := new A.C;// also fine, as A is bound
+ var i := 43;
+ var d := E(i); // these all refer to the same value
+ var d' := A.E(i);
+ var d'':= A.D.E(i);
+ assert d == d' == d'';
+ assert f(3) >= 0; // true because f(x): nat
+ assert A._default.f(3) >= 0;
+ }
+}
+
+module Test2 {
+ import opened B as A;
+ method m() {
+ var c := new C; // fine, as A was opened
+ var c' := new B.C;// also fine, as A is bound
+ assert B.f(0) >= 0;
+ }
+}
+
+module Test3 {
+ import opened A;
+ import opened B; // everything in B clashes with A
+ method m() {
+ var c := new C; // bad, ambiguous between A.C and B.C
+ var c' := new A.C; // good: qualified.
+ var i := 43;
+ var d := E(i); // bad, as both A and B give a definition of E
+ var d' := D.E(i); // bad, as D is still itself ambiguous.
+ var d'':= B.D.E(i); // good, just use the B version
+ assert f(3) >= 0; // bad because A and be both define f statically.
+ }
+}
+
+module Test4 {
+ import A = A; // good: looks strange, but A is not bound on the RHS of the equality
+ import B; // the same as the above, but for module B
+} \ No newline at end of file
diff --git a/Test/dafny0/ModulesCycle.dfy b/Test/dafny0/ModulesCycle.dfy
index 15cad8e8..72b7e6fb 100644
--- a/Test/dafny0/ModulesCycle.dfy
+++ b/Test/dafny0/ModulesCycle.dfy
@@ -1,12 +1,12 @@
module V {
- module t = T; // error: T is not visible (and isn't even a module)
+ import t = T; // error: T is not visible (and isn't even a module)
}
module A {
- module B = C;
+ import B = C;
}
module C {
- module D = A;
+ import D = A;
} \ No newline at end of file
diff --git a/Test/dafny0/Predicates.dfy b/Test/dafny0/Predicates.dfy
index 8857482f..19375ac2 100644
--- a/Test/dafny0/Predicates.dfy
+++ b/Test/dafny0/Predicates.dfy
@@ -79,7 +79,7 @@ module Tight refines Loose {
}
module UnawareClient {
- module L = Loose;
+ import L = Loose;
method Main0() {
var n := new L.MyNumber.Init();
assert n.N == 0; // error: this is not known
@@ -91,7 +91,7 @@ module UnawareClient {
}
module AwareClient {
- module T = Tight;
+ import T = Tight;
method Main1() {
var n := new T.MyNumber.Init();
assert n.N == 0;
diff --git a/Test/dafny0/Refinement.dfy b/Test/dafny0/Refinement.dfy
index 2c2fc52b..e5c06a5e 100644
--- a/Test/dafny0/Refinement.dfy
+++ b/Test/dafny0/Refinement.dfy
@@ -156,7 +156,7 @@ module Concrete refines Abstract {
}
module Client {
- module C = Concrete;
+ import C = Concrete;
class TheClient {
method Main() {
var n := new C.MyNumber.Init();
diff --git a/Test/dafny0/RefinementModificationChecking.dfy b/Test/dafny0/RefinementModificationChecking.dfy
index 887c3595..dbf39106 100644
--- a/Test/dafny0/RefinementModificationChecking.dfy
+++ b/Test/dafny0/RefinementModificationChecking.dfy
@@ -2,6 +2,7 @@
ghost module R1 {
var f: int;
method m(y: set<int>) returns (r: int)
+ modifies this;
{
var t := y;
}
@@ -13,9 +14,9 @@ ghost module R2 refines R1 {
{
...;
var x := 3;
- t := {1}; // bad: previous local
- r := 3; // bad: out parameter
- f := 4; // bad: previous field
+ t := {1}; // error: previous local
+ r := 3; // error: out parameter
+ f := 4; // fine: all fields, will cause re-verification
x := 6; // fine: new local
g := 34;// fine: new field
}
diff --git a/Test/dafny0/SmallTests.dfy b/Test/dafny0/SmallTests.dfy
index 40df1135..7b409a67 100644
--- a/Test/dafny0/SmallTests.dfy
+++ b/Test/dafny0/SmallTests.dfy
@@ -188,42 +188,21 @@ class Modifies {
class AllocatedTests {
method M(r: AllocatedTests, k: Node, S: set<Node>, d: Lindgren)
{
- assert allocated(r);
-
var n := new Node;
var t := S + {n};
- assert allocated(t);
-
- assert allocated(d);
+
if (*) {
- assert old(allocated(n)); // error: n was not allocated in the initial state
+ assert !fresh(n); // error: n was not allocated in the initial state
} else {
- assert !old(allocated(n)); // correct
+ assert fresh(n); // correct
}
var U := {k,n};
if (*) {
- assert old(allocated(U)); // error: n was not allocated initially
+ assert !fresh(U); // error: n was not allocated initially
} else {
- assert !old(allocated(U)); // correct (note, the assertion does NOT say: everything was unallocated in the initial state)
- }
-
- assert allocated(6);
- assert allocated(6);
- assert allocated(null);
- assert allocated(Lindgren.HerrNilsson);
-
- match (d) {
- case Pippi(n) => assert allocated(n);
- case Longstocking(q, dd) => assert allocated(q); assert allocated(dd);
- case HerrNilsson => assert old(allocated(d));
+ assert fresh(U); // correct (note, the assertion does NOT say: everything was unallocated in the initial state)
}
- var ls := Lindgren.Longstocking([], d);
- assert allocated(ls);
- assert old(allocated(ls));
-
- assert old(allocated(Lindgren.Longstocking([r], d)));
- assert old(allocated(Lindgren.Longstocking([n], d))); // error, because n was not allocated initially
}
}
@@ -542,9 +521,9 @@ method AssignSuchThat0(a: int, b: int) returns (x: int, y: int)
ensures x == a && y == b;
{
if (*) {
- x, y :| assume a <= x < a + 1 && b + a <= y + a && y <= b;
+ x, y :| a <= x < a + 1 && b + a <= y + a && y <= b;
} else {
- var xx, yy :| assume a <= xx < a + 1 && b + a <= yy + a && yy <= b;
+ var xx, yy :| a <= xx < a + 1 && b + a <= yy + a && yy <= b;
x, y := xx, yy;
}
}
@@ -553,10 +532,10 @@ method AssignSuchThat1(a: int, b: int) returns (x: int, y: int)
{
var k :| assume 0 <= k < a - b; // this acts like an 'assume 0 < a - b;'
assert b < a;
- k :| assume k == old(2*k); // note, the 'old' has no effect on local variables like k
+ k :| k == old(2*k); // note, the 'old' has no effect on local variables like k
assert k == 0;
var S := {2, 4, 7};
- var T :| assume T <= S;
+ var T :| T <= S;
assert 3 !in T;
assert T == {}; // error: T may be larger
}
@@ -593,7 +572,7 @@ method AssignSuchThat4()
method AssignSuchThat5()
{
var n := new Node;
- n :| assume fresh(n); // fine
+ n :| fresh(n); // fine
assert false; // error
}
@@ -603,3 +582,8 @@ method AssignSuchThat6()
n :| assume n != null && fresh(n); // there is no non-null fresh object, so this amounts to 'assume false;'
assert false; // no problemo
}
+
+method AssignSuchThat7<T>(A: set<T>, x: T) {
+ var B :| A <= B;
+ assert x in A ==> x in B;
+}
diff --git a/Test/dafny0/Superposition.dfy b/Test/dafny0/Superposition.dfy
new file mode 100644
index 00000000..c4e74871
--- /dev/null
+++ b/Test/dafny0/Superposition.dfy
@@ -0,0 +1,56 @@
+module M0 {
+ class C {
+ method M(c: C, x: int, y: int) returns (r: int)
+ requires 0 <= x && 0 <= y;
+ ensures r < 100;
+ {
+ if (c == null) {
+ assert c == null;
+ } else if (*) {
+ assert 0 <= x;
+ } else {
+ assert 0 <= y;
+ }
+ r := 8;
+ }
+
+ predicate P(x: int)
+ ensures true; // this postcondition will not be re-checked in refinements, because it does not mention P itself (or anything else that may change in the refinement)
+ ensures x < 60 ==> P(x);
+ {
+ true
+ }
+
+ predicate Q(x: int)
+ ensures Q(x) ==> x < 60; // error: postcondition violation
+ {
+ true
+ }
+
+ predicate R(x: int)
+ ensures R(x) ==> x < 60; // error: postcondition violation
+ {
+ true
+ }
+ }
+}
+
+module M1 refines M0 {
+ class C {
+ method M... // no further proof obligations for M, which is just making M0.M more deterministic
+ {
+ if ... {}
+ else if (x == y) {}
+ else {}
+ }
+
+ predicate P... // error: inherited postcondition 'x < 60 ==> P(x)' is violated by this strengthening of P()
+ {
+ false // with this strengthening of P(), the postcondition fails (still, note that only one of the postconditions is re-checked)
+ }
+
+ predicate Q... // we don't want another error about Q's body here (because it should not be re-checked here)
+ // Ditto for R
+ }
+}
+
diff --git a/Test/dafny0/TailCalls.dfy b/Test/dafny0/TailCalls.dfy
new file mode 100644
index 00000000..0aa46348
--- /dev/null
+++ b/Test/dafny0/TailCalls.dfy
@@ -0,0 +1,74 @@
+method {:tailrecursion} A(q: int) returns (x: int, ghost y: bool, z: nat)
+{
+ if (q < 10) {
+ x, y, z := 15, true, 20;
+ } else {
+ ghost var u;
+ x, u, z := A(q-1);
+ y := !u;
+ }
+}
+
+method {:tailrecursion} B(q: int) returns (x: int, ghost y: bool, z: nat)
+{
+ if (q < 10) {
+ x, y, z := 15, true, 20;
+ } else {
+ ghost var u;
+ x, u, z := B(q-1); // error: not a tail call, because it is followed by an increment to x
+ y, x := !u, x + 1;
+ }
+}
+
+method C(q: int) returns (x: int)
+ decreases *;
+{
+ x := C(q-1);
+}
+
+method D(q: int) returns (x: int)
+ decreases *; // error: not allowed, because the method is not tail recursive
+{
+ x := D(q-1);
+ x := x + 1;
+}
+
+method E0(q: int) returns (x: int)
+ decreases *; // error: not allowed, because the method is not tail recursive (since mutually recursive methods are currently not recognized as being tail recursive)
+{
+ x := E1(q-1);
+}
+method E1(q: int) returns (x: int)
+ decreases *; // error: not allowed, because the method is not tail recursive (since mutually recursive methods are currently not recognized as being tail recursive)
+{
+ x := E0(q);
+}
+
+method F0(q: int) returns (x: int)
+ decreases *; // fine, but no 'decreases' spec is needed at all here
+{
+ x := D(q);
+}
+method F1(q: int) returns (x: int)
+ decreases 5; // since this is okay (that is, you can--for no particular reason--add a 'decreases' clause to a non-recursive method), the 'decreases *' above is also allowed
+{
+ x := D(q);
+}
+
+method {:tailrecursion} G0(q: int) returns (x: int)
+ decreases *;
+{
+ x := D(q);
+}
+method {:tailrecursion false} G1(q: int) returns (x: int)
+ decreases *; // error: even though there is no recursion in this method's body, the annotation specifically says "not tail recursive", so (the easiest thing to do in the Resolver was to) generate an error
+{
+ x := D(q);
+}
+
+method H0(q: int) returns (x: int)
+ decreases *; // fine, but no 'decreases' spec is needed at all here
+method {:tailrecursion} H1(q: int) returns (x: int)
+ decreases *; // fine, but no 'decreases' spec is needed at all here
+method H2(q: int) returns (x: int)
+ decreases 5; // fine, but no 'decreases' spec is needed at all here
diff --git a/Test/dafny0/runtest.bat b/Test/dafny0/runtest.bat
index 3b4e6e19..2055e283 100644
--- a/Test/dafny0/runtest.bat
+++ b/Test/dafny0/runtest.bat
@@ -13,7 +13,7 @@ for %%f in (Simple.dfy) do (
for %%f in (TypeTests.dfy NatTypes.dfy SmallTests.dfy Definedness.dfy
FunctionSpecifications.dfy ResolutionErrors.dfy ParseErrors.dfy
Array.dfy MultiDimArray.dfy NonGhostQuantifiers.dfy AdvancedLHS.dfy
- ModulesCycle.dfy Modules0.dfy Modules1.dfy BadFunction.dfy
+ ModulesCycle.dfy Modules0.dfy Modules1.dfy Modules2.dfy BadFunction.dfy
Comprehensions.dfy Basics.dfy ControlStructures.dfy
Termination.dfy DTypes.dfy ParallelResolveErrors.dfy Parallel.dfy
TypeParameters.dfy Datatypes.dfy
@@ -23,12 +23,18 @@ for %%f in (TypeTests.dfy NatTypes.dfy SmallTests.dfy Definedness.dfy
ReturnErrors.dfy ReturnTests.dfy ChainingDisjointTests.dfy
CallStmtTests.dfy MultiSets.dfy PredExpr.dfy LetExpr.dfy
Predicates.dfy Skeletons.dfy Maps.dfy LiberalEquality.dfy
- RefinementModificationChecking.dfy) do (
+ RefinementModificationChecking.dfy TailCalls.dfy) do (
echo.
echo -------------------- %%f --------------------
%DAFNY_EXE% /compile:0 /print:out.bpl.tmp /dprint:out.dfy.tmp %* %%f
)
+for %%f in (Superposition.dfy) do (
+ echo.
+ echo -------------------- %%f --------------------
+ %DAFNY_EXE% /compile:0 /print:out.bpl.tmp /dprint:out.dfy.tmp /tracePOs %* %%f
+)
+
for %%f in (SmallTests.dfy LetExpr.dfy) do (
echo.
echo -------------------- %%f --------------------
diff --git a/Test/dafny1/SchorrWaite-stages.dfy b/Test/dafny1/SchorrWaite-stages.dfy
index 5a4da8ce..094e7be7 100644
--- a/Test/dafny1/SchorrWaite-stages.dfy
+++ b/Test/dafny1/SchorrWaite-stages.dfy
@@ -213,9 +213,9 @@ ghost module M2 refines M1 {
// references, we need to make sure we can deal with the proof obligation for the path
// argument. For this reason, we add invariants that say that "path" and the .pathFromRoot
// field of all marked nodes contain values that make sense in the pre-state.
- invariant old(allocated(path)) && old(ReachableVia(root, path, t, S));
+ invariant !fresh(path) && old(ReachableVia(root, path, t, S));
invariant forall n :: n in S && n.marked ==> var pth := n.pathFromRoot;
- old(allocated(pth)) && old(ReachableVia(root, pth, n, S));
+ !fresh(pth) && old(ReachableVia(root, pth, n, S));
invariant forall n :: n in S && n.marked ==> old(Reachable(root, n, S));
decreases *; // keep postponing termination checking
diff --git a/Test/dafny1/SchorrWaite.dfy b/Test/dafny1/SchorrWaite.dfy
index 8da32b05..18adf491 100644
--- a/Test/dafny1/SchorrWaite.dfy
+++ b/Test/dafny1/SchorrWaite.dfy
@@ -12,6 +12,7 @@ class Node {
datatype Path = Empty | Extend(Path, Node);
+
class Main {
method RecursiveMark(root: Node, ghost S: set<Node>)
requires root in S;
@@ -213,9 +214,9 @@ class Main {
(forall j :: 0 <= j && j < |n.children| ==>
j == n.childrenVisited || n.children[j] == old(n.children[j])));
// every marked node is reachable:
- invariant old(allocated(path)); // needed to show 'path' worthy as argument to old(Reachable(...))
+ invariant !fresh(path); // needed to show 'path' worthy as argument to old(Reachable(...))
invariant old(ReachableVia(root, path, t, S));
- invariant (forall n, pth :: n in S && n.marked && pth == n.pathFromRoot ==> old(allocated(pth)));
+ invariant (forall n, pth :: n in S && n.marked && pth == n.pathFromRoot ==> !fresh(pth));
invariant (forall n, pth :: n in S && n.marked && pth == n.pathFromRoot ==>
old(ReachableVia(root, pth, n, S)));
invariant (forall n :: n in S && n.marked ==> old(Reachable(root, n, S)));
diff --git a/Test/dafny2/Answer b/Test/dafny2/Answer
index f466d813..2feaf6f7 100644
--- a/Test/dafny2/Answer
+++ b/Test/dafny2/Answer
@@ -50,3 +50,11 @@ Dafny program verifier finished with 11 verified, 0 errors
-------------------- SegmentSum.dfy --------------------
Dafny program verifier finished with 3 verified, 0 errors
+
+-------------------- MonotonicHeapstate.dfy --------------------
+
+Dafny program verifier finished with 36 verified, 0 errors
+
+-------------------- Calculations.dfy --------------------
+
+Dafny program verifier finished with 26 verified, 0 errors
diff --git a/Test/dafny2/Calculations.dfy b/Test/dafny2/Calculations.dfy
new file mode 100644
index 00000000..8e3a4426
--- /dev/null
+++ b/Test/dafny2/Calculations.dfy
@@ -0,0 +1,212 @@
+/* Lists */
+// Here are some standard definitions of List and functions on Lists
+
+datatype List<T> = Nil | Cons(T, List);
+
+function length(l: List): nat
+{
+ match l
+ case Nil => 0
+ case Cons(x, xs) => 1 + length(xs)
+}
+
+function concat(l: List, ys: List): List
+{
+ match l
+ case Nil => ys
+ case Cons(x, xs) => Cons(x, concat(xs, ys))
+}
+
+function reverse(l: List): List
+{
+ match l
+ case Nil => Nil
+ case Cons(x, xs) => concat(reverse(xs), Cons(x, Nil))
+}
+
+function revacc(l: List, acc: List): List
+{
+ match l
+ case Nil => acc
+ case Cons(x, xs) => revacc(xs, Cons(x, acc))
+}
+
+function qreverse(l: List): List
+{
+ revacc(l, Nil)
+}
+
+// Here are two lemmas about the List functions.
+
+ghost method Lemma_ConcatNil()
+ ensures forall xs :: concat(xs, Nil) == xs;
+{
+}
+
+ghost method Lemma_RevCatCommute()
+ ensures forall xs, ys, zs :: revacc(xs, concat(ys, zs)) == concat(revacc(xs, ys), zs);
+{
+}
+
+// Here is a theorem that says "qreverse" and "reverse" calculate the same result. The proof
+// is given in a calculational style. The proof is not minimal--some lines can be omitted
+// and Dafny will still fill in the details.
+
+ghost method Theorem_QReverseIsCorrect_Calc(l: List)
+ ensures qreverse(l) == reverse(l);
+{
+ calc {
+ qreverse(l);
+ // def. qreverse
+ revacc(l, Nil);
+ { Lemma_Revacc_calc(l, Nil); }
+ concat(reverse(l), Nil);
+ { Lemma_ConcatNil(); }
+ reverse(l);
+ }
+}
+
+ghost method Lemma_Revacc_calc(xs: List, ys: List)
+ ensures revacc(xs, ys) == concat(reverse(xs), ys);
+{
+ match (xs) {
+ case Nil =>
+ case Cons(x, xrest) =>
+ calc {
+ concat(reverse(xs), ys);
+ // def. reverse
+ concat(concat(reverse(xrest), Cons(x, Nil)), ys);
+ // induction hypothesis: Lemma_Revacc_calc(xrest, Cons(x, Nil))
+ concat(revacc(xrest, Cons(x, Nil)), ys);
+ { Lemma_RevCatCommute(); } // forall xs,ys,zs :: revacc(xs, concat(ys, zs)) == concat(revacc(xs, ys), zs)
+ revacc(xrest, concat(Cons(x, Nil), ys));
+ {
+ assert forall g, gs :: concat(Cons(g, Nil), gs) == Cons(g, gs);
+ assert concat(Cons(x, Nil), ys) == Cons(x, ys);
+ }
+ revacc(xrest, Cons(x, ys));
+ // def. revacc
+ revacc(xs, ys);
+ }
+ }
+}
+
+// Here is a version of the same proof, as it was constructed before Dafny's "calc" construct.
+
+ghost method Theorem_QReverseIsCorrect(l: List)
+ ensures qreverse(l) == reverse(l);
+{
+ assert qreverse(l)
+ == // def. qreverse
+ revacc(l, Nil);
+ Lemma_Revacc(l, Nil);
+ assert revacc(l, Nil)
+ == concat(reverse(l), Nil);
+ Lemma_ConcatNil();
+}
+
+ghost method Lemma_Revacc(xs: List, ys: List)
+ ensures revacc(xs, ys) == concat(reverse(xs), ys);
+{
+ match (xs) {
+ case Nil =>
+ case Cons(x, xrest) =>
+ assert revacc(xs, ys)
+ == // def. revacc
+ revacc(xrest, Cons(x, ys));
+
+ assert concat(reverse(xs), ys)
+ == // def. reverse
+ concat(concat(reverse(xrest), Cons(x, Nil)), ys)
+ == // induction hypothesis: Lemma3a(xrest, Cons(x, Nil))
+ concat(revacc(xrest, Cons(x, Nil)), ys);
+ Lemma_RevCatCommute(); // forall xs,ys,zs :: revacc(xs, concat(ys, zs)) == concat(revacc(xs, ys), zs)
+ assert concat(revacc(xrest, Cons(x, Nil)), ys)
+ == revacc(xrest, concat(Cons(x, Nil), ys));
+
+ assert forall g, gs :: concat(Cons(g, Nil), gs) == Cons(g, gs);
+
+ assert revacc(xrest, concat(Cons(x, Nil), ys))
+ == // the assert lemma just above
+ revacc(xrest, Cons(x, ys));
+ }
+}
+
+/* Fibonacci */
+// To further demonstrate what the "calc" construct can do, here are some proofs about the Fibonacci function.
+
+function Fib(n: nat): nat
+{
+ if n < 2 then n else Fib(n - 2) + Fib(n - 1)
+}
+
+ghost method Lemma_Fib()
+ ensures Fib(5) < 6;
+{
+ calc {
+ Fib(5);
+ Fib(4) + Fib(3);
+ calc {
+ Fib(2);
+ Fib(0) + Fib(1);
+ 0 + 1;
+ 1;
+ }
+ < 6;
+ }
+}
+
+/* List length */
+// Here are some proofs that show the use of nested calculations.
+
+ghost method Lemma_Concat_Length(xs: List, ys: List)
+ ensures length(concat(xs, ys)) == length(xs) + length(ys);
+{}
+
+ghost method Lemma_Reverse_Length(xs: List)
+ ensures length(xs) == length(reverse(xs));
+{
+ match (xs) {
+ case Nil =>
+ case Cons(x, xrest) =>
+ calc {
+ length(reverse(xs));
+ // def. reverse
+ length(concat(reverse(xrest), Cons(x, Nil)));
+ { Lemma_Concat_Length(reverse(xrest), Cons(x, Nil)); }
+ length(reverse(xrest)) + length(Cons(x, Nil));
+ // induction hypothesis
+ length(xrest) + length(Cons(x, Nil));
+ calc {
+ length(Cons(x, Nil));
+ // def. length
+ 1 + length(Nil);
+ // def. length
+ 1 + 0;
+ 1;
+ }
+ length(xrest) + 1;
+ // def. length
+ length(xs);
+ }
+ }
+}
+
+ghost method Window(xs: List, ys: List)
+ ensures length(xs) == length(ys) ==> length(reverse(xs)) == length(reverse(ys));
+{
+ calc {
+ length(xs) == length(ys) ==> length(reverse(xs)) == length(reverse(ys));
+ { if (length(xs) == length(ys)) {
+ calc {
+ length(reverse(xs));
+ { Lemma_Reverse_Length(xs); }
+ length(xs);
+ length(ys);
+ { Lemma_Reverse_Length(ys); }
+ length(reverse(ys));
+ } } }
+ length(xs) == length(ys) ==> length(reverse(xs)) == length(reverse(xs));
+ true;
+ }
+}
diff --git a/Test/dafny2/MonotonicHeapstate.dfy b/Test/dafny2/MonotonicHeapstate.dfy
new file mode 100644
index 00000000..4844086e
--- /dev/null
+++ b/Test/dafny2/MonotonicHeapstate.dfy
@@ -0,0 +1,143 @@
+module M0 {
+ datatype Kind = Constant | Ident | Binary;
+
+ class Expr {
+ var kind: Kind;
+ var value: int; // value if kind==Constant; id if kind==VarDecl; operator if kind==Binary
+ var left: Expr; // if kind==Binary
+ var right: Expr; // if kind==Binary
+
+ ghost var Repr: set<object>;
+
+ predicate Valid()
+ reads this, Repr;
+ {
+ this in Repr && null !in Repr &&
+ (left != null ==> left in Repr && this !in left.Repr && right !in left.Repr && left.Repr <= Repr && left.Valid()) &&
+ (right != null ==> right in Repr && this !in right.Repr && left !in right.Repr && right.Repr <= Repr && right.Valid()) &&
+ (kind == Binary ==> left != null && right != null && left.Repr !! right.Repr)
+ }
+
+ constructor CreateConstant(x: int)
+ modifies this;
+ ensures Valid() && fresh(Repr - {this});
+ {
+ kind, value := Constant, x;
+ left, right := null, null;
+ Repr := {this};
+ }
+
+ constructor CreateIdent(name: int)
+ modifies this;
+ ensures Valid() && fresh(Repr - {this});
+ {
+ kind, value := Ident, name;
+ left, right := null, null;
+ Repr := {this};
+ }
+
+ constructor CreateBinary(op: int, left: Expr, right: Expr)
+ requires left != null && left.Valid() && this !in left.Repr;
+ requires right != null && right.Valid() && this !in right.Repr;
+ requires left.Repr !! right.Repr;
+ modifies this;
+ ensures Valid() && fresh(Repr - {this} - left.Repr - right.Repr);
+ {
+ kind, value := Binary, op;
+ this.left, this.right := left, right;
+ Repr := {this} + left.Repr + right.Repr;
+ }
+ }
+}
+
+// Introduce the idea of resolved
+module M1 refines M0 {
+ class Expr {
+ ghost var resolved: bool;
+
+ predicate Valid()
+ {
+ resolved ==>
+ (kind == Binary ==> left.resolved && right.resolved)
+ }
+
+ constructor CreateConstant...
+ {
+ resolved := false;
+ }
+
+ constructor CreateIdent...
+ {
+ resolved := false;
+ }
+
+ constructor CreateBinary...
+ {
+ resolved := false;
+ }
+
+ method Resolve()
+ requires Valid(); // it's okay if it's already resolved
+ modifies Repr;
+ ensures Valid() && fresh(Repr - old(Repr));
+ ensures resolved;
+ decreases Repr;
+ {
+ if (kind == Binary) {
+ left.Resolve();
+ right.Resolve();
+ }
+ Repr := Repr + (if left != null then left.Repr else {}) + (if right != null then right.Repr else {});
+ resolved := true;
+ }
+ }
+}
+
+// Give "resolved" some meaning
+module M2 refines M1 {
+ class VarDecl {
+ }
+
+ class Expr {
+ var decl: VarDecl; // if kind==Ident, filled in during resolution
+
+ predicate Valid()
+ {
+ resolved ==>
+ (kind == Ident ==> decl != null)
+ }
+
+ method Resolve...
+ {
+ if (kind == Ident) {
+ decl := new VarDecl;
+ }
+ }
+ }
+}
+
+// Finally, supposing each VarDecl has a value, evaluate a resolved expression
+module M3 refines M2 {
+ class VarDecl {
+ var val: int;
+ }
+
+ class Expr {
+ method Eval() returns (r: int)
+ requires Valid();
+ requires resolved;
+ decreases Repr;
+ {
+ match (kind) {
+ case Constant =>
+ r := value;
+ case Ident =>
+ r := decl.val; // note how this statement relies on "decl" being non-null, which follows from the expression being resolved
+ case Binary =>
+ var x := left.Eval();
+ var y := right.Eval();
+ r := x + y;
+ }
+ }
+ }
+}
diff --git a/Test/dafny2/StoreAndRetrieve.dfy b/Test/dafny2/StoreAndRetrieve.dfy
index dce9795b..da62f91c 100644
--- a/Test/dafny2/StoreAndRetrieve.dfy
+++ b/Test/dafny2/StoreAndRetrieve.dfy
@@ -1,5 +1,5 @@
ghost module A {
- module L = Library;
+ import L = Library;
class {:autocontracts} StoreAndRetrieve<Thing> {
ghost var Contents: set<Thing>;
predicate Valid
diff --git a/Test/dafny2/runtest.bat b/Test/dafny2/runtest.bat
index 25dbed54..72959830 100644
--- a/Test/dafny2/runtest.bat
+++ b/Test/dafny2/runtest.bat
@@ -16,6 +16,7 @@ for %%f in (
StoreAndRetrieve.dfy
Intervals.dfy TreeFill.dfy TuringFactorial.dfy
MajorityVote.dfy SegmentSum.dfy
+ MonotonicHeapstate.dfy Calculations.dfy
) do (
echo.
echo -------------------- %%f --------------------
diff --git a/Test/inline/Answer b/Test/inline/Answer
index eb409cc2..655143fa 100644
--- a/Test/inline/Answer
+++ b/Test/inline/Answer
@@ -306,12 +306,12 @@ implementation {:inline 3} recursive(x: int) returns (y: int)
goto anon3_Then, anon3_Else;
anon3_Then:
- assume x == 0;
+ assume {:partition} x == 0;
y := 1;
return;
anon3_Else:
- assume x != 0;
+ assume {:partition} x != 0;
goto anon2;
anon2:
@@ -350,12 +350,12 @@ implementation recursivetest()
goto inline$recursive$0$anon3_Then, inline$recursive$0$anon3_Else;
inline$recursive$0$anon3_Then:
- assume inline$recursive$0$x == 0;
+ assume {:partition} inline$recursive$0$x == 0;
inline$recursive$0$y := 1;
goto inline$recursive$0$Return;
inline$recursive$0$anon3_Else:
- assume inline$recursive$0$x != 0;
+ assume {:partition} inline$recursive$0$x != 0;
goto inline$recursive$1$Entry;
inline$recursive$1$Entry:
@@ -366,12 +366,12 @@ implementation recursivetest()
goto inline$recursive$1$anon3_Then, inline$recursive$1$anon3_Else;
inline$recursive$1$anon3_Then:
- assume inline$recursive$1$x == 0;
+ assume {:partition} inline$recursive$1$x == 0;
inline$recursive$1$y := 1;
goto inline$recursive$1$Return;
inline$recursive$1$anon3_Else:
- assume inline$recursive$1$x != 0;
+ assume {:partition} inline$recursive$1$x != 0;
goto inline$recursive$2$Entry;
inline$recursive$2$Entry:
@@ -382,12 +382,12 @@ implementation recursivetest()
goto inline$recursive$2$anon3_Then, inline$recursive$2$anon3_Else;
inline$recursive$2$anon3_Then:
- assume inline$recursive$2$x == 0;
+ assume {:partition} inline$recursive$2$x == 0;
inline$recursive$2$y := 1;
goto inline$recursive$2$Return;
inline$recursive$2$anon3_Else:
- assume inline$recursive$2$x != 0;
+ assume {:partition} inline$recursive$2$x != 0;
call inline$recursive$2$k := recursive(inline$recursive$2$x - 1);
inline$recursive$2$y := inline$recursive$2$y + inline$recursive$2$k;
goto inline$recursive$2$Return;
@@ -438,12 +438,12 @@ implementation {:inline 3} recursive(x: int) returns (y: int)
goto anon3_Then, anon3_Else;
anon3_Then:
- assume x == 0;
+ assume {:partition} x == 0;
y := 1;
return;
anon3_Else:
- assume x != 0;
+ assume {:partition} x != 0;
goto inline$recursive$0$Entry;
inline$recursive$0$Entry:
@@ -454,12 +454,12 @@ implementation {:inline 3} recursive(x: int) returns (y: int)
goto inline$recursive$0$anon3_Then, inline$recursive$0$anon3_Else;
inline$recursive$0$anon3_Then:
- assume inline$recursive$0$x == 0;
+ assume {:partition} inline$recursive$0$x == 0;
inline$recursive$0$y := 1;
goto inline$recursive$0$Return;
inline$recursive$0$anon3_Else:
- assume inline$recursive$0$x != 0;
+ assume {:partition} inline$recursive$0$x != 0;
goto inline$recursive$1$Entry;
inline$recursive$1$Entry:
@@ -470,12 +470,12 @@ implementation {:inline 3} recursive(x: int) returns (y: int)
goto inline$recursive$1$anon3_Then, inline$recursive$1$anon3_Else;
inline$recursive$1$anon3_Then:
- assume inline$recursive$1$x == 0;
+ assume {:partition} inline$recursive$1$x == 0;
inline$recursive$1$y := 1;
goto inline$recursive$1$Return;
inline$recursive$1$anon3_Else:
- assume inline$recursive$1$x != 0;
+ assume {:partition} inline$recursive$1$x != 0;
goto inline$recursive$2$Entry;
inline$recursive$2$Entry:
@@ -486,12 +486,12 @@ implementation {:inline 3} recursive(x: int) returns (y: int)
goto inline$recursive$2$anon3_Then, inline$recursive$2$anon3_Else;
inline$recursive$2$anon3_Then:
- assume inline$recursive$2$x == 0;
+ assume {:partition} inline$recursive$2$x == 0;
inline$recursive$2$y := 1;
goto inline$recursive$2$Return;
inline$recursive$2$anon3_Else:
- assume inline$recursive$2$x != 0;
+ assume {:partition} inline$recursive$2$x != 0;
call inline$recursive$2$k := recursive(inline$recursive$2$x - 1);
inline$recursive$2$y := inline$recursive$2$y + inline$recursive$2$k;
goto inline$recursive$2$Return;
@@ -542,12 +542,12 @@ implementation main(x: int)
goto anon3_Then, anon3_Else;
anon3_Then:
- assume b;
+ assume {:partition} b;
assert i > 0 && A[i] == x;
goto anon2;
anon3_Else:
- assume !b;
+ assume {:partition} !b;
goto anon2;
anon2:
@@ -576,22 +576,22 @@ implementation {:inline 1} find(A: [int]int, size: int, x: int) returns (ret: in
goto anon4_LoopDone, anon4_LoopBody;
anon4_LoopBody:
- assume i < size;
+ assume {:partition} i < size;
call b := check(A, i, x);
goto anon5_Then, anon5_Else;
anon5_Then:
- assume b;
+ assume {:partition} b;
ret := i;
found := b;
goto anon3;
anon5_Else:
- assume !b;
+ assume {:partition} !b;
goto anon4_LoopHead;
anon4_LoopDone:
- assume size <= i;
+ assume {:partition} size <= i;
goto anon3;
anon3:
@@ -613,12 +613,12 @@ implementation {:inline 3} check(A: [int]int, i: int, c: int) returns (ret: bool
goto anon4_Then, anon4_Else;
anon4_Then:
- assume A[i] == c;
+ assume {:partition} A[i] == c;
ret := true;
goto anon3;
anon4_Else:
- assume A[i] != c;
+ assume {:partition} A[i] != c;
ret := false;
goto anon3;
@@ -669,7 +669,7 @@ implementation main(x: int)
goto inline$find$0$anon4_LoopDone, inline$find$0$anon4_LoopBody;
inline$find$0$anon4_LoopBody:
- assume inline$find$0$i < inline$find$0$size;
+ assume {:partition} inline$find$0$i < inline$find$0$size;
goto inline$check$0$Entry;
inline$check$0$Entry:
@@ -683,12 +683,12 @@ implementation main(x: int)
goto inline$check$0$anon4_Then, inline$check$0$anon4_Else;
inline$check$0$anon4_Then:
- assume inline$check$0$A[inline$check$0$i] == inline$check$0$c;
+ assume {:partition} inline$check$0$A[inline$check$0$i] == inline$check$0$c;
inline$check$0$ret := true;
goto inline$check$0$anon3;
inline$check$0$anon4_Else:
- assume inline$check$0$A[inline$check$0$i] != inline$check$0$c;
+ assume {:partition} inline$check$0$A[inline$check$0$i] != inline$check$0$c;
inline$check$0$ret := false;
goto inline$check$0$anon3;
@@ -704,17 +704,17 @@ implementation main(x: int)
goto inline$find$0$anon5_Then, inline$find$0$anon5_Else;
inline$find$0$anon5_Then:
- assume inline$find$0$b;
+ assume {:partition} inline$find$0$b;
inline$find$0$ret := inline$find$0$i;
inline$find$0$found := inline$find$0$b;
goto inline$find$0$anon3;
inline$find$0$anon5_Else:
- assume !inline$find$0$b;
+ assume {:partition} !inline$find$0$b;
goto inline$find$0$anon4_LoopHead;
inline$find$0$anon4_LoopDone:
- assume inline$find$0$size <= inline$find$0$i;
+ assume {:partition} inline$find$0$size <= inline$find$0$i;
goto inline$find$0$anon3;
inline$find$0$anon3:
@@ -729,12 +729,12 @@ implementation main(x: int)
goto anon3_Then, anon3_Else;
anon3_Then:
- assume b;
+ assume {:partition} b;
assert i > 0 && A[i] == x;
goto anon2;
anon3_Else:
- assume !b;
+ assume {:partition} !b;
goto anon2;
anon2:
@@ -766,7 +766,7 @@ implementation {:inline 1} find(A: [int]int, size: int, x: int) returns (ret: in
goto anon4_LoopDone, anon4_LoopBody;
anon4_LoopBody:
- assume i < size;
+ assume {:partition} i < size;
goto inline$check$0$Entry;
inline$check$0$Entry:
@@ -780,12 +780,12 @@ implementation {:inline 1} find(A: [int]int, size: int, x: int) returns (ret: in
goto inline$check$0$anon4_Then, inline$check$0$anon4_Else;
inline$check$0$anon4_Then:
- assume inline$check$0$A[inline$check$0$i] == inline$check$0$c;
+ assume {:partition} inline$check$0$A[inline$check$0$i] == inline$check$0$c;
inline$check$0$ret := true;
goto inline$check$0$anon3;
inline$check$0$anon4_Else:
- assume inline$check$0$A[inline$check$0$i] != inline$check$0$c;
+ assume {:partition} inline$check$0$A[inline$check$0$i] != inline$check$0$c;
inline$check$0$ret := false;
goto inline$check$0$anon3;
@@ -801,17 +801,17 @@ implementation {:inline 1} find(A: [int]int, size: int, x: int) returns (ret: in
goto anon5_Then, anon5_Else;
anon5_Then:
- assume b;
+ assume {:partition} b;
ret := i;
found := b;
goto anon3;
anon5_Else:
- assume !b;
+ assume {:partition} !b;
goto anon4_LoopHead;
anon4_LoopDone:
- assume size <= i;
+ assume {:partition} size <= i;
goto anon3;
anon3:
diff --git a/Test/livevars/Answer b/Test/livevars/Answer
index 958fc852..f5c2e7ce 100644
--- a/Test/livevars/Answer
+++ b/Test/livevars/Answer
@@ -32,11 +32,9 @@ Execution trace:
bla1.bpl(1348,3): inline$I8xKeyboardGetSysButtonEvent$0$label_9_false#1
bla1.bpl(1376,3): inline$storm_IoSetCancelRoutine$0$label_7_false#1
bla1.bpl(1408,3): inline$storm_IoSetCancelRoutine$0$label_8#1
- bla1.bpl(1415,3): inline$storm_IoSetCancelRoutine$0$anon9_Else#1
- bla1.bpl(1423,3): inline$storm_IoSetCancelRoutine$0$anon10_Then#1
+ bla1.bpl(1427,3): inline$storm_IoSetCancelRoutine$0$anon9_Then#1
bla1.bpl(1431,3): inline$storm_IoSetCancelRoutine$0$anon3#1
- bla1.bpl(1438,3): inline$storm_IoSetCancelRoutine$0$anon11_Else#1
- bla1.bpl(1446,3): inline$storm_IoSetCancelRoutine$0$anon12_Then#1
+ bla1.bpl(1451,3): inline$storm_IoSetCancelRoutine$0$anon11_Then#1
bla1.bpl(1456,3): inline$storm_IoSetCancelRoutine$0$anon6#1
bla1.bpl(1467,3): inline$storm_IoSetCancelRoutine$0$anon13_Then#1
bla1.bpl(1472,3): inline$storm_IoSetCancelRoutine$0$anon8#1
@@ -56,17 +54,14 @@ Execution trace:
bla1.bpl(1739,3): anon7#1
bla1.bpl(1796,3): inline$storm_IoCancelIrp$0$anon12_Then#1
bla1.bpl(1801,3): inline$storm_IoCancelIrp$0$anon2#1
- bla1.bpl(1812,3): inline$storm_IoCancelIrp$0$anon14_Else#1
- bla1.bpl(1820,3): inline$storm_IoCancelIrp$0$anon15_Then#1
+ bla1.bpl(1825,3): inline$storm_IoCancelIrp$0$anon14_Then#1
bla1.bpl(1830,3): inline$storm_IoCancelIrp$0$anon5#1
- bla1.bpl(1838,3): inline$storm_IoCancelIrp$0$anon16_Else#1
- bla1.bpl(1846,3): inline$storm_IoCancelIrp$0$anon17_Then#1
+ bla1.bpl(1851,3): inline$storm_IoCancelIrp$0$anon16_Then#1
bla1.bpl(1856,3): inline$storm_IoCancelIrp$0$anon8#1
bla1.bpl(1867,3): inline$storm_IoCancelIrp$0$anon18_Then#1
bla1.bpl(1872,3): inline$storm_IoCancelIrp$0$anon10#1
bla1.bpl(1932,3): inline$storm_IoAcquireCancelSpinLock$0$label_11_true#1
- bla1.bpl(1947,3): inline$storm_IoAcquireCancelSpinLock$0$anon6_Else#1
- bla1.bpl(1955,3): inline$storm_IoAcquireCancelSpinLock$0$anon7_Then#1
+ bla1.bpl(1960,3): inline$storm_IoAcquireCancelSpinLock$0$anon6_Then#1
bla1.bpl(1965,3): inline$storm_IoAcquireCancelSpinLock$0$anon3#1
bla1.bpl(1976,3): inline$storm_IoAcquireCancelSpinLock$0$anon8_Then#1
bla1.bpl(1981,3): inline$storm_IoAcquireCancelSpinLock$0$anon5#1
diff --git a/Test/smoke/Answer b/Test/smoke/Answer
index de255422..98cff8d2 100644
--- a/Test/smoke/Answer
+++ b/Test/smoke/Answer
@@ -9,7 +9,7 @@ implementation b(x: int)
goto anon3_Then;
anon3_Then:
- assume x < 0;
+ assume {:partition} x < 0;
y := 1;
assert false;
return;
diff --git a/Test/test15/Answer b/Test/test15/Answer
index 473af09b..3361b320 100644
--- a/Test/test15/Answer
+++ b/Test/test15/Answer
@@ -1,19 +1,14 @@
-------------------- NullInModel --------------------
*** MODEL
-%lbl%@47 -> false
-%lbl%+24 -> true
-%lbl%+37 -> true
+%lbl%@46 -> false
+%lbl%+23 -> true
+%lbl%+36 -> true
boolType -> T@T!val!1
intType -> T@T!val!0
null -> T@U!val!0
refType -> T@T!val!2
s -> T@U!val!0
-tickleBool -> {
- true -> true
- false -> true
- else -> true
-}
type -> {
T@U!val!0 -> T@T!val!2
else -> T@T!val!2
@@ -24,6 +19,11 @@ Ctor -> {
T@T!val!2 -> 2
else -> 0
}
+tickleBool -> {
+ true -> true
+ false -> true
+ else -> true
+}
*** END_MODEL
NullInModel.bpl(2,3): Error BP5001: This assertion might not hold.
Execution trace:
@@ -33,22 +33,22 @@ Boogie program verifier finished with 0 verified, 1 error
-------------------- IntInModel --------------------
*** MODEL
-%lbl%@39 -> false
-%lbl%+23 -> true
-%lbl%+29 -> true
+%lbl%@38 -> false
+%lbl%+22 -> true
+%lbl%+28 -> true
boolType -> T@T!val!1
i -> 0
intType -> T@T!val!0
-tickleBool -> {
- true -> true
- false -> true
- else -> true
-}
Ctor -> {
T@T!val!0 -> 0
T@T!val!1 -> 1
else -> 0
}
+tickleBool -> {
+ true -> true
+ false -> true
+ else -> true
+}
*** END_MODEL
IntInModel.bpl(2,3): Error BP5001: This assertion might not hold.
Execution trace:
@@ -58,9 +58,9 @@ Boogie program verifier finished with 0 verified, 1 error
-------------------- ModelTest --------------------
*** MODEL
-%lbl%@182 -> false
-%lbl%+119 -> true
-%lbl%+64 -> true
+%lbl%@181 -> false
+%lbl%+118 -> true
+%lbl%+63 -> true
boolType -> T@T!val!1
i@0 -> 1
intType -> T@T!val!0
@@ -70,11 +70,6 @@ j@2 -> 4
r -> T@U!val!1
refType -> T@T!val!2
s -> T@U!val!0
-tickleBool -> {
- true -> true
- false -> true
- else -> true
-}
type -> {
T@U!val!0 -> T@T!val!2
T@U!val!1 -> T@T!val!2
@@ -86,6 +81,11 @@ Ctor -> {
T@T!val!2 -> 2
else -> 0
}
+tickleBool -> {
+ true -> true
+ false -> true
+ else -> true
+}
*** END_MODEL
ModelTest.bpl(7,3): Error BP5001: This assertion might not hold.
Execution trace:
@@ -114,11 +114,11 @@ Execution trace:
CaptureState.bpl(16,5): anon4_Then
CaptureState.bpl(24,5): anon3
*** MODEL
-%lbl%@334 -> false
-%lbl%+110 -> true
-%lbl%+112 -> true
-%lbl%+116 -> true
-%lbl%+189 -> true
+%lbl%@335 -> false
+%lbl%+111 -> true
+%lbl%+113 -> true
+%lbl%+117 -> true
+%lbl%+190 -> true
@MV_state_const -> 6
boolType -> T@T!val!1
F -> T@U!val!2
@@ -135,10 +135,9 @@ RefType -> T@T!val!2
this -> T@U!val!1
x@@4 -> 797
y@@1 -> **y@@1
-tickleBool -> {
- true -> true
- false -> true
- else -> true
+int_2_U -> {
+ -2 -> -2
+ else -> -2
}
type -> {
T@U!val!0 -> T@T!val!4
@@ -147,6 +146,13 @@ type -> {
-2 -> T@T!val!0
else -> T@T!val!4
}
+@MV_state -> {
+ 6 0 -> true
+ 6 3 -> true
+ 6 4 -> true
+ 6 5 -> true
+ else -> true
+}
Ctor -> {
T@T!val!0 -> 0
T@T!val!1 -> 1
@@ -155,13 +161,6 @@ Ctor -> {
T@T!val!4 -> 2
else -> 0
}
-@MV_state -> {
- 6 0 -> true
- 6 3 -> true
- 6 4 -> true
- 6 5 -> true
- else -> true
-}
[3] -> {
T@U!val!0 T@U!val!1 T@U!val!2 -> -2
else -> -2
@@ -174,6 +173,15 @@ MapType0TypeInv1 -> {
T@T!val!4 -> T@T!val!3
else -> T@T!val!3
}
+MapType0TypeInv0 -> {
+ T@T!val!4 -> T@T!val!2
+ else -> T@T!val!2
+}
+tickleBool -> {
+ true -> true
+ false -> true
+ else -> true
+}
MapType0Type -> {
T@T!val!2 T@T!val!3 T@T!val!0 -> T@T!val!4
else -> T@T!val!4
@@ -182,14 +190,6 @@ MapType0TypeInv2 -> {
T@T!val!4 -> T@T!val!0
else -> T@T!val!0
}
-MapType0TypeInv0 -> {
- T@T!val!4 -> T@T!val!2
- else -> T@T!val!2
-}
-int_2_U -> {
- -2 -> -2
- else -> -2
-}
*** STATE <initial>
Heap -> T@U!val!0
this -> T@U!val!1
diff --git a/Util/Emacs/dafny-mode.el b/Util/Emacs/dafny-mode.el
index e4a8c5d0..1e197644 100644
--- a/Util/Emacs/dafny-mode.el
+++ b/Util/Emacs/dafny-mode.el
@@ -8,7 +8,7 @@
(if dafny-mode-map nil
(setq dafny-mode-map (make-keymap))
- (define-key dafny-mode-map "\C-c\C-c" 'dafny-run-boogie)
+ (define-key dafny-mode-map "\C-c\C-c" 'dafny-run-verifier)
(define-key dafny-mode-map [(control return)] 'font-lock-fontify-buffer))
(setq auto-mode-alist
@@ -32,13 +32,13 @@
`(,(dafny-regexp-opt '(
"class" "datatype" "codatatype" "type" "function" "predicate" "copredicate"
"ghost" "var" "method" "constructor"
- "module" "imports" "static" "refines"
+ "module" "import" "default" "as" "opened" "static" "refines"
"returns" "requires" "ensures" "modifies" "reads" "free"
"invariant" "decreases"
)) . font-lock-builtin-face)
`(,(dafny-regexp-opt '(
- "assert" "assume" "break" "choose" "then" "else" "havoc" "if" "label" "return" "while" "print" "where"
- "old" "forall" "exists" "new" "parallel" "in" "this" "fresh" "allocated"
+ "assert" "assume" "break" "choose" "then" "else" "if" "label" "return" "while" "print" "where"
+ "old" "forall" "exists" "new" "parallel" "calc" "in" "this" "fresh"
"match" "case" "false" "true" "null")) . font-lock-keyword-face)
`(,(dafny-regexp-opt '("array" "array2" "array3" "bool" "multiset" "map" "nat" "int" "object" "set" "seq")) . font-lock-type-face)
)
@@ -69,7 +69,7 @@
dafny-mode-menu (list dafny-mode-map)
"Dafny Mode Menu."
'("Dafny"
- ["Run Boogie" dafny-run-boogie t]
+ ["Run Dafny" dafny-run-verifier t]
"---"
["Recolor buffer" font-lock-fontify-buffer t]
"---"
@@ -81,8 +81,8 @@
(defun dafny-command-line (file)
(concat "boogie " file))
-(defun dafny-run-boogie ()
- "run Boogie to check the Dafny program"
+(defun dafny-run-verifier ()
+ "run Dafny verifier"
(interactive)
(let ((f (buffer-name)))
(compile (dafny-command-line f))))
diff --git a/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs b/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs
index 4d8e2df1..8c3eee59 100644
--- a/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs
+++ b/Util/VS2010/Dafny/DafnyLanguageService/Grammar.cs
@@ -19,16 +19,16 @@ namespace Demo
this.MarkReservedWords( // NOTE: these keywords must also appear once more below
"class", "ghost", "static", "var", "method", "constructor", "datatype", "codatatype", "type",
"assert", "assume", "new", "this", "object", "refines",
- "module", "imports", "as",
+ "module", "import", "as", "default", "opened",
"if", "then", "else", "while", "invariant",
- "break", "label", "return", "parallel", "havoc", "print",
+ "break", "label", "return", "parallel", "print",
"returns", "requires", "ensures", "modifies", "reads", "decreases",
"bool", "nat", "int", "false", "true", "null",
"function", "predicate", "copredicate", "free",
"in", "forall", "exists",
"seq", "set", "map", "multiset", "array", "array2", "array3",
"match", "case",
- "fresh", "allocated", "old", "choose", "where"
+ "fresh", "old", "choose", "where", "calc"
);
StringLiteral s = new StringLiteral("String", "'", StringFlags.AllowsDoubledQuote);
@@ -276,7 +276,9 @@ namespace Demo
| "object"
| "refines"
| "module"
- | "imports"
+ | "import"
+ | "default"
+ | "opened"
| "as"
| "if"
| "then"
@@ -287,7 +289,7 @@ namespace Demo
| "label"
| "return"
| "parallel"
- | "havoc"
+ | "calc"
| "print"
| "returns"
| "requires"
@@ -318,7 +320,6 @@ namespace Demo
| "match"
| "case"
| "fresh"
- | "allocated"
| "old"
| "choose"
| "where"
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/ClassificationTagger.cs b/Util/VS2010/DafnyExtension/DafnyExtension/ClassificationTagger.cs
index 7e64dd1d..09835ac9 100644
--- a/Util/VS2010/DafnyExtension/DafnyExtension/ClassificationTagger.cs
+++ b/Util/VS2010/DafnyExtension/DafnyExtension/ClassificationTagger.cs
@@ -50,7 +50,7 @@ namespace DafnyLanguage
_typeMap[DafnyTokenKinds.String] = standards.StringLiteral;
_typeMap[DafnyTokenKinds.Comment] = standards.Comment;
_typeMap[DafnyTokenKinds.VariableIdentifier] = standards.Identifier;
- _typeMap[DafnyTokenKinds.TypeIdentifier] = typeService.GetClassificationType("Dafny user type");
+ _typeMap[DafnyTokenKinds.VariableIdentifierDefinition] = typeService.GetClassificationType("Dafny identifier");
}
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
@@ -82,16 +82,16 @@ namespace DafnyLanguage
/// Defines an editor format for user-defined type.
/// </summary>
[Export(typeof(EditorFormatDefinition))]
- [ClassificationType(ClassificationTypeNames = "Dafny user type")]
- [Name("Dafny user type")]
+ [ClassificationType(ClassificationTypeNames = "Dafny identifier")]
+ [Name("Dafny identifier")]
[UserVisible(true)]
//set the priority to be after the default classifiers
[Order(Before = Priority.Default)]
internal sealed class DafnyTypeFormat : ClassificationFormatDefinition
{
public DafnyTypeFormat() {
- this.DisplayName = "Dafny user type"; //human readable version of the name
- this.ForegroundColor = Colors.Coral;
+ this.DisplayName = "Dafny identifier"; //human readable version of the name
+ this.ForegroundColor = Colors.CornflowerBlue;
}
}
@@ -101,7 +101,7 @@ namespace DafnyLanguage
/// Defines the "ordinary" classification type.
/// </summary>
[Export(typeof(ClassificationTypeDefinition))]
- [Name("Dafny user type")]
+ [Name("Dafny identifier")]
internal static ClassificationTypeDefinition UserType = null;
}
}
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs b/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs
index f24aee55..9f22b887 100644
--- a/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs
+++ b/Util/VS2010/DafnyExtension/DafnyExtension/DafnyDriver.cs
@@ -33,91 +33,21 @@ namespace DafnyLanguage
_errors.Add(new DafnyError(line, col, cat, msg));
}
- void RecordProcessError(string msg) {
- RecordError(0, 0, ErrorCategory.ProcessError, msg);
- }
-
- public void Process_ViaBatchFile() {
- if (!File.Exists(@"C:\tmp\StartDafny.bat")) {
- RecordProcessError(@"Can't find C:\tmp\StartDafny.bat");
- }
-
- // From: http://dotnetperls.com/process-redirect-standard-output
- // (Also, see: http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput.aspx)
- //
- // Setup the process with the ProcessStartInfo class.
- //
- ProcessStartInfo start = new ProcessStartInfo();
- start.FileName = @"cmd.exe";
- start.Arguments = @"/c C:\tmp\StartDafny.bat"; // Specify exe name.
- start.UseShellExecute = false;
- start.RedirectStandardInput = true;
- start.RedirectStandardOutput = true;
- start.CreateNoWindow = true;
- //
- // Start the process.
- //
- using (System.Diagnostics.Process process = System.Diagnostics.Process.Start(start)) {
- //
- // Push the file contents to the new process
- //
- StreamWriter myStreamWriter = process.StandardInput;
- myStreamWriter.WriteLine(_programText);
- myStreamWriter.Close();
- //
- // Read in all the text from the process with the StreamReader.
- //
- using (StreamReader reader = process.StandardOutput) {
- for (string line = reader.ReadLine(); !String.IsNullOrEmpty(line); line = reader.ReadLine()) {
- // the lines of interest have the form "filename(line,col): some_error_label: error_message"
- // where "some_error_label" is "Error" or "syntax error" or "Error BP5003" or "Related location"
- string message;
- int n = line.IndexOf("): ", 2); // we start at 2, to avoid problems with "C:\..."
- if (n == -1) {
- continue;
- } else {
- int m = line.IndexOf(": ", n + 3);
- if (m == -1) {
- continue;
- }
- message = line.Substring(m + 2);
- }
- line = line.Substring(0, n); // line now has the form "filename(line,col"
-
- n = line.LastIndexOf(',');
- if (n == -1) { continue; }
- var colString = line.Substring(n + 1);
- line = line.Substring(0, n); // line now has the form "filename(line"
-
- n = line.LastIndexOf('(');
- if (n == -1) { continue; }
- var lineString = line.Substring(n + 1);
-
- try {
- int errLine = Int32.Parse(lineString) - 1;
- int errCol = Int32.Parse(colString) - 1;
- RecordError(errLine, errCol, message.StartsWith("syntax error") ? ErrorCategory.ParseError : ErrorCategory.VerificationError, message);
- } catch (System.FormatException) {
- continue;
- } catch (System.OverflowException) {
- continue;
- }
- }
- }
- }
- }
-
static DafnyDriver() {
Initialize();
}
static void Initialize() {
if (Dafny.DafnyOptions.O == null) {
- Dafny.DafnyOptions.Install(new Dafny.DafnyOptions());
+ var options = new Dafny.DafnyOptions();
+ options.ProverKillTime = 10;
+ options.ErrorTrace = 0;
+ Dafny.DafnyOptions.Install(options);
+ options.ApplyDefaultOptions();
}
}
- public Dafny.Program Process() {
+ public Dafny.Program ProcessResolution() {
if (!ParseAndTypeCheck()) {
return null;
}
@@ -125,12 +55,12 @@ namespace DafnyLanguage
}
bool ParseAndTypeCheck() {
- List<Dafny.ModuleDecl> modules = new List<Dafny.ModuleDecl>();
+ Dafny.ModuleDecl module = new Dafny.LiteralModuleDecl(new Dafny.DefaultModuleDecl(), null);
Dafny.BuiltIns builtIns = new Dafny.BuiltIns();
- int errorCount = Dafny.Parser.Parse(_programText, _filename, modules, builtIns, new VSErrors(this));
+ int errorCount = Dafny.Parser.Parse(_programText, _filename, module, builtIns, new VSErrors(this));
if (errorCount != 0)
return false;
- Dafny.Program program = new Dafny.Program(_filename, modules, builtIns);
+ Dafny.Program program = new Dafny.Program(_filename, module, builtIns);
Dafny.Resolver r = new VSResolver(program, this);
r.ResolveProgram(program);
@@ -174,77 +104,108 @@ namespace DafnyLanguage
}
}
-#if LATER
- static bool Verify(Microsoft.Dafny.Program dafnyProgram) {
+ public static bool Verify(Dafny.Program dafnyProgram, ErrorReporterDelegate er) {
Dafny.Translator translator = new Dafny.Translator();
- Program boogieProgram = translator.Translate(dafnyProgram);
+ Bpl.Program boogieProgram = translator.Translate(dafnyProgram);
- int errorCount, verified, inconclusives, timeOuts, outOfMemories;
- PipelineOutcome oc = BoogiePipeline(boogieProgram, out errorCount, out verified, out inconclusives, out timeOuts, out outOfMemories);
+ PipelineOutcome oc = BoogiePipeline(boogieProgram, er);
switch (oc) {
+ case PipelineOutcome.Done:
case PipelineOutcome.VerificationCompleted:
- case PipelineOutcome.Done: // (this says not to continue with compilation)
- // WriteTrailer(verified, errorCount, inconclusives, timeOuts, outOfMemories);
- break;
+ // TODO: This would be the place to proceed to compile the program, if desired
+ return true;
+ case PipelineOutcome.FatalError:
default:
- // error has already been reported to user
- break;
+ return false;
}
- return errorCount == 0 && inconclusives == 0 && timeOuts == 0 && outOfMemories == 0;
}
+ enum PipelineOutcome { Done, ResolutionError, TypeCheckingError, ResolvedAndTypeChecked, FatalError, VerificationCompleted }
+
/// <summary>
/// Resolve, type check, infer invariants for, and verify the given Boogie program.
/// The intention is that this Boogie program has been produced by translation from something
/// else. Hence, any resolution errors and type checking errors are due to errors in
/// the translation.
/// </summary>
- static PipelineOutcome BoogiePipeline(Program/*!*/ program,
- out int errorCount, out int verified, out int inconclusives, out int timeOuts, out int outOfMemories) {
+ static PipelineOutcome BoogiePipeline(Bpl.Program/*!*/ program, ErrorReporterDelegate er) {
Contract.Requires(program != null);
- Contract.Ensures(0 <= Contract.ValueAtReturn(out inconclusives) && 0 <= Contract.ValueAtReturn(out timeOuts));
- errorCount = verified = inconclusives = timeOuts = outOfMemories = 0;
- PipelineOutcome oc = ResolveAndTypecheck(program);
- switch (oc) {
- case PipelineOutcome.Done:
- return oc;
+ PipelineOutcome oc = BoogieResolveAndTypecheck(program);
+ if (oc == PipelineOutcome.ResolvedAndTypeChecked) {
+ EliminateDeadVariablesAndInline(program);
+ return BoogieInferAndVerify(program, er);
+ }
+ return oc;
+ }
- case PipelineOutcome.ResolutionError:
- case PipelineOutcome.TypeCheckingError:
- // the Dafny-to-Boogie translation must have been bad; this is an internal error
- return oc;
+ static void EliminateDeadVariablesAndInline(Bpl.Program program) {
+ Contract.Requires(program != null);
+ // Eliminate dead variables
+ Microsoft.Boogie.UnusedVarEliminator.Eliminate(program);
- case PipelineOutcome.ResolvedAndTypeChecked:
- return InferAndVerify(program, out errorCount, out verified, out inconclusives, out timeOuts, out outOfMemories);
+ // Collect mod sets
+ if (Bpl.CommandLineOptions.Clo.DoModSetAnalysis) {
+ Microsoft.Boogie.ModSetCollector.DoModSetAnalysis(program);
+ }
- default:
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected outcome
+ // Coalesce blocks
+ if (Bpl.CommandLineOptions.Clo.CoalesceBlocks) {
+ Microsoft.Boogie.BlockCoalescer.CoalesceBlocks(program);
}
- }
+ // Inline
+ var TopLevelDeclarations = program.TopLevelDeclarations;
- enum PipelineOutcome { Done, ResolutionError, TypeCheckingError, ResolvedAndTypeChecked, FatalError, VerificationCompleted }
+ if (Bpl.CommandLineOptions.Clo.ProcedureInlining != Bpl.CommandLineOptions.Inlining.None) {
+ bool inline = false;
+ foreach (var d in TopLevelDeclarations) {
+ if (d.FindExprAttribute("inline") != null) {
+ inline = true;
+ }
+ }
+ if (inline && Bpl.CommandLineOptions.Clo.StratifiedInlining == 0) {
+ foreach (var d in TopLevelDeclarations) {
+ var impl = d as Bpl.Implementation;
+ if (impl != null) {
+ impl.OriginalBlocks = impl.Blocks;
+ impl.OriginalLocVars = impl.LocVars;
+ }
+ }
+ foreach (var d in TopLevelDeclarations) {
+ var impl = d as Bpl.Implementation;
+ if (impl != null && !impl.SkipVerification) {
+ Bpl.Inliner.ProcessImplementation(program, impl);
+ }
+ }
+ foreach (var d in TopLevelDeclarations) {
+ var impl = d as Bpl.Implementation;
+ if (impl != null) {
+ impl.OriginalBlocks = null;
+ impl.OriginalLocVars = null;
+ }
+ }
+ }
+ }
+ }
/// <summary>
- /// Resolves and type checks the given Boogie program. Any errors are reported to the
- /// console. Returns:
+ /// Resolves and type checks the given Boogie program.
+ /// Returns:
/// - Done if no errors occurred, and command line specified no resolution or no type checking.
/// - ResolutionError if a resolution error occurred
/// - TypeCheckingError if a type checking error occurred
/// - ResolvedAndTypeChecked if both resolution and type checking succeeded
/// </summary>
- static PipelineOutcome ResolveAndTypecheck(Program program) {
+ static PipelineOutcome BoogieResolveAndTypecheck(Bpl.Program program) {
Contract.Requires(program != null);
// ---------- Resolve ------------------------------------------------------------
-
int errorCount = program.Resolve();
if (errorCount != 0) {
return PipelineOutcome.ResolutionError;
}
// ---------- Type check ------------------------------------------------------------
-
errorCount = program.Typecheck();
if (errorCount != 0) {
return PipelineOutcome.TypeCheckingError;
@@ -257,195 +218,209 @@ namespace DafnyLanguage
/// Given a resolved and type checked Boogie program, infers invariants for the program
/// and then attempts to verify it. Returns:
/// - Done if command line specified no verification
- /// - FatalError if a fatal error occurred, in which case an error has been printed to console
+ /// - FatalError if a fatal error occurred
/// - VerificationCompleted if inference and verification completed, in which the out
/// parameters contain meaningful values
/// </summary>
- static PipelineOutcome InferAndVerify(Program program,
- out int errorCount, out int verified, out int inconclusives, out int timeOuts, out int outOfMemories) {
+ static PipelineOutcome BoogieInferAndVerify(Bpl.Program program, ErrorReporterDelegate er) {
Contract.Requires(program != null);
- Contract.Ensures(0 <= Contract.ValueAtReturn(out inconclusives) && 0 <= Contract.ValueAtReturn(out timeOuts));
-
- errorCount = verified = inconclusives = timeOuts = outOfMemories = 0;
// ---------- Infer invariants --------------------------------------------------------
// Abstract interpretation -> Always use (at least) intervals, if not specified otherwise (e.g. with the "/noinfer" switch)
- Microsoft.Boogie.AbstractInterpretation.AbstractInterpretation.RunAbstractInterpretation(program);
+ if (Bpl.CommandLineOptions.Clo.UseAbstractInterpretation) {
+ if (Bpl.CommandLineOptions.Clo.Ai.J_Intervals || Bpl.CommandLineOptions.Clo.Ai.J_Trivial) {
+ Microsoft.Boogie.AbstractInterpretation.NativeAbstractInterpretation.RunAbstractInterpretation(program);
+ } else if (Bpl.CommandLineOptions.Clo.Ai.AnySet) {
+ // run one of the old domains
+ Microsoft.Boogie.AbstractInterpretation.AbstractInterpretation.RunAbstractInterpretation(program);
+ } else {
+ // use /infer:j as the default
+ Bpl.CommandLineOptions.Clo.Ai.J_Intervals = true;
+ Microsoft.Boogie.AbstractInterpretation.NativeAbstractInterpretation.RunAbstractInterpretation(program);
+ }
+ }
- if (CommandLineOptions.Clo.ExpandLambdas) {
- LambdaHelper.ExpandLambdas(program);
+ if (Bpl.CommandLineOptions.Clo.LoopUnrollCount != -1) {
+ program.UnrollLoops(Bpl.CommandLineOptions.Clo.LoopUnrollCount);
+ }
+
+ if (Bpl.CommandLineOptions.Clo.ExpandLambdas) {
+ Bpl.LambdaHelper.ExpandLambdas(program);
+ //PrintBplFile ("-", program, true);
}
// ---------- Verify ------------------------------------------------------------
- #region Verify each implementation
+ if (!Bpl.CommandLineOptions.Clo.Verify) { return PipelineOutcome.Done; }
+
+ #region Verify each implementation
ConditionGeneration vcgen = null;
try {
- if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) {
- vcgen = new DCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend);
+ if (Bpl.CommandLineOptions.Clo.vcVariety == Bpl.CommandLineOptions.VCVariety.Doomed) {
+ vcgen = new DCGen(program, Bpl.CommandLineOptions.Clo.SimplifyLogFilePath, Bpl.CommandLineOptions.Clo.SimplifyLogFileAppend);
} else {
- vcgen = new VCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend);
+ vcgen = new VCGen(program, Bpl.CommandLineOptions.Clo.SimplifyLogFilePath, Bpl.CommandLineOptions.Clo.SimplifyLogFileAppend);
}
- } catch (ProverException e) {
- ErrorWriteLine("Fatal Error: ProverException: {0}", e);
+ } catch (Bpl.ProverException) {
return PipelineOutcome.FatalError;
}
- foreach (Declaration decl in program.TopLevelDeclarations) {
+ var decls = program.TopLevelDeclarations.ToArray();
+ foreach (var decl in decls) {
Contract.Assert(decl != null);
- Implementation impl = decl as Implementation;
- if (impl != null && CommandLineOptions.Clo.UserWantsToCheckRoutine(cce.NonNull(impl.Name)) && !impl.SkipVerification) {
- List<Counterexample>/*?*/ errors;
-
- DateTime start = new DateTime(); // to please compiler's definite assignment rules
- if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.XmlSink != null) {
- start = DateTime.Now;
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine();
- Console.WriteLine("Verifying {0} ...", impl.Name);
- }
- if (CommandLineOptions.Clo.XmlSink != null) {
- CommandLineOptions.Clo.XmlSink.WriteStartMethod(impl.Name, start);
- }
- }
+ Bpl.Implementation impl = decl as Bpl.Implementation;
+ if (impl != null && Bpl.CommandLineOptions.Clo.UserWantsToCheckRoutine(impl.Name) && !impl.SkipVerification) {
+ List<Bpl.Counterexample>/*?*/ errors;
ConditionGeneration.Outcome outcome;
+ int prevAssertionCount = vcgen.CumulativeAssertionCount;
try {
- outcome = vcgen.VerifyImplementation(impl, program, out errors);
- } catch (VCGenException e) {
- ReportBplError(impl, String.Format("Error BP5010: {0} Encountered in implementation {1}.", e.Message, impl.Name), true);
+ outcome = vcgen.VerifyImplementation(impl, out errors);
+ } catch (VCGenException) {
errors = null;
outcome = VCGen.Outcome.Inconclusive;
- } catch (UnexpectedProverOutputException upo) {
- AdvisoryWriteLine("Advisory: {0} SKIPPED because of internal error: unexpected prover output: {1}", impl.Name, upo.Message);
+ } catch (Bpl.UnexpectedProverOutputException) {
errors = null;
outcome = VCGen.Outcome.Inconclusive;
}
- string timeIndication = "";
- DateTime end = DateTime.Now;
- TimeSpan elapsed = end - start;
- if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.XmlSink != null) {
- if (CommandLineOptions.Clo.Trace) {
- timeIndication = string.Format(" [{0} s] ", elapsed.TotalSeconds);
- }
- }
-
-
switch (outcome) {
default:
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected outcome
+ Contract.Assert(false); throw new Exception(); // unexpected outcome
case VCGen.Outcome.Correct:
- Inform(String.Format("{0}verified", timeIndication));
- verified++;
break;
case VCGen.Outcome.TimedOut:
- timeOuts++;
- Inform(String.Format("{0}timed out", timeIndication));
+ er(new DafnyErrorInformation(impl.tok, "Verification timed out (" + impl.Name + ")"));
break;
case VCGen.Outcome.OutOfMemory:
- outOfMemories++;
- Inform(String.Format("{0}out of memory", timeIndication));
+ er(new DafnyErrorInformation(impl.tok, "Verification out of memory (" + impl.Name + ")"));
break;
case VCGen.Outcome.Inconclusive:
- inconclusives++;
- Inform(String.Format("{0}inconclusive", timeIndication));
+ er(new DafnyErrorInformation(impl.tok, "Verification inconclusive (" + impl.Name + ")"));
break;
case VCGen.Outcome.Errors:
Contract.Assert(errors != null); // guaranteed by postcondition of VerifyImplementation
- // BP1xxx: Parsing errors
- // BP2xxx: Name resolution errors
- // BP3xxx: Typechecking errors
- // BP4xxx: Abstract interpretation errors (Is there such a thing?)
- // BP5xxx: Verification errors
-
- errors.Sort(new CounterexampleComparer());
- foreach (Counterexample error in errors) {
- if (error is CallCounterexample) {
- CallCounterexample err = (CallCounterexample)error;
- ReportBplError(err.FailingCall, "Error BP5002: A precondition for this call might not hold.", true);
- ReportBplError(err.FailingRequires, "Related location: This is the precondition that might not hold.", false);
- } else if (error is ReturnCounterexample) {
- ReturnCounterexample err = (ReturnCounterexample)error;
- ReportBplError(err.FailingReturn, "Error BP5003: A postcondition might not hold on this return path.", true);
- ReportBplError(err.FailingEnsures, "Related location: This is the postcondition that might not hold.", false);
- } else // error is AssertCounterexample
- {
- AssertCounterexample err = (AssertCounterexample)error;
- if (err.FailingAssert is LoopInitAssertCmd) {
- ReportBplError(err.FailingAssert, "Error BP5004: This loop invariant might not hold on entry.", true);
- } else if (err.FailingAssert is LoopInvMaintainedAssertCmd) {
- // this assertion is a loop invariant which is not maintained
- ReportBplError(err.FailingAssert, "Error BP5005: This loop invariant might not be maintained by the loop.", true);
- } else {
- string msg = err.FailingAssert.ErrorData as string;
- if (msg == null) {
- msg = "Error BP5001: This assertion might not hold.";
- }
- ReportBplError(err.FailingAssert, msg, true);
+
+ errors.Sort(new Bpl.CounterexampleComparer());
+ foreach (var error in errors) {
+ DafnyErrorInformation errorInfo;
+
+ if (error is Bpl.CallCounterexample) {
+ var err = (Bpl.CallCounterexample)error;
+ errorInfo = new DafnyErrorInformation(err.FailingCall.tok, err.FailingCall.ErrorData as string ?? "A precondition for this call might not hold.");
+ errorInfo.AddAuxInfo(err.FailingRequires.tok, err.FailingRequires.ErrorData as string ?? "Related location: This is the precondition that might not hold.");
+
+ } else if (error is Bpl.ReturnCounterexample) {
+ var err = (Bpl.ReturnCounterexample)error;
+ errorInfo = new DafnyErrorInformation(err.FailingReturn.tok, "A postcondition might not hold on this return path.");
+ errorInfo.AddAuxInfo(err.FailingEnsures.tok, err.FailingEnsures.ErrorData as string ?? "Related location: This is the postcondition that might not hold.");
+ errorInfo.AddAuxInfo(err.FailingEnsures.Attributes);
+
+ } else { // error is AssertCounterexample
+ var err = (Bpl.AssertCounterexample)error;
+ if (err.FailingAssert is Bpl.LoopInitAssertCmd) {
+ errorInfo = new DafnyErrorInformation(err.FailingAssert.tok, "This loop invariant might not hold on entry.");
+ } else if (err.FailingAssert is Bpl.LoopInvMaintainedAssertCmd) {
+ // this assertion is a loop invariant which is not maintained
+ errorInfo = new DafnyErrorInformation(err.FailingAssert.tok, "This loop invariant might not be maintained by the loop.");
+ } else {
+ string msg = err.FailingAssert.ErrorData as string;
+ if (msg == null) {
+ msg = "This assertion might not hold.";
}
+ errorInfo = new DafnyErrorInformation(err.FailingAssert.tok, msg);
+ errorInfo.AddAuxInfo(err.FailingAssert.Attributes);
}
- if (CommandLineOptions.Clo.ErrorTrace > 0) {
- Console.WriteLine("Execution trace:");
- foreach (Block b in error.Trace) {
- Contract.Assert(b != null);
- if (b.tok == null) {
- Console.WriteLine(" <intermediate block>");
- } 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)) {
- Console.WriteLine(" {0}({1},{2}): {3}", b.tok.filename, b.tok.line, b.tok.col, b.Label);
- }
- }
+ }
+ if (Bpl.CommandLineOptions.Clo.ErrorTrace > 0) {
+ foreach (Bpl.Block b in error.Trace) {
+ // 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 (!(Bpl.CommandLineOptions.Clo.ErrorTrace == 1 && b.tok.line == -17 && b.tok.col == -4) &&
+ b.tok.line != 0 && b.tok.col != 0) {
+ errorInfo.AddAuxInfo(b.tok, "Execution trace: " + b.Label);
}
}
- errorCount++;
}
- Inform(String.Format("{0}error{1}", timeIndication, errors.Count == 1 ? "" : "s"));
+ // if (Bpl.CommandLineOptions.Clo.ModelViewFile != null) {
+ // error.PrintModel();
+ // }
+ er(errorInfo);
+ }
break;
}
- if (outcome == VCGen.Outcome.Errors || CommandLineOptions.Clo.Trace) {
- Console.Out.Flush();
- }
}
}
vcgen.Close();
- cce.NonNull(CommandLineOptions.Clo.TheProverFactory).Close();
+ Bpl.CommandLineOptions.Clo.TheProverFactory.Close();
- #endregion
+ #endregion
return PipelineOutcome.VerificationCompleted;
}
- static void ReportBplError(Absy node, string message, bool error) {
- Contract.Requires(node != null); Contract.Requires(message != null);
- IToken tok = node.tok;
- string s;
- if (tok == null) {
- s = message;
- } else {
- s = string.Format("{0}({1},{2}): {3}", tok.filename, tok.line, tok.col, message);
+ public delegate void ErrorReporterDelegate(DafnyErrorInformation errInfo);
+
+ public class DafnyErrorInformation
+ {
+ public readonly Bpl.IToken Tok;
+ public readonly string Msg;
+ public readonly List<DafnyErrorAuxInfo> Aux = new List<DafnyErrorAuxInfo>();
+
+ public class DafnyErrorAuxInfo
+ {
+ public readonly Bpl.IToken Tok;
+ public readonly string Msg;
+ public DafnyErrorAuxInfo(Bpl.IToken tok, string msg) {
+ Tok = tok;
+ Msg = CleanUp(msg);
+ }
}
- if (error) {
- ErrorWriteLine(s);
- } else {
- Console.WriteLine(s);
+
+ public DafnyErrorInformation(Bpl.IToken tok, string msg) {
+ Contract.Requires(tok != null);
+ Contract.Requires(1 <= tok.line && 1 <= tok.col);
+ Contract.Requires(msg != null);
+ Tok = tok;
+ Msg = CleanUp(msg);
+ AddNestingsAsAux(tok);
+ }
+ public void AddAuxInfo(Bpl.IToken tok, string msg) {
+ Contract.Requires(tok != null);
+ Contract.Requires(1 <= tok.line && 1 <= tok.col);
+ Contract.Requires(msg != null);
+ Aux.Add(new DafnyErrorAuxInfo(tok, msg));
+ AddNestingsAsAux(tok);
+ }
+ void AddNestingsAsAux(Bpl.IToken tok) {
+ while (tok is Dafny.NestedToken) {
+ var nt = (Dafny.NestedToken)tok;
+ tok = nt.Inner;
+ Aux.Add(new DafnyErrorAuxInfo(tok, "Related location"));
+ }
+ }
+ public void AddAuxInfo(Bpl.QKeyValue attr) {
+ while (attr != null) {
+ if (attr.Key == "msg" && attr.Params.Count == 1 && attr.tok.line != 0 && attr.tok.col != 0) {
+ var str = attr.Params[0] as string;
+ if (str != null) {
+ AddAuxInfo(attr.tok, str);
+ }
+ }
+ attr = attr.Next;
+ }
}
- }
- /// <summary>
- /// Inform the user about something and proceed with translation normally.
- /// Print newline after the message.
- /// </summary>
- public static void Inform(string s) {
- if (CommandLineOptions.Clo.Trace) {
- Console.WriteLine(s);
+ public static string CleanUp(string msg) {
+ if (msg.ToLower().StartsWith("error: ")) {
+ return msg.Substring(7);
+ } else {
+ return msg;
+ }
}
}
-#endif
}
}
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/DafnyExtension.csproj b/Util/VS2010/DafnyExtension/DafnyExtension/DafnyExtension.csproj
index cf33e5a0..66370dec 100644
--- a/Util/VS2010/DafnyExtension/DafnyExtension/DafnyExtension.csproj
+++ b/Util/VS2010/DafnyExtension/DafnyExtension/DafnyExtension.csproj
@@ -63,10 +63,6 @@
<Reference Include="Houdini">
<HintPath>..\..\..\..\Binaries\Houdini.dll</HintPath>
</Reference>
- <Reference Include="Microsoft.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=736440c9b414ea16, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\..\..\..\Binaries\Microsoft.Contracts.dll</HintPath>
- </Reference>
<Reference Include="Model">
<HintPath>..\..\..\..\Binaries\Model.dll</HintPath>
</Reference>
@@ -76,6 +72,9 @@
<Reference Include="Provers.Z3">
<HintPath>..\..\..\..\Binaries\Provers.Z3.dll</HintPath>
</Reference>
+ <Reference Include="Provers.SMTLib">
+ <HintPath>..\..\..\..\Binaries\Provers.SMTLib.dll</HintPath>
+ </Reference>
<Reference Include="VCExpr">
<HintPath>..\..\..\..\Binaries\VCExpr.dll</HintPath>
</Reference>
@@ -129,28 +128,47 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BufferIdleEventUtil.cs" />
+ <Compile Include="HoverText.cs" />
+ <Compile Include="IdentifierTagger.cs" />
+ <Compile Include="ProgressMargin.cs" />
<Compile Include="OutliningTagger.cs" />
<Compile Include="ResolverTagger.cs" />
<Compile Include="DafnyDriver.cs" />
<Compile Include="ContentType.cs" />
<Compile Include="BraceMatching.cs" />
<Compile Include="WordHighlighter.cs" />
- <Compile Include="Outlining.cs" />
<Compile Include="ErrorTagger.cs" />
<Compile Include="TokenTagger.cs" />
<Compile Include="ClassificationTagger.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
+ <Content Include="DafnyPrelude.bpl">
+ <IncludeInVSIX>true</IncludeInVSIX>
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
</None>
+ <Content Include="UnivBackPred2.smt2">
+ <IncludeInVSIX>true</IncludeInVSIX>
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Service References\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\VSSDK\Microsoft.VsSDK.targets" />
+ <PropertyGroup>
+ <PostBuildEvent>cd</PostBuildEvent>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+ <PropertyGroup>
+ <PreBuildEvent>copy ..\..\..\..\..\..\Binaries\DafnyPrelude.bpl $(ProjectDir)
+copy ..\..\..\..\..\..\Binaries\UnivBackPred2.smt2 $(ProjectDir)</PreBuildEvent>
+ </PropertyGroup>
<!-- 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">
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/HoverText.cs b/Util/VS2010/DafnyExtension/DafnyExtension/HoverText.cs
new file mode 100644
index 00000000..be806f5b
--- /dev/null
+++ b/Util/VS2010/DafnyExtension/DafnyExtension/HoverText.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Input;
+using Microsoft.VisualStudio.Language.Intellisense;
+using System.Collections.ObjectModel;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Utilities;
+using System.Diagnostics.Contracts;
+
+
+namespace DafnyLanguage
+{
+ [Export(typeof(IQuickInfoSourceProvider))]
+ [ContentType("dafny")]
+ [Name("Dafny QuickInfo")]
+ class OokQuickInfoSourceProvider : IQuickInfoSourceProvider
+ {
+ [Import]
+ IBufferTagAggregatorFactoryService aggService = null;
+
+ public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) {
+ return new DafnyQuickInfoSource(textBuffer, aggService.CreateTagAggregator<DafnyTokenTag>(textBuffer));
+ }
+ }
+
+ class DafnyQuickInfoSource : IQuickInfoSource
+ {
+ private ITagAggregator<DafnyTokenTag> _aggregator;
+ private ITextBuffer _buffer;
+
+ public DafnyQuickInfoSource(ITextBuffer buffer, ITagAggregator<DafnyTokenTag> aggregator) {
+ _aggregator = aggregator;
+ _buffer = buffer;
+ }
+
+ public void AugmentQuickInfoSession(IQuickInfoSession session, IList<object> quickInfoContent, out ITrackingSpan applicableToSpan) {
+ applicableToSpan = null;
+
+ var triggerPoint = (SnapshotPoint)session.GetTriggerPoint(_buffer.CurrentSnapshot);
+ if (triggerPoint == null)
+ return;
+
+ foreach (IMappingTagSpan<DafnyTokenTag> curTag in _aggregator.GetTags(new SnapshotSpan(triggerPoint, triggerPoint))) {
+ var s = curTag.Tag.HoverText;
+ if (s != null) {
+ var tagSpan = curTag.Span.GetSpans(_buffer).First();
+ applicableToSpan = _buffer.CurrentSnapshot.CreateTrackingSpan(tagSpan, SpanTrackingMode.EdgeExclusive);
+ quickInfoContent.Add(s);
+ }
+ }
+ }
+ public void Dispose() {
+ }
+ }
+ // --------------------------------- QuickInfo controller ------------------------------------------
+
+ [Export(typeof(IIntellisenseControllerProvider))]
+ [Name("Dafny QuickInfo controller")]
+ [ContentType("dafny")]
+ class DafnyQuickInfoControllerProvider : IIntellisenseControllerProvider
+ {
+ [Import]
+ internal IQuickInfoBroker QuickInfoBroker { get; set; }
+
+ public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList<ITextBuffer> subjectBuffers) {
+ return new DafnyQuickInfoController(textView, subjectBuffers, this);
+ }
+ }
+
+ class DafnyQuickInfoController : IIntellisenseController
+ {
+ private ITextView _textView;
+ private IList<ITextBuffer> _subjectBuffers;
+ private DafnyQuickInfoControllerProvider _componentContext;
+
+ private IQuickInfoSession _session;
+
+ internal DafnyQuickInfoController(ITextView textView, IList<ITextBuffer> subjectBuffers, DafnyQuickInfoControllerProvider componentContext) {
+ _textView = textView;
+ _subjectBuffers = subjectBuffers;
+ _componentContext = componentContext;
+
+ _textView.MouseHover += this.OnTextViewMouseHover;
+ }
+
+ public void ConnectSubjectBuffer(ITextBuffer subjectBuffer) {
+ }
+
+ public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer) {
+ }
+
+ public void Detach(ITextView textView) {
+ if (_textView == textView) {
+ _textView.MouseHover -= OnTextViewMouseHover;
+ _textView = null;
+ }
+ }
+
+ void OnTextViewMouseHover(object sender, MouseHoverEventArgs e) {
+ SnapshotPoint? point = GetMousePosition(new SnapshotPoint(_textView.TextSnapshot, e.Position));
+
+ if (point != null) {
+ ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position, PointTrackingMode.Positive);
+
+ // Find the broker for this buffer
+ if (!_componentContext.QuickInfoBroker.IsQuickInfoActive(_textView)) {
+ _session = _componentContext.QuickInfoBroker.CreateQuickInfoSession(_textView, triggerPoint, true);
+ _session.Start();
+ }
+ }
+ }
+
+ SnapshotPoint? GetMousePosition(SnapshotPoint topPosition) {
+ return _textView.BufferGraph.MapDownToFirstMatch(
+ topPosition,
+ PointTrackingMode.Positive,
+ snapshot => _subjectBuffers.Contains(snapshot.TextBuffer),
+ PositionAffinity.Predecessor);
+ }
+ }
+}
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/IdentifierTagger.cs b/Util/VS2010/DafnyExtension/DafnyExtension/IdentifierTagger.cs
new file mode 100644
index 00000000..80a6dbb5
--- /dev/null
+++ b/Util/VS2010/DafnyExtension/DafnyExtension/IdentifierTagger.cs
@@ -0,0 +1,340 @@
+//***************************************************************************
+// Copyright © 2010 Microsoft Corporation. All Rights Reserved.
+// This code released under the terms of the
+// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)
+//***************************************************************************
+using EnvDTE;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ComponentModel.Composition;
+using System.Windows.Threading;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Text.Projection;
+using Microsoft.VisualStudio.Utilities;
+using System.Diagnostics.Contracts;
+using Bpl = Microsoft.Boogie;
+using Microsoft.Dafny;
+
+namespace DafnyLanguage
+{
+ [Export(typeof(ITaggerProvider))]
+ [ContentType("dafny")]
+ [TagType(typeof(DafnyTokenTag))]
+ internal sealed class IdentifierTaggerProvider : ITaggerProvider
+ {
+ [Import]
+ internal IBufferTagAggregatorFactoryService AggregatorFactory = null;
+
+ public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag {
+ ITagAggregator<DafnyResolverTag> tagAggregator = AggregatorFactory.CreateTagAggregator<DafnyResolverTag>(buffer);
+ // create a single tagger for each buffer.
+ Func<ITagger<T>> sc = delegate() { return new IdentifierTagger(buffer, tagAggregator) as ITagger<T>; };
+ return buffer.Properties.GetOrCreateSingletonProperty<ITagger<T>>(sc);
+ }
+ }
+
+ /// <summary>
+ /// Translate DafnyResolverTag's into IOutliningRegionTag's
+ /// </summary>
+ internal sealed class IdentifierTagger : ITagger<DafnyTokenTag>
+ {
+ ITextBuffer _buffer;
+ ITextSnapshot _snapshot; // the most recent snapshot of _buffer that we have been informed about
+ Microsoft.Dafny.Program _program; // the program parsed from _snapshot
+ List<IdRegion> _regions = new List<IdRegion>(); // the regions generated from _program
+ ITagAggregator<DafnyResolverTag> _aggregator;
+
+ internal IdentifierTagger(ITextBuffer buffer, ITagAggregator<DafnyResolverTag> tagAggregator) {
+ _buffer = buffer;
+ _snapshot = _buffer.CurrentSnapshot;
+ _aggregator = tagAggregator;
+ _aggregator.TagsChanged += new EventHandler<TagsChangedEventArgs>(_aggregator_TagsChanged);
+ }
+
+ /// <summary>
+ /// Find the Error tokens in the set of all tokens and create an ErrorTag for each
+ /// </summary>
+ public IEnumerable<ITagSpan<DafnyTokenTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
+ if (spans.Count == 0) yield break;
+ // (A NormalizedSnapshotSpanCollection contains spans that all come from the same snapshot.)
+ // The spans are ordered by the .Start component, and the collection contains no adjacent or abutting spans.
+ // Hence, to find a span that includes all the ones in "spans", we only need to look at the .Start for the
+ // first spand and the .End of the last span:
+ var startPoint = spans[0].Start;
+ var endPoint = spans[spans.Count - 1].End;
+
+ // Note, (startPoint,endPoint) are points in the spans for which we're being asked to provide tags. We need to translate
+ // these back into the most recent snapshot that we've computed regions for, namely _snapshot.
+ var entire = new SnapshotSpan(startPoint, endPoint).TranslateTo(_snapshot, SpanTrackingMode.EdgeExclusive);
+ int start = entire.Start;
+ int end = entire.End;
+ foreach (var r in _regions) {
+ if (0 <= r.Length && r.Start <= end && start <= r.Start + r.Length) {
+ DafnyTokenKinds kind;
+ switch (r.Kind) {
+ case IdRegion.OccurrenceKind.Use:
+ kind = DafnyTokenKinds.VariableIdentifier; break;
+ case IdRegion.OccurrenceKind.Definition:
+ kind = DafnyTokenKinds.VariableIdentifierDefinition; break;
+ case IdRegion.OccurrenceKind.WildDefinition:
+ kind = DafnyTokenKinds.Keyword; break;
+ default:
+ Contract.Assert(false); // unexpected OccurrenceKind
+ goto case IdRegion.OccurrenceKind.Use; // to please compiler
+ }
+ yield return new TagSpan<DafnyTokenTag>(
+ new SnapshotSpan(_snapshot, r.Start, r.Length),
+ new DafnyTokenTag(kind, r.HoverText));
+ }
+ }
+ }
+
+ // the Classifier tagger is translating buffer change events into TagsChanged events, so we don't have to
+ public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
+
+ void _aggregator_TagsChanged(object sender, TagsChangedEventArgs e) {
+ var r = sender as ResolverTagger;
+ if (r != null) {
+ ITextSnapshot snap;
+ Microsoft.Dafny.Program prog;
+ lock (this) {
+ snap = r._snapshot;
+ prog = r._program;
+ }
+ if (prog != null) {
+ if (!ComputeIdentifierRegions(prog, snap))
+ return; // no new regions
+
+ var chng = TagsChanged;
+ if (chng != null) {
+ NormalizedSnapshotSpanCollection spans = e.Span.GetSpans(_buffer.CurrentSnapshot);
+ if (spans.Count > 0) {
+ SnapshotSpan span = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End);
+ chng(this, new SnapshotSpanEventArgs(span));
+ }
+ }
+ }
+ }
+ }
+
+ bool ComputeIdentifierRegions(Microsoft.Dafny.Program program, ITextSnapshot snapshot) {
+ Contract.Requires(snapshot != null);
+
+ if (program == _program)
+ return false; // no new regions
+
+ List<IdRegion> newRegions = new List<IdRegion>();
+
+ foreach (var module in program.Modules) {
+ foreach (var d in module.TopLevelDecls) {
+ if (d is DatatypeDecl) {
+ var dt = (DatatypeDecl)d;
+ foreach (var ctor in dt.Ctors) {
+ foreach (var dtor in ctor.Destructors) {
+ if (dtor != null) {
+ IdRegion.Add(newRegions, dtor.tok, dtor, "destructor", true, module);
+ }
+ }
+ }
+ } else if (d is ClassDecl) {
+ var cl = (ClassDecl)d;
+ foreach (var member in cl.Members) {
+ if (member is Function) {
+ var f = (Function)member;
+ foreach (var p in f.Formals) {
+ IdRegion.Add(newRegions, p.tok, p, true, module);
+ }
+ f.Req.ForEach(e => ExprRegions(e, newRegions, module));
+ f.Reads.ForEach(fe => FrameExprRegions(fe, newRegions, true, module));
+ f.Ens.ForEach(e => ExprRegions(e, newRegions, module));
+ f.Decreases.Expressions.ForEach(e => ExprRegions(e, newRegions, module));
+ if (f.Body != null) {
+ ExprRegions(f.Body, newRegions, module);
+ }
+ } else if (member is Method) {
+ var m = (Method)member;
+ foreach (var p in m.Ins) {
+ IdRegion.Add(newRegions, p.tok, p, true, module);
+ }
+ foreach (var p in m.Outs) {
+ IdRegion.Add(newRegions, p.tok, p, true, module);
+ }
+ m.Req.ForEach(e => ExprRegions(e.E, newRegions, module));
+ m.Mod.Expressions.ForEach(fe => FrameExprRegions(fe, newRegions, true, module));
+ m.Ens.ForEach(e => ExprRegions(e.E, newRegions, module));
+ m.Decreases.Expressions.ForEach(e => ExprRegions(e, newRegions, module));
+ if (m.Body != null) {
+ StatementRegions(m.Body, newRegions, module);
+ }
+ } else if (member is Field) {
+ var fld = (Field)member;
+ IdRegion.Add(newRegions, fld.tok, fld, "field", true, module);
+ }
+ }
+ }
+ }
+ }
+ _snapshot = snapshot;
+ _regions = newRegions;
+ _program = program;
+ return true;
+ }
+
+ static void FrameExprRegions(FrameExpression fe, List<IdRegion> regions, bool descendIntoExpressions, ModuleDefinition module) {
+ Contract.Requires(fe != null);
+ Contract.Requires(regions != null);
+ if (descendIntoExpressions) {
+ ExprRegions(fe.E, regions, module);
+ }
+ if (fe.Field != null) {
+ IdRegion.Add(regions, fe.tok, fe.Field, "field", false, module);
+ }
+ }
+
+ static void ExprRegions(Microsoft.Dafny.Expression expr, List<IdRegion> regions, ModuleDefinition module) {
+ Contract.Requires(expr != null);
+ Contract.Requires(regions != null);
+ if (expr is IdentifierExpr) {
+ var e = (IdentifierExpr)expr;
+ IdRegion.Add(regions, e.tok, e.Var, false, module);
+ } else if (expr is FieldSelectExpr) {
+ var e = (FieldSelectExpr)expr;
+ IdRegion.Add(regions, e.tok, e.Field, "field", false, module);
+ } else if (expr is ComprehensionExpr) {
+ var e = (ComprehensionExpr)expr;
+ foreach (var bv in e.BoundVars) {
+ IdRegion.Add(regions, bv.tok, bv, true, module);
+ }
+ } else if (expr is MatchExpr) {
+ var e = (MatchExpr)expr;
+ foreach (var kase in e.Cases) {
+ kase.Arguments.ForEach(bv => IdRegion.Add(regions, bv.tok, bv, true, module));
+ }
+ } else if (expr is ChainingExpression) {
+ var e = (ChainingExpression)expr;
+ // Do the subexpressions only once (that is, avoid the duplication that occurs in the desugared form of the ChainingExpression)
+ e.Operands.ForEach(ee => ExprRegions(ee, regions, module));
+ return; // return here, so as to avoid doing the subexpressions below
+ }
+ foreach (var ee in expr.SubExpressions) {
+ ExprRegions(ee, regions, module);
+ }
+ }
+
+ static void StatementRegions(Statement stmt, List<IdRegion> regions, ModuleDefinition module) {
+ Contract.Requires(stmt != null);
+ Contract.Requires(regions != null);
+ if (stmt is VarDeclStmt) {
+ var s = (VarDeclStmt)stmt;
+ // Add the variables here, once, and then go directly to the RHS's (without letting the sub-statements re-do the LHS's)
+ foreach (var lhs in s.Lhss) {
+ IdRegion.Add(regions, lhs.Tok, lhs, true, module);
+ }
+ if (s.Update == null) {
+ // the VarDeclStmt has no associated assignment
+ } else if (s.Update is UpdateStmt) {
+ var upd = (UpdateStmt)s.Update;
+ foreach (var rhs in upd.Rhss) {
+ foreach (var ee in rhs.SubExpressions) {
+ ExprRegions(ee, regions, module);
+ }
+ }
+ } else {
+ var upd = (AssignSuchThatStmt)s.Update;
+ ExprRegions(upd.Expr, regions, module);
+ }
+ // we're done, so don't do the sub-statements/expressions again
+ return;
+ } else if (stmt is VarDecl) {
+ var s = (VarDecl)stmt;
+ IdRegion.Add(regions, s.Tok, s, true, module);
+ } else if (stmt is ParallelStmt) {
+ var s = (ParallelStmt)stmt;
+ s.BoundVars.ForEach(bv => IdRegion.Add(regions, bv.tok, bv, true, module));
+ } else if (stmt is MatchStmt) {
+ var s = (MatchStmt)stmt;
+ foreach (var kase in s.Cases) {
+ kase.Arguments.ForEach(bv => IdRegion.Add(regions, bv.tok, bv, true, module));
+ }
+ } else if (stmt is LoopStmt) {
+ var s = (LoopStmt)stmt;
+ if (s.Mod.Expressions != null) {
+ s.Mod.Expressions.ForEach(fe => FrameExprRegions(fe, regions, false, module));
+ }
+ }
+ foreach (var ee in stmt.SubExpressions) {
+ ExprRegions(ee, regions, module);
+ }
+ foreach (var ss in stmt.SubStatements) {
+ StatementRegions(ss, regions, module);
+ }
+ }
+
+ class IdRegion
+ {
+ public readonly int Start;
+ public readonly int Length;
+ public readonly string HoverText;
+ public enum OccurrenceKind { Use, Definition, WildDefinition }
+ public readonly OccurrenceKind Kind;
+
+ static bool SurfaceSyntaxToken(Bpl.IToken tok) {
+ Contract.Requires(tok != null);
+ return !(tok is TokenWrapper);
+ }
+
+ public static void Add(List<IdRegion> regions, Bpl.IToken tok, IVariable v, bool isDefinition, ModuleDefinition context) {
+ Contract.Requires(regions != null);
+ Contract.Requires(tok != null);
+ Contract.Requires(v != null);
+ if (SurfaceSyntaxToken(tok)) {
+ regions.Add(new IdRegion(tok, v, isDefinition, context));
+ }
+ }
+ public static void Add(List<IdRegion> regions, Bpl.IToken tok, Field decl, string kind, bool isDefinition, ModuleDefinition context) {
+ Contract.Requires(regions != null);
+ Contract.Requires(tok != null);
+ Contract.Requires(decl != null);
+ Contract.Requires(kind != null);
+ if (SurfaceSyntaxToken(tok)) {
+ regions.Add(new IdRegion(tok, decl, kind, isDefinition, context));
+ }
+ }
+
+ private IdRegion(Bpl.IToken tok, IVariable v, bool isDefinition, ModuleDefinition context) {
+ Contract.Requires(tok != null);
+ Contract.Requires(v != null);
+ Start = tok.pos;
+ Length = v.DisplayName.Length;
+ string kind;
+ if (v is VarDecl) {
+ kind = "local variable";
+ } else if (v is BoundVar) {
+ kind = "bound variable";
+ } else {
+ var formal = (Formal)v;
+ kind = formal.InParam ? "in-parameter" : "out-parameter";
+ }
+ HoverText = string.Format("({2}{3}) {0}: {1}", v.DisplayName, v.Type.TypeName(context), v.IsGhost ? "ghost " : "", kind);
+ Kind = !isDefinition ? OccurrenceKind.Use : VarDecl.HasWildcardName(v) ? OccurrenceKind.WildDefinition : OccurrenceKind.Definition;
+ }
+ private IdRegion(Bpl.IToken tok, Field decl, string kind, bool isDefinition, ModuleDefinition context) {
+ Contract.Requires(tok != null);
+ Contract.Requires(decl != null);
+ Contract.Requires(kind != null);
+ Start = tok.pos;
+ Length = decl.Name.Length;
+ HoverText = string.Format("({2}{3}) {0}: {1}", decl.FullNameInContext(context), decl.Type.TypeName(context), decl.IsGhost ? "ghost " : "", kind);
+ Kind = !isDefinition ? OccurrenceKind.Use : OccurrenceKind.Definition;
+ }
+ }
+ }
+
+}
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/Outlining.cs b/Util/VS2010/DafnyExtension/DafnyExtension/Outlining.cs
deleted file mode 100644
index 3e64e43d..00000000
--- a/Util/VS2010/DafnyExtension/DafnyExtension/Outlining.cs
+++ /dev/null
@@ -1,222 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Windows.Threading;
-using System.ComponentModel.Composition;
-using Microsoft.VisualStudio.Text.Outlining;
-using Microsoft.VisualStudio.Text.Tagging;
-using Microsoft.VisualStudio.Utilities;
-using Microsoft.VisualStudio.Text;
-
-namespace DafnyLanguage
-{
-#if THIS_IS_THE_PAST
- [Export(typeof(ITaggerProvider))]
- [ContentType("dafny")]
- [TagType(typeof(IOutliningRegionTag))]
- internal sealed class OutliningTaggerProvider : ITaggerProvider
- {
- public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag {
- // create a single tagger for each buffer.
- Func<ITagger<T>> sc = delegate() { return new OutlineTagger(buffer) as ITagger<T>; };
- return buffer.Properties.GetOrCreateSingletonProperty<ITagger<T>>(sc);
- }
- }
-
- /// <summary>
- /// Data about one outline region
- /// </summary>
- internal class OutlineRegion
- {
- public SnapshotPoint Start { get; set; }
- public SnapshotPoint End { get; set; }
- public SnapshotSpan Span {
- get { return new SnapshotSpan(Start, End); }
- }
-
- public string HoverText { get; set; }
- public string Label { get; set; }
- }
-
- internal sealed class OutlineTagger : ITagger<IOutliningRegionTag>
- {
- ITextBuffer _buffer;
- ITextSnapshot _snapshot;
- List<OutlineRegion> _regions;
-
- public OutlineTagger(ITextBuffer buffer) {
- _buffer = buffer;
- _snapshot = buffer.CurrentSnapshot;
- _regions = new List<OutlineRegion>();
-
- ReparseFile(null, EventArgs.Empty);
-
- // listen for changes to the buffer, but don't process until the user stops typing
- BufferIdleEventUtil.AddBufferIdleEventListener(_buffer, ReparseFile);
- }
-
- public void Dispose() {
- BufferIdleEventUtil.RemoveBufferIdleEventListener(_buffer, ReparseFile);
- }
-
- public IEnumerable<ITagSpan<IOutliningRegionTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
- if (spans.Count == 0)
- yield break;
-
- List<OutlineRegion> currentRegions = _regions;
- ITextSnapshot currentSnapshot = _snapshot;
-
- // create a new SnapshotSpan for the entire region encompassed by the span collection
- SnapshotSpan entire = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End).TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive);
- int startLineNumber = entire.Start.GetContainingLine().LineNumber;
- int endLineNumber = entire.End.GetContainingLine().LineNumber;
-
- // return outline tags for any regions that fall within that span
- foreach (var region in currentRegions) {
- if (entire.IntersectsWith(region.Span)) {
- //the region starts at the beginning of the "{", and goes until the *end* of the line that contains the "}".
- yield return new TagSpan<OutliningRegionTag>(new SnapshotSpan(region.Start, region.End),
- new OutliningRegionTag(false, false, region.Label, region.HoverText));
- }
- }
- }
-
- public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
-
- static string ellipsis = "..."; //the characters that are displayed when the region is collapsed
- static Regex matchKey = new Regex("^\\s*(datatype|method|function)");
- static int MaxHiddenLines = 15;
- static char[] eitherBrace = { '{', '}' };
-
- /// <summary>
- /// Find all of the outline sections in the snapshot
- /// </summary>
- private List<OutlineRegion> ParseOutlineSections(ITextSnapshot newSnapshot) {
- List<OutlineRegion> newRegions = new List<OutlineRegion>();
-
- // We care about three states:
- // (0) looking for an outlineable declaration
- // (1) have found an outlineable declaration, looking for an open curly
- // (2) looking for a close curly
- // The search used here is not at all exact, and it would be easy to get it to
- // do the wrong thing; however, in common cases, it will do the right thing.
- int state = 0;
- SnapshotPoint start = new SnapshotPoint(); // the value of "start" matters only if state==2
- int braceImbalance = 0; // used only if state==2
- string hoverText = ""; // used only if state==2
- int hoverLineCount = 0; // used only if state==2
- string prevLineBreak = ""; // used only if state==2
- foreach (ITextSnapshotLine line in newSnapshot.Lines) {
- string txt = line.GetText();
- if (state == 0) {
- MatchCollection matches = matchKey.Matches(txt);
- if (matches.Count != 0)
- state = 1;
- }
- int startPos = 0;
- if (state == 1) {
- startPos = txt.IndexOf('{');
- if (startPos != -1) {
- start = new SnapshotPoint(newSnapshot, line.Start.Position + startPos + 1);
- startPos++;
- state = 2;
- braceImbalance = 1;
- hoverText = txt.Substring(startPos).Trim();
- hoverLineCount = hoverText.Length == 0 ? 0 : 1;
- prevLineBreak = line.GetLineBreakText();
- }
- }
- if (state == 2) {
- int endPos = startPos;
- while (braceImbalance != 0) {
- endPos = txt.IndexOfAny(eitherBrace, endPos);
- if (endPos == -1) break;
- char ch = txt[endPos];
- if (ch == '{') {
- braceImbalance++;
- } else {
- braceImbalance--;
- if (braceImbalance == 0) break;
- }
- endPos++;
- }
-
- if (endPos == -1) {
- // not there yet
- if (startPos == 0 && hoverLineCount < MaxHiddenLines) {
- string h = txt.Trim();
- if (h.Length != 0) {
- if (hoverText.Length != 0)
- hoverText += prevLineBreak;
- hoverText += h;
- hoverLineCount++;
- prevLineBreak = line.GetLineBreakText();
- }
- }
- } else {
- // we found the end
- if (startPos != 0) {
- hoverText = txt.Substring(startPos, endPos - startPos).Trim();
- } else if (hoverLineCount < MaxHiddenLines) {
- string h = txt.Substring(0, endPos).Trim();
- if (h.Length != 0) {
- if (hoverText.Length != 0)
- hoverText += prevLineBreak;
- hoverText += h;
- }
- }
- SnapshotPoint end = new SnapshotPoint(newSnapshot, line.Start.Position + endPos);
- newRegions.Add(new OutlineRegion() {
- Start = start, End = end, Label = ellipsis,
- HoverText = hoverText
- });
- state = 0;
- }
- }
- }
-
- return newRegions;
- }
-
- /// <summary>
- /// Find all of the outline regions in the document (snapshot) and notify
- /// listeners of any that changed
- /// </summary>
- void ReparseFile(object sender, EventArgs args) {
- ITextSnapshot snapshot = _buffer.CurrentSnapshot;
-
- // get all of the outline regions in the snapshot
- List<OutlineRegion> newRegions = ParseOutlineSections(snapshot);
-
- // determine the changed span, and send a changed event with the new spans
- List<SnapshotSpan> oldSpans = new List<SnapshotSpan>(_regions.Select(r =>
- r.Span.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive)));
-
- List<SnapshotSpan> newSpans = new List<SnapshotSpan>(newRegions.Select(r => r.Span));
-
- NormalizedSnapshotSpanCollection oldSpanCollection = new NormalizedSnapshotSpanCollection(oldSpans);
- NormalizedSnapshotSpanCollection newSpanCollection = new NormalizedSnapshotSpanCollection(newSpans);
-
- NormalizedSnapshotSpanCollection difference = SymmetricDifference(oldSpanCollection, newSpanCollection);
-
- // save the new baseline
- _snapshot = snapshot;
- _regions = newRegions;
-
- foreach (var span in difference) {
- var chng = TagsChanged;
- if (chng != null)
- chng(this, new SnapshotSpanEventArgs(span));
- }
- }
-
- NormalizedSnapshotSpanCollection SymmetricDifference(NormalizedSnapshotSpanCollection first, NormalizedSnapshotSpanCollection second) {
- return NormalizedSnapshotSpanCollection.Union(
- NormalizedSnapshotSpanCollection.Difference(first, second),
- NormalizedSnapshotSpanCollection.Difference(second, first));
- }
- }
-#endif
-}
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/OutliningTagger.cs b/Util/VS2010/DafnyExtension/DafnyExtension/OutliningTagger.cs
index 390ed01f..a47cdba7 100644
--- a/Util/VS2010/DafnyExtension/DafnyExtension/OutliningTagger.cs
+++ b/Util/VS2010/DafnyExtension/DafnyExtension/OutliningTagger.cs
@@ -18,6 +18,7 @@ using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Tagging;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.VisualStudio.Utilities;
+using System.Diagnostics.Contracts;
using Bpl = Microsoft.Boogie;
using Dafny = Microsoft.Dafny;
@@ -45,12 +46,14 @@ namespace DafnyLanguage
internal sealed class OutliningTagger : ITagger<IOutliningRegionTag>
{
ITextBuffer _buffer;
+ ITextSnapshot _snapshot; // the most recent snapshot of _buffer that we have been informed about
+ Dafny.Program _program; // the program parsed from _snapshot
+ List<ORegion> _regions = new List<ORegion>(); // the regions generated from _program
ITagAggregator<DafnyResolverTag> _aggregator;
- Dafny.Program _program;
- List<ORegion> _regions = new List<ORegion>();
internal OutliningTagger(ITextBuffer buffer, ITagAggregator<DafnyResolverTag> tagAggregator) {
_buffer = buffer;
+ _snapshot = _buffer.CurrentSnapshot;
_aggregator = tagAggregator;
_aggregator.TagsChanged += new EventHandler<TagsChangedEventArgs>(_aggregator_TagsChanged);
}
@@ -60,11 +63,26 @@ namespace DafnyLanguage
/// </summary>
public IEnumerable<ITagSpan<IOutliningRegionTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
if (spans.Count == 0) yield break;
- var snapshot = spans[0].Snapshot;
+ // (A NormalizedSnapshotSpanCollection contains spans that all come from the same snapshot.)
+ // The spans are ordered by the .Start component, and the collection contains no adjacent or abutting spans.
+ // Hence, to find a span that includes all the ones in "spans", we only need to look at the .Start for the
+ // first spand and the .End of the last span:
+ var startPoint = spans[0].Start;
+ var endPoint = spans[spans.Count - 1].End;
+
+ // Note, (startPoint,endPoint) are points in the spans for which we're being asked to provide tags. We need to translate
+ // these back into the most recent snapshot that we've computed regions for, namely _snapshot.
+ var entire = new SnapshotSpan(startPoint, endPoint).TranslateTo(_snapshot, SpanTrackingMode.EdgeExclusive);
+ int start = entire.Start;
+ int end = entire.End;
+ if (start == end) yield break;
+
foreach (var r in _regions) {
- yield return new TagSpan<OutliningRegionTag>(
- new SnapshotSpan(snapshot, r.Start, r.Length),
- new OutliningRegionTag(false, false, "...", r.HoverText));
+ if (0 <= r.Length && r.Start <= end && start <= r.Start + r.Length) {
+ yield return new TagSpan<OutliningRegionTag>(
+ new SnapshotSpan(_snapshot, r.Start, r.Length),
+ new OutliningRegionTag(false, false, "...", r.HoverText));
+ }
}
}
@@ -73,34 +91,53 @@ namespace DafnyLanguage
void _aggregator_TagsChanged(object sender, TagsChangedEventArgs e) {
var r = sender as ResolverTagger;
- if (r != null && r._program != null) {
- if (!ComputeOutliningRegions(r._program))
- return; // no new regions
-
- var chng = TagsChanged;
- if (chng != null) {
- NormalizedSnapshotSpanCollection spans = e.Span.GetSpans(_buffer.CurrentSnapshot);
- if (spans.Count > 0) {
- SnapshotSpan span = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End);
- chng(this, new SnapshotSpanEventArgs(span));
+ if (r != null) {
+ ITextSnapshot snap;
+ Microsoft.Dafny.Program prog;
+ lock (this) {
+ snap = r._snapshot;
+ prog = r._program;
+ }
+ if (prog != null) {
+ if (!ComputeOutliningRegions(prog, snap))
+ return; // no new regions
+
+ var chng = TagsChanged;
+ if (chng != null) {
+ NormalizedSnapshotSpanCollection spans = e.Span.GetSpans(_buffer.CurrentSnapshot);
+ if (spans.Count > 0) {
+ SnapshotSpan span = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End);
+ chng(this, new SnapshotSpanEventArgs(span));
+ }
}
}
}
}
- bool ComputeOutliningRegions(Dafny.Program program) {
+ bool ComputeOutliningRegions(Dafny.Program program, ITextSnapshot snapshot) {
+ Contract.Requires(snapshot != null);
+
if (program == _program)
return false; // no new regions
List<ORegion> newRegions = new List<ORegion>();
- foreach (Dafny.ModuleDecl module in program.Modules) {
+ foreach (var module in program.Modules) {
if (!module.IsDefaultModule) {
newRegions.Add(new ORegion(module, "module"));
}
foreach (Dafny.TopLevelDecl d in module.TopLevelDecls) {
- if (d is Dafny.DatatypeDecl) {
+ if (!HasBodyTokens(d) && !(d is Dafny.ClassDecl)) {
+ continue;
+ }
+ if (d is Dafny.ArbitraryTypeDecl) {
+ newRegions.Add(new ORegion(d, "type"));
+ } else if (d is Dafny.CoDatatypeDecl) {
+ newRegions.Add(new ORegion(d, "codatatype"));
+ } else if (d is Dafny.DatatypeDecl) {
newRegions.Add(new ORegion(d, "datatype"));
+ } else if (d is Dafny.ModuleDecl) {
+ // do nothing here, since the outer loop handles modules
} else {
Dafny.ClassDecl cl = (Dafny.ClassDecl)d;
if (!cl.IsDefaultClass) {
@@ -108,20 +145,29 @@ namespace DafnyLanguage
}
// do the class members (in particular, functions and methods)
foreach (Dafny.MemberDecl m in cl.Members) {
+ if (!HasBodyTokens(m)) {
+ continue;
+ }
if (m is Dafny.Function && ((Dafny.Function)m).Body != null) {
- newRegions.Add(new ORegion(m, "function"));
+ newRegions.Add(new ORegion(m, m is Dafny.CoPredicate ? "copredicate" : m is Dafny.Predicate ? "predicate" : "function"));
} else if (m is Dafny.Method && ((Dafny.Method)m).Body != null) {
- newRegions.Add(new ORegion(m, "method"));
+ newRegions.Add(new ORegion(m, m is Dafny.Constructor ? "constructor" : "method"));
}
}
}
}
}
+ _snapshot = snapshot;
_regions = newRegions;
_program = program;
return true;
}
+ bool HasBodyTokens(Dafny.Declaration decl) {
+ Contract.Requires(decl != null);
+ return decl.BodyStartTok != Bpl.Token.NoToken && decl.BodyEndTok != Bpl.Token.NoToken;
+ }
+
class ORegion
{
public readonly int Start;
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/ProgressMargin.cs b/Util/VS2010/DafnyExtension/DafnyExtension/ProgressMargin.cs
new file mode 100644
index 00000000..7fdf38a6
--- /dev/null
+++ b/Util/VS2010/DafnyExtension/DafnyExtension/ProgressMargin.cs
@@ -0,0 +1,260 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Windows.Threading;
+using System.Windows;
+using System.Windows.Shapes;
+using System.Windows.Media;
+using System.Windows.Controls;
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Formatting;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Utilities;
+using System.Diagnostics.Contracts;
+using Dafny = Microsoft.Dafny;
+using Bpl = Microsoft.Boogie;
+
+
+namespace DafnyLanguage
+{
+ #region UI stuff
+ internal class ProgressMarginGlyphFactory : IGlyphFactory
+ {
+ public UIElement GenerateGlyph(IWpfTextViewLine line, IGlyphTag tag) {
+ var dtag = tag as ProgressGlyphTag;
+ if (dtag == null) {
+ return null;
+ }
+
+ System.Windows.Shapes.Rectangle sh = new Rectangle() {
+ Fill = dtag.Val == 0 ? Brushes.Violet : Brushes.DarkOrange,
+ Height = 18.0,
+ Width = 3.0
+ };
+ return sh;
+ }
+ }
+
+ [Export(typeof(IGlyphFactoryProvider))]
+ [Name("ProgressMarginGlyph")]
+ [Order(After = "TokenTagger")]
+ [ContentType("dafny")]
+ [TagType(typeof(ProgressGlyphTag))]
+ internal sealed class ProgressMarginGlyphFactoryProvider : IGlyphFactoryProvider
+ {
+ public IGlyphFactory GetGlyphFactory(IWpfTextView view, IWpfTextViewMargin margin) {
+ return new ProgressMarginGlyphFactory();
+ }
+ }
+
+ internal class ProgressGlyphTag : IGlyphTag
+ {
+ public readonly int Val;
+ public ProgressGlyphTag(int val) {
+ Val = val;
+ }
+ }
+ #endregion
+
+ [Export(typeof(ITaggerProvider))]
+ [ContentType("dafny")]
+ [TagType(typeof(ProgressGlyphTag))]
+ class ProgressTaggerProvider : ITaggerProvider
+ {
+ [Import]
+ internal IBufferTagAggregatorFactoryService AggregatorFactory = null;
+
+ [Import(typeof(Microsoft.VisualStudio.Shell.SVsServiceProvider))]
+ internal IServiceProvider _serviceProvider = null;
+
+ public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag {
+ ITagAggregator<DafnyResolverTag> tagAggregator = AggregatorFactory.CreateTagAggregator<DafnyResolverTag>(buffer);
+ // create a single tagger for each buffer.
+ Func<ITagger<T>> sc = delegate() { return new ProgressTagger(buffer, _serviceProvider, tagAggregator) as ITagger<T>; };
+ return buffer.Properties.GetOrCreateSingletonProperty<ITagger<T>>(sc);
+ }
+ }
+
+ internal class ProgressTagger : ITagger<ProgressGlyphTag>
+ {
+ ErrorListProvider _errorProvider;
+ ITextBuffer _buffer;
+
+ readonly DispatcherTimer timer;
+
+ public ProgressTagger(ITextBuffer buffer, IServiceProvider serviceProvider, ITagAggregator<DafnyResolverTag> tagAggregator) {
+ _buffer = buffer;
+ _errorProvider = new ErrorListProvider(serviceProvider);
+
+ timer = new DispatcherTimer(DispatcherPriority.ApplicationIdle);
+ timer.Interval = TimeSpan.FromMilliseconds(500);
+ timer.Tick += new EventHandler(UponIdle);
+
+ tagAggregator.TagsChanged += new EventHandler<TagsChangedEventArgs>(_aggregator_TagsChanged);
+ buffer.Changed += new EventHandler<TextContentChangedEventArgs>(buffer_Changed);
+ bufferChangesPostVerificationStart.Add(new SnapshotSpan(buffer.CurrentSnapshot, 0, buffer.CurrentSnapshot.Length));
+ }
+
+ public void Dispose() {
+ }
+
+ // The following fields and the contents of the following two lists are protected by the lock "this".
+ List<SnapshotSpan> bufferChangesPreVerificationStart = new List<SnapshotSpan>(); // buffer changes after the last completed verification and before the currently running verification
+ List<SnapshotSpan> bufferChangesPostVerificationStart = new List<SnapshotSpan>(); // buffer changes since the start of the currently running verification
+
+ void buffer_Changed(object sender, TextContentChangedEventArgs e) {
+ lock (this) {
+ foreach (var change in e.Changes) {
+ var startLine = e.After.GetLineFromPosition(change.NewPosition);
+ var endLine = e.After.GetLineFromPosition(change.NewEnd);
+ bufferChangesPostVerificationStart.Add(new SnapshotSpan(startLine.Start, endLine.End));
+ }
+ }
+ }
+
+ // The next field is protected by "this"
+ ResolverTagger resolver;
+ // Keep track of the most recent resolution results.
+ void _aggregator_TagsChanged(object sender, TagsChangedEventArgs e) {
+ var r = sender as ResolverTagger;
+ if (r != null) {
+ lock (this) {
+ resolver = r;
+ }
+ timer.Stop();
+ timer.Start();
+ }
+ }
+
+ bool verificationInProgress; // this field is protected by "this". Invariant: !verificationInProgress ==> bufferChangesPreVerificationStart.Count == 0
+ /// <summary>
+ /// This method is invoked when the user has been idle for a little while.
+ /// Note, "sender" and "args" are allowed to be passed in as null--they are not used by this method.
+ /// </summary>
+ public void UponIdle(object sender, EventArgs args) {
+ Dafny.Program prog;
+ ITextSnapshot snap;
+ ResolverTagger r;
+ lock (this) {
+ if (verificationInProgress) {
+ // This UponIdle message came at an inopportune time--we've already kicked off a verification.
+ // Just back off.
+ return;
+ }
+
+ if (resolver == null) return;
+ lock (resolver) {
+ prog = resolver._program;
+ snap = resolver._snapshot;
+ }
+ r = resolver;
+ resolver = null;
+ if (prog == null) return;
+ // We have a successfully resolved program to verify
+
+ var resolvedVersion = snap.Version.VersionNumber;
+ if (bufferChangesPostVerificationStart.Count == 0) {
+ // Nothing new to verify. No reason to start a new verification.
+ return;
+ } else if (!bufferChangesPostVerificationStart.TrueForAll(span => span.Snapshot.Version.VersionNumber <= resolvedVersion)) {
+ // There have been buffer changes since the program that was resolved. Do nothing here,
+ // and instead just await the next resolved program.
+ return;
+ }
+
+ // at this time, we're committed to running the verifier
+ verificationInProgress = true;
+
+ // Change orange progress markers into yellow ones
+ Contract.Assert(bufferChangesPreVerificationStart.Count == 0); // follows from monitor invariant
+ var empty = bufferChangesPreVerificationStart;
+ bufferChangesPreVerificationStart = bufferChangesPostVerificationStart;
+ bufferChangesPostVerificationStart = empty;
+ // Notify to-whom-it-may-concern about the changes we just made
+ var chng = TagsChanged;
+ if (chng != null) {
+ chng(this, new SnapshotSpanEventArgs(new SnapshotSpan(snap, 0, snap.Length)));
+ }
+
+ }
+ new Thread(() => VerificationWorker(prog, snap, r)).Start();
+ }
+
+ /// <summary>
+ /// Thread entry point.
+ /// </summary>
+ void VerificationWorker(Dafny.Program program, ITextSnapshot snapshot, ResolverTagger errorListHolder) {
+ Contract.Requires(program != null);
+ Contract.Requires(snapshot != null);
+ Contract.Requires(errorListHolder != null);
+
+ // Run the verifier
+ var newErrors = new List<DafnyError>();
+ try {
+ bool success = DafnyDriver.Verify(program, errorInfo => {
+ newErrors.Add(new DafnyError(errorInfo.Tok.line - 1, errorInfo.Tok.col - 1, ErrorCategory.VerificationError, errorInfo.Msg));
+ foreach (var aux in errorInfo.Aux) {
+ newErrors.Add(new DafnyError(aux.Tok.line - 1, aux.Tok.col - 1, ErrorCategory.AuxInformation, aux.Msg));
+ }
+ });
+ if (!success) {
+ newErrors.Add(new DafnyError(0, 0, ErrorCategory.InternalError, "verification process error"));
+ }
+ } catch (Exception e) {
+ newErrors.Add(new DafnyError(0, 0, ErrorCategory.InternalError, "verification process error: " + e.Message));
+ }
+ errorListHolder.PopulateErrorList(newErrors, true, snapshot);
+
+ lock (this) {
+ bufferChangesPreVerificationStart.Clear();
+ verificationInProgress = false;
+ }
+ // Notify to-whom-it-may-concern about the cleared pre-verification changes
+ var chng = TagsChanged;
+ if (chng != null) {
+ chng(this, new SnapshotSpanEventArgs(new SnapshotSpan(snapshot, 0, snapshot.Length)));
+ }
+
+ // If new changes took place since we started the verification, we may need to kick off another verification
+ // immediately.
+ UponIdle(null, null);
+ }
+
+ public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
+ IEnumerable<ITagSpan<ProgressGlyphTag>> ITagger<ProgressGlyphTag>.GetTags(NormalizedSnapshotSpanCollection spans) {
+ if (spans.Count == 0) yield break;
+ var targetSnapshot = spans[0].Snapshot;
+
+ List<SnapshotSpan> pre;
+ List<SnapshotSpan> post;
+ lock (this) {
+ pre = bufferChangesPreVerificationStart;
+ post = bufferChangesPostVerificationStart;
+ }
+
+ // If the requested snapshot isn't the same as the one our words are on, translate our spans to the expected snapshot
+ NormalizedSnapshotSpanCollection chs;
+ chs = new NormalizedSnapshotSpanCollection(Map(pre, span => span.TranslateTo(targetSnapshot, SpanTrackingMode.EdgeExclusive)));
+ foreach (SnapshotSpan span in NormalizedSnapshotSpanCollection.Overlap(spans, chs)) {
+ yield return new TagSpan<ProgressGlyphTag>(span, new ProgressGlyphTag(0));
+ }
+ chs = new NormalizedSnapshotSpanCollection(Map(post, span => span.TranslateTo(targetSnapshot, SpanTrackingMode.EdgeExclusive)));
+ foreach (SnapshotSpan span in NormalizedSnapshotSpanCollection.Overlap(spans, chs)) {
+ yield return new TagSpan<ProgressGlyphTag>(span, new ProgressGlyphTag(1));
+ }
+ }
+
+ /// <summary>
+ /// (Why the firetruck isn't an extension method like this already in the standard library?)
+ /// </summary>
+ public static IEnumerable<TOut> Map<TIn, TOut>(IEnumerable<TIn> coll, System.Func<TIn, TOut> fn) {
+ foreach (var e in coll) {
+ yield return fn(e);
+ }
+ }
+ }
+}
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/ResolverTagger.cs b/Util/VS2010/DafnyExtension/DafnyExtension/ResolverTagger.cs
index 1a288ab4..d1af6878 100644
--- a/Util/VS2010/DafnyExtension/DafnyExtension/ResolverTagger.cs
+++ b/Util/VS2010/DafnyExtension/DafnyExtension/ResolverTagger.cs
@@ -10,6 +10,7 @@ using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.Windows.Threading;
+using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
@@ -17,7 +18,9 @@ using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Tagging;
using Microsoft.VisualStudio.Text.Projection;
+using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
+using System.Diagnostics.Contracts;
using Dafny = Microsoft.Dafny;
namespace DafnyLanguage
@@ -67,10 +70,12 @@ namespace DafnyLanguage
{
ITextBuffer _buffer;
ITextDocument _document;
- ITextSnapshot _snapshot; // may be null
- List<DafnyError> _errors = new List<DafnyError>();
- ErrorListProvider _errorProvider;
+ // The _snapshot and _program fields should be updated and read together, so they are protected by "this"
+ public ITextSnapshot _snapshot; // may be null
public Dafny.Program _program; // non-null only if the snapshot contains a Dafny program that type checks
+ List<DafnyError> _resolutionErrors = new List<DafnyError>(); // if nonempty, then _snapshot is the snapshot from which the errors were produced
+ List<DafnyError> _verificationErrors = new List<DafnyError>();
+ ErrorListProvider _errorProvider;
internal ResolverTagger(ITextBuffer buffer, IServiceProvider serviceProvider, ITextDocumentFactoryService textDocumentFactory) {
_buffer = buffer;
@@ -79,7 +84,7 @@ namespace DafnyLanguage
_snapshot = null; // this makes sure the next snapshot will look different
_errorProvider = new ErrorListProvider(serviceProvider);
- BufferIdleEventUtil.AddBufferIdleEventListener(_buffer, ProcessFile);
+ BufferIdleEventUtil.AddBufferIdleEventListener(_buffer, ResolveBuffer);
}
public void Dispose() {
@@ -91,7 +96,20 @@ namespace DafnyLanguage
}
_errorProvider.Dispose();
}
- BufferIdleEventUtil.RemoveBufferIdleEventListener(_buffer, ProcessFile);
+ BufferIdleEventUtil.RemoveBufferIdleEventListener(_buffer, ResolveBuffer);
+ }
+
+ public IEnumerable<DafnyError> AllErrors() {
+ foreach (var err in _resolutionErrors) {
+ yield return err;
+ }
+ if (_resolutionErrors.Count != 0) {
+ // we're done
+ yield break;
+ }
+ foreach (var err in _verificationErrors) {
+ yield return err;
+ }
}
/// <summary>
@@ -99,110 +117,205 @@ namespace DafnyLanguage
/// </summary>
public IEnumerable<ITagSpan<DafnyResolverTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
if (spans.Count == 0) yield break;
- var snapshot = spans[0].Snapshot;
-
- foreach (var err in _errors) {
+ var currentSnapshot = spans[0].Snapshot;
+ foreach (var err in AllErrors()) {
if (err.Category != ErrorCategory.ProcessError) {
- var line = snapshot.GetLineFromLineNumber(err.Line);
- var length = line.Length - err.Column;
- if (5 < length) length = 5;
- SnapshotSpan span = new SnapshotSpan(new SnapshotPoint(snapshot, line.Start.Position + err.Column), length);
- // http://msdn.microsoft.com/en-us/library/dd885244.aspx says one can use the error types below, but they
- // all show as purple squiggles for me. And just "error" (which is not mentioned on that page) shows up
- // as red.
- string ty;
+ var span = err.Span().TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive);
+ string ty; // the COLORs below indicate what I see on my machine
switch (err.Category) {
default: // unexpected category
case ErrorCategory.ParseError:
- // ty = "syntax error";
- ty = "error"; break;
+ case ErrorCategory.ParseWarning:
+ ty = "syntax error"; break; // COLOR: red
case ErrorCategory.ResolveError:
- ty = "compiler error"; break;
+ ty = "compiler error"; break; // COLOR: blue
case ErrorCategory.VerificationError:
- ty = "other error"; break;
- case ErrorCategory.ParseWarning:
- ty = "warning"; break;
+ ty = "error"; break; // COLOR: red
+ case ErrorCategory.AuxInformation:
+ ty = "other error"; break; // COLOR: purple red
+ case ErrorCategory.InternalError:
+ ty = "error"; break; // COLOR: red
}
yield return new TagSpan<DafnyResolverTag>(span, new DafnyErrorResolverTag(ty, err.Message));
}
}
- if (_program != null) {
- yield return new TagSpan<DafnyResolverTag>(new SnapshotSpan(snapshot, 0, snapshot.Length), new DafnySuccessResolverTag(_program));
+
+ ITextSnapshot snap;
+ Dafny.Program prog;
+ lock (this) {
+ snap = _snapshot;
+ prog = _program;
+ }
+ if (prog != null) {
+ yield return new TagSpan<DafnyResolverTag>(new SnapshotSpan(snap, 0, snap.Length), new DafnySuccessResolverTag(prog));
}
}
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
/// <summary>
- /// Calls the Dafny verifier on the program, updates the Error List accordingly.
+ /// Calls the Dafny parser/resolver/type checker on the contents of the buffer, updates the Error List accordingly.
/// </summary>
- void ProcessFile(object sender, EventArgs args) {
+ void ResolveBuffer(object sender, EventArgs args) {
ITextSnapshot snapshot = _buffer.CurrentSnapshot;
if (snapshot == _snapshot)
return; // we've already done this snapshot
NormalizedSnapshotSpanCollection spans = new NormalizedSnapshotSpanCollection(new SnapshotSpan(snapshot, 0, snapshot.Length));
- var driver = new DafnyDriver(_buffer.CurrentSnapshot.GetText(), _document != null ? _document.FilePath : "<program>");
- Dafny.Program program = driver.Process();
- var newErrors = driver.Errors;
+ var driver = new DafnyDriver(snapshot.GetText(), _document != null ? _document.FilePath : "<program>");
+ List<DafnyError> newErrors;
+ Dafny.Program program;
+ try {
+ program = driver.ProcessResolution();
+ newErrors = driver.Errors;
+ } catch (Exception e) {
+ newErrors = new List<DafnyError>();
+ newErrors.Add(new DafnyError(0, 0, ErrorCategory.InternalError, "internal Dafny error: " + e.Message));
+ program = null;
+ }
- _errorProvider.Tasks.Clear();
+ lock (this) {
+ _snapshot = snapshot;
+ _program = program;
+ }
+ PopulateErrorList(newErrors, false, snapshot);
+ }
+
+ public void PopulateErrorList(List<DafnyError> newErrors, bool verificationErrors, ITextSnapshot snapshot) {
+ Contract.Requires(newErrors != null);
foreach (var err in newErrors) {
- ErrorTask task = new ErrorTask();
- task.CanDelete = true;
- task.Category = TaskCategory.BuildCompile;
- if (_document != null)
+ err.FillInSnapshot(snapshot);
+ }
+ if (verificationErrors) {
+ _verificationErrors = newErrors;
+ } else {
+ _resolutionErrors = newErrors;
+ }
+
+ _errorProvider.SuspendRefresh(); // reduce flickering
+ _errorProvider.Tasks.Clear();
+ foreach (var err in AllErrors()) {
+ ErrorTask task = new ErrorTask() {
+ Category = TaskCategory.BuildCompile,
+ ErrorCategory = CategoryConversion(err.Category),
+ Text = err.Message,
+ Line = err.Line,
+ Column = err.Column
+ };
+ if (_document != null) {
task.Document = _document.FilePath;
- task.ErrorCategory = TaskErrorCategory.Error;
- task.Text = err.Message;
- if (err.Category != ErrorCategory.ProcessError) {
- task.Line = err.Line;
- task.Column = err.Column;
- task.Navigate += new EventHandler(task_Navigate);
+ }
+ if (err.Category != ErrorCategory.ProcessError && err.Category != ErrorCategory.InternalError) {
+ task.Navigate += new EventHandler(NavigateHandler);
}
_errorProvider.Tasks.Add(task);
}
-
- _errors = newErrors;
- _snapshot = snapshot;
- _program = program;
+ _errorProvider.ResumeRefresh();
var chng = TagsChanged;
if (chng != null)
chng(this, new SnapshotSpanEventArgs(new SnapshotSpan(snapshot, 0, snapshot.Length)));
}
- /// <summary>
- /// Callback method attached to each of our tasks in the Error List
- /// </summary>
- void task_Navigate(object sender, EventArgs e) {
- ErrorTask error = sender as ErrorTask;
- if (error != null) {
- error.Line += 1;
- error.Column += 1;
- // TODO: how to move the cursor to the right column?
- _errorProvider.Navigate(error, new Guid(EnvDTE.Constants.vsViewKindCode));
- error.Column -= 1;
- error.Line -= 1;
+ TaskErrorCategory CategoryConversion(ErrorCategory cat) {
+ switch (cat) {
+ case ErrorCategory.ParseError:
+ case ErrorCategory.ResolveError:
+ case ErrorCategory.VerificationError:
+ case ErrorCategory.InternalError:
+ return TaskErrorCategory.Error;
+ case ErrorCategory.ParseWarning:
+ return TaskErrorCategory.Warning;
+ case ErrorCategory.AuxInformation:
+ return TaskErrorCategory.Message;
+ default:
+ Contract.Assert(false); // unexpected category
+ return TaskErrorCategory.Error; // please compiler
}
}
+
+ void NavigateHandler(object sender, EventArgs arguments) {
+ var task = sender as ErrorTask;
+ if (task == null || task.Document == null)
+ return;
+
+ // This would have been the simple way of doing things:
+ // _errorProvider.Navigate(error, new Guid(EnvDTE.Constants.vsViewKindCode));
+ // Unfortunately, it doesn't work--it seems to ignore the column position. (Moreover, it wants 1-based
+ // line/column numbers, whereas the Error Task pane wants 0-based line/column numbers.)
+ // So, instead we do all the things that follow:
+
+ var openDoc = Package.GetGlobalService(typeof(IVsUIShellOpenDocument)) as IVsUIShellOpenDocument;
+ if (openDoc == null)
+ return;
+
+ IVsWindowFrame frame;
+ Microsoft.VisualStudio.OLE.Interop.IServiceProvider sp;
+ IVsUIHierarchy hier;
+ uint itemid;
+ Guid logicalView = VSConstants.LOGVIEWID_Code;
+ if (Microsoft.VisualStudio.ErrorHandler.Failed(openDoc.OpenDocumentViaProject(task.Document, ref logicalView, out sp, out hier, out itemid, out frame)) || frame == null)
+ return;
+
+ object docData;
+ Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocData, out docData));
+
+ // Get the VsTextBuffer
+ VsTextBuffer buffer = docData as VsTextBuffer;
+ if (buffer == null) {
+ IVsTextBufferProvider bufferProvider = docData as IVsTextBufferProvider;
+ if (bufferProvider != null) {
+ IVsTextLines lines;
+ Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(bufferProvider.GetTextBuffer(out lines));
+ buffer = lines as VsTextBuffer;
+ if (buffer == null)
+ return;
+ }
+ }
+
+ VsTextManager textManager = Package.GetGlobalService(typeof(VsTextManagerClass)) as VsTextManager;
+ if (textManager == null)
+ return;
+
+ // Finally, move the cursor
+ Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(textManager.NavigateToLineAndColumn(buffer, ref logicalView, task.Line, task.Column, task.Line, task.Column));
+ }
+
}
public enum ErrorCategory
{
- ProcessError, ParseWarning, ParseError, ResolveError, VerificationError
+ ProcessError, ParseWarning, ParseError, ResolveError, VerificationError, AuxInformation, InternalError
}
internal class DafnyError
{
public readonly int Line; // 0 based
public readonly int Column; // 0 based
+ ITextSnapshot Snapshot; // filled in during the FillInSnapshot call
public readonly ErrorCategory Category;
public readonly string Message;
+ /// <summary>
+ /// "line" and "col" are expected to be 0-based
+ /// </summary>
public DafnyError(int line, int col, ErrorCategory cat, string msg) {
+ Contract.Requires(0 <= line);
+ Contract.Requires(0 <= col);
Line = line;
Column = col;
Category = cat;
Message = msg;
}
+
+ public void FillInSnapshot(ITextSnapshot snapshot) {
+ Contract.Requires(snapshot != null);
+ Snapshot = snapshot;
+ }
+ public SnapshotSpan Span() {
+ Contract.Requires(Snapshot != null); // requires that Snapshot has been filled in
+ var line = Snapshot.GetLineFromLineNumber(Line);
+ Contract.Assume(Column <= line.Length); // this is really a precondition of the constructor + FillInSnapshot
+ var length = Math.Min(line.Length - Column, 5);
+ return new SnapshotSpan(line.Start + Column, length);
+ }
}
}
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs b/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs
index 80976499..19f98ff7 100644
--- a/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs
+++ b/Util/VS2010/DafnyExtension/DafnyExtension/TokenTagger.cs
@@ -24,27 +24,21 @@ namespace DafnyLanguage
public enum DafnyTokenKinds
{
Keyword, Number, String, Comment,
- TypeIdentifier, VariableIdentifier
+ VariableIdentifier, VariableIdentifierDefinition
}
public class DafnyTokenTag : ITag
{
public DafnyTokenKinds Kind { get; private set; }
+ public string HoverText { get; private set; }
public DafnyTokenTag(DafnyTokenKinds kind) {
this.Kind = kind;
}
- }
- public class IdentifierDafnyTokenTag : DafnyTokenTag
- {
- public IdentifierDafnyTokenTag()
- : base(DafnyTokenKinds.VariableIdentifier) {
- }
- }
- public class TypeDafnyTokenTag : DafnyTokenTag
- {
- public TypeDafnyTokenTag()
- : base(DafnyTokenKinds.TypeIdentifier) {
+
+ public DafnyTokenTag(DafnyTokenKinds kind, string hoverText) {
+ this.Kind = kind;
+ this.HoverText = hoverText;
}
}
@@ -73,14 +67,11 @@ namespace DafnyLanguage
// create a new SnapshotSpan for the entire region encompassed by the span collection
SnapshotSpan entire = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End).TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive);
- int startLineNumber = entire.Start.GetContainingLine().LineNumber;
- int endLineNumber = entire.End.GetContainingLine().LineNumber;
// return tags for any regions that fall within that span
// BUGBUG: depending on how GetTags gets called (e.g., once for each line in the buffer), this may produce quadratic behavior
foreach (var region in currentRegions) {
if (entire.IntersectsWith(region.Span)) {
- // BUGBUG: this returns a span for currentSnapshot, but shouldn't we return spans for the spans[0].Snapshot?
yield return new TagSpan<DafnyTokenTag>(new SnapshotSpan(region.Start, region.End), new DafnyTokenTag(region.Kind));
}
}
@@ -113,10 +104,11 @@ namespace DafnyLanguage
_snapshot = snapshot;
_regions = newRegions;
- foreach (var span in difference) {
- var chng = TagsChanged;
- if (chng != null)
+ var chng = TagsChanged;
+ if (chng != null) {
+ foreach (var span in difference) {
chng(this, new SnapshotSpanEventArgs(span));
+ }
}
}
@@ -228,7 +220,7 @@ namespace DafnyLanguage
}
// we have a keyword or an identifier
string s = txt.Substring(cur, end - cur);
- if (0 < trailingDigits && s.Length == 5 + trailingDigits && s.StartsWith("array") && s[5] != '0' && s != "array1") {
+ if (0 < trailingDigits && s.Length == 5 + trailingDigits && s.StartsWith("array") && s[5] != '0' && (trailingDigits != 1 || s[5] != '1')) {
// this is a keyword (array2, array3, ...)
} else {
switch (s) {
@@ -239,6 +231,7 @@ namespace DafnyLanguage
case "assume":
case "bool":
case "break":
+ case "calc":
case "case":
case "choose":
case "class":
@@ -256,7 +249,6 @@ namespace DafnyLanguage
case "fresh":
case "function":
case "ghost":
- case "havoc":
case "if":
case "imports":
case "in":
diff --git a/Util/VS2010/DafnyExtension/DafnyExtension/source.extension.vsixmanifest b/Util/VS2010/DafnyExtension/DafnyExtension/source.extension.vsixmanifest
index 35e8f1f9..d822fbfc 100644
--- a/Util/VS2010/DafnyExtension/DafnyExtension/source.extension.vsixmanifest
+++ b/Util/VS2010/DafnyExtension/DafnyExtension/source.extension.vsixmanifest
@@ -16,5 +16,7 @@
<References />
<Content>
<MefComponent>|%CurrentProject%|</MefComponent>
+ <CustomExtension Type="Boogie">DafnyPrelude.bpl</CustomExtension>
+ <CustomExtension Type="SMTLib 2">UnivBackPred2.smt2</CustomExtension>
</Content>
</Vsix>
diff --git a/Util/latex/dafny.sty b/Util/latex/dafny.sty
index 74bfa65a..d60488d1 100644
--- a/Util/latex/dafny.sty
+++ b/Util/latex/dafny.sty
@@ -5,15 +5,15 @@
\usepackage{listings}
\lstdefinelanguage{dafny}{
- morekeywords={class,datatype,codatatype,type,bool,nat,int,object,set,multiset,seq,array,array2,array3,map%
+ morekeywords={class,datatype,codatatype,type,bool,nat,int,object,set,multiset,seq,array,array2,array3,map,%
function,predicate,copredicate,
ghost,var,static,refines,
- method,constructor,returns,module,imports,in,
+ method,constructor,returns,module,import,default,opened,as,in,
requires,modifies,ensures,reads,decreases,free,
% expressions
- match,case,false,true,null,old,fresh,allocated,choose,this,
+ match,case,false,true,null,old,fresh,choose,this,
% statements
- assert,assume,print,new,havoc,if,then,else,while,invariant,break,label,return,parallel,where
+ assert,assume,print,new,if,then,else,while,invariant,break,label,return,parallel,where,calc
},
literate=%
{:}{$\colon$}1
diff --git a/Util/vim/syntax/dafny.vim b/Util/vim/syntax/dafny.vim
index 37ec7be0..cc1c9d79 100644
--- a/Util/vim/syntax/dafny.vim
+++ b/Util/vim/syntax/dafny.vim
@@ -6,14 +6,14 @@
syntax clear
syntax case match
syntax keyword dafnyFunction function predicate copredicate method constructor
-syntax keyword dafnyTypeDef class datatype codatatype type
+syntax keyword dafnyTypeDef class datatype codatatype type module import opened as default
syntax keyword dafnyConditional if then else match case
syntax keyword dafnyRepeat while parallel
-syntax keyword dafnyStatement havoc assume assert return new print break label where
+syntax keyword dafnyStatement assume assert return new print break label where calc
syntax keyword dafnyKeyword var ghost returns null static this refines
syntax keyword dafnyType bool nat int seq set multiset object array array2 array3 map
syntax keyword dafnyLogic requires ensures modifies reads decreases invariant
-syntax keyword dafnyOperator forall exists old fresh allocated choose
+syntax keyword dafnyOperator forall exists old fresh choose
syntax keyword dafnyBoolean true false
syntax region dafnyString start=/"/ skip=/\\"/ end=/"/
diff --git a/_admin/Boogie/aste/summary.log b/_admin/Boogie/aste/summary.log
index 1613a4aa..65d20cc8 100644
--- a/_admin/Boogie/aste/summary.log
+++ b/_admin/Boogie/aste/summary.log
@@ -1,24 +1,24 @@
-# Aste started: 2012-07-10 07:00:02
+# Aste started: 2012-08-22 07:00:02
# Host id: Boogiebox
# Configuration: boogie.cfg
# Task: aste.tasks.boogie.FullBuild
-# [2012-07-10 07:01:07] SpecSharp revision: d78c1f490bc8
-# [2012-07-10 07:01:07] SscBoogie revision: d78c1f490bc8
-# [2012-07-10 07:02:08] Boogie revision: 2a3fa56ccdb4
-[2012-07-10 07:03:28] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com SpecSharp.sln /Project "Checkin Tests" /Build
+# [2012-08-22 07:01:12] SpecSharp revision: 5f64084327c6
+# [2012-08-22 07:01:12] SscBoogie revision: 5f64084327c6
+# [2012-08-22 07:02:05] Boogie revision: 693e9d4632c3
+[2012-08-22 07:03:35] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com SpecSharp.sln /Project "Checkin Tests" /Build
1>corflags : warning CF011: The specified file is strong name signed. Using /Force will invalidate the signature of this image and will require the assembly to be resigned.
warning CF011: The specified file is strong name signed. Using /Force will invalidate the signature of this image and will require the assembly to be resigned.
-[2012-07-10 07:04:57] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com Boogie.sln /Rebuild Checked
+[2012-08-22 07:05:01] C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com Boogie.sln /Rebuild Checked
D:\Temp\aste\Boogie\Source\Core\AbsyType.cs(823,16): warning CS0659: 'Microsoft.Boogie.BasicType' overrides Object.Equals(object o) but does not override Object.GetHashCode()
D:\Temp\aste\Boogie\Source\Core\AbsyType.cs(2802,16): warning CS0659: 'Microsoft.Boogie.CtorType' overrides Object.Equals(object o) but does not override Object.GetHashCode()
D:\Temp\aste\Boogie\Source\Core\OOLongUtil.cs(109,7): warning CS0162: Unreachable code detected
D:\Temp\aste\Boogie\Source\Core\Absy.cs(770,7): warning CC1036: Detected call to method 'Graphing.Graph`1<Microsoft.Boogie.Block>.TopologicalSort' without [Pure] in contracts of method 'Microsoft.Boogie.Program.GraphFromImpl(Microsoft.Boogie.Implementation)'.
EXEC : warning CC1079: Type Microsoft.Boogie.Variable implements Microsoft.AbstractInterpretationFramework.IVariable.get_Name by inheriting Microsoft.Boogie.NamedDeclaration.get_Name causing the interface contract to not be checked at runtime. Consider adding a wrapper method.
- D:\Temp\aste\Boogie\Source\Core\Parser.cs(116,3): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.Resolve(Microsoft.Boogie.ResolutionContext)' overrides 'Microsoft.Boogie.Absy.Resolve(Microsoft.Boogie.ResolutionContext)', thus cannot add Requires.
- D:\Temp\aste\Boogie\Source\Core\Parser.cs(121,5): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.Emit(Microsoft.Boogie.TokenTextWriter,System.Int32,System.Boolean)' overrides 'Microsoft.Boogie.Expr.Emit(Microsoft.Boogie.TokenTextWriter,System.Int32,System.Boolean)', thus cannot add Requires.
- D:\Temp\aste\Boogie\Source\Core\Parser.cs(124,74): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.ComputeFreeVariables(Microsoft.Boogie.GSet`1<System.Object>)' overrides 'Microsoft.Boogie.Expr.ComputeFreeVariables(Microsoft.Boogie.GSet`1<System.Object>)', thus cannot add Requires.
+ D:\Temp\aste\Boogie\Source\Core\Parser.cs(128,3): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.Resolve(Microsoft.Boogie.ResolutionContext)' overrides 'Microsoft.Boogie.Absy.Resolve(Microsoft.Boogie.ResolutionContext)', thus cannot add Requires.
+ D:\Temp\aste\Boogie\Source\Core\Parser.cs(133,5): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.Emit(Microsoft.Boogie.TokenTextWriter,System.Int32,System.Boolean)' overrides 'Microsoft.Boogie.Expr.Emit(Microsoft.Boogie.TokenTextWriter,System.Int32,System.Boolean)', thus cannot add Requires.
+ D:\Temp\aste\Boogie\Source\Core\Parser.cs(136,74): warning CC1032: Method 'Microsoft.Boogie.Parser+BvBounds.ComputeFreeVariables(Microsoft.Boogie.GSet`1<System.Object>)' overrides 'Microsoft.Boogie.Expr.ComputeFreeVariables(Microsoft.Boogie.GSet`1<System.Object>)', thus cannot add Requires.
D:\Temp\aste\Boogie\Source\AbsInt\ExprFactories.cs(247,7): warning CS0162: Unreachable code detected
D:\Temp\aste\Boogie\Source\AbsInt\ExprFactories.cs(266,7): warning CS0162: Unreachable code detected
D:\Temp\aste\Boogie\Source\AbsInt\IntervalDomain.cs(49,9): warning CC1036: Detected call to method 'Microsoft.Boogie.AbstractInterpretation.NativeIntervallDomain+Node.StrictlyBefore(Microsoft.Boogie.Variable,Microsoft.Boogie.Variable)' without [Pure] in contracts of method 'Microsoft.Boogie.AbstractInterpretation.NativeIntervallDomain+Node.#ctor(Microsoft.Boogie.Variable,System.Nullable`1<System.Numerics.BigInteger>,System.Nullable`1<System.Numerics.BigInteger>,Microsoft.Boogie.AbstractInterpretation.NativeIntervallDomain+Node)'.
@@ -41,5 +41,5 @@
warning CS0162: Unreachable code detected
warning CC1032: Method 'Microsoft.Boogie.Houdini.InlineRequiresVisitor.VisitCmdSeq(Microsoft.Boogie.CmdSeq)' overrides 'Microsoft.Boogie.StandardVisitor.VisitCmdSeq(Microsoft.Boogie.CmdSeq)', thus cannot add Requires.
warning CC1032: Method 'Microsoft.Boogie.Houdini.FreeRequiresVisitor.VisitAssertRequiresCmd(Microsoft.Boogie.AssertRequiresCmd)' overrides 'Microsoft.Boogie.StandardVisitor.VisitAssertRequiresCmd(Microsoft.Boogie.AssertRequiresCmd)', thus cannot add Requires.
-[2012-07-10 07:57:25] 0 out of 33 test(s) in D:\Temp\aste\Boogie\Test\alltests.txt failed
-# [2012-07-10 07:58:07] Released nightly of Boogie
+[2012-08-22 07:59:27] 0 out of 33 test(s) in D:\Temp\aste\Boogie\Test\alltests.txt failed
+# [2012-08-22 08:00:38] Released nightly of Boogie