// Adds a new main:
        //   assertsPassed := true;
        //   call main();
        //   assert assertsPassed;
        string addMain(CBAProgram program)
        {
            var dup      = new FixedDuplicator();
            var origMain = BoogieUtil.findProcedureImpl(program.TopLevelDeclarations, program.mainProcName);
            var newMain  = dup.VisitImplementation(origMain);
            var newProc  = dup.VisitProcedure(origMain.Proc);

            newMain.Name += "_SeqInstr";
            newProc.Name += "_SeqInstr";
            newMain.Proc  = newProc;

            var mainIns = new List <Expr>();

            foreach (Variable v in newMain.InParams)
            {
                mainIns.Add(Expr.Ident(v));
            }
            var mainOuts = new List <IdentifierExpr>();

            foreach (Variable v in newMain.OutParams)
            {
                mainOuts.Add(Expr.Ident(v));
            }

            var callMain = new CallCmd(Token.NoToken, program.mainProcName, mainIns, mainOuts);

            callMain.Proc = origMain.Proc;

            var cmds = new List <Cmd>();

            cmds.Add(BoogieAstFactory.MkVarEqConst(assertsPassed, true));
            cmds.Add(callMain);
            cmds.Add(new AssertCmd(Token.NoToken, Expr.Ident(assertsPassed)));

            var blk = new Block(Token.NoToken, "start", cmds, new ReturnCmd(Token.NoToken));

            newMain.Blocks = new List <Block>();
            newMain.Blocks.Add(blk);

            program.AddTopLevelDeclaration(newProc);
            program.AddTopLevelDeclaration(newMain);

            program.mainProcName = newMain.Name;

            // Set entrypoint
            origMain.Attributes      = BoogieUtil.removeAttr("entrypoint", origMain.Attributes);
            origMain.Proc.Attributes = BoogieUtil.removeAttr("entrypoint", origMain.Proc.Attributes);

            newMain.AddAttribute("entrypoint");

            return(newMain.Name);
        }
