// convert {:Ebasic} to {:Ebasic n} void NameEnvironmentConstraints(Program program) { procsWithEnvAssumptions = new HashSet <string>(); var cnt = 0; var AddAttr = new Action <Implementation, Cmd>((impl, cmd) => { var acmd = cmd as AssumeCmd; if (acmd == null) { return; } if (!QKeyValue.FindBoolAttribute(acmd.Attributes, AvnAnnotations.EnvironmentAssumptionAttr)) { return; } acmd.Attributes = BoogieUtil.removeAttr(AvnAnnotations.EnvironmentAssumptionAttr, acmd.Attributes); acmd.Attributes = new QKeyValue(Token.NoToken, AvnAnnotations.EnvironmentAssumptionAttr, new List <object> { Expr.Literal(cnt) }, acmd.Attributes); cnt++; procsWithEnvAssumptions.Add(impl.Name); }); foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>()) { foreach (var block in impl.Blocks) { block.Cmds.Iter(c => AddAttr(impl, c)); } } }
public override Expr VisitNAryExpr(NAryExpr node) { var nArgs = node.Args.Select(x => base.VisitExpr(x)).ToList(); node.Args = nArgs; var fcall = node.Fun as FunctionCall; if (fcall != null && fcall.Func.HasAttribute(ExprMatchVisitor.BoogieKeyWords.MkUniqueFn)) { var formals = new List <Variable>(); fcall.Func.InParams.Iter(a => { var z = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, a.Name, a.TypedIdent.Type), true); formals.Add(z); }); var r = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "r", fcall.Func.OutParams[0].TypedIdent.Type), false); var f = new Function(Token.NoToken, fcall.FunctionName + "__" + uniqFuncs.Count, formals, r); //inherit all attributes other than mkUniqueFn f.Attributes = BoogieUtil.removeAttr(ExprMatchVisitor.BoogieKeyWords.MkUniqueFn, fcall.Func.Attributes); f.Body = fcall.Func.Body; uniqFuncs.Add(f); program.AddTopLevelDeclaration(f); node.Fun = new FunctionCall(f); } return(node); }
static void MarkEntryPoint(Program program, string proc) { // remove existing entrypoints program.TopLevelDeclarations.OfType <NamedDeclaration>() .Iter(decl => decl.Attributes = BoogieUtil.removeAttr("entrypoint", decl.Attributes)); program.TopLevelDeclarations.OfType <Implementation>() .Where(impl => impl.Name == proc) .Iter(impl => impl.Proc.AddAttribute("entrypoint")); }
// 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 void VisitImplementation(Implementation impl) { // callee -> id var cnt = new Dictionary <string, int>(); foreach (var block in impl.Blocks) { var callcnt = 0; for (int i = 0; i < block.Cmds.Count; i++) { var cc = block.Cmds[i] as CallCmd; if (cc == null) { continue; } if (!cnt.ContainsKey(cc.callee)) { cnt[cc.callee] = 0; } var uniqueId = useGlobalCounter ? counter : cnt[cc.callee]; var attr = new List <object>(); attr.Add(new LiteralExpr(Token.NoToken, Microsoft.BaseTypes.BigNum.FromInt(uniqueId))); cc.Attributes = BoogieUtil.removeAttr("si_old_unique_call", cc.Attributes); var oldAttr = BoogieUtil.getAttr("si_unique_call", cc.Attributes); if (oldAttr != null) { cc.Attributes = BoogieUtil.removeAttr("si_unique_call", cc.Attributes); var newattr = new QKeyValue(Token.NoToken, "si_old_unique_call", oldAttr, null); if (cc.Attributes == null) { cc.Attributes = newattr; } else { cc.Attributes.AddLast(newattr); } } cc.Attributes = new QKeyValue(Token.NoToken, "si_unique_call", attr, cc.Attributes); callIdToLocation.Add(Tuple.Create(impl.Name, cc.callee, uniqueId), Tuple.Create(block.Label, callcnt)); cnt[cc.callee]++; callcnt++; counter++; } } }
private static bool MatchParams(ref QKeyValue toMatchAnyParamsAttributes, ref int anyParamsPosition, Dictionary <Declaration, Expr> paramSubstitution, List <Variable> toMatchInParams, List <Variable> toMatchProcInParams, List <Variable> dwfInParams, List <Variable> dwfProcInParams, bool matchPtrs) { // match procedure parameters for (var i = 0; i < toMatchInParams.Count; i++) { if (i == toMatchInParams.Count - 1 && BoogieUtil.checkAttrExists(ExprMatchVisitor.BoogieKeyWords.AnyParams, toMatchProcInParams[i].Attributes)) { toMatchAnyParamsAttributes = toMatchInParams[i].Attributes; if (toMatchAnyParamsAttributes != null) { toMatchAnyParamsAttributes.Next = toMatchProcInParams[i].Attributes; } else { toMatchAnyParamsAttributes = toMatchProcInParams[i].Attributes; } toMatchAnyParamsAttributes = BoogieUtil.removeAttr(ExprMatchVisitor.BoogieKeyWords.AnyParams, toMatchAnyParamsAttributes); //TODO the type may also be constrained anyParamsPosition = i; //don't add it to the substitution continue; } // not anyParams and param counts don't match.. if (i >= dwfInParams.Count) { return(false); } // param types don't match if (!toMatchInParams[i].TypedIdent.Type.Equals(dwfInParams[i].TypedIdent.Type)) { return(false); } // if {:#MatchPtrs} attribute is present, check if pointer references match if (matchPtrs) { if (!MatchPtrs(toMatchProcInParams[i], dwfProcInParams[i])) { return(false); } } paramSubstitution.Add(toMatchInParams[i], new IdentifierExpr(Token.NoToken, dwfInParams[i])); } return(true); }
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); } }
static Program GetProgram(string filename) { var init = GetInputProgram(filename); if (Options.addInitialization) { ComputeandInitializeUninitializedLocals(init); } // Do some instrumentation for the input program if (Options.markAssumesAsSlic) { // Mark all assumes as "slic" var AddAnnotation = new Action <AssumeCmd>(ac => { ac.Attributes = new QKeyValue(Token.NoToken, "slic", new List <object>(), ac.Attributes); }); init.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => impl.Blocks .Iter(blk => blk.Cmds.OfType <AssumeCmd>() .Iter(AddAnnotation))); } // Only keep assertions in assertProc procedures if (Options.assertProcs != null) { (new Instrumentations.PruneNonAssertProcs(Options.assertProcs)).Visit(init); } // Inline procedures supplied with {:inline} annotation cba.Driver.InlineProcedures(init); // Remove {:inline} impls init.RemoveTopLevelDeclarations(decl => (decl is Implementation) && (BoogieUtil.checkAttrExists("inline", decl.Attributes) || BoogieUtil.checkAttrExists("inline", (decl as Implementation).Proc.Attributes))); // Restrict entrypoints to those provided explicitly (overrides any other way to providing entryPoints) if (Options.entryPointProcs != null) { //only consider the user provided entry points in command line Options.useHarnessTag = false; Options.useProvidedEntryPoints = true; init.TopLevelDeclarations.OfType <NamedDeclaration>() .Iter(d => d.Attributes = BoogieUtil.removeAttr("entrypoint", d.Attributes)); } var matchesEntryPointExclude = new Func <string, bool>(s => { return(Options.entryPointExcludes.Any(t => new System.Text.RegularExpressions.Regex(t).IsMatch(s))); }); //when both entryPointProcs == null and entryPointExcludes == null, it should not add any entrypointProcs if (Options.entryPointProcs != null || Options.entryPointExcludes != null) { init.TopLevelDeclarations.OfType <NamedDeclaration>() .Where(d => d is Procedure || d is Implementation) .Where(d => Options.entryPointProcs == null || Options.entryPointProcs.Contains(d.Name)) .Where(d => (Options.entryPointExcludes == null || !matchesEntryPointExclude(d.Name))) .Iter(d => d.AddAttribute("entrypoint")); } // Add {:entrypoint} to procs with {:harness} if (Options.useHarnessTag) { foreach (var decl in init.TopLevelDeclarations.OfType <NamedDeclaration>() .Where(d => QKeyValue.FindBoolAttribute(d.Attributes, "harness"))) { decl.AddAttribute("entrypoint"); } } // inlining introduces havoc statements; lets just delete them (TODO: make inlining not introduce redundant havoc statements) //foreach (var impl in init.TopLevelDeclarations.OfType<Implementation>()) //{ // impl.Blocks.Iter(blk => // blk.Cmds.RemoveAll(cmd => cmd is HavocCmd)); //} ReplaceHavocsWithNonDet(init); //Instrument to create the harness harnessInstrumentation = new Instrumentations.HarnessInstrumentation(init, AvnAnnotations.CORRAL_MAIN_PROC, Options.useProvidedEntryPoints); harnessInstrumentation.DoInstrument(); //resolve+typecheck wo bothering about modSets CommandLineOptions.Clo.DoModSetAnalysis = true; init = BoogieUtil.ReResolveInMem(init); CommandLineOptions.Clo.DoModSetAnalysis = false; // Update mod sets BoogieUtil.DoModSetAnalysis(init); if (Options.AddMapSelectNonNullAssumptions) { (new Instrumentations.AssertMapSelectsNonNull()).Visit(init); } BoogieUtil.pruneProcs(init, AvnAnnotations.CORRAL_MAIN_PROC); if (Options.deadCodeDetect) { // Tag branches as reachable var tup = InstrumentBranches.Run(init, AvnAnnotations.CORRAL_MAIN_PROC, Options.UseAliasAnalysisForAngelicAssertions, false); init = tup.Item1; // TODO: inject this information into the program itself DeadCodeBranchesDependencyInfo = tup.Item2; } return(init); }
static void Main(string[] args) { con = new Context(); string inFileName = null, unrolledFileName = null, tidRewrittenFileName = null, expandedFileName = null, annotatedFileName = null, splitFileName = null, yieldedFileName = null, instantiatedFileName = null, finalFileName = null, mhpFileName = null, hmifFileName = null; dbg = false; inFileName = parseCommandLine(args); string[] parts = inFileName.Split('.'); if (parts.Count() == 1) { unrolledFileName = inFileName + "_unrolled"; hmifFileName = inFileName + "_hmif"; expandedFileName = inFileName + "_expanded"; tidRewrittenFileName = inFileName + "_tidRewritten"; annotatedFileName = inFileName + "_annotated"; splitFileName = inFileName + "_split"; yieldedFileName = inFileName + "_yielded"; finalFileName = inFileName + "_final"; mhpFileName = inFileName + "_mhp"; instantiatedFileName = inFileName + "_inst"; } else { string name = parts[0]; unrolledFileName = name + "_unrolled"; hmifFileName = name + "_hmif"; expandedFileName = name + "_expanded"; annotatedFileName = name + "_annotated"; splitFileName = name + "_split"; yieldedFileName = name + "_yielded"; finalFileName = name + "_final"; mhpFileName = name + "_mhp"; instantiatedFileName = name + "_inst"; tidRewrittenFileName = name + "_tidRewritten"; for (int i = 1; i < parts.Count(); ++i) { unrolledFileName += "." + parts[i]; hmifFileName += "." + parts[i]; expandedFileName += "." + parts[i]; annotatedFileName += "." + parts[i]; splitFileName += "." + parts[i]; yieldedFileName += "." + parts[i]; finalFileName += "." + parts[i]; tidRewrittenFileName += "." + parts[i]; mhpFileName += "." + parts[i]; instantiatedFileName += "." + parts[i]; } } var tmpFileName = "og__tmp.bpl"; ExecutionEngine.printer = new ConsolePrinter(); //CommanLineOptions will control how boogie parses the program and gives us the IR CommandLineOptions.Install(new CommandLineOptions()); CommandLineOptions.Clo.Parse(new string[] { }); CommandLineOptions.Clo.PrintInstrumented = true; CommandLineOptions.Clo.StratifiedInliningVerbose = 2; CommandLineOptions.Clo.UseArrayTheory = true; CommandLineOptions.Clo.TypeEncodingMethod = CommandLineOptions.TypeEncoding.Monomorphic; Program program; program = BoogieUtil.ReadAndOnlyResolve(inFileName); // TODO: assert that no procedure can be called in both sync and async mode! // Find entrypoint and initialize con var entry = program.TopLevelDeclarations.OfType <Procedure>() .Where(proc => QKeyValue.FindBoolAttribute(proc.Attributes, "entrypoint")) .FirstOrDefault(); if (entry == null) { Console.WriteLine("Warning: No entrypoint given"); con.entryFunc = null; } else { con.entryFunc = entry.Name; } // Remove unreachable procedures BoogieUtil.pruneProcs(program, con.entryFunc); // Extract loops if (extractLoops) { program.ExtractLoops(); } BoogieUtil.DoModSetAnalysis(program); if (pruneAsserts) { program = og.GuardAsserts(program); } if (injectYields) { program = og.InsertYields(program); } if (instantiateTemplates) { var inst = new TemplateInstantiator(program); inst.Instantiate(program); program = BoogieUtil.ReResolve(program, dbg ? instantiatedFileName : tmpFileName); } var sp = new SplitThreads(con, dbg); var hmif = new HowManyInstanceFinder(con, dbg); var split = new Converter <Program, Program>(sp.split); var findHowManyInstances = new Converter <Program, Program>(hmif.Compute); if (entry != null && splitThreads) { if (dbg) { Console.WriteLine("Splitting procedures on thread entry: {0}", splitFileName); } program = split(program); program = BoogieUtil.ReResolve(program, dbg ? hmifFileName : tmpFileName); program = findHowManyInstances(program); program = BoogieUtil.ReResolve(program, dbg ? splitFileName : tmpFileName); } // Get rid of corral_yield program = og.RemoveCorralYield(program, con.yieldProc); var yieldedProgram = new ProgTransformation.PersistentProgram(program); if (dbg) { Console.WriteLine("Instrumenting: {0}", annotatedFileName); } if (!noTid) { program = og.InstrumentTid(program); } program = og.InstrumentAtomicBlocks(program); if (instrumentPermissions) { program = og.InstrumentPermissions(program); } program = BoogieUtil.ReResolve(program, dbg ? annotatedFileName : tmpFileName); CommandLineOptions.Clo.ContractInfer = true; CommandLineOptions.Clo.AbstractHoudini = absDomain; CommandLineOptions.Clo.UseProverEvaluate = true; CommandLineOptions.Clo.ModelViewFile = "z3model"; Microsoft.Boogie.Houdini.AbstractDomainFactory.Initialize(program); // First, do sequential var answer = DoInference(program, InferenceMode.SEQUENTIAL, annotatedFileName, expandedFileName); program = BoogieUtil.ReadAndOnlyResolve(dbg ? annotatedFileName : tmpFileName); // prune "true" functions var progFuncs = new Dictionary <string, Function>(); program.TopLevelDeclarations.OfType <Function>() .Iter(f => progFuncs.Add(f.Name, f)); var truefuncs = new List <Function>(); foreach (var f in answer) { if (f.Body is LiteralExpr && (f.Body as LiteralExpr).IsTrue) { truefuncs.Add(f); var actualf = progFuncs[f.Name]; actualf.Attributes = BoogieUtil.removeAttr("existential", actualf.Attributes); actualf.Body = Expr.True; } } Console.WriteLine("Sequential check pruned away {0} functions, {1} remain", truefuncs.Count, answer.Count() - truefuncs.Count); // now do concurrent answer = DoInference(program, InferenceMode.CONCURRENT, annotatedFileName, expandedFileName); answer = answer.Concat(truefuncs); var provedAsserts = new Dictionary <string, bool>(); answer.Where(func => QKeyValue.FindBoolAttribute(func.Attributes, "assertGuard")) .Iter(func => { var le = func.Body as LiteralExpr; System.Diagnostics.Debug.Assert(le != null); provedAsserts.Add(func.Name, le.IsFalse); }); // remove injected existential functions answer = answer.Where(func => !QKeyValue.FindBoolAttribute(func.Attributes, "chignore") && !QKeyValue.FindBoolAttribute(func.Attributes, "assertGuard")); if (printAssignment) { using (var tt = new TokenTextWriter(Console.Out)) answer.ToList().Iter(func => func.Emit(tt, 0)); } if (dbg) { Console.WriteLine("Injecting invariants back into the original program: {0}", finalFileName); } program = yieldedProgram.getProgram(); // remove existential functions program.RemoveTopLevelDeclarations(decl => (decl is Function) && QKeyValue.FindBoolAttribute((decl as Function).Attributes, "existential")); program.AddTopLevelDeclarations(answer); program = og.PruneProvedAsserts(program, f => provedAsserts[f]); // Remove ensures and requires program = og.RemoveRequiresAndEnsures(program); // Remove tid func program = og.RemoveThreadIdFunc(program); using (Microsoft.Boogie.TokenTextWriter writer = new Microsoft.Boogie.TokenTextWriter(finalFileName)) program.Emit(writer); }
private void CreateMainProcedure(Function reach) { //blocks List <Block> mainBlocks = new List <Block>(); List <Variable> locals = new List <Variable>(); HashSet <Constant> blockCallConsts = new HashSet <Constant>(); foreach (Implementation impl in prog.TopLevelDeclarations.Where(x => x is Implementation)) { // skip this impl if it is not marked as an entrypoint if (useProvidedEntryPoints && !QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "entrypoint")) { continue; } impl.Attributes = BoogieUtil.removeAttr("entrypoint", impl.Attributes); impl.Proc.Attributes = BoogieUtil.removeAttr("entrypoint", impl.Proc.Attributes); // skip initialization procedure if (QKeyValue.FindBoolAttribute(impl.Attributes, AvnAnnotations.InitialializationProcAttr) || QKeyValue.FindBoolAttribute(impl.Proc.Attributes, AvnAnnotations.InitialializationProcAttr)) { continue; } entrypoints.Add(impl.Name); //allocate params var args = new List <Variable>(); var rets = new List <Variable>(); impl.OutParams.ForEach(v => rets.Add(BoogieAstFactory.MkLocal(v.Name + "_" + impl.Name, v.TypedIdent.Type))); if (Options.allocateParameters) { // use impl.Proc here to pickup scalar/pointer attributes impl.Proc.InParams.ForEach(v => { var l = BoogieAstFactory.MkLocal(v.Name + "_" + impl.Name, v.TypedIdent.Type); // We are delibrately dropping the attributes so that // all parameters are initialized by allocation //l.Attributes = v.Attributes; args.Add(l); }); locals.AddRange(args); } else { impl.Proc.InParams.ForEach(v => { var g = BoogieAstFactory.MkGlobal(v.Name + "_" + impl.Name, v.TypedIdent.Type); //g.Attributes = v.Attributes; args.Add(g); }); globalParams.AddRange(args); } locals.AddRange(rets); //call var blockCallConst = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "__block_call_" + impl.Name, btype.Bool), false); blockCallConsts.Add(blockCallConst); blockEntryPointConstants[blockCallConst.Name] = impl.Name; impl2BlockingConstant[impl.Name] = blockCallConst; var blockCallAssumeCmd = new AssumeCmd(Token.NoToken, IdentifierExpr.Ident(blockCallConst)); var cmds = new List <Cmd>(); cmds.Add(blockCallAssumeCmd); if (Options.allocateParameters) // allocate parameters if option is enabled { var argMallocCmds = AllocatePointersAsUnknowns(args); cmds.AddRange(argMallocCmds); } // The beginning of an entry point must be reachable: assume reach(true); cmds.Add(new AssumeCmd(Token.NoToken, new NAryExpr(Token.NoToken, new FunctionCall(reach), new List <Expr> { Expr.True }))); var callCmd = new CallCmd(Token.NoToken, impl.Name, args.ConvertAll(x => (Expr)IdentifierExpr.Ident(x)), rets.ConvertAll(x => IdentifierExpr.Ident(x))); callCmd.Attributes = new QKeyValue(Token.NoToken, AvUtil.AvnAnnotations.AvhEntryPointAttr, new List <object>(), callCmd.Attributes); cmds.Add(callCmd); //succ var txCmd = new ReturnCmd(Token.NoToken); var blk = BoogieAstFactory.MkBlock(cmds, txCmd); mainBlocks.Add(blk); } foreach (Procedure proc in prog.TopLevelDeclarations.OfType <Procedure>()) { proc.Attributes = BoogieUtil.removeAttr("entrypoint", proc.Attributes); } // add global variables to prog // globals.Iter(x => prog.AddTopLevelDeclaration(x)); //add the constants to the prog blockCallConsts.Iter(x => prog.AddTopLevelDeclaration(x)); //TODO: get globals of type refs/pointers and maps var initCmd = (AssumeCmd)BoogieAstFactory.MkAssume(Expr.True); var globalCmds = new List <Cmd>() { initCmd }; //add call to corralExtraInit var init = Instrumentations.GetEnvironmentAssumptionsProc(prog); if (init != null && !Options.DelayInitialization) { globalCmds.Add(BoogieAstFactory.MkCall(init, new List <Expr>(), new List <Variable>())); } // Dont initialize Boogie instrumentation variables prog.GlobalVariables .Where(g => g.Name == "alloc" || BoogieUtil.checkAttrExists(AvnAnnotations.AllocatorVarAttr, g.Attributes)) .Where(g => !BoogieUtil.checkAttrExists("scalar", g.Attributes)) .Iter(g => g.AddAttribute("scalar")); // initialize globals prog.GlobalVariables .Where(g => g.Name != "alloc" && !BoogieUtil.checkAttrExists(AvnAnnotations.AllocatorVarAttr, g.Attributes)) .Iter(g => g.Attributes = BoogieUtil.removeAttrs(new HashSet <string> { "scalar", "pointer" }, g.Attributes)); globalCmds.AddRange(AllocatePointersAsUnknowns(prog.GlobalVariables.Select(x => (Variable)x).ToList())); if (init != null && Options.DelayInitialization) { globalCmds.Add(BoogieAstFactory.MkCall(init, new List <Expr>(), new List <Variable>())); } // globals for parameters prog.AddTopLevelDeclarations(globalParams); //first block var transferCmd = mainBlocks.Count > 0 ? (TransferCmd)(new GotoCmd(Token.NoToken, mainBlocks)) : (TransferCmd)(new ReturnCmd(Token.NoToken)); Block blkStart = new Block(Token.NoToken, "CorralMainStart", globalCmds, transferCmd); var blocks = new List <Block>(); blocks.Add(blkStart); blocks.AddRange(mainBlocks); var mainProcImpl = BoogieAstFactory.MkImpl(AvnAnnotations.CORRAL_MAIN_PROC, new List <Variable>(), new List <Variable>(), locals, blocks); mainProcImpl[0].AddAttribute("entrypoint"); prog.AddTopLevelDeclarations(mainProcImpl); }