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 (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); }
// -- There should be no ensures and requires on shared globals // -- For ensures and requires on non-shared globals, they should be "free" // -- One cannot use "old" versions of shared globals private static void checkProc(Procedure proc, HashSet <string> procsWithImpl, HashSet <string> procsNotCalled) { VarsUsed used = new VarsUsed(); foreach (Requires re in proc.Requires) { used.reset(); used.Visit(re.Condition); if (used.globalsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Requires has a shared global"); } if (used.oldVarsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Requires has an \"old\" shared global"); } if (used.globalsUsed.Count == 0) { continue; } // We dont care about requires on pros that are not called if (procsNotCalled.Contains(proc.Name)) { continue; } if (re.Free == false) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("A non-free requires has a non-shared global (not yet supported)"); } } foreach (Ensures re in proc.Ensures) { used.reset(); used.Visit(re.Condition); if (used.globalsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Ensures has a shared global"); } if (used.oldVarsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Ensures has an \"old\" shared global"); } /* * if (used.globalsUsed.Count == 0) * { * continue; * } */ // "Ensures" in procs without implementation are considered free if (re.Free == false && procsWithImpl.Contains(proc.Name)) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("A non-free ensures is not yet supported"); } } }