Complete MIPS code generation support

With this CL code generation for MIPS is complete (though untested on
actual hardware).  Core and the boot classpath compile without issue.

The primary thrust here was to support expanding of short branch
sequences to long form during assembly if the displacement field overflowed.
That led to a general cleanup of creation on LIR nodes outside of the
normal flow.

Also introduced is a README to describe the state of MIPS support, as well
as memory barrier handling.

Change-Id: I251a2ef8d74bc7183406dce9493464be24a9d7f7
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
index 8a38db4..07eb672 100644
--- a/src/compiler/codegen/CodegenUtil.cc
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -410,21 +410,34 @@
     }
 }
 
+
+LIR* rawLIR(CompilationUnit* cUnit, int dalvikOffset, int opcode, int op0,
+            int op1, int op2, int op3, LIR* target)
+{
+    LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
+    insn->dalvikOffset = dalvikOffset;
+    insn->opcode = opcode;
+    insn->operands[0] = op0;
+    insn->operands[1] = op1;
+    insn->operands[2] = op2;
+    insn->operands[3] = op3;
+    insn->target = target;
+    oatSetupResourceMasks(insn);
+    if (opcode == kPseudoTargetLabel) {
+        // Always make labels scheduling barriers
+        insn->defMask = ENCODE_ALL;
+    }
+    return insn;
+}
+
 /*
  * The following are building blocks to construct low-level IRs with 0 - 4
  * operands.
  */
 LIR* newLIR0(CompilationUnit* cUnit, int opcode)
 {
-    LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
     DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
-    insn->opcode = opcode;
-    setupResourceMasks(insn);
-    insn->dalvikOffset = cUnit->currentDalvikOffset;
-    if (opcode == kPseudoTargetLabel) {
-        // Always make labels scheduling barriers
-        insn->defMask = ENCODE_ALL;
-    }
+    LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode);
     oatAppendLIR(cUnit, (LIR*) insn);
     return insn;
 }
@@ -432,12 +445,8 @@
 LIR* newLIR1(CompilationUnit* cUnit, int opcode,
                            int dest)
 {
-    LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
     DCHECK(isPseudoOpcode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
-    insn->opcode = opcode;
-    insn->operands[0] = dest;
-    setupResourceMasks(insn);
-    insn->dalvikOffset = cUnit->currentDalvikOffset;
+    LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest);
     oatAppendLIR(cUnit, (LIR*) insn);
     return insn;
 }
@@ -445,14 +454,9 @@
 LIR* newLIR2(CompilationUnit* cUnit, int opcode,
                            int dest, int src1)
 {
-    LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
     DCHECK(isPseudoOpcode(opcode) ||
            (EncodingMap[opcode].flags & IS_BINARY_OP));
-    insn->opcode = opcode;
-    insn->operands[0] = dest;
-    insn->operands[1] = src1;
-    setupResourceMasks(insn);
-    insn->dalvikOffset = cUnit->currentDalvikOffset;
+    LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1);
     oatAppendLIR(cUnit, (LIR*) insn);
     return insn;
 }
@@ -460,18 +464,13 @@
 LIR* newLIR3(CompilationUnit* cUnit, int opcode,
                            int dest, int src1, int src2)
 {
-    LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
     DCHECK(isPseudoOpcode(opcode) ||
            (EncodingMap[opcode].flags & IS_TERTIARY_OP))
             << (int)opcode << " "
             << PrettyMethod(cUnit->method_idx, *cUnit->dex_file) << " "
             << cUnit->currentDalvikOffset;
-    insn->opcode = opcode;
-    insn->operands[0] = dest;
-    insn->operands[1] = src1;
-    insn->operands[2] = src2;
-    setupResourceMasks(insn);
-    insn->dalvikOffset = cUnit->currentDalvikOffset;
+    LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1,
+                       src2);
     oatAppendLIR(cUnit, (LIR*) insn);
     return insn;
 }
@@ -479,16 +478,10 @@
 LIR* newLIR4(CompilationUnit* cUnit, int opcode,
                            int dest, int src1, int src2, int info)
 {
-    LIR* insn = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
     DCHECK(isPseudoOpcode(opcode) ||
            (EncodingMap[opcode].flags & IS_QUAD_OP));
-    insn->opcode = opcode;
-    insn->operands[0] = dest;
-    insn->operands[1] = src1;
-    insn->operands[2] = src2;
-    insn->operands[3] = info;
-    setupResourceMasks(insn);
-    insn->dalvikOffset = cUnit->currentDalvikOffset;
+    LIR* insn = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, dest, src1,
+                       src2, info);
     oatAppendLIR(cUnit, (LIR*) insn);
     return insn;
 }
diff --git a/src/compiler/codegen/CompilerCodegen.h b/src/compiler/codegen/CompilerCodegen.h
index 26dad82..fdcb555 100644
--- a/src/compiler/codegen/CompilerCodegen.h
+++ b/src/compiler/codegen/CompilerCodegen.h
@@ -21,6 +21,9 @@
 
 namespace art {
 
+LIR* rawLIR(CompilationUnit* cUnit, int dalvikOffset, int opcode, int op0 = 0,
+            int op1 = 0, int op2 = 0, int op3 = 0, LIR* target = NULL);
+
 /* Lower middle-level IR to low-level IR for the whole method */
 void oatMethodMIR2LIR(CompilationUnit* cUnit);
 
diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/GenCommon.cc
index d0063fa..f33b374 100644
--- a/src/compiler/codegen/GenCommon.cc
+++ b/src/compiler/codegen/GenCommon.cc
@@ -58,10 +58,8 @@
 LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode, MIR* mir,
               ThrowKind kind)
 {
-    LIR* tgt = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
-    tgt->opcode = kPseudoThrowTarget;
-    tgt->operands[0] = kind;
-    tgt->operands[1] = mir ? mir->offset : 0;
+    LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
+                      mir ? mir->offset : 0);
     LIR* branch = opCondBranch(cUnit, cCode, tgt);
     // Remember branch target - will process later
     oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
