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); }
private static void InjectCode(Implementation impl, int anyParamsPosition, QKeyValue anyParamsAttributes, int anyParamsPositionOut, QKeyValue anyParamsAttributesOut, Implementation procSig, InsertAtBeginningRule rule, Dictionary <Declaration, Expr> paramSubstitution) { //TODO handle anyParams in the OutParam case var doesAnyParamOccurInRhs = false; if (anyParamsPosition != int.MaxValue) { var anyParam = procSig.InParams[anyParamsPosition]; var oiv = new OccursInVisitor(anyParam); oiv.VisitCmdSeq(rule.ProcedureToMatchToInsertion[procSig]); doesAnyParamOccurInRhs = oiv.Success; } if (doesAnyParamOccurInRhs) { for (int i = anyParamsPosition; i < impl.InParams.Count; i++) { var p = impl.InParams[i]; // If attributes for the ##anyparams in the toMatch are given, we only insert code for those parameters of impl // with matching (subset) attributes // we look both in the implementation's and the procedure declaration's signature if (anyParamsAttributes == null || ExprMatchVisitor.AreAttributesASubset(anyParamsAttributes, impl.Proc.InParams[i].Attributes)) { if (!procSig.InParams[anyParamsPosition].TypedIdent.Type.Equals(p.TypedIdent.Type)) { continue; //skip parameters that don't match type } var id = new IdentifierExpr(Token.NoToken, p.Name, p.TypedIdent.Type, true); var substitution = new Dictionary <Declaration, Expr> { { procSig.InParams[anyParamsPosition], id } }; foreach (var kvp in paramSubstitution) { substitution.Add(kvp.Key, kvp.Value); } var sv = new SubstitionVisitor(substitution); var newCmds = sv.VisitCmdSeq(rule.ProcedureToMatchToInsertion[procSig]); if (impl.Blocks.Count > 0 && !QKeyValue.FindBoolAttribute(procSig.Attributes, ExprMatchVisitor.BoogieKeyWords.ReplaceImplementation)) { impl.Blocks.Insert(0, BoogieAstFactory.MkBlock(newCmds, BoogieAstFactory.MkGotoCmd(impl.Blocks.First().Label))); } else { impl.Blocks = new List <Block>(); impl.Blocks.Add( BoogieAstFactory.MkBlock(newCmds)); } } } } else { var sv = new SubstitionVisitor(paramSubstitution); var newCmds = sv.VisitCmdSeq(rule.ProcedureToMatchToInsertion[procSig]); if (impl.Blocks.Count > 0 && !QKeyValue.FindBoolAttribute(procSig.Attributes, ExprMatchVisitor.BoogieKeyWords.ReplaceImplementation)) { impl.Blocks.Insert(0, BoogieAstFactory.MkBlock(newCmds, BoogieAstFactory.MkGotoCmd(impl.Blocks.First().Label))); } else { impl.Blocks = new List <Block>(); impl.Blocks.Add( BoogieAstFactory.MkBlock(newCmds)); } } }
//Change the body of any stub that returns a pointer into calling unknown() //TODO: only do this for procedures with a single return with a pointer type private void MkStubImplementation(List <Implementation> stubImpls, Procedure p) { List <Cmd> cmds = new List <Cmd>(); List <Variable> localVars = new List <Variable>(); stubs.Add(p.Name); foreach (var op in p.OutParams) { if (IsPointerVariable(op)) { cmds.Add(AllocatePointerAsUnknown(op)); } else { // Avoid using Havoc -- we'll let this fall on the floor as an // uninitialized variable. AVN will take care of concretizing it //cmds.Add(BoogieAstFactory.MkHavocVar(op)); } } foreach (var v in p.Modifies.Select(ie => ie.Decl)) { if (IsPointerVariable(v)) { cmds.Add(AllocatePointerAsUnknown(v)); } else { // unsupported Console.WriteLine("Warning: demonic havoc of global {0} in {1}", v.Name, p.Name); } } foreach (var ip in p.InParams) { if (!BoogieUtil.checkAttrExists("ref", ip.Attributes)) { continue; } string mapName = QKeyValue.FindStringAttribute(ip.Attributes, "ref"); if (mapName == null) { Utils.Print(String.Format("Expecting a map <name> with {:ref <name>} annotation on procedure {0}", p.Name), Utils.PRINT_TAG.AV_WARNING); continue; } var mapVars = prog.TopLevelDeclarations.OfType <Variable>().Where(x => x.Name == mapName && x.TypedIdent.Type.IsMap); if (mapVars.Count() != 1) { Utils.Print(String.Format("Mapname {0} provided in {{:ref}} for parameter {1} for procedure {2} has {3} matches, expecting exactly 1 match", mapName, ip.Name, p.Name, mapVars.Count()), Utils.PRINT_TAG.AV_WARNING); continue; } var tmpVar = BoogieAstFactory.MkLocal("__tmp_" + ip.Name, ip.TypedIdent.Type); localVars.Add(tmpVar); cmds.Add(AllocatePointerAsUnknown(tmpVar)); cmds.Add(BoogieAstFactory.MkMapAssign(mapVars.First(), IdentifierExpr.Ident(ip), IdentifierExpr.Ident(tmpVar))); } if (cmds.Count == 0) { return; //don't create a body if no statements } var blk = BoogieAstFactory.MkBlock(cmds, new ReturnCmd(Token.NoToken)); var blks = new List <Block>() { blk }; //don't insert the proc as it already exists var impl = BoogieAstFactory.MkImpl(p.Name, DropAnnotations(p.InParams), DropAnnotations(p.OutParams), new List <Variable>(), blks); ((Implementation)impl[1]).LocVars.AddRange(localVars); stubImpls.Add((Implementation)impl[1]); }
// If the impl has multiple calls: // "call foo(args); return;" // with the same args, then merge these calls into one public static string mergeRecCalls(Implementation impl) { // find the recursive calls var rBlocks = new List <Block>(); foreach (var blk in impl.Blocks) { var rc = blk.Cmds .OfType <CallCmd>() .Where(cc => cc.callee == impl.Name); if (!rc.Any()) { continue; } if (rc.Count() != 1) { return(null); } // make sure recursive call is last in the block var rcall = rc.First(); if (rcall != blk.Cmds.Last()) { return(null); } // check return if (!(blk.TransferCmd is ReturnCmd)) { return(null); } rBlocks.Add(blk); } if (rBlocks.Count <= 1) { return(null); } // grab the rec calls var recCalls = new Dictionary <string, CallCmd>(); rBlocks.Iter(blk => recCalls.Add(blk.Label, blk.Cmds.Last() as CallCmd)); // prune attributes var origAttr = new Dictionary <string, QKeyValue>(); recCalls.Iter(kvp => origAttr.Add(kvp.Key, kvp.Value.Attributes)); recCalls.Values .Iter(cc => cc.Attributes = BoogieUtil.removeAttrs(new HashSet <string> { "si_unique_call", "si_old_unique_call" }, cc.Attributes)); // check that all recursive calls have the same arguments // Check 1: ToString var callStr = new HashSet <string>(); recCalls.Values .Iter(cc => { var str = new System.IO.StringWriter(); var tt = new TokenTextWriter(str); cc.Emit(tt, 0); tt.Close(); callStr.Add(str.ToString()); str.Close(); }); if (callStr.Count != 1) { // restore attributes recCalls .Iter(kvp => kvp.Value.Attributes = origAttr[kvp.Key]); return(null); } // Check 2: AST var rc1 = recCalls[recCalls.Keys.First()]; if ( recCalls.Values .Where(c => !IsSame(rc1, c)) .Any()) { // restore attributes recCalls .Iter(kvp => kvp.Value.Attributes = origAttr[kvp.Key]); return(null); } // Merge rc1.Attributes = origAttr[recCalls.Keys.First()]; var nb = BoogieAstFactory.MkBlock(rc1); rBlocks.Iter(blk => blk.Cmds.Remove(blk.Cmds.Last())); rBlocks.Iter(blk => { var gc = BoogieAstFactory.MkGotoCmd(nb.Label); gc.labelTargets = new List <Block>(); gc.labelTargets.Add(nb); blk.TransferCmd = gc; }); impl.Blocks.Add(nb); return(nb.Label); }