// result[0] is the entry block protected List<Block/*!*/>/*!*/ CreateInlinedBlocks(CallCmd callCmd, Implementation impl, string nextBlockLabel) { Contract.Requires(nextBlockLabel != null); Contract.Requires(impl != null); Contract.Requires(impl.Proc != null); Contract.Requires(callCmd != null); Contract.Requires(codeCopier.Subst != null); Contract.Requires(codeCopier.OldSubst != null); Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>())); List<Block/*!*/>/*!*/ implBlocks = cce.NonNull(impl.OriginalBlocks); Contract.Assert(implBlocks.Count > 0); Procedure proc = impl.Proc; string startLabel = implBlocks[0].Label; List<Block/*!*/>/*!*/ inlinedBlocks = new List<Block/*!*/>(); // create in block List<Cmd> inCmds = new List<Cmd>(); // assign in parameters for (int i = 0; i < impl.InParams.Count; ++i) { Cmd cmd = Cmd.SimpleAssign(impl.tok, (IdentifierExpr)cce.NonNull(codeCopier.Subst)(cce.NonNull(impl.InParams[i])), cce.NonNull(callCmd.Ins[i])); inCmds.Add(cmd); } // inject requires for (int i = 0; i < proc.Requires.Count; i++) { Requires/*!*/ req = cce.NonNull(proc.Requires[i]); inCmds.Add(InlinedRequires(callCmd, req)); } List<Variable> locVars = cce.NonNull(impl.OriginalLocVars); // havoc locals and out parameters in case procedure is invoked in a loop List<IdentifierExpr> havocVars = new List<IdentifierExpr>(); foreach (Variable v in locVars) { havocVars.Add((IdentifierExpr)codeCopier.Subst(v)); } foreach (Variable v in impl.OutParams) { havocVars.Add((IdentifierExpr)codeCopier.Subst(v)); } if (havocVars.Count > 0) { inCmds.Add(new HavocCmd(Token.NoToken, havocVars)); } // add where clauses of local vars as assume for (int i = 0; i < locVars.Count; ++i) { Expr whereExpr = (cce.NonNull(locVars[i])).TypedIdent.WhereExpr; if (whereExpr != null) { whereExpr = Substituter.Apply(codeCopier.Subst, whereExpr); // FIXME we cannot overwrite it, can we?! (cce.NonNull(locVars[i])).TypedIdent.WhereExpr = whereExpr; AssumeCmd/*!*/ a = new AssumeCmd(Token.NoToken, whereExpr); Contract.Assert(a != null); inCmds.Add(a); } } // add where clauses of output params as assume for (int i = 0; i < impl.OutParams.Count; ++i) { Expr whereExpr = (cce.NonNull(impl.OutParams[i])).TypedIdent.WhereExpr; if (whereExpr != null) { whereExpr = Substituter.Apply(codeCopier.Subst, whereExpr); // FIXME likewise (cce.NonNull(impl.OutParams[i])).TypedIdent.WhereExpr = whereExpr; AssumeCmd/*!*/ a = new AssumeCmd(Token.NoToken, whereExpr); Contract.Assert(a != null); inCmds.Add(a); } } // assign modifies old values foreach (IdentifierExpr/*!*/ mie in proc.Modifies) { Contract.Assert(mie != null); Variable/*!*/ mvar = cce.NonNull(mie.Decl); AssignCmd assign = Cmd.SimpleAssign(impl.tok, (IdentifierExpr)cce.NonNull(codeCopier.OldSubst(mvar)), mie); inCmds.Add(assign); } GotoCmd inGotoCmd = new GotoCmd(callCmd.tok, new List<String> { GetInlinedProcLabel(proc.Name) + "$" + startLabel }); Block inBlock = new Block(impl.tok, GetInlinedProcLabel(proc.Name) + "$Entry", inCmds, inGotoCmd); inlinedBlocks.Add(inBlock); // inject the blocks of the implementation Block intBlock; foreach (Block block in implBlocks) { List<Cmd> copyCmds = codeCopier.CopyCmdSeq(block.Cmds); if (0 <= inlineDepth) { copyCmds = RemoveAsserts(copyCmds); } TransferCmd transferCmd = CreateInlinedTransferCmd(cce.NonNull(block.TransferCmd), GetInlinedProcLabel(proc.Name)); intBlock = new Block(block.tok, GetInlinedProcLabel(proc.Name) + "$" + block.Label, copyCmds, transferCmd); inlinedBlocks.Add(intBlock); } // create out block List<Cmd> outCmds = new List<Cmd>(); // inject ensures for (int i = 0; i < proc.Ensures.Count; i++) { Ensures/*!*/ ens = cce.NonNull(proc.Ensures[i]); outCmds.Add(InlinedEnsures(callCmd, ens)); } // assign out params for (int i = 0; i < impl.OutParams.Count; ++i) { Expr/*!*/ cout_exp = (IdentifierExpr)cce.NonNull(codeCopier.Subst(cce.NonNull(impl.OutParams[i]))); Cmd cmd = Cmd.SimpleAssign(impl.tok, cce.NonNull(callCmd.Outs[i]), cout_exp); outCmds.Add(cmd); } // create out block GotoCmd outGotoCmd = new GotoCmd(Token.NoToken, new List<String> { nextBlockLabel }); Block outBlock = new Block(impl.tok, GetInlinedProcLabel(proc.Name) + "$Return", outCmds, outGotoCmd); inlinedBlocks.Add(outBlock); return inlinedBlocks; }