@@ -72,10 +70,7 @@
 LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode,
                    int reg, int immVal, MIR* mir, ThrowKind kind)
 {
-    LIR* tgt = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
-    tgt->opcode = kPseudoThrowTarget;
-    tgt->operands[0] = kind;
-    tgt->operands[1] = mir->offset;
+    LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind, mir->offset);
     LIR* branch;
     if (cCode == kCondAl) {
         branch = opUnconditionalBranch(cUnit, tgt);
@@ -101,12 +96,8 @@
 LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
                         int reg1, int reg2, MIR* mir, ThrowKind kind)
 {
-    LIR* tgt = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
-    tgt->opcode = kPseudoThrowTarget;
-    tgt->operands[0] = kind;
-    tgt->operands[1] = mir ? mir->offset : 0;
-    tgt->operands[2] = reg1;
-    tgt->operands[3] = reg2;
+    LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
+                      mir ? mir->offset : 0, reg1, reg2);
 #if defined(TARGET_MIPS)
     LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt);
 #else
@@ -2127,11 +2118,8 @@
 #endif
     }
     LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
-    LIR* target = (LIR*)oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
-    target->dalvikOffset = cUnit->currentDalvikOffset;
-    target->opcode = kPseudoSuspendTarget;
-    target->operands[0] = (intptr_t)retLab;
-    target->operands[1] = mir->offset;
+    LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
+                         kPseudoSuspendTarget, (intptr_t)retLab, mir->offset);
     branch->target = (LIR*)target;
     oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
 }
diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc
index 79a72e7..acd2af5 100644
--- a/src/compiler/codegen/arm/Assemble.cc
+++ b/src/compiler/codegen/arm/Assemble.cc
@@ -1050,13 +1050,8 @@
                         lir->operands[0] : rLR;
 
                     // Add new Adr to generate the address
-                    LIR *newAdr = (LIR *)oatNew(cUnit, sizeof(LIR),
-                        true, kAllocLIR);
-                    newAdr->dalvikOffset = lir->dalvikOffset;
-                    newAdr->target = lir->target;
-                    newAdr->opcode = kThumb2Adr;
-                    newAdr->operands[0] = baseReg;
-                    oatSetupResourceMasks(newAdr);
+                    LIR* newAdr = rawLIR(cUnit, lir->dalvikOffset, kThumb2Adr,
+                                         baseReg, 0, 0, 0, lir->target);
                     oatInsertLIRBefore((LIR*)lir, (LIR*)newAdr);
 
                     // Convert to normal load
@@ -1083,17 +1078,14 @@
                 intptr_t target = targetLIR->offset;
                 int delta = target - pc;
                 if (delta > 126 || delta < 0) {
-                    /* Convert to cmp rx,#0 / b[eq/ne] tgt pair */
-                    LIR *newInst = (LIR *)oatNew(cUnit, sizeof(LIR),
-                        true, kAllocLIR);
-                    /* Make new branch instruction and insert after */
-                    newInst->dalvikOffset = lir->dalvikOffset;
-                    newInst->opcode = kThumbBCond;
-                    newInst->operands[0] = 0;
-                    newInst->operands[1] = (lir->opcode == kThumb2Cbz) ?
-                                            kArmCondEq : kArmCondNe;
-                    newInst->target = lir->target;
-                    oatSetupResourceMasks(newInst);
+                    /*
+                     * Convert to cmp rx,#0 / b[eq/ne] tgt pair
+                     * Make new branch instruction and insert after
+                     */
+                    LIR* newInst =
+                        rawLIR(cUnit, lir->dalvikOffset, kThumbBCond, 0,
+                               (lir->opcode == kThumb2Cbz) ? kArmCondEq : kArmCondNe,
+                               0, 0, lir->target);
                     oatInsertLIRAfter((LIR *)lir, (LIR *)newInst);
                     /* Convert the cb[n]z to a cmp rx, #0 ] */
                     lir->opcode = kThumbCmpRI8;
@@ -1209,26 +1201,14 @@
                 } else {
                     // convert to ldimm16l, ldimm16h, add tgt, pc, operands[0]
                     LIR *newMov16L =
-                        (LIR *)oatNew(cUnit, sizeof(LIR), true,
-                        kAllocLIR);
-                    newMov16L->dalvikOffset = lir->dalvikOffset;
-                    newMov16L->target = lir->target;
-                    newMov16L->opcode = kThumb2MovImm16LST;
-                    newMov16L->operands[0] = lir->operands[0];
-                    newMov16L->operands[2] = (intptr_t)lir;
-                    newMov16L->operands[3] = (intptr_t)tabRec;
-                    oatSetupResourceMasks(newMov16L);
+                        rawLIR(cUnit, lir->dalvikOffset, kThumb2MovImm16LST,
+                               lir->operands[0], 0, (intptr_t)lir, (intptr_t)tabRec,
+                               lir->target);
                     oatInsertLIRBefore((LIR*)lir, (LIR*)newMov16L);
                     LIR *newMov16H =
-                        (LIR *)oatNew(cUnit, sizeof(LIR), true,
-                        kAllocLIR);
-                    newMov16H->dalvikOffset = lir->dalvikOffset;
-                    newMov16H->target = lir->target;
-                    newMov16H->opcode = kThumb2MovImm16HST;
-                    newMov16H->operands[0] = lir->operands[0];
-                    newMov16H->operands[2] = (intptr_t)lir;
-                    newMov16H->operands[3] = (intptr_t)tabRec;
-                    oatSetupResourceMasks(newMov16H);
+                        rawLIR(cUnit, lir->dalvikOffset, kThumb2MovImm16HST,
+                               lir->operands[0], 0, (intptr_t)lir, (intptr_t)tabRec,
+                               lir->target);
                     oatInsertLIRBefore((LIR*)lir, (LIR*)newMov16H);
                     lir->opcode = kThumb2AddRRR;
                     lir->operands[1] = rPC;
diff --git a/src/compiler/codegen/arm/Thumb2/Factory.cc b/src/compiler/codegen/arm/Thumb2/Factory.cc
index 03a69d5..b6df8e3 100644
--- a/src/compiler/codegen/arm/Thumb2/Factory.cc
+++ b/src/compiler/codegen/arm/Thumb2/Factory.cc
@@ -68,14 +68,8 @@
     if (dataTarget == NULL) {
         dataTarget = addWordData(cUnit, &cUnit->literalList, value);
     }
-    LIR* loadPcRel = (LIR* ) oatNew(cUnit, sizeof(LIR), true,
-                                          kAllocLIR);
-    loadPcRel->dalvikOffset = cUnit->currentDalvikOffset;
-    loadPcRel->opcode = kThumb2Vldrs;
-    loadPcRel->target = (LIR* ) dataTarget;
-    loadPcRel->operands[0] = rDest;
-    loadPcRel->operands[1] = r15pc;
-    setupResourceMasks(loadPcRel);
+    LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset, kThumb2Vldrs,
+                            rDest, r15pc, 0, 0, dataTarget);
     setMemRefType(loadPcRel, true, kLiteral);
     loadPcRel->aliasInfo = (intptr_t)dataTarget;
     oatAppendLIR(cUnit, (LIR* ) loadPcRel);
