public void Compile() { Util.Assert(!isPrinting); string name = FunName(DafnySpec.SimpleName(typeApply.AppName())); string fullName = FunName(DafnySpec.SimpleName(typeApply.AppFullName())); bool isAxiom = Attributes.Contains(function.Attributes, "axiom"); bool isPrivate = Attributes.Contains(function.Attributes, "private"); bool hidden = Attributes.Contains(function.Attributes, "opaque"); bool isHeap = DafnySpec.IsHeapFunction(function); List <string> heapParams = isHeap ? new List <string> { "$absMem:[int][int]int" } : new List <string>(); List <string> heapArgs = isHeap ? new List <string> { "$absMem" } : new List <string>(); var formals = function.Formals; var reads = function.Reads.Where(e => e.Field != null).ToList().ConvertAll(e => new Formal(e.tok, e.FieldName, e.Field.Type, true, e.Field.IsGhost)); formals = reads.Concat(formals).ToList(); if (hidden && formals.Count == 0) { formals = new List <Formal> { new Formal(function.tok, "___dummy", Type.Bool, true, true) }; } if (hidden && !function.Name.EndsWith("_FULL")) { ClassDecl cls = (ClassDecl)function.EnclosingClass; Function full = (Function)cls.Members.Find(m => m.Name == "#" + function.Name + "_FULL"); dafnySpec.Compile_Function(full, typeApply.typeArgs); } bool isFull = hidden && function.Name.EndsWith("_FULL"); string unfullName = isFull ? name.Substring(0, name.Length - "__FULL".Length) .Replace("#", "").Replace("____HASH", "") : null; string argsNoRec = String.Join(", ", heapArgs.Concat(formals.Select(f => GhostVar(f.Name)))); List <RtlExp> reqsNoRec = minVerify ? new List <RtlExp>() : function.Req.ConvertAll(e => GhostExpression(e, true)); List <RtlExp> enssNoRec = minVerify ? new List <RtlExp>() : function.Ens.ConvertAll(e => GhostExpression(e, true)); AddTypeWellFormed(reqsNoRec, formals); AddTypeWellFormed(enssNoRec, name + "(" + argsNoRec + ")", function.IsGhost, function.ResultType); if (function.Body != null && !minVerify) { recFunName = name; stmtExprEnabled = true; GhostExpression(function.Body); function.IsRecursive = recCalls.Count != 0; stmtExprEnabled = false; stmts = new List <RtlStmt>(); recCalls = new List <List <RtlExp> >(); recFunName = null; } if (function.IsRecursive) { recFunName = name; } stmts = new List <RtlStmt>(); stmtExprEnabled = true; var bodyDecls = PushForall(); RtlExp body = (function.Body == null || minVerify) ? null : GhostExpression(function.Body); List <RtlStmt> bodyStmts = stmts; PopForall(); stmtExprEnabled = false; stmts = new List <RtlStmt>(); string parms = String.Join(", ", heapParams.Concat( formals.Select(f => GhostVar(f.Name) + ":" + TypeString(AppType(f.Type))))); string args = String.Join(", ", heapArgs.Concat( formals.Select(f => GhostVar(f.Name)))); string sep = (heapArgs.Count + formals.Count != 0) ? ", " : ""; string ret = TypeString(AppType(function.ResultType)); string recName = "rec_" + name; string decreases = null; List <RtlExp> reqs = minVerify ? new List <RtlExp>() : function.Req.ConvertAll(e => GhostExpression(e, true)); List <RtlExp> enss = minVerify ? new List <RtlExp>() : function.Ens.ConvertAll(e => GhostExpression(e, true)); AddTypeWellFormed(reqs, formals); AddTypeWellFormed(enss, name + "(" + args + ")", function.IsGhost, function.ResultType); string reqConjunct = "(true" + String.Concat(reqs.Select(e => " && (" + e + ")")) + ")"; string ensConjunct = "(true" + String.Concat(enss.Select(e => " && (" + e + ")")) + ")"; Util.Assert(!isPrinting); if (function.IsRecursive && function.Body != null && !minVerify) { decreases = DecreasesExp(function); } List <RtlExp> enssRec = null; if (function.IsRecursive && (!hidden || isFull) && body != null && !minVerify) { enssRec = function.Ens.ConvertAll(e => GhostExpression(e, true)); } isPrinting = true; var fiWriter = isPrivate ? writer : iwriter; if (function.IsRecursive && function.Body != null && !minVerify) { iwriter.WriteLine("function decreases0_" + name + "(" + parms + "):int { " + decreases + " }"); iwriter.WriteLine("function decreases_" + name + "(" + parms + "):int { if decreases0_" + name + "(" + args + ") < 0 then 0 else 1 + decreases0_" + name + "(" + args + ") }"); iwriter.WriteLine("function " + recName + "(__decreases:int, __unroll:int" + sep + parms + "):" + ret + ";"); fiWriter.WriteLine("function implementation{" + FunName("unroll") + "(__unroll), " + recName + "(__decreases, __unroll" + sep + args + ")} " + recName + "(__decreases:int, __unroll:int" + sep + parms + "):" + ret); fiWriter.WriteLine("{"); fiWriter.WriteLine(" " + body.ToString()); fiWriter.WriteLine("}"); } iwriter.WriteLine("function " + name + "(" + parms + "):" + ret + ";"); if (hidden && !isFull && !minVerify) { iwriter.WriteLine("function unhide_" + name + "(" + parms + "):bool { true }"); fiWriter.WriteLine("function implementation{unhide_" + name + "(" + args + ")} " + name + "(" + parms + "):" + ret); fiWriter.WriteLine("{"); fiWriter.WriteLine(" " + fullName + "(" + args + ")"); fiWriter.WriteLine("}"); iwriter.WriteLine("atomic ghost procedure " + GhostProcName("reveal__" + DafnySpec.SimpleName(typeApply.AppName())) + "();"); string forall = "forall " + parms + "::" + name + "(" + args + ") == " + fullName + "(" + args + ")"; iwriter.WriteLine(" ensures (" + forall + ");"); writer.WriteLine("implementation " + GhostProcName("reveal__" + DafnySpec.SimpleName(typeApply.AppName())) + "()"); writer.WriteLine("{"); writer.WriteLine(" " + forall); writer.WriteLine(" {"); writer.WriteLine(" assert unhide_" + name + "(" + args + ");"); writer.WriteLine(" }"); writer.WriteLine("}"); } if (body != null && (!hidden || isFull)) { fiWriter.WriteLine("function implementation{" + name + "(" + args + ")" + "} " + name + "(" + parms + "):" + ret); fiWriter.WriteLine("{"); if (function.IsRecursive) { fiWriter.WriteLine(" " + recName + "(decreases_" + name + "(" + args + "), 0" + sep + args + ")"); } else { fiWriter.WriteLine(" " + body.ToString()); } fiWriter.WriteLine("}"); } if (function.IsRecursive && (!hidden || isFull) && body != null && !minVerify) { AddTypeWellFormed(enssRec, recName + "(__decreases, __unroll" + sep + args + ")", function.IsGhost, function.ResultType); string ensRecConjunct = "(true" + String.Concat(enssRec.Select(e => " && (" + e + ")")) + ")"; iwriter.WriteLine("atomic ghost procedure lemma_unroll2_" + recName + "(__decreases:int, __unroll:int, __unroll2:int" + sep + parms + ");"); iwriter.WriteLine(" requires __decreases == decreases_" + name + "(" + args + ");"); iwriter.WriteLine(" ensures " + reqConjunct + " ==> " + ensRecConjunct + " && " + recName + "(__decreases, __unroll" + sep + args + ") == " + recName + "(__decreases, __unroll2" + sep + args + ");"); writer.WriteLine("implementation lemma_unroll2_" + recName + "(__decreases:int, __unroll:int, __unroll2:int" + sep + parms + ")"); writer.WriteLine("{"); writer.WriteLine(" " + bodyDecls); writer.WriteLine(" assert fun_unroll(__unroll) && fun_unroll(__unroll2);"); dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes); writer.WriteLine(" if (" + reqConjunct + ")"); writer.WriteLine(" {"); bodyStmts.ForEach(s => writer.WriteLine(" " + s)); writer.WriteLine(" }"); foreach (List <RtlExp> recArgs in recCalls) { string rec_args = String.Join(", ", recArgs); string rec_decrease = "decreases_" + name + "(" + rec_args + ")"; writer.WriteLine(" if (0 <= " + rec_decrease + " && " + rec_decrease + " < __decreases)"); writer.WriteLine(" {"); writer.WriteLine(" call lemma_unroll2_" + recName + "(" + rec_decrease + ", __unroll + 1, __unroll2 + 1" + sep + rec_args + ");"); writer.WriteLine(" }"); } writer.WriteLine("}"); string unroll_args = "decreases_" + name + "(" + args + "), __unroll"; string unroll_args0 = "decreases_" + name + "(" + args + "), 0"; string unroll = recName + "(" + unroll_args + sep + args + ")"; string unroll0 = recName + "(" + unroll_args0 + sep + args + ")"; var lwriter = isPrivate ? writer : iwriter; string recForall = "forall __unroll:int" + sep + parms + "::" + "{fun_unroll(__unroll), " + unroll + "} " + reqConjunct + " ==> fun_unroll(__unroll) ==> " + unroll + " == " + body; lwriter.WriteLine("atomic ghost procedure lemma_unroll_" + recName + "();"); lwriter.WriteLine(" ensures (" + recForall + ");"); writer.WriteLine("implementation lemma_unroll_" + recName + "()"); writer.WriteLine("{"); dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes); writer.WriteLine(" " + recForall); writer.WriteLine(" {"); writer.WriteLine(" " + bodyDecls); writer.WriteLine(" if (" + reqConjunct + ")"); writer.WriteLine(" {"); bodyStmts.ForEach(s => writer.WriteLine(" " + s)); writer.WriteLine(" }"); writer.WriteLine(" }"); writer.WriteLine("}"); dafnySpec.AddLemma(new LemmaCall((isPrivate ? "private##" : "") + moduleName, visibleElementType, "call lemma_unroll_" + recName + "();", false)); Func <string, string> forall = s => "forall __unroll:int" + sep + parms + "::" + "{" + s + unroll + "} " + "{fun_unroll__all(__unroll), " + unroll + "} " + reqConjunct + " ==> " + unroll + " == " + name + "(" + args + ") && " + ensConjunct; iwriter.WriteLine("atomic ghost procedure lemma_unroll_" + name + "();"); iwriter.WriteLine(" ensures (" + forall(unroll0 + ", ") + ");"); writer.WriteLine("implementation lemma_unroll_" + name + "()"); writer.WriteLine("{"); dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes); writer.WriteLine(" " + forall("")); writer.WriteLine(" {"); writer.WriteLine(" call lemma_unroll2_" + recName + "(" + unroll_args + ", 0" + sep + args + ");"); writer.WriteLine(" if (" + reqConjunct + ")"); writer.WriteLine(" {"); enss.ForEach(e => writer.WriteLine(" assert " + e + ";")); writer.WriteLine(" }"); writer.WriteLine(" }"); writer.WriteLine("}"); dafnySpec.AddLemma(new LemmaCall(moduleName, visibleElementType, "call lemma_unroll_" + name + "();", false)); } else if (enssNoRec.Count > 0 && !minVerify) { string reqConjunctNoRec = "(true" + String.Concat(reqsNoRec.Select(e => " && (" + e + ")")) + ")"; string ensConjunctNoRec = "(true" + String.Concat(enssNoRec.Select(e => " && (" + e + ")")) + ")"; iwriter.WriteLine("function trigger_" + name + "(" + parms + "):bool { true }"); iwriter.WriteLine("atomic ghost procedure lemma_fun_ensures_" + name + "();"); string forallNoRec = "forall " + parms + "::{" + name + "(" + argsNoRec + ")}" + (isFull ? ("{" + unfullName + "(" + argsNoRec + ")}") : "") + "{trigger_" + name + "(" + argsNoRec + ")}" + "trigger_" + name + "(" + argsNoRec + ") ==> " + reqConjunctNoRec + " ==> " + ensConjunctNoRec; iwriter.WriteLine(" ensures (" + forallNoRec + ");"); if (body != null || hidden || isAxiom) { writer.WriteLine("implementation lemma_fun_ensures_" + name + "()"); writer.WriteLine("{"); dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes); writer.WriteLine(" " + forallNoRec); writer.WriteLine(" {"); writer.WriteLine(" " + bodyDecls); writer.WriteLine(" if (" + reqConjunct + ")"); writer.WriteLine(" {"); if (isAxiom) { writer.WriteLine(" // dummy lemma body for axiom"); } else { bodyStmts.ForEach(s => writer.WriteLine(" " + s)); } writer.WriteLine(" }"); if (hidden && !isFull) { writer.WriteLine(" assert unhide_" + name + "(" + argsNoRec + ");"); } if (hidden && isFull) { writer.WriteLine(" assert unhide_" + unfullName + "(" + argsNoRec + ");"); } writer.WriteLine(" if (" + reqConjunct + ")"); writer.WriteLine(" {"); enssNoRec.ForEach(e => writer.WriteLine(" assert " + e + ";")); writer.WriteLine(" }"); writer.WriteLine(" }"); writer.WriteLine("}"); } dafnySpec.AddLemma(new LemmaCall(moduleName, visibleElementType, "call lemma_fun_ensures_" + name + "();", false)); } isPrinting = false; }
public List <RtlStmt> Alloc() { assigned = new List <List <string> >(new List <string> [stmts.Count]); Func <int, string> slotMem = offset => "stk.map[r.regs[ESP] + " + offset + "]"; Func <RtlExp, string> spillLoc = e => "EvalPtr(r, " + e.AsOperand() + ")"; Func <RtlExp, string> spillMem = e => "stk.map[" + spillLoc(e) + "]"; Stack <int> workList = new Stack <int>(); List <RtlStmt> newStmts = new List <RtlStmt>(); Action <string, string> move = (string dest, string src) => { if (dest != src) { newStmts.Add(new RtlInst("instr_Mov", new RtlVar[] { new RtlVar(dest, false) }, new RtlVar[0], new RtlExp[] { new RtlVar(src, false) }, false) .WithComment("regalloc_move:: " + dest + " := " + src)); } }; Action <string, RtlExp, string> sLoad = (string dest, RtlExp src, string var) => { int dbgTag = debugTag++; Util.DebugWriteLine("sLoad: dest = " + dest + " " + dbgTag); newStmts.Add(new RtlStmtComputed((inst => { var eDst = inst.args[0].e; string opPtr = inst.args[1].e.AsOperand(); string ptr = "EvalPtr(r, " + opPtr + ")"; return(IsPtr(var) ? "call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, " + "$commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, " + eDst + ", " + opPtr + ", " + ptr + ");" + Environment.NewLine + " " + var + "__abs := frameGet($stacksFrames, " + ptr + ");" : "call r := logical_Load(r, core_state, stk, " + eDst + ", " + opPtr + ");"); }), new RtlArg[] { new RtlArg(true, false, new RtlVar(dest, false)), new RtlArg(true, false, src) }, false) .WithComment(() => "regalloc_stack_load:: " + dest + " := " + src + " // var = " + var + " " + dbgTag)); }; Action <RtlExp, string, string> sStore = (RtlExp dest, string src, string var) => { newStmts.Add(new RtlStmtComputed((inst => { string opPtr = inst.args[0].e.AsOperand(); string opVal = inst.args[1].e.AsOperand(); string ptr = "EvalPtr(r, " + opPtr + ")"; string val = "Eval(r, " + opVal + ")"; return(IsPtr(var) ? "call mems, $stacksFrames := " + "heapStoreStack(r, core_state, stk, statics, io, mems, " + "$commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, " + opPtr + ", " + opVal + ", " + ptr + ", " + var + "__abs);" : "call stk := logical_Store(r, core_state, stk, " + opPtr + ", " + opVal + ");"); }), new RtlArg[] { new RtlArg(true, false, dest), new RtlArg(true, false, new RtlVar(src, false)) }, false) .WithComment(() => "regalloc_stack_store:: " + dest + " := " + src + " // var = " + var)); }; workList.Push(0); while (workList.Count > 0) { int i = workList.Pop(); RtlStmt stmt = stmts[i]; stmt.Uses().ForEach(x => preds[i].ForEach(p => { if (!defVars[p].Contains(x)) { throw new Exception( "variable " + x + " is used before it is assigned"); } })); Util.DebugWriteLine(i + ": " + stmt); List <string> vars = stmt.Vars(); List <string> assignment = new List <string>((i == 0) ? initAssign : preds[i].ConvertAll(p => assigned[p]).Find(a => a != null)); Util.DebugWriteLine(" " + String.Join(", ", assignment)); RtlInst inst = stmt as RtlInst; List <Tuple <string, string> > pinVars = (inst == null) ? new List <Tuple <string, string> >() : inst.args.Where(arg => arg.pinReg != null && arg.e is RtlVar) .Select(arg => Tuple.Create(((RtlVar)arg.e).x, arg.pinReg)).ToList(); for (int r = 0; r < regs.Count; r++) { string rx = assignment[r]; if (rx != null && !liveVars[i].ContainsKey(rx)) { assignment[r] = null; } if (pinVars.Exists(p => p.Item1 == rx)) { assignment[r] = null; } foreach (var p in pinVars) { if (p.Item2 == regs[r]) { assignment[r] = p.Item1; } } } if (stmt is RtlCall) { RtlCall call = (RtlCall)stmt; if (!call.ghost) { for (int r = 0; r < regs.Count; r++) { assignment[r] = null; } /* * Func<RtlExp, bool> shouldSkip = (RtlExp e) => ((e is RtlVar) && ((RtlVar)e).isGhost); * int[] outsToReg = new int[2] { regs.IndexOf("EAX"), regs.IndexOf("ESI") }; * int[] argsToReg = new int[3] { regs.IndexOf("ECX"), regs.IndexOf("EDX"), regs.IndexOf("EBX") }; * * for (int r = 0; r < regs.Count; r++) * { * string rx = assignment[r]; * if (rx != null && (call.outs.Where(v => v.ToString() == rx).Count() != 0 || call.args.Where(v => v.ToString() == rx).Count() != 0)) * { * assignment[r] = null; * } * } * for (int idx = 0; idx < 2; idx++) * { * if (call.outs.Count >= idx + 1 && !shouldSkip(call.outs[idx])) * { * int r = outsToReg[idx]; * string rx = assignment[r]; * if (rx != null) * { * sStore(Spill(rx), regs[r]); * } * assignment[r] = call.outs[idx].ToString(); * } * } * for (int idx = 0; idx < 3; idx++) * { * if (call.args.Count >= idx + 1 && !shouldSkip(call.args[idx])) * { * int r = argsToReg[idx]; * string rx = assignment[r]; * if (rx != null) * { * sStore(Spill(rx), regs[r]); * } * assignment[r] = call.args[idx].ToString(); * } * } */ } } else if (stmt is RtlReturn) { for (int r = 0; r < regs.Count; r++) { assignment[r] = null; } } else if (inst == null || !inst.ghost) { foreach (string x in vars) { Tuple <int, int> bestEvict = null; for (int r = 0; r < regs.Count; r++) { var rx = assignment[r]; if (rx == x) { goto done; } if (!vars.Contains(rx)) { int thisEvict = (rx == null) ? Int32.MaxValue : liveVars[i][rx]; if (bestEvict == null || thisEvict > bestEvict.Item2) { bestEvict = Tuple.Create(r, thisEvict); } } } string ex = assignment[bestEvict.Item1]; if (ex != null) { Spill(ex); } assignment[bestEvict.Item1] = x; done : {} } } Util.DebugWriteLine(" vars = " + String.Join(", ", vars)); Util.DebugWriteLine(" preds = " + String.Join(", ", preds[i])); Util.DebugWriteLine(" succs = " + String.Join(", ", succs[i])); Util.DebugWriteLine(" live = " + String.Join(", ", liveVars[i].Keys.Select(x => Tuple.Create(x, liveVars[i][x])))); Util.DebugWriteLine(" assign: " + String.Join(", ", assignment)); assigned[i] = assignment; succs[i].Where(s => assigned[s] == null).ToList().ForEach(workList.Push); } for (int i = 0; i < stmts.Count; i++) { RtlJump jump = stmts[i] as RtlJump; if (jump != null && jump.cond != null) { List <string> assignment1 = assigned[i]; List <string> assignment2 = assigned[labels[jump.label]]; List <string> condVars = jump.cond.Vars(); for (int r = 0; r < regs.Count; r++) { string x1 = assignment1[r]; string x2 = assignment2[r]; if (x1 != null && x2 != null && condVars.Contains(x1) && x1 != x2) { assignment2[r] = null; Spill(x2); } } } } Action <List <string>, Dictionary <string, int>, Dictionary <string, int>, Dictionary <string, string> > transition = (List <string> assignment2, Dictionary <string, int> live, Dictionary <string, int> liveAlt, Dictionary <string, string> varToReg) => { Util.DebugWriteLine("start transition"); varToReg.Keys.Where(x => x != null && !live.ContainsKey(x) && !liveAlt.ContainsKey(x)).ToList() .ForEach(x => varToReg.Remove(x)); bool done; do { done = true; for (int rx = 0; rx < regs.Count; rx++) { string x = assignment2[rx]; string reg = regs[rx]; if (x != null && varToReg.ContainsKey(x) && varToReg[x] != reg && !varToReg.ContainsValue(reg)) { Util.DebugWriteLine("move " + x + ": " + regs[rx] + " <- " + varToReg[x]); move(regs[rx], varToReg[x]); varToReg[x] = reg; done = false; } } } while (!done); List <string> toSpill = new List <string>(); foreach (var current in varToReg) { string x = current.Key; int rx = regs.IndexOf(current.Value); Util.DebugWriteLine("current = " + x + " -> " + regs[rx]); Util.DebugWriteLine("assign = " + assignment2[rx] + " -> " + regs[rx]); if (assignment2[rx] != x && (live.ContainsKey(x) || liveAlt.ContainsKey(x))) { Util.DebugWriteLine("spilling " + x + " from " + regs[rx]); toSpill.Add(x); sStore(Spill(x), regs[rx], x); } } toSpill.ForEach(x => varToReg.Remove(x)); Util.DebugWriteLine("live = " + String.Join(", ", live)); for (int rx = 0; rx < regs.Count; rx++) { string x = assignment2[rx]; if (x != null && live.ContainsKey(x)) { Util.DebugWriteLine("assign = " + x + " -> " + regs[rx]); if (varToReg.ContainsKey(x)) { Util.Assert(varToReg[x] == regs[rx]); } else { Util.DebugWriteLine("loading " + x + " to " + regs[rx]); sLoad(regs[rx], Spill(x), x); Util.DebugWriteLine("loaded " + x + " to " + regs[rx]); varToReg.Add(x, regs[rx]); } } } }; Util.DebugWriteLine("spilled: " + String.Join(", ", spillInts.Keys)); Action <string> DebugWriteLine = s => { }; if (stmts.Count > 0) { transition(assigned[0], liveVars[0], liveVars[0], new Dictionary <string, string>()); } for (int i = 0; i < stmts.Count; i++) { List <string> assignment = assigned[i]; RtlStmt stmt = stmts[i]; List <string> vars = stmt.Vars(); List <string> uses = stmt.Uses(); Dictionary <string, string> varToReg = new Dictionary <string, string>(); Util.DebugWriteLine(i + ": " + stmt); Util.DebugWriteLine(" assignment: " + String.Join(", ", assignment)); Util.DebugWriteLine(" vars:" + String.Join(", ", vars)); Util.DebugWriteLine(" uses:" + String.Join(", ", uses)); DebugWriteLine(i + ": " + stmt.GetType() + ": " + stmt); DebugWriteLine(" vars = " + String.Join(", ", vars)); DebugWriteLine(" uses = " + String.Join(", ", uses)); DebugWriteLine(" preds = " + String.Join(", ", preds[i])); DebugWriteLine(" succs = " + String.Join(", ", succs[i])); DebugWriteLine(" live = " + String.Join(", ", liveVars[i].Keys.Select(x => Tuple.Create(x, liveVars[i][x])))); DebugWriteLine(" defs = " + String.Join(", ", defVars[i])); DebugWriteLine(" assign: " + String.Join(", ", assignment)); Action <int, int> transitionTarget = (int target, int altTarget) => { Util.DebugWriteLine("transition from " + i + " to " + target); transition(assigned[target], liveVars[target], liveVars[altTarget], varToReg); }; int r; for (r = 0; r < regs.Count; r++) { string x = assignment[r]; if (x != null) { varToReg.Add(x, regs[r]); } } r = 0; foreach (string x in vars) { if (varToReg.ContainsKey(x) || stmt is RtlReturn) { continue; } int rx = assignment.IndexOf(x); if (rx < 0) { rx = assignment.IndexOf(null, r); Util.Assert(rx >= 0); Util.DebugWriteLine(i + ": MOVE(1): " + x); sLoad(regs[rx], Spill(x), x); r = rx + 1; } varToReg.Add(x, regs[rx]); } Util.DebugWriteLine("vars = " + String.Join(", ", vars)); List <string> defs = stmt.Defs(); stmt = stmt.Subst(varToReg); Dictionary <string, string> regToVar = new Dictionary <string, string>(); varToReg.ToList().ForEach(p => regToVar.Add(p.Value, p.Key)); RtlJump jump = stmt as RtlJump; RtlReturn ret = stmt as RtlReturn; RtlLabel label = stmt as RtlLabel; RtlCall call = stmt as RtlCall; RtlCallInOut inOut = stmt as RtlCallInOut; if (ret != null) { Util.DebugWriteLine("RETURN: " + outVars.Count); for (int rr = 0; rr < regs.Count; rr++) { string rx = assignment[rr]; if (rx != null) { newStmts.Add(new RtlComment("spill variable " + rx + " from register " + regs[rr])); sStore(Spill(rx), regs[rr], rx); } } } if (jump == null) { List <string> spilledArgs = new List <string>(); if (inOut != null) { string reg = ((RtlVar)(inOut.args[0].e)).getName(); string var = regToVar[reg]; bool isPtr = IsPtr(var); int offset = 4 * inOut.index; RtlExp slot = new RtlExpComputed(e => isPtr ? StackOMemPtr(offset) : StackOMem(offset)); newStmts.Add(new RtlComment(inOut.comment)); if (inOut.isRet) { if (isPtr) { callPtrRets = Math.Max(callPtrRets, inOut.index + 1); } else { callIntRets = Math.Max(callIntRets, inOut.index + 1); newStmts.Add(new RtlInst(null, new RtlVar[] { new RtlVar(var, true) }, new RtlVar[0], new RtlExp[] { new RtlLiteral( CompileMethod.IntToTyped(varTypes[var], slotMem(offset))) }, true)); } Util.DebugWriteLine(" var = " + var + " live = " + String.Join(",", liveVars[i].Keys) + " live' = " + String.Join(",", liveVars[i + 1].Keys)); if (i + 1 >= liveVars.Count || liveVars[i + 1].ContainsKey(var)) { Util.DebugWriteLine("sLoad inOut: " + reg + " " + slot + " " + var); sLoad(reg, slot, var); } } else { if (isPtr) { callPtrArgs = Math.Max(callPtrArgs, inOut.index + 1); } else { callIntArgs = Math.Max(callIntArgs, inOut.index + 1); } sStore(slot, reg, var); } } else { newStmts.Add(stmt); defs.Where(x => !IsPtr(x)).ToList() .ForEach(x => newStmts.Add(new RtlInst(null, new RtlVar[] { new RtlVar(x, true) }, new RtlVar[0], new RtlExp[] { new RtlLiteral( CompileBase.IntToTyped(varTypes[x], Reg(varToReg[x]))) }, true))); } Util.DebugWriteLine("sLoad spilled: " + String.Join(", ", spilledArgs.Select(arg => "(" + varToReg[arg] + " <- " + arg + ")"))); spilledArgs.ForEach(arg => sLoad(varToReg[arg], Spill(arg), arg)); } if (label != null && label.loop) { List <RtlExp> typeInvs = new List <RtlExp>(); newStmts.Add(new RtlComment("loop invariants")); foreach (string x in liveVars[i].Keys) { if (defVars[i].Contains(x)) { compileMethod.AddTypeWellFormed(typeInvs, x, false, varTypes[x]); string save_x = x; RtlExp loc = varToReg.ContainsKey(x) ? new RtlVar(Reg(varToReg[x]), false) : (RtlExp) new RtlExpComputed(e => spillMem(Spill(save_x))); if (IsPtr(x)) { string absData = "Abs_" + TypeString(varTypes[x]) + "(" + x + ")"; if (varToReg.ContainsKey(x)) { newStmts.Add(new RtlAssert(new RtlLiteral( "HeapAbsData(heap, " + x + "__abs) == " + absData), true)); newStmts.Add(new RtlAssert(new RtlExpComputed(e => "HeapValue(objLayouts, true, $toAbs, " + loc + ", " + save_x + "__abs)"), true)); if (IsArray(x)) { newStmts.Add(new RtlAssert(new RtlLiteral( x + "__abs == " + x + ".arrAbs"), true)); } } else { newStmts.Add(new RtlAssert(new RtlExpComputed(e => "StackAbsSlot(heap, $stacksFrames, " + spillLoc(Spill(save_x)) + ") == " + absData), true)); if (IsArray(x)) { newStmts.Add(new RtlAssert(new RtlExpComputed(e => "frameGet($stacksFrames, " + spillLoc(Spill(save_x)) + ") == " + save_x + ".arrAbs"), true)); } } } else { newStmts.Add(new RtlAssert(CompileMethod.IntEqTyped(varTypes[x], new RtlVar(x, false), new RtlExpComputed(e => loc.ToString())), true)); } } } typeInvs.ForEach(e => newStmts.Add(new RtlAssert(e, true))); } bool fallThru = (ret == null && i + 1 < stmts.Count && (jump == null || jump.cond != null)); if (jump != null) { transitionTarget(labels[jump.label], fallThru ? (i + 1) : labels[jump.label]); newStmts.Add(stmt); } if (fallThru) { transitionTarget(i + 1, i + 1); } } return(newStmts); }
public override string ToString() { return(e.ToString()); }