From ff3465d251f498b778dd00f6d97784f3cc8c6408 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 18 Sep 2012 23:03:30 +0100 Subject: Uniformity analysis. Patch by Peter Collingbourne. --- Source/GPUVerify/CommandLineOptions.cs | 8 +- Source/GPUVerify/GPUVerifier.cs | 4409 ++++++++++---------- Source/GPUVerify/GPUVerify.csproj | 356 +- Source/GPUVerify/IRaceInstrumenter.cs | 61 +- .../LoopVariableBoundsInvariantGenerator.cs | 109 +- .../PowerOfTwoInvariantGenerator.cs | 122 +- Source/GPUVerify/KernelDualiser.cs | 43 +- Source/GPUVerify/LoopInvariantGenerator.cs | 516 +-- Source/GPUVerify/NullRaceInstrumenter.cs | 129 +- Source/GPUVerify/RaceInstrumenter.cs | 2277 +++++----- .../GPUVerify/UniformExpressionAnalysisVisitor.cs | 39 - Source/GPUVerify/UniformityAnalyser.cs | 425 -- Source/Graph/Graph.cs | 1913 ++++----- Source/VCGeneration/GraphAlgorithms.cs | 28 + Source/VCGeneration/SmartBlockPredicator.cs | 992 ++--- Source/VCGeneration/UniformityAnalyser.cs | 539 +++ Source/VCGeneration/VCGeneration.csproj | 455 +- 17 files changed, 6305 insertions(+), 6116 deletions(-) delete mode 100644 Source/GPUVerify/UniformExpressionAnalysisVisitor.cs delete mode 100644 Source/GPUVerify/UniformityAnalyser.cs create mode 100644 Source/VCGeneration/UniformityAnalyser.cs diff --git a/Source/GPUVerify/CommandLineOptions.cs b/Source/GPUVerify/CommandLineOptions.cs index 2f9ed792..5f6f0066 100644 --- a/Source/GPUVerify/CommandLineOptions.cs +++ b/Source/GPUVerify/CommandLineOptions.cs @@ -25,7 +25,7 @@ namespace GPUVerify public static bool ShowStages = false; 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; @@ -116,9 +116,9 @@ namespace GPUVerify ShowUniformityAnalysis = true; break; - case "-noUniformityAnalysis": - case "/noUniformityAnalysis": - DoUniformityAnalysis = false; + case "-uniformityAnalysis": + case "/uniformityAnalysis": + DoUniformityAnalysis = true; break; case "-showMayBePowerOfTwoAnalysis": diff --git a/Source/GPUVerify/GPUVerifier.cs b/Source/GPUVerify/GPUVerifier.cs index 26dffc0f..5afabe80 100644 --- a/Source/GPUVerify/GPUVerifier.cs +++ b/Source/GPUVerify/GPUVerifier.cs @@ -1,2201 +1,2212 @@ -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 ReservedNames = new HashSet(); - - internal HashSet OnlyThread1 = new HashSet(); - internal HashSet OnlyThread2 = new HashSet(); - - 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 varDefAnalyses; - public Dictionary 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(), 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()) - 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(); - +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 ReservedNames = new HashSet(); + + internal HashSet OnlyThread1 = new HashSet(); + internal HashSet OnlyThread2 = new HashSet(); + + 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 varDefAnalyses; + public Dictionary 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(), 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()) + 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.Inference) - { - foreach (var impl in Program.TopLevelDeclarations.OfType().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() - { - uniformityAnalyser = new UniformityAnalyser(this); - uniformityAnalyser.Analyse(); - } - - private void DoLiveVariableAnalysis() - { - liveVariableAnalyser = new LiveVariableAnalyser(this); - liveVariableAnalyser.Analyse(); - } - - private void DoVariableDefinitionAnalysis() - { - varDefAnalyses = Program.TopLevelDeclarations - .OfType() - .ToDictionary(i => i, i => VariableDefinitionAnalysis.Analyse(this, i)); - } - - private void DoReducedStrengthAnalysis() - { - reducedStrengthAnalyses = Program.TopLevelDeclarations - .OfType() - .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 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 names = new HashSet(); - 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 names = new HashSet(); - 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 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 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 GetUserSuppliedInvariants(string ProcedureName) - { - List result = new List(); - - 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(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 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 RealDecls = Program.TopLevelDeclarations; - List TempDecls = new List(); - 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(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 bigblocks = new List(); - 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(new object[] { }), null); - BarrierProcedure.Requires.Add(nonDivergenceRequires); - - if (!CommandLineOptions.OnlyDivergence) - { - List returnbigblocks = new List(); - 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 MakeResetBlocks(int Thread, ICollection variables) - { - Debug.Assert(variables.Count > 0); - List ResetAndHavocBlocks = new List(); - foreach (Variable v in variables) - { - ResetAndHavocBlocks.Add(RaceInstrumenter.MakeResetReadWriteSetStatements(v, Thread)); - } - Debug.Assert(ResetAndHavocBlocks.Count > 0); - return ResetAndHavocBlocks; - } - - private List MakeHavocBlocks(ICollection variables) { - Debug.Assert(variables.Count > 0); - List result = new List(); - 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(), 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(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(), 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 newIns = new List(); - - 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 newLhss = new List(); - newLhss.Add(lhs); - List newRhss = new List(); - 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 NewTopLevelDeclarations = new List(); - - 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); - } - 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); - } - - } - - -} + DoVariableDefinitionAnalysis(); + + DoReducedStrengthAnalysis(); + + DoMayBePowerOfTwoAnalysis(); + + DoArrayControlFlowAnalysis(); + + if (CommandLineOptions.Inference) + { + foreach (var proc in Program.TopLevelDeclarations.OfType().ToList()) + { + RaceInstrumenter.DoHoudiniPointerAnalysis(proc); + } + + foreach (var impl in Program.TopLevelDeclarations.OfType().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(); + 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() + .ToDictionary(i => i, i => VariableDefinitionAnalysis.Analyse(this, i)); + } + + private void DoReducedStrengthAnalysis() + { + reducedStrengthAnalyses = Program.TopLevelDeclarations + .OfType() + .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 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 names = new HashSet(); + 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 names = new HashSet(); + 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 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 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 GetUserSuppliedInvariants(string ProcedureName) + { + List result = new List(); + + 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(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 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 RealDecls = Program.TopLevelDeclarations; + List TempDecls = new List(); + 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(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 bigblocks = new List(); + 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(new object[] { }), null); + BarrierProcedure.Requires.Add(nonDivergenceRequires); + + if (!CommandLineOptions.OnlyDivergence) + { + List returnbigblocks = new List(); + 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 MakeResetBlocks(int Thread, ICollection variables) + { + Debug.Assert(variables.Count > 0); + List ResetAndHavocBlocks = new List(); + foreach (Variable v in variables) + { + ResetAndHavocBlocks.Add(RaceInstrumenter.MakeResetReadWriteSetStatements(v, Thread)); + } + Debug.Assert(ResetAndHavocBlocks.Count > 0); + return ResetAndHavocBlocks; + } + + private List MakeHavocBlocks(ICollection variables) { + Debug.Assert(variables.Count > 0); + List result = new List(); + 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(), 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(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(), 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 newIns = new List(); + + 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 newLhss = new List(); + newLhss.Add(lhs); + List newRhss = new List(); + 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 NewTopLevelDeclarations = new List(); + + 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 => proc != KernelProcedure, 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 08913944..e7122edf 100644 --- a/Source/GPUVerify/GPUVerify.csproj +++ b/Source/GPUVerify/GPUVerify.csproj @@ -1,180 +1,178 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {E5D16606-06D0-434F-A9D7-7D079BC80229} - Exe - Properties - GPUVerify - GPUVerifyVCGen - v4.0 - Client - 512 - 1 - - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - True - False - True - False - False - False - True - True - True - False - False - False - True - True - False - False - - - - - - - True - Full - %28none%29 - 0 - 0 - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - bin\Debug\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\GPUVerify.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - false - - - bin\Release\ - TRACE - true - pdbonly - AnyCPU - bin\Release\GPUVerify.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {39B0658D-C955-41C5-9A43-48C97A1EF5FD} - AIFramework - - - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Basetypes - - - {B230A69C-C466-4065-B9C1-84D80E76D802} - Core - - - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E} - Graph - - - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} - ParserHelper - - - {E1F10180-C7B9-4147-B51F-FA1B701966DC} - VCGeneration - - - - + + + + Debug + x86 + 8.0.30703 + 2.0 + {E5D16606-06D0-434F-A9D7-7D079BC80229} + Exe + Properties + GPUVerify + GPUVerifyVCGen + v4.0 + Client + 512 + 1 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + True + False + True + False + False + False + True + True + True + False + False + False + True + True + False + False + + + + + + + True + Full + %28none%29 + 0 + 0 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\Debug\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\GPUVerify.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + false + + + bin\Release\ + TRACE + true + pdbonly + AnyCPU + bin\Release\GPUVerify.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {39B0658D-C955-41C5-9A43-48C97A1EF5FD} + AIFramework + + + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + Basetypes + + + {B230A69C-C466-4065-B9C1-84D80E76D802} + Core + + + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E} + Graph + + + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} + ParserHelper + + + {E1F10180-C7B9-4147-B51F-FA1B701966DC} + VCGeneration + + + + \ No newline at end of file diff --git a/Source/GPUVerify/IRaceInstrumenter.cs b/Source/GPUVerify/IRaceInstrumenter.cs index 2e997fe0..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(); - - 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 AddStandardSourceVariablePreconditions(); - - void AddStandardSourceVariablePostconditions(); - } -} +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 53bee54e..201018bb 100644 --- a/Source/GPUVerify/KernelDualiser.cs +++ b/Source/GPUVerify/KernelDualiser.cs @@ -152,23 +152,36 @@ namespace GPUVerify { 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 { - foreach(var i in new int[] { 1, 2 }) { - List newLhss = assign.Lhss.Select(lhs => - new VariableDualiser(i, verifier.uniformityAnalyser, procName). - Visit(lhs.Clone() as AssignLhs) as AssignLhs).ToList(); - List newRhss = assign.Rhss.Select(rhs => - new VariableDualiser(i, verifier.uniformityAnalyser, procName). - VisitExpr(rhs.Clone() as Expr)).ToList(); - AssignCmd newAssign = new AssignCmd(assign.tok, newLhss, newRhss); - cs.Add(newAssign); + var vd1 = new VariableDualiser(1, verifier.uniformityAnalyser, procName); + var vd2 = new VariableDualiser(2, verifier.uniformityAnalyser, procName); + + List lhss1 = new List(); + List lhss2 = new List(); + + List rhss1 = new List(); + List rhss2 = new List(); + + 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)); } } + + Debug.Assert(lhss1.Count > 0); + cs.Add(new AssignCmd(Token.NoToken, lhss1, rhss1)); + + if(lhss2.Count > 0) { + cs.Add(new AssignCmd(Token.NoToken, lhss2, rhss2)); + } + } else if (c is HavocCmd) { HavocCmd havoc = c as HavocCmd; diff --git a/Source/GPUVerify/LoopInvariantGenerator.cs b/Source/GPUVerify/LoopInvariantGenerator.cs index 1c15f5e6..a465a98a 100644 --- a/Source/GPUVerify/LoopInvariantGenerator.cs +++ b/Source/GPUVerify/LoopInvariantGenerator.cs @@ -1,258 +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 invariantGenerationRules; - - LoopInvariantGenerator(GPUVerifier verifier, Implementation Impl) { - this.verifier = verifier; - this.Impl = Impl; - - invariantGenerationRules = new List(); - 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 UserSuppliedInvariants) { - new LoopInvariantGenerator(verifier, Impl).PostInstrument(UserSuppliedInvariants); - } - - internal void PostInstrument(List UserSuppliedInvariants) { - HashSet LocalVars = new HashSet(); - 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 GetAssignmentCounts(Implementation impl) { - - Dictionary result = new Dictionary(); - - foreach (var c in verifier.RootRegion(impl).Cmds()) { - if (c is AssignCmd) { - var aCmd = (AssignCmd)c; - HashSet alreadySeenInThisAssignment = new HashSet(); - 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 LocalVars, Implementation Impl, IRegion region) - { - - if (!verifier.ContainsBarrierCall(region)) - { - return; - } - - Expr guard = region.Guard(); - if (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 assignmentCounts = GetAssignmentCounts(Impl); - - HashSet alreadyConsidered = new HashSet(); - - 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 LocalVars, List 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 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 GetModifiedVariables(IRegion region) { - HashSet result = new HashSet(); - - 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 invariantGenerationRules; + + LoopInvariantGenerator(GPUVerifier verifier, Implementation Impl) { + this.verifier = verifier; + this.Impl = Impl; + + invariantGenerationRules = new List(); + 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 UserSuppliedInvariants) { + new LoopInvariantGenerator(verifier, Impl).PostInstrument(UserSuppliedInvariants); + } + + internal void PostInstrument(List UserSuppliedInvariants) { + HashSet LocalVars = new HashSet(); + 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 GetAssignmentCounts(Implementation impl) { + + Dictionary result = new Dictionary(); + + foreach (var c in verifier.RootRegion(impl).Cmds()) { + if (c is AssignCmd) { + var aCmd = (AssignCmd)c; + HashSet alreadySeenInThisAssignment = new HashSet(); + 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 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 assignmentCounts = GetAssignmentCounts(Impl); + + HashSet alreadyConsidered = new HashSet(); + + 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 LocalVars, List 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 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 GetModifiedVariables(IRegion region) { + HashSet result = new HashSet(); + + 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/NullRaceInstrumenter.cs b/Source/GPUVerify/NullRaceInstrumenter.cs index 60c28b5b..fae08aa3 100644 --- a/Source/GPUVerify/NullRaceInstrumenter.cs +++ b/Source/GPUVerify/NullRaceInstrumenter.cs @@ -1,62 +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 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 AddStandardSourceVariablePreconditions() - { - - } - - public void AddStandardSourceVariablePostconditions() - { - - } - } -} +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 1e462635..c73b9b13 100644 --- a/Source/GPUVerify/RaceInstrumenter.cs +++ b/Source/GPUVerify/RaceInstrumenter.cs @@ -1,1146 +1,1131 @@ -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> ReadAccessSourceLocations = new Dictionary>(); - - private Dictionary> WriteAccessSourceLocations = new Dictionary>(); - - public IKernelArrayInfo NonLocalStateToCheck; - - private Dictionary RaceCheckingProcedures = new Dictionary(); - - 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 offsetPredicatesRead = new List(); - List offsetPredicatesWrite = new List(); - 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(offsetPredicatesRead.Zip(CollectSourceLocPredicates(region, v, "READ"), Expr.And))); - AddOffsetsSatisfyPredicatesCandidateInvariant(region, v, "WRITE", new List(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 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(); - - 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 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(); - - 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 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 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 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 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(null, null); - } - - NAryExpr nary = expr as NAryExpr; - - if (!(nary.Fun.FunctionName.Equals("BV32_C_LT") || nary.Fun.FunctionName.Equals("BV32_LT"))) { - return new KeyValuePair(null, null); - } - - if (!(nary.Args[0] is IdentifierExpr)) { - return new KeyValuePair(null, null); - } - - if (!IsConstant(nary.Args[1])) { - return new KeyValuePair(null, null); - } - - return new KeyValuePair(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(), 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()); - } - WriteAccessSourceLocations[Key].Add(CurrStmtNo); - } - else if (Access == "READ") - { - if (!ReadAccessSourceLocations.ContainsKey(Key)) - { - ReadAccessSourceLocations.Add(Key, new List()); - } - 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); - } - - DoHoudiniPointerAnalysis(Proc); - - } - - private void DoHoudiniPointerAnalysis(Procedure Proc) { - HashSet alreadyConsidered = new HashSet(); - - 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[] { - 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 GetOffsetsAccessed(IRegion region, Variable v, string AccessType) { - HashSet result = new HashSet(); - - 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 bigblocks = new List(); - - 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(), null); - NoWriteReadRaceRequires.Attributes = new QKeyValue(Token.NoToken, "race", new List(), 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(), null); - NoWriteWriteRaceRequires.Attributes = new QKeyValue(Token.NoToken, "race", new List(), 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(), null); - NoReadWriteRaceRequires.Attributes = new QKeyValue(Token.NoToken, "race", new List(), 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 lhss = new List(); - List rhss = new List(); - 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 sourceLocExprs = new List(); - Dictionary> 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 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 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); - } - } - - - -} +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> ReadAccessSourceLocations = new Dictionary>(); + + private Dictionary> WriteAccessSourceLocations = new Dictionary>(); + + public IKernelArrayInfo NonLocalStateToCheck; + + private Dictionary RaceCheckingProcedures = new Dictionary(); + + 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 offsetPredicatesRead = new List(); + List offsetPredicatesWrite = new List(); + 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(offsetPredicatesRead.Zip(CollectSourceLocPredicates(region, v, "READ"), Expr.And))); + AddOffsetsSatisfyPredicatesCandidateInvariant(region, v, "WRITE", new List(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 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(); + + 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 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(); + + 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 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 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 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 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(null, null); + } + + NAryExpr nary = expr as NAryExpr; + + if (!(nary.Fun.FunctionName.Equals("BV32_C_LT") || nary.Fun.FunctionName.Equals("BV32_LT"))) { + return new KeyValuePair(null, null); + } + + if (!(nary.Args[0] is IdentifierExpr)) { + return new KeyValuePair(null, null); + } + + if (!IsConstant(nary.Args[1])) { + return new KeyValuePair(null, null); + } + + return new KeyValuePair(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(), 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()); + } + WriteAccessSourceLocations[Key].Add(CurrStmtNo); + } + else if (Access == "READ") + { + if (!ReadAccessSourceLocations.ContainsKey(Key)) + { + ReadAccessSourceLocations.Add(Key, new List()); + } + 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[] { + 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 GetOffsetsAccessed(IRegion region, Variable v, string AccessType) { + HashSet result = new HashSet(); + + 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 bigblocks = new List(); + + 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(), null); + NoWriteReadRaceRequires.Attributes = new QKeyValue(Token.NoToken, "race", new List(), 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(), null); + NoWriteWriteRaceRequires.Attributes = new QKeyValue(Token.NoToken, "race", new List(), 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(), null); + NoReadWriteRaceRequires.Attributes = new QKeyValue(Token.NoToken, "race", new List(), 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 lhss = new List(); + List rhss = new List(); + 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 sourceLocExprs = new List(); + Dictionary> 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 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 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/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 uniformityInfo; - - public UniformExpressionAnalysisVisitor(Dictionary 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/UniformityAnalyser.cs b/Source/GPUVerify/UniformityAnalyser.cs deleted file mode 100644 index 35f297ed..00000000 --- a/Source/GPUVerify/UniformityAnalyser.cs +++ /dev/null @@ -1,425 +0,0 @@ -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>> uniformityInfo; - - private Dictionary> nonUniformLoops; - - private Dictionary> loopsWithNonuniformReturn; - - private Dictionary> inParameters; - - private Dictionary> outParameters; - - private List loopStack; - - private bool hitNonuniformReturn; - - public UniformityAnalyser(GPUVerifier verifier) - { - this.verifier = verifier; - uniformityInfo = new Dictionary>>(); - nonUniformLoops = new Dictionary>(); - loopsWithNonuniformReturn = new Dictionary>(); - inParameters = new Dictionary>(); - outParameters = new Dictionary>(); - loopStack = new List(); - } - - internal void Analyse() - { - if (CommandLineOptions.Unstructured) - return; - - foreach (Declaration D in verifier.Program.TopLevelDeclarations) - { - if(D is Implementation) - { - bool uniformProcedure = - (D == verifier.KernelImplementation - || CommandLineOptions.DoUniformityAnalysis); - - Implementation Impl = D as Implementation; - uniformityInfo.Add(Impl.Name, new KeyValuePair> - (uniformProcedure, new Dictionary ())); - - nonUniformLoops.Add(Impl.Name, new HashSet()); - loopsWithNonuniformReturn.Add(Impl.Name, new HashSet()); - - 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(); - - 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); - } - } - - outParameters[Impl.Name] = new List(); - foreach (Variable v in Impl.OutParams) - { - outParameters[Impl.Name].Add(v.Name); - if (CommandLineOptions.DoUniformityAnalysis) - { - SetUniform(Impl.Name, v.Name); - } - else - { - 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 (Declaration D in verifier.Program.TopLevelDeclarations) - { - if (D is Implementation) - { - Implementation Impl = D as Implementation; - if (!IsUniform (Impl.Name)) - { - List newIns = new List(); - newIns.Add("_P"); - foreach (string s in inParameters[Impl.Name]) - { - newIns.Add(s); - } - inParameters[Impl.Name] = newIns; - } - } - } - - 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) - { - 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])) - { - 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); - } - } - - } - } - } - - 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> - (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)); - } - } - -} diff --git a/Source/Graph/Graph.cs b/Source/Graph/Graph.cs index 654360f4..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(IEnumerable xs) { - Contract.Ensures(Contract.Result() != 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(Dictionary> d) { - Contract.Ensures(Contract.Result() != null); - StringBuilder sb = new StringBuilder(); - sb.Append("{"); - bool first = true; - foreach (KeyValuePair> 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 { - 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 { - // 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[] postOrderNumberToNode; - private Dictionary nodeToPostOrderNumber; - private int sourceNum; // (number for) root of the graph - private Node source; // root of the graph - private Graph graph; - private Dictionary> immediateDominatorMap; - - [NotDelayed] - internal DomRelation(Graph 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> 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> 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>(); - for (int i = 1; i < localDoms.Length; i++) { // 0 slot is not used - int domineeNum = i; - int currentNodeNum = domineeNum; - List dominators = new List(); - 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> 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(IEnumerable 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(IEnumerable xs) { - Contract.Ensures(Contract.Result() != 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[n + 1]; - this.nodeToPostOrderNumber = new Dictionary(); - //HashSet visited = new HashSet(); - //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 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>(); - 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 l = new List(); - 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 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(); - var grey = new HashSet(); - var stack = new Stack(); - - 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 { - private HashSet> es; - private HashSet ns; - private Node source; - private bool reducible; - private HashSet headers; - private Dictionary> backEdgeNodes; - private Dictionary, HashSet> naturalLoops; - private HashSet splitCandidates; - - private DomRelation dominatorMap = null; - private Dictionary> predCache = new Dictionary>(); - private Dictionary> succCache = new Dictionary>(); - 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() != null); - return "#" + myHeader.ToString(); - } - } - - public Graph(HashSet> edges) { - - Contract.Requires(cce.NonNullElements(edges) && Contract.ForAll(edges, p => p.Item1 != null && p.Item2 != null)); - es = edges; - - // original A# - //ns = Set{ x : in es } + Set{ y : in es }; - - // closest Spec# - //ns = new Set{ Tuple p in edges; p.Item1 } + new Set{ Tuple p in edges; p.Item2 }; - - // - HashSet temp = new HashSet(); - foreach (Tuple 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>(); - ns = new HashSet(); - } - - // BUGBUG: Set.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{x}; - ns.Add(x); - source = x; - } - - public void AddEdge(Node/*!*/ source, Node/*!*/ dest) { - Contract.Requires(source != null); - Contract.Requires(dest != null); - //es += Set{}; - //ns += Set{source, dest}; - es.Add(new Tuple(source, dest)); - ns.Add(source); - ns.Add(dest); - predComputed = false; - } - - public HashSet Nodes { - get { - return ns; - } - } - public IEnumerable> Edges { - get { - Contract.Ensures(cce.NonNullElements(Contract.Result>>()) - && Contract.ForAll(Contract.Result>>(), 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 in es; - return es.Contains(new Tuple(x, y)); - } - - private void ComputePredSuccCaches() { - if (predComputed) - return; - predComputed = true; - predCache = new Dictionary>(); - succCache = new Dictionary>(); - - foreach (Node n in Nodes) { - predCache[n] = new HashSet(); - succCache[n] = new HashSet(); - } - - foreach (Tuple p in Edges) { - Contract.Assert(p.Item1 != null); - Contract.Assert(p.Item2 != null); - HashSet 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 Predecessors(Node n) { - // original A# - //Set result = Set{ x : x in Nodes, Edge(x,n) }; - - ComputePredSuccCaches(); - return predCache[n]; - } - - public IEnumerable Successors(Node n) { - ComputePredSuccCaches(); - return succCache[n]; - } - - public List SuccessorsAsList(Node n) { - ComputePredSuccCaches(); - List ret = new List(); - foreach (Node s in succCache[n]) - ret.Add(s); - return ret; - } - - public DomRelation /*Map>*/ DominatorMap { - get { - Contract.Assert(source != null); - if (this.dominatorMap == null) { - this.dominatorMap = new DomRelation(this, this.source); - } - return this.dominatorMap; - } - } - - public Dictionary> ImmediateDominatorMap { - get { - Contract.Assert(source != null); - if (this.dominatorMap == null) { - this.dominatorMap = new DomRelation(this, this.source); - } - return this.dominatorMap.ImmediateDominatorMap; - } - } - public List ImmediatelyDominatedBy(Node/*!*/ n) { - Contract.Requires(n != null); - List dominees; - this.ImmediateDominatorMap.TryGetValue(n, out dominees); - return dominees == null ? new List() : dominees; - } - - public IEnumerable TopologicalSort() { - bool acyclic; - List sortedList; - this.TarjanTopSort(out acyclic, out sortedList); - return acyclic ? sortedList : new List(); - } - // From Tarjan 1972 - public void TarjanTopSort(out bool acyclic, out List sortedNodes) { - int n = this.Nodes.Count; - if (n == 0) { - acyclic = true; - sortedNodes = new List(); - 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 nodeToNumber = new Dictionary(n); - Maybe[] numberToNode = new Maybe[n]; - int counter = 0; - foreach (Node node in this.Nodes) { - numberToNode[counter].Val = node; - nodeToNumber[node] = counter; - counter++; - } - foreach (Tuple e in this.Edges) { - Contract.Assert(e.Item1 != null); - Contract.Assert(e.Item2 != null); - Node/*!*/ target = e.Item2; - incomingEdges[nodeToNumber[target]]++; - } - List sorted = new List(); - 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(); - 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 OldTopologicalSort() { - Tuple> result = this.TopSort(); - return result.Item1 ? result.Item2 : (IEnumerable)new List(); - } - // From AsmL distribution example - private Tuple> TopSort() - { - List S = new List(); - HashSet V = this.Nodes; - HashSet X = new HashSet(); - 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>(false, new List()); - } - } - } - return new Tuple>(true, S); - } - - public static bool Acyclic(Graph g, Node source) { - bool acyclic; - List sortedList; - g.TarjanTopSort(out acyclic, out sortedList); - return acyclic; - } - - // [Dragon, Fig. 10.15, p. 604. Algorithm for constructing the natural loop.] - static HashSet NaturalLoop(Graph g, Tuple backEdge) - { - Contract.Requires(backEdge.Item1 != null && backEdge.Item2 != null); - Node/*!*/ n = backEdge.Item1; - Node/*!*/ d = backEdge.Item2; - Stack stack = new Stack(); - HashSet loop = new HashSet(); - 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 headers; - internal Dictionary> backEdgeNodes; - internal Dictionary, HashSet> naturalLoops; - internal HashSet splitCandidates; - [ContractInvariantMethod] - void ObjectInvariant() { - Contract.Invariant(Contract.ForAll(naturalLoops.Keys, p => p.Item1 != null && p.Item2 != null)); - } - - internal ReducibleResult(bool b, HashSet headers, Dictionary> backEdgeNodes, Dictionary, HashSet> naturalLoops, HashSet 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 g, Node source) { - // first, compute the dom relation - DomRelation /*Map>*/ D = g.DominatorMap; - return ComputeReducible(g, source, D); - } - - static HashSet FindCycle(Graph g, Node source) { - Stack>> stack = new Stack>>(); - HashSet stackAsSet = new HashSet(); - HashSet visited = new HashSet(); - stack.Push(new Tuple>(source, g.SuccessorsAsList(source))); - stackAsSet.Add(source); - while (stack.Count > 0) { - Tuple> tuple = stack.Peek(); - List 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 ret = new HashSet(); - 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>(n, g.SuccessorsAsList(n))); - visited.Add(n); - stackAsSet.Add(n); - System.Diagnostics.Debug.Assert(stack.Count == stackAsSet.Count); - } - return new HashSet(); - } - - // [Dragon, p. 606] - static ReducibleResult ComputeReducible(Graph g, - Node source, - DomRelation/*!*/ DomRelation) { - Contract.Requires(DomRelation != null); - - //Console.WriteLine("[" + DateTime.Now +"]: begin ComputeReducible"); - IEnumerable> edges = g.Edges; - Contract.Assert(Contract.ForAll(edges, n => n.Item1 != null && n.Item2 != null)); - HashSet> backEdges = new HashSet>(); - HashSet> nonBackEdges = new HashSet>(); - foreach (Tuple 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 withoutBackEdges = new Graph(nonBackEdges); - if (!Acyclic(withoutBackEdges, source)) { - return new ReducibleResult(false, - new HashSet(), - new Dictionary>(), - new Dictionary, HashSet>(), - FindCycle(withoutBackEdges, source)); - } else { - // original A#: - //Set headers = Set{ d : in backEdges }; - HashSet headers = new HashSet(); - foreach (Tuple e in backEdges) { - - Contract.Assert(e.Item1 != null); - Contract.Assert(e.Item2 != null); - headers.Add(e.Item2); - } - // original A#: - //Map> backEdgeNodes = Map{ h -> bs : h in headers, bs = Set{ b : in backEdges, x == h } }; - Dictionary> backEdgeNodes = new Dictionary>(); - foreach (Node/*!*/ h in headers) { - Contract.Assert(h != null); - HashSet bs = new HashSet(); - foreach (Tuple 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,Set> naturalLoops = Map{ e -> NaturalLoop(g,e) : e in backEdges }; - Dictionary, HashSet> naturalLoops = new Dictionary, HashSet>(); - foreach (Tuple 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()); - } - } - - public bool Reducible { - get { - return reducible; - } - } - public IEnumerable Headers { - get { - return headers; - } - } - public IEnumerable BackEdgeNodes(Node/*!*/ h) { - Contract.Requires(h != null); - // original A#: - //return h in backEdgeNodes ? backEdgeNodes[h] : null; - return (backEdgeNodes.ContainsKey(h) ? backEdgeNodes[h] : (IEnumerable)new List()); - } - public IEnumerable NaturalLoops(Node/*!*/ header, Node/*!*/ backEdgeNode) { - Contract.Requires(header != null); - Contract.Requires(backEdgeNode != null); - Tuple e = new Tuple(backEdgeNode, header); - return naturalLoops.ContainsKey(e) ? naturalLoops[e] : (IEnumerable)new List(); - } - public HashSet 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 SortHeadersByDominance() - { - Graph dag = new Graph(); - 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 NodeLabel = null, Func 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/*!*/ source, params Tuple[] edges) { - Contract.Requires(source != null); - Contract.Requires(Contract.ForAll(edges, pair => pair.Item1 != null && pair.Item2 != null)); - HashSet> es = new HashSet>(); - foreach (Tuple e in edges) { - Contract.Assert(e.Item1 != null && e.Item2 != null); - es.Add(e); - } - Graph g = new Graph(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 g = new Graph(new Set>{ new Tuple(1,2), new Tuple(1,3), new Tuple(2,3) }); - - Console.WriteLine(""); - TestGraph('a', - new Tuple('a', 'b'), - new Tuple('a', 'c'), - new Tuple('b', 'c') - ); - - Console.WriteLine(""); - TestGraph('a', - new Tuple('a', 'b'), - new Tuple('a', 'c'), - new Tuple('b', 'd'), - new Tuple('c', 'e'), - new Tuple('c', 'f'), - new Tuple('d', 'e'), - new Tuple('e', 'd'), - new Tuple('e', 'f'), - new Tuple('f', 'e') - ); - - Console.WriteLine(""); - TestGraph('a', - new Tuple('a', 'b'), - new Tuple('a', 'c'), - new Tuple('b', 'c'), - new Tuple('c', 'b') - ); - - Console.WriteLine(""); - TestGraph(1, - new Tuple(1, 2), - new Tuple(1, 3), - new Tuple(2, 3) - ); - - Console.WriteLine(""); - TestGraph(1, - new Tuple(1, 2), - new Tuple(1, 3), - new Tuple(2, 3), - new Tuple(3, 2) - ); - - Console.WriteLine(""); - TestGraph(2, - new Tuple(2, 3), - new Tuple(2, 4), - new Tuple(3, 2) - ); - - Console.WriteLine(""); - TestGraph('a', - new Tuple('a', 'b'), - new Tuple('a', 'c'), - new Tuple('b', 'c'), - new Tuple('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(IEnumerable xs) { + Contract.Ensures(Contract.Result() != 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(Dictionary> d) { + Contract.Ensures(Contract.Result() != null); + StringBuilder sb = new StringBuilder(); + sb.Append("{"); + bool first = true; + foreach (KeyValuePair> 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 { + 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 { + // 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[] postOrderNumberToNode; + private Dictionary nodeToPostOrderNumber; + private int sourceNum; // (number for) root of the graph + private Node source; // root of the graph + private Graph graph; + private Dictionary> immediateDominatorMap; + + [NotDelayed] + internal DomRelation(Graph 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> ImmediateDominatorMap { + get { + Contract.Assume(this.immediateDominatorMap != null); + return this.immediateDominatorMap; + } + } + public bool DominatedBy(Node dominee, Node dominator, List 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> 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>(); + for (int i = 1; i < localDoms.Length; i++) { // 0 slot is not used + int domineeNum = i; + int currentNodeNum = domineeNum; + List dominators = new List(); + 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> 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(IEnumerable 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(IEnumerable xs) { + Contract.Ensures(Contract.Result() != 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[n + 1]; + this.nodeToPostOrderNumber = new Dictionary(); + //HashSet visited = new HashSet(); + //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 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>(); + 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 l = new List(); + 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 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(); + var grey = new HashSet(); + var stack = new Stack(); + + 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 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 { + private HashSet> es; + private HashSet ns; + private Node source; + private bool reducible; + private HashSet headers; + private Dictionary> backEdgeNodes; + private Dictionary, HashSet> naturalLoops; + private HashSet splitCandidates; + + private DomRelation dominatorMap = null; + private Dictionary> predCache = new Dictionary>(); + private Dictionary> succCache = new Dictionary>(); + 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() != null); + return "#" + myHeader.ToString(); + } + } + + public Graph(HashSet> edges) { + + Contract.Requires(cce.NonNullElements(edges) && Contract.ForAll(edges, p => p.Item1 != null && p.Item2 != null)); + es = edges; + + // original A# + //ns = Set{ x : in es } + Set{ y : in es }; + + // closest Spec# + //ns = new Set{ Tuple p in edges; p.Item1 } + new Set{ Tuple p in edges; p.Item2 }; + + // + HashSet temp = new HashSet(); + foreach (Tuple 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>(); + ns = new HashSet(); + } + + // BUGBUG: Set.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{x}; + ns.Add(x); + source = x; + } + + public void AddEdge(Node/*!*/ source, Node/*!*/ dest) { + Contract.Requires(source != null); + Contract.Requires(dest != null); + //es += Set{}; + //ns += Set{source, dest}; + es.Add(new Tuple(source, dest)); + ns.Add(source); + ns.Add(dest); + predComputed = false; + } + + public HashSet Nodes { + get { + return ns; + } + } + public IEnumerable> Edges { + get { + Contract.Ensures(cce.NonNullElements(Contract.Result>>()) + && Contract.ForAll(Contract.Result>>(), 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 in es; + return es.Contains(new Tuple(x, y)); + } + + private void ComputePredSuccCaches() { + if (predComputed) + return; + predComputed = true; + predCache = new Dictionary>(); + succCache = new Dictionary>(); + + foreach (Node n in Nodes) { + predCache[n] = new HashSet(); + succCache[n] = new HashSet(); + } + + foreach (Tuple p in Edges) { + Contract.Assert(p.Item1 != null); + Contract.Assert(p.Item2 != null); + HashSet 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 Predecessors(Node n) { + // original A# + //Set result = Set{ x : x in Nodes, Edge(x,n) }; + + ComputePredSuccCaches(); + return predCache[n]; + } + + public IEnumerable Successors(Node n) { + ComputePredSuccCaches(); + return succCache[n]; + } + + public List SuccessorsAsList(Node n) { + ComputePredSuccCaches(); + List ret = new List(); + foreach (Node s in succCache[n]) + ret.Add(s); + return ret; + } + + public DomRelation /*Map>*/ DominatorMap { + get { + Contract.Assert(source != null); + if (this.dominatorMap == null) { + this.dominatorMap = new DomRelation(this, this.source); + } + return this.dominatorMap; + } + } + + public Dictionary> ImmediateDominatorMap { + get { + Contract.Assert(source != null); + if (this.dominatorMap == null) { + this.dominatorMap = new DomRelation(this, this.source); + } + return this.dominatorMap.ImmediateDominatorMap; + } + } + public List ImmediatelyDominatedBy(Node/*!*/ n) { + Contract.Requires(n != null); + List dominees; + this.ImmediateDominatorMap.TryGetValue(n, out dominees); + return dominees == null ? new List() : dominees; + } + + public IEnumerable TopologicalSort() { + bool acyclic; + List sortedList; + this.TarjanTopSort(out acyclic, out sortedList); + return acyclic ? sortedList : new List(); + } + // From Tarjan 1972 + public void TarjanTopSort(out bool acyclic, out List sortedNodes) { + int n = this.Nodes.Count; + if (n == 0) { + acyclic = true; + sortedNodes = new List(); + 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 nodeToNumber = new Dictionary(n); + Maybe[] numberToNode = new Maybe[n]; + int counter = 0; + foreach (Node node in this.Nodes) { + numberToNode[counter].Val = node; + nodeToNumber[node] = counter; + counter++; + } + foreach (Tuple e in this.Edges) { + Contract.Assert(e.Item1 != null); + Contract.Assert(e.Item2 != null); + Node/*!*/ target = e.Item2; + incomingEdges[nodeToNumber[target]]++; + } + List sorted = new List(); + 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(); + 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 OldTopologicalSort() { + Tuple> result = this.TopSort(); + return result.Item1 ? result.Item2 : (IEnumerable)new List(); + } + // From AsmL distribution example + private Tuple> TopSort() + { + List S = new List(); + HashSet V = this.Nodes; + HashSet X = new HashSet(); + 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>(false, new List()); + } + } + } + return new Tuple>(true, S); + } + + public static bool Acyclic(Graph g, Node source) { + bool acyclic; + List sortedList; + g.TarjanTopSort(out acyclic, out sortedList); + return acyclic; + } + + // [Dragon, Fig. 10.15, p. 604. Algorithm for constructing the natural loop.] + static HashSet NaturalLoop(Graph g, Tuple backEdge) + { + Contract.Requires(backEdge.Item1 != null && backEdge.Item2 != null); + Node/*!*/ n = backEdge.Item1; + Node/*!*/ d = backEdge.Item2; + Stack stack = new Stack(); + HashSet loop = new HashSet(); + 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 headers; + internal Dictionary> backEdgeNodes; + internal Dictionary, HashSet> naturalLoops; + internal HashSet splitCandidates; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Contract.ForAll(naturalLoops.Keys, p => p.Item1 != null && p.Item2 != null)); + } + + internal ReducibleResult(bool b, HashSet headers, Dictionary> backEdgeNodes, Dictionary, HashSet> naturalLoops, HashSet 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 g, Node source) { + // first, compute the dom relation + DomRelation /*Map>*/ D = g.DominatorMap; + return ComputeReducible(g, source, D); + } + + static HashSet FindCycle(Graph g, Node source) { + Stack>> stack = new Stack>>(); + HashSet stackAsSet = new HashSet(); + HashSet visited = new HashSet(); + stack.Push(new Tuple>(source, g.SuccessorsAsList(source))); + stackAsSet.Add(source); + while (stack.Count > 0) { + Tuple> tuple = stack.Peek(); + List 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 ret = new HashSet(); + 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>(n, g.SuccessorsAsList(n))); + visited.Add(n); + stackAsSet.Add(n); + System.Diagnostics.Debug.Assert(stack.Count == stackAsSet.Count); + } + return new HashSet(); + } + + // [Dragon, p. 606] + static ReducibleResult ComputeReducible(Graph g, + Node source, + DomRelation/*!*/ DomRelation) { + Contract.Requires(DomRelation != null); + + //Console.WriteLine("[" + DateTime.Now +"]: begin ComputeReducible"); + IEnumerable> edges = g.Edges; + Contract.Assert(Contract.ForAll(edges, n => n.Item1 != null && n.Item2 != null)); + HashSet> backEdges = new HashSet>(); + HashSet> nonBackEdges = new HashSet>(); + foreach (Tuple 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 withoutBackEdges = new Graph(nonBackEdges); + if (!Acyclic(withoutBackEdges, source)) { + return new ReducibleResult(false, + new HashSet(), + new Dictionary>(), + new Dictionary, HashSet>(), + FindCycle(withoutBackEdges, source)); + } else { + // original A#: + //Set headers = Set{ d : in backEdges }; + HashSet headers = new HashSet(); + foreach (Tuple e in backEdges) { + + Contract.Assert(e.Item1 != null); + Contract.Assert(e.Item2 != null); + headers.Add(e.Item2); + } + // original A#: + //Map> backEdgeNodes = Map{ h -> bs : h in headers, bs = Set{ b : in backEdges, x == h } }; + Dictionary> backEdgeNodes = new Dictionary>(); + foreach (Node/*!*/ h in headers) { + Contract.Assert(h != null); + HashSet bs = new HashSet(); + foreach (Tuple 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,Set> naturalLoops = Map{ e -> NaturalLoop(g,e) : e in backEdges }; + Dictionary, HashSet> naturalLoops = new Dictionary, HashSet>(); + foreach (Tuple 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()); + } + } + + public bool Reducible { + get { + return reducible; + } + } + public IEnumerable Headers { + get { + return headers; + } + } + public IEnumerable BackEdgeNodes(Node/*!*/ h) { + Contract.Requires(h != null); + // original A#: + //return h in backEdgeNodes ? backEdgeNodes[h] : null; + return (backEdgeNodes.ContainsKey(h) ? backEdgeNodes[h] : (IEnumerable)new List()); + } + public IEnumerable NaturalLoops(Node/*!*/ header, Node/*!*/ backEdgeNode) { + Contract.Requires(header != null); + Contract.Requires(backEdgeNode != null); + Tuple e = new Tuple(backEdgeNode, header); + return naturalLoops.ContainsKey(e) ? naturalLoops[e] : (IEnumerable)new List(); + } + public HashSet 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 SortHeadersByDominance() + { + Graph dag = new Graph(); + 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 NodeLabel = null, Func 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/*!*/ source, params Tuple[] edges) { + Contract.Requires(source != null); + Contract.Requires(Contract.ForAll(edges, pair => pair.Item1 != null && pair.Item2 != null)); + HashSet> es = new HashSet>(); + foreach (Tuple e in edges) { + Contract.Assert(e.Item1 != null && e.Item2 != null); + es.Add(e); + } + Graph g = new Graph(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 g = new Graph(new Set>{ new Tuple(1,2), new Tuple(1,3), new Tuple(2,3) }); + + Console.WriteLine(""); + TestGraph('a', + new Tuple('a', 'b'), + new Tuple('a', 'c'), + new Tuple('b', 'c') + ); + + Console.WriteLine(""); + TestGraph('a', + new Tuple('a', 'b'), + new Tuple('a', 'c'), + new Tuple('b', 'd'), + new Tuple('c', 'e'), + new Tuple('c', 'f'), + new Tuple('d', 'e'), + new Tuple('e', 'd'), + new Tuple('e', 'f'), + new Tuple('f', 'e') + ); + + Console.WriteLine(""); + TestGraph('a', + new Tuple('a', 'b'), + new Tuple('a', 'c'), + new Tuple('b', 'c'), + new Tuple('c', 'b') + ); + + Console.WriteLine(""); + TestGraph(1, + new Tuple(1, 2), + new Tuple(1, 3), + new Tuple(2, 3) + ); + + Console.WriteLine(""); + TestGraph(1, + new Tuple(1, 2), + new Tuple(1, 3), + new Tuple(2, 3), + new Tuple(3, 2) + ); + + Console.WriteLine(""); + TestGraph(2, + new Tuple(2, 3), + new Tuple(2, 4), + new Tuple(3, 2) + ); + + Console.WriteLine(""); + TestGraph('a', + new Tuple('a', 'b'), + new Tuple('a', 'c'), + new Tuple('b', 'c'), + new Tuple('b', 'b') + ); + + + } + } + +} diff --git a/Source/VCGeneration/GraphAlgorithms.cs b/Source/VCGeneration/GraphAlgorithms.cs index 1a8ab9b1..006a923f 100644 --- a/Source/VCGeneration/GraphAlgorithms.cs +++ b/Source/VCGeneration/GraphAlgorithms.cs @@ -93,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> ControlDependence(this Graph g) where Node : class, new() { + Graph dual = g.Dual(new Node()); + DomRelation pdom = dual.DominatorMap; + var result = new Dictionary>(); + + 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(); + 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(deps); + } + } + return result; + } } diff --git a/Source/VCGeneration/SmartBlockPredicator.cs b/Source/VCGeneration/SmartBlockPredicator.cs index f769822c..9dada1a5 100644 --- a/Source/VCGeneration/SmartBlockPredicator.cs +++ b/Source/VCGeneration/SmartBlockPredicator.cs @@ -1,469 +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 blockGraph; - List> sortedBlocks; - - bool useProcedurePredicates = true; - - Dictionary predMap, defMap; - Dictionary> ownedMap; - Dictionary parentMap; - Dictionary partInfo; - - IdentifierExpr fp; - Dictionary havocVars = - new Dictionary(); - Dictionary blockIds = new Dictionary(); - HashSet doneBlocks = new HashSet(); - - SmartBlockPredicator(Program p, Implementation i, bool upp) { - prog = p; - impl = i; - useProcedurePredicates = upp; - } - - void PredicateCmd(Expr p, List blocks, Block block, Cmd cmd, out Block nextBlock) { - if (!useProcedurePredicates && cmd is CallCmd) { - 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 (p == null) { - cmdSeq.Add(cmd); - return; - } - - if (cmd is AssignCmd) { - var aCmd = (AssignCmd)cmd; - cmdSeq.Add(new AssignCmd(Token.NoToken, aCmd.Lhss, - new List(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 CallCmd) { - Debug.Assert(useProcedurePredicates); - var cCmd = (CallCmd)cmd; - cCmd.Ins.Insert(0, p); - cmdSeq.Add(cCmd); - } - 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()); - } - } - - void PredicateTransferCmd(Expr p, Block src, CmdSeq cmdSeq, TransferCmd cmd) { - if (cmd is GotoCmd) { - var gCmd = (GotoCmd)cmd; - 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().All(t => partInfo.ContainsKey(t))); - foreach (Block target in gCmd.labelTargets) { - 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>(); - foreach (Block exit in LoopsExited(src, target)) { - List predList; - if (!predsExitingLoop.ContainsKey(exit)) - predList = predsExitingLoop[exit] = new List(); - 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 blockGraph, - DomRelation dom, - DomRelation pdom, - IEnumerator> i, - Variable headPredicate, - ref int predCount) { - var header = i.Current.Item1; - var regionPreds = new List>(); - var ownedPreds = new HashSet(); - ownedMap[header] = ownedPreds; - - predMap[header] = headPredicate; - defMap[header] = headPredicate; - regionPreds.Add(new Tuple(header, headPredicate)); - - while (i.MoveNext()) { - var block = i.Current; - 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.Item1, condPred)); - } - } - } - } - } - - void AssignPredicates() { - DomRelation dom = blockGraph.DominatorMap; - - Graph dualGraph = blockGraph.Dual(new Block()); - DomRelation pdom = dualGraph.DominatorMap; - - var iter = sortedBlocks.GetEnumerator(); - if (!iter.MoveNext()) { - predMap = defMap = null; - ownedMap = null; - return; - } - - int predCount = 0; - predMap = new Dictionary(); - defMap = new Dictionary(); - ownedMap = new Dictionary>(); - parentMap = new Dictionary(); - AssignPredicates(blockGraph, dom, pdom, iter, - useProcedurePredicates ? impl.InParams[0] : null, - ref predCount); - } - - IEnumerable 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 LoopsExitedBackEdge(Block src, IEnumerator> i) { - var headsSeen = new HashSet(); - 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 LoopsExitedForwardEdge(Block dest, IEnumerator> i) { - var headsSeen = new HashSet(); - 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 BuildPartitionInfo() { - var partInfo = new Dictionary(); - foreach (var block in blockGraph.Nodes) { - var parts = block.Cmds.Cast().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().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 (useProcedurePredicates) - fp = Expr.Ident(impl.InParams[0]); - - var newBlocks = new List(); - Block prevBlock = null; - foreach (var n in sortedBlocks) { - 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(), 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 { - var runBlock = n.Item1; - var oldCmdSeq = runBlock.Cmds; - runBlock.Cmds = new CmdSeq(); - newBlocks.Add(runBlock); - if (prevBlock != null) - prevBlock.TransferCmd = new GotoCmd(Token.NoToken, - new BlockSeq(runBlock)); - - if (parentMap.ContainsKey(runBlock)) { - var parent = parentMap[runBlock]; - if (predMap.ContainsKey(parent)) { - var parentPred = predMap[parent]; - if (parentPred != null) { - runBlock.Cmds.Add(new AssertCmd(Token.NoToken, - Expr.Imp(pExpr, Expr.Ident(parentPred)))); - } - } - } - - var transferCmd = runBlock.TransferCmd; - foreach (Cmd cmd in oldCmdSeq) - PredicateCmd(pExpr, newBlocks, runBlock, cmd, out runBlock); - - if (ownedMap.ContainsKey(n.Item1)) { - var owned = ownedMap[n.Item1]; - foreach (var v in owned) - runBlock.Cmds.Add(Cmd.SimpleAssign(Token.NoToken, Expr.Ident(v), Expr.False)); - } - - PredicateTransferCmd(pExpr, runBlock, runBlock.Cmds, transferCmd); - - prevBlock = runBlock; - doneBlocks.Add(runBlock); - } - } - - prevBlock.TransferCmd = new ReturnCmd(Token.NoToken); - impl.Blocks = newBlocks; - } - - private Expr CreateIfFPThenElse(Expr then, Expr eElse) { - if (useProcedurePredicates) { - return new NAryExpr(Token.NoToken, - new IfThenElse(Token.NoToken), - new ExprSeq(fp, then, eElse)); - } else { - return then; - } - } - - public static void Predicate(Program p, - bool useProcedurePredicates = true) { - foreach (var decl in p.TopLevelDeclarations.ToList()) { - if (useProcedurePredicates && decl is DeclWithFormals && !(decl is Function)) { - 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())) - .ToArray()); - - if (dwf is Procedure) - { - var proc = (Procedure)dwf; - 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))); - } - } - - } - - try { - var impl = decl as Implementation; - if (impl != null) - new SmartBlockPredicator(p, impl, useProcedurePredicates).PredicateImplementation(); - } - catch (Program.IrreducibleLoopException) { } - } - } - - public static void Predicate(Program p, Implementation impl) { - try { - new SmartBlockPredicator(p, impl, false).PredicateImplementation(); - } - catch (Program.IrreducibleLoopException) { } - } - -} - -} +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 blockGraph; + List> sortedBlocks; + + Func useProcedurePredicates; + + Dictionary predMap, defMap; + Dictionary> ownedMap; + Dictionary parentMap; + Dictionary partInfo; + + IdentifierExpr fp; + Dictionary havocVars = + new Dictionary(); + Dictionary blockIds = new Dictionary(); + HashSet doneBlocks = new HashSet(); + bool myUseProcedurePredicates; + UniformityAnalyser uni; + + SmartBlockPredicator(Program p, Implementation i, Func upp, UniformityAnalyser u) { + prog = p; + impl = i; + useProcedurePredicates = upp; + myUseProcedurePredicates = useProcedurePredicates(i.Proc); + uni = u; + } + + void PredicateCmd(Expr p, List 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(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().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().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>(); + foreach (Block exit in LoopsExited(src, target)) { + List predList; + if (!predsExitingLoop.ContainsKey(exit)) + predList = predsExitingLoop[exit] = new List(); + 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 blockGraph, + DomRelation dom, + DomRelation pdom, + IEnumerator> i, + Variable headPredicate, + ref int predCount) { + var header = i.Current.Item1; + var regionPreds = new List>(); + var ownedPreds = new HashSet(); + ownedMap[header] = ownedPreds; + + if (headPredicate != null) { + predMap[header] = headPredicate; + defMap[header] = headPredicate; + regionPreds.Add(new Tuple(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.Item1, condPred)); + } + } + } + } + } + + void AssignPredicates() { + DomRelation dom = blockGraph.DominatorMap; + + Graph dualGraph = blockGraph.Dual(new Block()); + DomRelation pdom = dualGraph.DominatorMap; + + var iter = sortedBlocks.GetEnumerator(); + if (!iter.MoveNext()) { + predMap = defMap = null; + ownedMap = null; + return; + } + + int predCount = 0; + predMap = new Dictionary(); + defMap = new Dictionary(); + ownedMap = new Dictionary>(); + parentMap = new Dictionary(); + AssignPredicates(blockGraph, dom, pdom, iter, + myUseProcedurePredicates ? impl.InParams[0] : null, + ref predCount); + } + + IEnumerable 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 LoopsExitedBackEdge(Block src, IEnumerator> i) { + var headsSeen = new HashSet(); + 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 LoopsExitedForwardEdge(Block dest, IEnumerator> i) { + var headsSeen = new HashSet(); + 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 BuildPartitionInfo() { + var partInfo = new Dictionary(); + foreach (var block in blockGraph.Nodes) { + if (uni.IsUniform(impl.Name, block)) + continue; + + var parts = block.Cmds.Cast().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().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 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(), 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 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 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())) + .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/VCGeneration/UniformityAnalyser.cs b/Source/VCGeneration/UniformityAnalyser.cs new file mode 100644 index 00000000..e5647a21 --- /dev/null +++ b/Source/VCGeneration/UniformityAnalyser.cs @@ -0,0 +1,539 @@ +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 entryPoints; + + private IEnumerable nonUniformVars; + + private bool ProcedureChanged; + + private Dictionary>> uniformityInfo; + + private Dictionary> nonUniformLoops; + + private Dictionary> nonUniformBlocks; + + private Dictionary> loopsWithNonuniformReturn; + + private Dictionary> inParameters; + + private Dictionary> outParameters; + + private List loopStack; + + private bool hitNonuniformReturn; + + public UniformityAnalyser(Program prog, bool doAnalysis, bool unstructured, ISet entryPoints, IEnumerable nonUniformVars) + { + this.prog = prog; + this.doAnalysis = doAnalysis; + this.unstructured = unstructured; + this.entryPoints = entryPoints; + this.nonUniformVars = nonUniformVars; + uniformityInfo = new Dictionary>>(); + nonUniformLoops = new Dictionary>(); + nonUniformBlocks = new Dictionary>(); + loopsWithNonuniformReturn = new Dictionary>(); + inParameters = new Dictionary>(); + outParameters = new Dictionary>(); + loopStack = new List(); + } + + public void Analyse() + { + var impls = prog.TopLevelDeclarations.OfType(); + + foreach (var Impl in impls) + { + bool uniformProcedure = doAnalysis || entryPoints.Contains(Impl); + + uniformityInfo.Add(Impl.Name, new KeyValuePair> + (uniformProcedure, new Dictionary ())); + + nonUniformLoops.Add(Impl.Name, new HashSet()); + loopsWithNonuniformReturn.Add(Impl.Name, new HashSet()); + + 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(); + + 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(); + 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) + { + 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 newIns = new List(); + 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(Impl.Blocks); + + foreach (Variable v in Impl.LocVars) { + if (IsUniform(Impl.Name, v.Name)) { + SetNonUniform(Impl.Name, v.Name); + } + } + + foreach (Variable v in Impl.InParams) { + if (IsUniform(Impl.Name, v.Name)) { + SetNonUniform(Impl.Name, v.Name); + } + } + + foreach (Variable v in Impl.OutParams) { + if (IsUniform(Impl.Name, v.Name)) { + SetNonUniform(Impl.Name, v.Name); + } + } + + return; + } + + Graph 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(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(); + 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]); + } + } + } 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)) + { + + 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(impl.Name, lhs.AssignedVariable.Name); + } + + } + } + } + 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> + (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 uniformityInfo; + + public UniformExpressionAnalysisVisitor(Dictionary 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/VCGeneration.csproj b/Source/VCGeneration/VCGeneration.csproj index 780e4891..fe7ddc70 100644 --- a/Source/VCGeneration/VCGeneration.csproj +++ b/Source/VCGeneration/VCGeneration.csproj @@ -1,227 +1,228 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {E1F10180-C7B9-4147-B51F-FA1B701966DC} - Library - Properties - VCGeneration - VCGeneration - v4.0 - 512 - 1 - true - ..\InterimKey.snk - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - False - False - True - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - - - - - - - Full - %28none%29 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\z3apidebug\ - DEBUG;TRACE - full - AnyCPU - - - true - GlobalSuppressions.cs - prompt - Migrated rules for VCGeneration.ruleset - true - - - true - bin\Checked\ - DEBUG;TRACE - full - AnyCPU - bin\Debug\VCGeneration.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - True - False - True - False - False - False - False - False - False - False - False - False - True - False - False - False - - - - - - - False - Full - Build - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - {39B0658D-C955-41C5-9A43-48C97A1EF5FD} - AIFramework - - - {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} - Basetypes - - - {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} - CodeContractsExtender - - - {B230A69C-C466-4065-B9C1-84D80E76D802} - Core - - - {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E} - Graph - - - {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83} - Model - - - {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} - ParserHelper - - - {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1} - VCExpr - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {E1F10180-C7B9-4147-B51F-FA1B701966DC} + Library + Properties + VCGeneration + VCGeneration + v4.0 + 512 + 1 + true + ..\InterimKey.snk + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + False + False + True + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + + + + + + + Full + %28none%29 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\z3apidebug\ + DEBUG;TRACE + full + AnyCPU + + + true + GlobalSuppressions.cs + prompt + Migrated rules for VCGeneration.ruleset + true + + + true + bin\Checked\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\VCGeneration.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + True + False + True + False + False + False + False + False + False + False + False + False + True + False + False + False + + + + + + + False + Full + Build + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {39B0658D-C955-41C5-9A43-48C97A1EF5FD} + AIFramework + + + {43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0} + Basetypes + + + {ACCC0156-0921-43ED-8F67-AD8BDC8CDE31} + CodeContractsExtender + + + {B230A69C-C466-4065-B9C1-84D80E76D802} + Core + + + {69A2B0B8-BCAC-4101-AE7A-556FCC58C06E} + Graph + + + {ACEF88D5-DADD-46DA-BAE1-2144D63F4C83} + Model + + + {FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5} + ParserHelper + + + {56FFDBCA-7D14-43B8-A6CA-22A20E417EE1} + VCExpr + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file -- cgit v1.2.3