@@ -177,13 +171,8 @@
     if (dataTarget == NULL) {
         dataTarget = addWordData(cUnit, &cUnit->literalList, value);
     }
-    LIR* loadPcRel = (LIR* ) oatNew(cUnit, sizeof(LIR), true,
-                                          kAllocLIR);
-    loadPcRel->opcode = kThumb2LdrPcRel12;
-    loadPcRel->target = (LIR* ) dataTarget;
-    loadPcRel->dalvikOffset = cUnit->currentDalvikOffset;
-    loadPcRel->operands[0] = rDest;
-    setupResourceMasks(loadPcRel);
+    LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
+                            kThumb2LdrPcRel12, rDest, 0, 0, 0, dataTarget);
     setMemRefType(loadPcRel, true, kLiteral);
     loadPcRel->aliasInfo = (intptr_t)dataTarget;
     res = loadPcRel;
@@ -643,14 +632,9 @@
                 dataTarget = addWideData(cUnit, &cUnit->literalList, valLo,
                                          valHi);
             }
-            LIR* loadPcRel = (LIR* ) oatNew(cUnit, sizeof(LIR), true,
-                                                  kAllocLIR);
-            loadPcRel->dalvikOffset = cUnit->currentDalvikOffset;
-            loadPcRel->opcode = kThumb2Vldrd;
-            loadPcRel->target = (LIR* ) dataTarget;
-            loadPcRel->operands[0] = S2D(rDestLo, rDestHi);
-            loadPcRel->operands[1] = r15pc;
-            setupResourceMasks(loadPcRel);
+            LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
+                                    kThumb2Vldrd, S2D(rDestLo, rDestHi),
+                                    r15pc, 0, 0, dataTarget);
             setMemRefType(loadPcRel, true, kLiteral);
             loadPcRel->aliasInfo = (intptr_t)dataTarget;
             oatAppendLIR(cUnit, (LIR* ) loadPcRel);
@@ -1042,28 +1026,22 @@
 
 LIR* fpRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
 {
-    LIR* res = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
-    res->dalvikOffset = cUnit->currentDalvikOffset;
-    res->operands[0] = rDest;
-    res->operands[1] = rSrc;
+    int opcode;
+    DCHECK_EQ(DOUBLEREG(rDest), DOUBLEREG(rSrc));
+    if (DOUBLEREG(rDest)) {
+        opcode = kThumb2Vmovd;
+    } else {
+        if (SINGLEREG(rDest)) {
+            opcode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
+        } else {
+            DCHECK(SINGLEREG(rSrc));
+            opcode = kThumb2Fmrs;
+        }
+    }
+    LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rDest, rSrc);
     if (rDest == rSrc) {
         res->flags.isNop = true;
-    } else {
-        DCHECK_EQ(DOUBLEREG(rDest), DOUBLEREG(rSrc));
-        if (DOUBLEREG(rDest)) {
-            res->opcode = kThumb2Vmovd;
-        } else {
-            if (SINGLEREG(rDest)) {
-                res->opcode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
-            } else {
-                DCHECK(SINGLEREG(rSrc));
-                res->opcode = kThumb2Fmrs;
-            }
-        }
-        res->operands[0] = rDest;
-        res->operands[1] = rSrc;
     }
-    setupResourceMasks(res);
     return res;
 }
 
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index cba37b7..1351992 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -428,8 +428,6 @@
     ArmOpcode opcode;
     if (FPREG(rDest) || FPREG(rSrc))
         return fpRegCopy(cUnit, rDest, rSrc);
-    res = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
-    res->dalvikOffset = cUnit->currentDalvikOffset;
     if (LOWREG(rDest) && LOWREG(rSrc))
         opcode = kThumbMovRR;
     else if (!LOWREG(rDest) && !LOWREG(rSrc))
@@ -438,11 +436,7 @@
          opcode = kThumbMovRR_H2L;
     else
          opcode = kThumbMovRR_L2H;
