Exemple #1
0
        public void BwUnresolveableIndirect()
        {
            var eax = m.Reg32("eax", 0);
            var esi = m.Reg32("esi", 6);
            var Z   = m.Frame.EnsureFlagGroup(Registers.eflags, 1, "Z", PrimitiveType.Bool);

            var xfer = new RtlCall(eax, 4, InstrClass.Transfer);

            m.Assign(eax, m.Mem32(esi));
            m.Assign(Z, m.Cond(m.And(eax, eax)));
            m.BranchIf(m.Test(ConditionCode.EQ, Z), "null_ptr");
            m.Label("do_call");

            var bw = new Backwalker <Block, Instruction>(host, xfer, expSimp);

            Assert.IsTrue(bw.CanBackwalk());
            Assert.AreEqual("eax", bw.Index.Name);
            bw.BackWalk(m.Block);
            Assert.AreEqual("None", bw.Index.ToString());
        }
Exemple #2
0
        public void BwUnresolveableIndirect()
        {
            var eax = m.Frame.CreateTemporary("eax", PrimitiveType.Word32);
            var esi = m.Frame.CreateTemporary("esi", PrimitiveType.Word32);
            var Z   = m.Frame.EnsureFlagGroup(1, "Z", PrimitiveType.Bool);

            var xfer = new RtlCall(eax, 4, RtlClass.Transfer);

            m.Assign(eax, m.LoadDw(esi));
            m.Assign(Z, m.Cond(m.And(eax, eax)));
            m.BranchIf(m.Test(ConditionCode.EQ, Z), "null_ptr");
            m.Label("do_call");

            var bw = new Backwalker(host, xfer, expSimp);

            Assert.IsTrue(bw.CanBackwalk());
            Assert.AreEqual("eax", bw.Index.Name);
            bw.BackWalk(m.Block);
            Assert.AreEqual("None", bw.Index.Name);
        }
Exemple #3
0
        public void MacOS_ResolveIndirectCall()
        {
            var macOS = new MacOSClassic(null, new M68kArchitecture("m68k"));
            var a5    = new Identifier(Registers.a5.Name, Registers.a5.DataType, Registers.a5);

            var a5world = new MemoryArea(Address.Ptr32(0x00100000), new byte[0x0300]);

            macOS.A5World  = new ImageSegment("A5World", a5world, AccessMode.ReadWrite);
            macOS.A5Offset = 0x0100u;
            const int  jumpTableOffset = 0x0032;
            const uint uAddrDirect     = 0x00123400u;
            var        w = new BeImageWriter(a5world, macOS.A5Offset + jumpTableOffset);

            w.WriteBeUInt16(0x4EF9);        // jmp... (not really necessary for the test but hey....);
            w.WriteBeUInt32(uAddrDirect);

            var m     = new RtlEmitter(null);
            var instr = new RtlCall(m.IAdd(a5, jumpTableOffset), 4, RtlClass.Call);
            var addr  = macOS.ResolveIndirectCall(instr);

            Assert.AreEqual(uAddrDirect, addr.ToUInt32());
        }
