// 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); }
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); }