Beispiel #2
0
        public override CBAProgram runCBAPass(CBAProgram program)
        {
            var nameImplMap = BoogieUtil.nameImplMapping(program);

            // Construct call graph, compute SCCs
            var graph = new Graph <string>();

            foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>())
            {
                impl.Blocks.Iter(block =>
                                 block.Cmds.OfType <CallCmd>().Iter(cmd =>
                                                                    graph.AddEdge(impl.Name, cmd.callee)));
            }
            graph.AddSource(program.mainProcName);
            var preds = new Adjacency <string>(st => graph.Predecessors(st));
            var succs = new Adjacency <string>(st => graph.Successors(st));
            var sccs  = new StronglyConnectedComponents <string>(graph.Nodes, preds, succs);

            sccs.Compute();

            //var dotFileCnt = 1;

            // For each SCC, compute backedges
            foreach (var scc in sccs)
            {
                if (scc.Count == 1)
                {
                    var onlyProc = scc.First();
                    if (nameImplMap.ContainsKey(onlyProc) && QKeyValue.FindBoolAttribute(nameImplMap[onlyProc].Attributes, "LoopProcedure"))
                    {
                        continue;
                    }

                    if (graph.Successors(onlyProc).All(callee => callee != onlyProc))
                    {
                        continue;
                    }
                }

                Console.Write("Considering SCC: ");
                scc.Iter(s => Console.Write("{0} ", s));
                Console.WriteLine();

                foundRecursion = true;

                // pick source
                var sccProcs = new HashSet <string>(scc);
                var src      = scc.FirstOrDefault(proc => graph.Predecessors(proc).Any(pred => !sccProcs.Contains(pred)));
                if (src == null)
                {
                    src = scc.First();
                }

                var grey  = new HashSet <string>();
                var black = new HashSet <string>();
                grey.Add(src);

                backedges     = new HashSet <Tuple <string, string> >();
                dfsTreeParent = new Dictionary <string, string>();
                someCycles    = new List <HashSet <string> >();

                dfs(graph, src, sccProcs, grey, black);

                InferWhatToCut(graph, scc);

                // create copies
                var procCopies = new Dictionary <Tuple <string, int>, Procedure>();
                var implCopies = new Dictionary <Tuple <string, int>, Implementation>();
                foreach (var name in scc)
                {
                    var impl = nameImplMap[name];
                    program.RemoveTopLevelDeclaration(impl);
                    program.RemoveTopLevelDeclaration(impl.Proc);

                    for (int i = 0; i < CommandLineOptions.Clo.RecursionBound; i++)
                    {
                        var dup   = new FixedDuplicator(true);
                        var nimpl = dup.VisitImplementation(impl);
                        var nproc = dup.VisitProcedure(impl.Proc);

                        nimpl.Name += string.Format("#{0}", i);
                        nproc.Name += string.Format("#{0}", i);
                        nimpl.Proc  = nproc;

                        program.AddTopLevelDeclaration(nimpl);
                        program.AddTopLevelDeclaration(nproc);

                        procCopies.Add(Tuple.Create(impl.Name, i), nproc);
                        implCopies.Add(Tuple.Create(impl.Name, i), nimpl);
                    }
                }

                // redirect calls
                foreach (var name in scc)
                {
                    foreach (var pred in graph.Predecessors(name))
                    {
                        if (sccProcs.Contains(pred))
                        {
                            continue;
                        }
                        var pimpl = nameImplMap[pred];
                        foreach (var blk in pimpl.Blocks)
                        {
                            var newcmds = new List <Cmd>();
                            foreach (var cmd in blk.Cmds)
                            {
                                var ccmd = cmd as CallCmd;
                                if (ccmd == null || !sccProcs.Contains(ccmd.callee))
                                {
                                    newcmds.Add(cmd);
                                    continue;
                                }
                                newcmds.Add(
                                    new CallCmd(ccmd.tok, ccmd.callee + string.Format("#{0}", CommandLineOptions.Clo.RecursionBound - 1),
                                                ccmd.Ins, ccmd.Outs, ccmd.Attributes, ccmd.IsAsync));
                            }
                            blk.Cmds = newcmds;
                        }
                    }

                    for (int i = 0; i < CommandLineOptions.Clo.RecursionBound; i++)
                    {
                        var impl = implCopies[Tuple.Create(name, i)];
                        foreach (var blk in impl.Blocks)
                        {
                            var newcmds = new List <Cmd>();
                            foreach (var cmd in blk.Cmds)
                            {
                                var ccmd = cmd as CallCmd;
                                if (ccmd == null || !sccProcs.Contains(ccmd.callee))
                                {
                                    newcmds.Add(cmd);
                                    continue;
                                }
                                var cnt = i;
                                if (CutEdge(name, ccmd.callee))
                                {
                                    cnt--;
                                }

                                if (cnt < 0)
                                {
                                    newcmds.Add(new AssumeCmd(Token.NoToken, Expr.False));
                                }
                                else
                                {
                                    newcmds.Add(new CallCmd(ccmd.tok, ccmd.callee + string.Format("#{0}", cnt),
                                                            ccmd.Ins, ccmd.Outs, ccmd.Attributes, ccmd.IsAsync));
                                }
                            }
                            blk.Cmds = newcmds;
                        }
                    }
                }
            }

            return(program);
        }
        private static Program PrepareQuery(IEnumerable <Implementation> loopImpls, Program program)
        {
            // Sometimes loops have multiple backedges, hence multiple recursive calls: merge them
            loopImpls.Iter(impl => mergeRecCalls(impl));

            var dup = new FixedDuplicator(true);
            // Make copies of loopImpl procs
            var loopProcsCopy = new Dictionary <string, Procedure>();

            loopImpls
            .Iter(impl => loopProcsCopy.Add(impl.Name, dup.VisitProcedure(impl.Proc)));

            loopProcsCopy.Values.Iter(proc => proc.Name += "_PassiveCopy");

            // Make copies of the caller implementations
            var loopCallerImplCopy = new Dictionary <string, Implementation>();
            var loopCallerProcCopy = new Dictionary <string, Procedure>();

            loopImpls
            .Iter(impl => loopCallerImplCopy.Add(impl.Name, dup.VisitImplementation(loopCaller[impl.Name])));

            loopImpls
            .Iter(impl => loopCallerProcCopy.Add(impl.Name, dup.VisitProcedure(loopCaller[impl.Name].Proc)));

            loopCallerImplCopy
            .Iter(kvp => kvp.Value.Name += "_EntryCopy_" + kvp.Key);

            loopCallerProcCopy
            .Iter(kvp => kvp.Value.Name += "_EntryCopy_" + kvp.Key);

            loopCallerImplCopy
            .Iter(kvp => kvp.Value.Proc = loopCallerProcCopy[kvp.Key]);

            // Instrument callers
            foreach (var kvp in loopCallerImplCopy)
            {
                var impl = kvp.Value;

                var av = BoogieAstFactory.MkLocal("LoopBound_AssertVar", Microsoft.Boogie.Type.Bool);
                impl.LocVars.Add(av);

                // av := true
                var init     = BoogieAstFactory.MkVarEqConst(av, true);
                var initCmds = new List <Cmd>();
                initCmds.Add(init);
                initCmds.AddRange(impl.Blocks[0].Cmds);
                impl.Blocks[0].Cmds = initCmds;

                // av := false
                foreach (var blk in impl.Blocks)
                {
                    var newCmds = new List <Cmd>();
                    for (int i = 0; i < blk.Cmds.Count; i++)
                    {
                        // disable assertions
                        if (blk.Cmds[i] is AssertCmd && !BoogieUtil.isAssertTrue(blk.Cmds[i]))
                        {
                            newCmds.Add(new AssumeCmd(Token.NoToken, (blk.Cmds[i] as AssertCmd).Expr));
                            continue;
                        }
                        var cc = blk.Cmds[i] as CallCmd;
                        if (cc != null && cc.callee == kvp.Key)
                        {
                            newCmds.Add(blk.Cmds[i]);
                            newCmds.Add(BoogieAstFactory.MkVarEqConst(av, false));
                        }
                        else if (cc != null && loopProcsCopy.ContainsKey(cc.callee))
                        {
                            var ncc = new CallCmd(cc.tok, loopProcsCopy[cc.callee].Name, cc.Ins, cc.Outs, cc.Attributes, cc.IsAsync);
                            ncc.Proc = loopProcsCopy[cc.callee];
                            newCmds.Add(ncc);
                        }
                        else
                        {
                            newCmds.Add(blk.Cmds[i]);
                        }
                    }
                    blk.Cmds = newCmds;
                }

                // assert av
                impl.Blocks
                .Where(blk => blk.TransferCmd is ReturnCmd)
                .Iter(blk => blk.Cmds.Add(new AssertCmd(Token.NoToken, Expr.Ident(av))));
            }

            // Prepare program
            var ret = new Program();

            program.TopLevelDeclarations
            .Where(decl => !(decl is Implementation))
            .Iter(decl => ret.AddTopLevelDeclaration(decl));

            loopProcsCopy.Values
            .Iter(decl => ret.AddTopLevelDeclaration(decl));

            loopCallerImplCopy.Values
            .Iter(decl => ret.AddTopLevelDeclaration(decl));

            loopCallerProcCopy.Values
            .Iter(decl => ret.AddTopLevelDeclaration(decl));

            loopImpls
            .Iter(impl => ret.AddTopLevelDeclaration(impl));

            loopCallerImplCopy.Values
            .Iter(impl => impl.AddAttribute("entrypoint"));

            // Store mapping: entrypoint -> loop
            loopImpls
            .Select(loop => Tuple.Create(loop, loopCallerImplCopy[loop.Name]))
            .Iter(tup => tup.Item2.AddAttribute("LB_Mapping", tup.Item1.Name));

            ret = BoogieUtil.ReResolveInMem(ret);

            return(ret);
        }