Exemple #4
0
        public void BwReg_00121()
        {
            var d0    = m.Reg32("d0", 0);
            var d3    = m.Reg32("d3", 3);
            var a5    = m.Reg32("a5", 5);
            var v38   = m.Temp(PrimitiveType.Word16, "v38");
            var v39   = m.Temp(PrimitiveType.Byte, "v39");
            var v40   = m.Temp(PrimitiveType.Word16, "v40");
            var VZN   = m.Flags("VZN");
            var ZN    = m.Flags("ZN");
            var C     = m.Flags("C");
            var V     = m.Flags("V");
            var CVZN  = m.Flags("CVZN");
            var CVZNX = m.Flags("CVZNX");

            m.Assign(d0, d3);
            m.Assign(CVZN, m.Cond(d0));
            m.Assign(v38, m.And(m.Cast(PrimitiveType.Word16, d0), 0xF0));
            m.Assign(d0, m.Dpb(d0, v38, 0));
            m.Assign(ZN, m.Cond(v38));
            m.Assign(C, false);
            m.Assign(V, false);
            m.Assign(v39, m.Shl(m.Cast(PrimitiveType.Byte, d0), 2));
            m.Assign(d0, m.Dpb(d0, v39, 0));
            m.Assign(CVZNX, m.Cond(v39));
            m.Assign(v40, m.ISub(m.Cast(PrimitiveType.Word16, d0), 44));
            m.Assign(CVZN, m.Cond(v40));
            m.BranchIf(m.Test(ConditionCode.GT, VZN), "lDefault");
            m.Assign(a5, m.Mem32(m.IAdd(Address.Ptr32(0x0000C046), d0)));
            var xfer = new RtlCall(a5, 4, RtlClass.Transfer);

            var bw = new Backwalker <Block, Instruction>(host, xfer, expSimp);

            Assert.IsTrue(bw.CanBackwalk());
            Assert.AreEqual("a5", bw.Index.Name);
            bw.BackWalk(m.Block);
            Assert.AreEqual("v40", bw.IndexExpression.ToString());
        }
        // Delayed call (for SPARC / MIPS)
        public RtlInstruction CallD(Expression target)
        {
            var call = new RtlCall(target, 4, RtlClass.Transfer | RtlClass.Delay);

            return(Emit(call));
        }
        public void BwReg_00121()
        {
            var d0 = m.Reg32("d0", 0);
            var d3 = m.Reg32("d3", 3);
            var a5 = m.Reg32("a5", 5);
            var v38 = m.Temp(PrimitiveType.Word16, "v38");
            var v39 = m.Temp(PrimitiveType.Byte, "v39");
            var v40 = m.Temp(PrimitiveType.Word16, "v40");
            var VZN = m.Flags("VZN");
            var ZN = m.Flags("ZN");
            var C = m.Flags("C");
            var V = m.Flags("V");
            var CVZN = m.Flags("CVZN");
            var CVZNX = m.Flags("CVZNX");
            m.Assign(d0, d3);
            m.Assign(CVZN, m.Cond(d0));
            m.Assign(v38, m.And(m.Cast(PrimitiveType.Word16, d0), 0xF0));
            m.Assign(d0, m.Dpb(d0, v38, 0));
            m.Assign(ZN, m.Cond(v38));
            m.Assign(C, false);
            m.Assign(V, false);
            m.Assign(v39, m.Shl(m.Cast(PrimitiveType.Byte, d0), 2));
            m.Assign(d0, m.Dpb(d0, v39, 0));
            m.Assign(CVZNX, m.Cond(v39));
            m.Assign(v40, m.ISub(m.Cast(PrimitiveType.Word16, d0), 44));
            m.Assign(CVZN, m.Cond(v40));
            m.BranchIf(m.Test(ConditionCode.GT, VZN), "lDefault");
            m.Assign(a5, m.LoadDw(m.IAdd(Address.Ptr32(0x0000C046), d0)));
            var xfer = new RtlCall(a5, 4, RtlClass.Transfer);

            var bw = new Backwalker(host, xfer, expSimp);
            Assert.IsTrue(bw.CanBackwalk());
            Assert.AreEqual("a5", bw.Index.Name);
            bw.BackWalk(m.Block);
            Assert.AreEqual("v40", bw.IndexExpression.ToString());
        }
Exemple #7
0
        public RtlInstruction Call(Expression target)
        {
            var call = new RtlCall(target, 4, InstrClass.Transfer);

            return(Emit(call));
        }
Exemple #8
0
 public Address ResolveIndirectCall(RtlCall call)
 {
     return(null);
 }
Exemple #9
0
 /// <summary>
 /// Given an indirect call, attempt to resolve it into an address.
 /// </summary>
 /// <param name="instr"></param>
 /// <returns>null if the call couldn't be resolved, or an Address to
 /// what must be a procedure if the call could be resolved.
 /// </returns>
 public virtual Address ResolveIndirectCall(RtlCall instr)
 {
     return(null);
 }
Exemple #10
0
 // Delayed call (for SPARC / MIPS)
 public RtlInstruction CallD(Expression target)
 {
     var call = new RtlCall(target, 4, RtlClass.Transfer|RtlClass.Delay);
     return Emit(call);
 }