-
-    res->operands[0] = rDest;
-    res->operands[1] = rSrc;
-    res->opcode = opcode;
-    setupResourceMasks(res);
+    res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rDest, rSrc);
     if (rDest == rSrc) {
         res->flags.isNop = true;
     }
diff --git a/src/compiler/codegen/mips/Assemble.cc b/src/compiler/codegen/mips/Assemble.cc
index 5f215ef..a70d9da 100644
--- a/src/compiler/codegen/mips/Assemble.cc
+++ b/src/compiler/codegen/mips/Assemble.cc
@@ -106,44 +106,44 @@
                  "andi", "!0r,!1r,0x!2h(!2d)", 4),
     ENCODING_MAP(kMipsB, 0x10000000,
                  kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
+                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | NEEDS_FIXUP,
                  "b", "!0t!0N", 8),
     ENCODING_MAP(kMipsBal, 0x04110000,
                  kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
-                 "bal", "!0t!0N", 8),
+                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR |
+                 NEEDS_FIXUP, "bal", "!0t!0N", 8),
     ENCODING_MAP(kMipsBeq, 0x10000000,
                  kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
-                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
-                 "beq", "!0r,!1r,!2t!0N", 8),
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
+                 NEEDS_FIXUP, "beq", "!0r,!1r,!2t!0N", 8),
     ENCODING_MAP(kMipsBeqz, 0x10000000, /* same as beq above with t = $zero */
                  kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
-                 "beqz", "!0r,!1t!0N", 8),
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+                 NEEDS_FIXUP, "beqz", "!0r,!1t!0N", 8),
     ENCODING_MAP(kMipsBgez, 0x04010000,
                  kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
-                 "bgez", "!0r,!1t!0N", 8),
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+                 NEEDS_FIXUP, "bgez", "!0r,!1t!0N", 8),
     ENCODING_MAP(kMipsBgtz, 0x1C000000,
                  kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
-                 "bgtz", "!0r,!1t!0N", 8),
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+                 NEEDS_FIXUP, "bgtz", "!0r,!1t!0N", 8),
     ENCODING_MAP(kMipsBlez, 0x18000000,
                  kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
-                 "blez", "!0r,!1t!0N", 8),
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+                 NEEDS_FIXUP, "blez", "!0r,!1t!0N", 8),
     ENCODING_MAP(kMipsBltz, 0x04000000,
                  kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
-                 "bltz", "!0r,!1t!0N", 8),
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+                 NEEDS_FIXUP, "bltz", "!0r,!1t!0N", 8),
     ENCODING_MAP(kMipsBnez, 0x14000000, /* same as bne below with t = $zero */
                  kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
-                 "bnez", "!0r,!1t!0N", 8),
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+                 NEEDS_FIXUP, "bnez", "!0r,!1t!0N", 8),
     ENCODING_MAP(kMipsBne, 0x14000000,
                  kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
-                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
-                 "bne", "!0r,!1r,!2t!0N", 8),
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01 |
+                 NEEDS_FIXUP, "bne", "!0r,!1r,!2t!0N", 8),
     ENCODING_MAP(kMipsDiv, 0x0000001a,
                  kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
                  kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
@@ -164,8 +164,8 @@
                  "jalr", "!0r,!1r!0N", 8),
     ENCODING_MAP(kMipsJr, 0x00000008,
                  kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
-                 "jr", "!0r!0N", 8),
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0 |
+                 NEEDS_FIXUP, "jr", "!0r!0N", 8),
     ENCODING_MAP(kMipsLahi, 0x3C000000,
                  kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
@@ -400,26 +400,117 @@
 #endif
     ENCODING_MAP(kMipsDelta, 0x27e00000,
                  kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, 15, 0,
-                 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | REG_USE_LR,
-                 "addiu", "!0r,r_ra,0x!1h(!1d)", 4),
+                 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | REG_USE_LR |
+                 NEEDS_FIXUP, "addiu", "!0r,r_ra,0x!1h(!1d)", 4),
     ENCODING_MAP(kMipsDeltaHi, 0x3C000000,
                  kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0,
+                 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | NEEDS_FIXUP,
                  "lui", "!0r,0x!1h(!1d)", 4),
     ENCODING_MAP(kMipsDeltaLo, 0x34000000,
                  kFmtBlt5_2, 16, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
-                 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0_USE0,
+                 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0_USE0 | NEEDS_FIXUP,
                  "ori", "!0r,!0r,0x!1h(!1d)", 4),
-    ENCODING_MAP(kMipsCurrPC, 0x0c000000,
+    ENCODING_MAP(kMipsCurrPC, 0x04110020,
                  kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
                  "pc2ra", "; r_ra <- .+8", 4),
+    ENCODING_MAP(kMipsSync, 0x0000000f,
+                 kFmtBitBlt, 10, 6, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP,
+                 "sync", ";", 4),
     ENCODING_MAP(kMipsUndefined, 0x64000000,
                  kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, NO_OPERAND,
                  "undefined", "", 4),
 };
 
