private void MakeDual(List <Cmd> cs, Cmd c) { if (c is CallCmd) { CallCmd Call = c as CallCmd; if (QKeyValue.FindBoolAttribute(Call.Proc.Attributes, "barrier_invariant")) { // There may be a predicate, and there must be an invariant expression and at least one instantiation Debug.Assert(Call.Ins.Count >= (2 + (verifier.uniformityAnalyser.IsUniform(Call.callee) ? 0 : 1))); var BIDescriptor = new UnaryBarrierInvariantDescriptor( verifier.uniformityAnalyser.IsUniform(Call.callee) ? Expr.True : Call.Ins[0], Expr.Neq(Call.Ins[verifier.uniformityAnalyser.IsUniform(Call.callee) ? 0 : 1], verifier.Zero(1)), Call.Attributes, this, procName, verifier); for (var i = 1 + (verifier.uniformityAnalyser.IsUniform(Call.callee) ? 0 : 1); i < Call.Ins.Count; i++) { BIDescriptor.AddInstantiationExpr(Call.Ins[i]); } BarrierInvariantDescriptors.Add(BIDescriptor); return; } if (QKeyValue.FindBoolAttribute(Call.Proc.Attributes, "binary_barrier_invariant")) { // There may be a predicate, and there must be an invariant expression and at least one pair of // instantiation expressions Debug.Assert(Call.Ins.Count >= (3 + (verifier.uniformityAnalyser.IsUniform(Call.callee) ? 0 : 1))); var BIDescriptor = new BinaryBarrierInvariantDescriptor( verifier.uniformityAnalyser.IsUniform(Call.callee) ? Expr.True : Call.Ins[0], Expr.Neq(Call.Ins[verifier.uniformityAnalyser.IsUniform(Call.callee) ? 0 : 1], verifier.Zero(1)), Call.Attributes, this, procName, verifier); for (var i = 1 + (verifier.uniformityAnalyser.IsUniform(Call.callee) ? 0 : 1); i < Call.Ins.Count; i += 2) { BIDescriptor.AddInstantiationExprPair(Call.Ins[i], Call.Ins[i + 1]); } BarrierInvariantDescriptors.Add(BIDescriptor); return; } if (GPUVerifier.IsBarrier(Call.Proc)) { // Assert barrier invariants foreach (var BIDescriptor in BarrierInvariantDescriptors) { QKeyValue SourceLocationInfo = BIDescriptor.GetSourceLocationInfo(); cs.Add(BIDescriptor.GetAssertCmd()); var vd = new VariableDualiser(1, verifier.uniformityAnalyser, procName); if (GPUVerifyVCGenCommandLineOptions.BarrierAccessChecks) { foreach (Expr AccessExpr in BIDescriptor.GetAccessedExprs()) { var Assert = new AssertCmd(Token.NoToken, AccessExpr, MakeThreadSpecificAttributes(SourceLocationInfo, 1)); Assert.Attributes = new QKeyValue(Token.NoToken, "barrier_invariant_access_check", new List <object> { Expr.True }, Assert.Attributes); cs.Add(vd.VisitAssertCmd(Assert)); } } } } List <Expr> uniformNewIns = new List <Expr>(); List <Expr> nonUniformNewIns = new List <Expr>(); for (int i = 0; i < Call.Ins.Count; i++) { if (verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetInParameter(Call.callee, i))) { uniformNewIns.Add(Call.Ins[i]); } else if (!verifier.OnlyThread2.Contains(Call.callee)) { nonUniformNewIns.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(Call.Ins[i])); } } for (int i = 0; i < Call.Ins.Count; i++) { if ( !(verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetInParameter(Call.callee, i))) && !verifier.OnlyThread1.Contains(Call.callee)) { nonUniformNewIns.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(Call.Ins[i])); } } List <Expr> newIns = uniformNewIns; newIns.AddRange(nonUniformNewIns); List <IdentifierExpr> uniformNewOuts = new List <IdentifierExpr>(); List <IdentifierExpr> nonUniformNewOuts = new List <IdentifierExpr>(); for (int i = 0; i < Call.Outs.Count; i++) { if (verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetOutParameter(Call.callee, i))) { uniformNewOuts.Add(Call.Outs[i]); } else { nonUniformNewOuts.Add(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(Call.Outs[i].Clone() as IdentifierExpr) as IdentifierExpr); } } for (int i = 0; i < Call.Outs.Count; i++) { if (!(verifier.uniformityAnalyser.knowsOf(Call.callee) && verifier.uniformityAnalyser.IsUniform(Call.callee, verifier.uniformityAnalyser.GetOutParameter(Call.callee, i)))) { nonUniformNewOuts.Add(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(Call.Outs[i].Clone() as IdentifierExpr) as IdentifierExpr); } } List <IdentifierExpr> newOuts = uniformNewOuts; newOuts.AddRange(nonUniformNewOuts); CallCmd NewCallCmd = new CallCmd(Call.tok, Call.callee, newIns, newOuts); NewCallCmd.Proc = Call.Proc; NewCallCmd.Attributes = Call.Attributes; if (NewCallCmd.callee.StartsWith("_LOG_ATOMIC")) { QKeyValue curr = NewCallCmd.Attributes; if (curr.Key.StartsWith("arg")) { NewCallCmd.Attributes = new QKeyValue(Token.NoToken, curr.Key, new List <object>(new object[] { Dualise(curr.Params[0] as Expr, 1) }), curr.Next); } for (curr = NewCallCmd.Attributes; curr.Next != null; curr = curr.Next) { if (curr.Next.Key.StartsWith("arg")) { curr.Next = new QKeyValue(Token.NoToken, curr.Next.Key, new List <object>(new object[] { Dualise(curr.Next.Params[0] as Expr, 1) }), curr.Next.Next); } } } else if (NewCallCmd.callee.StartsWith("_CHECK_ATOMIC")) { QKeyValue curr = NewCallCmd.Attributes; if (curr.Key.StartsWith("arg")) { NewCallCmd.Attributes = new QKeyValue(Token.NoToken, curr.Key, new List <object>(new object[] { Dualise(curr.Params[0] as Expr, 2) }), curr.Next); } for (curr = NewCallCmd.Attributes; curr.Next != null; curr = curr.Next) { if (curr.Next.Key.StartsWith("arg")) { curr.Next = new QKeyValue(Token.NoToken, curr.Next.Key, new List <object>(new object[] { Dualise(curr.Next.Params[0] as Expr, 2) }), curr.Next.Next); } } } cs.Add(NewCallCmd); if (GPUVerifier.IsBarrier(Call.Proc)) { foreach (var BIDescriptor in BarrierInvariantDescriptors) { foreach (var Instantiation in BIDescriptor.GetInstantiationCmds()) { cs.Add(Instantiation); } } BarrierInvariantDescriptors.Clear(); } } else if (c is AssignCmd) { AssignCmd assign = c as AssignCmd; var vd1 = new VariableDualiser(1, verifier.uniformityAnalyser, procName); var vd2 = new VariableDualiser(2, verifier.uniformityAnalyser, procName); List <AssignLhs> lhss1 = new List <AssignLhs>(); List <AssignLhs> lhss2 = new List <AssignLhs>(); List <Expr> rhss1 = new List <Expr>(); List <Expr> rhss2 = new List <Expr>(); foreach (var pair in assign.Lhss.Zip(assign.Rhss)) { if (pair.Item1 is SimpleAssignLhs && verifier.uniformityAnalyser.IsUniform(procName, (pair.Item1 as SimpleAssignLhs).AssignedVariable.Name)) { lhss1.Add(pair.Item1); rhss1.Add(pair.Item2); } else { lhss1.Add(vd1.Visit(pair.Item1.Clone() as AssignLhs) as AssignLhs); lhss2.Add(vd2.Visit(pair.Item1.Clone() as AssignLhs) as AssignLhs); rhss1.Add(vd1.VisitExpr(pair.Item2.Clone() as Expr)); rhss2.Add(vd2.VisitExpr(pair.Item2.Clone() as Expr)); } } 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; Debug.Assert(havoc.Vars.Count() == 1); HavocCmd newHavoc; newHavoc = new HavocCmd(havoc.tok, new List <IdentifierExpr>(new IdentifierExpr[] { (IdentifierExpr)(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr)), (IdentifierExpr)(new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr)) })); cs.Add(newHavoc); } else if (c is AssertCmd) { AssertCmd a = c as AssertCmd; if (QKeyValue.FindBoolAttribute(a.Attributes, "sourceloc") || QKeyValue.FindBoolAttribute(a.Attributes, "block_sourceloc") || QKeyValue.FindBoolAttribute(a.Attributes, "array_bounds")) { // This is just a location marker, so we do not dualise it cs.Add(new AssertCmd(Token.NoToken, new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(a.Expr.Clone() as Expr), (QKeyValue)a.Attributes.Clone())); } else { var isUniform = verifier.uniformityAnalyser.IsUniform(procName, a.Expr); cs.Add(MakeThreadSpecificAssert(a, 1)); if (!GPUVerifyVCGenCommandLineOptions.AsymmetricAsserts && !ContainsAsymmetricExpression(a.Expr) && !isUniform) { cs.Add(MakeThreadSpecificAssert(a, 2)); } } } else if (c is AssumeCmd) { AssumeCmd ass = c as AssumeCmd; if (QKeyValue.FindStringAttribute(ass.Attributes, "captureState") != null) { cs.Add(c); } else if (QKeyValue.FindBoolAttribute(ass.Attributes, "backedge")) { AssumeCmd newAss = new AssumeCmd(c.tok, Expr.Or(new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr), new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr))); newAss.Attributes = ass.Attributes; cs.Add(newAss); } else if (QKeyValue.FindBoolAttribute(ass.Attributes, "atomic_refinement")) { // Generate the following: // havoc v$1, v$2; // assume !_USED[offset$1][v$1]; // _USED[offset$1][v$1] := true; // assume !_USED[offset$2][v$2]; // _USED[offset$2][v$2] := true; Expr variable = QKeyValue.FindExprAttribute(ass.Attributes, "variable"); Expr offset = QKeyValue.FindExprAttribute(ass.Attributes, "offset"); List <Expr> offsets = (new int[] { 1, 2 }).Select(x => new VariableDualiser(x, verifier.uniformityAnalyser, procName).VisitExpr(offset.Clone() as Expr)).ToList(); List <Expr> vars = (new int[] { 1, 2 }).Select(x => new VariableDualiser(x, verifier.uniformityAnalyser, procName).VisitExpr(variable.Clone() as Expr)).ToList(); IdentifierExpr arrayref = new IdentifierExpr(Token.NoToken, verifier.FindOrCreateUsedMap(QKeyValue.FindStringAttribute(ass.Attributes, "arrayref"), vars[0].Type)); foreach (int i in (new int[] { 0, 1 })) { AssumeCmd newAss = new AssumeCmd(c.tok, Expr.Not(new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List <Expr> { new NAryExpr(Token.NoToken, new MapSelect(Token.NoToken, 1), new List <Expr> { arrayref, offsets[i] }), vars[i] }))); cs.Add(newAss); var lhs = new MapAssignLhs(Token.NoToken, new MapAssignLhs(Token.NoToken, new SimpleAssignLhs(Token.NoToken, arrayref), new List <Expr> { offsets[i] }), new List <Expr> { vars[i] }); AssignCmd assign = new AssignCmd(c.tok, new List <AssignLhs> { lhs }, new List <Expr> { Expr.True }); cs.Add(assign); } } else { var isUniform = verifier.uniformityAnalyser.IsUniform(procName, ass.Expr); AssumeCmd newAss = new AssumeCmd(c.tok, new VariableDualiser(1, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr)); if (!ContainsAsymmetricExpression(ass.Expr) && !isUniform) { newAss.Expr = Expr.And(newAss.Expr, new VariableDualiser(2, verifier.uniformityAnalyser, procName).VisitExpr(ass.Expr.Clone() as Expr)); } newAss.Attributes = ass.Attributes; cs.Add(newAss); } } else { Debug.Assert(false); } }
private static bool AccessesGlobalArrayOrUnsafeBarrier(Cmd c, GPUVerifier verifier) { var stateToCheck = verifier.KernelArrayInfo; if (c is CallCmd) { // Speculate invariants if we see atomics, async_work_group_copy, and // wait_group_events, which relate to race checking CallCmd call = c as CallCmd; if (QKeyValue.FindBoolAttribute(call.Attributes, "atomic")) { return(true); } if (QKeyValue.FindBoolAttribute(call.Attributes, "async_work_group_copy")) { return(true); } if (QKeyValue.FindBoolAttribute(call.Attributes, "wait_group_events")) { return(true); } // Speculate invariants if we see an unsafe barrier, // which we need to check for barrier divergence if (GPUVerifier.IsBarrier(call.Proc) && !QKeyValue.FindBoolAttribute(call.Proc.Attributes, "safe_barrier")) { return(true); } // Speculate invariants if we see a call to a procedure that has a non-local array // or constant array in its modset List <Variable> vars = new List <Variable>(); call.AddAssignedVariables(vars); foreach (Variable v in vars) { if (stateToCheck.GetGlobalAndGroupSharedArrays(false).Contains(v)) { return(true); } if (stateToCheck.GetConstantArrays().Contains(v)) { return(true); } } } // Speculate invariants if race instrumentation or a constant write // instrumentation will occur if (c is AssignCmd) { AssignCmd assign = c as AssignCmd; ReadCollector rc = new ReadCollector(stateToCheck); foreach (var rhs in assign.Rhss) { rc.Visit(rhs); } foreach (var access in rc.NonPrivateAccesses) { // Ignore disabled arrays if (stateToCheck.GetGlobalAndGroupSharedArrays(false).Contains(access.V)) { // Ignore read-only arrays (whether or not they are disabled) if (!stateToCheck.GetReadOnlyGlobalAndGroupSharedArrays(true).Contains(access.V)) { return(true); } } } foreach (var lhsRhs in assign.Lhss.Zip(assign.Rhss)) { WriteCollector wc = new WriteCollector(stateToCheck); wc.Visit(lhsRhs.Item1); if (wc.FoundNonPrivateWrite()) { // Ignore disabled arrays if (stateToCheck.GetGlobalAndGroupSharedArrays(false).Contains(wc.GetAccess().V)) { return(true); } } } foreach (var lhsRhs in assign.Lhss.Zip(assign.Rhss)) { ConstantWriteCollector cwc = new ConstantWriteCollector(stateToCheck); cwc.Visit(lhsRhs.Item1); if (cwc.FoundWrite()) { // Ignore disabled arrays if (stateToCheck.GetGlobalAndGroupSharedArrays(false).Contains(cwc.GetAccess().V)) { return(true); } } } } // Speculate invariants if we see an assert that is not a sourceloc or // block_sourceloc assert; such asserts is likely user supplied. if (c is AssertCmd) { AssertCmd assertion = c as AssertCmd; if (!QKeyValue.FindBoolAttribute(assertion.Attributes, "sourceloc") && !QKeyValue.FindBoolAttribute(assertion.Attributes, "block_sourceloc") && !assertion.Expr.Equals(Expr.True)) { return(true); } } // Speculate invariants if we see an assume that is not a partition; such // an assume is likely user supplied. if (c is AssumeCmd) { AssumeCmd assumption = c as AssumeCmd; if (!QKeyValue.FindBoolAttribute(assumption.Attributes, "partition")) { return(true); } } return(false); }
private bool StartsWithUnconditionalBarrier(Block b, Implementation impl, Block specialExitBlock) { if (verifier.IsKernelProcedure(impl.Proc)) { if (b == impl.Blocks[0]) { // There is a barrier at the very start of the kernel return(true); } if (b == specialExitBlock) { // There is a barrier at the very end of the kernel return(true); } } if (b.Cmds.Count == 0) { return(false); } CallCmd c = b.Cmds[0] as CallCmd; if (c == null || !GPUVerifier.IsBarrier(c.Proc)) { return(false); } var barrierProcedure = c.Proc; if (!verifier.UniformityAnalyser.IsUniform(barrierProcedure.Name)) { // We may be able to do better in this case, but for now we conservatively say no return(false); } if (BarrierHasNonUniformArgument(barrierProcedure)) { // Also we may be able to do better in this case, but for now we conservatively say no return(false); } Debug.Assert(c.Ins.Count() == 2); if (strength == BarrierStrength.GROUP_SHARED || strength == BarrierStrength.ALL) { if (!c.Ins[0].Equals(verifier.IntRep.GetLiteral(1, verifier.IntRep.GetIntType(1)))) { return(false); } } else if (strength == BarrierStrength.GLOBAL || strength == BarrierStrength.ALL) { if (!c.Ins[1].Equals(verifier.IntRep.GetLiteral(1, verifier.IntRep.GetIntType(1)))) { return(false); } } else { // All cases should be covered by the above Debug.Assert(false); } return(true); }
private HashSet <BarrierInterval> ComputeBarrierIntervals(Implementation impl) { HashSet <BarrierInterval> result = new HashSet <BarrierInterval>(); ExtractCommandsIntoBlocks(impl, item => (item is CallCmd && GPUVerifier.IsBarrier(((CallCmd)item).Proc))); Graph <Block> cfg = Program.GraphFromImpl(impl); // If the CFG has no exit nodes, i.e. it cannot terminate, // we bail out; we need a single-entry single-exit CFG // and we cannot get one under such circumstances if (NoExitFromCFG(cfg)) { return(result); } // To make the CFG single-exit, we add a special exit block Block specialExitBlock = new Block(); cfg.Nodes.Add(specialExitBlock); // Now link any existing CFG node that has no successors to the // special exit node. foreach (var b in cfg.Nodes) { if (b == specialExitBlock) { continue; } if (cfg.Successors(b).Count() == 0) { cfg.AddEdge(b, specialExitBlock); } } Graph <Block> dual = cfg.Dual(new Block()); DomRelation <Block> dom = cfg.DominatorMap; DomRelation <Block> pdom = dual.DominatorMap; foreach (var dominator in cfg.Nodes.Where(item => StartsWithUnconditionalBarrier(item, impl, specialExitBlock))) { Block smallestBarrierIntervalEnd = null; foreach (var postdominator in cfg.Nodes .Where(item => item != dominator && StartsWithUnconditionalBarrier(item, impl, specialExitBlock) && dom.DominatedBy(item, dominator) && pdom.DominatedBy(dominator, item))) { if (smallestBarrierIntervalEnd == null || dom.DominatedBy(smallestBarrierIntervalEnd, postdominator)) { smallestBarrierIntervalEnd = postdominator; } else { Debug.Assert(dom.DominatedBy(postdominator, smallestBarrierIntervalEnd)); } } if (smallestBarrierIntervalEnd != null) { result.Add(new BarrierInterval(dominator, smallestBarrierIntervalEnd, dom, pdom, impl)); } } if (GPUVerifyVCGenCommandLineOptions.DebugGPUVerify) { Console.WriteLine("Found " + result.Count() + " barrier interval(s) in " + impl.Name); } return(result); }
private void Analyse(Implementation impl, List <Cmd> cs) { foreach (var c in cs) { if (c is AssignCmd) { AssignCmd assignCmd = c as AssignCmd; for (int i = 0; i != assignCmd.Lhss.Count; i++) { if (assignCmd.Lhss[i] is SimpleAssignLhs) { SimpleAssignLhs lhs = assignCmd.Lhss[i] as SimpleAssignLhs; Expr rhs = assignCmd.Rhss[i]; VariablesOccurringInExpressionVisitor visitor = new VariablesOccurringInExpressionVisitor(); visitor.VisitExpr(rhs); foreach (Variable v in visitor.GetVariables()) { if (!mayBeDerivedFrom[impl.Name].ContainsKey(v.Name)) { continue; } foreach (string s in mayBeDerivedFrom[impl.Name][v.Name]) { if (mayBeDerivedFrom[impl.Name].ContainsKey(lhs.AssignedVariable.Name) && !mayBeDerivedFrom[impl.Name][lhs.AssignedVariable.Name].Contains(s)) { SetMayBeDerivedFrom(impl.Name, lhs.AssignedVariable.Name, s); } } } } } } else if (c is CallCmd) { CallCmd callCmd = c as CallCmd; if (QKeyValue.FindBoolAttribute(callCmd.Proc.Attributes, "barrier_invariant") || QKeyValue.FindBoolAttribute(callCmd.Proc.Attributes, "binary_barrier_invariant")) { foreach (Expr param in callCmd.Ins) { ExprMayAffectControlFlow(impl.Name, param); } } else if (!GPUVerifier.IsBarrier(callCmd.Proc)) { Implementation CalleeImplementation = verifier.GetImplementation(callCmd.callee); if (CalleeImplementation != null) { for (int i = 0; i < CalleeImplementation.InParams.Count(); i++) { VariablesOccurringInExpressionVisitor visitor = new VariablesOccurringInExpressionVisitor(); visitor.VisitExpr(callCmd.Ins[i]); foreach (Variable v in visitor.GetVariables()) { if (!mayBeDerivedFrom[impl.Name].ContainsKey(v.Name)) { continue; } foreach (string s in mayBeDerivedFrom[impl.Name][v.Name]) { if (!mayBeDerivedFrom[callCmd.callee][CalleeImplementation.InParams[i].Name].Contains(s)) { SetMayBeDerivedFrom(callCmd.callee, CalleeImplementation.InParams[i].Name, s); } } } } for (int i = 0; i < CalleeImplementation.OutParams.Count(); i++) { foreach (string s in mayBeDerivedFrom[callCmd.callee][CalleeImplementation.OutParams[i].Name]) { if (!mayBeDerivedFrom[impl.Name][callCmd.Outs[i].Name].Contains(s)) { SetMayBeDerivedFrom(impl.Name, callCmd.Outs[i].Name, s); } } } } } } else if (c is AssumeCmd) { var assumeCmd = c as AssumeCmd; ExprMayAffectControlFlow(impl.Name, assumeCmd.Expr); } else if (c is AssertCmd) { var assertCmd = c as AssertCmd; ExprMayAffectControlFlow(impl.Name, assertCmd.Expr); } } }