Exemple #11
0
        public void BwUnresolveableIndirect()
        {
            var eax = m.Reg32("eax", 0);
            var esi = m.Reg32("esi", 6);
            var Z = m.Frame.EnsureFlagGroup(Registers.eflags, 1, "Z", PrimitiveType.Bool);

            var xfer = new RtlCall(eax, 4, RtlClass.Transfer);
            m.Assign(eax, m.LoadDw(esi));
            m.Assign(Z, m.Cond(m.And(eax, eax)));
            m.BranchIf(m.Test(ConditionCode.EQ, Z), "null_ptr");
            m.Label("do_call");

            var bw = new Backwalker(host, xfer, expSimp);
            Assert.IsTrue(bw.CanBackwalk());
            Assert.AreEqual("eax", bw.Index.Name);
            bw.BackWalk(m.Block);
            Assert.AreEqual("None", bw.Index.ToString());
        }
Exemple #12
0
        public void BwTempRegister()
        {
            var v1 = m.Frame.CreateTemporary(PrimitiveType.Word32);
            var edi = m.Frame.CreateTemporary(PrimitiveType.Word32);
            var esi = m.Frame.EnsureRegister(Registers.esi);
            var xfer = new RtlCall(m.LoadDw(m.IAdd(esi, 40)), 4, RtlClass.Transfer);
            m.Assign(v1, m.LoadDw(edi));
            m.Assign(esi, v1);
            var bw = new Backwalker(host, xfer, expSimp);
            bool result;
            result = bw.BackwalkInstruction(m.Block.Statements[1].Instruction);
            result = bw.BackwalkInstruction(m.Block.Statements[0].Instruction);

            Assert.IsFalse(result);
            Assert.AreEqual("None", bw.Index.ToString());
        }
Exemple #13
0
        public bool VisitCall(RtlCall call)
        {
            if ((call.Class & RtlClass.Delay) != 0)
            {
                // Get delay slot instruction cluster.
                rtlStream.MoveNext();
                ProcessRtlCluster(rtlStream.Current);
            }
            var                      site = OnBeforeCall(stackReg, call.ReturnAddressSize);
            FunctionType             sig;
            ProcedureCharacteristics chr  = null;
            Address                  addr = call.Target as Address;

            if (addr != null)
            {
                var impProc = scanner.GetImportedProcedure(addr, this.ric.Address);
                if (impProc != null)
                {
                    sig = impProc.Signature;
                    chr = impProc.Characteristics;
                    if (chr != null && chr.IsAlloca)
                    {
                        return(ProcessAlloca(site, impProc));
                    }
                    EmitCall(CreateProcedureConstant(impProc), sig, chr, site);
                    return(OnAfterCall(sig, chr));
                }
                if (!program.SegmentMap.IsValidAddress(addr))
                {
                    return(GenerateCallToOutsideProcedure(site, addr));
                }
                var callee   = scanner.ScanProcedure(addr, null, state);
                var pcCallee = CreateProcedureConstant(callee);
                sig = callee.Signature;
                chr = callee.Characteristics;
                EmitCall(pcCallee, sig, chr, site);
                var pCallee = callee as Procedure;
                if (pCallee != null)
                {
                    program.CallGraph.AddEdge(blockCur.Statements.Last, pCallee);
                }
                return(OnAfterCall(sig, chr));
            }

            var procCallee = call.Target as ProcedureConstant;

            if (procCallee != null)
            {
                sig = procCallee.Procedure.Signature;
                chr = procCallee.Procedure.Characteristics;
                EmitCall(procCallee, sig, chr, site);
                return(OnAfterCall(sig, chr));
            }
            sig = GetCallSignatureAtAddress(ric.Address);
            if (sig != null)
            {
                EmitCall(call.Target, sig, chr, site);
                return(OnAfterCall(sig, chr));  //$TODO: make characteristics available
            }

            Identifier id;

            if (call.Target.As <Identifier>(out id))
            {
                var ppp = SearchBackForProcedureConstant(id);
                if (ppp != null)
                {
                    var e = CreateProcedureConstant(ppp);
                    sig = ppp.Signature;
                    chr = ppp.Characteristics;
                    EmitCall(e, sig, chr, site);
                    return(OnAfterCall(sig, chr));
                }
            }

            var imp = ImportedProcedureName(call.Target);

            if (imp != null)
            {
                sig = imp.Signature;
                chr = imp.Characteristics;
                EmitCall(CreateProcedureConstant(imp), sig, chr, site);
                return(OnAfterCall(sig, chr));
            }

            var syscall = program.Platform.FindService(call, state);

            if (syscall != null)
            {
                return(!EmitSystemServiceCall(syscall));
            }

            ProcessIndirectControlTransfer(ric.Address, call);

            var ic = new CallInstruction(call.Target, site);

            Emit(ic);
            sig = GuessProcedureSignature(ic);
            return(OnAfterCall(sig, chr));
        }