+
+/*
+ * Convert a short-form branch to long form.  Hopefully, this won't happen
+ * very often because the PIC sequence is especially unfortunate.
+ *
+ * Orig conditional branch
+ * -----------------------
+ *      beq  rs,rt,target
+ *
+ * Long conditional branch
+ * -----------------------
+ *      bne  rs,rt,hop
+ *      bal  .+8   ; r_RA <- anchor
+ *      lui  r_AT, ((target-anchor) >> 16)
+ * anchor:
+ *      ori  r_AT, r_AT, ((target-anchor) & 0xffff)
+ *      addu r_AT, r_AT, r_RA
+ *      jr   r_AT
+ * hop:
+ *
+ * Orig unconditional branch
+ * -------------------------
+ *      b target
+ *
+ * Long unconditional branch
+ * -----------------------
+ *      bal  .+8   ; r_RA <- anchor
+ *      lui  r_AT, ((target-anchor) >> 16)
+ * anchor:
+ *      ori  r_AT, r_AT, ((target-anchor) & 0xffff)
+ *      addu r_AT, r_AT, r_RA
+ *      jr   r_AT
+ *
+ *
+ * NOTE: An out-of-range bal isn't supported because it should
+ * never happen with the current PIC model.
+ */
+void convertShortToLongBranch(CompilationUnit* cUnit, LIR* lir)
+{
+    // For conditional branches we'll need to reverse the sense
+    bool unconditional = false;
+    int opcode = lir->opcode;
+    int dalvikOffset = lir->dalvikOffset;
+    switch(opcode) {
+        case kMipsBal:
+            LOG(FATAL) << "long branch and link unsupported";
+        case kMipsB:
+            unconditional = true;
+            break;
+        case kMipsBeq:  opcode = kMipsBne; break;
+        case kMipsBne:  opcode = kMipsBeq; break;
+        case kMipsBeqz: opcode = kMipsBnez; break;
+        case kMipsBgez: opcode = kMipsBltz; break;
+        case kMipsBgtz: opcode = kMipsBlez; break;
+        case kMipsBlez: opcode = kMipsBgtz; break;
+        case kMipsBltz: opcode = kMipsBgez; break;
+        case kMipsBnez: opcode = kMipsBeqz; break;
+        default:
+            LOG(FATAL) << "Unexpected branch kind " << (int)opcode;
+    }
+    LIR* hopTarget = NULL;
+    if (!unconditional) {
+        hopTarget = rawLIR(cUnit, dalvikOffset, kPseudoTargetLabel);
+        LIR* hopBranch = rawLIR(cUnit, dalvikOffset, opcode, lir->operands[0],
+                                lir->operands[1], 0, 0, hopTarget);
+        oatInsertLIRBefore(lir, hopBranch);
+    }
+    LIR* currPC = rawLIR(cUnit, dalvikOffset, kMipsCurrPC);
+    oatInsertLIRBefore(lir, currPC);
+    LIR* anchor = rawLIR(cUnit, dalvikOffset, kPseudoTargetLabel);
+    LIR* deltaHi = rawLIR(cUnit, dalvikOffset, kMipsDeltaHi, r_AT, 0,
+                          (uintptr_t)anchor, 0, lir->target);
+    oatInsertLIRBefore(lir, deltaHi);
+    oatInsertLIRBefore(lir, anchor);
+    LIR* deltaLo = rawLIR(cUnit, dalvikOffset, kMipsDeltaLo, r_AT, 0,
+                          (uintptr_t)anchor, 0, lir->target);
+    oatInsertLIRBefore(lir, deltaLo);
+    LIR* addu = rawLIR(cUnit, dalvikOffset, kMipsAddu, r_AT, r_AT, r_RA);
+    oatInsertLIRBefore(lir, addu);
+    LIR* jr = rawLIR(cUnit, dalvikOffset, kMipsJr, r_AT);
+    oatInsertLIRBefore(lir, jr);
+    if (!unconditional) {
+        oatInsertLIRBefore(lir, hopTarget);
+    }
+    lir->flags.isNop = true;
+}
+
 /*
  * Assemble the LIR into binary instruction format.  Note that we may
  * discover that pc-relative displacements may not fit the selected
@@ -442,108 +533,112 @@
             continue;
         }
 
-// TODO: check for lir->flags.pcRelFixup
-
-        if (lir->opcode == kMipsDelta) {
-            int offset1 = ((LIR*)lir->operands[2])->offset;
-            SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
-            int offset2 = tabRec ? tabRec->offset : lir->target->offset;
-            int delta = offset2 - offset1;
-            if ((delta & 0xffff) == delta) {
-                // Fits
-                lir->operands[1] = delta;
-            } else {
-                // Doesn't fit - must expand to kMipsDelta[Hi|Lo] pair
-                LIR *newDeltaHi =
-                    (LIR *)oatNew(cUnit, sizeof(LIR), true,
-                    kAllocLIR);
-                newDeltaHi->dalvikOffset = lir->dalvikOffset;
-                newDeltaHi->target = lir->target;
-                newDeltaHi->opcode = kMipsDeltaHi;
-                newDeltaHi->operands[0] = lir->operands[0];
-                newDeltaHi->operands[2] = lir->operands[2];
-                newDeltaHi->operands[3] = lir->operands[3];
-                oatSetupResourceMasks(newDeltaHi);
-                oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaHi);
-                LIR *newDeltaLo =
-                    (LIR *)oatNew(cUnit, sizeof(LIR), true,
-                    kAllocLIR);
-                newDeltaLo->dalvikOffset = lir->dalvikOffset;
-                newDeltaLo->target = lir->target;
-                newDeltaLo->opcode = kMipsDeltaLo;
-                newDeltaLo->operands[0] = lir->operands[0];
-                newDeltaLo->operands[2] = lir->operands[2];
-                newDeltaLo->operands[3] = lir->operands[3];
-                oatSetupResourceMasks(newDeltaLo);
-                oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaLo);
-                lir->flags.isNop = true;
-                res = kRetryAll;
+        if (lir->flags.pcRelFixup) {
+            if (lir->opcode == kMipsDelta) {
+                /*
+                 * The "Delta" pseudo-ops load the difference between
+                 * two pc-relative locations into a the target register
+                 * found in operands[0].  The delta is determined by
+                 * (label2 - label1), where label1 is a standard
+                 * kPseudoTargetLabel and is stored in operands[2].
+                 * If operands[3] is null, then label2 is a kPseudoTargetLabel
+                 * and is found in lir->target.  If operands[3] is non-NULL,
+                 * then it is a Switch/Data table.
+                 */
+                int offset1 = ((LIR*)lir->operands[2])->offset;
+                SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
+                int offset2 = tabRec ? tabRec->offset : lir->target->offset;
+                int delta = offset2 - offset1;
+                if ((delta & 0xffff) == delta) {
+                    // Fits
+                    lir->operands[1] = delta;
+                } else {
+                    // Doesn't fit - must expand to kMipsDelta[Hi|Lo] pair
+                    LIR *newDeltaHi =
+                          rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaHi,
+                                 lir->operands[0], 0, lir->operands[2],
+                                 lir->operands[3], lir->target);
+                    oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaHi);
+                    LIR *newDeltaLo =
+                          rawLIR(cUnit, lir->dalvikOffset, kMipsDeltaLo,
+                                 lir->operands[0], 0, lir->operands[2],
+                                 lir->operands[3], lir->target);
+                    oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaLo);
+                    lir->flags.isNop = true;
+                    res = kRetryAll;
+                }
+            } else if (lir->opcode == kMipsDeltaLo) {
+                int offset1 = ((LIR*)lir->operands[2])->offset;
+                SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
+                int offset2 = tabRec ? tabRec->offset : lir->target->offset;
+                int delta = offset2 - offset1;
+                lir->operands[1] = delta & 0xffff;
+            } else if (lir->opcode == kMipsDeltaHi) {
+                int offset1 = ((LIR*)lir->operands[2])->offset;
+                SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
+                int offset2 = tabRec ? tabRec->offset : lir->target->offset;
+                int delta = offset2 - offset1;
+                lir->operands[1] = (delta >> 16) & 0xffff;
+            } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
+                LIR *targetLIR = (LIR *) lir->target;
+                intptr_t pc = lir->offset + 4;
+                intptr_t target = targetLIR->offset;
+                int delta = target - pc;
+                if (delta & 0x3) {
+                    LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
+                }
+                if (delta > 131068 || delta < -131069) {
+                    res = kRetryAll;
+                    convertShortToLongBranch(cUnit, lir);
+                } else {
+                    lir->operands[0] = delta >> 2;
+                }
+            } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
+                LIR *targetLIR = (LIR *) lir->target;
+                intptr_t pc = lir->offset + 4;
+                intptr_t target = targetLIR->offset;
+                int delta = target - pc;
+                if (delta & 0x3) {
+                    LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
+                }
+                if (delta > 131068 || delta < -131069) {
+                    res = kRetryAll;
+                    convertShortToLongBranch(cUnit, lir);
+                } else {
+                    lir->operands[1] = delta >> 2;
+                }
+            } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
+                LIR *targetLIR = (LIR *) lir->target;
+                intptr_t pc = lir->offset + 4;
+                intptr_t target = targetLIR->offset;
+                int delta = target - pc;
+                if (delta & 0x3) {
+                    LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
+                }
+                if (delta > 131068 || delta < -131069) {
+                    res = kRetryAll;
+                    convertShortToLongBranch(cUnit, lir);
+                } else {
+                    lir->operands[2] = delta >> 2;
+                }
+            } else if (lir->opcode == kMipsJal) {
+                intptr_t curPC = (startAddr + lir->offset + 4) & ~3;
+                intptr_t target = lir->operands[0];
+                /* ensure PC-region branch can be used */
+                DCHECK_EQ((curPC & 0xF0000000), (target & 0xF0000000));
+                if (target & 0x3) {
+                    LOG(FATAL) << "Jump target not multiple of 4: " << target;
+                }
+                lir->operands[0] =  target >> 2;
+            } else if (lir->opcode == kMipsLahi) { /* ld address hi (via lui) */
+                LIR *targetLIR = (LIR *) lir->target;
+                intptr_t target = startAddr + targetLIR->offset;
+                lir->operands[1] = target >> 16;
+            } else if (lir->opcode == kMipsLalo) { /* ld address lo (via ori) */
+                LIR *targetLIR = (LIR *) lir->target;
+                intptr_t target = startAddr + targetLIR->offset;
+                lir->operands[2] = lir->operands[2] + target;
             }
