From 01eeacd436643afced5b864592bc88243861a84d Mon Sep 17 00:00:00 2001 From: Egor Kyshtymov Date: Sun, 16 Sep 2012 09:59:58 +0100 Subject: Added creation of source variable pre- and post- conditions. Changed style of error messages. Cleaned up error reporting code. --- Source/GPUVerify/RaceInstrumenter.cs | 142 +++++++++++++++++++++++++++++------ 1 file changed, 120 insertions(+), 22 deletions(-) (limited to 'Source/GPUVerify/RaceInstrumenter.cs') diff --git a/Source/GPUVerify/RaceInstrumenter.cs b/Source/GPUVerify/RaceInstrumenter.cs index 1ec8f7ec..35e7da4b 100644 --- a/Source/GPUVerify/RaceInstrumenter.cs +++ b/Source/GPUVerify/RaceInstrumenter.cs @@ -78,12 +78,18 @@ namespace GPUVerify { } 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"); - AddOffsetsSatisfyPredicatesCandidateInvariant(region, v, "READ", CollectOffsetPredicates(impl, region, v, "READ")); - AddOffsetsSatisfyPredicatesCandidateInvariant(region, v, "WRITE", CollectOffsetPredicates(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))); } } @@ -98,6 +104,22 @@ namespace GPUVerify { 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); @@ -879,44 +901,120 @@ namespace GPUVerify { } } + 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, Expr.Imp(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateAccessHasOccurredVariable(name, AccessType)), - Expr.False)); + return new AssertCmd(Token.NoToken, BuildAccessOccurredFalseExpr(name, AccessType)); } - private AssertCmd BuildNoAccessInvariant(string name, string AccessType) + private Expr BuildNoAccessExpr(string name, string AccessType) { - return new AssertCmd(Token.NoToken, Expr.Imp(Expr.Not(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateAccessHasOccurredVariable(name, 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)))); + 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, - Expr.Imp(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateAccessHasOccurredVariable(name, AccessType)), - BuildDisjunctionFromAccessSourceLocations(name, AccessType))); + return new AssertCmd(Token.NoToken, BuildPossibleSourceLocationsExpr(name, AccessType)); } private Expr BuildDisjunctionFromAccessSourceLocations(string key, string AccessType) { - Expr disj = Expr.False; + List sourceLocExprs = new List(); Dictionary> AccessSourceLocations = (AccessType.Equals("WRITE")) ? WriteAccessSourceLocations : ReadAccessSourceLocations; foreach (int loc in AccessSourceLocations[key]) { - if (disj.Equals(Expr.False)) - { - disj = Expr.Eq(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateSourceVariable(key, AccessType)), - new LiteralExpr(Token.NoToken, BigNum.FromInt(loc), 32)); - } - else - { - disj = Expr.Or(disj, Expr.Eq(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateSourceVariable(key, AccessType)), - new LiteralExpr(Token.NoToken, BigNum.FromInt(loc), 32))); - } + sourceLocExprs.Add(Expr.Eq(new IdentifierExpr(Token.NoToken, verifier.FindOrCreateSourceVariable(key, AccessType)), + new LiteralExpr(Token.NoToken, BigNum.FromInt(loc), 32))); } - return disj; + return sourceLocExprs.Aggregate(Expr.Or); } protected Expr NoReadOrWriteExpr(Variable v, string ReadOrWrite, string OneOrTwo) { -- cgit v1.2.3 From 024f5aa8a58340d4073c2921aba2ed7b07d41451 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 18 Sep 2012 06:53:17 +0100 Subject: Dualisation modified so that global arrays are not dualised, and group-shared arrays are turned into 2D maps with first index type bool. Thread 1 always indexes into "true", while threads 2 indexes into "samegroup" (a formula which is true iff threads 1 and 2 are in the same group). Thus if the threads are in different groups they operate on different shared arrays, but if they are in the same group they operate on the same shared array. This paves the way for implementing support for barrier invariants. --- Source/GPUVerify/GPUVerifier.cs | 113 ++++++++++++++++------------------- Source/GPUVerify/RaceInstrumenter.cs | 38 ++++++------ Source/GPUVerify/VariableDualiser.cs | 65 ++++++++++++++------ 3 files changed, 119 insertions(+), 97 deletions(-) (limited to 'Source/GPUVerify/RaceInstrumenter.cs') diff --git a/Source/GPUVerify/GPUVerifier.cs b/Source/GPUVerify/GPUVerifier.cs index 7e1c9370..26dffc0f 100644 --- a/Source/GPUVerify/GPUVerifier.cs +++ b/Source/GPUVerify/GPUVerifier.cs @@ -834,25 +834,25 @@ namespace GPUVerify - public Microsoft.Boogie.Type GetTypeOfIdX() + public static Microsoft.Boogie.Type GetTypeOfIdX() { Contract.Requires(_X != null); return _X.TypedIdent.Type; } - public Microsoft.Boogie.Type GetTypeOfIdY() + public static Microsoft.Boogie.Type GetTypeOfIdY() { Contract.Requires(_Y != null); return _Y.TypedIdent.Type; } - public Microsoft.Boogie.Type GetTypeOfIdZ() + public static Microsoft.Boogie.Type GetTypeOfIdZ() { Contract.Requires(_Z != null); return _Z.TypedIdent.Type; } - public Microsoft.Boogie.Type GetTypeOfId(string dimension) + 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(); @@ -1060,7 +1060,7 @@ namespace GPUVerify } - internal Expr ThreadsInSameGroup() + internal static Expr ThreadsInSameGroup() { return Expr.And( Expr.And( @@ -1297,7 +1297,7 @@ namespace GPUVerify return new Constant(tok, new TypedIdent(tok, resultWithoutThreadId.Name + "$" + number, GetTypeOfId(dimension))); } - internal Constant GetGroupId(string 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; @@ -1307,7 +1307,7 @@ namespace GPUVerify return null; } - internal Constant MakeGroupId(string dimension, int number) + 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))); @@ -1367,11 +1367,13 @@ namespace GPUVerify Expr IfGuard2 = Expr.And(P2, LocalFence2); bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(), - new IfCmd(Token.NoToken, IfGuard1, new StmtList(MakeResetAndHavocBlocks(1, KernelArrayInfo.getGroupSharedArrays()), Token.NoToken), null, null), + 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(MakeResetAndHavocBlocks(2, KernelArrayInfo.getGroupSharedArrays()), Token.NoToken), null, null), + 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) @@ -1380,19 +1382,13 @@ namespace GPUVerify Expr IfGuard2 = Expr.And(P2, GlobalFence2); bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(), - new IfCmd(Token.NoToken, IfGuard1, new StmtList(MakeResetAndHavocBlocks(1, KernelArrayInfo.getGlobalArrays()), Token.NoToken), null, null), + 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(MakeResetAndHavocBlocks(2, KernelArrayInfo.getGlobalArrays()), Token.NoToken), null, null), + new IfCmd(Token.NoToken, IfGuard2, new StmtList(MakeResetBlocks(2, KernelArrayInfo.getGlobalArrays()), Token.NoToken), null, null), null)); - } - foreach (Variable v in KernelArrayInfo.getAllNonLocalArrays()) - { - if (!ArrayModelledAdversarially(v)) - { - bigblocks.Add(AssumeEqualityBetweenSharedArrays(v, P1, P2, LocalFence1, LocalFence2, GlobalFence1, GlobalFence2)); - } + bigblocks.AddRange(MakeHavocBlocks(KernelArrayInfo.getGlobalArrays())); } StmtList statements = new StmtList(bigblocks, BarrierProcedure.tok); @@ -1423,22 +1419,28 @@ namespace GPUVerify new LiteralExpr(Token.NoToken, BigNum.FromInt(1), 1)); } - private List MakeResetAndHavocBlocks(int Thread, ICollection variables) + 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)); - if (!ArrayModelledAdversarially(v)) - { - ResetAndHavocBlocks.Add(HavocSharedArray(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) { @@ -1459,38 +1461,13 @@ namespace GPUVerify return false; } - private BigBlock HavocSharedArray(Variable v, int thread) + private BigBlock HavocSharedArray(Variable v) { - IdentifierExpr vForThread = new IdentifierExpr(Token.NoToken, new VariableDualiser(thread, null, null).VisitVariable(v.Clone() as Variable)); - return new BigBlock(Token.NoToken, null, new CmdSeq(new Cmd[] { new HavocCmd(Token.NoToken, new IdentifierExprSeq(new IdentifierExpr[] { vForThread })) }), null, null); - } - - private BigBlock AssumeEqualityBetweenSharedArrays(Variable v, Expr P1, Expr P2, Expr LocalFence1, Expr LocalFence2, Expr GlobalFence1, Expr GlobalFence2) - { - IdentifierExpr v1 = new IdentifierExpr(Token.NoToken, new VariableDualiser(1, null, null).VisitVariable(v.Clone() as Variable)); - IdentifierExpr v2 = new IdentifierExpr(Token.NoToken, new VariableDualiser(2, null, null).VisitVariable(v.Clone() as Variable)); - - Expr AssumeGuard = Expr.Eq(v1, v2); - - Expr EqualityCondition = ThreadsInSameGroup(); - - if (KernelArrayInfo.getGroupSharedArrays().Contains(v)) - { - EqualityCondition = Expr.And(EqualityCondition, - Expr.And(LocalFence1, LocalFence2)); - } - else if (KernelArrayInfo.getGlobalArrays().Contains(v)) - { - EqualityCondition = Expr.And(EqualityCondition, - Expr.And(GlobalFence1, GlobalFence2)); - } - - AssumeGuard = Expr.Imp(EqualityCondition, AssumeGuard); - - return new BigBlock(Token.NoToken, null, new CmdSeq(new Cmd[] { new AssumeCmd(Token.NoToken, AssumeGuard) }), null, null); + 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) @@ -1880,16 +1857,32 @@ namespace GPUVerify } - if (d is Variable && ((d as Variable).IsMutable || IsThreadLocalIdConstant(d as Variable) - || IsGroupIdConstant(d as Variable) )) - { - NewTopLevelDeclarations.Add(new VariableDualiser(1, null, null).VisitVariable((Variable)d.Clone())); - if (!QKeyValue.FindBoolAttribute(d.Attributes, "race_checking")) - { - NewTopLevelDeclarations.Add(new VariableDualiser(2, null, null).VisitVariable((Variable)d.Clone())); - } + 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); diff --git a/Source/GPUVerify/RaceInstrumenter.cs b/Source/GPUVerify/RaceInstrumenter.cs index 35e7da4b..1e462635 100644 --- a/Source/GPUVerify/RaceInstrumenter.cs +++ b/Source/GPUVerify/RaceInstrumenter.cs @@ -304,12 +304,6 @@ namespace GPUVerify { foreach (Variable v in NonLocalStateToCheck.getAllNonLocalArrays()) { AddRequiresNoPendingAccess(v); AddRequiresSourceAccessZero(v); - - if (!verifier.ArrayModelledAdversarially(v)) { - IdentifierExpr v1 = new IdentifierExpr(Token.NoToken, new VariableDualiser(1, null, null).VisitVariable(v.Clone() as Variable)); - IdentifierExpr v2 = new IdentifierExpr(Token.NoToken, new VariableDualiser(2, null, null).VisitVariable(v.Clone() as Variable)); - verifier.KernelProcedure.Requires.Add(new Requires(false, Expr.Eq(v1, v2))); - } } } @@ -491,8 +485,8 @@ namespace GPUVerify { new VariableDualiser(1, null, null).VisitVariable(GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "WRITE")))); if (verifier.KernelArrayInfo.getGlobalArrays().Contains(v)) { - ResetReadAssumeGuard = Expr.Imp(verifier.ThreadsInSameGroup(), ResetReadAssumeGuard); - ResetWriteAssumeGuard = Expr.Imp(verifier.ThreadsInSameGroup(), ResetWriteAssumeGuard); + ResetReadAssumeGuard = Expr.Imp(GPUVerifier.ThreadsInSameGroup(), ResetReadAssumeGuard); + ResetWriteAssumeGuard = Expr.Imp(GPUVerifier.ThreadsInSameGroup(), ResetWriteAssumeGuard); } result.simpleCmds.Add(new AssumeCmd(Token.NoToken, ResetReadAssumeGuard)); @@ -747,13 +741,15 @@ namespace GPUVerify { if (!verifier.ArrayModelledAdversarially(v)) { WriteReadGuard = Expr.And(WriteReadGuard, Expr.Neq( - MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteOffsetVariable)), 1, "WRITE"), - MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter)), 2, "READ") + 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, verifier.ThreadsInSameGroup()); + WriteReadGuard = Expr.And(WriteReadGuard, GPUVerifier.ThreadsInSameGroup()); } WriteReadGuard = Expr.Not(WriteReadGuard); @@ -776,13 +772,15 @@ namespace GPUVerify { new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter)))); if (!verifier.ArrayModelledAdversarially(v)) { WriteWriteGuard = Expr.And(WriteWriteGuard, Expr.Neq( - MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(1, WriteOffsetVariable)), 1, "WRITE"), - MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter)), 2, "WRITE") + 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, verifier.ThreadsInSameGroup()); + WriteWriteGuard = Expr.And(WriteWriteGuard, GPUVerifier.ThreadsInSameGroup()); } WriteWriteGuard = Expr.Not(WriteWriteGuard); @@ -801,13 +799,15 @@ namespace GPUVerify { new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter)))); if (!verifier.ArrayModelledAdversarially(v)) { ReadWriteGuard = Expr.And(ReadWriteGuard, Expr.Neq( - MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(1, ReadOffsetVariable)), 1, "WRITE"), - MakeAccessedIndex(v, new IdentifierExpr(Token.NoToken, VariableForThread(2, OffsetParameter)), 2, "READ") + 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, verifier.ThreadsInSameGroup()); + ReadWriteGuard = Expr.And(ReadWriteGuard, GPUVerifier.ThreadsInSameGroup()); } ReadWriteGuard = Expr.Not(ReadWriteGuard); @@ -847,8 +847,8 @@ namespace GPUVerify { return new AssignCmd(lhs.tok, lhss, rhss); } - private Expr MakeAccessedIndex(Variable v, Expr offsetExpr, int Thread, string AccessType) { - Expr result = new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(v.Clone() as Variable)); + 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); diff --git a/Source/GPUVerify/VariableDualiser.cs b/Source/GPUVerify/VariableDualiser.cs index d5d9917a..ce5f78ee 100644 --- a/Source/GPUVerify/VariableDualiser.cs +++ b/Source/GPUVerify/VariableDualiser.cs @@ -54,13 +54,18 @@ namespace GPUVerify private TypedIdent DualiseTypedIdent(Variable v) { + if (QKeyValue.FindBoolAttribute(v.Attributes, "global") || + QKeyValue.FindBoolAttribute(v.Attributes, "group_shared")) { + return new TypedIdent(v.tok, v.Name, v.TypedIdent.Type); + } - if (uniformityAnalyser == null || !uniformityAnalyser.IsUniform(procName, v.Name)) - { - return new TypedIdent(v.tok, v.Name + "$" + id, v.TypedIdent.Type); - } - + if (uniformityAnalyser != null && uniformityAnalyser.IsUniform(procName, v.Name)) + { return new TypedIdent(v.tok, v.Name, v.TypedIdent.Type); + } + + return new TypedIdent(v.tok, v.Name + "$" + id, v.TypedIdent.Type); + } public override Variable VisitVariable(Variable node) @@ -79,26 +84,50 @@ namespace GPUVerify public override Expr VisitNAryExpr(NAryExpr node) { - // The point of this override is to avoid dualisation of certain special - // intrinsics that are cross-thread + if (node.Fun is MapSelect) { + Debug.Assert((node.Fun as MapSelect).Arity == 1); + Debug.Assert(node.Args[0] is IdentifierExpr); + var v = (node.Args[0] as IdentifierExpr).Decl; + if (QKeyValue.FindBoolAttribute(v.Attributes, "group_shared")) { + return new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), + new ExprSeq(new Expr[] { new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), + new ExprSeq(new Expr[] { node.Args[0], GroupSharedIndexingExpr() })), VisitExpr(node.Args[1]) })); + } + } - if (node.Fun is FunctionCall) + // Avoid dualisation of certain special builtin functions that are cross-thread + if (node.Fun is FunctionCall) + { + FunctionCall call = node.Fun as FunctionCall; + + if (otherFunctionNames.Contains(call.Func.Name)) { - FunctionCall call = node.Fun as FunctionCall; + Debug.Assert(id == 1 || id == 2); + int otherId = id == 1 ? 2 : 1; + return new VariableDualiser(otherId, uniformityAnalyser, procName).VisitExpr( + node.Args[0]); + } - if (otherFunctionNames.Contains(call.Func.Name)) - { - Debug.Assert(id == 1 || id == 2); - int otherId = id == 1 ? 2 : 1; - return new VariableDualiser(otherId, uniformityAnalyser, procName).VisitExpr( - node.Args[0]); - } + } - } + return base.VisitNAryExpr(node); + } - return base.VisitNAryExpr(node); + + public override AssignLhs VisitMapAssignLhs(MapAssignLhs node) { + + var v = node.DeepAssignedVariable; + if(QKeyValue.FindBoolAttribute(v.Attributes, "group_shared")) { + return new MapAssignLhs(Token.NoToken, new MapAssignLhs(Token.NoToken, node.Map, + new List(new Expr[] { GroupSharedIndexingExpr() })), node.Indexes.Select(idx => this.VisitExpr(idx)).ToList()); + + } + return base.VisitMapAssignLhs(node); } + private Expr GroupSharedIndexingExpr() { + return id == 1 ? Expr.True : GPUVerifier.ThreadsInSameGroup(); + } } -- cgit v1.2.3 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 (limited to 'Source/GPUVerify/RaceInstrumenter.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 From 15e8142718b25cc3d3d56286de8955c3296848fb Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 21 Sep 2012 08:59:07 +0100 Subject: Added support for invariants about shared state. Reworked implementation of barriers. Started on support for barrier invariants. --- Source/GPUVerify/ArrayControlFlowAnalyser.cs | 4 +- Source/GPUVerify/GPUVerifier.cs | 103 +++++++++++++++++++-------- Source/GPUVerify/IRaceInstrumenter.cs | 2 +- Source/GPUVerify/NonLocalAccessCollector.cs | 1 - Source/GPUVerify/NullRaceInstrumenter.cs | 2 +- Source/GPUVerify/RaceInstrumenter.cs | 17 ++--- 6 files changed, 88 insertions(+), 41 deletions(-) (limited to 'Source/GPUVerify/RaceInstrumenter.cs') diff --git a/Source/GPUVerify/ArrayControlFlowAnalyser.cs b/Source/GPUVerify/ArrayControlFlowAnalyser.cs index d7841f0e..649d76d7 100644 --- a/Source/GPUVerify/ArrayControlFlowAnalyser.cs +++ b/Source/GPUVerify/ArrayControlFlowAnalyser.cs @@ -172,7 +172,9 @@ namespace GPUVerify { CallCmd callCmd = c as CallCmd; - if (callCmd.callee != verifier.BarrierProcedure.Name) + if (callCmd.callee != verifier.BarrierProcedure.Name && + callCmd.callee != verifier.BarrierInvariantProcedure.Name && + callCmd.callee != verifier.BarrierInvariantInstantiationProcedure.Name) { Implementation CalleeImplementation = verifier.GetImplementation(callCmd.callee); diff --git a/Source/GPUVerify/GPUVerifier.cs b/Source/GPUVerify/GPUVerifier.cs index 868bcaa1..351fe45e 100644 --- a/Source/GPUVerify/GPUVerifier.cs +++ b/Source/GPUVerify/GPUVerifier.cs @@ -18,7 +18,9 @@ namespace GPUVerify public Procedure KernelProcedure; public Implementation KernelImplementation; - public Procedure BarrierProcedure; + public Procedure BarrierProcedure; + public Procedure BarrierInvariantProcedure; + public Procedure BarrierInvariantInstantiationProcedure; public IKernelArrayInfo KernelArrayInfo = new KernelArrayInfoLists(); @@ -128,6 +130,42 @@ namespace GPUVerify ResContext.AddProcedure(p); } return p; + } + + private Procedure FindOrCreateBarrierInvariantProcedure() { + var p = CheckSingleInstanceOfAttributedProcedure("barrier_invariant"); + if (p == null) { + p = new Procedure(Token.NoToken, "barrier_invariant", new TypeVariableSeq(), + new VariableSeq(new Variable[] { + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "__cond", + Microsoft.Boogie.Type.Bool), true) + }), + new VariableSeq(), new RequiresSeq(), new IdentifierExprSeq(), + new EnsuresSeq(), + new QKeyValue(Token.NoToken, "barrier_invariant", new List(), null)); + Program.TopLevelDeclarations.Add(p); + ResContext.AddProcedure(p); + } + return p; + } + + private Procedure FindOrCreateBarrierInvariantInstantiationProcedure() { + var p = CheckSingleInstanceOfAttributedProcedure("barrier_invariant_instantiation"); + if (p == null) { + p = new Procedure(Token.NoToken, "barrier_invariant_instantiation", new TypeVariableSeq(), + new VariableSeq(new Variable[] { + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "__t1", + new BvType(32)), true), + new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "__t2", + new BvType(32)), true) + }), + new VariableSeq(), new RequiresSeq(), new IdentifierExprSeq(), + new EnsuresSeq(), + new QKeyValue(Token.NoToken, "barrier_invariant_instantiation", new List(), null)); + Program.TopLevelDeclarations.Add(p); + ResContext.AddProcedure(p); + } + return p; } private Procedure CheckSingleInstanceOfAttributedProcedure(string attribute) @@ -1376,17 +1414,19 @@ namespace GPUVerify 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())); + bigblocks.AddRange( + MakeResetBlocks(Expr.And(P1, LocalFence1), KernelArrayInfo.getGroupSharedArrays())); + + // This could be relaxed to take into account whether the threads are in different + // groups, but for now we keep it relatively simple + + Expr AtLeastOneEnabledWithLocalFence = + Expr.Or(Expr.And(P1, LocalFence1), Expr.And(P2, LocalFence2)); + + bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(new Cmd[] { }), + new IfCmd(Token.NoToken, + AtLeastOneEnabledWithLocalFence, + new StmtList(MakeHavocBlocks(KernelArrayInfo.getGroupSharedArrays()), Token.NoToken), null, null), null)); } if (KernelArrayInfo.getGlobalArrays().Count > 0) @@ -1394,14 +1434,16 @@ namespace GPUVerify 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())); + bigblocks.AddRange( + MakeResetBlocks(Expr.And(P1, GlobalFence1), KernelArrayInfo.getGlobalArrays())); + + Expr ThreadsInSameGroup_BothEnabled_AtLeastOneGlobalFence = + Expr.And(Expr.And(GPUVerifier.ThreadsInSameGroup(), Expr.And(P1, P2)), Expr.Or(GlobalFence1, GlobalFence2)); + + bigblocks.Add(new BigBlock(Token.NoToken, null, new CmdSeq(new Cmd[] { }), + new IfCmd(Token.NoToken, + ThreadsInSameGroup_BothEnabled_AtLeastOneGlobalFence, + new StmtList(MakeHavocBlocks(KernelArrayInfo.getGlobalArrays()), Token.NoToken), null, null), null)); } StmtList statements = new StmtList(bigblocks, BarrierProcedure.tok); @@ -1432,16 +1474,16 @@ namespace GPUVerify new LiteralExpr(Token.NoToken, BigNum.FromInt(1), 1)); } - private List MakeResetBlocks(int Thread, ICollection variables) + private List MakeResetBlocks(Expr ResetCondition, ICollection variables) { Debug.Assert(variables.Count > 0); - List ResetAndHavocBlocks = new List(); + List result = new List(); foreach (Variable v in variables) { - ResetAndHavocBlocks.Add(RaceInstrumenter.MakeResetReadWriteSetStatements(v, Thread)); + result.Add(RaceInstrumenter.MakeResetReadWriteSetStatements(v, ResetCondition)); } - Debug.Assert(ResetAndHavocBlocks.Count > 0); - return ResetAndHavocBlocks; + Debug.Assert(result.Count > 0); + return result; } private List MakeHavocBlocks(ICollection variables) { @@ -1765,7 +1807,7 @@ namespace GPUVerify } else if (c is AssertCmd) { - result.simpleCmds.Add(new AssertCmd(c.tok, PullOutNonLocalAccessesIntoTemps(result, (c as AssertCmd).Expr, impl))); + // Do not pull non-local accesses out of assert commands } else if (c is AssumeCmd) { @@ -1982,7 +2024,9 @@ namespace GPUVerify private int Check() { - BarrierProcedure = FindOrCreateBarrierProcedure(); + BarrierProcedure = FindOrCreateBarrierProcedure(); + BarrierInvariantProcedure = FindOrCreateBarrierInvariantProcedure(); + BarrierInvariantInstantiationProcedure = FindOrCreateBarrierInvariantInstantiationProcedure(); KernelProcedure = CheckExactlyOneKernelProcedure(); if (ErrorCount > 0) @@ -2039,8 +2083,9 @@ namespace GPUVerify { return D as Implementation; } - } - Debug.Assert(false); + } + Error(Token.NoToken, "No implementation found for procedure \"" + procedureName + "\""); + Environment.Exit(1); return null; } diff --git a/Source/GPUVerify/IRaceInstrumenter.cs b/Source/GPUVerify/IRaceInstrumenter.cs index c85989c9..7f14fcd0 100644 --- a/Source/GPUVerify/IRaceInstrumenter.cs +++ b/Source/GPUVerify/IRaceInstrumenter.cs @@ -15,7 +15,7 @@ namespace GPUVerify void AddRaceCheckingDeclarations(); - BigBlock MakeResetReadWriteSetStatements(Variable v, int thread); + BigBlock MakeResetReadWriteSetStatements(Variable v, Expr ResetCondition); void AddRaceCheckingCandidateRequires(Procedure Proc); diff --git a/Source/GPUVerify/NonLocalAccessCollector.cs b/Source/GPUVerify/NonLocalAccessCollector.cs index 6a934899..d1361ff4 100644 --- a/Source/GPUVerify/NonLocalAccessCollector.cs +++ b/Source/GPUVerify/NonLocalAccessCollector.cs @@ -70,7 +70,6 @@ namespace GPUVerify return collector.Accesses.Count > 0; } - public override Expr VisitNAryExpr(NAryExpr node) { if (IsNonLocalAccess(node, NonLocalState)) diff --git a/Source/GPUVerify/NullRaceInstrumenter.cs b/Source/GPUVerify/NullRaceInstrumenter.cs index fae08aa3..6452331f 100644 --- a/Source/GPUVerify/NullRaceInstrumenter.cs +++ b/Source/GPUVerify/NullRaceInstrumenter.cs @@ -24,7 +24,7 @@ namespace GPUVerify } - public Microsoft.Boogie.BigBlock MakeResetReadWriteSetStatements(Variable v, int Thread) + public Microsoft.Boogie.BigBlock MakeResetReadWriteSetStatements(Variable v, Expr ResetCondition) { return new BigBlock(Token.NoToken, null, new CmdSeq(), null, null); } diff --git a/Source/GPUVerify/RaceInstrumenter.cs b/Source/GPUVerify/RaceInstrumenter.cs index c73b9b13..71214cb3 100644 --- a/Source/GPUVerify/RaceInstrumenter.cs +++ b/Source/GPUVerify/RaceInstrumenter.cs @@ -473,16 +473,17 @@ namespace GPUVerify { } - public BigBlock MakeResetReadWriteSetStatements(Variable v, int Thread) { + public BigBlock MakeResetReadWriteSetStatements(Variable v, Expr ResetCondition) { 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")))); + Expr ResetReadAssumeGuard = Expr.Imp(ResetCondition, + Expr.Not(new IdentifierExpr(Token.NoToken, + new VariableDualiser(1, null, null).VisitVariable( + GPUVerifier.MakeAccessHasOccurredVariable(v.Name, "READ"))))); + Expr ResetWriteAssumeGuard = Expr.Imp(ResetCondition, + 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); -- cgit v1.2.3 From 930161bb7df44eb931e38bc2dc1a480e282d1e94 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 28 Sep 2012 11:19:53 +0100 Subject: Fixed bug with uniformity analysis for havoc. Allowed barrier invariants to support a more expressive class of expressions. Refactored thread id creation functions. --- .../GPUVerify/BinaryBarrierInvariantDescriptor.cs | 4 +-- Source/GPUVerify/GPUVerifier.cs | 33 +++++++++++----------- Source/GPUVerify/KernelDualiser.cs | 22 +++++++++++---- Source/GPUVerify/RaceInstrumenter.cs | 7 +++-- Source/VCGeneration/UniformityAnalyser.cs | 10 +++++++ 5 files changed, 50 insertions(+), 26 deletions(-) (limited to 'Source/GPUVerify/RaceInstrumenter.cs') diff --git a/Source/GPUVerify/BinaryBarrierInvariantDescriptor.cs b/Source/GPUVerify/BinaryBarrierInvariantDescriptor.cs index 8d8f75ec..8be05ecb 100644 --- a/Source/GPUVerify/BinaryBarrierInvariantDescriptor.cs +++ b/Source/GPUVerify/BinaryBarrierInvariantDescriptor.cs @@ -21,7 +21,7 @@ namespace GPUVerify { } internal override AssertCmd GetAssertCmd() { - var vd = new VariableDualiser(1, null, null); + var vd = new VariableDualiser(1, Dualiser.verifier.uniformityAnalyser, ProcName); return new AssertCmd( Token.NoToken, Expr.Imp(GPUVerifier.ThreadsInSameGroup(), @@ -34,7 +34,7 @@ namespace GPUVerify { foreach (var Instantiation in InstantiationExprPairs) { foreach (var Thread in new int[] { 1, 2 }) { - var vd = new VariableDualiser(Thread, null, null); + var vd = new VariableDualiser(Thread, Dualiser.verifier.uniformityAnalyser, ProcName); var ThreadInstantiationExpr = vd.VisitExpr(Instantiation.Item1); var OtherThreadInstantiationExpr = vd.VisitExpr(Instantiation.Item2); diff --git a/Source/GPUVerify/GPUVerifier.cs b/Source/GPUVerify/GPUVerifier.cs index f94cf5ef..216954c5 100644 --- a/Source/GPUVerify/GPUVerifier.cs +++ b/Source/GPUVerify/GPUVerifier.cs @@ -1023,17 +1023,17 @@ namespace GPUVerify Expr.Or( Expr.Or( Expr.Neq( - new IdentifierExpr(tok, MakeThreadId(tok, "X", 1)), - new IdentifierExpr(tok, MakeThreadId(tok, "X", 2)) + new IdentifierExpr(tok, MakeThreadId("X", 1)), + new IdentifierExpr(tok, MakeThreadId("X", 2)) ), Expr.Neq( - new IdentifierExpr(tok, MakeThreadId(tok, "Y", 1)), - new IdentifierExpr(tok, MakeThreadId(tok, "Y", 2)) + new IdentifierExpr(tok, MakeThreadId("Y", 1)), + new IdentifierExpr(tok, MakeThreadId("Y", 2)) ) ), Expr.Neq( - new IdentifierExpr(tok, MakeThreadId(tok, "Z", 1)), - new IdentifierExpr(tok, MakeThreadId(tok, "Z", 2)) + new IdentifierExpr(tok, MakeThreadId("Z", 1)), + new IdentifierExpr(tok, MakeThreadId("Z", 2)) ) ); @@ -1196,14 +1196,14 @@ namespace GPUVerify Expr ThreadIdNonNegative = GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)) ? - MakeBVSge(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), ZeroBV()) + MakeBVSge(new IdentifierExpr(tok, MakeThreadId(dimension)), ZeroBV()) : - Expr.Ge(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), Zero()); + Expr.Ge(new IdentifierExpr(tok, MakeThreadId(dimension)), Zero()); Expr ThreadIdLessThanGroupSize = GetTypeOfId(dimension).Equals(Microsoft.Boogie.Type.GetBvType(32)) ? - MakeBVSlt(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), new IdentifierExpr(tok, GetGroupSize(dimension))) + MakeBVSlt(new IdentifierExpr(tok, MakeThreadId(dimension)), new IdentifierExpr(tok, GetGroupSize(dimension))) : - Expr.Lt(new IdentifierExpr(tok, MakeThreadId(tok, dimension)), new IdentifierExpr(tok, GetGroupSize(dimension))); + Expr.Lt(new IdentifierExpr(tok, MakeThreadId(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))); @@ -1329,7 +1329,7 @@ namespace GPUVerify return null; } - internal Constant MakeThreadId(IToken tok, string dimension) + internal static Constant MakeThreadId(string dimension) { Contract.Requires(dimension.Equals("X") || dimension.Equals("Y") || dimension.Equals("Z")); string name = null; @@ -1337,13 +1337,14 @@ namespace GPUVerify 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))); + return new Constant(Token.NoToken, new TypedIdent(Token.NoToken, name, GetTypeOfId(dimension))); } - internal Constant MakeThreadId(IToken tok, string dimension, int number) + internal static Constant MakeThreadId(string dimension, int number) { - Constant resultWithoutThreadId = MakeThreadId(tok, dimension); - return new Constant(tok, new TypedIdent(tok, resultWithoutThreadId.Name + "$" + number, GetTypeOfId(dimension))); + Constant resultWithoutThreadId = MakeThreadId(dimension); + return new Constant(Token.NoToken, new TypedIdent( + Token.NoToken, resultWithoutThreadId.Name + "$" + number, GetTypeOfId(dimension))); } internal static Constant GetGroupId(string dimension) @@ -2142,7 +2143,7 @@ namespace GPUVerify { return MakeBVAdd(MakeBVMul( new IdentifierExpr(Token.NoToken, GetGroupId(dimension)), new IdentifierExpr(Token.NoToken, GetGroupSize(dimension))), - new IdentifierExpr(Token.NoToken, MakeThreadId(Token.NoToken, dimension))); + new IdentifierExpr(Token.NoToken, MakeThreadId(dimension))); } internal IRegion RootRegion(Implementation Impl) diff --git a/Source/GPUVerify/KernelDualiser.cs b/Source/GPUVerify/KernelDualiser.cs index d2b921f2..3a2a1776 100644 --- a/Source/GPUVerify/KernelDualiser.cs +++ b/Source/GPUVerify/KernelDualiser.cs @@ -445,12 +445,24 @@ namespace GPUVerify { return InstantiationExpr.Clone() as Expr; } - Debug.Assert(node.Decl is Constant || - QKeyValue.FindBoolAttribute(node.Decl.Attributes, "global") || - QKeyValue.FindBoolAttribute(node.Decl.Attributes, "group_shared") || - (Uni != null && Uni.IsUniform(ProcName, node.Decl.Name))); + if(node.Decl is Constant || + QKeyValue.FindBoolAttribute(node.Decl.Attributes, "global") || + QKeyValue.FindBoolAttribute(node.Decl.Attributes, "group_shared") || + (Uni != null && Uni.IsUniform(ProcName, node.Decl.Name))) { + return base.VisitIdentifierExpr(node); + } - return base.VisitIdentifierExpr(node); + if (InstantiationExprIsThreadId()) { + return new VariableDualiser(Thread, Uni, ProcName).VisitIdentifierExpr(node); + } + + Debug.Assert(false); + return null; + } + + private bool InstantiationExprIsThreadId() { + return (InstantiationExpr is IdentifierExpr) && + ((IdentifierExpr)InstantiationExpr).Decl.Name.Equals(GPUVerifier.MakeThreadId("X", Thread).Name); } public override Expr VisitNAryExpr(NAryExpr node) { diff --git a/Source/GPUVerify/RaceInstrumenter.cs b/Source/GPUVerify/RaceInstrumenter.cs index 71214cb3..f3b9194b 100644 --- a/Source/GPUVerify/RaceInstrumenter.cs +++ b/Source/GPUVerify/RaceInstrumenter.cs @@ -1028,7 +1028,8 @@ namespace GPUVerify { 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)))); + Expr.Eq(new IdentifierExpr(v.tok, new VariableDualiser(Thread, null, null).VisitVariable(GPUVerifier.MakeOffsetVariable(v.Name, ReadOrWrite))), + new IdentifierExpr(v.tok, GPUVerifier.MakeThreadId("X", Thread)))); } private Expr GlobalIdExpr(string dimension, int Thread) { @@ -1043,10 +1044,10 @@ namespace GPUVerify { 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))); + new IdentifierExpr(Token.NoToken, GPUVerifier.MakeThreadId("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); + new IdentifierExpr(Token.NoToken, GPUVerifier.MakeThreadId("X", Thread))), constant.Clone() as Expr); Expr CTimesLocalIdLeqAccessedOffset = GPUVerifier.MakeBitVectorBinaryBoolean("BV32_LEQ", CTimesLocalId, OffsetXExpr(v, ReadOrWrite, Thread)); diff --git a/Source/VCGeneration/UniformityAnalyser.cs b/Source/VCGeneration/UniformityAnalyser.cs index 849333b3..802ee2d2 100644 --- a/Source/VCGeneration/UniformityAnalyser.cs +++ b/Source/VCGeneration/UniformityAnalyser.cs @@ -309,6 +309,16 @@ namespace Microsoft.Boogie } } } + else if (c is HavocCmd) + { + HavocCmd havocCmd = c as HavocCmd; + foreach(IdentifierExpr ie in havocCmd.Vars) + { + if(IsUniform(impl.Name, ie.Decl.Name)) { + SetNonUniform(impl.Name, ie.Decl.Name); + } + } + } else if (c is CallCmd) { CallCmd callCmd = c as CallCmd; -- cgit v1.2.3