protected override ProgTransformation.PersistentProgram recordOutput(Program p) { CBAProgram ap = p as CBAProgram; Debug.Assert(ap != null); return(ap.getPersistentVersion()); }
public override CBAProgram runCBAPass(CBAProgram inp) { if (cp == null) { return(null); } cp.setInput(input); return(cp.runCBAPass(inp)); }
protected override Program runPass(Program inp) { CBAProgram ap = inp as CBAProgram; Debug.Assert(ap != null); CBAProgram ret = runCBAPass(ap); return(ret as Program); }
// Remove all procs in "procsToRemove" from the program, and replace calls to these procedures by // assume false public static PersistentCBAProgram prune(PersistentCBAProgram pprogram, HashSet <string> procsToRemove) { if (procsToRemove.Count == 0) { return(pprogram); } // Go through all Commands and remove calls CBAProgram program = pprogram.getCBAProgram(); foreach (var decl in program.TopLevelDeclarations) { if (!(decl is Implementation)) { continue; } var impl = decl as Implementation; foreach (Block blk in impl.Blocks) { for (int i = 0; i < blk.Cmds.Count; i++) { if (isCall(blk.Cmds[i], procsToRemove)) { blk.Cmds[i] = new AssumeCmd(Token.NoToken, Expr.False); } } } } // Remove declarations and implementations var newDecls = new List <Declaration>(); foreach (var decl in program.TopLevelDeclarations) { if (decl is Implementation) { if (procsToRemove.Contains((decl as Implementation).Name)) { continue; } } else if (decl is Procedure) { if (procsToRemove.Contains((decl as Procedure).Name)) { continue; } } newDecls.Add(decl); } program.TopLevelDeclarations = newDecls; return(new PersistentCBAProgram(program, program.mainProcName, program.contextBound)); }
private void doInlining(CBAProgram p) { inlineInput = new PersistentCBAProgram(p, p.mainProcName, p.contextBound); // Temporary fix for Boogie's bug while inlining calls // that have don't care expressions. This does not change the control // structure nor the number of commands per block -- hence, this transformation // need not be recorded. RewriteCallDontCares rdc = new RewriteCallDontCares(); rdc.VisitProgram(p); // Copy of OnlyBoogie.EliminateDeadVariablesAndInline var TopLevelDeclarations = p.TopLevelDeclarations; bool inline = false; foreach (Declaration d in TopLevelDeclarations) { if ((d is Procedure || d is Implementation) && d.FindExprAttribute("inline") != null) { inline = true; } } if (inline) { foreach (Declaration d in TopLevelDeclarations) { Implementation impl = d as Implementation; if (impl != null) { impl.OriginalBlocks = impl.Blocks; impl.OriginalLocVars = impl.LocVars; } } foreach (Declaration d in TopLevelDeclarations) { Implementation impl = d as Implementation; if (impl != null && !impl.SkipVerification) { Inliner.ProcessImplementation(p as Program, impl); } } foreach (Declaration d in TopLevelDeclarations) { Implementation impl = d as Implementation; if (impl != null) { impl.OriginalBlocks = null; impl.OriginalLocVars = null; } } } }
public override CBAProgram runCBAPass(CBAProgram inp) { if (unrollNum < 0) { return(null); } else { inp.UnrollLoops(unrollNum, false); } return(inp); }
public override CBAProgram runCBAPass(CBAProgram p) { foreach (var decl in p.TopLevelDeclarations) { var impl = decl as Implementation; if (impl == null) { continue; } compile(impl); } return(p); }
public override CBAProgram runCBAPass(CBAProgram p) { // Type information is needed in some cases. For instance, the Command // Mem[x] := untracked-expr is converted to havoc temp; Mem[x] := temp. Here // we need the type of "untracked-expr" or of "Mem[x]" if (p.Typecheck() != 0) { p.Emit(new TokenTextWriter("error.bpl")); throw new InternalError("Type errors"); } vslice.VisitProgram(p as Program); BoogieUtil.DoModSetAnalysis(p); return(p); }
public override CBAProgram runCBAPass(CBAProgram p) { // Set the input for the first pass, just in case passes[0].setInput(input); CBAProgram curr = p; CBAProgram next = null; for (int i = 0; i < passes.Count; i++) { next = passes[i].runCBAPass(curr); curr = (next == null) ? curr : next; } return(next); }
public override CBAProgram runCBAPass(CBAProgram p) { // Eliminate dead variables UnusedVarEliminator.Eliminate(p as Program); // Add the inlining bound addInlineAttribute(p); // Inline doInlining(p); // Remove the inlined procedures & implementations removeInlinedProcs(p); // Remove annotations that won't parse because of dropped variables RemoveVarsFromAttributes.Prune(p); return(p); }
private void addInlineAttribute(CBAProgram p) { foreach (var impl in p.TopLevelDeclarations.OfType <Implementation>()) { if (QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint")) { continue; } var proc = impl.Proc; var newattr = BoogieUtil.removeAttr("inline", proc.Attributes); Expr num = Expr.Literal(bound); var val = new List <object>(); val.Add(num); proc.Attributes = new QKeyValue(Token.NoToken, "inline", val, newattr); } }
private void removeInlinedProcs(CBAProgram program) { HashSet <string> procsToRemove = new HashSet <string>(); foreach (var decl in program.TopLevelDeclarations) { if (decl is Procedure) { if (decl.FindExprAttribute("inline") != null) { procsToRemove.Add((decl as Procedure).Name); } } } // Make sure we're not removing main procsToRemove.Remove(program.mainProcName); // Remove procs and Impls var newDecls = new List <Declaration>(); foreach (var decl in program.TopLevelDeclarations) { if (decl is Procedure) { if (procsToRemove.Contains((decl as Procedure).Name)) { continue; } } else if (decl is Implementation) { if (procsToRemove.Contains((decl as Implementation).Name)) { continue; } } newDecls.Add(decl); } program.TopLevelDeclarations = newDecls; }
// Returns all backedges of the call graph (i.e., a cutset in terms of edges) private HashSet <Tuple <string, string> > findRecursiveProcs(CBAProgram p) { var ret = new HashSet <Tuple <string, string> >(); Graph <string> callGraph = new Graph <string>(); callGraph.AddSource(p.mainProcName); foreach (var decl in p.TopLevelDeclarations) { var impl = decl as Implementation; if (impl == null) { continue; } foreach (var blk in impl.Blocks) { foreach (Cmd cmd in blk.Cmds) { var ccmd = cmd as CallCmd; if (ccmd == null) { continue; } callGraph.AddEdge(impl.Name, ccmd.callee); } } } // Do DFS to find a cutset // 0: white, 1: gray, 2: black var color = new Dictionary <string, int>(); foreach (var n in callGraph.Nodes) { color.Add(n, 0); } dfs(callGraph, p.mainProcName, color, ret); return(ret); }
public override CBAProgram runCBAPass(CBAProgram p) { if (p.mode == ConcurrencyMode.FixedContext) { InstrumentationConfig.addRaiseException = false; } // Step1: Gather program information pinfo = new ProgramInfo(p.mainProcName, p, LanguageSemantics.assertNotReachableName()); TidArithmetic.reset(); if (pinfo.threadIdType.IsBv) { TidArithmetic.useIntArithmetic = false; p.AddTopLevelDeclaration(TidArithmetic.getBvAdd()); p.AddTopLevelDeclaration(TidArithmetic.getBvGt()); } else { TidArithmetic.useIntArithmetic = true; } // Step2: Set up a variable manager vmgr = new VariableManager(pinfo); // Step3: Set up the instrumentation policy // The globals not to instrument are: // -- ones not modified by any procedure // -- ones not shared // -- ones to treat as thread-local HashSet <string> globalsToInstrument = new HashSet <string>(); foreach (var g in pinfo.declaredGlobals) { string name = g.Key; if (!pinfo.modifiedGlobals.ContainsKey(name)) { continue; } if (!LanguageSemantics.isShared(name)) { continue; } if (pinfo.threadLocalGlobals.ContainsKey(name)) { continue; } globalsToInstrument.Add(name); } var rprocs = findRecursiveProcs(p); //foreach (var be in rprocs) Console.WriteLine("{0} -> {1}", be.Item1, be.Item2); policy = new InstrumentationPolicy(p.contextBound, globalsToInstrument, pinfo.procsWithImplementation, pinfo.asyncProcs, rprocs, p.mode); //policy.print(Log.getWriter(Log.Debug)); // Step4: Split program declarations based on the instrumentation policy // skipping this step (not needed for basic CBA reduction) // Step5: Carry out the K-split instrumentation inst = new Instrumenter(policy, vmgr, pinfo, tinfo_instrument); List <Declaration> newDecls = inst.instrument(p.TopLevelDeclarations.ToList()); foreach (var trp in inst.blocksWithFixedK) { blockExecutionContextMap.Add(trp.fst + "::" + trp.snd, trp.trd); } // Step6: Instrument main with initialization and the Checker Implementation mainProcImpl = BoogieUtil.findProcedureImpl(newDecls, p.mainProcName); inst.instrumentGivenMainImpl(mainProcImpl); // Step7: Instrument Async calls bool instrumentedAsync = false; InstrumentAsyncCalls ainst = new InstrumentAsyncCalls(vmgr, pinfo, tinfo_async); foreach (var decl in newDecls) { if (decl is Implementation) { ainst.VisitImplementation(decl as Implementation); instrumentedAsync = instrumentedAsync || ainst.hasAsync; } } if (!instrumentedAsync) { Log.WriteLine(Log.Debug, "Warning: Did not find any async call"); } // Step8: Set entrypoint mainProcImpl.AddAttribute("entrypoint"); // Step9: Add new variable declarations newDecls.AddRange(vmgr.getNewDeclarations(policy.executionContextBound)); newDecls.AddRange(BoogieAstFactory.newDecls); BoogieAstFactory.newDecls.Clear(); // Thats it. Program ret = new Program(); ret.TopLevelDeclarations = newDecls; if (InstrumentationConfig.printInstrumented) { // Re-resolve ret ProgTransformation.PersistentProgram tprog = new ProgTransformation.PersistentProgram(ret); var instrumented = tprog.getProgram(); // Re-do the modsets -- make them as concise as possible. BoogieUtil.DoModSetAnalysis(instrumented); // Temporary fix for Boogie's bug while inlining calls // that have don't care expressions. RewriteCallDontCares rdc = new RewriteCallDontCares(); rdc.VisitProgram(instrumented); BoogieUtil.PrintProgram(instrumented, InstrumentationConfig.instrumentedFile); throw new NormalExit("Printed " + InstrumentationConfig.instrumentedFile); } // Resolve the program (Do not typecheck because that does inlining). //BoogieUtil.PrintProgram(ret, "instrumented.bpl"); //ret = BoogieUtil.ReadAndOnlyResolve("instrumented.bpl"); if (p.mode == ConcurrencyMode.FixedContext) { InstrumentationConfig.addRaiseException = true; } p = new CBAProgram(ret, p.mainProcName, p.contextBound); return(p); }
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); }
public override CBAProgram runCBAPass(CBAProgram p) { rcc.VisitProgram(p as Program); return(p); }
public override CBAProgram runCBAPass(CBAProgram p) { if (!aggressive) { return(null); } var procsWithAsserts = procsWithAssertions(p); HashSet <string> procsToDelete = new HashSet <string>(); // Gather the set of procedures to delete foreach (Declaration d in p.TopLevelDeclarations) { if (d is Procedure) { var proc = d as Procedure; if (proc.Name.Equals(p.mainProcName)) { continue; } if (procsWithAsserts.Contains(proc.Name)) { continue; } if (proc.OutParams.Count > 0) { continue; } var modifiesShared = false; foreach (IdentifierExpr ie in proc.Modifies) { if (LanguageSemantics.isShared(ie.Decl.Name)) { modifiesShared = true; break; } } if (!modifiesShared) { procsToDelete.Add(proc.Name); } } } // Delete the implementations CBAProgram ret = new CBAProgram(new Program(), p.mainProcName, p.contextBound); foreach (Declaration d in p.TopLevelDeclarations) { if (d is Implementation) { Implementation impl = d as Implementation; if (procsToDelete.Contains(impl.Name) && !BoogieUtil.hasAssert(impl)) { Log.WriteLine(Log.Debug, "Deleting " + impl.Name); continue; } ret.AddTopLevelDeclaration(d); } else { ret.AddTopLevelDeclaration(d); } } Log.WriteLine(Log.Debug, "Empty Mod Sets: Deleted " + (p.TopLevelDeclarations.Count() - ret.TopLevelDeclarations.Count()).ToString() + " implementations"); return(ret); }
public override CBAProgram runCBAPass(CBAProgram p) { if (unrollNum >= 0) { return(base.runCBAPass(p)); } foreach (var impl in BoogieUtil.GetImplementations(p)) { impl.PruneUnreachableBlocks(); } // save RB var rb = CommandLineOptions.Clo.RecursionBound; if (BoogieVerify.irreducibleLoopUnroll >= 0) { CommandLineOptions.Clo.RecursionBound = BoogieVerify.irreducibleLoopUnroll; } var procsWithIrreducibleLoops = new HashSet <string>(); var passInfo = p.ExtractLoops(out procsWithIrreducibleLoops); // restore RB CommandLineOptions.Clo.RecursionBound = rb; // no loops found, then this transformation is identity if (passInfo.Count == 0 && procsWithIrreducibleLoops.Count == 0) { return(null); } if (addUniqueCallLabels) { // annotate calls with a unique number var addIds = new AddUniqueCallIds(); // Loop unrolling is done for procs with irreducible loops. // This simply copies Cmd objects. Duplicate them to remove // aliasing foreach (var impl in p.TopLevelDeclarations .OfType <Implementation>() .Where(impl => procsWithIrreducibleLoops.Contains(impl.Name))) { var dup = new FixedDuplicator(true); foreach (var blk in impl.Blocks) { blk.Cmds = dup.VisitCmdSeq(blk.Cmds); } } // Add labels again to all procedures foreach (var impl in p.TopLevelDeclarations .OfType <Implementation>()) { addIds.VisitImplementation(impl); } } info = new Dictionary <string, Dictionary <string, string> >(); passInfo.Iter(kvp => { info.Add(kvp.Key, new Dictionary <string, string>()); kvp.Value.Iter(sb => info[kvp.Key].Add(sb.Key, sb.Value.Label)); }); // Construct the set of procs in the original program // and the loop procedures allProcs = new HashSet <string>(); loopProcs = new HashSet <string>(); foreach (var decl in p.TopLevelDeclarations) { var impl = decl as Implementation; if (impl == null) { continue; } allProcs.Add(impl.Name); if (impl.Proc is LoopProcedure) { loopProcs.Add(impl.Name); impl.Proc.AddAttribute("LoopProcedure"); } } //foreach (var impl in BoogieUtil.GetImplementations(p)) //{ //removeAssumeFalseBlocks(impl); //} // Optimization: if no loop is found, then no need to print // out a new program if (loopProcs.Count == 0) { return(null); } // Remove vars from attributes that are not in scope anymore RemoveVarsFromAttributes.Prune(p); return(p); }
public override CBAProgram runCBAPass(CBAProgram p) { // Run verification, gather traces var verifier = getVerifier(); verifier.run(input); // Set verification result success = verifier.success; traces = verifier.traces; // Now compute coverage, provided error was not reached if (!verifier.success) { return(null); } // Gather procedure names var nameImplMap = BoogieUtil.nameImplMapping(p); var allProcs = new HashSet <string>(); foreach (var tp in nameImplMap) { allProcs.Add(tp.Key); } procsNotCovered = new HashSet <string>(); procsNotCovered.UnionWith(allProcs); procsNotCovered.Remove(p.mainProcName); // Iterate and gather procedures that can be reached int oldProverLimit = CommandLineOptions.Clo.ProverCCLimit; var done = false; do { // Set the number of traces returned by boogie in one shot CommandLineOptions.Clo.ProverCCLimit = procsNotCovered.Count(); var covered = iterateComputation(input as PersistentCBAProgram, procsNotCovered); if (covered.Count == 0) { done = true; } else { procsNotCovered = HashSetExtras <string> .Difference(procsNotCovered, covered); if (!procsNotCovered.Any()) { done = true; } } } while (!done); CommandLineOptions.Clo.ProverCCLimit = oldProverLimit; return(null); }
// Short-circuit the chain of returns produced by raiseException public void optimizeRaiseExceptionInstrumentation(CBAProgram program) { var procMap = BoogieUtil.nameImplMapping(program); var mainImpl = procMap[program.mainProcName]; var labelBlockMap = BoogieUtil.labelBlockMapping(mainImpl); // For each block, check if the first statement is "assume raiseException" foreach (var blk in mainImpl.Blocks) { if (blk.Cmds.Count == 0) { continue; } var cmd = blk.Cmds[0]; if (!(cmd is AssumeCmd)) { continue; } var expr = (cmd as AssumeCmd).Expr; if (expr is IdentifierExpr) { var v = (expr as IdentifierExpr).Decl; if (v.Name != "raiseException") { continue; } } else { continue; } // Yup, its "assume raiseException" -- follow the chain of gotos through empty blocks var lab = getSingleSucc(blk.TransferCmd); if (lab == null) { continue; } var b = labelBlockMap[lab]; var chainLen = 0; /* Heuristic, possibly unsound: some blocks have a single statement that contains * an assignment for the return value. Note that once raiseException has been raised, * no return value is needed. */ while (b.Cmds.Count <= 1) { var next = getSingleSucc(b.TransferCmd); if (next == null) { break; } lab = next; b = labelBlockMap[lab]; chainLen++; } blk.TransferCmd = BoogieAstFactory.MkGotoCmd(lab); if (chainLen != 0) { Log.WriteLine(Log.Debug, "raiseException chain shortened by " + chainLen.ToString()); } } }
abstract public CBAProgram runCBAPass(CBAProgram p);
public override CBAProgram runCBAPass(CBAProgram p) { compressBlocks.VisitProgram(p); return(p); }
public override CBAProgram runCBAPass(CBAProgram p) { procsOnEP = new HashSet <string>(); var nameImplMap = BoogieUtil.nameImplMapping(p); // Set of all procedures (with an implementation) var allProcs = new HashSet <string>(); foreach (var tp in nameImplMap) { allProcs.Add(tp.Key); } var verifier = getVerifier(); // Run verification, gather traces verifier.run(input); // Set verification result success = verifier.success; traces = verifier.traces; // Now, compute the error projection if (verifier.success) { ErrorProjection = allProcs; return(null); } // Look at all procedures that lie on the error trace foreach (var trace in verifier.traces) { procsOnEP.UnionWith(trace.getProcs()); } Log.WriteLine(Log.Normal, string.Format("EP: Got {0} traces and {1} procs", verifier.traces.Count, procsOnEP.Count)); // Just make sure that we inlcude main here (probably not necessary) procsOnEP.Add(p.mainProcName); // Have we already covered all of the program? if (procsOnEP.Equals(allProcs)) { ErrorProjection = new HashSet <string>(); return(null); } // Iterate and try to force the verifier to return paths in // different procedures var done = false; do { var moreProcs = iterateComputation(input as PersistentCBAProgram, HashSetExtras <string> .Difference(allProcs, procsOnEP)); if (moreProcs.Count == 0) { done = true; } else { procsOnEP.UnionWith(moreProcs); if (procsOnEP.Equals(allProcs)) { done = true; } } } while (!done); ErrorProjection = HashSetExtras <string> .Difference(allProcs, procsOnEP); return(null); }
public static Dictionary <string, int> Compute(CBAProgram program, int max, List <string> Annotations, BoogieVerifyOptions options) { var loopBounds = new Dictionary <string, int>(); Initialize(Annotations); maxBound = max; var start = DateTime.Now; // remove non-free ensures and requires program.TopLevelDeclarations.OfType <Procedure>() .Iter(proc => proc.Ensures = proc.Ensures.Filter(en => en.Free)); program.TopLevelDeclarations.OfType <Procedure>() .Iter(proc => proc.Requires = proc.Requires.Filter(en => en.Free)); // remove assertions program.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => impl.Blocks .Iter(blk => blk.Cmds = blk.Cmds.Map(c => { var ac = c as AssertCmd; if (ac == null) { return(c); } return(new AssumeCmd(ac.tok, /*ac.Expr*/ Expr.True, ac.Attributes)); }))); // delete yield program.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => impl.Blocks .Iter(blk => blk.Cmds.RemoveAll(c => c is YieldCmd))); // Call graph ComputeCallGraph(program); // Gather the set of implementations with "loop" inside their name var allLoopImpls = new List <Implementation>(); program.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => { if (impl.Name.Contains("loop")) { allLoopImpls.Add(impl); } }); // Prune to the right form var loopImpls = allLoopImpls.Filter(CheckImpl); #region Process user annotations // Include user anntations var allLoops = new HashSet <string>(); loopImpls.Iter(impl => allLoops.Add(impl.Name)); foreach (var sp in UserAnnotations .Where(s => s.StartsWith("LB:")) .Select(s => s.Split(':')) .Where(sp => sp.Length == 3)) { // grab bound var bound = 0; if (!Int32.TryParse(sp[2], out bound)) { continue; } // grab proc if (!allLoops.Contains(sp[1])) { continue; } loopBounds[sp[1]] = bound; Console.WriteLine("LB: Loop {0} requires minimum {1} iterations (annotated)", sp[1], bound); } loopImpls = loopImpls.Filter(impl => !loopBounds.ContainsKey(impl.Name)); #endregion if (loopImpls.Count == 0) { return(loopBounds); } // Prepare query var query = PrepareQuery(loopImpls, program); // Set general options BoogieVerify.options = options; // Set rec. bound var oldBound = CommandLineOptions.Clo.RecursionBound; CommandLineOptions.Clo.RecursionBound = maxBound; // Query var allErrors = new List <BoogieErrorTrace>(); BoogieVerify.Verify(query, out allErrors); foreach (var trace in allErrors) { var loopName = QKeyValue.FindStringAttribute(trace.impl.Attributes, "LB_Mapping"); var bound = RecBound(loopName, trace.cex, trace.impl.Name); if (bound <= 1) { continue; } loopBounds.Add(loopName, bound); Console.WriteLine("LB: Loop {0} requires minimum {1} iterations", loopName, bound); } CommandLineOptions.Clo.RecursionBound = oldBound; timeTaken = (DateTime.Now - start); return(loopBounds); }