-        } else if (lir->opcode == kMipsDeltaLo) {
-            int offset1 = ((LIR*)lir->operands[2])->offset;
-            SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
-            int offset2 = tabRec ? tabRec->offset : lir->target->offset;
-            int delta = offset2 - offset1;
-            lir->operands[1] = delta & 0xffff;
-        } else if (lir->opcode == kMipsDeltaHi) {
-            int offset1 = ((LIR*)lir->operands[2])->offset;
-            SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
-            int offset2 = tabRec ? tabRec->offset : lir->target->offset;
-            int delta = offset2 - offset1;
-            lir->operands[1] = (delta >> 16) & 0xffff;
-        } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
-            LIR *targetLIR = (LIR *) lir->target;
-            intptr_t pc = lir->offset + 4;
-            intptr_t target = targetLIR->offset;
-            int delta = target - pc;
-            if (delta & 0x3) {
-                LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
-            }
-            if (delta > 131068 || delta < -131069) {
-                UNIMPLEMENTED(FATAL) << "B out of range, need long sequence: " << delta;
-            }
-            lir->operands[0] = delta >> 2;
-        } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
-            LIR *targetLIR = (LIR *) lir->target;
-            intptr_t pc = lir->offset + 4;
-            intptr_t target = targetLIR->offset;
-            int delta = target - pc;
-            if (delta & 0x3) {
-                LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
-            }
-            if (delta > 131068 || delta < -131069) {
-                UNIMPLEMENTED(FATAL) << "B[eq|ne]z needs long sequence: " << delta;
-            }
-            lir->operands[1] = delta >> 2;
-        } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
-            LIR *targetLIR = (LIR *) lir->target;
-            intptr_t pc = lir->offset + 4;
-            intptr_t target = targetLIR->offset;
-            int delta = target - pc;
-            if (delta & 0x3) {
-                LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
-            }
-            if (delta > 131068 || delta < -131069) {
-                UNIMPLEMENTED(FATAL) << "B[eq|ne] needs long sequence: " << delta;
-            }
-            lir->operands[2] = delta >> 2;
-        } else if (lir->opcode == kMipsJal) {
-            intptr_t curPC = (startAddr + lir->offset + 4) & ~3;
-            intptr_t target = lir->operands[0];
-            /* ensure PC-region branch can be used */
-            DCHECK_EQ((curPC & 0xF0000000), (target & 0xF0000000));
-            if (target & 0x3) {
-                LOG(FATAL) << "Jump target not multiple of 4: " << target;
-            }
-            lir->operands[0] =  target >> 2;
-        } else if (lir->opcode == kMipsLahi) { /* load address hi (via lui) */
-            LIR *targetLIR = (LIR *) lir->target;
-            intptr_t target = startAddr + targetLIR->offset;
-            lir->operands[1] = target >> 16;
-        } else if (lir->opcode == kMipsLalo) { /* load address lo (via ori) */
-            LIR *targetLIR = (LIR *) lir->target;
-            intptr_t target = startAddr + targetLIR->offset;
-            lir->operands[2] = lir->operands[2] + target;
         }
 
         /*
diff --git a/src/compiler/codegen/mips/Mips32/Factory.cc b/src/compiler/codegen/mips/Mips32/Factory.cc
index 105677e..ecc0180 100644
--- a/src/compiler/codegen/mips/Mips32/Factory.cc
+++ b/src/compiler/codegen/mips/Mips32/Factory.cc
@@ -28,7 +28,8 @@
                          r_T0, r_T1, r_T2, r_T3, r_T4, r_T5, r_T6, r_T7,
                          r_S0, r_S1, r_S2, r_S3, r_S4, r_S5, r_S6, r_S7, r_T8,
                          r_T9, r_K0, r_K1, r_GP, r_SP, r_FP, r_RA};
-static int reservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP, r_RA};
+static int reservedRegs[] = {r_ZERO, r_AT, r_S0, r_S1, r_K0, r_K1, r_GP, r_SP,
+                             r_RA};
 static int coreTemps[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
                           r_T3, r_T4, r_T5, r_T6, r_T7, r_T8, r_T9};
 #ifdef __mips_hard_float
@@ -51,33 +52,31 @@
 #ifdef __mips_hard_float
 LIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
 {
-    LIR* res = (LIR *) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
-    res->operands[0] = rDest;
-    res->operands[1] = rSrc;
-    if (rDest == rSrc) {
-        res->flags.isNop = true;
+    int opcode;
+    /* must be both DOUBLE or both not DOUBLE */
+    DCHECK_EQ(DOUBLEREG(rDest),DOUBLEREG(rSrc));
+    if (DOUBLEREG(rDest)) {
+        opcode = kMipsFmovd;
     } else {
-        /* must be both DOUBLE or both not DOUBLE */
-        DCHECK_EQ(DOUBLEREG(rDest),DOUBLEREG(rSrc));
-        if (DOUBLEREG(rDest)) {
-            res->opcode = kMipsFmovd;
-        } else {
-            if (SINGLEREG(rDest)) {
-                if (SINGLEREG(rSrc)) {
-                    res->opcode = kMipsFmovs;
-                } else {
-                    /* note the operands are swapped for the mtc1 instr */
-                    res->opcode = kMipsMtc1;
-                    res->operands[0] = rSrc;
-                    res->operands[1] = rDest;
-                }
+        if (SINGLEREG(rDest)) {
+            if (SINGLEREG(rSrc)) {
+                opcode = kMipsFmovs;
             } else {
-                DCHECK(SINGLEREG(rSrc));
-                res->opcode = kMipsMfc1;
+                /* note the operands are swapped for the mtc1 instr */
+                int tOpnd = rSrc;
+                rSrc = rDest;
+                rDest = tOpnd;
+                opcode = kMipsMtc1;
             }
+        } else {
+            DCHECK(SINGLEREG(rSrc));
+            opcode = kMipsMfc1;
         }
     }
-    setupResourceMasks(res);
+    LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rSrc, rDest);
+    if (rDest == rSrc) {
+        res->flags.isNop = true;
+    }
     return res;
 }
 #endif
