Example #1
0
        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);
        }
Example #3
0
        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);
        }
Example #4
0
        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);
        }
Example #5
0
        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);
                }
            }
        }