public static ErrorTrace undoUnrolling(ErrorTrace trace) { // The heuristic used here is to get rid of the "#num" sign in the labels. // We assume that is the only way that Boogie.UnrollLoops changes the labels ErrorTrace ret = new ErrorTrace(trace.procName); for (int i = 0, n = trace.Blocks.Count; i < n; i++) { ret.addBlock(new ErrorTraceBlock(sanitizeLabel(trace.Blocks[i].blockName))); foreach (var c in trace.Blocks[i].Cmds) { if (c is CallInstr) { var cc = c as CallInstr; if (cc.calleeTrace != null) { ret.addInstr(new CallInstr(undoUnrolling(cc.calleeTrace), cc.asyncCall, cc.info)); continue; } } ret.addInstr(c); } } if (trace.returns) { ret.addReturn(); } return(ret); }
public ErrorTrace mapBackTrace(ErrorTrace trace) { if (!dict.ContainsKey(trace.procName)) { // missing transformations are assumed to be identity var ret = new ErrorTrace(getSrcProcName(trace.procName)); foreach (var blk in trace.Blocks) { ret.addBlock(new ErrorTraceBlock(blk.blockName)); foreach (var c in blk.Cmds) { if (c.isCall()) { CallInstr cc = c as CallInstr; if (cc.calleeTrace != null) { var t = mapBackTrace(cc.calleeTrace); ret.addInstr(new CallInstr(t, cc.asyncCall, cc.info)); continue; } } ret.addInstr(c); } } if (trace.returns) { ret.addReturn(trace.raisesException); } return(ret); } return(dict[trace.procName].mapBackTrace(trace, this)); }
private ErrorTrace mapBackTraceInline(ErrorTrace trace) { Debug.Assert(trace.isIntra()); Program inputProg = inlineInput.getProgram(); var nameImplMap = BoogieUtil.nameImplMapping(inputProg); var traceLabels = trace.getBlockLabels(); var stack = new List <WorkItemR>(); Implementation startImpl = getImpl(trace.procName, nameImplMap); Debug.Assert(traceLabels[0] == startImpl.Blocks[0].Label); var curr = new WorkItemR(startImpl, traceLabels[0]); // This variable keeps our current position in traceLabels int ecount = 0; // This variable keeps our current position in traceLabels[ecount].Cmds int icount = 0; var ret = new ErrorTrace(trace.procName); ret.addBlock(new ErrorTraceBlock(traceLabels[0])); // We will walk over the input program, trying to cover the same path as // trace, knowing that trace represents an inlined path while (true) { // Reached the end of the path? if (ecount == traceLabels.Count) { break; } //Console.WriteLine(curr.impl.Name + ": " + curr.label); // Reached the end of the current block? if (curr.count == curr.block.Cmds.Count) { ecount++; icount = 0; if (ecount == traceLabels.Count) { break; } // Move onto the next block TransferCmd tc = curr.block.TransferCmd; if (tc is ReturnCmd) { ret.addReturn(); if (stack.Count == 0) { // We're done Debug.Assert(ecount == traceLabels.Count); break; } curr = stack[0]; stack.RemoveAt(0); // An inlined procedure ends with "Return" label Debug.Assert(inlinedLabelMatches("Return", traceLabels[ecount])); ecount++; icount = 0; Debug.Assert(traceLabels[ecount].Contains(curr.block.Label)); continue; } if (tc is GotoCmd) { List <String> targets = (tc as GotoCmd).labelNames; string target = matchInlinedLabelNames(targets, traceLabels[ecount]); curr = new WorkItemR(curr.impl, target); ret.addBlock(new ErrorTraceBlock(curr.label)); continue; } // Unknown transfer command Debug.Assert(false); } // We have to continue in the same block Cmd c = curr.block.Cmds[curr.count]; curr.count++; if (!(c is CallCmd)) { ret.addInstr(new IntraInstr(getInfo(trace, ecount, icount))); icount++; continue; } // We're at a procedure call CallCmd cc = c as CallCmd; // If this is a call to a procedure without implementation, then skip if (!nameImplMap.ContainsKey(cc.Proc.Name)) { ret.addInstr(new CallInstr(cc.Proc.Name, null, false, getInfo(trace, ecount, icount))); icount++; continue; } Implementation callee = getImpl(cc.Proc.Name, nameImplMap); string label = callee.Blocks[0].Label; // The first label in a inlined procedure is always called Entry ecount++; Debug.Assert(inlinedLabelMatches("Entry", traceLabels[ecount])); ecount++; icount = 0; Debug.Assert(inlinedLabelMatches(label, traceLabels[ecount])); WorkItemR next = new WorkItemR(callee, label); stack.Insert(0, curr); curr = next; ret.addCall(callee.Name); ret.addBlock(new ErrorTraceBlock(curr.label)); } return(ret); }