Exemple #14
0
 public SlicerResult VisitCall(RtlCall call)
 {
     return(null);
 }
Exemple #15
0
        public bool VisitCall(RtlCall call)
        {
            var site = state.OnBeforeCall(stackReg, call.ReturnAddressSize);
            ProcedureSignature sig;
            Address            addr = call.Target as Address;

            if (addr != null)
            {
                var impProc = scanner.GetImportedProcedure(addr, this.ric.Address);
                if (impProc != null && impProc.Characteristics.IsAlloca)
                {
                    return(ProcessAlloca(site, impProc));
                }

                var callee   = scanner.ScanProcedure(addr, null, state);
                var pcCallee = CreateProcedureConstant(callee);
                sig = callee.Signature;
                if (sig != null && sig.ParametersValid)
                {
                    Emit(BuildApplication(pcCallee, sig, site));
                }
                else
                {
                    Emit(new CallInstruction(pcCallee, site));
                }
                var pCallee = callee as Procedure;
                if (pCallee != null)
                {
                    program.CallGraph.AddEdge(blockCur.Statements.Last, pCallee);
                }
                return(OnAfterCall(sig, callee.Characteristics));
            }

            var procCallee = call.Target as ProcedureConstant;

            if (procCallee != null)
            {
                var ppp = procCallee.Procedure as PseudoProcedure;
                if (ppp != null)
                {
                    sig = ppp.Signature;
                    if (sig != null && sig.ParametersValid)
                    {
                        Emit(BuildApplication(procCallee, sig, site));
                    }
                    else
                    {
                        Emit(new CallInstruction(procCallee, site));
                    }
                    return(OnAfterCall(ppp.Signature, ppp.Characteristics));
                }
                var ep = procCallee.Procedure as ExternalProcedure;
                if (ep != null)
                {
                    sig = ep.Signature;
                    if (sig != null && sig.ParametersValid)
                    {
                        Emit(BuildApplication(procCallee, sig, site));
                    }
                    else
                    {
                        Emit(new CallInstruction(procCallee, site));
                    }
                    return(OnAfterCall(ep.Signature, ep.Characteristics));
                }
            }
            sig = scanner.GetCallSignatureAtAddress(ric.Address);
            if (sig != null)
            {
                Emit(BuildApplication(call.Target, sig, site));
                return(OnAfterCall(sig, null));  //$TODO: make characteristics available
            }

            var id = call.Target as Identifier;

            if (id != null)
            {
                var ppp = SearchBackForProcedureConstant(id);
                if (ppp != null)
                {
                    var e = CreateProcedureConstant(ppp);
                    if (ppp.Signature != null && ppp.Signature.ParametersValid)
                    {
                        Emit(BuildApplication(e, ppp.Signature, site));
                    }
                    else
                    {
                        Emit(new CallInstruction(e, site));
                    }
                    return(OnAfterCall(ppp.Signature, ppp.Characteristics));
                }
            }

            var imp = ImportedProcedureName(call.Target);

            if (imp != null)
            {
                Emit(BuildApplication(CreateProcedureConstant(imp), imp.Signature, site));
                return(OnAfterCall(imp.Signature, imp.Characteristics));
            }

            var syscall = program.Platform.FindService(call, state);

            if (syscall != null)
            {
                return(!EmitSystemServiceCall(syscall));
            }
            ProcessIndirectControlTransfer(ric.Address, call);

            var ic = new CallInstruction(call.Target, site);

            Emit(ic);
            sig = GuessProcedureSignature(ic);
            return(OnAfterCall(sig, null));
        }
Exemple #16
0
    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);
    }