diff --git a/src/compiler/codegen/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/Mips32/Gen.cc
index c975889..2bb2f7a 100644
--- a/src/compiler/codegen/mips/Mips32/Gen.cc
+++ b/src/compiler/codegen/mips/Mips32/Gen.cc
@@ -389,8 +389,7 @@
             swapped = true;
             break;
         default:
-            UNIMPLEMENTED(FATAL) << "No support for ConditionCode: "
-                                 << (int) cond;
+            LOG(FATAL) << "No support for ConditionCode: " << (int) cond;
             return NULL;
     }
     if (cmpZero) {
@@ -445,19 +444,12 @@
 
 LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
 {
-    LIR* res;
-    MipsOpCode opcode;
 #ifdef __mips_hard_float
     if (FPREG(rDest) || FPREG(rSrc))
         return fpRegCopy(cUnit, rDest, rSrc);
 #endif
-    res = (LIR *) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
-    opcode = kMipsMove;
-    assert(LOWREG(rDest) && LOWREG(rSrc));
-    res->operands[0] = rDest;
-    res->operands[1] = rSrc;
-    res->opcode = opcode;
-    setupResourceMasks(res);
+    LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove,
+                      rDest, rSrc);
     if (rDest == rSrc) {
         res->flags.isNop = true;
     }
diff --git a/src/compiler/codegen/mips/MipsLIR.h b/src/compiler/codegen/mips/MipsLIR.h
index 5034623..18f06ae 100644
--- a/src/compiler/codegen/mips/MipsLIR.h
+++ b/src/compiler/codegen/mips/MipsLIR.h
@@ -311,9 +311,17 @@
     kMipsRor = 0x3
 } MipsShiftEncodings;
 