Beispiel #4
0
        // Split on the postconditions of procedure "proc"
        // 1. only retain its postconditions; make everything else as assumes
        // 2. drop the implementation of the procedure
        // 3. convert calls to itself to calls to a fake procedure with assumed postconditions
        static Program SplitOnProcedure(Program program, string proc)
        {
            var dup = new FixedDuplicator();

            program = dup.VisitProgram(program);
            program = BoogieUtil.ReResolveInMem(program, true);

            var            toremove = new HashSet <Implementation>();
            Implementation procimpl = null;

            foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>())
            {
                if (impl.Name == proc)
                {
                    procimpl = impl;
                    continue;
                }

                if (impl.Proc.Ensures.All(ens => ens.Free))
                {
                    continue;
                }

                var newens = new List <Ensures>();
                impl.Proc.Ensures.Iter(ens => newens.Add(new Ensures(ens.tok, true, ens.Condition, ens.Comment)));
                impl.Proc.Ensures = newens;
                toremove.Add(impl);
            }

            program.RemoveTopLevelDeclarations(decl => decl is Implementation && toremove.Contains(decl));

            if (procimpl != null)
            {
                // create copy
                var proccopy = dup.VisitProcedure(procimpl.Proc);
                proccopy.Name += "_dup";

                // make assumes
                var newens = new List <Ensures>();
                proccopy.Ensures.Iter(ens => newens.Add(new Ensures(ens.tok, true, ens.Condition, ens.Comment)));
                proccopy.Ensures = newens;

                foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>())
                {
                    foreach (var blk in impl.Blocks)
                    {
                        for (int i = 0; i < blk.Cmds.Count; i++)
                        {
                            var ccmd = blk.Cmds[i] as CallCmd;
                            if (ccmd == null || ccmd.callee != procimpl.Name)
                            {
                                continue;
                            }
                            blk.Cmds[i] = new CallCmd(ccmd.tok, proccopy.Name, ccmd.Ins, ccmd.Outs, ccmd.Attributes);
                        }
                    }
                }

                program.AddTopLevelDeclaration(proccopy);
            }

            return(program);
        }