-// FIXME: Need support for barriers.  Adding these defines to allow compile
-#define kST 0
-#define kSY 1
+// MIPS sync kinds (Note: support for kinds other than kSYNC0 may not exist)
+#define kSYNC0        0x00
+#define kSYNC_WMB     0x04
+#define kSYNC_MB      0x01
+#define kSYNC_ACQUIRE 0x11
+#define kSYNC_RELEASE 0x12
+#define kSYNC_RMB     0x13
+
+// TODO: Use smaller hammer when appropriate for target CPU
+#define kST kSYNC0
+#define kSY kSYNC0
 
 #define isPseudoOpcode(opCode) ((int)(opCode) < 0)
 
@@ -430,6 +438,7 @@
     kMipsDeltaHi, /* Pseudo for lui t, high16(<label>-<label>) */
     kMipsDeltaLo, /* Pseudo for ori t, s, low16(<label>-<label>) */
     kMipsCurrPC,  /* jal to .+8 to materialize pc */
+    kMipsSync,    /* sync kind [000000] [0000000000000000] s[10..6] [001111] */
     kMipsUndefined,  /* undefined [011001xxxxxxxxxxxxxxxx] */
     kMipsLast
 } MipsOpCode;
@@ -463,7 +472,6 @@
     kMemStore,
     kPCRelFixup,
     kRegUseLR,
-// FIXME: add NEEDS_FIXUP to instruction attributes
 } MipsOpFeatureFlags;
 
 #define IS_LOAD         (1 << kMemLoad)
diff --git a/src/compiler/codegen/mips/MipsRallocUtil.cc b/src/compiler/codegen/mips/MipsRallocUtil.cc
index 774dffc..3cad4d9 100644
--- a/src/compiler/codegen/mips/MipsRallocUtil.cc
+++ b/src/compiler/codegen/mips/MipsRallocUtil.cc
@@ -47,7 +47,7 @@
  */
 void oatMarkPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
 {
-    UNIMPLEMENTED(FATAL) << "No support yet for promoted FP regs";
+    LOG(FATAL) << "No support yet for promoted FP regs";
 }
 
 void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
diff --git a/src/compiler/codegen/mips/README.mips b/src/compiler/codegen/mips/README.mips
new file mode 100644
index 0000000..5add2f3
--- /dev/null
+++ b/src/compiler/codegen/mips/README.mips
@@ -0,0 +1,57 @@
+               Notes on the Mips target (3/4/2012)
+               -----------------------------------
+
+Testing
+
+The initial implementation of Mips support in the compiler is untested on
+actual hardware, and as such should be expected to have many bugs.  However,
+the vast majority of code for Mips support is either shared with other
+tested targets, or was taken from the functional Mips JIT compiler.  The
+expectation is that when it is first tried out on actual hardware lots of
+small bugs will be flushed out, but it should not take long to get it
+solidly running.  The following area are considered most likely to have
+problems that need to be addressed:
+
+    o Endianness.  Focus was on little-endian support, and if a big-endian
+      target is desired, you should pay particular attention to the
+      code generation for switch tables, fill array data, 64-bit
+      data handling and the register usage conventions.
+
+    o The memory model.  Verify that oatGenMemoryBarrier() generates the
+      appropriate flavor of sync.
+
+Register promotion
+
+The resource masks in the LIR structure are 64-bits wide, which is enough
+room to fully describe def/use info for Arm and x86 instructions.  However,
+the larger number of MIPS core and float registers render this too small.
+Currently, the workaround for this limitation is to avoid using floating
+point registers 16-31.  These are the callee-save registers, which therefore
+means that no floating point promotion is allowed.  Among the solution are:
+     o Expand the def/use mask (which, unfortunately, is a significant change)
+     o The Arm target uses 52 of the 64 bits, so we could support float
+       registers 16-27 without much effort.
+     o We could likely assign the 4 non-register bits (kDalvikReg, kLiteral,
+       kHeapRef & kMustNotAlias) to positions occuped by MIPS registers that
+       don't need def/use bits because they are never modified by code
+       subject to scheduling: r_K0, r_K1, r_SP, r_ZERO, r_S1 (rSELF).
+
+Branch delay slots
+
+Little to no attempt was made to fill branch delay slots.  Branch
+instructions in the encoding map are given a length of 8 bytes to include
+an implicit NOP.  It should not be too difficult to provide a slot-filling
+pass following successful assembly, but thought should be given to the
+design.  Branches are currently treated as scheduling barriers.  One
+simple solution would be to copy the instruction at branch targets to the
+slot and adjust the displacement.  However, given that code expansion is
+already a problem it would be preferable to use a more sophisticated
+scheduling solution.
+
+Code expansion
+
+Code expansion for the MIPS target is significantly higher than we see
+for Arm and x86.  It might make sense to replace the inline code generation
+for some of the more verbose Dalik byte codes with subroutine calls to
+shared helper functions.
+
diff --git a/src/compiler/codegen/mips/mips/ArchVariant.cc b/src/compiler/codegen/mips/mips/ArchVariant.cc
index 32b50e9..6d29fc5 100644
--- a/src/compiler/codegen/mips/mips/ArchVariant.cc
+++ b/src/compiler/codegen/mips/mips/ArchVariant.cc
@@ -52,7 +52,7 @@
 void oatGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
 {
 #if ANDROID_SMP != 0
-    // FIXME: what to do here for Mips?
+    newLIR1(cUnit, kMipsSync, barrierKind);
 #endif
 }