Multi-target support

This CL represents a step towards splitting out the target dependent
and target independent portions of the compiler, and also adds in the
beginning of a MIPS compiler based on the MIPS AOSP Jit submission.

More polish is clearly needed, but the split is here probably pretty
close.  The MIPS code will not compile at this point (and there is no
makefile target at present), but it's pretty close.

There should be no changes in functionality of the Arm compiler in this
CL - just moved stuff around.

Change-Id: Ia66b2847e22644a1ec63e66bf5f2fee722f963d4
diff --git a/build/Android.common.mk b/build/Android.common.mk
index dd92042..aee7bdd 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -239,7 +239,6 @@
 	src/compiler/codegen/arm/ArchUtility.cc \
 	src/compiler/codegen/arm/ArmRallocUtil.cc \
 	src/compiler/codegen/arm/Assemble.cc \
-	src/compiler/codegen/arm/LocalOptimizations.cc \
 	src/compiler/codegen/arm/armv7-a/Codegen.cc \
 	src/jni_internal_arm.cc \
 	src/jni_internal_x86.cc
diff --git a/src/compiler/Compiler.h b/src/compiler/Compiler.h
index 16a48df..a7dc798 100644
--- a/src/compiler/Compiler.h
+++ b/src/compiler/Compiler.h
@@ -32,10 +32,19 @@
 #define DEBUGGER_METHOD_ENTRY -1
 #define DEBUGGER_METHOD_EXIT -2
 
+/*
+ * Assembly is an iterative process, and usually terminates within
+ * two or three passes.  This should be high enough to handle bizarre
+ * cases, but detect an infinite loop bug.
+ */
+#define MAX_ASSEMBLER_RETRIES 50
+
 typedef enum OatInstructionSetType {
     DALVIK_OAT_NONE = 0,
     DALVIK_OAT_ARM,
     DALVIK_OAT_THUMB2,
+    DALVIK_OAT_IA32,
+    DALVIK_OAT_MIPS32
 } OatInstructionSetType;
 
 /* Supress optimization if corresponding bit set */
@@ -206,6 +215,8 @@
 u8 oatGetRegResourceMask(int reg);
 void oatDumpCFG(struct CompilationUnit* cUnit, const char* dirPrefix);
 void oatProcessSwitchTables(CompilationUnit* cUnit);
+bool oatIsFpReg(int reg);
+uint32_t oatFpRegMask(void);
 
 }  // namespace art
 
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index 9a992a1..66cc322 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -56,6 +56,34 @@
     s2 sRegLow;           // SSA name for low Dalvik word
 } RegLocation;
 
+ /*
+ * Data structure tracking the mapping between a Dalvik register (pair) and a
+ * native register (pair). The idea is to reuse the previously loaded value
+ * if possible, otherwise to keep the value in a native register as long as
+ * possible.
+ */
+typedef struct RegisterInfo {
+    int reg;                    // Reg number
+    bool inUse;                 // Has it been allocated?
+    bool isTemp;                // Can allocate as temp?
+    bool pair;                  // Part of a register pair?
+    int partner;                // If pair, other reg of pair
+    bool live;                  // Is there an associated SSA name?
+    bool dirty;                 // If live, is it dirty?
+    int sReg;                   // Name of live value
+    struct LIR *defStart;       // Starting inst in last def sequence
+    struct LIR *defEnd;         // Ending inst in last def sequence
+} RegisterInfo;
+
+typedef struct RegisterPool {
+    int numCoreRegs;
+    RegisterInfo *coreRegs;
+    int nextCoreReg;
+    int numFPRegs;
+    RegisterInfo *FPRegs;
+    int nextFPReg;
+} RegisterPool;
+
 #define INVALID_SREG (-1)
 #define INVALID_VREG (0xFFFFU)
 #define INVALID_REG (0xFF)
@@ -342,6 +370,17 @@
      struct Memstats* mstats;
 } CompilationUnit;
 
+typedef enum OpSize {
+    kWord,
+    kLong,
+    kSingle,
+    kDouble,
+    kUnsignedHalf,
+    kSignedHalf,
+    kUnsignedByte,
+    kSignedByte,
+} OpSize;
+
 BasicBlock* oatNewBB(CompilationUnit* cUnit, BBType blockType, int blockId);
 
 void oatAppendMIR(BasicBlock* bb, MIR* mir);
diff --git a/src/compiler/Ralloc.cc b/src/compiler/Ralloc.cc
index b450393..bf9cb6a7 100644
--- a/src/compiler/Ralloc.cc
+++ b/src/compiler/Ralloc.cc
@@ -293,9 +293,10 @@
              i, storageName[table[i].location], table[i].wide ? 'W' : 'N',
              table[i].defined ? 'D' : 'U', table[i].fp ? 'F' : 'C',
              table[i].highWord ? 'H' : 'L', table[i].home ? 'h' : 't',
-             FPREG(table[i].lowReg) ? 's' : 'r', table[i].lowReg & FP_REG_MASK,
-             FPREG(table[i].highReg) ? 's' : 'r', table[i].highReg & FP_REG_MASK,
-             table[i].sRegLow);
+             oatIsFpReg(table[i].lowReg) ? 's' : 'r',
+             table[i].lowReg & oatFpRegMask(),
+             oatIsFpReg(table[i].highReg) ? 's' : 'r',
+             table[i].highReg & oatFpRegMask(), table[i].sRegLow);
         LOG(INFO) << buf;
     }
 }
diff --git a/src/compiler/codegen/CodegenFactory.cc b/src/compiler/codegen/CodegenFactory.cc
index 4b2fd4a..d141156 100644
--- a/src/compiler/codegen/CodegenFactory.cc
+++ b/src/compiler/codegen/CodegenFactory.cc
@@ -28,6 +28,8 @@
  * Prior to including this file, TGT_LIR should be #defined.
  * For example, for arm:
  *    #define TGT_LIR ArmLIR
+ * for MIPS:
+ *    #define TGT_LIR MipsLIR
  * and for x86:
  *    #define TGT_LIR X86LIR
  */
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
new file mode 100644
index 0000000..1f05a17
--- /dev/null
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+STATIC void pushWord(std::vector<uint16_t>&buf, int data) {
+    buf.push_back( data & 0xffff);
+    buf.push_back( (data >> 16) & 0xffff);
+}
+
+void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
+    while (buf.size() < (offset/2))
+        buf.push_back(0);
+}
+
+/* Write the literal pool to the output stream */
+STATIC void installLiteralPools(CompilationUnit* cUnit)
+{
+    alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
+    TGT_LIR* dataLIR = (TGT_LIR*) cUnit->literalList;
+    while (dataLIR != NULL) {
+        pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
+        dataLIR = NEXT_LIR(dataLIR);
+    }
+}
+
+/* Write the switch tables to the output stream */
+STATIC void installSwitchTables(CompilationUnit* cUnit)
+{
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
+    while (true) {
+        SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext(
+             &iterator);
+        if (tabRec == NULL) break;
+        alignBuffer(cUnit->codeBuffer, tabRec->offset);
+        int bxOffset = tabRec->bxInst->generic.offset + 4;
+        if (cUnit->printMe) {
+            LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset;
+        }
+        if (tabRec->table[0] == kSparseSwitchSignature) {
+            int* keys = (int*)&(tabRec->table[2]);
+            for (int elems = 0; elems < tabRec->table[1]; elems++) {
+                int disp = tabRec->targets[elems]->generic.offset - bxOffset;
+                if (cUnit->printMe) {
+                    LOG(INFO) << "    Case[" << elems << "] key: 0x" <<
+                        std::hex << keys[elems] << ", disp: 0x" <<
+                        std::hex << disp;
+                }
+                pushWord(cUnit->codeBuffer, keys[elems]);
+                pushWord(cUnit->codeBuffer,
+                    tabRec->targets[elems]->generic.offset - bxOffset);
+            }
+        } else {
+            DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
+            for (int elems = 0; elems < tabRec->table[1]; elems++) {
+                int disp = tabRec->targets[elems]->generic.offset - bxOffset;
+                if (cUnit->printMe) {
+                    LOG(INFO) << "    Case[" << elems << "] disp: 0x" <<
+                        std::hex << disp;
+                }
+                pushWord(cUnit->codeBuffer,
+                         tabRec->targets[elems]->generic.offset - bxOffset);
+            }
+        }
+    }
+}
+
+/* Write the fill array dta to the output stream */
+STATIC void installFillArrayData(CompilationUnit* cUnit)
+{
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
+    while (true) {
+        FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
+             &iterator);
+        if (tabRec == NULL) break;
+        alignBuffer(cUnit->codeBuffer, tabRec->offset);
+        for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) {
+            cUnit->codeBuffer.push_back( tabRec->table[i]);
+        }
+    }
+}
+
+STATIC int assignLiteralOffsetCommon(LIR* lir, int offset)
+{
+    for (;lir != NULL; lir = lir->next) {
+        lir->offset = offset;
+        offset += 4;
+    }
+    return offset;
+}
+
+STATIC void createMappingTable(CompilationUnit* cUnit)
+{
+    TGT_LIR* tgtLIR;
+    int currentDalvikOffset = -1;
+
+    for (tgtLIR = (TGT_LIR *) cUnit->firstLIRInsn;
+         tgtLIR;
+         tgtLIR = NEXT_LIR(tgtLIR)) {
+        if ((tgtLIR->opcode >= 0) && !tgtLIR->flags.isNop &&
+            (currentDalvikOffset != tgtLIR->generic.dalvikOffset)) {
+            // Changed - need to emit a record
+            cUnit->mappingTable.push_back(tgtLIR->generic.offset);
+            cUnit->mappingTable.push_back(tgtLIR->generic.dalvikOffset);
+            currentDalvikOffset = tgtLIR->generic.dalvikOffset;
+        }
+    }
+}
+
+/* Determine the offset of each literal field */
+STATIC int assignLiteralOffset(CompilationUnit* cUnit, int offset)
+{
+    offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
+    return offset;
+}
+
+STATIC int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset)
+{
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
+    while (true) {
+        SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
+             &iterator);
+        if (tabRec == NULL) break;
+        tabRec->offset = offset;
+        if (tabRec->table[0] == kSparseSwitchSignature) {
+            offset += tabRec->table[1] * (sizeof(int) * 2);
+        } else {
+            DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
+            offset += tabRec->table[1] * sizeof(int);
+        }
+    }
+    return offset;
+}
+
+STATIC int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset)
+{
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
+    while (true) {
+        FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
+             &iterator);
+        if (tabRec == NULL) break;
+        tabRec->offset = offset;
+        offset += tabRec->size;
+        // word align
+        offset = (offset + 3) & ~3;
+        }
+    return offset;
+}
+
+/*
+ * Walk the compilation unit and assign offsets to instructions
+ * and literals and compute the total size of the compiled unit.
+ */
+void oatAssignOffsets(CompilationUnit* cUnit)
+{
+    int offset = oatAssignInsnOffsets(cUnit);
+
+    /* Const values have to be word aligned */
+    offset = (offset + 3) & ~3;
+
+    /* Set up offsets for literals */
+    cUnit->dataOffset = offset;
+
+    offset = assignLiteralOffset(cUnit, offset);
+
+    offset = assignSwitchTablesOffset(cUnit, offset);
+
+    offset = assignFillArrayDataOffset(cUnit, offset);
+
+    cUnit->totalSize = offset;
+}
+
+/*
+ * Go over each instruction in the list and calculate the offset from the top
+ * before sending them off to the assembler. If out-of-range branch distance is
+ * seen rearrange the instructions a bit to correct it.
+ */
+void oatAssembleLIR(CompilationUnit* cUnit)
+{
+    oatAssignOffsets(cUnit);
+    /*
+     * Assemble here.  Note that we generate code with optimistic assumptions
+     * and if found now to work, we'll have to redo the sequence and retry.
+     */
+
+    while (true) {
+        AssemblerStatus res = oatAssembleInstructions(cUnit, 0);
+        if (res == kSuccess) {
+            break;
+        } else {
+            cUnit->assemblerRetries++;
+            if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) {
+                LOG(FATAL) << "Assembler error - too many retries";
+            }
+            // Redo offsets and try again
+            oatAssignOffsets(cUnit);
+            cUnit->codeBuffer.clear();
+        }
+    }
+
+    // Install literals
+    installLiteralPools(cUnit);
+
+    // Install switch tables
+    installSwitchTables(cUnit);
+
+    // Install fill array data
+    installFillArrayData(cUnit);
+
+    /*
+     * Create the mapping table
+     */
+    createMappingTable(cUnit);
+}
+
+
+
+}  // namespace art
diff --git a/src/compiler/codegen/CompilerCodegen.h b/src/compiler/codegen/CompilerCodegen.h
index f1ca07a..ae85bb3 100644
--- a/src/compiler/codegen/CompilerCodegen.h
+++ b/src/compiler/codegen/CompilerCodegen.h
@@ -26,6 +26,10 @@
 
 /* Assemble LIR into machine code */
 void oatAssembleLIR(CompilationUnit* cUnit);
+AssemblerStatus oatAssembleInstructions(CompilationUnit* cUnit,
+                                        intptr_t startAddr);
+void oatAssignOffsets(CompilationUnit* cUnit);
+int oatAssignInsnOffsets(CompilationUnit* cUnit);
 
 /* Implemented in the codegen/<target>/ArchUtility.c */
 void oatCodegenDump(CompilationUnit* cUnit);
diff --git a/src/compiler/codegen/arm/LocalOptimizations.cc b/src/compiler/codegen/LocalOptimizations.cc
similarity index 93%
rename from src/compiler/codegen/arm/LocalOptimizations.cc
rename to src/compiler/codegen/LocalOptimizations.cc
index 9098627..cc276f2 100644
--- a/src/compiler/codegen/arm/LocalOptimizations.cc
+++ b/src/compiler/codegen/LocalOptimizations.cc
@@ -14,11 +14,6 @@
  * limitations under the License.
  */
 
-#include "../../Dalvik.h"
-#include "../../CompilerInternals.h"
-#include "ArmLIR.h"
-#include "Codegen.h"
-
 namespace art {
 
 #define DEBUG_OPT(X)
@@ -32,7 +27,7 @@
 #define LDLD_DISTANCE 4
 #define LD_LATENCY 2
 
-STATIC inline bool isDalvikRegisterClobbered(ArmLIR* lir1, ArmLIR* lir2)
+STATIC inline bool isDalvikRegisterClobbered(TGT_LIR* lir1, TGT_LIR* lir2)
 {
     int reg1Lo = DECODE_ALIAS_INFO_REG(lir1->aliasInfo);
     int reg1Hi = reg1Lo + DECODE_ALIAS_INFO_WIDE(lir1->aliasInfo);
@@ -43,11 +38,11 @@
 }
 
 /* Convert a more expensive instruction (ie load) into a move */
-STATIC void convertMemOpIntoMove(CompilationUnit* cUnit, ArmLIR* origLIR,
+STATIC void convertMemOpIntoMove(CompilationUnit* cUnit, TGT_LIR* origLIR,
                                  int dest, int src)
 {
     /* Insert a move to replace the load */
-    ArmLIR* moveLIR;
+    TGT_LIR* moveLIR;
     moveLIR = oatRegCopyNoInsert( cUnit, dest, src);
     /*
      * Insert the converted instruction after the original since the
@@ -77,10 +72,10 @@
  *   2) The memory location is not written to in between
  */
 STATIC void applyLoadStoreElimination(CompilationUnit* cUnit,
-                                      ArmLIR* headLIR,
-                                      ArmLIR* tailLIR)
+                                      TGT_LIR* headLIR,
+                                      TGT_LIR* tailLIR)
 {
-    ArmLIR* thisLIR;
+    TGT_LIR* thisLIR;
 
     if (headLIR == tailLIR) return;
 
@@ -98,7 +93,7 @@
 
         int nativeRegId = thisLIR->operands[0];
         bool isThisLIRLoad = EncodingMap[thisLIR->opcode].flags & IS_LOAD;
-        ArmLIR* checkLIR;
+        TGT_LIR* checkLIR;
         /* Use the mem mask to determine the rough memory location */
         u8 thisMemMask = (thisLIR->useMask | thisLIR->defMask) & ENCODE_MEM;
 
@@ -235,8 +230,8 @@
                                                 "REG CLOBBERED"));
                 /* Only sink store instructions */
                 if (sinkDistance && !isThisLIRLoad) {
-                    ArmLIR* newStoreLIR =
-                        (ArmLIR* ) oatNew(cUnit, sizeof(ArmLIR), true,
+                    TGT_LIR* newStoreLIR =
+                        (TGT_LIR* ) oatNew(cUnit, sizeof(TGT_LIR), true,
                                           kAllocLIR);
                     *newStoreLIR = *thisLIR;
                     /*
@@ -261,15 +256,15 @@
  * superblock, to try to hoist loads to earlier slots.
  */
 STATIC void applyLoadHoisting(CompilationUnit* cUnit,
-                              ArmLIR* headLIR,
-                              ArmLIR* tailLIR)
+                              TGT_LIR* headLIR,
+                              TGT_LIR* tailLIR)
 {
-    ArmLIR* thisLIR, *checkLIR;
+    TGT_LIR* thisLIR, *checkLIR;
     /*
      * Store the list of independent instructions that can be hoisted past.
      * Will decide the best place to insert later.
      */
-    ArmLIR* prevInstList[MAX_HOIST_DISTANCE];
+    TGT_LIR* prevInstList[MAX_HOIST_DISTANCE];
 
     /* Empty block */
     if (headLIR == tailLIR) return;
@@ -378,7 +373,7 @@
         if (nextSlot >= 2) {
             int firstSlot = nextSlot - 2;
             int slot;
-            ArmLIR* depLIR = prevInstList[nextSlot-1];
+            TGT_LIR* depLIR = prevInstList[nextSlot-1];
             /* If there is ld-ld dependency, wait LDLD_DISTANCE cycles */
             if (!isPseudoOpcode(depLIR->opcode) &&
                 (EncodingMap[depLIR->opcode].flags & IS_LOAD)) {
@@ -389,8 +384,8 @@
              * when the loop is first entered.
              */
             for (slot = firstSlot; slot >= 0; slot--) {
-                ArmLIR* curLIR = prevInstList[slot];
-                ArmLIR* prevLIR = prevInstList[slot+1];
+                TGT_LIR* curLIR = prevInstList[slot];
+                TGT_LIR* prevLIR = prevInstList[slot+1];
 
                 /* Check the highest instruction */
                 if (prevLIR->defMask == ENCODE_ALL) {
@@ -423,8 +418,8 @@
 
             /* Found a slot to hoist to */
             if (slot >= 0) {
-                ArmLIR* curLIR = prevInstList[slot];
-                ArmLIR* newLoadLIR = (ArmLIR* ) oatNew(cUnit, sizeof(ArmLIR),
+                TGT_LIR* curLIR = prevInstList[slot];
+                TGT_LIR* newLoadLIR = (TGT_LIR* ) oatNew(cUnit, sizeof(TGT_LIR),
                                                        true, kAllocLIR);
                 *newLoadLIR = *thisLIR;
                 /*
@@ -442,11 +437,11 @@
                                         LIR* tailLIR)
 {
     if (!(cUnit->disableOpt & (1 << kLoadStoreElimination))) {
-        applyLoadStoreElimination(cUnit, (ArmLIR* ) headLIR,
-                                  (ArmLIR* ) tailLIR);
+        applyLoadStoreElimination(cUnit, (TGT_LIR* ) headLIR,
+                                  (TGT_LIR* ) tailLIR);
     }
     if (!(cUnit->disableOpt & (1 << kLoadHoisting))) {
-        applyLoadHoisting(cUnit, (ArmLIR* ) headLIR, (ArmLIR* ) tailLIR);
+        applyLoadHoisting(cUnit, (TGT_LIR* ) headLIR, (TGT_LIR* ) tailLIR);
     }
 }
 
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
new file mode 100644
index 0000000..72b3d6e
--- /dev/null
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -0,0 +1,879 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "object_utils.h"
+
+namespace art {
+
+#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
+    (1 << kDebugDisplayMissingTargets))
+
+STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0,
+                                   INVALID_REG, INVALID_REG, INVALID_SREG};
+
+/* Mark register usage state and return long retloc */
+STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN_WIDE;
+    oatLockTemp(cUnit, res.lowReg);
+    oatLockTemp(cUnit, res.highReg);
+    oatMarkPair(cUnit, res.lowReg, res.highReg);
+    return res;
+}
+
+STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN;
+    oatLockTemp(cUnit, res.lowReg);
+    return res;
+}
+
+STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir,
+                      InvokeType type, bool isRange)
+{
+    DecodedInstruction* dInsn = &mir->dalvikInsn;
+    int callState = 0;
+    TGT_LIR* nullCk;
+    TGT_LIR** pNullCk = NULL;
+    NextCallInsn nextCallInsn;
+    oatFlushAllRegs(cUnit);    /* Everything to home location */
+    // Explicit register usage
+    oatLockCallTemps(cUnit);
+
+    uint32_t dexMethodIdx = dInsn->vB;
+    int vtableIdx;
+    bool skipThis;
+    bool fastPath =
+        cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit, type,
+                                           vtableIdx)
+        && !SLOW_INVOKE_PATH;
+    if (type == kInterface) {
+      nextCallInsn = fastPath ? nextInterfaceCallInsn
+                              : nextInterfaceCallInsnWithAccessCheck;
+      skipThis = false;
+    } else if (type == kDirect) {
+      if (fastPath) {
+        pNullCk = &nullCk;
+      }
+      nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP;
+      skipThis = false;
+    } else if (type == kStatic) {
+      nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP;
+      skipThis = false;
+    } else if (type == kSuper) {
+      nextCallInsn = fastPath ? nextSuperCallInsn : nextSuperCallInsnSP;
+      skipThis = fastPath;
+    } else {
+      DCHECK_EQ(type, kVirtual);
+      nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
+      skipThis = fastPath;
+    }
+    if (!isRange) {
+        callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
+                                         nextCallInsn, dexMethodIdx,
+                                         vtableIdx, skipThis);
+    } else {
+        callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
+                                       nextCallInsn, dexMethodIdx, vtableIdx,
+                                       skipThis);
+    }
+    // Finish up any of the call sequence not interleaved in arg loading
+    while (callState >= 0) {
+        callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx,
+                                 vtableIdx);
+    }
+    if (DISPLAY_MISSING_TARGETS) {
+        genShowTarget(cUnit);
+    }
+    opReg(cUnit, kOpBlx, rLR);
+    oatClobberCalleeSave(cUnit);
+}
+
+/*
+ * Target-independent code generation.  Use only high-level
+ * load/store utilities here, or target-dependent genXX() handlers
+ * when necessary.
+ */
+STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
+                                     BasicBlock* bb, TGT_LIR* labelList)
+{
+    bool res = false;   // Assume success
+    RegLocation rlSrc[3];
+    RegLocation rlDest = badLoc;
+    RegLocation rlResult = badLoc;
+    Opcode opcode = mir->dalvikInsn.opcode;
+
+    /* Prep Src and Dest locations */
+    int nextSreg = 0;
+    int nextLoc = 0;
+    int attrs = oatDataFlowAttributes[opcode];
+    rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
+    if (attrs & DF_UA) {
+        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
+        nextSreg++;
+    } else if (attrs & DF_UA_WIDE) {
+        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
+                                                 nextSreg + 1);
+        nextSreg+= 2;
+    }
+    if (attrs & DF_UB) {
+        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
+        nextSreg++;
+    } else if (attrs & DF_UB_WIDE) {
+        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
+                                                 nextSreg + 1);
+        nextSreg+= 2;
+    }
+    if (attrs & DF_UC) {
+        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
+    } else if (attrs & DF_UC_WIDE) {
+        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
+                                                 nextSreg + 1);
+    }
+    if (attrs & DF_DA) {
+        rlDest = oatGetDest(cUnit, mir, 0);
+    } else if (attrs & DF_DA_WIDE) {
+        rlDest = oatGetDestWide(cUnit, mir, 0, 1);
+    }
+
+    switch(opcode) {
+        case OP_NOP:
+            break;
+
+        case OP_MOVE_EXCEPTION:
+            int exOffset;
+            int resetReg;
+            exOffset = Thread::ExceptionOffset().Int32Value();
+            resetReg = oatAllocTemp(cUnit);
+            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+            loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
+            loadConstant(cUnit, resetReg, 0);
+            storeWordDisp(cUnit, rSELF, exOffset, resetReg);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_RETURN_VOID:
+            genSuspendTest(cUnit, mir);
+            break;
+
+        case OP_RETURN:
+        case OP_RETURN_OBJECT:
+            genSuspendTest(cUnit, mir);
+            storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
+            break;
+
+        case OP_RETURN_WIDE:
+            genSuspendTest(cUnit, mir);
+            storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
+            break;
+
+        case OP_MOVE_RESULT_WIDE:
+            if (mir->optimizationFlags & MIR_INLINED)
+                break;  // Nop - combined w/ previous invoke
+            storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
+            break;
+
+        case OP_MOVE_RESULT:
+        case OP_MOVE_RESULT_OBJECT:
+            if (mir->optimizationFlags & MIR_INLINED)
+                break;  // Nop - combined w/ previous invoke
+            storeValue(cUnit, rlDest, getRetLoc(cUnit));
+            break;
+
+        case OP_MOVE:
+        case OP_MOVE_OBJECT:
+        case OP_MOVE_16:
+        case OP_MOVE_OBJECT_16:
+        case OP_MOVE_FROM16:
+        case OP_MOVE_OBJECT_FROM16:
+            storeValue(cUnit, rlDest, rlSrc[0]);
+            break;
+
+        case OP_MOVE_WIDE:
+        case OP_MOVE_WIDE_16:
+        case OP_MOVE_WIDE_FROM16:
+            storeValueWide(cUnit, rlDest, rlSrc[0]);
+            break;
+
+        case OP_CONST:
+        case OP_CONST_4:
+        case OP_CONST_16:
+            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_CONST_HIGH16:
+            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantNoClobber(cUnit, rlResult.lowReg,
+                                  mir->dalvikInsn.vB << 16);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_CONST_WIDE_16:
+        case OP_CONST_WIDE_32:
+            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
+                                  mir->dalvikInsn.vB,
+                                  (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
+            storeValueWide(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_CONST_WIDE:
+            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
+                          mir->dalvikInsn.vB_wide & 0xffffffff,
+                          (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
+            storeValueWide(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_CONST_WIDE_HIGH16:
+            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
+                                  0, mir->dalvikInsn.vB << 16);
+            storeValueWide(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_MONITOR_ENTER:
+            genMonitorEnter(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_MONITOR_EXIT:
+            genMonitorExit(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_CHECK_CAST:
+            genCheckCast(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_INSTANCE_OF:
+            genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_NEW_INSTANCE:
+            genNewInstance(cUnit, mir, rlDest);
+            break;
+
+        case OP_THROW:
+            genThrow(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_THROW_VERIFICATION_ERROR:
+            genThrowVerificationError(cUnit, mir);
+            break;
+
+        case OP_ARRAY_LENGTH:
+            int lenOffset;
+            lenOffset = Array::LengthOffset().Int32Value();
+            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
+            genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
+            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+            loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
+                         rlResult.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
+            break;
+
+        case OP_CONST_STRING:
+        case OP_CONST_STRING_JUMBO:
+            genConstString(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_CONST_CLASS:
+            genConstClass(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_FILL_ARRAY_DATA:
+            genFillArrayData(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_FILLED_NEW_ARRAY:
+            genFilledNewArray(cUnit, mir, false /* not range */);
+            break;
+
+        case OP_FILLED_NEW_ARRAY_RANGE:
+            genFilledNewArray(cUnit, mir, true /* range */);
+            break;
+
+        case OP_NEW_ARRAY:
+            genNewArray(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_GOTO:
+        case OP_GOTO_16:
+        case OP_GOTO_32:
+            if (bb->taken->startOffset <= mir->offset) {
+                genSuspendTest(cUnit, mir);
+            }
+            genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
+            break;
+
+        case OP_PACKED_SWITCH:
+            genPackedSwitch(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_SPARSE_SWITCH:
+            genSparseSwitch(cUnit, mir, rlSrc[0]);
+            break;
+
+        case OP_CMPL_FLOAT:
+        case OP_CMPG_FLOAT:
+        case OP_CMPL_DOUBLE:
+        case OP_CMPG_DOUBLE:
+            res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_CMP_LONG:
+            genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_IF_EQ:
+        case OP_IF_NE:
+        case OP_IF_LT:
+        case OP_IF_GE:
+        case OP_IF_GT:
+        case OP_IF_LE: {
+            bool backwardBranch;
+            backwardBranch = (bb->taken->startOffset <= mir->offset);
+            if (backwardBranch) {
+                genSuspendTest(cUnit, mir);
+            }
+            genCompareAndBranch(cUnit, bb, mir, rlSrc[0], rlSrc[1], labelList);
+            break;
+            }
+
+        case OP_IF_EQZ:
+        case OP_IF_NEZ:
+        case OP_IF_LTZ:
+        case OP_IF_GEZ:
+        case OP_IF_GTZ:
+        case OP_IF_LEZ: {
+            bool backwardBranch;
+            backwardBranch = (bb->taken->startOffset <= mir->offset);
+            if (backwardBranch) {
+                genSuspendTest(cUnit, mir);
+            }
+            genCompareZeroAndBranch(cUnit, bb, mir, rlSrc[0], labelList);
+            break;
+            }
+
+      case OP_AGET_WIDE:
+            genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
+            break;
+        case OP_AGET:
+        case OP_AGET_OBJECT:
+            genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
+            break;
+        case OP_AGET_BOOLEAN:
+            genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
+                        rlDest, 0);
+            break;
+        case OP_AGET_BYTE:
+            genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
+            break;
+        case OP_AGET_CHAR:
+            genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
+                        rlDest, 1);
+            break;
+        case OP_AGET_SHORT:
+            genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
+            break;
+        case OP_APUT_WIDE:
+            genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
+            break;
+        case OP_APUT:
+            genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
+            break;
+        case OP_APUT_OBJECT:
+            genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
+            break;
+        case OP_APUT_SHORT:
+        case OP_APUT_CHAR:
+            genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
+                        rlSrc[0], 1);
+            break;
+        case OP_APUT_BYTE:
+        case OP_APUT_BOOLEAN:
+            genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
+                        rlSrc[0], 0);
+            break;
+
+        case OP_IGET_OBJECT:
+        case OP_IGET_OBJECT_VOLATILE:
+            genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, true);
+            break;
+
+        case OP_IGET_WIDE:
+        case OP_IGET_WIDE_VOLATILE:
+            genIGet(cUnit, mir, kLong, rlDest, rlSrc[0], true, false);
+            break;
+
+        case OP_IGET:
+        case OP_IGET_VOLATILE:
+            genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, false);
+            break;
+
+        case OP_IGET_CHAR:
+            genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0], false, false);
+            break;
+
+        case OP_IGET_SHORT:
+            genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0], false, false);
+            break;
+
+        case OP_IGET_BOOLEAN:
+        case OP_IGET_BYTE:
+            genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0], false, false);
+            break;
+
+        case OP_IPUT_WIDE:
+        case OP_IPUT_WIDE_VOLATILE:
+            genIPut(cUnit, mir, kLong, rlSrc[0], rlSrc[1], true, false);
+            break;
+
+        case OP_IPUT_OBJECT:
+        case OP_IPUT_OBJECT_VOLATILE:
+            genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, true);
+            break;
+
+        case OP_IPUT:
+        case OP_IPUT_VOLATILE:
+            genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, false);
+            break;
+
+        case OP_IPUT_BOOLEAN:
+        case OP_IPUT_BYTE:
+            genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false, false);
+            break;
+
+        case OP_IPUT_CHAR:
+            genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false, false);
+            break;
+
+        case OP_IPUT_SHORT:
+            genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false, false);
+            break;
+
+        case OP_SGET_OBJECT:
+            genSget(cUnit, mir, rlDest, false, true);
+            break;
+        case OP_SGET:
+        case OP_SGET_BOOLEAN:
+        case OP_SGET_BYTE:
+        case OP_SGET_CHAR:
+        case OP_SGET_SHORT:
+            genSget(cUnit, mir, rlDest, false, false);
+            break;
+
+        case OP_SGET_WIDE:
+            genSget(cUnit, mir, rlDest, true, false);
+            break;
+
+        case OP_SPUT_OBJECT:
+            genSput(cUnit, mir, rlSrc[0], false, true);
+            break;
+
+        case OP_SPUT:
+        case OP_SPUT_BOOLEAN:
+        case OP_SPUT_BYTE:
+        case OP_SPUT_CHAR:
+        case OP_SPUT_SHORT:
+            genSput(cUnit, mir, rlSrc[0], false, false);
+            break;
+
+        case OP_SPUT_WIDE:
+            genSput(cUnit, mir, rlSrc[0], true, false);
+            break;
+
+        case OP_INVOKE_STATIC_RANGE:
+            genInvoke(cUnit, mir, kStatic, true /*range*/);
+            break;
+        case OP_INVOKE_STATIC:
+            genInvoke(cUnit, mir, kStatic, false /*range*/);
+            break;
+
+        case OP_INVOKE_DIRECT:
+            genInvoke(cUnit, mir, kDirect, false /*range*/);
+            break;
+        case OP_INVOKE_DIRECT_RANGE:
+            genInvoke(cUnit, mir, kDirect, true /*range*/);
+            break;
+
+        case OP_INVOKE_VIRTUAL:
+            genInvoke(cUnit, mir, kVirtual, false /*range*/);
+            break;
+        case OP_INVOKE_VIRTUAL_RANGE:
+            genInvoke(cUnit, mir, kVirtual, true /*range*/);
+            break;
+
+        case OP_INVOKE_SUPER:
+            genInvoke(cUnit, mir, kSuper, false /*range*/);
+            break;
+        case OP_INVOKE_SUPER_RANGE:
+            genInvoke(cUnit, mir, kSuper, true /*range*/);
+            break;
+
+        case OP_INVOKE_INTERFACE:
+            genInvoke(cUnit, mir, kInterface, false /*range*/);
+            break;
+        case OP_INVOKE_INTERFACE_RANGE:
+            genInvoke(cUnit, mir, kInterface, true /*range*/);
+            break;
+
+        case OP_NEG_INT:
+        case OP_NOT_INT:
+            res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+            break;
+
+        case OP_NEG_LONG:
+        case OP_NOT_LONG:
+            res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+            break;
+
+        case OP_NEG_FLOAT:
+            res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+            break;
+
+        case OP_NEG_DOUBLE:
+            res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
+            break;
+
+        case OP_INT_TO_LONG:
+            genIntToLong(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_LONG_TO_INT:
+            rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
+            rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
+            storeValue(cUnit, rlDest, rlSrc[0]);
+            break;
+
+        case OP_INT_TO_BYTE:
+        case OP_INT_TO_SHORT:
+        case OP_INT_TO_CHAR:
+            genIntNarrowing(cUnit, mir, rlDest, rlSrc[0]);
+            break;
+
+        case OP_INT_TO_FLOAT:
+        case OP_INT_TO_DOUBLE:
+        case OP_LONG_TO_FLOAT:
+        case OP_LONG_TO_DOUBLE:
+        case OP_FLOAT_TO_INT:
+        case OP_FLOAT_TO_LONG:
+        case OP_FLOAT_TO_DOUBLE:
+        case OP_DOUBLE_TO_INT:
+        case OP_DOUBLE_TO_LONG:
+        case OP_DOUBLE_TO_FLOAT:
+            genConversion(cUnit, mir);
+            break;
+
+        case OP_ADD_INT:
+        case OP_SUB_INT:
+        case OP_MUL_INT:
+        case OP_DIV_INT:
+        case OP_REM_INT:
+        case OP_AND_INT:
+        case OP_OR_INT:
+        case OP_XOR_INT:
+        case OP_SHL_INT:
+        case OP_SHR_INT:
+        case OP_USHR_INT:
+        case OP_ADD_INT_2ADDR:
+        case OP_SUB_INT_2ADDR:
+        case OP_MUL_INT_2ADDR:
+        case OP_DIV_INT_2ADDR:
+        case OP_REM_INT_2ADDR:
+        case OP_AND_INT_2ADDR:
+        case OP_OR_INT_2ADDR:
+        case OP_XOR_INT_2ADDR:
+        case OP_SHL_INT_2ADDR:
+        case OP_SHR_INT_2ADDR:
+        case OP_USHR_INT_2ADDR:
+            genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_ADD_LONG:
+        case OP_SUB_LONG:
+        case OP_MUL_LONG:
+        case OP_DIV_LONG:
+        case OP_REM_LONG:
+        case OP_AND_LONG:
+        case OP_OR_LONG:
+        case OP_XOR_LONG:
+        case OP_ADD_LONG_2ADDR:
+        case OP_SUB_LONG_2ADDR:
+        case OP_MUL_LONG_2ADDR:
+        case OP_DIV_LONG_2ADDR:
+        case OP_REM_LONG_2ADDR:
+        case OP_AND_LONG_2ADDR:
+        case OP_OR_LONG_2ADDR:
+        case OP_XOR_LONG_2ADDR:
+            genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_SHL_LONG:
+        case OP_SHR_LONG:
+        case OP_USHR_LONG:
+        case OP_SHL_LONG_2ADDR:
+        case OP_SHR_LONG_2ADDR:
+        case OP_USHR_LONG_2ADDR:
+            genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_ADD_FLOAT:
+        case OP_SUB_FLOAT:
+        case OP_MUL_FLOAT:
+        case OP_DIV_FLOAT:
+        case OP_REM_FLOAT:
+        case OP_ADD_FLOAT_2ADDR:
+        case OP_SUB_FLOAT_2ADDR:
+        case OP_MUL_FLOAT_2ADDR:
+        case OP_DIV_FLOAT_2ADDR:
+        case OP_REM_FLOAT_2ADDR:
+            genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_ADD_DOUBLE:
+        case OP_SUB_DOUBLE:
+        case OP_MUL_DOUBLE:
+        case OP_DIV_DOUBLE:
+        case OP_REM_DOUBLE:
+        case OP_ADD_DOUBLE_2ADDR:
+        case OP_SUB_DOUBLE_2ADDR:
+        case OP_MUL_DOUBLE_2ADDR:
+        case OP_DIV_DOUBLE_2ADDR:
+        case OP_REM_DOUBLE_2ADDR:
+            genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
+            break;
+
+        case OP_RSUB_INT:
+        case OP_ADD_INT_LIT16:
+        case OP_MUL_INT_LIT16:
+        case OP_DIV_INT_LIT16:
+        case OP_REM_INT_LIT16:
+        case OP_AND_INT_LIT16:
+        case OP_OR_INT_LIT16:
+        case OP_XOR_INT_LIT16:
+        case OP_ADD_INT_LIT8:
+        case OP_RSUB_INT_LIT8:
+        case OP_MUL_INT_LIT8:
+        case OP_DIV_INT_LIT8:
+        case OP_REM_INT_LIT8:
+        case OP_AND_INT_LIT8:
+        case OP_OR_INT_LIT8:
+        case OP_XOR_INT_LIT8:
+        case OP_SHL_INT_LIT8:
+        case OP_SHR_INT_LIT8:
+        case OP_USHR_INT_LIT8:
+            genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
+            break;
+
+        default:
+            res = true;
+    }
+    return res;
+}
+
+STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
+    "kMirOpPhi",
+    "kMirOpNullNRangeUpCheck",
+    "kMirOpNullNRangeDownCheck",
+    "kMirOpLowerBound",
+    "kMirOpPunt",
+    "kMirOpCheckInlinePrediction",
+};
+
+/* Extended MIR instructions like PHI */
+STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
+{
+    int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
+    char* msg = NULL;
+    if (cUnit->printMe) {
+        msg = (char*)oatNew(cUnit, strlen(extendedMIROpNames[opOffset]) + 1,
+                            false, kAllocDebugInfo);
+        strcpy(msg, extendedMIROpNames[opOffset]);
+    }
+    TGT_LIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
+
+    switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
+        case kMirOpPhi: {
+            char* ssaString = NULL;
+            if (cUnit->printMe) {
+                ssaString = oatGetSSAString(cUnit, mir->ssaRep);
+            }
+            op->flags.isNop = true;
+            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+/* Handle the content in each basic block */
+STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    MIR* mir;
+    TGT_LIR* labelList = (TGT_LIR*) cUnit->blockLabelList;
+    int blockId = bb->id;
+
+    cUnit->curBlock = bb;
+    labelList[blockId].operands[0] = bb->startOffset;
+
+    /* Insert the block label */
+    labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
+    oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
+
+    /* Reset local optimization data on block boundaries */
+    oatResetRegPool(cUnit);
+    oatClobberAllRegs(cUnit);
+    oatResetDefTracking(cUnit);
+
+    TGT_LIR* headLIR = NULL;
+
+    if (bb->blockType == kEntryBlock) {
+        genEntrySequence(cUnit, bb);
+    } else if (bb->blockType == kExitBlock) {
+        genExitSequence(cUnit, bb);
+    }
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+
+        oatResetRegPool(cUnit);
+        if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
+            oatClobberAllRegs(cUnit);
+        }
+
+        if (cUnit->disableOpt & (1 << kSuppressLoads)) {
+            oatResetDefTracking(cUnit);
+        }
+
+        if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
+            handleExtendedMethodMIR(cUnit, mir);
+            continue;
+        }
+
+        cUnit->currentDalvikOffset = mir->offset;
+
+        Opcode dalvikOpcode = mir->dalvikInsn.opcode;
+        InstructionFormat dalvikFormat =
+            dexGetFormatFromOpcode(dalvikOpcode);
+
+        TGT_LIR* boundaryLIR;
+
+        /* Mark the beginning of a Dalvik instruction for line tracking */
+        char* instStr = cUnit->printMe ?
+           oatGetDalvikDisassembly(cUnit, &mir->dalvikInsn, "") : NULL;
+        boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
+                              (intptr_t) instStr);
+        cUnit->boundaryMap.insert(std::make_pair(mir->offset,
+                                 (LIR*)boundaryLIR));
+        /* Remember the first LIR for this block */
+        if (headLIR == NULL) {
+            headLIR = boundaryLIR;
+            /* Set the first boundaryLIR as a scheduling barrier */
+            headLIR->defMask = ENCODE_ALL;
+        }
+
+        /* If we're compiling for the debugger, generate an update callout */
+        if (cUnit->genDebugger) {
+            genDebuggerUpdate(cUnit, mir->offset);
+        }
+
+        /* Don't generate the SSA annotation unless verbose mode is on */
+        if (cUnit->printMe && mir->ssaRep) {
+            char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
+            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
+        }
+
+        bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
+
+        if (notHandled) {
+            char buf[100];
+            snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
+                 mir->offset,
+                 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
+                 dalvikFormat);
+            LOG(FATAL) << buf;
+        }
+    }
+
+    if (headLIR) {
+        /*
+         * Eliminate redundant loads/stores and delay stores into later
+         * slots
+         */
+        oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
+                                           cUnit->lastLIRInsn);
+
+        /*
+         * Generate an unconditional branch to the fallthrough block.
+         */
+        if (bb->fallThrough) {
+            genUnconditionalBranch(cUnit,
+                                   &labelList[bb->fallThrough->id]);
+        }
+    }
+    return false;
+}
+
+void oatMethodMIR2LIR(CompilationUnit* cUnit)
+{
+    /* Used to hold the labels of each block */
+    cUnit->blockLabelList =
+        (void *) oatNew(cUnit, sizeof(TGT_LIR) * cUnit->numBlocks, true,
+                        kAllocLIR);
+
+    oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
+                                  kPreOrderDFSTraversal, false /* Iterative */);
+    handleSuspendLaunchpads(cUnit);
+
+    handleThrowLaunchpads(cUnit);
+
+    removeRedundantBranches(cUnit);
+}
+
+/* Needed by the ld/st optmizatons */
+TGT_LIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
+{
+    return genRegCopyNoInsert(cUnit, rDest, rSrc);
+}
+
+/* Needed by the register allocator */
+void oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
+{
+    genRegCopy(cUnit, rDest, rSrc);
+}
+
+/* Needed by the register allocator */
+void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
+                            int srcLo, int srcHi)
+{
+    genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
+}
+
+void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
+                             int displacement, int rSrc, OpSize size)
+{
+    storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
+}
+
+void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
+                                 int displacement, int rSrcLo, int rSrcHi)
+{
+    storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/Ralloc.h b/src/compiler/codegen/Ralloc.h
index e72cdcb..c9e5308 100644
--- a/src/compiler/codegen/Ralloc.h
+++ b/src/compiler/codegen/Ralloc.h
@@ -24,25 +24,18 @@
 #include "../CompilerUtility.h"
 #include "../CompilerIR.h"
 #include "../Dataflow.h"
-#include "arm/ArmLIR.h"
 
 namespace art {
 
-/*
- * Return most flexible allowed register class based on size.
- * Bug: 2813841
- * Must use a core register for data types narrower than word (due
- * to possible unaligned load/store.
- */
-STATIC inline RegisterClass oatRegClassBySize(OpSize size)
-{
-    return (size == kUnsignedHalf ||
-            size == kSignedHalf ||
-            size == kUnsignedByte ||
-            size == kSignedByte ) ? kCoreReg : kAnyReg;
-}
+/* Static register use counts */
+typedef struct RefCounts {
+    int count;
+    int sReg;
+    bool doubleStart;   // Starting vReg for a double
+} RefCounts;
 
-STATIC inline int oatS2VReg(CompilationUnit* cUnit, int sReg)
+
+inline int oatS2VReg(CompilationUnit* cUnit, int sReg)
 {
     DCHECK_NE(sReg, INVALID_SREG);
     return DECODE_REG(oatConvertSSARegToDalvik(cUnit, sReg));
@@ -58,18 +51,18 @@
  * identified by the dataflow pass what it's new name is.
  */
 
-STATIC inline int oatSRegHi(int lowSreg) {
+inline int oatSRegHi(int lowSreg) {
     return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
 }
 
 
-STATIC inline bool oatLiveOut(CompilationUnit* cUnit, int sReg)
+inline bool oatLiveOut(CompilationUnit* cUnit, int sReg)
 {
     //For now.
     return true;
 }
 
-STATIC inline int oatSSASrc(MIR* mir, int num)
+inline int oatSSASrc(MIR* mir, int num)
 {
     DCHECK_GT(mir->ssaRep->numUses, num);
     return mir->ssaRep->uses[num];
@@ -108,7 +101,7 @@
 extern void oatResetDefLoc(CompilationUnit* cUnit, RegLocation rl);
 
 /* Set up temp & preserved register pools specialized by target */
-extern void oatInitPool(RegisterInfo* regs, int* regNums, int num);
+extern void oatInitPool(struct RegisterInfo* regs, int* regNums, int num);
 
 /*
  * Mark the beginning and end LIR of a def sequence.  Note that
@@ -212,6 +205,13 @@
 
 extern void oatFlushReg(CompilationUnit* cUnit, int reg);
 
+extern void oatDoPromotion(CompilationUnit* cUnit);
+extern int oatVRegOffset(CompilationUnit* cUnit, int reg);
+extern int oatSRegOffset(CompilationUnit* cUnit, int reg);
+extern void oatCountRefs(CompilationUnit*, BasicBlock*, RefCounts*, RefCounts*);
+extern int oatSortCounts(const void *val1, const void *val2);
+extern void oatDumpCounts(const RefCounts* arr, int size, const char* msg);
+
 /*
  * Architecture-dependent register allocation routines implemented in
  * ${TARGET_ARCH}/${TARGET_ARCH_VARIANT}/Ralloc.c
@@ -222,8 +222,6 @@
 extern int oatAllocTypedTemp(CompilationUnit* cUnit, bool fpHint,
                              int regClass);
 
-extern ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc);
-
 extern void oatRegCopyWide(CompilationUnit* cUnit, int destLo,
                            int destHi, int srcLo, int srcHi);
 
@@ -233,13 +231,16 @@
 extern void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
                                 int displacement, int rSrcLo, int rSrcHi);
 
-extern void oatDoPromotion(CompilationUnit* cUnit);
-extern int oatVRegOffset(CompilationUnit* cUnit, int reg);
-extern int oatSRegOffset(CompilationUnit* cUnit, int reg);
 extern void oatDumpCoreRegPool(CompilationUnit* cUint);
 extern void oatDumpFPRegPool(CompilationUnit* cUint);
 extern bool oatCheckCorePoolSanity(CompilationUnit* cUnit);
 extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg);
+extern void oatNopLIR(LIR* lir);
+extern bool oatIsFPReg(int reg);
+extern uint32_t oatFPRegMask(void);
+extern void oatAdjustSpillMask(CompilationUnit* cUnit);
+void oatMarkPreservedSingle(CompilationUnit* cUnit, int sReg, int reg);
+void oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc);
 
 }  // namespace art
 
diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc
index 2a4fe59..77fb23b 100644
--- a/src/compiler/codegen/RallocUtil.cc
+++ b/src/compiler/codegen/RallocUtil.cc
@@ -58,7 +58,10 @@
     }
 }
 
- /* Set up temp & preserved register pools specialized by target */
+ /*
+  * Set up temp & preserved register pools specialized by target.
+  * Note: numRegs may be zero.
+  */
 extern void oatInitPool(RegisterInfo* regs, int* regNums, int num)
 {
     int i;
@@ -99,43 +102,6 @@
     dumpRegPool(cUnit->regPool->FPRegs, cUnit->regPool->numFPRegs);
 }
 
-void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
-{
-    RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
-    RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
-    DCHECK(info1 && info2 && info1->pair && info2->pair &&
-           (info1->partner == info2->reg) &&
-           (info2->partner == info1->reg));
-    if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
-        if (!(info1->isTemp && info2->isTemp)) {
-            /* Should not happen.  If it does, there's a problem in evalLoc */
-            LOG(FATAL) << "Long half-temp, half-promoted";
-        }
-
-        info1->dirty = false;
-        info2->dirty = false;
-        if (oatS2VReg(cUnit, info2->sReg) <
-            oatS2VReg(cUnit, info1->sReg))
-            info1 = info2;
-        int vReg = oatS2VReg(cUnit, info1->sReg);
-        oatFlushRegWideImpl(cUnit, rSP,
-                                    oatVRegOffset(cUnit, vReg),
-                                    info1->reg, info1->partner);
-    }
-}
-
-void oatFlushReg(CompilationUnit* cUnit, int reg)
-{
-    RegisterInfo* info = oatGetRegInfo(cUnit, reg);
-    if (info->live && info->dirty) {
-        info->dirty = false;
-        int vReg = oatS2VReg(cUnit, info->sReg);
-        oatFlushRegImpl(cUnit, rSP,
-                                oatVRegOffset(cUnit, vReg),
-                                reg, kWord);
-    }
-}
-
 /* Mark a temp register as dead.  Does not affect allocation state. */
 static inline void clobberBody(CompilationUnit *cUnit, RegisterInfo* p)
 {
@@ -204,28 +170,6 @@
 }
 
 /*
- * Mark a callee-save fp register as promoted.  Note that
- * vpush/vpop uses contiguous register lists so we must
- * include any holes in the mask.  Associate holes with
- * Dalvik register INVALID_VREG (0xFFFFU).
- */
-STATIC void markPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
-{
-    DCHECK_GE(reg, FP_REG_MASK + FP_CALLEE_SAVE_BASE);
-    reg = (reg & FP_REG_MASK) - FP_CALLEE_SAVE_BASE;
-    // Ensure fpVmapTable is large enough
-    int tableSize = cUnit->fpVmapTable.size();
-    for (int i = tableSize; i < (reg + 1); i++) {
-        cUnit->fpVmapTable.push_back(INVALID_VREG);
-    }
-    // Add the current mapping
-    cUnit->fpVmapTable[reg] = sReg;
-    // Size of fpVmapTable is high-water mark, use to set mask
-    cUnit->numFPSpills = cUnit->fpVmapTable.size();
-    cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << FP_CALLEE_SAVE_BASE;
-}
-
-/*
  * Reserve a callee-save fp single register.  Try to fullfill request for
  * even/odd  allocation, but go ahead and allocate anything if not
  * available.  If nothing's available, return -1.
@@ -241,7 +185,7 @@
             FPRegs[i].inUse = true;
             //  Should be promoting based on initial sReg set
             DCHECK_EQ(sReg, oatS2VReg(cUnit, sReg));
-            markPreservedSingle(cUnit, sReg, res);
+            oatMarkPreservedSingle(cUnit, sReg, res);
             cUnit->promotionMap[sReg].fpLocation = kLocPhysReg;
             cUnit->promotionMap[sReg].fpReg = res;
             break;
@@ -280,7 +224,7 @@
         res = p->reg;
         p->inUse = true;
         DCHECK_EQ((res & 1), 0);
-        markPreservedSingle(cUnit, sReg, res);
+        oatMarkPreservedSingle(cUnit, sReg, res);
     } else {
         RegisterInfo* FPRegs = cUnit->regPool->FPRegs;
         for (int i = 0; i < cUnit->regPool->numFPRegs; i++) {
@@ -291,10 +235,10 @@
                 (FPRegs[i].reg + 1) == FPRegs[i+1].reg) {
                 res = FPRegs[i].reg;
                 FPRegs[i].inUse = true;
-                markPreservedSingle(cUnit, sReg, res);
+                oatMarkPreservedSingle(cUnit, sReg, res);
                 FPRegs[i+1].inUse = true;
                 DCHECK_EQ(res + 1, FPRegs[i+1].reg);
-                markPreservedSingle(cUnit, sReg+1, res+1);
+                oatMarkPreservedSingle(cUnit, sReg+1, res+1);
                 break;
             }
         }
@@ -600,8 +544,7 @@
         LIR *p;
         DCHECK_EQ(sReg1, sReg2);
         for (p = start; ;p = p->next) {
-            ((ArmLIR *)p)->flags.isNop = true;
-            ((ArmLIR *)p)->flags.squashed = true;
+            oatNopLIR(p);
             if (p == finish)
                 break;
         }
@@ -714,26 +657,6 @@
     }
 }
 
-/* To be used when explicitly managing register use */
-extern void oatLockCallTemps(CompilationUnit* cUnit)
-{
-    //TODO: Arm specific - move to target dependent code
-    oatLockTemp(cUnit, r0);
-    oatLockTemp(cUnit, r1);
-    oatLockTemp(cUnit, r2);
-    oatLockTemp(cUnit, r3);
-}
-
-/* To be used when explicitly managing register use */
-extern void oatFreeCallTemps(CompilationUnit* cUnit)
-{
-    //TODO: Arm specific - move to target dependent code
-    oatFreeTemp(cUnit, r0);
-    oatFreeTemp(cUnit, r1);
-    oatFreeTemp(cUnit, r2);
-    oatFreeTemp(cUnit, r3);
-}
-
 // Make sure nothing is live and dirty
 STATIC void flushAllRegsBody(CompilationUnit* cUnit, RegisterInfo* info,
                              int numRegs)
@@ -766,9 +689,9 @@
     if (regClass == kAnyReg) {
         return true;
     } else if (regClass == kCoreReg) {
-        return !FPREG(reg);
+        return !oatIsFpReg(reg);
     } else {
-        return FPREG(reg);
+        return oatIsFpReg(reg);
     }
 }
 
@@ -926,9 +849,9 @@
         match = match && (infoLo != NULL);
         match = match && (infoHi != NULL);
         // Are they both core or both FP?
-        match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
+        match = match && (oatIsFpReg(infoLo->reg) == oatIsFpReg(infoHi->reg));
         // If a pair of floating point singles, are they properly aligned?
-        if (match && FPREG(infoLo->reg)) {
+        if (match && oatIsFpReg(infoLo->reg)) {
             match &= ((infoLo->reg & 0x1) == 0);
             match &= ((infoHi->reg - infoLo->reg) == 1);
         }
@@ -944,7 +867,7 @@
             loc.highReg = infoHi->reg;
             loc.location = kLocPhysReg;
             oatMarkPair(cUnit, loc.lowReg, loc.highReg);
-            DCHECK(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+            DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
             return loc;
         }
         // Can't easily reuse - clobber and free any overlaps
@@ -987,8 +910,8 @@
 
     /* If already in registers, we can assume proper form.  Right reg class? */
     if (loc.location == kLocPhysReg) {
-        DCHECK_EQ(FPREG(loc.lowReg), FPREG(loc.highReg));
-        DCHECK(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+        DCHECK_EQ(oatIsFpReg(loc.lowReg), oatIsFpReg(loc.highReg));
+        DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
         if (!regClassMatches(regClass, loc.lowReg)) {
             /* Wrong register class.  Reallocate and copy */
             newRegs = oatAllocTypedTempPair(cUnit, loc.fp, regClass);
@@ -1003,7 +926,7 @@
             loc.lowReg = lowReg;
             loc.highReg = highReg;
             oatMarkPair(cUnit, loc.lowReg, loc.highReg);
-            DCHECK(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+            DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
         }
         return loc;
     }
@@ -1021,7 +944,7 @@
         oatMarkLive(cUnit, loc.lowReg, loc.sRegLow);
         oatMarkLive(cUnit, loc.highReg, oatSRegHi(loc.sRegLow));
     }
-    DCHECK(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+    DCHECK(!oatIsFpReg(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
     return loc;
 }
 
@@ -1092,4 +1015,247 @@
     return res;
 }
 
+/* USE SSA names to count references of base Dalvik vRegs. */
+void oatCountRefs(CompilationUnit *cUnit, BasicBlock* bb,
+                      RefCounts* coreCounts, RefCounts* fpCounts)
+{
+    MIR* mir;
+    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
+        bb->blockType != kExitBlock)
+        return;
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        SSARepresentation *ssaRep = mir->ssaRep;
+        if (ssaRep) {
+            for (int i = 0; i < ssaRep->numDefs;) {
+                RegLocation loc = cUnit->regLocation[ssaRep->defs[i]];
+                RefCounts* counts = loc.fp ? fpCounts : coreCounts;
+                int vReg = oatS2VReg(cUnit, ssaRep->defs[i]);
+                if (loc.defined) {
+                    counts[vReg].count++;
+                }
+                if (loc.wide) {
+                    if (loc.defined) {
+                        if (loc.fp) {
+                            counts[vReg].doubleStart = true;
+                        }
+                        counts[vReg+1].count++;
+                    }
+                    i += 2;
+                } else {
+                    i++;
+                }
+            }
+            for (int i = 0; i < ssaRep->numUses;) {
+                RegLocation loc = cUnit->regLocation[ssaRep->uses[i]];
+                RefCounts* counts = loc.fp ? fpCounts : coreCounts;
+                int vReg = oatS2VReg(cUnit, ssaRep->uses[i]);
+                if (loc.defined) {
+                    counts[vReg].count++;
+                }
+                if (loc.wide) {
+                    if (loc.defined) {
+                        if (loc.fp) {
+                            counts[vReg].doubleStart = true;
+                        }
+                        counts[vReg+1].count++;
+                    }
+                    i += 2;
+                } else {
+                    i++;
+                }
+            }
+        }
+    }
+}
+
+/* qsort callback function, sort descending */
+int oatSortCounts(const void *val1, const void *val2)
+{
+    const RefCounts* op1 = (const RefCounts*)val1;
+    const RefCounts* op2 = (const RefCounts*)val2;
+    return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
+}
+
+void oatDumpCounts(const RefCounts* arr, int size, const char* msg)
+{
+    LOG(INFO) << msg;
+    for (int i = 0; i < size; i++) {
+        LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count;
+    }
+}
+
+/*
+ * Note: some portions of this code required even if the kPromoteRegs
+ * optimization is disabled.
+ */
+extern void oatDoPromotion(CompilationUnit* cUnit)
+{
+    int numRegs = cUnit->numDalvikRegisters;
+
+    // Allow target code to add any special registers
+    oatAdjustSpillMask(cUnit);
+
+    /*
+     * Simple register promotion. Just do a static count of the uses
+     * of Dalvik registers.  Note that we examine the SSA names, but
+     * count based on original Dalvik register name.  Count refs
+     * separately based on type in order to give allocation
+     * preference to fp doubles - which must be allocated sequential
+     * physical single fp registers started with an even-numbered
+     * reg.
+     * TUNING: replace with linear scan once we have the ability
+     * to describe register live ranges for GC.
+     */
+    RefCounts *coreRegs = (RefCounts *)
+          oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
+    RefCounts *fpRegs = (RefCounts *)
+          oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
+    for (int i = 0; i < numRegs; i++) {
+        coreRegs[i].sReg = fpRegs[i].sReg = i;
+    }
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
+    while (true) {
+        BasicBlock* bb;
+        bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator);
+        if (bb == NULL) break;
+        oatCountRefs(cUnit, bb, coreRegs, fpRegs);
+    }
+
+    /*
+     * Ideally, we'd allocate doubles starting with an even-numbered
+     * register.  Bias the counts to try to allocate any vreg that's
+     * used as the start of a pair first.
+     */
+    for (int i = 0; i < numRegs; i++) {
+        if (fpRegs[i].doubleStart) {
+            fpRegs[i].count *= 2;
+        }
+    }
+
+    // Sort the count arrays
+    qsort(coreRegs, numRegs, sizeof(RefCounts), oatSortCounts);
+    qsort(fpRegs, numRegs, sizeof(RefCounts), oatSortCounts);
+
+    if (cUnit->printMe) {
+        oatDumpCounts(coreRegs, numRegs, "Core regs after sort");
+        oatDumpCounts(fpRegs, numRegs, "Fp regs after sort");
+    }
+
+    if (!(cUnit->disableOpt & (1 << kPromoteRegs))) {
+        // Promote fpRegs
+        for (int i = 0; (fpRegs[i].count > 0) && (i < numRegs); i++) {
+            if (cUnit->promotionMap[fpRegs[i].sReg].fpLocation != kLocPhysReg) {
+                if (fpRegs[i].sReg >= cUnit->numRegs) {
+                    // don't promote arg regs
+                    continue;
+                }
+                int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg,
+                    fpRegs[i].doubleStart);
+                if (reg < 0) {
+                    break;  // No more left
+                }
+            }
+        }
+
+        // Promote core regs
+        for (int i = 0; (coreRegs[i].count > 0) && i < numRegs; i++) {
+            if (cUnit->promotionMap[coreRegs[i].sReg].coreLocation !=
+                    kLocPhysReg) {
+                if (coreRegs[i].sReg >= cUnit->numRegs) {
+                    // don't promote arg regs
+                    continue;
+                }
+                int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg);
+                if (reg < 0) {
+                   break;  // No more left
+                }
+            }
+        }
+    }
+
+    // Now, update SSA names to new home locations
+    for (int i = 0; i < cUnit->numSSARegs; i++) {
+        RegLocation *curr = &cUnit->regLocation[i];
+        int baseVReg = oatS2VReg(cUnit, curr->sRegLow);
+        if (!curr->wide) {
+            if (curr->fp) {
+                if (cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) {
+                    curr->location = kLocPhysReg;
+                    curr->lowReg = cUnit->promotionMap[baseVReg].fpReg;
+                    curr->home = true;
+                }
+            } else {
+                if (cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg) {
+                    curr->location = kLocPhysReg;
+                    curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
+                    curr->home = true;
+                }
+            }
+            curr->highReg = INVALID_REG;
+        } else {
+            if (curr->highWord) {
+                continue;
+            }
+            if (curr->fp) {
+                if ((cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) &&
+                    (cUnit->promotionMap[baseVReg+1].fpLocation ==
+                    kLocPhysReg)) {
+                    int lowReg = cUnit->promotionMap[baseVReg].fpReg;
+                    int highReg = cUnit->promotionMap[baseVReg+1].fpReg;
+                    // Doubles require pair of singles starting at even reg
+                    if (((lowReg & 0x1) == 0) && ((lowReg + 1) == highReg)) {
+                        curr->location = kLocPhysReg;
+                        curr->lowReg = lowReg;
+                        curr->highReg = highReg;
+                        curr->home = true;
+                    }
+                }
+            } else {
+                if ((cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg)
+                     && (cUnit->promotionMap[baseVReg+1].coreLocation ==
+                     kLocPhysReg)) {
+                    curr->location = kLocPhysReg;
+                    curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
+                    curr->highReg = cUnit->promotionMap[baseVReg+1].coreReg;
+                    curr->home = true;
+                }
+            }
+        }
+    }
+}
+
+/* Returns sp-relative offset in bytes for a VReg */
+extern int oatVRegOffset(CompilationUnit* cUnit, int vReg)
+{
+    return (vReg < cUnit->numRegs) ? cUnit->regsOffset + (vReg << 2) :
+            cUnit->insOffset + ((vReg - cUnit->numRegs) << 2);
+}
+
+/* Returns sp-relative offset in bytes for a SReg */
+extern int oatSRegOffset(CompilationUnit* cUnit, int sReg)
+{
+    return oatVRegOffset(cUnit, oatS2VReg(cUnit, sReg));
+}
+
+
+/* Return sp-relative offset in bytes using Method* */
+extern int oatVRegOffset(const DexFile::CodeItem* code_item,
+                         uint32_t core_spills, uint32_t fp_spills,
+                         size_t frame_size, int reg)
+{
+    int numIns = code_item->ins_size_;
+    int numRegs = code_item->registers_size_ - numIns;
+    int numOuts = code_item->outs_size_;
+    int numSpills = __builtin_popcount(core_spills) +
+                    __builtin_popcount(fp_spills);
+    int numPadding = (STACK_ALIGN_WORDS -
+        (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1);
+    int regsOffset = (numOuts + numPadding + 1) * 4;
+    int insOffset = frame_size + 4;
+    return (reg < numRegs) ? regsOffset + (reg << 2) :
+           insOffset + ((reg - numRegs) << 2);
+}
+
 }  // namespace art
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index d700e48..62e4b3e 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -22,11 +22,64 @@
  *
  */
 
+#define SLOW_FIELD_PATH (cUnit->enableDebug & (1 << kDebugSlowFieldPath))
+#define SLOW_INVOKE_PATH (cUnit->enableDebug & (1 << kDebugSlowInvokePath))
+#define SLOW_STRING_PATH (cUnit->enableDebug & (1 << kDebugSlowStringPath))
+#define SLOW_TYPE_PATH (cUnit->enableDebug & (1 << kDebugSlowTypePath))
+#define EXERCISE_SLOWEST_FIELD_PATH (cUnit->enableDebug & \
+    (1 << kDebugSlowestFieldPath))
+#define EXERCISE_SLOWEST_STRING_PATH (cUnit->enableDebug & \
+    (1 << kDebugSlowestStringPath))
+#define EXERCISE_RESOLVE_METHOD (cUnit->enableDebug & \
+    (1 << kDebugExerciseResolveMethod))
+
 namespace art {
 
-STATIC ArmLIR* genUnconditionalBranch(CompilationUnit*, ArmLIR*);
-STATIC ArmLIR* genConditionalBranch(CompilationUnit*, ArmConditionCode,
-                                    ArmLIR*);
+STATIC void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
+
+/* Generate conditional branch instructions */
+STATIC ArmLIR* genConditionalBranch(CompilationUnit* cUnit,
+                                    ArmConditionCode cond,
+                                    ArmLIR* target)
+{
+    ArmLIR* branch = opCondBranch(cUnit, cond);
+    branch->generic.target = (LIR*) target;
+    return branch;
+}
+
+/* Generate unconditional branch instructions */
+STATIC ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
+{
+    ArmLIR* branch = opNone(cUnit, kOpUncondBr);
+    branch->generic.target = (LIR*) target;
+    return branch;
+}
+
+STATIC ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
+{
+    oatClobberCalleeSave(cUnit);
+    return opReg(cUnit, kOpBlx, reg);
+}
+
+/*
+ * Mark garbage collection card. Skip if the value we're storing is null.
+ */
+STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
+{
+    int regCardBase = oatAllocTemp(cUnit);
+    int regCardNo = oatAllocTemp(cUnit);
+    ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
+    loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
+                 regCardBase);
+    opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
+    storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
+                     kUnsignedByte);
+    ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR*)target;
+    oatFreeTemp(cUnit, regCardBase);
+    oatFreeTemp(cUnit, regCardNo);
+}
 
 /*
  * Utiltiy to load the current Method*.  Broken out
@@ -113,4 +166,1154 @@
     return branch;
 }
 
+/*
+ * Let helper function take care of everything.  Will call
+ * Array::AllocFromCode(type_idx, method, count);
+ * Note: AllocFromCode will handle checks for errNegativeArraySize.
+ */
+STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                        RegLocation rlSrc)
+{
+    oatFlushAllRegs(cUnit);    /* Everything to home location */
+    uint32_t type_idx = mir->dalvikInsn.vC;
+    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
+                                                    cUnit->dex_cache,
+                                                    *cUnit->dex_file,
+                                                    type_idx)) {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
+    } else {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), rLR);
+    }
+    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
+    loadConstant(cUnit, r0, type_idx);            // arg0 <- type_id
+    loadValueDirectFixed(cUnit, rlSrc, r2);       // arg2 <- count
+    callRuntimeHelper(cUnit, rLR);
+    RegLocation rlResult = oatGetReturn(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
+}
+
+/*
+ * Similar to genNewArray, but with post-allocation initialization.
+ * Verifier guarantees we're dealing with an array class.  Current
+ * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
+ * Current code also throws internal unimp if not 'L', '[' or 'I'.
+ */
+STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
+{
+    DecodedInstruction* dInsn = &mir->dalvikInsn;
+    int elems = dInsn->vA;
+    int typeId = dInsn->vB;
+    oatFlushAllRegs(cUnit);    /* Everything to home location */
+    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
+                                                    cUnit->dex_cache,
+                                                    *cUnit->dex_file,
+                                                    typeId)) {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
+    } else {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCodeWithAccessCheck), rLR);
+    }
+    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
+    loadConstant(cUnit, r0, typeId);              // arg0 <- type_id
+    loadConstant(cUnit, r2, elems);               // arg2 <- count
+    callRuntimeHelper(cUnit, rLR);
+    /*
+     * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
+     * return region.  Because AllocFromCode placed the new array
+     * in r0, we'll just lock it into place.  When debugger support is
+     * added, it may be necessary to additionally copy all return
+     * values to a home location in thread-local storage
+     */
+    oatLockTemp(cUnit, r0);
+
+    // Having a range of 0 is legal
+    if (isRange && (dInsn->vA > 0)) {
+        /*
+         * Bit of ugliness here.  We're going generate a mem copy loop
+         * on the register range, but it is possible that some regs
+         * in the range have been promoted.  This is unlikely, but
+         * before generating the copy, we'll just force a flush
+         * of any regs in the source range that have been promoted to
+         * home location.
+         */
+        for (unsigned int i = 0; i < dInsn->vA; i++) {
+            RegLocation loc = oatUpdateLoc(cUnit,
+                oatGetSrc(cUnit, mir, i));
+            if (loc.location == kLocPhysReg) {
+                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
+                              loc.lowReg, kWord);
+            }
+        }
+        /*
+         * TUNING note: generated code here could be much improved, but
+         * this is an uncommon operation and isn't especially performance
+         * critical.
+         */
+        int rSrc = oatAllocTemp(cUnit);
+        int rDst = oatAllocTemp(cUnit);
+        int rIdx = oatAllocTemp(cUnit);
+        int rVal = rLR;  // Using a lot of temps, rLR is known free here
+        // Set up source pointer
+        RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
+        opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
+                    oatSRegOffset(cUnit, rlFirst.sRegLow));
+        // Set up the target pointer
+        opRegRegImm(cUnit, kOpAdd, rDst, r0,
+                    Array::DataOffset().Int32Value());
+        // Set up the loop counter (known to be > 0)
+        loadConstant(cUnit, rIdx, dInsn->vA - 1);
+        // Generate the copy loop.  Going backwards for convenience
+        ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
+        target->defMask = ENCODE_ALL;
+        // Copy next element
+        loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
+        storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
+        // Use setflags encoding here
+        newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
+        ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
+        branch->generic.target = (LIR*)target;
+    } else if (!isRange) {
+        // TUNING: interleave
+        for (unsigned int i = 0; i < dInsn->vA; i++) {
+            RegLocation rlArg = loadValue(cUnit,
+                oatGetSrc(cUnit, mir, i), kCoreReg);
+            storeBaseDisp(cUnit, r0,
+                          Array::DataOffset().Int32Value() +
+                          i * 4, rlArg.lowReg, kWord);
+            // If the loadValue caused a temp to be allocated, free it
+            if (oatIsTemp(cUnit, rlArg.lowReg)) {
+                oatFreeTemp(cUnit, rlArg.lowReg);
+            }
+        }
+    }
+}
+
+STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
+                    bool isLongOrDouble, bool isObject)
+{
+    int fieldOffset;
+    int ssbIndex;
+    bool isVolatile;
+    bool isReferrersClass;
+    uint32_t fieldIdx = mir->dalvikInsn.vB;
+    bool fastPath =
+        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
+                                                fieldOffset, ssbIndex,
+                                                isReferrersClass, isVolatile, true);
+    if (fastPath && !SLOW_FIELD_PATH) {
+        DCHECK_GE(fieldOffset, 0);
+        int rBase;
+        int rMethod;
+        if (isReferrersClass) {
+            // Fast path, static storage base is this method's class
+            rMethod  = loadCurrMethod(cUnit);
+            rBase = oatAllocTemp(cUnit);
+            loadWordDisp(cUnit, rMethod,
+                         Method::DeclaringClassOffset().Int32Value(), rBase);
+        } else {
+            // Medium path, static storage base in a different class which
+            // requires checks that the other class is initialized.
+            DCHECK_GE(ssbIndex, 0);
+            // May do runtime call so everything to home locations.
+            oatFlushAllRegs(cUnit);
+            // Using fixed register to sync with possible call to runtime
+            // support.
+            rMethod = r1;
+            oatLockTemp(cUnit, rMethod);
+            loadCurrMethodDirect(cUnit, rMethod);
+            rBase = r0;
+            oatLockTemp(cUnit, rBase);
+            loadWordDisp(cUnit, rMethod,
+                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
+                rBase);
+            loadWordDisp(cUnit, rBase,
+                         Array::DataOffset().Int32Value() + sizeof(int32_t*) *
+                         ssbIndex, rBase);
+            // rBase now points at appropriate static storage base (Class*)
+            // or NULL if not initialized. Check for NULL and call helper if NULL.
+            // TUNING: fast path should fall through
+            ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
+            loadConstant(cUnit, r0, ssbIndex);
+            callRuntimeHelper(cUnit, rLR);
+            ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+            skipTarget->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR*)skipTarget;
+        }
+        // rBase now holds static storage base
+        oatFreeTemp(cUnit, rMethod);
+        if (isLongOrDouble) {
+            rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+            rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+        } else {
+            rlSrc = oatGetSrc(cUnit, mir, 0);
+            rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+        }
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kST);
+        }
+        if (isLongOrDouble) {
+            storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
+                              rlSrc.highReg);
+        } else {
+            storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
+        }
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kSY);
+        }
+        if (isObject) {
+            markGCCard(cUnit, rlSrc.lowReg, rBase);
+        }
+        oatFreeTemp(cUnit, rBase);
+    } else {
+        oatFlushAllRegs(cUnit);  // Everything to home locations
+        int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
+                           (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
+                                     : OFFSETOF_MEMBER(Thread, pSet32Static));
+        loadWordDisp(cUnit, rSELF, setterOffset, rLR);
+        loadConstant(cUnit, r0, fieldIdx);
+        if (isLongOrDouble) {
+            loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
+        } else {
+            loadValueDirect(cUnit, rlSrc, r1);
+        }
+        callRuntimeHelper(cUnit, rLR);
+    }
+}
+
+STATIC void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                    bool isLongOrDouble, bool isObject)
+{
+    int fieldOffset;
+    int ssbIndex;
+    bool isVolatile;
+    bool isReferrersClass;
+    uint32_t fieldIdx = mir->dalvikInsn.vB;
+    bool fastPath =
+        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
+                                                fieldOffset, ssbIndex,
+                                                isReferrersClass, isVolatile, false);
+    if (fastPath && !SLOW_FIELD_PATH) {
+        DCHECK_GE(fieldOffset, 0);
+        int rBase;
+        int rMethod;
+        if (isReferrersClass) {
+            // Fast path, static storage base is this method's class
+            rMethod  = loadCurrMethod(cUnit);
+            rBase = oatAllocTemp(cUnit);
+            loadWordDisp(cUnit, rMethod,
+                         Method::DeclaringClassOffset().Int32Value(), rBase);
+        } else {
+            // Medium path, static storage base in a different class which
+            // requires checks that the other class is initialized
+            DCHECK_GE(ssbIndex, 0);
+            // May do runtime call so everything to home locations.
+            oatFlushAllRegs(cUnit);
+            // Using fixed register to sync with possible call to runtime
+            // support
+            rMethod = r1;
+            oatLockTemp(cUnit, rMethod);
+            loadCurrMethodDirect(cUnit, rMethod);
+            rBase = r0;
+            oatLockTemp(cUnit, rBase);
+            loadWordDisp(cUnit, rMethod,
+                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
+                rBase);
+            loadWordDisp(cUnit, rBase,
+                         Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex,
+                         rBase);
+            // rBase now points at appropriate static storage base (Class*)
+            // or NULL if not initialized. Check for NULL and call helper if NULL.
+            // TUNING: fast path should fall through
+            ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
+            loadConstant(cUnit, r0, ssbIndex);
+            callRuntimeHelper(cUnit, rLR);
+            ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+            skipTarget->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR*)skipTarget;
+        }
+        // rBase now holds static storage base
+        oatFreeTemp(cUnit, rMethod);
+        rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
+                                : oatGetDest(cUnit, mir, 0);
+        RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kSY);
+        }
+        if (isLongOrDouble) {
+            loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
+                             rlResult.highReg, INVALID_SREG);
+        } else {
+            loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
+        }
+        oatFreeTemp(cUnit, rBase);
+        if (isLongOrDouble) {
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    } else {
+        oatFlushAllRegs(cUnit);  // Everything to home locations
+        int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
+                           (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
+                                     : OFFSETOF_MEMBER(Thread, pGet32Static));
+        loadWordDisp(cUnit, rSELF, getterOffset, rLR);
+        loadConstant(cUnit, r0, fieldIdx);
+        callRuntimeHelper(cUnit, rLR);
+        if (isLongOrDouble) {
+            RegLocation rlResult = oatGetReturnWide(cUnit);
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            RegLocation rlResult = oatGetReturn(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    }
+}
+
+typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
+                            uint32_t methodIdx);
+
+/*
+ * Bit of a hack here - in leiu of a real scheduling pass,
+ * emit the next instruction in static & direct invoke sequences.
+ */
+STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
+                          int state, uint32_t dexIdx, uint32_t unused)
+{
+    switch(state) {
+        case 0:  // Get the current Method* [sets r0]
+            loadCurrMethodDirect(cUnit, r0);
+            break;
+        case 1:  // Get method->code_and_direct_methods_
+            loadWordDisp(cUnit, r0,
+                Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
+                r0);
+            break;
+        case 2:  // Grab target method* and target code_
+            loadWordDisp(cUnit, r0,
+                CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR);
+            loadWordDisp(cUnit, r0,
+                CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0);
+            break;
+        default:
+            return -1;
+    }
+    return state + 1;
+}
+
+/*
+ * Bit of a hack here - in leiu of a real scheduling pass,
+ * emit the next instruction in a virtual invoke sequence.
+ * We can use rLR as a temp prior to target address loading
+ * Note also that we'll load the first argument ("this") into
+ * r1 here rather than the standard loadArgRegs.
+ */
+STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
+                         int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    RegLocation rlArg;
+    /*
+     * This is the fast path in which the target virtual method is
+     * fully resolved at compile time.
+     */
+    switch(state) {
+        case 0:  // Get "this" [set r1]
+            rlArg = oatGetSrc(cUnit, mir, 0);
+            loadValueDirectFixed(cUnit, rlArg, r1);
+            break;
+        case 1: // Is "this" null? [use r1]
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+            // get this->klass_ [use r1, set rLR]
+            loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
+            break;
+        case 2: // Get this->klass_->vtable [usr rLR, set rLR]
+            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
+            break;
+        case 3: // Get target method [use rLR, set r0]
+            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
+                         Array::DataOffset().Int32Value(), r0);
+            break;
+        case 4: // Get the target compiled code address [uses r0, sets rLR]
+            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
+            break;
+        default:
+            return -1;
+    }
+    return state + 1;
+}
+
+/*
+ * Interleave launch code for INVOKE_SUPER.  See comments
+ * for nextVCallIns.
+ */
+STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
+                             int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    /*
+     * This is the fast path in which the target virtual method is
+     * fully resolved at compile time.  Note also that this path assumes
+     * that the check to verify that the target method index falls
+     * within the size of the super's vtable has been done at compile-time.
+     */
+    RegLocation rlArg;
+    switch(state) {
+        case 0: // Get current Method* [set r0]
+            loadCurrMethodDirect(cUnit, r0);
+            // Load "this" [set r1]
+            rlArg = oatGetSrc(cUnit, mir, 0);
+            loadValueDirectFixed(cUnit, rlArg, r1);
+            // Get method->declaring_class_ [use r0, set rLR]
+            loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
+                         rLR);
+            // Is "this" null? [use r1]
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+            break;
+        case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
+            loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
+                         rLR);
+            break;
+        case 2: // Get ...->super_class_->vtable [u/s rLR]
+            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
+            break;
+        case 3: // Get target method [use rLR, set r0]
+            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
+                         Array::DataOffset().Int32Value(), r0);
+            break;
+        case 4: // Get the target compiled code address [uses r0, sets rLR]
+            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
+            break;
+        default:
+            return -1;
+    }
+    return state + 1;
+}
+
+STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, int trampoline,
+                            int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    /*
+     * This handles the case in which the base method is not fully
+     * resolved at compile time, we bail to a runtime helper.
+     */
+    if (state == 0) {
+        // Load trampoline target
+        loadWordDisp(cUnit, rSELF, trampoline, rLR);
+        // Load r0 with method index
+        loadConstant(cUnit, r0, dexIdx);
+        return 1;
+    }
+    return -1;
+}
+
+STATIC int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                                int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                                int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                               int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                           int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+/*
+ * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
+ * which will locate the target and continue on via a tail call.
+ */
+STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
+                                 int state, uint32_t dexIdx, uint32_t unused)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
+                                                MIR* mir, int state,
+                                                uint32_t dexIdx,
+                                                uint32_t unused)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
+                          DecodedInstruction* dInsn, int callState,
+                          NextCallInsn nextCallInsn, uint32_t dexIdx,
+                          uint32_t methodIdx, bool skipThis)
+{
+    int nextReg = r1;
+    int nextArg = 0;
+    if (skipThis) {
+        nextReg++;
+        nextArg++;
+    }
+    for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
+        RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
+        rlArg = oatUpdateRawLoc(cUnit, rlArg);
+        if (rlArg.wide && (nextReg <= r2)) {
+            loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
+            nextReg++;
+            nextArg++;
+        } else {
+            rlArg.wide = false;
+            loadValueDirectFixed(cUnit, rlArg, nextReg);
+        }
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    }
+    return callState;
+}
+
+/*
+ * Load up to 5 arguments, the first three of which will be in
+ * r1 .. r3.  On entry r0 contains the current method pointer,
+ * and as part of the load sequence, it must be replaced with
+ * the target method pointer.  Note, this may also be called
+ * for "range" variants if the number of arguments is 5 or fewer.
+ */
+STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
+                                DecodedInstruction* dInsn, int callState,
+                                ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
+                                uint32_t dexIdx, uint32_t methodIdx,
+                                bool skipThis)
+{
+    RegLocation rlArg;
+
+    /* If no arguments, just return */
+    if (dInsn->vA == 0)
+        return callState;
+
+    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+
+    DCHECK_LE(dInsn->vA, 5U);
+    if (dInsn->vA > 3) {
+        uint32_t nextUse = 3;
+        //Detect special case of wide arg spanning arg3/arg4
+        RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
+        RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
+        RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
+        if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
+            rlUse2.wide) {
+            int reg;
+            // Wide spans, we need the 2nd half of uses[2].
+            rlArg = oatUpdateLocWide(cUnit, rlUse2);
+            if (rlArg.location == kLocPhysReg) {
+                reg = rlArg.highReg;
+            } else {
+                // r2 & r3 can safely be used here
+                reg = r3;
+                loadWordDisp(cUnit, rSP,
+                             oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
+                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+                                         methodIdx);
+            }
+            storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
+            storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
+            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+            nextUse++;
+        }
+        // Loop through the rest
+        while (nextUse < dInsn->vA) {
+            int lowReg;
+            int highReg;
+            rlArg = oatGetRawSrc(cUnit, mir, nextUse);
+            rlArg = oatUpdateRawLoc(cUnit, rlArg);
+            if (rlArg.location == kLocPhysReg) {
+                lowReg = rlArg.lowReg;
+                highReg = rlArg.highReg;
+            } else {
+                lowReg = r2;
+                highReg = r3;
+                if (rlArg.wide) {
+                    loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
+                } else {
+                    loadValueDirectFixed(cUnit, rlArg, lowReg);
+                }
+                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+                                         methodIdx);
+            }
+            int outsOffset = (nextUse + 1) * 4;
+            if (rlArg.wide) {
+                storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
+                nextUse += 2;
+            } else {
+                storeWordDisp(cUnit, rSP, outsOffset, lowReg);
+                nextUse++;
+            }
+            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        }
+    }
+
+    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
+                            dexIdx, methodIdx, skipThis);
+
+    if (pcrLabel) {
+        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+    }
+    return callState;
+}
+
+/*
+ * May have 0+ arguments (also used for jumbo).  Note that
+ * source virtual registers may be in physical registers, so may
+ * need to be flushed to home location before copying.  This
+ * applies to arg3 and above (see below).
+ *
+ * Two general strategies:
+ *    If < 20 arguments
+ *       Pass args 3-18 using vldm/vstm block copy
+ *       Pass arg0, arg1 & arg2 in r1-r3
+ *    If 20+ arguments
+ *       Pass args arg19+ using memcpy block copy
+ *       Pass arg0, arg1 & arg2 in r1-r3
+ *
+ */
+STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
+                              DecodedInstruction* dInsn, int callState,
+                              ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
+                              uint32_t dexIdx, uint32_t methodIdx,
+                              bool skipThis)
+{
+    int firstArg = dInsn->vC;
+    int numArgs = dInsn->vA;
+
+    // If we can treat it as non-range (Jumbo ops will use range form)
+    if (numArgs <= 5)
+        return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
+                                    nextCallInsn, dexIdx, methodIdx,
+                                    skipThis);
+    /*
+     * Make sure range list doesn't span the break between in normal
+     * Dalvik vRegs and the ins.
+     */
+    int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
+    int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
+    if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
+        LOG(FATAL) << "Argument list spanned locals & args";
+    }
+
+    /*
+     * First load the non-register arguments.  Both forms expect all
+     * of the source arguments to be in their home frame location, so
+     * scan the sReg names and flush any that have been promoted to
+     * frame backing storage.
+     */
+    // Scan the rest of the args - if in physReg flush to memory
+    for (int nextArg = 0; nextArg < numArgs;) {
+        RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
+        if (loc.wide) {
+            loc = oatUpdateLocWide(cUnit, loc);
+            if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
+                storeBaseDispWide(cUnit, rSP,
+                                  oatSRegOffset(cUnit, loc.sRegLow),
+                                  loc.lowReg, loc.highReg);
+            }
+            nextArg += 2;
+        } else {
+            loc = oatUpdateLoc(cUnit, loc);
+            if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
+                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
+                              loc.lowReg, kWord);
+            }
+            nextArg++;
+        }
+    }
+
+    int startOffset = oatSRegOffset(cUnit,
+        cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
+    int outsOffset = 4 /* Method* */ + (3 * 4);
+    if (numArgs >= 20) {
+        // Generate memcpy
+        opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
+        opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
+        loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
+        loadConstant(cUnit, r2, (numArgs - 3) * 4);
+        callRuntimeHelper(cUnit, rLR);
+        // Restore Method*
+        loadCurrMethodDirect(cUnit, r0);
+    } else {
+        // Use vldm/vstm pair using r3 as a temp
+        int regsLeft = std::min(numArgs - 3, 16);
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
+        ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
+        //TUNING: loosen barrier
+        ld->defMask = ENCODE_ALL;
+        setMemRefType(ld, true /* isLoad */, kDalvikReg);
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
+        setMemRefType(st, false /* isLoad */, kDalvikReg);
+        st->defMask = ENCODE_ALL;
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    }
+
+    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
+                            dexIdx, methodIdx, skipThis);
+
+    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    if (pcrLabel) {
+        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+    }
+    return callState;
+}
+
+// Debugging routine - if null target, branch to DebugMe
+STATIC void genShowTarget(CompilationUnit* cUnit)
+{
+    ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
+    loadWordDisp(cUnit, rSELF,
+                 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
+    ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = -1;
+    branchOver->generic.target = (LIR*)target;
+}
+
+STATIC void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
+{
+    loadWordDisp(cUnit, rSELF,
+                 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
+    loadConstant(cUnit, r0, mir->dalvikInsn.vA);
+    loadConstant(cUnit, r1, mir->dalvikInsn.vB);
+    callRuntimeHelper(cUnit, rLR);
+}
+
+STATIC void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
+                                MIR* mir, RegLocation rlSrc1,
+                                RegLocation rlSrc2, ArmLIR* labelList)
+{
+    ArmConditionCode cond;
+    rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+    opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
+    Opcode opcode = mir->dalvikInsn.opcode;
+    switch(opcode) {
+        case OP_IF_EQ:
+            cond = kArmCondEq;
+            break;
+        case OP_IF_NE:
+            cond = kArmCondNe;
+            break;
+        case OP_IF_LT:
+            cond = kArmCondLt;
+            break;
+        case OP_IF_GE:
+            cond = kArmCondGe;
+            break;
+        case OP_IF_GT:
+            cond = kArmCondGt;
+            break;
+        case OP_IF_LE:
+            cond = kArmCondLe;
+            break;
+        default:
+            cond = (ArmConditionCode)0;
+            LOG(FATAL) << "Unexpected opcode " << (int)opcode;
+    }
+    genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
+    genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+}
+
+STATIC void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
+                                   MIR* mir, RegLocation rlSrc,
+                                   ArmLIR* labelList)
+{
+    ArmConditionCode cond;
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
+    Opcode opcode = mir->dalvikInsn.opcode;
+    switch(opcode) {
+        case OP_IF_EQZ:
+            cond = kArmCondEq;
+            break;
+        case OP_IF_NEZ:
+            cond = kArmCondNe;
+            break;
+        case OP_IF_LTZ:
+            cond = kArmCondLt;
+            break;
+        case OP_IF_GEZ:
+            cond = kArmCondGe;
+            break;
+        case OP_IF_GTZ:
+            cond = kArmCondGt;
+            break;
+        case OP_IF_LEZ:
+            cond = kArmCondLe;
+            break;
+        default:
+            cond = (ArmConditionCode)0;
+            LOG(FATAL) << "Unexpected opcode " << (int)opcode;
+    }
+    genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
+    genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+}
+
+STATIC void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                         RegLocation rlSrc)
+{
+    RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+    if (rlSrc.location == kLocPhysReg) {
+        genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+    } else {
+        loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
+    }
+    opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
+                rlResult.lowReg, 31);
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+STATIC void genIntNarrowing(CompilationUnit* cUnit, MIR* mir,
+                            RegLocation rlDest, RegLocation rlSrc)
+{
+     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+     RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+     OpKind op = kOpInvalid;
+     switch(mir->dalvikInsn.opcode) {
+         case OP_INT_TO_BYTE:
+             op = kOp2Byte;
+             break;
+         case OP_INT_TO_SHORT:
+              op = kOp2Short;
+              break;
+         case OP_INT_TO_CHAR:
+              op = kOp2Char;
+              break;
+         default:
+             LOG(ERROR) << "Bad int conversion type";
+     }
+     opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
+     storeValue(cUnit, rlDest, rlResult);
+}
+
+/*
+ * If there are any ins passed in registers that have not been promoted
+ * to a callee-save register, flush them to the frame.  Perform intial
+ * assignment of promoted arguments.
+ */
+STATIC void flushIns(CompilationUnit* cUnit)
+{
+    if (cUnit->numIns == 0)
+        return;
+    int firstArgReg = r1;
+    int lastArgReg = r3;
+    int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
+    /*
+     * Arguments passed in registers should be flushed
+     * to their backing locations in the frame for now.
+     * Also, we need to do initial assignment for promoted
+     * arguments.  NOTE: an older version of dx had an issue
+     * in which it would reuse static method argument registers.
+     * This could result in the same Dalvik virtual register
+     * being promoted to both core and fp regs.  In those
+     * cases, copy argument to both.  This will be uncommon
+     * enough that it isn't worth attempting to optimize.
+     */
+    for (int i = 0; i < cUnit->numIns; i++) {
+        PromotionMap vMap = cUnit->promotionMap[startVReg + i];
+        if (i <= (lastArgReg - firstArgReg)) {
+            // If arriving in register
+            if (vMap.coreLocation == kLocPhysReg) {
+                genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
+            }
+            if (vMap.fpLocation == kLocPhysReg) {
+                genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
+            }
+            // Also put a copy in memory in case we're partially promoted
+            storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                          firstArgReg + i, kWord);
+        } else {
+            // If arriving in frame & promoted
+            if (vMap.coreLocation == kLocPhysReg) {
+                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                             vMap.coreReg);
+            }
+            if (vMap.fpLocation == kLocPhysReg) {
+                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                             vMap.fpReg);
+            }
+        }
+    }
+}
+
+STATIC void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
+    /*
+     * On entry, r0, r1, r2 & r3 are live.  Let the register allocation
+     * mechanism know so it doesn't try to use any of them when
+     * expanding the frame or flushing.  This leaves the utility
+     * code with a single temp: r12.  This should be enough.
+     */
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+    oatLockTemp(cUnit, r2);
+    oatLockTemp(cUnit, r3);
+
+    /*
+     * We can safely skip the stack overflow check if we're
+     * a leaf *and* our frame size < fudge factor.
+     */
+    bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
+                              ((size_t)cUnit->frameSize <
+                              Thread::kStackOverflowReservedBytes));
+    newLIR0(cUnit, kArmPseudoMethodEntry);
+    if (!skipOverflowCheck) {
+        /* Load stack limit */
+        loadWordDisp(cUnit, rSELF,
+                     Thread::StackEndOffset().Int32Value(), r12);
+    }
+    /* Spill core callee saves */
+    newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
+    /* Need to spill any FP regs? */
+    if (cUnit->numFPSpills) {
+        /*
+         * NOTE: fp spills are a little different from core spills in that
+         * they are pushed as a contiguous block.  When promoting from
+         * the fp set, we must allocate all singles from s16..highest-promoted
+         */
+        newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
+    }
+    if (!skipOverflowCheck) {
+        opRegRegImm(cUnit, kOpSub, rLR, rSP,
+                    cUnit->frameSize - (spillCount * 4));
+        genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
+                       kArmThrowStackOverflow);
+        genRegCopy(cUnit, rSP, rLR);         // Establish stack
+    } else {
+        opRegImm(cUnit, kOpSub, rSP,
+                 cUnit->frameSize - (spillCount * 4));
+    }
+    storeBaseDisp(cUnit, rSP, 0, r0, kWord);
+    flushIns(cUnit);
+
+    if (cUnit->genDebugger) {
+        // Refresh update debugger callout
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
+        genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
+    }
+
+    oatFreeTemp(cUnit, r0);
+    oatFreeTemp(cUnit, r1);
+    oatFreeTemp(cUnit, r2);
+    oatFreeTemp(cUnit, r3);
+}
+
+STATIC void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
+    /*
+     * In the exit path, r0/r1 are live - make sure they aren't
+     * allocated by the register utilities as temps.
+     */
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+
+    newLIR0(cUnit, kArmPseudoMethodExit);
+    /* If we're compiling for the debugger, generate an update callout */
+    if (cUnit->genDebugger) {
+        genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
+    }
+    opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
+    /* Need to restore any FP callee saves? */
+    if (cUnit->numFPSpills) {
+        newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
+    }
+    if (cUnit->coreSpillMask & (1 << rLR)) {
+        /* Unspill rLR to rPC */
+        cUnit->coreSpillMask &= ~(1 << rLR);
+        cUnit->coreSpillMask |= (1 << rPC);
+    }
+    newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
+    if (!(cUnit->coreSpillMask & (1 << rPC))) {
+        /* We didn't pop to rPC, so must do a bv rLR */
+        newLIR1(cUnit, kThumbBx, rLR);
+    }
+}
+
+/*
+ * Nop any unconditional branches that go to the next instruction.
+ * Note: new redundant branches may be inserted later, and we'll
+ * use a check in final instruction assembly to nop those out.
+ */
+void removeRedundantBranches(CompilationUnit* cUnit)
+{
+    ArmLIR* thisLIR;
+
+    for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
+         thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
+         thisLIR = NEXT_LIR(thisLIR)) {
+
+        /* Branch to the next instruction */
+        if ((thisLIR->opcode == kThumbBUncond) ||
+            (thisLIR->opcode == kThumb2BUncond)) {
+            ArmLIR* nextLIR = thisLIR;
+
+            while (true) {
+                nextLIR = NEXT_LIR(nextLIR);
+
+                /*
+                 * Is the branch target the next instruction?
+                 */
+                if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
+                    thisLIR->flags.isNop = true;
+                    break;
+                }
+
+                /*
+                 * Found real useful stuff between the branch and the target.
+                 * Need to explicitly check the lastLIRInsn here because it
+                 * might be the last real instruction.
+                 */
+                if (!isPseudoOpcode(nextLIR->opcode) ||
+                    (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
+                    break;
+            }
+        }
+    }
+}
+
+STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
+{
+    ArmLIR** suspendLabel =
+        (ArmLIR **) cUnit->suspendLaunchpads.elemList;
+    int numElems = cUnit->suspendLaunchpads.numUsed;
+
+    for (int i = 0; i < numElems; i++) {
+        /* TUNING: move suspend count load into helper */
+        ArmLIR* lab = suspendLabel[i];
+        ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
+        cUnit->currentDalvikOffset = lab->operands[1];
+        oatAppendLIR(cUnit, (LIR *)lab);
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
+        if (!cUnit->genDebugger) {
+            // use rSUSPEND for suspend count
+            loadWordDisp(cUnit, rSELF,
+                         Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
+        }
+        opReg(cUnit, kOpBlx, rLR);
+        if ( cUnit->genDebugger) {
+            // use rSUSPEND for update debugger
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
+        }
+        genUnconditionalBranch(cUnit, resumeLab);
+    }
+}
+
+STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
+{
+    ArmLIR** throwLabel =
+        (ArmLIR **) cUnit->throwLaunchpads.elemList;
+    int numElems = cUnit->throwLaunchpads.numUsed;
+    int i;
+
+    for (i = 0; i < numElems; i++) {
+        ArmLIR* lab = throwLabel[i];
+        cUnit->currentDalvikOffset = lab->operands[1];
+        oatAppendLIR(cUnit, (LIR *)lab);
+        int funcOffset = 0;
+        int v1 = lab->operands[2];
+        int v2 = lab->operands[3];
+        switch(lab->operands[0]) {
+            case kArmThrowNullPointer:
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
+                break;
+            case kArmThrowArrayBounds:
+                if (v2 != r0) {
+                    genRegCopy(cUnit, r0, v1);
+                    genRegCopy(cUnit, r1, v2);
+                } else {
+                    if (v1 == r1) {
+                        genRegCopy(cUnit, r12, v1);
+                        genRegCopy(cUnit, r1, v2);
+                        genRegCopy(cUnit, r0, r12);
+                    } else {
+                        genRegCopy(cUnit, r1, v2);
+                        genRegCopy(cUnit, r0, v1);
+                    }
+                }
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
+                break;
+            case kArmThrowDivZero:
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
+                break;
+            case kArmThrowVerificationError:
+                loadConstant(cUnit, r0, v1);
+                loadConstant(cUnit, r1, v2);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
+                break;
+            case kArmThrowNegArraySize:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
+                break;
+            case kArmThrowNoSuchMethod:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
+                break;
+            case kArmThrowStackOverflow:
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
+                // Restore stack alignment
+                opRegImm(cUnit, kOpAdd, rSP,
+                         (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
+                break;
+            default:
+                LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
+        }
+        loadWordDisp(cUnit, rSELF, funcOffset, rLR);
+        callRuntimeHelper(cUnit, rLR);
+    }
+}
+
+/* Common initialization routine for an architecture family */
+bool oatArchInit()
+{
+    int i;
+
+    for (i = 0; i < kArmLast; i++) {
+        if (EncodingMap[i].opcode != i) {
+            LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
+               " is wrong: expecting " << i << ", seeing " <<
+               (int)EncodingMap[i].opcode;
+        }
+    }
+
+    return oatArchVariantInit();
+}
+
+/* Needed by the Assembler */
+void oatSetupResourceMasks(ArmLIR* lir)
+{
+    setupResourceMasks(lir);
+}
+
 }  // namespace art
diff --git a/src/compiler/codegen/arm/ArchUtility.cc b/src/compiler/codegen/arm/ArchUtility.cc
index c9a30fd..75ae456 100644
--- a/src/compiler/codegen/arm/ArchUtility.cc
+++ b/src/compiler/codegen/arm/ArchUtility.cc
@@ -363,9 +363,8 @@
             } else {
                 std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr));
                 std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr));
-                LOG(INFO) << StringPrintf("%p (%04x): %-9s%s%s%s", baseAddr + offset, offset,
-                    op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : "",
-                    lir->flags.squashed ? "(squashed)" : "");
+                LOG(INFO) << StringPrintf("%p (%04x): %-9s%s%s", baseAddr + offset, offset,
+                    op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : "");
             }
             break;
     }
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index 510a5ea..a9c8286 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -125,41 +125,9 @@
 #define rNone   (-1)
 
 /* RegisterLocation templates return values (r0, or r0/r1) */
-#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 1, r0, INVALID_REG, INVALID_SREG}
+#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 1, r0, INVALID_REG,\
+                      INVALID_SREG}
 #define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 1, r0, r1, INVALID_SREG}
-/* RegisterLocation templates for interpState->retVal; */
-#define LOC_DALVIK_RETURN_VAL {kLocPhysReg, 0, 0, 0, 0, 0, 1, r0, INVALID_REG, \
-                      INVALID_SREG}
-#define LOC_DALVIK_RETURN_VAL_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 1, r0, r1, \
-                      INVALID_SREG}
-
- /*
- * Data structure tracking the mapping between a Dalvik register (pair) and a
- * native register (pair). The idea is to reuse the previously loaded value
- * if possible, otherwise to keep the value in a native register as long as
- * possible.
- */
-typedef struct RegisterInfo {
-    int reg;                    // Reg number
-    bool inUse;                 // Has it been allocated?
-    bool isTemp;                // Can allocate as temp?
-    bool pair;                  // Part of a register pair?
-    int partner;                // If pair, other reg of pair
-    bool live;                  // Is there an associated SSA name?
-    bool dirty;                 // If live, is it dirty?
-    int sReg;                   // Name of live value
-    struct LIR *defStart;       // Starting inst in last def sequence
-    struct LIR *defEnd;         // Ending inst in last def sequence
-} RegisterInfo;
-
-typedef struct RegisterPool {
-    int numCoreRegs;
-    RegisterInfo *coreRegs;
-    int nextCoreReg;
-    int numFPRegs;
-    RegisterInfo *FPRegs;
-    int nextFPReg;
-} RegisterPool;
 
 typedef enum ResourceEncodingPos {
     kGPReg0     = 0,
@@ -199,17 +167,6 @@
 #define DECODE_ALIAS_INFO_REG(X)        (X & 0xffff)
 #define DECODE_ALIAS_INFO_WIDE(X)       ((X & 0x80000000) ? 1 : 0)
 
-typedef enum OpSize {
-    kWord,
-    kLong,
-    kSingle,
-    kDouble,
-    kUnsignedHalf,
-    kSignedHalf,
-    kUnsignedByte,
-    kSignedByte,
-} OpSize;
-
 typedef enum OpKind {
     kOpMov,
     kOpMvn,
@@ -243,6 +200,7 @@
     kOp2Byte,
     kOpCondBr,
     kOpUncondBr,
+    kOpInvalid,
 } OpKind;
 
 /*
@@ -844,12 +802,10 @@
     int operands[4];            // [0..3] = [dest, src1, src2, extra]
     struct {
         bool isNop:1;           // LIR is optimized away
-        bool insertWrapper:1;   // insert branch to emulate memory accesses
-        bool squashed:1;        // Eliminated def
         bool pcRelFixup:1;      // May need pc-relative fixup
         unsigned int age:4;     // default is 0, set lazily by the optimizer
         unsigned int size:3;    // bytes (2 for thumb, 2/4 for thumb2)
-        unsigned int unused:21;
+        unsigned int unused:23;
     } flags;
     int aliasInfo;              // For Dalvik register & litpool disambiguation
     u8 useMask;                 // Resource mask for use
@@ -871,10 +827,6 @@
     int vaddr;                 // Dalvik offset of OP_FILL_ARRAY_DATA opcode
 } FillArrayData;
 
-/* Init values when a predicted chain is initially assembled */
-/* E7FE is branch to self */
-#define PREDICTED_CHAIN_BX_PAIR_INIT     0xe7fe
-
 /* Utility macros to traverse the LIR/ArmLIR list */
 #define NEXT_LIR(lir) ((ArmLIR *) lir->generic.next)
 #define PREV_LIR(lir) ((ArmLIR *) lir->generic.prev)
@@ -882,11 +834,6 @@
 #define NEXT_LIR_LVALUE(lir) (lir)->generic.next
 #define PREV_LIR_LVALUE(lir) (lir)->generic.prev
 
-#define CHAIN_CELL_OFFSET_TAG   0xcdab
-
-#define CHAIN_CELL_NORMAL_SIZE 12
-#define CHAIN_CELL_PREDICTED_SIZE 16
-
 }  // namespace art
 
 #endif  // ART_SRC_COMPILER_CODEGEN_ARM_ARMLIR_H_
diff --git a/src/compiler/codegen/arm/ArmRallocUtil.cc b/src/compiler/codegen/arm/ArmRallocUtil.cc
index 1986b0f..38f1b88 100644
--- a/src/compiler/codegen/arm/ArmRallocUtil.cc
+++ b/src/compiler/codegen/arm/ArmRallocUtil.cc
@@ -28,262 +28,87 @@
 namespace art {
 
 /*
- * Placeholder routine until we do proper register allocation.
+ * TUNING: is leaf?  Can't just use "hasInvoke" to determine as some
+ * instructions might call out to C/assembly helper functions.  Until
+ * machinery is in place, always spill lr.
  */
 
-typedef struct RefCounts {
-    int count;
-    int sReg;
-    bool doubleStart;   // Starting vReg for a double
-} RefCounts;
-
-/* USE SSA names to count references of base Dalvik vRegs. */
-STATIC void countRefs(CompilationUnit *cUnit, BasicBlock* bb,
-                      RefCounts* coreCounts, RefCounts* fpCounts)
+void oatAdjustSpillMask(CompilationUnit* cUnit)
 {
-    MIR* mir;
-    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
-        bb->blockType != kExitBlock)
-        return;
-
-    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
-        SSARepresentation *ssaRep = mir->ssaRep;
-        if (ssaRep) {
-            for (int i = 0; i < ssaRep->numDefs;) {
-                RegLocation loc = cUnit->regLocation[ssaRep->defs[i]];
-                RefCounts* counts = loc.fp ? fpCounts : coreCounts;
-                int vReg = oatS2VReg(cUnit, ssaRep->defs[i]);
-                if (loc.defined) {
-                    counts[vReg].count++;
-                }
-                if (loc.wide) {
-                    if (loc.defined) {
-                        if (loc.fp) {
-                            counts[vReg].doubleStart = true;
-                        }
-                        counts[vReg+1].count++;
-                    }
-                    i += 2;
-                } else {
-                    i++;
-                }
-            }
-            for (int i = 0; i < ssaRep->numUses;) {
-                RegLocation loc = cUnit->regLocation[ssaRep->uses[i]];
-                RefCounts* counts = loc.fp ? fpCounts : coreCounts;
-                int vReg = oatS2VReg(cUnit, ssaRep->uses[i]);
-                if (loc.defined) {
-                    counts[vReg].count++;
-                }
-                if (loc.wide) {
-                    if (loc.defined) {
-                        if (loc.fp) {
-                            counts[vReg].doubleStart = true;
-                        }
-                        counts[vReg+1].count++;
-                    }
-                    i += 2;
-                } else {
-                    i++;
-                }
-            }
-        }
-    }
-}
-
-/* qsort callback function, sort descending */
-STATIC int sortCounts(const void *val1, const void *val2)
-{
-    const RefCounts* op1 = (const RefCounts*)val1;
-    const RefCounts* op2 = (const RefCounts*)val2;
-    return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
-}
-
-STATIC void dumpCounts(const RefCounts* arr, int size, const char* msg)
-{
-    LOG(INFO) << msg;
-    for (int i = 0; i < size; i++) {
-        LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count;
-    }
+    cUnit->coreSpillMask |= (1 << rLR);
+    cUnit->numCoreSpills++;
 }
 
 /*
- * Note: some portions of this code required even if the kPromoteRegs
- * optimization is disabled.
+ * Mark a callee-save fp register as promoted.  Note that
+ * vpush/vpop uses contiguous register lists so we must
+ * include any holes in the mask.  Associate holes with
+ * Dalvik register INVALID_VREG (0xFFFFU).
  */
-extern void oatDoPromotion(CompilationUnit* cUnit)
+void oatMarkPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
 {
-    int numRegs = cUnit->numDalvikRegisters;
-
-    /*
-     * TUNING: is leaf?  Can't just use "hasInvoke" to determine as some
-     * instructions might call out to C/assembly helper functions.  Until
-     * machinery is in place, always spill lr.
-     */
-    cUnit->coreSpillMask |= (1 << rLR);
-    cUnit->numCoreSpills++;
-    /*
-     * Simple hack for testing register allocation.  Just do a static
-     * count of the uses of Dalvik registers.  Note that we examine
-     * the SSA names, but count based on original Dalvik register name.
-     * Count refs separately based on type in order to give allocation
-     * preference to fp doubles - which must be allocated sequential
-     * physical single fp registers started with an even-numbered
-     * reg.
-     */
-    RefCounts *coreRegs = (RefCounts *)
-          oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
-    RefCounts *fpRegs = (RefCounts *)
-          oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
-    for (int i = 0; i < numRegs; i++) {
-        coreRegs[i].sReg = fpRegs[i].sReg = i;
+    DCHECK_GE(reg, FP_REG_MASK + FP_CALLEE_SAVE_BASE);
+    reg = (reg & FP_REG_MASK) - FP_CALLEE_SAVE_BASE;
+    // Ensure fpVmapTable is large enough
+    int tableSize = cUnit->fpVmapTable.size();
+    for (int i = tableSize; i < (reg + 1); i++) {
+        cUnit->fpVmapTable.push_back(INVALID_VREG);
     }
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
-    while (true) {
-        BasicBlock* bb;
-        bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator);
-        if (bb == NULL) break;
-        countRefs(cUnit, bb, coreRegs, fpRegs);
-    }
+    // Add the current mapping
+    cUnit->fpVmapTable[reg] = sReg;
+    // Size of fpVmapTable is high-water mark, use to set mask
+    cUnit->numFPSpills = cUnit->fpVmapTable.size();
+    cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << FP_CALLEE_SAVE_BASE;
+}
 
-    /*
-     * Ideally, we'd allocate doubles starting with an even-numbered
-     * register.  Bias the counts to try to allocate any vreg that's
-     * used as the start of a pair first.
-     */
-    for (int i = 0; i < numRegs; i++) {
-        if (fpRegs[i].doubleStart) {
-            fpRegs[i].count *= 2;
-        }
-    }
-
-    // Sort the count arrays
-    qsort(coreRegs, numRegs, sizeof(RefCounts), sortCounts);
-    qsort(fpRegs, numRegs, sizeof(RefCounts), sortCounts);
-
-    if (cUnit->printMe) {
-        dumpCounts(coreRegs, numRegs, "Core regs after sort");
-        dumpCounts(fpRegs, numRegs, "Fp regs after sort");
-    }
-
-    if (!(cUnit->disableOpt & (1 << kPromoteRegs))) {
-        // Promote fpRegs
-        for (int i = 0; (fpRegs[i].count > 0) && (i < numRegs); i++) {
-            if (cUnit->promotionMap[fpRegs[i].sReg].fpLocation != kLocPhysReg) {
-                if (fpRegs[i].sReg >= cUnit->numRegs) {
-                    // don't promote arg regs
-                    continue;
-                }
-                int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg,
-                    fpRegs[i].doubleStart);
-                if (reg < 0) {
-                    break;  // No more left
-                }
-            }
+void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
+{
+    RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
+    RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
+    DCHECK(info1 && info2 && info1->pair && info2->pair &&
+           (info1->partner == info2->reg) &&
+           (info2->partner == info1->reg));
+    if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
+        if (!(info1->isTemp && info2->isTemp)) {
+            /* Should not happen.  If it does, there's a problem in evalLoc */
+            LOG(FATAL) << "Long half-temp, half-promoted";
         }
 
-        // Promote core regs
-        for (int i = 0; (coreRegs[i].count > 0) && i < numRegs; i++) {
-            if (cUnit->promotionMap[coreRegs[i].sReg].coreLocation !=
-                    kLocPhysReg) {
-                if (coreRegs[i].sReg >= cUnit->numRegs) {
-                    // don't promote arg regs
-                    continue;
-                }
-                int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg);
-                if (reg < 0) {
-                   break;  // No more left
-                }
-            }
-        }
-    }
-
-    // Now, update SSA names to new home locations
-    for (int i = 0; i < cUnit->numSSARegs; i++) {
-        RegLocation *curr = &cUnit->regLocation[i];
-        int baseVReg = oatS2VReg(cUnit, curr->sRegLow);
-        if (!curr->wide) {
-            if (curr->fp) {
-                if (cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) {
-                    curr->location = kLocPhysReg;
-                    curr->lowReg = cUnit->promotionMap[baseVReg].fpReg;
-                    curr->home = true;
-                }
-            } else {
-                if (cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg) {
-                    curr->location = kLocPhysReg;
-                    curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
-                    curr->home = true;
-                }
-            }
-            curr->highReg = INVALID_REG;
-        } else {
-            if (curr->highWord) {
-                continue;
-            }
-            if (curr->fp) {
-                if ((cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) &&
-                    (cUnit->promotionMap[baseVReg+1].fpLocation ==
-                    kLocPhysReg)) {
-                    int lowReg = cUnit->promotionMap[baseVReg].fpReg;
-                    int highReg = cUnit->promotionMap[baseVReg+1].fpReg;
-                    // Doubles require pair of singles starting at even reg
-                    if (((lowReg & 0x1) == 0) && ((lowReg + 1) == highReg)) {
-                        curr->location = kLocPhysReg;
-                        curr->lowReg = lowReg;
-                        curr->highReg = highReg;
-                        curr->home = true;
-                    }
-                }
-            } else {
-                if ((cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg)
-                     && (cUnit->promotionMap[baseVReg+1].coreLocation ==
-                     kLocPhysReg)) {
-                    curr->location = kLocPhysReg;
-                    curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
-                    curr->highReg = cUnit->promotionMap[baseVReg+1].coreReg;
-                    curr->home = true;
-                }
-            }
-        }
+        info1->dirty = false;
+        info2->dirty = false;
+        if (oatS2VReg(cUnit, info2->sReg) <
+            oatS2VReg(cUnit, info1->sReg))
+            info1 = info2;
+        int vReg = oatS2VReg(cUnit, info1->sReg);
+        oatFlushRegWideImpl(cUnit, rSP,
+                                    oatVRegOffset(cUnit, vReg),
+                                    info1->reg, info1->partner);
     }
 }
 
-/* Returns sp-relative offset in bytes for a VReg */
-extern int oatVRegOffset(CompilationUnit* cUnit, int vReg)
+void oatFlushReg(CompilationUnit* cUnit, int reg)
 {
-    return (vReg < cUnit->numRegs) ? cUnit->regsOffset + (vReg << 2) :
-            cUnit->insOffset + ((vReg - cUnit->numRegs) << 2);
+    RegisterInfo* info = oatGetRegInfo(cUnit, reg);
+    if (info->live && info->dirty) {
+        info->dirty = false;
+        int vReg = oatS2VReg(cUnit, info->sReg);
+        oatFlushRegImpl(cUnit, rSP,
+                                oatVRegOffset(cUnit, vReg),
+                                reg, kWord);
+    }
 }
 
-/* Returns sp-relative offset in bytes for a SReg */
-extern int oatSRegOffset(CompilationUnit* cUnit, int sReg)
-{
-    return oatVRegOffset(cUnit, oatS2VReg(cUnit, sReg));
+/* Give access to the target-dependent FP register encoding to common code */
+bool oatIsFpReg(int reg) {
+    return FPREG(reg);
 }
 
-
-/* Return sp-relative offset in bytes using Method* */
-extern int oatVRegOffset(const DexFile::CodeItem* code_item,
-                         uint32_t core_spills, uint32_t fp_spills,
-                         size_t frame_size, int reg)
-{
-    int numIns = code_item->ins_size_;
-    int numRegs = code_item->registers_size_ - numIns;
-    int numOuts = code_item->outs_size_;
-    int numSpills = __builtin_popcount(core_spills) +
-                    __builtin_popcount(fp_spills);
-    int numPadding = (STACK_ALIGN_WORDS -
-        (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1);
-    int regsOffset = (numOuts + numPadding + 1) * 4;
-    int insOffset = frame_size + 4;
-    return (reg < numRegs) ? regsOffset + (reg << 2) :
-           insOffset + ((reg - numRegs) << 2);
+uint32_t oatFpRegMask() {
+    return FP_REG_MASK;
 }
 
 /* Clobber all regs that might be used by an external C call */
-extern void oatClobberCalleeSave(CompilationUnit *cUnit)
+void oatClobberCalleeSave(CompilationUnit *cUnit)
 {
     oatClobber(cUnit, r0);
     oatClobber(cUnit, r1);
@@ -340,4 +165,28 @@
                       : &cUnit->regPool->coreRegs[reg];
 }
 
+/* To be used when explicitly managing register use */
+extern void oatLockCallTemps(CompilationUnit* cUnit)
+{
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+    oatLockTemp(cUnit, r2);
+    oatLockTemp(cUnit, r3);
+}
+
+/* To be used when explicitly managing register use */
+extern void oatFreeCallTemps(CompilationUnit* cUnit)
+{
+    oatFreeTemp(cUnit, r0);
+    oatFreeTemp(cUnit, r1);
+    oatFreeTemp(cUnit, r2);
+    oatFreeTemp(cUnit, r3);
+}
+
+/* Convert an instruction to a NOP */
+STATIC void oatNopLIR( LIR* lir)
+{
+    ((ArmLIR*)lir)->flags.isNop = true;
+}
+
 }  // namespace art
diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc
index 2990631..0cd7605 100644
--- a/src/compiler/codegen/arm/Assemble.cc
+++ b/src/compiler/codegen/arm/Assemble.cc
@@ -22,8 +22,6 @@
 
 namespace art {
 
-#define MAX_ASSEMBLER_RETRIES 50
-
 /*
  * opcode: ArmOpcode enum
  * skeleton: pre-designated bit-pattern for this opcode
@@ -977,92 +975,13 @@
  */
 #define PADDING_MOV_R5_R5               0x1C2D
 
-STATIC void pushWord(std::vector<uint16_t>&buf, int data) {
-    buf.push_back( data & 0xffff);
-    buf.push_back( (data >> 16) & 0xffff);
-}
-
-void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
-    while (buf.size() < (offset/2))
-        buf.push_back(0);
-}
-
-/* Write the numbers in the constant to the output stream */
-STATIC void installLiteralPools(CompilationUnit* cUnit)
-{
-    alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
-    ArmLIR* dataLIR = (ArmLIR*) cUnit->literalList;
-    while (dataLIR) {
-        pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
-        dataLIR = NEXT_LIR(dataLIR);
-    }
-}
-
-/* Write the switch tables to the output stream */
-STATIC void installSwitchTables(CompilationUnit* cUnit)
-{
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
-    while (true) {
-        SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext(
-             &iterator);
-        if (tabRec == NULL) break;
-        alignBuffer(cUnit->codeBuffer, tabRec->offset);
-        int bxOffset = tabRec->bxInst->generic.offset + 4;
-        if (cUnit->printMe) {
-            LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset;
-        }
-        if (tabRec->table[0] == kSparseSwitchSignature) {
-            int* keys = (int*)&(tabRec->table[2]);
-            for (int elems = 0; elems < tabRec->table[1]; elems++) {
-                int disp = tabRec->targets[elems]->generic.offset - bxOffset;
-                if (cUnit->printMe) {
-                    LOG(INFO) << "    Case[" << elems << "] key: 0x" <<
-                        std::hex << keys[elems] << ", disp: 0x" <<
-                        std::hex << disp;
-                }
-                pushWord(cUnit->codeBuffer, keys[elems]);
-                pushWord(cUnit->codeBuffer,
-                    tabRec->targets[elems]->generic.offset - bxOffset);
-            }
-        } else {
-            DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
-            for (int elems = 0; elems < tabRec->table[1]; elems++) {
-                int disp = tabRec->targets[elems]->generic.offset - bxOffset;
-                if (cUnit->printMe) {
-                    LOG(INFO) << "    Case[" << elems << "] disp: 0x" <<
-                        std::hex << disp;
-                }
-                pushWord(cUnit->codeBuffer,
-                         tabRec->targets[elems]->generic.offset - bxOffset);
-            }
-        }
-    }
-}
-
-/* Write the fill array dta to the output stream */
-STATIC void installFillArrayData(CompilationUnit* cUnit)
-{
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
-    while (true) {
-        FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
-             &iterator);
-        if (tabRec == NULL) break;
-        alignBuffer(cUnit->codeBuffer, tabRec->offset);
-        for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) {
-            cUnit->codeBuffer.push_back( tabRec->table[i]);
-        }
-    }
-}
-
 /*
  * Assemble the LIR into binary instruction format.  Note that we may
  * discover that pc-relative displacements may not fit the selected
  * instruction.
  */
-STATIC AssemblerStatus assembleInstructions(CompilationUnit* cUnit,
-                                            intptr_t startAddr)
+AssemblerStatus oatAssembleInstructions(CompilationUnit* cUnit,
+                                        intptr_t startAddr)
 {
     ArmLIR* lir;
     AssemblerStatus res = kSuccess;  // Assume success
@@ -1461,80 +1380,12 @@
     return res;
 }
 
-STATIC int assignLiteralOffsetCommon(LIR* lir, int offset)
-{
-    for (;lir != NULL; lir = lir->next) {
-        lir->offset = offset;
-        offset += 4;
-    }
-    return offset;
-}
-
-STATIC void createMappingTable(CompilationUnit* cUnit)
-{
-    ArmLIR* armLIR;
-    int currentDalvikOffset = -1;
-
-    for (armLIR = (ArmLIR *) cUnit->firstLIRInsn;
-         armLIR;
-         armLIR = NEXT_LIR(armLIR)) {
-        if ((armLIR->opcode >= 0) && !armLIR->flags.isNop &&
-            (currentDalvikOffset != armLIR->generic.dalvikOffset)) {
-            // Changed - need to emit a record
-            cUnit->mappingTable.push_back(armLIR->generic.offset);
-            cUnit->mappingTable.push_back(armLIR->generic.dalvikOffset);
-            currentDalvikOffset = armLIR->generic.dalvikOffset;
-        }
-    }
-}
-
-/* Determine the offset of each literal field */
-STATIC int assignLiteralOffset(CompilationUnit* cUnit, int offset)
-{
-    offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
-    return offset;
-}
-
-STATIC int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset)
-{
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
-    while (true) {
-        SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
-             &iterator);
-        if (tabRec == NULL) break;
-        tabRec->offset = offset;
-        if (tabRec->table[0] == kSparseSwitchSignature) {
-            offset += tabRec->table[1] * (sizeof(int) * 2);
-        } else {
-            DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
-            offset += tabRec->table[1] * sizeof(int);
-        }
-    }
-    return offset;
-}
-
-STATIC int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset)
-{
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
-    while (true) {
-        FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
-             &iterator);
-        if (tabRec == NULL) break;
-        tabRec->offset = offset;
-        offset += tabRec->size;
-        // word align
-        offset = (offset + 3) & ~3;
-        }
-    return offset;
-}
-
 /*
- * Walk the compilation unit and assign offsets to instructions
- * and literals and compute the total size of the compiled unit.
+ * Target-dependent offset assignment.
+ * TODO: normalize usage of flags.size and make this target
+ * independent.
  */
-void assignOffsets(CompilationUnit* cUnit)
+int oatAssignInsnOffsets(CompilationUnit* cUnit)
 {
     ArmLIR* armLIR;
     int offset = 0;
@@ -1559,61 +1410,7 @@
         /* Pseudo opcodes don't consume space */
     }
 
-    /* Const values have to be word aligned */
-    offset = (offset + 3) & ~3;
-
-    /* Set up offsets for literals */
-    cUnit->dataOffset = offset;
-
-    offset = assignLiteralOffset(cUnit, offset);
-
-    offset = assignSwitchTablesOffset(cUnit, offset);
-
-    offset = assignFillArrayDataOffset(cUnit, offset);
-
-    cUnit->totalSize = offset;
-}
-/*
- * Go over each instruction in the list and calculate the offset from the top
- * before sending them off to the assembler. If out-of-range branch distance is
- * seen rearrange the instructions a bit to correct it.
- */
-void oatAssembleLIR(CompilationUnit* cUnit)
-{
-    assignOffsets(cUnit);
-    /*
-     * Assemble here.  Note that we generate code with optimistic assumptions
-     * and if found now to work, we'll have to redo the sequence and retry.
-     */
-
-    while (true) {
-        AssemblerStatus res = assembleInstructions(cUnit, 0);
-        if (res == kSuccess) {
-            break;
-        } else {
-            cUnit->assemblerRetries++;
-            if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) {
-                LOG(FATAL) << "Assembler error - too many retries";
-            }
-            // Redo offsets and try again
-            assignOffsets(cUnit);
-            cUnit->codeBuffer.clear();
-        }
-    }
-
-    // Install literals
-    installLiteralPools(cUnit);
-
-    // Install switch tables
-    installSwitchTables(cUnit);
-
-    // Install fill array data
-    installFillArrayData(cUnit);
-
-    /*
-     * Create the mapping table
-     */
-    createMappingTable(cUnit);
+    return offset;
 }
 
 }  // namespace art
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
deleted file mode 100644
index 4efa27a..0000000
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ /dev/null
@@ -1,1978 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "object_utils.h"
-
-namespace art {
-
-#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
-    (1 << kDebugDisplayMissingTargets))
-
-STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, INVALID_REG,
-                                   INVALID_REG, INVALID_SREG};
-
-/* Mark register usage state and return long retloc */
-STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
-{
-    RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
-    oatLockTemp(cUnit, res.lowReg);
-    oatLockTemp(cUnit, res.highReg);
-    oatMarkPair(cUnit, res.lowReg, res.highReg);
-    return res;
-}
-
-STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
-{
-    RegLocation res = LOC_DALVIK_RETURN_VAL;
-    oatLockTemp(cUnit, res.lowReg);
-    return res;
-}
-
-/*
- * Let helper function take care of everything.  Will call
- * Array::AllocFromCode(type_idx, method, count);
- * Note: AllocFromCode will handle checks for errNegativeArraySize.
- */
-STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
-                        RegLocation rlSrc)
-{
-    oatFlushAllRegs(cUnit);    /* Everything to home location */
-    uint32_t type_idx = mir->dalvikInsn.vC;
-    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
-                                                    cUnit->dex_cache,
-                                                    *cUnit->dex_file,
-                                                    type_idx)) {
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
-    } else {
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), rLR);
-    }
-    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
-    loadConstant(cUnit, r0, type_idx);            // arg0 <- type_id
-    loadValueDirectFixed(cUnit, rlSrc, r2);       // arg2 <- count
-    callRuntimeHelper(cUnit, rLR);
-    RegLocation rlResult = oatGetReturn(cUnit);
-    storeValue(cUnit, rlDest, rlResult);
-}
-
-/*
- * Similar to genNewArray, but with post-allocation initialization.
- * Verifier guarantees we're dealing with an array class.  Current
- * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
- * Current code also throws internal unimp if not 'L', '[' or 'I'.
- */
-STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
-{
-    DecodedInstruction* dInsn = &mir->dalvikInsn;
-    int elems = dInsn->vA;
-    int typeId = dInsn->vB;
-    oatFlushAllRegs(cUnit);    /* Everything to home location */
-    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
-                                                    cUnit->dex_cache,
-                                                    *cUnit->dex_file,
-                                                    typeId)) {
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
-    } else {
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCodeWithAccessCheck), rLR);
-    }
-    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
-    loadConstant(cUnit, r0, typeId);              // arg0 <- type_id
-    loadConstant(cUnit, r2, elems);               // arg2 <- count
-    callRuntimeHelper(cUnit, rLR);
-    /*
-     * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
-     * return region.  Because AllocFromCode placed the new array
-     * in r0, we'll just lock it into place.  When debugger support is
-     * added, it may be necessary to additionally copy all return
-     * values to a home location in thread-local storage
-     */
-    oatLockTemp(cUnit, r0);
-
-    // Having a range of 0 is legal
-    if (isRange && (dInsn->vA > 0)) {
-        /*
-         * Bit of ugliness here.  We're going generate a mem copy loop
-         * on the register range, but it is possible that some regs
-         * in the range have been promoted.  This is unlikely, but
-         * before generating the copy, we'll just force a flush
-         * of any regs in the source range that have been promoted to
-         * home location.
-         */
-        for (unsigned int i = 0; i < dInsn->vA; i++) {
-            RegLocation loc = oatUpdateLoc(cUnit,
-                oatGetSrc(cUnit, mir, i));
-            if (loc.location == kLocPhysReg) {
-                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
-                              loc.lowReg, kWord);
-            }
-        }
-        /*
-         * TUNING note: generated code here could be much improved, but
-         * this is an uncommon operation and isn't especially performance
-         * critical.
-         */
-        int rSrc = oatAllocTemp(cUnit);
-        int rDst = oatAllocTemp(cUnit);
-        int rIdx = oatAllocTemp(cUnit);
-        int rVal = rLR;  // Using a lot of temps, rLR is known free here
-        // Set up source pointer
-        RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
-        opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
-                    oatSRegOffset(cUnit, rlFirst.sRegLow));
-        // Set up the target pointer
-        opRegRegImm(cUnit, kOpAdd, rDst, r0,
-                    Array::DataOffset().Int32Value());
-        // Set up the loop counter (known to be > 0)
-        loadConstant(cUnit, rIdx, dInsn->vA - 1);
-        // Generate the copy loop.  Going backwards for convenience
-        ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
-        target->defMask = ENCODE_ALL;
-        // Copy next element
-        loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
-        storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
-        // Use setflags encoding here
-        newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
-        ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
-        branch->generic.target = (LIR*)target;
-    } else if (!isRange) {
-        // TUNING: interleave
-        for (unsigned int i = 0; i < dInsn->vA; i++) {
-            RegLocation rlArg = loadValue(cUnit,
-                oatGetSrc(cUnit, mir, i), kCoreReg);
-            storeBaseDisp(cUnit, r0,
-                          Array::DataOffset().Int32Value() +
-                          i * 4, rlArg.lowReg, kWord);
-            // If the loadValue caused a temp to be allocated, free it
-            if (oatIsTemp(cUnit, rlArg.lowReg)) {
-                oatFreeTemp(cUnit, rlArg.lowReg);
-            }
-        }
-    }
-}
-
-STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
-                    bool isLongOrDouble, bool isObject)
-{
-    int fieldOffset;
-    int ssbIndex;
-    bool isVolatile;
-    bool isReferrersClass;
-    uint32_t fieldIdx = mir->dalvikInsn.vB;
-    bool fastPath =
-        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
-                                                fieldOffset, ssbIndex,
-                                                isReferrersClass, isVolatile, true);
-    if (fastPath && !SLOW_FIELD_PATH) {
-        DCHECK_GE(fieldOffset, 0);
-        int rBase;
-        int rMethod;
-        if (isReferrersClass) {
-            // Fast path, static storage base is this method's class
-            rMethod  = loadCurrMethod(cUnit);
-            rBase = oatAllocTemp(cUnit);
-            loadWordDisp(cUnit, rMethod,
-                         Method::DeclaringClassOffset().Int32Value(), rBase);
-        } else {
-            // Medium path, static storage base in a different class which
-            // requires checks that the other class is initialized.
-            DCHECK_GE(ssbIndex, 0);
-            // May do runtime call so everything to home locations.
-            oatFlushAllRegs(cUnit);
-            // Using fixed register to sync with possible call to runtime
-            // support.
-            rMethod = r1;
-            oatLockTemp(cUnit, rMethod);
-            loadCurrMethodDirect(cUnit, rMethod);
-            rBase = r0;
-            oatLockTemp(cUnit, rBase);
-            loadWordDisp(cUnit, rMethod,
-                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
-                rBase);
-            loadWordDisp(cUnit, rBase,
-                         Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex,
-                         rBase);
-            // rBase now points at appropriate static storage base (Class*)
-            // or NULL if not initialized. Check for NULL and call helper if NULL.
-            // TUNING: fast path should fall through
-            ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
-            loadWordDisp(cUnit, rSELF,
-                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
-            loadConstant(cUnit, r0, ssbIndex);
-            callRuntimeHelper(cUnit, rLR);
-            ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
-            skipTarget->defMask = ENCODE_ALL;
-            branchOver->generic.target = (LIR*)skipTarget;
-        }
-        // rBase now holds static storage base
-        oatFreeTemp(cUnit, rMethod);
-        if (isLongOrDouble) {
-            rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
-            rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
-        } else {
-            rlSrc = oatGetSrc(cUnit, mir, 0);
-            rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
-        }
-        if (isVolatile) {
-            oatGenMemBarrier(cUnit, kST);
-        }
-        if (isLongOrDouble) {
-            storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
-                              rlSrc.highReg);
-        } else {
-            storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
-        }
-        if (isVolatile) {
-            oatGenMemBarrier(cUnit, kSY);
-        }
-        if (isObject) {
-            markGCCard(cUnit, rlSrc.lowReg, rBase);
-        }
-        oatFreeTemp(cUnit, rBase);
-    } else {
-        oatFlushAllRegs(cUnit);  // Everything to home locations
-        int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
-                           (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
-                                     : OFFSETOF_MEMBER(Thread, pSet32Static));
-        loadWordDisp(cUnit, rSELF, setterOffset, rLR);
-        loadConstant(cUnit, r0, fieldIdx);
-        if (isLongOrDouble) {
-            loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
-        } else {
-            loadValueDirect(cUnit, rlSrc, r1);
-        }
-        callRuntimeHelper(cUnit, rLR);
-    }
-}
-
-STATIC void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
-                    bool isLongOrDouble, bool isObject)
-{
-    int fieldOffset;
-    int ssbIndex;
-    bool isVolatile;
-    bool isReferrersClass;
-    uint32_t fieldIdx = mir->dalvikInsn.vB;
-    bool fastPath =
-        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
-                                                fieldOffset, ssbIndex,
-                                                isReferrersClass, isVolatile, false);
-    if (fastPath && !SLOW_FIELD_PATH) {
-        DCHECK_GE(fieldOffset, 0);
-        int rBase;
-        int rMethod;
-        if (isReferrersClass) {
-            // Fast path, static storage base is this method's class
-            rMethod  = loadCurrMethod(cUnit);
-            rBase = oatAllocTemp(cUnit);
-            loadWordDisp(cUnit, rMethod,
-                         Method::DeclaringClassOffset().Int32Value(), rBase);
-        } else {
-            // Medium path, static storage base in a different class which
-            // requires checks that the other class is initialized
-            DCHECK_GE(ssbIndex, 0);
-            // May do runtime call so everything to home locations.
-            oatFlushAllRegs(cUnit);
-            // Using fixed register to sync with possible call to runtime
-            // support
-            rMethod = r1;
-            oatLockTemp(cUnit, rMethod);
-            loadCurrMethodDirect(cUnit, rMethod);
-            rBase = r0;
-            oatLockTemp(cUnit, rBase);
-            loadWordDisp(cUnit, rMethod,
-                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
-                rBase);
-            loadWordDisp(cUnit, rBase,
-                         Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex,
-                         rBase);
-            // rBase now points at appropriate static storage base (Class*)
-            // or NULL if not initialized. Check for NULL and call helper if NULL.
-            // TUNING: fast path should fall through
-            ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
-            loadWordDisp(cUnit, rSELF,
-                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
-            loadConstant(cUnit, r0, ssbIndex);
-            callRuntimeHelper(cUnit, rLR);
-            ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
-            skipTarget->defMask = ENCODE_ALL;
-            branchOver->generic.target = (LIR*)skipTarget;
-        }
-        // rBase now holds static storage base
-        oatFreeTemp(cUnit, rMethod);
-        rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
-                                : oatGetDest(cUnit, mir, 0);
-        RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-        if (isVolatile) {
-            oatGenMemBarrier(cUnit, kSY);
-        }
-        if (isLongOrDouble) {
-            loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
-                             rlResult.highReg, INVALID_SREG);
-        } else {
-            loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
-        }
-        oatFreeTemp(cUnit, rBase);
-        if (isLongOrDouble) {
-            storeValueWide(cUnit, rlDest, rlResult);
-        } else {
-            storeValue(cUnit, rlDest, rlResult);
-        }
-    } else {
-        oatFlushAllRegs(cUnit);  // Everything to home locations
-        int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
-                           (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
-                                     : OFFSETOF_MEMBER(Thread, pGet32Static));
-        loadWordDisp(cUnit, rSELF, getterOffset, rLR);
-        loadConstant(cUnit, r0, fieldIdx);
-        callRuntimeHelper(cUnit, rLR);
-        if (isLongOrDouble) {
-            RegLocation rlResult = oatGetReturnWide(cUnit);
-            storeValueWide(cUnit, rlDest, rlResult);
-        } else {
-            RegLocation rlResult = oatGetReturn(cUnit);
-            storeValue(cUnit, rlDest, rlResult);
-        }
-    }
-}
-
-typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
-                            uint32_t methodIdx);
-
-/*
- * Bit of a hack here - in leiu of a real scheduling pass,
- * emit the next instruction in static & direct invoke sequences.
- */
-STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
-                          int state, uint32_t dexIdx, uint32_t unused)
-{
-    switch(state) {
-        case 0:  // Get the current Method* [sets r0]
-            loadCurrMethodDirect(cUnit, r0);
-            break;
-        case 1:  // Get method->code_and_direct_methods_
-            loadWordDisp(cUnit, r0,
-                Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
-                r0);
-            break;
-        case 2:  // Grab target method* and target code_
-            loadWordDisp(cUnit, r0,
-                CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR);
-            loadWordDisp(cUnit, r0,
-                CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0);
-            break;
-        default:
-            return -1;
-    }
-    return state + 1;
-}
-
-/*
- * Bit of a hack here - in leiu of a real scheduling pass,
- * emit the next instruction in a virtual invoke sequence.
- * We can use rLR as a temp prior to target address loading
- * Note also that we'll load the first argument ("this") into
- * r1 here rather than the standard loadArgRegs.
- */
-STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
-                         int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-    RegLocation rlArg;
-    /*
-     * This is the fast path in which the target virtual method is
-     * fully resolved at compile time.
-     */
-    switch(state) {
-        case 0:  // Get "this" [set r1]
-            rlArg = oatGetSrc(cUnit, mir, 0);
-            loadValueDirectFixed(cUnit, rlArg, r1);
-            break;
-        case 1: // Is "this" null? [use r1]
-            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
-            // get this->klass_ [use r1, set rLR]
-            loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
-            break;
-        case 2: // Get this->klass_->vtable [usr rLR, set rLR]
-            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
-            break;
-        case 3: // Get target method [use rLR, set r0]
-            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
-                         Array::DataOffset().Int32Value(), r0);
-            break;
-        case 4: // Get the target compiled code address [uses r0, sets rLR]
-            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
-            break;
-        default:
-            return -1;
-    }
-    return state + 1;
-}
-
-/*
- * Interleave launch code for INVOKE_SUPER.  See comments
- * for nextVCallIns.
- */
-STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
-                             int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-    /*
-     * This is the fast path in which the target virtual method is
-     * fully resolved at compile time.  Note also that this path assumes
-     * that the check to verify that the target method index falls
-     * within the size of the super's vtable has been done at compile-time.
-     */
-    RegLocation rlArg;
-    switch(state) {
-        case 0: // Get current Method* [set r0]
-            loadCurrMethodDirect(cUnit, r0);
-            // Load "this" [set r1]
-            rlArg = oatGetSrc(cUnit, mir, 0);
-            loadValueDirectFixed(cUnit, rlArg, r1);
-            // Get method->declaring_class_ [use r0, set rLR]
-            loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
-                         rLR);
-            // Is "this" null? [use r1]
-            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
-            break;
-        case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
-            loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
-                         rLR);
-            break;
-        case 2: // Get ...->super_class_->vtable [u/s rLR]
-            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
-            break;
-        case 3: // Get target method [use rLR, set r0]
-            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
-                         Array::DataOffset().Int32Value(), r0);
-            break;
-        case 4: // Get the target compiled code address [uses r0, sets rLR]
-            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
-            break;
-        default:
-            return -1;
-    }
-    return state + 1;
-}
-
-STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, int trampoline,
-                            int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-    /*
-     * This handles the case in which the base method is not fully
-     * resolved at compile time, we bail to a runtime helper.
-     */
-    if (state == 0) {
-        // Load trampoline target
-        loadWordDisp(cUnit, rSELF, trampoline, rLR);
-        // Load r0 with method index
-        loadConstant(cUnit, r0, dexIdx);
-        return 1;
-    }
-    return -1;
-}
-
-STATIC int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
-                                int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir,
-                                int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
-                               int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
-                           int state, uint32_t dexIdx, uint32_t methodIdx)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-/*
- * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
- * which will locate the target and continue on via a tail call.
- */
-STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
-                                 int state, uint32_t dexIdx, uint32_t unused)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
-                                                MIR* mir, int state,
-                                                uint32_t dexIdx,
-                                                uint32_t unused)
-{
-  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
-  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
-}
-
-STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
-                          DecodedInstruction* dInsn, int callState,
-                          NextCallInsn nextCallInsn, uint32_t dexIdx,
-                          uint32_t methodIdx, bool skipThis)
-{
-    int nextReg = r1;
-    int nextArg = 0;
-    if (skipThis) {
-        nextReg++;
-        nextArg++;
-    }
-    for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
-        RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
-        rlArg = oatUpdateRawLoc(cUnit, rlArg);
-        if (rlArg.wide && (nextReg <= r2)) {
-            loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
-            nextReg++;
-            nextArg++;
-        } else {
-            rlArg.wide = false;
-            loadValueDirectFixed(cUnit, rlArg, nextReg);
-        }
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-    }
-    return callState;
-}
-
-/*
- * Load up to 5 arguments, the first three of which will be in
- * r1 .. r3.  On entry r0 contains the current method pointer,
- * and as part of the load sequence, it must be replaced with
- * the target method pointer.  Note, this may also be called
- * for "range" variants if the number of arguments is 5 or fewer.
- */
-STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
-                                DecodedInstruction* dInsn, int callState,
-                                ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
-                                uint32_t dexIdx, uint32_t methodIdx,
-                                bool skipThis)
-{
-    RegLocation rlArg;
-
-    /* If no arguments, just return */
-    if (dInsn->vA == 0)
-        return callState;
-
-    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-
-    DCHECK_LE(dInsn->vA, 5U);
-    if (dInsn->vA > 3) {
-        uint32_t nextUse = 3;
-        //Detect special case of wide arg spanning arg3/arg4
-        RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
-        RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
-        RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
-        if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
-            rlUse2.wide) {
-            int reg;
-            // Wide spans, we need the 2nd half of uses[2].
-            rlArg = oatUpdateLocWide(cUnit, rlUse2);
-            if (rlArg.location == kLocPhysReg) {
-                reg = rlArg.highReg;
-            } else {
-                // r2 & r3 can safely be used here
-                reg = r3;
-                loadWordDisp(cUnit, rSP,
-                             oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
-                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
-                                         methodIdx);
-            }
-            storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
-            storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
-            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-            nextUse++;
-        }
-        // Loop through the rest
-        while (nextUse < dInsn->vA) {
-            int lowReg;
-            int highReg;
-            rlArg = oatGetRawSrc(cUnit, mir, nextUse);
-            rlArg = oatUpdateRawLoc(cUnit, rlArg);
-            if (rlArg.location == kLocPhysReg) {
-                lowReg = rlArg.lowReg;
-                highReg = rlArg.highReg;
-            } else {
-                lowReg = r2;
-                highReg = r3;
-                if (rlArg.wide) {
-                    loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
-                } else {
-                    loadValueDirectFixed(cUnit, rlArg, lowReg);
-                }
-                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
-                                         methodIdx);
-            }
-            int outsOffset = (nextUse + 1) * 4;
-            if (rlArg.wide) {
-                storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
-                nextUse += 2;
-            } else {
-                storeWordDisp(cUnit, rSP, outsOffset, lowReg);
-                nextUse++;
-            }
-            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-        }
-    }
-
-    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
-                            dexIdx, methodIdx, skipThis);
-
-    if (pcrLabel) {
-        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
-    }
-    return callState;
-}
-
-/*
- * May have 0+ arguments (also used for jumbo).  Note that
- * source virtual registers may be in physical registers, so may
- * need to be flushed to home location before copying.  This
- * applies to arg3 and above (see below).
- *
- * Two general strategies:
- *    If < 20 arguments
- *       Pass args 3-18 using vldm/vstm block copy
- *       Pass arg0, arg1 & arg2 in r1-r3
- *    If 20+ arguments
- *       Pass args arg19+ using memcpy block copy
- *       Pass arg0, arg1 & arg2 in r1-r3
- *
- */
-STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
-                              DecodedInstruction* dInsn, int callState,
-                              ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
-                              uint32_t dexIdx, uint32_t methodIdx,
-                              bool skipThis)
-{
-    int firstArg = dInsn->vC;
-    int numArgs = dInsn->vA;
-
-    // If we can treat it as non-range (Jumbo ops will use range form)
-    if (numArgs <= 5)
-        return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
-                                    nextCallInsn, dexIdx, methodIdx,
-                                    skipThis);
-    /*
-     * Make sure range list doesn't span the break between in normal
-     * Dalvik vRegs and the ins.
-     */
-    int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
-    int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
-    if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
-        LOG(FATAL) << "Argument list spanned locals & args";
-    }
-
-    /*
-     * First load the non-register arguments.  Both forms expect all
-     * of the source arguments to be in their home frame location, so
-     * scan the sReg names and flush any that have been promoted to
-     * frame backing storage.
-     */
-    // Scan the rest of the args - if in physReg flush to memory
-    for (int nextArg = 0; nextArg < numArgs;) {
-        RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
-        if (loc.wide) {
-            loc = oatUpdateLocWide(cUnit, loc);
-            if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
-                storeBaseDispWide(cUnit, rSP,
-                                  oatSRegOffset(cUnit, loc.sRegLow),
-                                  loc.lowReg, loc.highReg);
-            }
-            nextArg += 2;
-        } else {
-            loc = oatUpdateLoc(cUnit, loc);
-            if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
-                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
-                              loc.lowReg, kWord);
-            }
-            nextArg++;
-        }
-    }
-
-    int startOffset = oatSRegOffset(cUnit,
-        cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
-    int outsOffset = 4 /* Method* */ + (3 * 4);
-    if (numArgs >= 20) {
-        // Generate memcpy
-        opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
-        opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
-        loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
-        loadConstant(cUnit, r2, (numArgs - 3) * 4);
-        callRuntimeHelper(cUnit, rLR);
-        // Restore Method*
-        loadCurrMethodDirect(cUnit, r0);
-    } else {
-        // Use vldm/vstm pair using r3 as a temp
-        int regsLeft = std::min(numArgs - 3, 16);
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-        opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
-        ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
-        //TUNING: loosen barrier
-        ld->defMask = ENCODE_ALL;
-        setMemRefType(ld, true /* isLoad */, kDalvikReg);
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-        opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-        ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
-        setMemRefType(st, false /* isLoad */, kDalvikReg);
-        st->defMask = ENCODE_ALL;
-        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-    }
-
-    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
-                            dexIdx, methodIdx, skipThis);
-
-    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
-    if (pcrLabel) {
-        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
-    }
-    return callState;
-}
-
-// Debugging routine - if null target, branch to DebugMe
-STATIC void genShowTarget(CompilationUnit* cUnit)
-{
-    ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
-    loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
-    ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
-    target->defMask = -1;
-    branchOver->generic.target = (LIR*)target;
-}
-
-STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir,
-                      InvokeType type, bool isRange)
-{
-    DecodedInstruction* dInsn = &mir->dalvikInsn;
-    int callState = 0;
-    ArmLIR* nullCk;
-    ArmLIR** pNullCk = NULL;
-    NextCallInsn nextCallInsn;
-    oatFlushAllRegs(cUnit);    /* Everything to home location */
-    // Explicit register usage
-    oatLockCallTemps(cUnit);
-
-    uint32_t dexMethodIdx = dInsn->vB;
-    int vtableIdx;
-    bool skipThis;
-    bool fastPath =
-        cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit, type,
-                                           vtableIdx)
-        && !SLOW_INVOKE_PATH;
-    if (type == kInterface) {
-      nextCallInsn = fastPath ? nextInterfaceCallInsn
-                              : nextInterfaceCallInsnWithAccessCheck;
-      skipThis = false;
-    } else if (type == kDirect) {
-      if (fastPath) {
-        pNullCk = &nullCk;
-      }
-      nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP;
-      skipThis = false;
-    } else if (type == kStatic) {
-      nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP;
-      skipThis = false;
-    } else if (type == kSuper) {
-      nextCallInsn = fastPath ? nextSuperCallInsn : nextSuperCallInsnSP;
-      skipThis = fastPath;
-    } else {
-      DCHECK_EQ(type, kVirtual);
-      nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
-      skipThis = fastPath;
-    }
-    if (!isRange) {
-        callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
-                                         nextCallInsn, dexMethodIdx,
-                                         vtableIdx, skipThis);
-    } else {
-        callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
-                                       nextCallInsn, dexMethodIdx, vtableIdx,
-                                       skipThis);
-    }
-    // Finish up any of the call sequence not interleaved in arg loading
-    while (callState >= 0) {
-        callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx,
-                                 vtableIdx);
-    }
-    if (DISPLAY_MISSING_TARGETS) {
-        genShowTarget(cUnit);
-    }
-    opReg(cUnit, kOpBlx, rLR);
-    oatClobberCalleeSave(cUnit);
-}
-
-STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
-                                     BasicBlock* bb, ArmLIR* labelList)
-{
-    bool res = false;   // Assume success
-    RegLocation rlSrc[3];
-    RegLocation rlDest = badLoc;
-    RegLocation rlResult = badLoc;
-    Opcode opcode = mir->dalvikInsn.opcode;
-
-    /* Prep Src and Dest locations */
-    int nextSreg = 0;
-    int nextLoc = 0;
-    int attrs = oatDataFlowAttributes[opcode];
-    rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
-    if (attrs & DF_UA) {
-        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
-        nextSreg++;
-    } else if (attrs & DF_UA_WIDE) {
-        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
-                                                 nextSreg + 1);
-        nextSreg+= 2;
-    }
-    if (attrs & DF_UB) {
-        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
-        nextSreg++;
-    } else if (attrs & DF_UB_WIDE) {
-        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
-                                                 nextSreg + 1);
-        nextSreg+= 2;
-    }
-    if (attrs & DF_UC) {
-        rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
-    } else if (attrs & DF_UC_WIDE) {
-        rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
-                                                 nextSreg + 1);
-    }
-    if (attrs & DF_DA) {
-        rlDest = oatGetDest(cUnit, mir, 0);
-    } else if (attrs & DF_DA_WIDE) {
-        rlDest = oatGetDestWide(cUnit, mir, 0, 1);
-    }
-
-    switch(opcode) {
-        case OP_NOP:
-            break;
-
-        case OP_MOVE_EXCEPTION:
-            int exOffset;
-            int resetReg;
-            exOffset = Thread::ExceptionOffset().Int32Value();
-            resetReg = oatAllocTemp(cUnit);
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
-            loadConstant(cUnit, resetReg, 0);
-            storeWordDisp(cUnit, rSELF, exOffset, resetReg);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_RETURN_VOID:
-            genSuspendTest(cUnit, mir);
-            break;
-
-        case OP_RETURN:
-        case OP_RETURN_OBJECT:
-            genSuspendTest(cUnit, mir);
-            storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
-            break;
-
-        case OP_RETURN_WIDE:
-            genSuspendTest(cUnit, mir);
-            storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
-            break;
-
-        case OP_MOVE_RESULT_WIDE:
-            if (mir->optimizationFlags & MIR_INLINED)
-                break;  // Nop - combined w/ previous invoke
-            storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
-            break;
-
-        case OP_MOVE_RESULT:
-        case OP_MOVE_RESULT_OBJECT:
-            if (mir->optimizationFlags & MIR_INLINED)
-                break;  // Nop - combined w/ previous invoke
-            storeValue(cUnit, rlDest, getRetLoc(cUnit));
-            break;
-
-        case OP_MOVE:
-        case OP_MOVE_OBJECT:
-        case OP_MOVE_16:
-        case OP_MOVE_OBJECT_16:
-        case OP_MOVE_FROM16:
-        case OP_MOVE_OBJECT_FROM16:
-            storeValue(cUnit, rlDest, rlSrc[0]);
-            break;
-
-        case OP_MOVE_WIDE:
-        case OP_MOVE_WIDE_16:
-        case OP_MOVE_WIDE_FROM16:
-            storeValueWide(cUnit, rlDest, rlSrc[0]);
-            break;
-
-        case OP_CONST:
-        case OP_CONST_4:
-        case OP_CONST_16:
-            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-            loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_CONST_HIGH16:
-            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-            loadConstantNoClobber(cUnit, rlResult.lowReg,
-                                  mir->dalvikInsn.vB << 16);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_CONST_WIDE_16:
-        case OP_CONST_WIDE_32:
-            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
-                                  mir->dalvikInsn.vB,
-                                  (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
-            storeValueWide(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_CONST_WIDE:
-            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
-                          mir->dalvikInsn.vB_wide & 0xffffffff,
-                          (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
-            storeValueWide(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_CONST_WIDE_HIGH16:
-            rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
-                                  0, mir->dalvikInsn.vB << 16);
-            storeValueWide(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_MONITOR_ENTER:
-            genMonitorEnter(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_MONITOR_EXIT:
-            genMonitorExit(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_CHECK_CAST:
-            genCheckCast(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_INSTANCE_OF:
-            genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
-            break;
-
-        case OP_NEW_INSTANCE:
-            genNewInstance(cUnit, mir, rlDest);
-            break;
-
-        case OP_THROW:
-            genThrow(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_THROW_VERIFICATION_ERROR:
-            loadWordDisp(cUnit, rSELF,
-                OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
-            loadConstant(cUnit, r0, mir->dalvikInsn.vA);
-            loadConstant(cUnit, r1, mir->dalvikInsn.vB);
-            callRuntimeHelper(cUnit, rLR);
-            break;
-
-        case OP_ARRAY_LENGTH:
-            int lenOffset;
-            lenOffset = Array::LengthOffset().Int32Value();
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
-                         rlResult.lowReg);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_CONST_STRING:
-        case OP_CONST_STRING_JUMBO:
-            genConstString(cUnit, mir, rlDest, rlSrc[0]);
-            break;
-
-        case OP_CONST_CLASS:
-            genConstClass(cUnit, mir, rlDest, rlSrc[0]);
-            break;
-
-        case OP_FILL_ARRAY_DATA:
-            genFillArrayData(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_FILLED_NEW_ARRAY:
-            genFilledNewArray(cUnit, mir, false /* not range */);
-            break;
-
-        case OP_FILLED_NEW_ARRAY_RANGE:
-            genFilledNewArray(cUnit, mir, true /* range */);
-            break;
-
-        case OP_NEW_ARRAY:
-            genNewArray(cUnit, mir, rlDest, rlSrc[0]);
-            break;
-
-        case OP_GOTO:
-        case OP_GOTO_16:
-        case OP_GOTO_32:
-            if (bb->taken->startOffset <= mir->offset) {
-                genSuspendTest(cUnit, mir);
-            }
-            genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
-            break;
-
-        case OP_PACKED_SWITCH:
-            genPackedSwitch(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_SPARSE_SWITCH:
-            genSparseSwitch(cUnit, mir, rlSrc[0]);
-            break;
-
-        case OP_CMPL_FLOAT:
-        case OP_CMPG_FLOAT:
-        case OP_CMPL_DOUBLE:
-        case OP_CMPG_DOUBLE:
-            res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_CMP_LONG:
-            genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_IF_EQ:
-        case OP_IF_NE:
-        case OP_IF_LT:
-        case OP_IF_GE:
-        case OP_IF_GT:
-        case OP_IF_LE: {
-            bool backwardBranch;
-            ArmConditionCode cond;
-            backwardBranch = (bb->taken->startOffset <= mir->offset);
-            if (backwardBranch) {
-                genSuspendTest(cUnit, mir);
-            }
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
-            opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
-            switch(opcode) {
-                case OP_IF_EQ:
-                    cond = kArmCondEq;
-                    break;
-                case OP_IF_NE:
-                    cond = kArmCondNe;
-                    break;
-                case OP_IF_LT:
-                    cond = kArmCondLt;
-                    break;
-                case OP_IF_GE:
-                    cond = kArmCondGe;
-                    break;
-                case OP_IF_GT:
-                    cond = kArmCondGt;
-                    break;
-                case OP_IF_LE:
-                    cond = kArmCondLe;
-                    break;
-                default:
-                    cond = (ArmConditionCode)0;
-                    LOG(FATAL) << "Unexpected opcode " << (int)opcode;
-            }
-            genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
-            genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
-            break;
-            }
-
-        case OP_IF_EQZ:
-        case OP_IF_NEZ:
-        case OP_IF_LTZ:
-        case OP_IF_GEZ:
-        case OP_IF_GTZ:
-        case OP_IF_LEZ: {
-            bool backwardBranch;
-            ArmConditionCode cond;
-            backwardBranch = (bb->taken->startOffset <= mir->offset);
-            if (backwardBranch) {
-                genSuspendTest(cUnit, mir);
-            }
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
-            switch(opcode) {
-                case OP_IF_EQZ:
-                    cond = kArmCondEq;
-                    break;
-                case OP_IF_NEZ:
-                    cond = kArmCondNe;
-                    break;
-                case OP_IF_LTZ:
-                    cond = kArmCondLt;
-                    break;
-                case OP_IF_GEZ:
-                    cond = kArmCondGe;
-                    break;
-                case OP_IF_GTZ:
-                    cond = kArmCondGt;
-                    break;
-                case OP_IF_LEZ:
-                    cond = kArmCondLe;
-                    break;
-                default:
-                    cond = (ArmConditionCode)0;
-                    LOG(FATAL) << "Unexpected opcode " << (int)opcode;
-            }
-            genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
-            genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
-            break;
-            }
-
-      case OP_AGET_WIDE:
-            genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
-            break;
-        case OP_AGET:
-        case OP_AGET_OBJECT:
-            genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
-            break;
-        case OP_AGET_BOOLEAN:
-            genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
-                        rlDest, 0);
-            break;
-        case OP_AGET_BYTE:
-            genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
-            break;
-        case OP_AGET_CHAR:
-            genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
-                        rlDest, 1);
-            break;
-        case OP_AGET_SHORT:
-            genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
-            break;
-        case OP_APUT_WIDE:
-            genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
-            break;
-        case OP_APUT:
-            genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
-            break;
-        case OP_APUT_OBJECT:
-            genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
-            break;
-        case OP_APUT_SHORT:
-        case OP_APUT_CHAR:
-            genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
-                        rlSrc[0], 1);
-            break;
-        case OP_APUT_BYTE:
-        case OP_APUT_BOOLEAN:
-            genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
-                        rlSrc[0], 0);
-            break;
-
-        case OP_IGET_OBJECT:
-        case OP_IGET_OBJECT_VOLATILE:
-            genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, true);
-            break;
-
-        case OP_IGET_WIDE:
-        case OP_IGET_WIDE_VOLATILE:
-            genIGet(cUnit, mir, kLong, rlDest, rlSrc[0], true, false);
-            break;
-
-        case OP_IGET:
-        case OP_IGET_VOLATILE:
-            genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, false);
-            break;
-
-        case OP_IGET_CHAR:
-            genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0], false, false);
-            break;
-
-        case OP_IGET_SHORT:
-            genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0], false, false);
-            break;
-
-        case OP_IGET_BOOLEAN:
-        case OP_IGET_BYTE:
-            genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0], false, false);
-            break;
-
-        case OP_IPUT_WIDE:
-        case OP_IPUT_WIDE_VOLATILE:
-            genIPut(cUnit, mir, kLong, rlSrc[0], rlSrc[1], true, false);
-            break;
-
-        case OP_IPUT_OBJECT:
-        case OP_IPUT_OBJECT_VOLATILE:
-            genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, true);
-            break;
-
-        case OP_IPUT:
-        case OP_IPUT_VOLATILE:
-            genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, false);
-            break;
-
-        case OP_IPUT_BOOLEAN:
-        case OP_IPUT_BYTE:
-            genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false, false);
-            break;
-
-        case OP_IPUT_CHAR:
-            genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false, false);
-            break;
-
-        case OP_IPUT_SHORT:
-            genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false, false);
-            break;
-
-        case OP_SGET_OBJECT:
-          genSget(cUnit, mir, rlDest, false, true);
-          break;
-        case OP_SGET:
-        case OP_SGET_BOOLEAN:
-        case OP_SGET_BYTE:
-        case OP_SGET_CHAR:
-        case OP_SGET_SHORT:
-            genSget(cUnit, mir, rlDest, false, false);
-            break;
-
-        case OP_SGET_WIDE:
-            genSget(cUnit, mir, rlDest, true, false);
-            break;
-
-        case OP_SPUT_OBJECT:
-          genSput(cUnit, mir, rlSrc[0], false, true);
-          break;
-
-        case OP_SPUT:
-        case OP_SPUT_BOOLEAN:
-        case OP_SPUT_BYTE:
-        case OP_SPUT_CHAR:
-        case OP_SPUT_SHORT:
-            genSput(cUnit, mir, rlSrc[0], false, false);
-            break;
-
-        case OP_SPUT_WIDE:
-            genSput(cUnit, mir, rlSrc[0], true, false);
-            break;
-
-        case OP_INVOKE_STATIC_RANGE:
-            genInvoke(cUnit, mir, kStatic, true /*range*/);
-            break;
-        case OP_INVOKE_STATIC:
-            genInvoke(cUnit, mir, kStatic, false /*range*/);
-            break;
-
-        case OP_INVOKE_DIRECT:
-            genInvoke(cUnit, mir, kDirect, false /*range*/);
-            break;
-        case OP_INVOKE_DIRECT_RANGE:
-            genInvoke(cUnit, mir, kDirect, true /*range*/);
-            break;
-
-        case OP_INVOKE_VIRTUAL:
-            genInvoke(cUnit, mir, kVirtual, false /*range*/);
-            break;
-        case OP_INVOKE_VIRTUAL_RANGE:
-            genInvoke(cUnit, mir, kVirtual, true /*range*/);
-            break;
-
-        case OP_INVOKE_SUPER:
-            genInvoke(cUnit, mir, kSuper, false /*range*/);
-            break;
-        case OP_INVOKE_SUPER_RANGE:
-            genInvoke(cUnit, mir, kSuper, true /*range*/);
-            break;
-
-        case OP_INVOKE_INTERFACE:
-            genInvoke(cUnit, mir, kInterface, false /*range*/);
-            break;
-        case OP_INVOKE_INTERFACE_RANGE:
-            genInvoke(cUnit, mir, kInterface, true /*range*/);
-            break;
-
-        case OP_NEG_INT:
-        case OP_NOT_INT:
-            res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
-            break;
-
-        case OP_NEG_LONG:
-        case OP_NOT_LONG:
-            res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
-            break;
-
-        case OP_NEG_FLOAT:
-            res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
-            break;
-
-        case OP_NEG_DOUBLE:
-            res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
-            break;
-
-        case OP_INT_TO_LONG:
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            if (rlSrc[0].location == kLocPhysReg) {
-                genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
-            } else {
-                loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
-            }
-            opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
-                        rlResult.lowReg, 31);
-            storeValueWide(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_LONG_TO_INT:
-            rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
-            rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
-            storeValue(cUnit, rlDest, rlSrc[0]);
-            break;
-
-        case OP_INT_TO_BYTE:
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_INT_TO_SHORT:
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_INT_TO_CHAR:
-            rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
-            rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
-            storeValue(cUnit, rlDest, rlResult);
-            break;
-
-        case OP_INT_TO_FLOAT:
-        case OP_INT_TO_DOUBLE:
-        case OP_LONG_TO_FLOAT:
-        case OP_LONG_TO_DOUBLE:
-        case OP_FLOAT_TO_INT:
-        case OP_FLOAT_TO_LONG:
-        case OP_FLOAT_TO_DOUBLE:
-        case OP_DOUBLE_TO_INT:
-        case OP_DOUBLE_TO_LONG:
-        case OP_DOUBLE_TO_FLOAT:
-            genConversion(cUnit, mir);
-            break;
-
-        case OP_ADD_INT:
-        case OP_SUB_INT:
-        case OP_MUL_INT:
-        case OP_DIV_INT:
-        case OP_REM_INT:
-        case OP_AND_INT:
-        case OP_OR_INT:
-        case OP_XOR_INT:
-        case OP_SHL_INT:
-        case OP_SHR_INT:
-        case OP_USHR_INT:
-        case OP_ADD_INT_2ADDR:
-        case OP_SUB_INT_2ADDR:
-        case OP_MUL_INT_2ADDR:
-        case OP_DIV_INT_2ADDR:
-        case OP_REM_INT_2ADDR:
-        case OP_AND_INT_2ADDR:
-        case OP_OR_INT_2ADDR:
-        case OP_XOR_INT_2ADDR:
-        case OP_SHL_INT_2ADDR:
-        case OP_SHR_INT_2ADDR:
-        case OP_USHR_INT_2ADDR:
-            genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_ADD_LONG:
-        case OP_SUB_LONG:
-        case OP_MUL_LONG:
-        case OP_DIV_LONG:
-        case OP_REM_LONG:
-        case OP_AND_LONG:
-        case OP_OR_LONG:
-        case OP_XOR_LONG:
-        case OP_ADD_LONG_2ADDR:
-        case OP_SUB_LONG_2ADDR:
-        case OP_MUL_LONG_2ADDR:
-        case OP_DIV_LONG_2ADDR:
-        case OP_REM_LONG_2ADDR:
-        case OP_AND_LONG_2ADDR:
-        case OP_OR_LONG_2ADDR:
-        case OP_XOR_LONG_2ADDR:
-            genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_SHL_LONG:
-        case OP_SHR_LONG:
-        case OP_USHR_LONG:
-        case OP_SHL_LONG_2ADDR:
-        case OP_SHR_LONG_2ADDR:
-        case OP_USHR_LONG_2ADDR:
-            genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_ADD_FLOAT:
-        case OP_SUB_FLOAT:
-        case OP_MUL_FLOAT:
-        case OP_DIV_FLOAT:
-        case OP_REM_FLOAT:
-        case OP_ADD_FLOAT_2ADDR:
-        case OP_SUB_FLOAT_2ADDR:
-        case OP_MUL_FLOAT_2ADDR:
-        case OP_DIV_FLOAT_2ADDR:
-        case OP_REM_FLOAT_2ADDR:
-            genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_ADD_DOUBLE:
-        case OP_SUB_DOUBLE:
-        case OP_MUL_DOUBLE:
-        case OP_DIV_DOUBLE:
-        case OP_REM_DOUBLE:
-        case OP_ADD_DOUBLE_2ADDR:
-        case OP_SUB_DOUBLE_2ADDR:
-        case OP_MUL_DOUBLE_2ADDR:
-        case OP_DIV_DOUBLE_2ADDR:
-        case OP_REM_DOUBLE_2ADDR:
-            genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
-            break;
-
-        case OP_RSUB_INT:
-        case OP_ADD_INT_LIT16:
-        case OP_MUL_INT_LIT16:
-        case OP_DIV_INT_LIT16:
-        case OP_REM_INT_LIT16:
-        case OP_AND_INT_LIT16:
-        case OP_OR_INT_LIT16:
-        case OP_XOR_INT_LIT16:
-        case OP_ADD_INT_LIT8:
-        case OP_RSUB_INT_LIT8:
-        case OP_MUL_INT_LIT8:
-        case OP_DIV_INT_LIT8:
-        case OP_REM_INT_LIT8:
-        case OP_AND_INT_LIT8:
-        case OP_OR_INT_LIT8:
-        case OP_XOR_INT_LIT8:
-        case OP_SHL_INT_LIT8:
-        case OP_SHR_INT_LIT8:
-        case OP_USHR_INT_LIT8:
-            genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
-            break;
-
-        default:
-            res = true;
-    }
-    return res;
-}
-
-STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
-    "kMirOpPhi",
-    "kMirOpNullNRangeUpCheck",
-    "kMirOpNullNRangeDownCheck",
-    "kMirOpLowerBound",
-    "kMirOpPunt",
-    "kMirOpCheckInlinePrediction",
-};
-
-/* Extended MIR instructions like PHI */
-STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
-{
-    int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
-    char* msg = NULL;
-    if (cUnit->printMe) {
-        msg = (char*)oatNew(cUnit, strlen(extendedMIROpNames[opOffset]) + 1,
-                            false, kAllocDebugInfo);
-        strcpy(msg, extendedMIROpNames[opOffset]);
-    }
-    ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
-
-    switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
-        case kMirOpPhi: {
-            char* ssaString = NULL;
-            if (cUnit->printMe) {
-                ssaString = oatGetSSAString(cUnit, mir->ssaRep);
-            }
-            op->flags.isNop = true;
-            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
-            break;
-        }
-        default:
-            break;
-    }
-}
-
-/*
- * If there are any ins passed in registers that have not been promoted
- * to a callee-save register, flush them to the frame.  Perform intial
- * assignment of promoted arguments.
- */
-STATIC void flushIns(CompilationUnit* cUnit)
-{
-    if (cUnit->numIns == 0)
-        return;
-    int firstArgReg = r1;
-    int lastArgReg = r3;
-    int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
-    /*
-     * Arguments passed in registers should be flushed
-     * to their backing locations in the frame for now.
-     * Also, we need to do initial assignment for promoted
-     * arguments.  NOTE: an older version of dx had an issue
-     * in which it would reuse static method argument registers.
-     * This could result in the same Dalvik virtual register
-     * being promoted to both core and fp regs.  In those
-     * cases, copy argument to both.  This will be uncommon
-     * enough that it isn't worth attempting to optimize.
-     */
-    for (int i = 0; i < cUnit->numIns; i++) {
-        PromotionMap vMap = cUnit->promotionMap[startVReg + i];
-        if (i <= (lastArgReg - firstArgReg)) {
-            // If arriving in register
-            if (vMap.coreLocation == kLocPhysReg) {
-                genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
-            }
-            if (vMap.fpLocation == kLocPhysReg) {
-                genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
-            }
-            // Also put a copy in memory in case we're partially promoted
-            storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
-                          firstArgReg + i, kWord);
-        } else {
-            // If arriving in frame & promoted
-            if (vMap.coreLocation == kLocPhysReg) {
-                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
-                             vMap.coreReg);
-            }
-            if (vMap.fpLocation == kLocPhysReg) {
-                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
-                             vMap.fpReg);
-            }
-        }
-    }
-}
-
-/* Handle the content in each basic block */
-STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
-{
-    MIR* mir;
-    ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
-    int blockId = bb->id;
-
-    cUnit->curBlock = bb;
-    labelList[blockId].operands[0] = bb->startOffset;
-
-    /* Insert the block label */
-    labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
-    oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
-
-    /* Reset local optimization data on block boundaries */
-    oatResetRegPool(cUnit);
-    oatClobberAllRegs(cUnit);
-    oatResetDefTracking(cUnit);
-
-    ArmLIR* headLIR = NULL;
-
-    int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
-    if (bb->blockType == kEntryBlock) {
-        /*
-         * On entry, r0, r1, r2 & r3 are live.  Let the register allocation
-         * mechanism know so it doesn't try to use any of them when
-         * expanding the frame or flushing.  This leaves the utility
-         * code with a single temp: r12.  This should be enough.
-         */
-        oatLockTemp(cUnit, r0);
-        oatLockTemp(cUnit, r1);
-        oatLockTemp(cUnit, r2);
-        oatLockTemp(cUnit, r3);
-
-        /*
-         * We can safely skip the stack overflow check if we're
-         * a leaf *and* our frame size < fudge factor.
-         */
-        bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
-                                  ((size_t)cUnit->frameSize <
-                                  Thread::kStackOverflowReservedBytes));
-        newLIR0(cUnit, kArmPseudoMethodEntry);
-        if (!skipOverflowCheck) {
-            /* Load stack limit */
-            loadWordDisp(cUnit, rSELF,
-                         Thread::StackEndOffset().Int32Value(), r12);
-        }
-        /* Spill core callee saves */
-        newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
-        /* Need to spill any FP regs? */
-        if (cUnit->numFPSpills) {
-            /*
-             * NOTE: fp spills are a little different from core spills in that
-             * they are pushed as a contiguous block.  When promoting from
-             * the fp set, we must allocate all singles from s16..highest-promoted
-             */
-            newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
-        }
-        if (!skipOverflowCheck) {
-            opRegRegImm(cUnit, kOpSub, rLR, rSP,
-                        cUnit->frameSize - (spillCount * 4));
-            genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
-                           kArmThrowStackOverflow);
-            genRegCopy(cUnit, rSP, rLR);         // Establish stack
-        } else {
-            opRegImm(cUnit, kOpSub, rSP,
-                     cUnit->frameSize - (spillCount * 4));
-        }
-        storeBaseDisp(cUnit, rSP, 0, r0, kWord);
-        flushIns(cUnit);
-
-        if (cUnit->genDebugger) {
-            // Refresh update debugger callout
-            loadWordDisp(cUnit, rSELF,
-                         OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
-            genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
-        }
-
-        oatFreeTemp(cUnit, r0);
-        oatFreeTemp(cUnit, r1);
-        oatFreeTemp(cUnit, r2);
-        oatFreeTemp(cUnit, r3);
-    } else if (bb->blockType == kExitBlock) {
-        /*
-         * In the exit path, r0/r1 are live - make sure they aren't
-         * allocated by the register utilities as temps.
-         */
-        oatLockTemp(cUnit, r0);
-        oatLockTemp(cUnit, r1);
-
-        newLIR0(cUnit, kArmPseudoMethodExit);
-        /* If we're compiling for the debugger, generate an update callout */
-        if (cUnit->genDebugger) {
-            genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
-        }
-        opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
-        /* Need to restore any FP callee saves? */
-        if (cUnit->numFPSpills) {
-            newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
-        }
-        if (cUnit->coreSpillMask & (1 << rLR)) {
-            /* Unspill rLR to rPC */
-            cUnit->coreSpillMask &= ~(1 << rLR);
-            cUnit->coreSpillMask |= (1 << rPC);
-        }
-        newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
-        if (!(cUnit->coreSpillMask & (1 << rPC))) {
-            /* We didn't pop to rPC, so must do a bv rLR */
-            newLIR1(cUnit, kThumbBx, rLR);
-        }
-    }
-
-    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
-
-        oatResetRegPool(cUnit);
-        if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
-            oatClobberAllRegs(cUnit);
-        }
-
-        if (cUnit->disableOpt & (1 << kSuppressLoads)) {
-            oatResetDefTracking(cUnit);
-        }
-
-        if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
-            handleExtendedMethodMIR(cUnit, mir);
-            continue;
-        }
-
-        cUnit->currentDalvikOffset = mir->offset;
-
-        Opcode dalvikOpcode = mir->dalvikInsn.opcode;
-        InstructionFormat dalvikFormat =
-            dexGetFormatFromOpcode(dalvikOpcode);
-
-        ArmLIR* boundaryLIR;
-
-        /* Mark the beginning of a Dalvik instruction for line tracking */
-        char* instStr = cUnit->printMe ?
-           oatGetDalvikDisassembly(cUnit, &mir->dalvikInsn, "") : NULL;
-        boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
-                              (intptr_t) instStr);
-        cUnit->boundaryMap.insert(std::make_pair(mir->offset,
-                                 (LIR*)boundaryLIR));
-        /* Remember the first LIR for this block */
-        if (headLIR == NULL) {
-            headLIR = boundaryLIR;
-            /* Set the first boundaryLIR as a scheduling barrier */
-            headLIR->defMask = ENCODE_ALL;
-        }
-
-        /* If we're compiling for the debugger, generate an update callout */
-        if (cUnit->genDebugger) {
-            genDebuggerUpdate(cUnit, mir->offset);
-        }
-
-        /* Don't generate the SSA annotation unless verbose mode is on */
-        if (cUnit->printMe && mir->ssaRep) {
-            char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
-            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
-        }
-
-        bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
-
-        if (notHandled) {
-            char buf[100];
-            snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
-                 mir->offset,
-                 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
-                 dalvikFormat);
-            LOG(FATAL) << buf;
-        }
-    }
-
-    if (headLIR) {
-        /*
-         * Eliminate redundant loads/stores and delay stores into later
-         * slots
-         */
-        oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
-                                           cUnit->lastLIRInsn);
-
-        /*
-         * Generate an unconditional branch to the fallthrough block.
-         */
-        if (bb->fallThrough) {
-            genUnconditionalBranch(cUnit,
-                                   &labelList[bb->fallThrough->id]);
-        }
-    }
-    return false;
-}
-
-/*
- * Nop any unconditional branches that go to the next instruction.
- * Note: new redundant branches may be inserted later, and we'll
- * use a check in final instruction assembly to nop those out.
- */
-void removeRedundantBranches(CompilationUnit* cUnit)
-{
-    ArmLIR* thisLIR;
-
-    for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
-         thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
-         thisLIR = NEXT_LIR(thisLIR)) {
-
-        /* Branch to the next instruction */
-        if ((thisLIR->opcode == kThumbBUncond) ||
-            (thisLIR->opcode == kThumb2BUncond)) {
-            ArmLIR* nextLIR = thisLIR;
-
-            while (true) {
-                nextLIR = NEXT_LIR(nextLIR);
-
-                /*
-                 * Is the branch target the next instruction?
-                 */
-                if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
-                    thisLIR->flags.isNop = true;
-                    break;
-                }
-
-                /*
-                 * Found real useful stuff between the branch and the target.
-                 * Need to explicitly check the lastLIRInsn here because it
-                 * might be the last real instruction.
-                 */
-                if (!isPseudoOpcode(nextLIR->opcode) ||
-                    (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
-                    break;
-            }
-        }
-    }
-}
-
-STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
-{
-    ArmLIR** suspendLabel =
-        (ArmLIR **) cUnit->suspendLaunchpads.elemList;
-    int numElems = cUnit->suspendLaunchpads.numUsed;
-
-    for (int i = 0; i < numElems; i++) {
-        /* TUNING: move suspend count load into helper */
-        ArmLIR* lab = suspendLabel[i];
-        ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
-        cUnit->currentDalvikOffset = lab->operands[1];
-        oatAppendLIR(cUnit, (LIR *)lab);
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
-        if (!cUnit->genDebugger) {
-            // use rSUSPEND for suspend count
-            loadWordDisp(cUnit, rSELF,
-                         Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
-        }
-        opReg(cUnit, kOpBlx, rLR);
-        if ( cUnit->genDebugger) {
-            // use rSUSPEND for update debugger
-            loadWordDisp(cUnit, rSELF,
-                         OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
-        }
-        genUnconditionalBranch(cUnit, resumeLab);
-    }
-}
-
-STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
-{
-    ArmLIR** throwLabel =
-        (ArmLIR **) cUnit->throwLaunchpads.elemList;
-    int numElems = cUnit->throwLaunchpads.numUsed;
-    int i;
-
-    for (i = 0; i < numElems; i++) {
-        ArmLIR* lab = throwLabel[i];
-        cUnit->currentDalvikOffset = lab->operands[1];
-        oatAppendLIR(cUnit, (LIR *)lab);
-        int funcOffset = 0;
-        int v1 = lab->operands[2];
-        int v2 = lab->operands[3];
-        switch(lab->operands[0]) {
-            case kArmThrowNullPointer:
-                funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
-                break;
-            case kArmThrowArrayBounds:
-                if (v2 != r0) {
-                    genRegCopy(cUnit, r0, v1);
-                    genRegCopy(cUnit, r1, v2);
-                } else {
-                    if (v1 == r1) {
-                        genRegCopy(cUnit, r12, v1);
-                        genRegCopy(cUnit, r1, v2);
-                        genRegCopy(cUnit, r0, r12);
-                    } else {
-                        genRegCopy(cUnit, r1, v2);
-                        genRegCopy(cUnit, r0, v1);
-                    }
-                }
-                funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
-                break;
-            case kArmThrowDivZero:
-                funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
-                break;
-            case kArmThrowVerificationError:
-                loadConstant(cUnit, r0, v1);
-                loadConstant(cUnit, r1, v2);
-                funcOffset =
-                    OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
-                break;
-            case kArmThrowNegArraySize:
-                genRegCopy(cUnit, r0, v1);
-                funcOffset =
-                    OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
-                break;
-            case kArmThrowNoSuchMethod:
-                genRegCopy(cUnit, r0, v1);
-                funcOffset =
-                    OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
-                break;
-            case kArmThrowStackOverflow:
-                funcOffset =
-                    OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
-                // Restore stack alignment
-                opRegImm(cUnit, kOpAdd, rSP,
-                         (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
-                break;
-            default:
-                LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
-        }
-        loadWordDisp(cUnit, rSELF, funcOffset, rLR);
-        callRuntimeHelper(cUnit, rLR);
-    }
-}
-
-void oatMethodMIR2LIR(CompilationUnit* cUnit)
-{
-    /* Used to hold the labels of each block */
-    cUnit->blockLabelList =
-        (void *) oatNew(cUnit, sizeof(ArmLIR) * cUnit->numBlocks, true,
-                        kAllocLIR);
-
-    oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
-                                  kPreOrderDFSTraversal, false /* Iterative */);
-    handleSuspendLaunchpads(cUnit);
-
-    handleThrowLaunchpads(cUnit);
-
-    removeRedundantBranches(cUnit);
-}
-
-/* Common initialization routine for an architecture family */
-bool oatArchInit()
-{
-    int i;
-
-    for (i = 0; i < kArmLast; i++) {
-        if (EncodingMap[i].opcode != i) {
-            LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
-               " is wrong: expecting " << i << ", seeing " <<
-               (int)EncodingMap[i].opcode;
-        }
-    }
-
-    return oatArchVariantInit();
-}
-
-/* Needed by the Assembler */
-void oatSetupResourceMasks(ArmLIR* lir)
-{
-    setupResourceMasks(lir);
-}
-
-/* Needed by the ld/st optmizatons */
-ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
-{
-    return genRegCopyNoInsert(cUnit, rDest, rSrc);
-}
-
-/* Needed by the register allocator */
-ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
-{
-    return genRegCopy(cUnit, rDest, rSrc);
-}
-
-/* Needed by the register allocator */
-void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
-                            int srcLo, int srcHi)
-{
-    genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
-}
-
-void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
-                             int displacement, int rSrc, OpSize size)
-{
-    storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
-}
-
-void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
-                                 int displacement, int rSrcLo, int rSrcHi)
-{
-    storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
-}
-
-}  // namespace art
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index dff05b7..c385f35 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -22,19 +22,22 @@
  *
  */
 
-#define SLOW_FIELD_PATH (cUnit->enableDebug & (1 << kDebugSlowFieldPath))
-#define SLOW_INVOKE_PATH (cUnit->enableDebug & (1 << kDebugSlowInvokePath))
-#define SLOW_STRING_PATH (cUnit->enableDebug & (1 << kDebugSlowStringPath))
-#define SLOW_TYPE_PATH (cUnit->enableDebug & (1 << kDebugSlowTypePath))
-#define EXERCISE_SLOWEST_FIELD_PATH (cUnit->enableDebug & \
-    (1 << kDebugSlowestFieldPath))
-#define EXERCISE_SLOWEST_STRING_PATH (cUnit->enableDebug & \
-    (1 << kDebugSlowestStringPath))
-#define EXERCISE_RESOLVE_METHOD (cUnit->enableDebug & \
-    (1 << kDebugExerciseResolveMethod))
-
 namespace art {
 
+/*
+ * Return most flexible allowed register class based on size.
+ * Bug: 2813841
+ * Must use a core register for data types narrower than word (due
+ * to possible unaligned load/store.
+ */
+STATIC inline RegisterClass oatRegClassBySize(OpSize size)
+{
+    return (size == kUnsignedHalf ||
+            size == kSignedHalf ||
+            size == kUnsignedByte ||
+            size == kSignedByte ) ? kCoreReg : kAnyReg;
+}
+
 STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
 
 void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
@@ -67,20 +70,6 @@
 }
 #endif
 
-STATIC ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
-{
-    oatClobberCalleeSave(cUnit);
-    return opReg(cUnit, kOpBlx, reg);
-}
-
-/* Generate unconditional branch instructions */
-STATIC ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
-{
-    ArmLIR* branch = opNone(cUnit, kOpUncondBr);
-    branch->generic.target = (LIR*) target;
-    return branch;
-}
-
 /*
  * Generate a Thumb2 IT instruction, which can nullify up to
  * four subsequent instructions based on a condition and its
@@ -386,26 +375,6 @@
     callRuntimeHelper(cUnit, rLR);
 }
 
-/*
- * Mark garbage collection card. Skip if the value we're storing is null.
- */
-STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
-{
-    int regCardBase = oatAllocTemp(cUnit);
-    int regCardNo = oatAllocTemp(cUnit);
-    ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
-    loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
-                 regCardBase);
-    opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
-    storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
-                     kUnsignedByte);
-    ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
-    target->defMask = ENCODE_ALL;
-    branchOver->generic.target = (LIR*)target;
-    oatFreeTemp(cUnit, regCardBase);
-    oatFreeTemp(cUnit, regCardNo);
-}
-
 STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
                     RegLocation rlDest, RegLocation rlObj,
                     bool isLongOrDouble, bool isObject)
@@ -1274,16 +1243,6 @@
     return false;
 }
 
-/* Generate conditional branch instructions */
-STATIC ArmLIR* genConditionalBranch(CompilationUnit* cUnit,
-                                    ArmConditionCode cond,
-                                    ArmLIR* target)
-{
-    ArmLIR* branch = opCondBranch(cUnit, cond);
-    branch->generic.target = (LIR*) target;
-    return branch;
-}
-
 /*
  * Generate array store
  *
diff --git a/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc b/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc
index 00339ef6..f042d5d 100644
--- a/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc
+++ b/src/compiler/codegen/arm/armv7-a-neon/Codegen.cc
@@ -18,11 +18,8 @@
 #define TGT_LIR ArmLIR
 
 #include "../../../Dalvik.h"
-//#include "interp/InterpDefs.h"
-//#include "libdex/DexOpcodes.h"
 #include "../../../CompilerInternals.h"
 #include "../arm/ArmLIR.h"
-//#include "mterp/common/FindInterface.h"
 #include "../../Ralloc.h"
 #include "../Codegen.h"
 
@@ -45,7 +42,13 @@
 #include "../Thumb2/Ralloc.cc"
 
 /* MIR2LIR dispatcher and architectural independent codegen routines */
-#include "../MethodCodegenDriver.cc"
+#include "../../MethodCodegenDriver.cc"
+
+/* Target-independent local optimizations */
+#include "../../LocalOptimizations.cc"
+
+/* Common codegen utility code */
+#include "../../CodegenUtil.cc"
 
 /* Architecture manifest */
 #include "ArchVariant.cc"
diff --git a/src/compiler/codegen/arm/armv7-a/Codegen.cc b/src/compiler/codegen/arm/armv7-a/Codegen.cc
index 384ce15..633ab1e 100644
--- a/src/compiler/codegen/arm/armv7-a/Codegen.cc
+++ b/src/compiler/codegen/arm/armv7-a/Codegen.cc
@@ -18,11 +18,8 @@
 #define TGT_LIR ArmLIR
 
 #include "../../../Dalvik.h"
-//#include "interp/InterpDefs.h"
-//#include "libdex/DexOpcodes.h"
 #include "../../../CompilerInternals.h"
 #include "../ArmLIR.h"
-//#include "mterp/common/FindInterface.h"
 #include "../../Ralloc.h"
 #include "../Codegen.h"
 
@@ -45,7 +42,13 @@
 #include "../Thumb2/Ralloc.cc"
 
 /* MIR2LIR dispatcher and architectural independent codegen routines */
-#include "../MethodCodegenDriver.cc"
+#include "../../MethodCodegenDriver.cc"
+
+/* Target-independent local optimizations */
+#include "../../LocalOptimizations.cc"
+
+/* Common codegen utility code */
+#include "../../CodegenUtil.cc"
 
 /* Architecture manifest */
 #include "ArchVariant.cc"
diff --git a/src/compiler/codegen/mips/ArchFactory.cc b/src/compiler/codegen/mips/ArchFactory.cc
new file mode 100644
index 0000000..6a3e667
--- /dev/null
+++ b/src/compiler/codegen/mips/ArchFactory.cc
@@ -0,0 +1,1416 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains mips-specific codegen factory support.
+ * It is included by
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#define SLOW_FIELD_PATH (cUnit->enableDebug & (1 << kDebugSlowFieldPath))
+#define SLOW_INVOKE_PATH (cUnit->enableDebug & (1 << kDebugSlowInvokePath))
+#define SLOW_STRING_PATH (cUnit->enableDebug & (1 << kDebugSlowStringPath))
+#define SLOW_TYPE_PATH (cUnit->enableDebug & (1 << kDebugSlowTypePath))
+#define EXERCISE_SLOWEST_FIELD_PATH (cUnit->enableDebug & \
+    (1 << kDebugSlowestFieldPath))
+#define EXERCISE_SLOWEST_STRING_PATH (cUnit->enableDebug & \
+    (1 << kDebugSlowestStringPath))
+#define EXERCISE_RESOLVE_METHOD (cUnit->enableDebug & \
+    (1 << kDebugExerciseResolveMethod))
+
+// FIXME - this is the Mips version, change to MIPS
+
+namespace art {
+
+STATIC void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset);
+
+/* Generate conditional branch instructions */
+STATIC MipsLIR* genConditionalBranch(CompilationUnit* cUnit,
+                                    MipsConditionCode cond,
+                                    MipsLIR* target)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+    return NULL;
+#if 0
+    MipsLIR* branch = opCondBranch(cUnit, cond);
+    branch->generic.target = (LIR*) target;
+    return branch;
+#endif
+}
+
+/* Generate unconditional branch instructions */
+STATIC MipsLIR* genUnconditionalBranch(CompilationUnit* cUnit, MipsLIR* target)
+{
+    MipsLIR* branch = opNone(cUnit, kOpUncondBr);
+    branch->generic.target = (LIR*) target;
+    return branch;
+}
+
+STATIC MipsLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
+{
+    oatClobberCalleeSave(cUnit);
+    return opReg(cUnit, kOpBlx, reg);
+}
+
+/*
+ * Mark garbage collection card. Skip if the value we're storing is null.
+ */
+STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int regCardBase = oatAllocTemp(cUnit);
+    int regCardNo = oatAllocTemp(cUnit);
+    MipsLIR* branchOver = genCmpImmBranch(cUnit, kMipsCondEq, valReg, 0);
+    loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
+                 regCardBase);
+    opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
+    storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
+                     kUnsignedByte);
+    MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR*)target;
+    oatFreeTemp(cUnit, regCardBase);
+    oatFreeTemp(cUnit, regCardNo);
+#endif
+}
+
+/*
+ * Utiltiy to load the current Method*.  Broken out
+ * to allow easy change between placing the current Method* in a
+ * dedicated register or its home location in the frame.
+ */
+STATIC void loadCurrMethodDirect(CompilationUnit *cUnit, int rTgt)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+#if defined(METHOD_IN_REG)
+    genRegCopy(cUnit, rTgt, rMETHOD);
+#else
+    loadWordDisp(cUnit, rSP, 0, rTgt);
+#endif
+#endif
+}
+
+STATIC int loadCurrMethod(CompilationUnit *cUnit)
+{
+#if defined(METHOD_IN_REG)
+    return rMETHOD;
+#else
+    int mReg = oatAllocTemp(cUnit);
+    loadCurrMethodDirect(cUnit, mReg);
+    return mReg;
+#endif
+}
+
+STATIC MipsLIR* genCheck(CompilationUnit* cUnit, MipsConditionCode cCode,
+                        MIR* mir, MipsThrowKind kind)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+    return 0;
+#if 0
+    MipsLIR* tgt = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    tgt->opcode = kMipsPseudoThrowTarget;
+    tgt->operands[0] = kind;
+    tgt->operands[1] = mir ? mir->offset : 0;
+    MipsLIR* branch = genConditionalBranch(cUnit, cCode, tgt);
+    // Remember branch target - will process later
+    oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
+    return branch;
+#endif
+}
+
+STATIC MipsLIR* genImmedCheck(CompilationUnit* cUnit, MipsConditionCode cCode,
+                             int reg, int immVal, MIR* mir, MipsThrowKind kind)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+    return 0;
+#if 0
+    MipsLIR* tgt = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    tgt->opcode = kMipsPseudoThrowTarget;
+    tgt->operands[0] = kind;
+    tgt->operands[1] = mir->offset;
+    MipsLIR* branch;
+    if (cCode == kMipsCondAl) {
+        branch = genUnconditionalBranch(cUnit, tgt);
+    } else {
+        branch = genCmpImmBranch(cUnit, cCode, reg, immVal);
+        branch->generic.target = (LIR*)tgt;
+    }
+    // Remember branch target - will process later
+    oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
+    return branch;
+#endif
+}
+
+/* Perform null-check on a register.  */
+STATIC MipsLIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg,
+                             MIR* mir)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+    return 0;
+#if 0
+    if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
+        mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) {
+        return NULL;
+    }
+    return genImmedCheck(cUnit, kMipsCondEq, mReg, 0, mir, kMipsThrowNullPointer);
+#endif
+}
+
+/* Perform check on two registers */
+STATIC TGT_LIR* genRegRegCheck(CompilationUnit* cUnit, MipsConditionCode cCode,
+                               int reg1, int reg2, MIR* mir, MipsThrowKind kind)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+    return 0;
+#if 0
+    MipsLIR* tgt = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    tgt->opcode = kMipsPseudoThrowTarget;
+    tgt->operands[0] = kind;
+    tgt->operands[1] = mir ? mir->offset : 0;
+    tgt->operands[2] = reg1;
+    tgt->operands[3] = reg2;
+    opRegReg(cUnit, kOpCmp, reg1, reg2);
+    MipsLIR* branch = genConditionalBranch(cUnit, cCode, tgt);
+    // Remember branch target - will process later
+    oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
+    return branch;
+#endif
+}
+
+/*
+ * Let helper function take care of everything.  Will call
+ * Array::AllocFromCode(type_idx, method, count);
+ * Note: AllocFromCode will handle checks for errNegativeArraySize.
+ */
+STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                        RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    oatFlushAllRegs(cUnit);    /* Everything to home location */
+    uint32_t type_idx = mir->dalvikInsn.vC;
+    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
+                                                    cUnit->dex_cache,
+                                                    *cUnit->dex_file,
+                                                    type_idx)) {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
+    } else {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), rLR);
+    }
+    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
+    loadConstant(cUnit, r0, type_idx);            // arg0 <- type_id
+    loadValueDirectFixed(cUnit, rlSrc, r2);       // arg2 <- count
+    callRuntimeHelper(cUnit, rLR);
+    RegLocation rlResult = oatGetReturn(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
+#endif
+}
+
+/*
+ * Similar to genNewArray, but with post-allocation initialization.
+ * Verifier guarantees we're dealing with an array class.  Current
+ * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
+ * Current code also throws internal unimp if not 'L', '[' or 'I'.
+ */
+STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    DecodedInstruction* dInsn = &mir->dalvikInsn;
+    int elems = dInsn->vA;
+    int typeId = dInsn->vB;
+    oatFlushAllRegs(cUnit);    /* Everything to home location */
+    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
+                                                    cUnit->dex_cache,
+                                                    *cUnit->dex_file,
+                                                    typeId)) {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
+    } else {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCodeWithAccessCheck), rLR);
+    }
+    loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
+    loadConstant(cUnit, r0, typeId);              // arg0 <- type_id
+    loadConstant(cUnit, r2, elems);               // arg2 <- count
+    callRuntimeHelper(cUnit, rLR);
+    /*
+     * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
+     * return region.  Because AllocFromCode placed the new array
+     * in r0, we'll just lock it into place.  When debugger support is
+     * added, it may be necessary to additionally copy all return
+     * values to a home location in thread-local storage
+     */
+    oatLockTemp(cUnit, r0);
+
+    // Having a range of 0 is legal
+    if (isRange && (dInsn->vA > 0)) {
+        /*
+         * Bit of ugliness here.  We're going generate a mem copy loop
+         * on the register range, but it is possible that some regs
+         * in the range have been promoted.  This is unlikely, but
+         * before generating the copy, we'll just force a flush
+         * of any regs in the source range that have been promoted to
+         * home location.
+         */
+        for (unsigned int i = 0; i < dInsn->vA; i++) {
+            RegLocation loc = oatUpdateLoc(cUnit,
+                oatGetSrc(cUnit, mir, i));
+            if (loc.location == kLocPhysReg) {
+                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
+                              loc.lowReg, kWord);
+            }
+        }
+        /*
+         * TUNING note: generated code here could be much improved, but
+         * this is an uncommon operation and isn't especially performance
+         * critical.
+         */
+        int rSrc = oatAllocTemp(cUnit);
+        int rDst = oatAllocTemp(cUnit);
+        int rIdx = oatAllocTemp(cUnit);
+        int rVal = rLR;  // Using a lot of temps, rLR is known free here
+        // Set up source pointer
+        RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
+        opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
+                    oatSRegOffset(cUnit, rlFirst.sRegLow));
+        // Set up the target pointer
+        opRegRegImm(cUnit, kOpAdd, rDst, r0,
+                    Array::DataOffset().Int32Value());
+        // Set up the loop counter (known to be > 0)
+        loadConstant(cUnit, rIdx, dInsn->vA - 1);
+        // Generate the copy loop.  Going backwards for convenience
+        MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+        target->defMask = ENCODE_ALL;
+        // Copy next element
+        loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
+        storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
+        // Use setflags encoding here
+        newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
+        MipsLIR* branch = opCondBranch(cUnit, kMipsCondGe);
+        branch->generic.target = (LIR*)target;
+    } else if (!isRange) {
+        // TUNING: interleave
+        for (unsigned int i = 0; i < dInsn->vA; i++) {
+            RegLocation rlArg = loadValue(cUnit,
+                oatGetSrc(cUnit, mir, i), kCoreReg);
+            storeBaseDisp(cUnit, r0,
+                          Array::DataOffset().Int32Value() +
+                          i * 4, rlArg.lowReg, kWord);
+            // If the loadValue caused a temp to be allocated, free it
+            if (oatIsTemp(cUnit, rlArg.lowReg)) {
+                oatFreeTemp(cUnit, rlArg.lowReg);
+            }
+        }
+    }
+#endif
+}
+
+STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
+                    bool isLongOrDouble, bool isObject)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int fieldOffset;
+    int ssbIndex;
+    bool isVolatile;
+    bool isReferrersClass;
+    uint32_t fieldIdx = mir->dalvikInsn.vB;
+    bool fastPath =
+        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
+                                                fieldOffset, ssbIndex,
+                                                isReferrersClass, isVolatile, true);
+    if (fastPath && !SLOW_FIELD_PATH) {
+        DCHECK_GE(fieldOffset, 0);
+        int rBase;
+        int rMethod;
+        if (isReferrersClass) {
+            // Fast path, static storage base is this method's class
+            rMethod  = loadCurrMethod(cUnit);
+            rBase = oatAllocTemp(cUnit);
+            loadWordDisp(cUnit, rMethod,
+                         Method::DeclaringClassOffset().Int32Value(), rBase);
+        } else {
+            // Medium path, static storage base in a different class which
+            // requires checks that the other class is initialized.
+            DCHECK_GE(ssbIndex, 0);
+            // May do runtime call so everything to home locations.
+            oatFlushAllRegs(cUnit);
+            // Using fixed register to sync with possible call to runtime
+            // support.
+            rMethod = r1;
+            oatLockTemp(cUnit, rMethod);
+            loadCurrMethodDirect(cUnit, rMethod);
+            rBase = r0;
+            oatLockTemp(cUnit, rBase);
+            loadWordDisp(cUnit, rMethod,
+                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
+                rBase);
+            loadWordDisp(cUnit, rBase,
+                         Array::DataOffset().Int32Value() + sizeof(int32_t*) *
+                         ssbIndex, rBase);
+            // rBase now points at appropriate static storage base (Class*)
+            // or NULL if not initialized. Check for NULL and call helper if NULL.
+            // TUNING: fast path should fall through
+            MipsLIR* branchOver = genCmpImmBranch(cUnit, kMipsCondNe, rBase, 0);
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
+            loadConstant(cUnit, r0, ssbIndex);
+            callRuntimeHelper(cUnit, rLR);
+            MipsLIR* skipTarget = newLIR0(cUnit, kMipsPseudoTargetLabel);
+            skipTarget->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR*)skipTarget;
+        }
+        // rBase now holds static storage base
+        oatFreeTemp(cUnit, rMethod);
+        if (isLongOrDouble) {
+            rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+            rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+        } else {
+            rlSrc = oatGetSrc(cUnit, mir, 0);
+            rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+        }
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kST);
+        }
+        if (isLongOrDouble) {
+            storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
+                              rlSrc.highReg);
+        } else {
+            storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
+        }
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kSY);
+        }
+        if (isObject) {
+            markGCCard(cUnit, rlSrc.lowReg, rBase);
+        }
+        oatFreeTemp(cUnit, rBase);
+    } else {
+        oatFlushAllRegs(cUnit);  // Everything to home locations
+        int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
+                           (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
+                                     : OFFSETOF_MEMBER(Thread, pSet32Static));
+        loadWordDisp(cUnit, rSELF, setterOffset, rLR);
+        loadConstant(cUnit, r0, fieldIdx);
+        if (isLongOrDouble) {
+            loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
+        } else {
+            loadValueDirect(cUnit, rlSrc, r1);
+        }
+        callRuntimeHelper(cUnit, rLR);
+    }
+#endif
+}
+
+STATIC void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                    bool isLongOrDouble, bool isObject)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int fieldOffset;
+    int ssbIndex;
+    bool isVolatile;
+    bool isReferrersClass;
+    uint32_t fieldIdx = mir->dalvikInsn.vB;
+    bool fastPath =
+        cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
+                                                fieldOffset, ssbIndex,
+                                                isReferrersClass, isVolatile, false);
+    if (fastPath && !SLOW_FIELD_PATH) {
+        DCHECK_GE(fieldOffset, 0);
+        int rBase;
+        int rMethod;
+        if (isReferrersClass) {
+            // Fast path, static storage base is this method's class
+            rMethod  = loadCurrMethod(cUnit);
+            rBase = oatAllocTemp(cUnit);
+            loadWordDisp(cUnit, rMethod,
+                         Method::DeclaringClassOffset().Int32Value(), rBase);
+        } else {
+            // Medium path, static storage base in a different class which
+            // requires checks that the other class is initialized
+            DCHECK_GE(ssbIndex, 0);
+            // May do runtime call so everything to home locations.
+            oatFlushAllRegs(cUnit);
+            // Using fixed register to sync with possible call to runtime
+            // support
+            rMethod = r1;
+            oatLockTemp(cUnit, rMethod);
+            loadCurrMethodDirect(cUnit, rMethod);
+            rBase = r0;
+            oatLockTemp(cUnit, rBase);
+            loadWordDisp(cUnit, rMethod,
+                Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
+                rBase);
+            loadWordDisp(cUnit, rBase,
+                         Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex,
+                         rBase);
+            // rBase now points at appropriate static storage base (Class*)
+            // or NULL if not initialized. Check for NULL and call helper if NULL.
+            // TUNING: fast path should fall through
+            MipsLIR* branchOver = genCmpImmBranch(cUnit, kMipsCondNe, rBase, 0);
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
+            loadConstant(cUnit, r0, ssbIndex);
+            callRuntimeHelper(cUnit, rLR);
+            MipsLIR* skipTarget = newLIR0(cUnit, kMipsPseudoTargetLabel);
+            skipTarget->defMask = ENCODE_ALL;
+            branchOver->generic.target = (LIR*)skipTarget;
+        }
+        // rBase now holds static storage base
+        oatFreeTemp(cUnit, rMethod);
+        rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
+                                : oatGetDest(cUnit, mir, 0);
+        RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+        if (isVolatile) {
+            oatGenMemBarrier(cUnit, kSY);
+        }
+        if (isLongOrDouble) {
+            loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
+                             rlResult.highReg, INVALID_SREG);
+        } else {
+            loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
+        }
+        oatFreeTemp(cUnit, rBase);
+        if (isLongOrDouble) {
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    } else {
+        oatFlushAllRegs(cUnit);  // Everything to home locations
+        int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
+                           (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
+                                     : OFFSETOF_MEMBER(Thread, pGet32Static));
+        loadWordDisp(cUnit, rSELF, getterOffset, rLR);
+        loadConstant(cUnit, r0, fieldIdx);
+        callRuntimeHelper(cUnit, rLR);
+        if (isLongOrDouble) {
+            RegLocation rlResult = oatGetReturnWide(cUnit);
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            RegLocation rlResult = oatGetReturn(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    }
+#endif
+}
+
+typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
+                            uint32_t methodIdx);
+
+/*
+ * Bit of a hack here - in leiu of a real scheduling pass,
+ * emit the next instruction in static & direct invoke sequences.
+ */
+STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
+                          int state, uint32_t dexIdx, uint32_t unused)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    switch(state) {
+        case 0:  // Get the current Method* [sets r0]
+            loadCurrMethodDirect(cUnit, r0);
+            break;
+        case 1:  // Get method->code_and_direct_methods_
+            loadWordDisp(cUnit, r0,
+                Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
+                r0);
+            break;
+        case 2:  // Grab target method* and target code_
+            loadWordDisp(cUnit, r0,
+                CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR);
+            loadWordDisp(cUnit, r0,
+                CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0);
+            break;
+        default:
+            return -1;
+    }
+#endif
+    return state + 1;
+}
+
+/*
+ * Bit of a hack here - in leiu of a real scheduling pass,
+ * emit the next instruction in a virtual invoke sequence.
+ * We can use rLR as a temp prior to target address loading
+ * Note also that we'll load the first argument ("this") into
+ * r1 here rather than the standard loadArgRegs.
+ */
+STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
+                         int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    RegLocation rlArg;
+    /*
+     * This is the fast path in which the target virtual method is
+     * fully resolved at compile time.
+     */
+    switch(state) {
+        case 0:  // Get "this" [set r1]
+            rlArg = oatGetSrc(cUnit, mir, 0);
+            loadValueDirectFixed(cUnit, rlArg, r1);
+            break;
+        case 1: // Is "this" null? [use r1]
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+            // get this->klass_ [use r1, set rLR]
+            loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
+            break;
+        case 2: // Get this->klass_->vtable [usr rLR, set rLR]
+            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
+            break;
+        case 3: // Get target method [use rLR, set r0]
+            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
+                         Array::DataOffset().Int32Value(), r0);
+            break;
+        case 4: // Get the target compiled code address [uses r0, sets rLR]
+            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
+            break;
+        default:
+            return -1;
+    }
+#endif
+    return state + 1;
+}
+
+/*
+ * Interleave launch code for INVOKE_SUPER.  See comments
+ * for nextVCallIns.
+ */
+STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
+                             int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    /*
+     * This is the fast path in which the target virtual method is
+     * fully resolved at compile time.  Note also that this path assumes
+     * that the check to verify that the target method index falls
+     * within the size of the super's vtable has been done at compile-time.
+     */
+    RegLocation rlArg;
+    switch(state) {
+        case 0: // Get current Method* [set r0]
+            loadCurrMethodDirect(cUnit, r0);
+            // Load "this" [set r1]
+            rlArg = oatGetSrc(cUnit, mir, 0);
+            loadValueDirectFixed(cUnit, rlArg, r1);
+            // Get method->declaring_class_ [use r0, set rLR]
+            loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
+                         rLR);
+            // Is "this" null? [use r1]
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+            break;
+        case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
+            loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
+                         rLR);
+            break;
+        case 2: // Get ...->super_class_->vtable [u/s rLR]
+            loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
+            break;
+        case 3: // Get target method [use rLR, set r0]
+            loadWordDisp(cUnit, rLR, (methodIdx * 4) +
+                         Array::DataOffset().Int32Value(), r0);
+            break;
+        case 4: // Get the target compiled code address [uses r0, sets rLR]
+            loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
+            break;
+        default:
+            return -1;
+    }
+#endif
+    return state + 1;
+}
+
+STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, int trampoline,
+                            int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    /*
+     * This handles the case in which the base method is not fully
+     * resolved at compile time, we bail to a runtime helper.
+     */
+    if (state == 0) {
+        // Load trampoline target
+        loadWordDisp(cUnit, rSELF, trampoline, rLR);
+        // Load r0 with method index
+        loadConstant(cUnit, r0, dexIdx);
+        return 1;
+    }
+#endif
+    return -1;
+}
+
+STATIC int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                                int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                                int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                               int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+                           int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+/*
+ * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
+ * which will locate the target and continue on via a tail call.
+ */
+STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
+                                 int state, uint32_t dexIdx, uint32_t unused)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
+                                                MIR* mir, int state,
+                                                uint32_t dexIdx,
+                                                uint32_t unused)
+{
+  int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
+  return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
+                          DecodedInstruction* dInsn, int callState,
+                          NextCallInsn nextCallInsn, uint32_t dexIdx,
+                          uint32_t methodIdx, bool skipThis)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int nextReg = r1;
+    int nextArg = 0;
+    if (skipThis) {
+        nextReg++;
+        nextArg++;
+    }
+    for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
+        RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
+        rlArg = oatUpdateRawLoc(cUnit, rlArg);
+        if (rlArg.wide && (nextReg <= r2)) {
+            loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
+            nextReg++;
+            nextArg++;
+        } else {
+            rlArg.wide = false;
+            loadValueDirectFixed(cUnit, rlArg, nextReg);
+        }
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    }
+#endif
+    return callState;
+}
+
+/*
+ * Load up to 5 arguments, the first three of which will be in
+ * r1 .. r3.  On entry r0 contains the current method pointer,
+ * and as part of the load sequence, it must be replaced with
+ * the target method pointer.  Note, this may also be called
+ * for "range" variants if the number of arguments is 5 or fewer.
+ */
+STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
+                                DecodedInstruction* dInsn, int callState,
+                                MipsLIR** pcrLabel, NextCallInsn nextCallInsn,
+                                uint32_t dexIdx, uint32_t methodIdx,
+                                bool skipThis)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    RegLocation rlArg;
+
+    /* If no arguments, just return */
+    if (dInsn->vA == 0)
+        return callState;
+
+    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+
+    DCHECK_LE(dInsn->vA, 5U);
+    if (dInsn->vA > 3) {
+        uint32_t nextUse = 3;
+        //Detect special case of wide arg spanning arg3/arg4
+        RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
+        RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
+        RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
+        if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
+            rlUse2.wide) {
+            int reg;
+            // Wide spans, we need the 2nd half of uses[2].
+            rlArg = oatUpdateLocWide(cUnit, rlUse2);
+            if (rlArg.location == kLocPhysReg) {
+                reg = rlArg.highReg;
+            } else {
+                // r2 & r3 can safely be used here
+                reg = r3;
+                loadWordDisp(cUnit, rSP,
+                             oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
+                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+                                         methodIdx);
+            }
+            storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
+            storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
+            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+            nextUse++;
+        }
+        // Loop through the rest
+        while (nextUse < dInsn->vA) {
+            int lowReg;
+            int highReg;
+            rlArg = oatGetRawSrc(cUnit, mir, nextUse);
+            rlArg = oatUpdateRawLoc(cUnit, rlArg);
+            if (rlArg.location == kLocPhysReg) {
+                lowReg = rlArg.lowReg;
+                highReg = rlArg.highReg;
+            } else {
+                lowReg = r2;
+                highReg = r3;
+                if (rlArg.wide) {
+                    loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
+                } else {
+                    loadValueDirectFixed(cUnit, rlArg, lowReg);
+                }
+                callState = nextCallInsn(cUnit, mir, callState, dexIdx,
+                                         methodIdx);
+            }
+            int outsOffset = (nextUse + 1) * 4;
+            if (rlArg.wide) {
+                storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
+                nextUse += 2;
+            } else {
+                storeWordDisp(cUnit, rSP, outsOffset, lowReg);
+                nextUse++;
+            }
+            callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        }
+    }
+
+    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
+                            dexIdx, methodIdx, skipThis);
+
+    if (pcrLabel) {
+        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+    }
+#endif
+    return callState;
+}
+
+/*
+ * May have 0+ arguments (also used for jumbo).  Note that
+ * source virtual registers may be in physical registers, so may
+ * need to be flushed to home location before copying.  This
+ * applies to arg3 and above (see below).
+ *
+ * Two general strategies:
+ *    If < 20 arguments
+ *       Pass args 3-18 using vldm/vstm block copy
+ *       Pass arg0, arg1 & arg2 in r1-r3
+ *    If 20+ arguments
+ *       Pass args arg19+ using memcpy block copy
+ *       Pass arg0, arg1 & arg2 in r1-r3
+ *
+ */
+STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
+                              DecodedInstruction* dInsn, int callState,
+                              MipsLIR** pcrLabel, NextCallInsn nextCallInsn,
+                              uint32_t dexIdx, uint32_t methodIdx,
+                              bool skipThis)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int firstArg = dInsn->vC;
+    int numArgs = dInsn->vA;
+
+    // If we can treat it as non-range (Jumbo ops will use range form)
+    if (numArgs <= 5)
+        return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
+                                    nextCallInsn, dexIdx, methodIdx,
+                                    skipThis);
+    /*
+     * Make sure range list doesn't span the break between in normal
+     * Dalvik vRegs and the ins.
+     */
+    int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
+    int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
+    if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
+        LOG(FATAL) << "Argument list spanned locals & args";
+    }
+
+    /*
+     * First load the non-register arguments.  Both forms expect all
+     * of the source arguments to be in their home frame location, so
+     * scan the sReg names and flush any that have been promoted to
+     * frame backing storage.
+     */
+    // Scan the rest of the args - if in physReg flush to memory
+    for (int nextArg = 0; nextArg < numArgs;) {
+        RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
+        if (loc.wide) {
+            loc = oatUpdateLocWide(cUnit, loc);
+            if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
+                storeBaseDispWide(cUnit, rSP,
+                                  oatSRegOffset(cUnit, loc.sRegLow),
+                                  loc.lowReg, loc.highReg);
+            }
+            nextArg += 2;
+        } else {
+            loc = oatUpdateLoc(cUnit, loc);
+            if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
+                storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
+                              loc.lowReg, kWord);
+            }
+            nextArg++;
+        }
+    }
+
+    int startOffset = oatSRegOffset(cUnit,
+        cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
+    int outsOffset = 4 /* Method* */ + (3 * 4);
+    if (numArgs >= 20) {
+        // Generate memcpy
+        opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
+        opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
+        loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
+        loadConstant(cUnit, r2, (numArgs - 3) * 4);
+        callRuntimeHelper(cUnit, rLR);
+        // Restore Method*
+        loadCurrMethodDirect(cUnit, r0);
+    } else {
+        // Use vldm/vstm pair using r3 as a temp
+        int regsLeft = std::min(numArgs - 3, 16);
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
+        MipsLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
+        //TUNING: loosen barrier
+        ld->defMask = ENCODE_ALL;
+        setMemRefType(ld, true /* isLoad */, kDalvikReg);
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+        MipsLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
+        setMemRefType(st, false /* isLoad */, kDalvikReg);
+        st->defMask = ENCODE_ALL;
+        callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    }
+
+    callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
+                            dexIdx, methodIdx, skipThis);
+
+    callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
+    if (pcrLabel) {
+        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
+    }
+#endif
+    return callState;
+}
+
+// Debugging routine - if null target, branch to DebugMe
+STATIC void genShowTarget(CompilationUnit* cUnit)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsLIR* branchOver = genCmpImmBranch(cUnit, kMipsCondNe, rLR, 0);
+    loadWordDisp(cUnit, rSELF,
+                 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
+    MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+    target->defMask = -1;
+    branchOver->generic.target = (LIR*)target;
+#endif
+}
+
+STATIC void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    loadWordDisp(cUnit, rSELF,
+                 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
+    loadConstant(cUnit, r0, mir->dalvikInsn.vA);
+    loadConstant(cUnit, r1, mir->dalvikInsn.vB);
+    callRuntimeHelper(cUnit, rLR);
+#endif
+}
+
+STATIC void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
+                                MIR* mir, RegLocation rlSrc1,
+                                RegLocation rlSrc2, MipsLIR* labelList)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsConditionCode cond;
+    rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+    opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
+    Opcode opcode = mir->dalvikInsn.opcode;
+    switch(opcode) {
+        case OP_IF_EQ:
+            cond = kMipsCondEq;
+            break;
+        case OP_IF_NE:
+            cond = kMipsCondNe;
+            break;
+        case OP_IF_LT:
+            cond = kMipsCondLt;
+            break;
+        case OP_IF_GE:
+            cond = kMipsCondGe;
+            break;
+        case OP_IF_GT:
+            cond = kMipsCondGt;
+            break;
+        case OP_IF_LE:
+            cond = kMipsCondLe;
+            break;
+        default:
+            cond = (MipsConditionCode)0;
+            LOG(FATAL) << "Unexpected opcode " << (int)opcode;
+    }
+    genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
+    genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+#endif
+}
+
+STATIC void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb,
+                                   MIR* mir, RegLocation rlSrc,
+                                   MipsLIR* labelList)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsConditionCode cond;
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
+    Opcode opcode = mir->dalvikInsn.opcode;
+    switch(opcode) {
+        case OP_IF_EQZ:
+            cond = kMipsCondEq;
+            break;
+        case OP_IF_NEZ:
+            cond = kMipsCondNe;
+            break;
+        case OP_IF_LTZ:
+            cond = kMipsCondLt;
+            break;
+        case OP_IF_GEZ:
+            cond = kMipsCondGe;
+            break;
+        case OP_IF_GTZ:
+            cond = kMipsCondGt;
+            break;
+        case OP_IF_LEZ:
+            cond = kMipsCondLe;
+            break;
+        default:
+            cond = (MipsConditionCode)0;
+            LOG(FATAL) << "Unexpected opcode " << (int)opcode;
+    }
+    genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
+    genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+#endif
+}
+
+STATIC void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                         RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+    if (rlSrc.location == kLocPhysReg) {
+        genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+    } else {
+        loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
+    }
+    opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
+                rlResult.lowReg, 31);
+    storeValueWide(cUnit, rlDest, rlResult);
+#endif
+}
+
+STATIC void genIntNarrowing(CompilationUnit* cUnit, MIR* mir,
+                            RegLocation rlDest, RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+     RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+     OpKind op = kOpInvalid;
+     switch(mir->dalvikInsn.opcode) {
+         case OP_INT_TO_BYTE:
+             op = kOp2Byte;
+             break;
+         case OP_INT_TO_SHORT:
+              op = kOp2Short;
+              break;
+         case OP_INT_TO_CHAR:
+              op = kOp2Char;
+              break;
+         default:
+             LOG(ERROR) << "Bad int conversion type";
+     }
+     opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
+     storeValue(cUnit, rlDest, rlResult);
+#endif
+}
+
+/*
+ * If there are any ins passed in registers that have not been promoted
+ * to a callee-save register, flush them to the frame.  Perform intial
+ * assignment of promoted arguments.
+ */
+STATIC void flushIns(CompilationUnit* cUnit)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    if (cUnit->numIns == 0)
+        return;
+    int firstArgReg = r1;
+    int lastArgReg = r3;
+    int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
+    /*
+     * Arguments passed in registers should be flushed
+     * to their backing locations in the frame for now.
+     * Also, we need to do initial assignment for promoted
+     * arguments.  NOTE: an older version of dx had an issue
+     * in which it would reuse static method argument registers.
+     * This could result in the same Dalvik virtual register
+     * being promoted to both core and fp regs.  In those
+     * cases, copy argument to both.  This will be uncommon
+     * enough that it isn't worth attempting to optimize.
+     */
+    for (int i = 0; i < cUnit->numIns; i++) {
+        PromotionMap vMap = cUnit->promotionMap[startVReg + i];
+        if (i <= (lastArgReg - firstArgReg)) {
+            // If arriving in register
+            if (vMap.coreLocation == kLocPhysReg) {
+                genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
+            }
+            if (vMap.fpLocation == kLocPhysReg) {
+                genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
+            }
+            // Also put a copy in memory in case we're partially promoted
+            storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                          firstArgReg + i, kWord);
+        } else {
+            // If arriving in frame & promoted
+            if (vMap.coreLocation == kLocPhysReg) {
+                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                             vMap.coreReg);
+            }
+            if (vMap.fpLocation == kLocPhysReg) {
+                loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
+                             vMap.fpReg);
+            }
+        }
+    }
+#endif
+}
+
+STATIC void genEntrySequence(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
+    /*
+     * On entry, r0, r1, r2 & r3 are live.  Let the register allocation
+     * mechanism know so it doesn't try to use any of them when
+     * expanding the frame or flushing.  This leaves the utility
+     * code with a single temp: r12.  This should be enough.
+     */
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+    oatLockTemp(cUnit, r2);
+    oatLockTemp(cUnit, r3);
+
+    /*
+     * We can safely skip the stack overflow check if we're
+     * a leaf *and* our frame size < fudge factor.
+     */
+    bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
+                              ((size_t)cUnit->frameSize <
+                              Thread::kStackOverflowReservedBytes));
+    newLIR0(cUnit, kMipsPseudoMethodEntry);
+    if (!skipOverflowCheck) {
+        /* Load stack limit */
+        loadWordDisp(cUnit, rSELF,
+                     Thread::StackEndOffset().Int32Value(), r12);
+    }
+    /* Spill core callee saves */
+    newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
+    /* Need to spill any FP regs? */
+    if (cUnit->numFPSpills) {
+        /*
+         * NOTE: fp spills are a little different from core spills in that
+         * they are pushed as a contiguous block.  When promoting from
+         * the fp set, we must allocate all singles from s16..highest-promoted
+         */
+        newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
+    }
+    if (!skipOverflowCheck) {
+        opRegRegImm(cUnit, kOpSub, rLR, rSP,
+                    cUnit->frameSize - (spillCount * 4));
+        genRegRegCheck(cUnit, kMipsCondCc, rLR, r12, NULL,
+                       kMipsThrowStackOverflow);
+        genRegCopy(cUnit, rSP, rLR);         // Establish stack
+    } else {
+        opRegImm(cUnit, kOpSub, rSP,
+                 cUnit->frameSize - (spillCount * 4));
+    }
+    storeBaseDisp(cUnit, rSP, 0, r0, kWord);
+    flushIns(cUnit);
+
+    if (cUnit->genDebugger) {
+        // Refresh update debugger callout
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
+        genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
+    }
+
+    oatFreeTemp(cUnit, r0);
+    oatFreeTemp(cUnit, r1);
+    oatFreeTemp(cUnit, r2);
+    oatFreeTemp(cUnit, r3);
+#endif
+}
+
+STATIC void genExitSequence(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
+    /*
+     * In the exit path, r0/r1 are live - make sure they aren't
+     * allocated by the register utilities as temps.
+     */
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+
+    newLIR0(cUnit, kMipsPseudoMethodExit);
+    /* If we're compiling for the debugger, generate an update callout */
+    if (cUnit->genDebugger) {
+        genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
+    }
+    opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
+    /* Need to restore any FP callee saves? */
+    if (cUnit->numFPSpills) {
+        newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
+    }
+    if (cUnit->coreSpillMask & (1 << rLR)) {
+        /* Unspill rLR to rPC */
+        cUnit->coreSpillMask &= ~(1 << rLR);
+        cUnit->coreSpillMask |= (1 << rPC);
+    }
+    newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
+    if (!(cUnit->coreSpillMask & (1 << rPC))) {
+        /* We didn't pop to rPC, so must do a bv rLR */
+        newLIR1(cUnit, kThumbBx, rLR);
+    }
+#endif
+}
+
+/*
+ * Nop any unconditional branches that go to the next instruction.
+ * Note: new redundant branches may be inserted later, and we'll
+ * use a check in final instruction assembly to nop those out.
+ */
+void removeRedundantBranches(CompilationUnit* cUnit)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsLIR* thisLIR;
+
+    for (thisLIR = (MipsLIR*) cUnit->firstLIRInsn;
+         thisLIR != (MipsLIR*) cUnit->lastLIRInsn;
+         thisLIR = NEXT_LIR(thisLIR)) {
+
+        /* Branch to the next instruction */
+        if ((thisLIR->opcode == kThumbBUncond) ||
+            (thisLIR->opcode == kThumb2BUncond)) {
+            MipsLIR* nextLIR = thisLIR;
+
+            while (true) {
+                nextLIR = NEXT_LIR(nextLIR);
+
+                /*
+                 * Is the branch target the next instruction?
+                 */
+                if (nextLIR == (MipsLIR*) thisLIR->generic.target) {
+                    thisLIR->flags.isNop = true;
+                    break;
+                }
+
+                /*
+                 * Found real useful stuff between the branch and the target.
+                 * Need to explicitly check the lastLIRInsn here because it
+                 * might be the last real instruction.
+                 */
+                if (!isPseudoOpcode(nextLIR->opcode) ||
+                    (nextLIR = (MipsLIR*) cUnit->lastLIRInsn))
+                    break;
+            }
+        }
+    }
+#endif
+}
+
+STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsLIR** suspendLabel =
+        (MipsLIR **) cUnit->suspendLaunchpads.elemList;
+    int numElems = cUnit->suspendLaunchpads.numUsed;
+
+    for (int i = 0; i < numElems; i++) {
+        /* TUNING: move suspend count load into helper */
+        MipsLIR* lab = suspendLabel[i];
+        MipsLIR* resumeLab = (MipsLIR*)lab->operands[0];
+        cUnit->currentDalvikOffset = lab->operands[1];
+        oatAppendLIR(cUnit, (LIR *)lab);
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
+        if (!cUnit->genDebugger) {
+            // use rSUSPEND for suspend count
+            loadWordDisp(cUnit, rSELF,
+                         Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
+        }
+        opReg(cUnit, kOpBlx, rLR);
+        if ( cUnit->genDebugger) {
+            // use rSUSPEND for update debugger
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
+        }
+        genUnconditionalBranch(cUnit, resumeLab);
+    }
+#endif
+}
+
+STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
+{
+    UNIMPLEMENTED(FATAL) << "Needs mips version";
+#if 0
+    MipsLIR** throwLabel =
+        (MipsLIR **) cUnit->throwLaunchpads.elemList;
+    int numElems = cUnit->throwLaunchpads.numUsed;
+    int i;
+
+    for (i = 0; i < numElems; i++) {
+        MipsLIR* lab = throwLabel[i];
+        cUnit->currentDalvikOffset = lab->operands[1];
+        oatAppendLIR(cUnit, (LIR *)lab);
+        int funcOffset = 0;
+        int v1 = lab->operands[2];
+        int v2 = lab->operands[3];
+        switch(lab->operands[0]) {
+            case kMipsThrowNullPointer:
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
+                break;
+            case kMipsThrowArrayBounds:
+                if (v2 != r0) {
+                    genRegCopy(cUnit, r0, v1);
+                    genRegCopy(cUnit, r1, v2);
+                } else {
+                    if (v1 == r1) {
+                        genRegCopy(cUnit, r12, v1);
+                        genRegCopy(cUnit, r1, v2);
+                        genRegCopy(cUnit, r0, r12);
+                    } else {
+                        genRegCopy(cUnit, r1, v2);
+                        genRegCopy(cUnit, r0, v1);
+                    }
+                }
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
+                break;
+            case kMipsThrowDivZero:
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
+                break;
+            case kMipsThrowVerificationError:
+                loadConstant(cUnit, r0, v1);
+                loadConstant(cUnit, r1, v2);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
+                break;
+            case kMipsThrowNegArraySize:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
+                break;
+            case kMipsThrowNoSuchMethod:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
+                break;
+            case kMipsThrowStackOverflow:
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
+                // Restore stack alignment
+                opRegImm(cUnit, kOpAdd, rSP,
+                         (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
+                break;
+            default:
+                LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
+        }
+        loadWordDisp(cUnit, rSELF, funcOffset, rLR);
+        callRuntimeHelper(cUnit, rLR);
+    }
+#endif
+}
+
+/* Common initialization routine for an architecture family */
+bool oatArchInit()
+{
+    int i;
+
+    for (i = 0; i < kMipsLast; i++) {
+        if (EncodingMap[i].opcode != i) {
+            LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
+               " is wrong: expecting " << i << ", seeing " <<
+               (int)EncodingMap[i].opcode;
+        }
+    }
+
+    return oatArchVariantInit();
+}
+
+/* Needed by the Assembler */
+void oatSetupResourceMasks(MipsLIR* lir)
+{
+    setupResourceMasks(lir);
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/ArchUtility.cc b/src/compiler/codegen/mips/ArchUtility.cc
new file mode 100644
index 0000000..f218436
--- /dev/null
+++ b/src/compiler/codegen/mips/ArchUtility.cc
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../../CompilerInternals.h"
+#include "MipsLIR.h"
+#include "../Ralloc.h"
+
+#include <string>
+
+namespace art {
+
+/* For dumping instructions */
+#define MIPS_REG_COUNT 32
+static const char *mipsRegName[MIPS_REG_COUNT] = {
+    "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+    "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+    "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+    "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
+};
+
+/*
+ * Interpret a format string and build a string no longer than size
+ * See format key in Assemble.c.
+ */
+STATIC std::string buildInsnString(const char *fmt, MipsLIR *lir, unsigned char* baseAddr)
+{
+    std::string buf;
+    int i;
+    const char *fmtEnd = &fmt[strlen(fmt)];
+    char tbuf[256];
+    char nc;
+    while (fmt < fmtEnd) {
+        int operand;
+        if (*fmt == '!') {
+            fmt++;
+            DCHECK_LT(fmt, fmtEnd);
+            nc = *fmt++;
+            if (nc=='!') {
+                strcpy(tbuf, "!");
+            } else {
+               DCHECK_LT(fmt, fmtEnd);
+               DCHECK_LT((unsigned)(nc-'0'), 4u);
+               operand = lir->operands[nc-'0'];
+               switch(*fmt++) {
+                   case 'b':
+                       strcpy(tbuf,"0000");
+                       for (i=3; i>= 0; i--) {
+                           tbuf[i] += operand & 1;
+                           operand >>= 1;
+                       }
+                       break;
+                   case 's':
+                       sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
+                       break;
+                   case 'S':
+                       DCHECK_EQ(((operand & FP_REG_MASK) & 1), 0);
+                       sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
+                       break;
+                   case 'h':
+                       sprintf(tbuf,"%04x", operand);
+                       break;
+                   case 'M':
+                   case 'd':
+                       sprintf(tbuf,"%d", operand);
+                       break;
+                   case 'D':
+                       sprintf(tbuf,"%d", operand+1);
+                       break;
+                   case 'E':
+                       sprintf(tbuf,"%d", operand*4);
+                       break;
+                   case 'F':
+                       sprintf(tbuf,"%d", operand*2);
+                       break;
+                   case 'c':
+                       switch (operand) {
+                           case kMipsCondEq:
+                               strcpy(tbuf, "eq");
+                               break;
+                           case kMipsCondNe:
+                               strcpy(tbuf, "ne");
+                               break;
+                           case kMipsCondLt:
+                               strcpy(tbuf, "lt");
+                               break;
+                           case kMipsCondGe:
+                               strcpy(tbuf, "ge");
+                               break;
+                           case kMipsCondGt:
+                               strcpy(tbuf, "gt");
+                               break;
+                           case kMipsCondLe:
+                               strcpy(tbuf, "le");
+                               break;
+                           case kMipsCondCs:
+                               strcpy(tbuf, "cs");
+                               break;
+                           case kMipsCondMi:
+                               strcpy(tbuf, "mi");
+                               break;
+                           default:
+                               strcpy(tbuf, "");
+                               break;
+                       }
+                       break;
+                   case 't':
+                       sprintf(tbuf,"0x%08x (L%p)",
+                               (int) baseAddr + lir->generic.offset + 4 +
+                               (operand << 2),
+                               lir->generic.target);
+                       break;
+                   case 'T':
+                       sprintf(tbuf,"0x%08x",
+                               (int) (operand << 2));
+                       break;
+                   case 'u': {
+                       int offset_1 = lir->operands[0];
+                       int offset_2 = NEXT_LIR(lir)->operands[0];
+                       intptr_t target =
+                           ((((intptr_t) baseAddr + lir->generic.offset + 4) &
+                            ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
+                           0xfffffffc;
+                       sprintf(tbuf, "%p", (void *) target);
+                       break;
+                    }
+
+                   /* Nothing to print for BLX_2 */
+                   case 'v':
+                       strcpy(tbuf, "see above");
+                       break;
+                   case 'r':
+                       DCHECK(operand >= 0 && operand < MIPS_REG_COUNT);
+                       strcpy(tbuf, mipsRegName[operand]);
+                       break;
+                   default:
+                       strcpy(tbuf,"DecodeError");
+                       break;
+               }
+               buf += tbuf;
+            }
+        } else {
+           buf += *fmt++;
+        }
+    }
+    return buf;
+}
+
+// FIXME: need to redo resourse maps for MIPS - fix this at that time
+void oatDumpResourceMask(LIR *lir, u8 mask, const char *prefix)
+{
+    char buf[256];
+    buf[0] = 0;
+    MipsLIR *mipsLIR = (MipsLIR *) lir;
+
+    if (mask == ENCODE_ALL) {
+        strcpy(buf, "all");
+    } else {
+        char num[8];
+        int i;
+
+        for (i = 0; i < kRegEnd; i++) {
+            if (mask & (1ULL << i)) {
+                sprintf(num, "%d ", i);
+                strcat(buf, num);
+            }
+        }
+
+        if (mask & ENCODE_CCODE) {
+            strcat(buf, "cc ");
+        }
+        if (mask & ENCODE_FP_STATUS) {
+            strcat(buf, "fpcc ");
+        }
+        /* Memory bits */
+        if (mipsLIR && (mask & ENCODE_DALVIK_REG)) {
+            sprintf(buf + strlen(buf), "dr%d%s", mipsLIR->aliasInfo & 0xffff,
+                    (mipsLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
+        }
+        if (mask & ENCODE_LITERAL) {
+            strcat(buf, "lit ");
+        }
+
+        if (mask & ENCODE_HEAP_REF) {
+            strcat(buf, "heap ");
+        }
+        if (mask & ENCODE_MUST_NOT_ALIAS) {
+            strcat(buf, "noalias ");
+        }
+    }
+    if (buf[0]) {
+        LOG(INFO) << prefix << ": " <<  buf;
+    }
+}
+
+/*
+ * Debugging macros
+ */
+#define DUMP_RESOURCE_MASK(X)
+#define DUMP_SSA_REP(X)
+
+/* Pretty-print a LIR instruction */
+void oatDumpLIRInsn(CompilationUnit* cUnit, LIR* arg, unsigned char* baseAddr)
+{
+    MipsLIR* lir = (MipsLIR*) arg;
+    int offset = lir->generic.offset;
+    int dest = lir->operands[0];
+    const bool dumpNop = false;
+
+    /* Handle pseudo-ops individually, and all regular insns as a group */
+    switch(lir->opcode) {
+        case kMipsPseudoMethodEntry:
+            LOG(INFO) << "-------- method entry " <<
+                PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
+            break;
+        case kMipsPseudoMethodExit:
+            LOG(INFO) << "-------- Method_Exit";
+            break;
+        case kMipsPseudoBarrier:
+            LOG(INFO) << "-------- BARRIER";
+            break;
+        case kMipsPseudoExtended:
+            LOG(INFO) << "-------- " << (char* ) dest;
+            break;
+        case kMipsPseudoSSARep:
+            DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " <<  (char* ) dest);
+            break;
+        case kMipsPseudoEntryBlock:
+            LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest;
+            break;
+        case kMipsPseudoDalvikByteCodeBoundary:
+            LOG(INFO) << "-------- dalvik offset: 0x" << std::hex <<
+                 lir->generic.dalvikOffset << " @ " << (char* )lir->operands[0];
+            break;
+        case kMipsPseudoExitBlock:
+            LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest;
+            break;
+        case kMipsPseudoPseudoAlign4:
+            LOG(INFO) << (intptr_t)baseAddr + offset << " (0x" << std::hex <<
+                offset << "): .align4";
+            break;
+        case kMipsPseudoEHBlockLabel:
+            LOG(INFO) << "Exception_Handling:";
+            break;
+        case kMipsPseudoTargetLabel:
+        case kMipsPseudoNormalBlockLabel:
+            LOG(INFO) << "L" << (intptr_t)lir << ":";
+            break;
+        case kMipsPseudoThrowTarget:
+            LOG(INFO) << "LT" << (intptr_t)lir << ":";
+            break;
+        case kMipsPseudoSuspendTarget:
+            LOG(INFO) << "LS" << (intptr_t)lir << ":";
+            break;
+        case kMipsPseudoCaseLabel:
+            LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" <<
+                std::hex << lir->operands[0] << "|" << std::dec <<
+                lir->operands[0];
+            break;
+        default:
+            if (lir->flags.isNop && !dumpNop) {
+                break;
+            } else {
+                std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr));
+                std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr));
+                LOG(INFO) << StringPrintf("%p (%04x): %-9s%s%s", baseAddr + offset, offset,
+                    op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : "");
+            }
+            break;
+    }
+
+    if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
+        DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
+                                               lir->useMask, "use"));
+    }
+    if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
+        DUMP_RESOURCE_MASK(oatDumpResourceMask((LIR* ) lir,
+                                               lir->defMask, "def"));
+    }
+}
+
+void oatDumpPromotionMap(CompilationUnit *cUnit)
+{
+    for (int i = 0; i < cUnit->numDalvikRegisters; i++) {
+        PromotionMap vRegMap = cUnit->promotionMap[i];
+        char buf[100];
+        if (vRegMap.fpLocation == kLocPhysReg) {
+            snprintf(buf, 100, " : s%d", vRegMap.fpReg & FP_REG_MASK);
+        } else {
+            buf[0] = 0;
+        }
+        char buf2[100];
+        snprintf(buf2, 100, "V[%02d] -> %s%d%s", i,
+                 vRegMap.coreLocation == kLocPhysReg ?
+                 "r" : "SP+", vRegMap.coreLocation == kLocPhysReg ?
+                 vRegMap.coreReg : oatSRegOffset(cUnit, i), buf);
+        LOG(INFO) << buf2;
+    }
+}
+
+void oatDumpFullPromotionMap(CompilationUnit *cUnit)
+{
+    for (int i = 0; i < cUnit->numDalvikRegisters; i++) {
+        PromotionMap vRegMap = cUnit->promotionMap[i];
+        LOG(INFO) << i << " -> " << "CL:" << (int)vRegMap.coreLocation <<
+            ", CR:" << (int)vRegMap.coreReg << ", FL:" <<
+            (int)vRegMap.fpLocation << ", FR:" << (int)vRegMap.fpReg <<
+            ", - " << (int)vRegMap.firstInPair;
+    }
+}
+
+/* Dump instructions and constant pool contents */
+void oatCodegenDump(CompilationUnit* cUnit)
+{
+    LOG(INFO) << "/*";
+    LOG(INFO) << "Dumping LIR insns for "
+        << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
+    LIR* lirInsn;
+    MipsLIR* mipsLIR;
+    int insnsSize = cUnit->insnsSize;
+
+    LOG(INFO) << "Regs (excluding ins) : " << cUnit->numRegs;
+    LOG(INFO) << "Ins                  : " << cUnit->numIns;
+    LOG(INFO) << "Outs                 : " << cUnit->numOuts;
+    LOG(INFO) << "CoreSpills           : " << cUnit->numCoreSpills;
+    LOG(INFO) << "FPSpills             : " << cUnit->numFPSpills;
+    LOG(INFO) << "Padding              : " << cUnit->numPadding;
+    LOG(INFO) << "Frame size           : " << cUnit->frameSize;
+    LOG(INFO) << "Start of ins         : " << cUnit->insOffset;
+    LOG(INFO) << "Start of regs        : " << cUnit->regsOffset;
+    LOG(INFO) << "code size is " << cUnit->totalSize <<
+        " bytes, Dalvik size is " << insnsSize * 2;
+    LOG(INFO) << "expansion factor: " <<
+         (float)cUnit->totalSize / (float)(insnsSize * 2);
+    oatDumpPromotionMap(cUnit);
+    for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
+        oatDumpLIRInsn(cUnit, lirInsn, 0);
+    }
+    for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
+        mipsLIR = (MipsLIR*) lirInsn;
+        LOG(INFO) << StringPrintf("%x (%04x): .class (%s)",
+            mipsLIR->generic.offset, mipsLIR->generic.offset,
+            ((CallsiteInfo *) mipsLIR->operands[0])->classDescriptor);
+    }
+    for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
+        mipsLIR = (MipsLIR*) lirInsn;
+        LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)",
+            mipsLIR->generic.offset, mipsLIR->generic.offset, mipsLIR->operands[0]);
+    }
+
+    const DexFile::MethodId& method_id =
+        cUnit->dex_file->GetMethodId(cUnit->method_idx);
+    std::string signature(cUnit->dex_file->GetMethodSignature(method_id));
+    std::string name(cUnit->dex_file->GetMethodName(method_id));
+    std::string descriptor(cUnit->dex_file->GetMethodDeclaringClassDescriptor(method_id));
+
+    // Dump mapping table
+    if (cUnit->mappingTable.size() > 0) {
+        std::string line(StringPrintf("\n    MappingTable %s%s_%s_mappingTable[%zu] = {",
+            descriptor.c_str(), name.c_str(), signature.c_str(), cUnit->mappingTable.size()));
+        std::replace(line.begin(), line.end(), ';', '_');
+        LOG(INFO) << line;
+        for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) {
+            line = StringPrintf("        {0x%08x, 0x%04x},",
+                cUnit->mappingTable[i], cUnit->mappingTable[i+1]);
+            LOG(INFO) << line;
+        }
+        LOG(INFO) <<"    };\n\n";
+    }
+}
+
+} // namespace art
diff --git a/src/compiler/codegen/mips/Assemble.cc b/src/compiler/codegen/mips/Assemble.cc
new file mode 100644
index 0000000..9e8af2a
--- /dev/null
+++ b/src/compiler/codegen/mips/Assemble.cc
@@ -0,0 +1,557 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../../Dalvik.h"
+#include "../../CompilerInternals.h"
+#include "MipsLIR.h"
+#include "Codegen.h"
+#include <sys/mman.h>           /* for protection change */
+
+namespace art {
+
+#define MAX_ASSEMBLER_RETRIES 50
+
+/*
+ * opcode: MipsOpCode enum
+ * skeleton: pre-designated bit-pattern for this opcode
+ * k0: key to applying ds/de
+ * ds: dest start bit position
+ * de: dest end bit position
+ * k1: key to applying s1s/s1e
+ * s1s: src1 start bit position
+ * s1e: src1 end bit position
+ * k2: key to applying s2s/s2e
+ * s2s: src2 start bit position
+ * s2e: src2 end bit position
+ * operands: number of operands (for sanity check purposes)
+ * name: mnemonic name
+ * fmt: for pretty-printing
+ */
+#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
+                     k3, k3s, k3e, flags, name, fmt, size) \
+        {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
+                    {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
+
+/* Instruction dump string format keys: !pf, where "!" is the start
+ * of the key, "p" is which numeric operand to use and "f" is the
+ * print format.
+ *
+ * [p]ositions:
+ *     0 -> operands[0] (dest)
+ *     1 -> operands[1] (src1)
+ *     2 -> operands[2] (src2)
+ *     3 -> operands[3] (extra)
+ *
+ * [f]ormats:
+ *     h -> 4-digit hex
+ *     d -> decimal
+ *     E -> decimal*4
+ *     F -> decimal*2
+ *     c -> branch condition (beq, bne, etc.)
+ *     t -> pc-relative target
+ *     T -> pc-region target
+ *     u -> 1st half of bl[x] target
+ *     v -> 2nd half ob bl[x] target
+ *     R -> register list
+ *     s -> single precision floating point register
+ *     S -> double precision floating point register
+ *     m -> Thumb2 modified immediate
+ *     n -> complimented Thumb2 modified immediate
+ *     M -> Thumb2 16-bit zero-extended immediate
+ *     b -> 4-digit binary
+ *
+ *  [!] escape.  To insert "!", use "!!"
+ */
+/* NOTE: must be kept in sync with enum MipsOpcode from MipsLIR.h */
+MipsEncodingMap EncodingMap[kMipsLast] = {
+    ENCODING_MAP(kMips32BitData, 0x00000000,
+                 kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP,
+                 "data", "0x!0h(!0d)", 2),
+    ENCODING_MAP(kMipsAddiu, 0x24000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "addiu", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsAddu, 0x00000021,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "addu", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsAnd, 0x00000024,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "and", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsAndi, 0x30000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "andi", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsB, 0x10000000,
+                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
+                 "b", "!0t", 2),
+    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", 2),
+    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", 2),
+    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", 2),
+    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", 2),
+    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", 2),
+    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", 2),
+    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", 2),
+    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", 2),
+    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", 2),
+    ENCODING_MAP(kMipsDiv, 0x0000001a,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
+                 kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
+                 "div", "!2r,!3r", 2),
+#if __mips_isa_rev>=2
+    ENCODING_MAP(kMipsExt, 0x7c000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 10, 6,
+                 kFmtBitBlt, 15, 11, IS_QUAD_OP | REG_DEF0 | REG_USE1,
+                 "ext", "!0r,!1r,!2d,!3D", 2),
+#endif
+    ENCODING_MAP(kMipsJal, 0x0c000000,
+                 kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
+                 "jal", "!0T(!0E)", 2),
+    ENCODING_MAP(kMipsJalr, 0x00000009,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF0_USE1,
+                 "jalr", "!0r,!1r", 2),
+    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", 2),
+    ENCODING_MAP(kMipsLahi, 0x3C000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "lahi/lui", "!0r,0x!1h(!1d)", 2),
+    ENCODING_MAP(kMipsLalo, 0x34000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "lalo/ori", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsLui, 0x3C000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "lui", "!0r,0x!1h(!1d)", 2),
+    ENCODING_MAP(kMipsLb, 0x80000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lb", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsLbu, 0x90000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lbu", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsLh, 0x84000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lh", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsLhu, 0x94000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lhu", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsLw, 0x8C000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lw", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsMfhi, 0x00000010,
+                 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mfhi", "!0r", 2),
+    ENCODING_MAP(kMipsMflo, 0x00000012,
+                 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mflo", "!0r", 2),
+    ENCODING_MAP(kMipsMove, 0x00000025, /* or using zero reg */
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "move", "!0r,!1r", 2),
+    ENCODING_MAP(kMipsMovz, 0x0000000a,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "movz", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsMul, 0x70000002,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "mul", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsNop, 0x00000000,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND,
+                 "nop", "", 2),
+    ENCODING_MAP(kMipsNor, 0x00000027, /* used for "not" too */
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "nor", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsOr, 0x00000025,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "or", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsOri, 0x34000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "ori", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsPref, 0xCC000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE2,
+                 "pref", "!0d,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsSb, 0xA0000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+                 "sb", "!0r,!1d(!2r)", 2),
+#if __mips_isa_rev>=2
+    ENCODING_MAP(kMipsSeb, 0x7c000420,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "seb", "!0r,!1r", 2),
+    ENCODING_MAP(kMipsSeh, 0x7c000620,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "seh", "!0r,!1r", 2),
+#endif
+    ENCODING_MAP(kMipsSh, 0xA4000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+                 "sh", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsSll, 0x00000000,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "sll", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsSllv, 0x00000004,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "sllv", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSlt, 0x0000002a,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "slt", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSlti, 0x28000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "slti", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsSltu, 0x0000002b,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "sltu", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSra, 0x00000003,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "sra", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsSrav, 0x00000007,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "srav", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSrl, 0x00000002,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "srl", "!0r,!1r,0x!2h(!2d)", 2),
+    ENCODING_MAP(kMipsSrlv, 0x00000006,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "srlv", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSubu, 0x00000023, /* used for "neg" too */
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "subu", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsSw, 0xAC000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+                 "sw", "!0r,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsXor, 0x00000026,
+                 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "xor", "!0r,!1r,!2r", 2),
+    ENCODING_MAP(kMipsXori, 0x38000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "xori", "!0r,!1r,0x!2h(!2d)", 2),
+#ifdef __mips_hard_float
+    ENCODING_MAP(kMipsFadds, 0x46000000,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "add.s", "!0s,!1s,!2s", 2),
+    ENCODING_MAP(kMipsFsubs, 0x46000001,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "sub.s", "!0s,!1s,!2s", 2),
+    ENCODING_MAP(kMipsFmuls, 0x46000002,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "mul.s", "!0s,!1s,!2s", 2),
+    ENCODING_MAP(kMipsFdivs, 0x46000003,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "div.s", "!0s,!1s,!2s", 2),
+    ENCODING_MAP(kMipsFaddd, 0x46200000,
+                 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "add.d", "!0S,!1S,!2S", 2),
+    ENCODING_MAP(kMipsFsubd, 0x46200001,
+                 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "sub.d", "!0S,!1S,!2S", 2),
+    ENCODING_MAP(kMipsFmuld, 0x46200002,
+                 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "mul.d", "!0S,!1S,!2S", 2),
+    ENCODING_MAP(kMipsFdivd, 0x46200003,
+                 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
+                 "div.d", "!0S,!1S,!2S", 2),
+    ENCODING_MAP(kMipsFcvtsd, 0x46200020,
+                 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.s.d", "!0s,!1S", 2),
+    ENCODING_MAP(kMipsFcvtsw, 0x46800020,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.s.w", "!0s,!1s", 2),
+    ENCODING_MAP(kMipsFcvtds, 0x46000021,
+                 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.d.s", "!0S,!1s", 2),
+    ENCODING_MAP(kMipsFcvtdw, 0x46800021,
+                 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.d.w", "!0S,!1s", 2),
+    ENCODING_MAP(kMipsFcvtws, 0x46000024,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.w.s", "!0s,!1s", 2),
+    ENCODING_MAP(kMipsFcvtwd, 0x46200024,
+                 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "cvt.w.d", "!0s,!1S", 2),
+    ENCODING_MAP(kMipsFmovs, 0x46000006,
+                 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mov.s", "!0s,!1s", 2),
+    ENCODING_MAP(kMipsFmovd, 0x46200006,
+                 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mov.d", "!0S,!1S", 2),
+    ENCODING_MAP(kMipsFlwc1, 0xC4000000,
+                 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "lwc1", "!0s,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsFldc1, 0xD4000000,
+                 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
+                 "ldc1", "!0S,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsFswc1, 0xE4000000,
+                 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+                 "swc1", "!0s,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsFsdc1, 0xF4000000,
+                 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
+                 "sdc1", "!0S,!1d(!2r)", 2),
+    ENCODING_MAP(kMipsMfc1, 0x44000000,
+                 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "mfc1", "!0r,!1s", 2),
+    ENCODING_MAP(kMipsMtc1, 0x44800000,
+                 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
+                 "mtc1", "!0r,!1s", 2),
+#endif
+    ENCODING_MAP(kMipsUndefined, 0x64000000,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND,
+                 "undefined", "", 2),
+};
+
+/*
+ * Assemble the LIR into binary instruction format.  Note that we may
+ * discover that pc-relative displacements may not fit the selected
+ * instruction.  In those cases we will try to substitute a new code
+ * sequence or request that the trace be shortened and retried.
+ */
+AssemblerStatus oatAssembleInstructions(CompilationUnit *cUnit,
+                                        intptr_t startAddr)
+{
+    UNIMPLEMENTED(FATAL) << "Rework for art code buffer";
+#if 0
+    int *bufferAddr = (int *) cUnit->codeBuffer;
+    MipsLIR *lir;
+
+    for (lir = (MipsLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
+        if (lir->opcode < 0) {
+            continue;
+        }
+
+
+        if (lir->flags.isNop) {
+            continue;
+        }
+
+        if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
+            MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+            intptr_t pc = lir->generic.offset + 4;
+            intptr_t target = targetLIR->generic.offset;
+            int delta = target - pc;
+            if (delta & 0x3) {
+                LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
+            }
+            if (delta > 131068 || delta < -131069) {
+                LOG(FATAL) << "Unconditional branch out of range: " << delta;
+            }
+            lir->operands[0] = delta >> 2;
+        } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
+            MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+            intptr_t pc = lir->generic.offset + 4;
+            intptr_t target = targetLIR->generic.offset;
+            int delta = target - pc;
+            if (delta & 0x3) {
+                LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
+            }
+            if (delta > 131068 || delta < -131069) {
+                LOG(FATAL) << "Conditional branch out of range: " << delta;
+            }
+            lir->operands[1] = delta >> 2;
+        } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
+            MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+            intptr_t pc = lir->generic.offset + 4;
+            intptr_t target = targetLIR->generic.offset;
+            int delta = target - pc;
+            if (delta & 0x3) {
+                LOG(FATAL) << "PC-rel offset not multiple of 4: " << delta;
+            }
+            if (delta > 131068 || delta < -131069) {
+                LOG(FATAL) << "Conditional branch out of range: " << delta;
+            }
+            lir->operands[2] = delta >> 2;
+        } else if (lir->opcode == kMipsJal) {
+            intptr_t curPC = (startAddr + lir->generic.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) */
+            MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+            intptr_t target = startAddr + targetLIR->generic.offset;
+            lir->operands[1] = target >> 16;
+        } else if (lir->opcode == kMipsLalo) { /* load address lo (via ori) */
+            MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
+            intptr_t target = startAddr + targetLIR->generic.offset;
+            lir->operands[2] = lir->operands[2] + target;
+        }
+
+        MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
+        u4 bits = encoder->skeleton;
+        int i;
+        for (i = 0; i < 4; i++) {
+            u4 operand;
+            u4 value;
+            operand = lir->operands[i];
+            switch(encoder->fieldLoc[i].kind) {
+                case kFmtUnused:
+                    break;
+                case kFmtBitBlt:
+                    if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) {
+                        value = operand;
+                    } else {
+                        value = (operand << encoder->fieldLoc[i].start) &
+                                ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+                    }
+                    bits |= value;
+                    break;
+                case kFmtDfp: {
+                    DCHECK(DOUBLEREG(operand));
+                    DCHECK_EQ((operand & 0x1), 0);
+                    value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
+                            ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+                    bits |= value;
+                    break;
+                }
+                case kFmtSfp:
+                    DCHECK(SINGLEREG(operand));
+                    value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
+                            ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+                    bits |= value;
+                    break;
+                default:
+                    LOG(FATAL) << "Bad encoder format: "
+                               << encoder->fieldLoc[i].kind;
+            }
+        }
+        DCHECK_EQ(encoder->size, 2);
+        *bufferAddr++ = bits;
+    }
+#endif
+    return kSuccess;
+}
+
+/*
+ * Target-dependent offset assignment.
+ * TODO: normalize usage of flags.size and make this target
+ * independent.
+ */
+int oatAssignInsnOffsets(CompilationUnit* cUnit)
+{
+    MipsLIR* mipsLIR;
+    int offset = 0;
+
+    for (mipsLIR = (MipsLIR *) cUnit->firstLIRInsn;
+         mipsLIR;
+         mipsLIR = NEXT_LIR(mipsLIR)) {
+        mipsLIR->generic.offset = offset;
+        if (mipsLIR->opcode >= 0) {
+            if (!mipsLIR->flags.isNop) {
+                mipsLIR->flags.size = EncodingMap[mipsLIR->opcode].size * 2;
+                offset += mipsLIR->flags.size;
+            }
+        } else if (mipsLIR->opcode == kMipsPseudoPseudoAlign4) {
+            if (offset & 0x2) {
+                offset += 2;
+                mipsLIR->operands[0] = 1;
+            } else {
+                mipsLIR->operands[0] = 0;
+            }
+        }
+        /* Pseudo opcodes don't consume space */
+    }
+
+    return offset;
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/Codegen.h b/src/compiler/codegen/mips/Codegen.h
new file mode 100644
index 0000000..b350dae
--- /dev/null
+++ b/src/compiler/codegen/mips/Codegen.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains register alloction support and is intended to be
+ * included by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "../../CompilerIR.h"
+
+namespace art {
+
+#if defined(_CODEGEN_C)
+/*
+ * loadConstant() sometimes needs to add a small imm to a pre-existing constant
+ */
+STATIC MipsLIR *opRegImm(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
+                        int value);
+STATIC MipsLIR *opRegReg(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
+                        int rSrc2);
+
+/* Forward decalraton the portable versions due to circular dependency */
+STATIC bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
+                                    RegLocation rlDest, RegLocation rlSrc1,
+                                    RegLocation rlSrc2);
+
+STATIC bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
+                                     RegLocation rlDest, RegLocation rlSrc1,
+                                     RegLocation rlSrc2);
+
+STATIC bool genConversionPortable(CompilationUnit* cUnit, MIR* mir);
+
+#endif
+
+extern void oatSetupResourceMasks(MipsLIR* lir);
+
+extern MipsLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest,
+                                          int rSrc);
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/CodegenCommon.cc b/src/compiler/codegen/mips/CodegenCommon.cc
new file mode 100644
index 0000000..3645643
--- /dev/null
+++ b/src/compiler/codegen/mips/CodegenCommon.cc
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+/*
+ * This file contains codegen and support common to all supported
+ * Mips variants.  It is included by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ * which combines this common code with specific support found in the
+ * applicable directory below this one.
+ */
+
+/* Track exercised opcodes */
+static int opcodeCoverage[kNumPackedOpcodes];
+
+static void setMemRefType(MipsLIR *lir, bool isLoad, int memType)
+{
+    /* MIPSTODO simplify setMemRefType() */
+    u8 *maskPtr;
+    u8 mask = ENCODE_MEM;;
+    DCHECK(EncodingMap[lir->opcode].flags & (IS_LOAD | IS_STORE));
+
+    if (isLoad) {
+        maskPtr = &lir->useMask;
+    } else {
+        maskPtr = &lir->defMask;
+    }
+    /* Clear out the memref flags */
+    *maskPtr &= ~mask;
+    /* ..and then add back the one we need */
+    switch(memType) {
+        case kLiteral:
+            DCHECK(isLoad);
+            *maskPtr |= ENCODE_LITERAL;
+            break;
+        case kDalvikReg:
+            *maskPtr |= ENCODE_DALVIK_REG;
+            break;
+        case kHeapRef:
+            *maskPtr |= ENCODE_HEAP_REF;
+            break;
+        case kMustNotAlias:
+            /* Currently only loads can be marked as kMustNotAlias */
+            DCHECK(!(EncodingMap[lir->opcode].flags & IS_STORE));
+            *maskPtr |= ENCODE_MUST_NOT_ALIAS;
+            break;
+        default:
+            LOG(FATAL) << "Oat: invalid memref kind - " << memType;
+    }
+}
+
+/*
+ * Mark load/store instructions that access Dalvik registers through rFP +
+ * offset.
+ */
+STATIC void annotateDalvikRegAccess(MipsLIR *lir, int regId, bool isLoad)
+{
+    /* MIPSTODO simplify annotateDalvikRegAccess() */
+    setMemRefType(lir, isLoad, kDalvikReg);
+
+    /*
+     * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
+     * access.
+     */
+    lir->aliasInfo = regId;
+    if (DOUBLEREG(lir->operands[0])) {
+        lir->aliasInfo |= 0x80000000;
+    }
+}
+
+/*
+ * Decode the register id
+ */
+STATIC inline u8 getRegMaskCommon(int reg)
+{
+    u8 seed;
+    int shift;
+    int regId = reg & 0x1f;
+
+    /*
+     * Each double register is equal to a pair of single-precision FP registers
+     */
+    if (!DOUBLEREG(reg)) {
+        seed = 1;
+    } else {
+        DCHECK_EQ((regId & 1), 0); /* double registers must be even */
+        seed = 3;
+    }
+
+    if (FPREG(reg)) {
+       DCHECK_LT(regId, 16); /* only 16 fp regs */
+       shift = kFPReg0;
+    } else if (EXTRAREG(reg)) {
+       DCHECK_LT(regId, 3); /* only 3 extra regs */
+       shift = kFPRegEnd;
+    } else {
+       shift = 0;
+    }
+
+    /* Expand the double register id into single offset */
+    shift += regId;
+    return (seed << shift);
+}
+
+/*
+ * Mark the corresponding bit(s).
+ */
+STATIC inline void setupRegMask(u8 *mask, int reg)
+{
+    *mask |= getRegMaskCommon(reg);
+}
+
+/*
+ * Set up the proper fields in the resource mask
+ */
+STATIC void setupResourceMasks(MipsLIR *lir)
+{
+    /* MIPSTODO simplify setupResourceMasks() */
+    int opcode = lir->opcode;
+    int flags;
+
+    if (opcode <= 0) {
+        lir->useMask = lir->defMask = 0;
+        return;
+    }
+
+    flags = EncodingMap[lir->opcode].flags;
+
+    // TODO: do we need this for MIPS?  if so, add to inst table defs
+#if 0
+    if (flags & NEEDS_FIXUP) {
+        lir->flags.pcRelFixup = true;
+    }
+#endif
+
+    /* Set up the mask for resources that are updated */
+    if (flags & (IS_LOAD | IS_STORE)) {
+        /* Default to heap - will catch specialized classes later */
+        setMemRefType(lir, flags & IS_LOAD, kHeapRef);
+    }
+
+    /*
+     * Conservatively assume the branch here will call out a function that in
+     * turn will trash everything.
+     */
+    if (flags & IS_BRANCH) {
+        lir->defMask = lir->useMask = ENCODE_ALL;
+        return;
+    }
+
+    if (flags & REG_DEF0) {
+        setupRegMask(&lir->defMask, lir->operands[0]);
+    }
+
+    if (flags & REG_DEF1) {
+        setupRegMask(&lir->defMask, lir->operands[1]);
+    }
+
+    if (flags & REG_DEF_SP) {
+        lir->defMask |= ENCODE_REG_SP;
+    }
+
+    if (flags & REG_DEF_LR) {
+        lir->defMask |= ENCODE_REG_LR;
+    }
+
+    if (flags & REG_DEF_LIST0) {
+        lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
+    }
+
+    if (flags & REG_DEF_LIST1) {
+        lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
+    }
+
+    if (flags & SETS_CCODES) {
+        lir->defMask |= ENCODE_CCODE;
+    }
+
+    // TODO: needed for MIPS?
+    /* Conservatively treat the IT block */
+    if (flags & IS_IT) {
+        lir->defMask = ENCODE_ALL;
+    }
+
+    if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+        int i;
+
+        for (i = 0; i < 4; i++) {
+            if (flags & (1 << (kRegUse0 + i))) {
+                setupRegMask(&lir->useMask, lir->operands[i]);
+            }
+        }
+    }
+
+    if (flags & REG_USE_PC) {
+        lir->useMask |= ENCODE_REG_PC;
+    }
+
+    if (flags & REG_USE_SP) {
+        lir->useMask |= ENCODE_REG_SP;
+    }
+
+    if (flags & REG_USE_LIST0) {
+        lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
+    }
+
+    if (flags & REG_USE_LIST1) {
+        lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
+    }
+
+    if (flags & USES_CCODES) {
+        lir->useMask |= ENCODE_CCODE;
+    }
+}
+
+/*
+ * Set up the accurate resource mask for branch instructions
+ */
+static void relaxBranchMasks(MipsLIR *lir)
+{
+    int flags = EncodingMap[lir->opcode].flags;
+
+    /* Make sure only branch instructions are passed here */
+    DCHECK(flags & IS_BRANCH);
+
+    lir->defMask |= ENCODE_REG_PC;
+    lir->useMask |= ENCODE_REG_PC;
+
+
+    if (flags & REG_DEF_LR) {
+        lir->defMask |= ENCODE_REG_LR;
+    }
+
+    if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+        int i;
+
+        for (i = 0; i < 4; i++) {
+            if (flags & (1 << (kRegUse0 + i))) {
+                setupRegMask(&lir->useMask, lir->operands[i]);
+            }
+        }
+    }
+
+    if (flags & USES_CCODES) {
+        lir->useMask |= ENCODE_CCODE;
+    }
+}
+
+/*
+ * The following are building blocks to construct low-level IRs with 0 - 4
+ * operands.
+ */
+static MipsLIR *newLIR0(CompilationUnit *cUnit, MipsOpCode opcode)
+{
+    MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    DCHECK(isPseudoOpCode(opcode) || (EncodingMap[opcode].flags & NO_OPERAND));
+    insn->opcode = opcode;
+    setupResourceMasks(insn);
+    insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    oatAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static MipsLIR *newLIR1(CompilationUnit *cUnit, MipsOpCode opcode,
+                           int dest)
+{
+    MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    DCHECK(isPseudoOpCode(opcode) || (EncodingMap[opcode].flags & IS_UNARY_OP));
+    insn->opcode = opcode;
+    insn->operands[0] = dest;
+    setupResourceMasks(insn);
+    insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    oatAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static MipsLIR *newLIR2(CompilationUnit *cUnit, MipsOpCode opcode,
+                           int dest, int src1)
+{
+    MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), 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->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    oatAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static MipsLIR *newLIR3(CompilationUnit *cUnit, MipsOpCode opcode,
+                           int dest, int src1, int src2)
+{
+    MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    if (!(EncodingMap[opcode].flags & IS_TERTIARY_OP)) {
+        LOG(FATAL) << "Bad LIR3: " << EncodingMap[opcode].name;
+    }
+    DCHECK(isPseudoOpCode(opcode) ||
+           (EncodingMap[opcode].flags & IS_TERTIARY_OP));
+    insn->opcode = opcode;
+    insn->operands[0] = dest;
+    insn->operands[1] = src1;
+    insn->operands[2] = src2;
+    setupResourceMasks(insn);
+    insn->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    oatAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+static MipsLIR *newLIR4(CompilationUnit *cUnit, MipsOpCode opcode,
+                           int dest, int src1, int src2, int info)
+{
+    MipsLIR *insn = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), 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->generic.dalvikOffset = cUnit->currentDalvikOffset;
+    oatAppendLIR(cUnit, (LIR *) insn);
+    return insn;
+}
+
+/*
+ * The following are building blocks to insert constants into the pool or
+ * instruction streams.
+ */
+
+/* Add a 32-bit constant either in the constant pool or mixed with code */
+static MipsLIR *addWordData(CompilationUnit *cUnit, LIR **constantListP,
+                           int value)
+{
+    /* Add the constant to the literal pool */
+    if (constantListP) {
+        MipsLIR *newValue = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true,
+                                               kAllocData);
+        newValue->operands[0] = value;
+        newValue->generic.next = *constantListP;
+        *constantListP = (LIR *) newValue;
+        return newValue;
+    } else {
+        /* Add the constant in the middle of code stream */
+        newLIR1(cUnit, kMips32BitData, value);
+    }
+    return NULL;
+}
+
+/*
+ * Generate an kMipsPseudoBarrier marker to indicate the boundary of special
+ * blocks.
+ */
+static void genBarrier(CompilationUnit *cUnit)
+{
+    MipsLIR *barrier = newLIR0(cUnit, kMipsPseudoBarrier);
+    /* Mark all resources as being clobbered */
+    barrier->defMask = -1;
+}
+
+} // namespace art
diff --git a/src/compiler/codegen/mips/FP/MipsFP.cc b/src/compiler/codegen/mips/FP/MipsFP.cc
new file mode 100644
index 0000000..fd07a34
--- /dev/null
+++ b/src/compiler/codegen/mips/FP/MipsFP.cc
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+extern void oatFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
+                                              int reg1, int reg2);
+extern void oatFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg);
+
+/* First, flush any registers associated with this value */
+static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc,
+                             int rDest)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+     rlSrc = rlSrc.wide ? oatUpdateLocWide(cUnit, rlSrc) :
+                          oatUpdateLoc(cUnit, rlSrc);
+     if (rlSrc.location == kLocPhysReg) {
+         if (rlSrc.wide) {
+             oatFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg,
+                                               rlSrc.highReg);
+         } else {
+             oatFlushRegForV5TEVFP(cUnit, rlSrc.lowReg);
+         }
+     }
+     opRegRegImm(cUnit, kOpAdd, rDest, rFP,
+                 oatS2VReg(cUnit, rlSrc.sRegLow) << 2);
+#endif
+}
+
+/*
+ * TUNING: On some implementations, it is quicker to pass addresses
+ * to the handlers rather than load the operands into core registers
+ * and then move the values to FP regs in the handlers.  Other implementations
+ * may prefer passing data in registers (and the latter approach would
+ * yeild cleaner register handling - avoiding the requirement that operands
+ * be flushed to memory prior to the call).
+ */
+static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+                            RegLocation rlDest, RegLocation rlSrc1,
+                            RegLocation rlSrc2)
+{
+#ifdef __mips_hard_float
+    int op = kMipsNop;
+    RegLocation rlResult;
+
+    /*
+     * Don't attempt to optimize register usage since these opcodes call out to
+     * the handlers.
+     */
+    switch (mir->dalvikInsn.opcode) {
+        case OP_ADD_FLOAT_2ADDR:
+        case OP_ADD_FLOAT:
+            op = kMipsFadds;
+            break;
+        case OP_SUB_FLOAT_2ADDR:
+        case OP_SUB_FLOAT:
+            op = kMipsFsubs;
+            break;
+        case OP_DIV_FLOAT_2ADDR:
+        case OP_DIV_FLOAT:
+            op = kMipsFdivs;
+            break;
+        case OP_MUL_FLOAT_2ADDR:
+        case OP_MUL_FLOAT:
+            op = kMipsFmuls;
+            break;
+        case OP_REM_FLOAT_2ADDR:
+        case OP_REM_FLOAT:
+        case OP_NEG_FLOAT: {
+            return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+        }
+        default:
+            return true;
+    }
+    rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
+    rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR3(cUnit, (MipsOpCode)op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+    storeValue(cUnit, rlDest, rlResult);
+
+    return false;
+#else
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+    return false;
+#if 0
+    TemplateOpcode opcode;
+
+    /*
+     * Don't attempt to optimize register usage since these opcodes call out to
+     * the handlers.
+     */
+    switch (mir->dalvikInsn.opcode) {
+        case OP_ADD_FLOAT_2ADDR:
+        case OP_ADD_FLOAT:
+            opcode = TEMPLATE_ADD_FLOAT_VFP;
+            break;
+        case OP_SUB_FLOAT_2ADDR:
+        case OP_SUB_FLOAT:
+            opcode = TEMPLATE_SUB_FLOAT_VFP;
+            break;
+        case OP_DIV_FLOAT_2ADDR:
+        case OP_DIV_FLOAT:
+            opcode = TEMPLATE_DIV_FLOAT_VFP;
+            break;
+        case OP_MUL_FLOAT_2ADDR:
+        case OP_MUL_FLOAT:
+            opcode = TEMPLATE_MUL_FLOAT_VFP;
+            break;
+        case OP_REM_FLOAT_2ADDR:
+        case OP_REM_FLOAT:
+        case OP_NEG_FLOAT: {
+            return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+        }
+        default:
+            return true;
+    }
+    loadValueAddress(cUnit, rlDest, r_A0);
+    oatClobber(cUnit, r_A0);
+    loadValueAddress(cUnit, rlSrc1, r_A1);
+    oatClobber(cUnit, r_A1);
+    loadValueAddress(cUnit, rlSrc2, r_A2);
+    UNIMP(FATAL) << "Need callout to handler";
+#if 0
+    genDispatchToHandler(cUnit, opcode);
+#endif
+    rlDest = oatUpdateLoc(cUnit, rlDest);
+    if (rlDest.location == kLocPhysReg) {
+        oatClobber(cUnit, rlDest.lowReg);
+    }
+    return false;
+#endif
+#endif
+}
+
+static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+                             RegLocation rlDest, RegLocation rlSrc1,
+                             RegLocation rlSrc2)
+{
+#ifdef __mips_hard_float
+    int op = kMipsNop;
+    RegLocation rlResult;
+
+    switch (mir->dalvikInsn.opcode) {
+        case OP_ADD_DOUBLE_2ADDR:
+        case OP_ADD_DOUBLE:
+            op = kMipsFaddd;
+            break;
+        case OP_SUB_DOUBLE_2ADDR:
+        case OP_SUB_DOUBLE:
+            op = kMipsFsubd;
+            break;
+        case OP_DIV_DOUBLE_2ADDR:
+        case OP_DIV_DOUBLE:
+            op = kMipsFdivd;
+            break;
+        case OP_MUL_DOUBLE_2ADDR:
+        case OP_MUL_DOUBLE:
+            op = kMipsFmuld;
+            break;
+        case OP_REM_DOUBLE_2ADDR:
+        case OP_REM_DOUBLE:
+        case OP_NEG_DOUBLE: {
+            return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
+        }
+        default:
+            return true;
+    }
+    rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
+    DCHECK(rlSrc1.wide);
+    rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
+    DCHECK(rlSrc2.wide);
+    rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
+    DCHECK(rlDest.wide);
+    DCHECK(rlResult.wide);
+    newLIR3(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlSrc1.lowReg, rlSrc1.highReg),
+            S2D(rlSrc2.lowReg, rlSrc2.highReg));
+    storeValueWide(cUnit, rlDest, rlResult);
+    return false;
+#else
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+    return false;
+#if 0
+    TemplateOpcode opcode;
+
+    switch (mir->dalvikInsn.opcode) {
+        case OP_ADD_DOUBLE_2ADDR:
+        case OP_ADD_DOUBLE:
+            opcode = TEMPLATE_ADD_DOUBLE_VFP;
+            break;
+        case OP_SUB_DOUBLE_2ADDR:
+        case OP_SUB_DOUBLE:
+            opcode = TEMPLATE_SUB_DOUBLE_VFP;
+            break;
+        case OP_DIV_DOUBLE_2ADDR:
+        case OP_DIV_DOUBLE:
+            opcode = TEMPLATE_DIV_DOUBLE_VFP;
+            break;
+        case OP_MUL_DOUBLE_2ADDR:
+        case OP_MUL_DOUBLE:
+            opcode = TEMPLATE_MUL_DOUBLE_VFP;
+            break;
+        case OP_REM_DOUBLE_2ADDR:
+        case OP_REM_DOUBLE:
+        case OP_NEG_DOUBLE: {
+            return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
+                                               rlSrc2);
+        }
+        default:
+            return true;
+    }
+    loadValueAddress(cUnit, rlDest, r_A0);
+    oatClobber(cUnit, r_A0);
+    loadValueAddress(cUnit, rlSrc1, r_A1);
+    oatClobber(cUnit, r_A1);
+    loadValueAddress(cUnit, rlSrc2, r_A2);
+    UNIMP(FATAL) << "Need callout to handler";
+#if 0
+    genDispatchToHandler(cUnit, opcode);
+#endif
+    rlDest = oatUpdateLocWide(cUnit, rlDest);
+    if (rlDest.location == kLocPhysReg) {
+        oatClobber(cUnit, rlDest.lowReg);
+        oatClobber(cUnit, rlDest.highReg);
+    }
+    return false;
+#endif
+#endif
+}
+
+static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+{
+    Opcode opcode = mir->dalvikInsn.opcode;
+    bool longSrc = false;
+    bool longDest = false;
+    RegLocation rlSrc;
+    RegLocation rlDest;
+#ifdef __mips_hard_float
+    int op = kMipsNop;
+    int srcReg;
+    RegLocation rlResult;
+
+    switch (opcode) {
+        case OP_INT_TO_FLOAT:
+            longSrc = false;
+            longDest = false;
+            op = kMipsFcvtsw;
+            break;
+        case OP_DOUBLE_TO_FLOAT:
+            longSrc = true;
+            longDest = false;
+            op = kMipsFcvtsd;
+            break;
+        case OP_FLOAT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            op = kMipsFcvtds;
+            break;
+        case OP_INT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            op = kMipsFcvtdw;
+            break;
+        case OP_FLOAT_TO_INT:
+        case OP_DOUBLE_TO_INT:
+        case OP_LONG_TO_DOUBLE:
+        case OP_FLOAT_TO_LONG:
+        case OP_LONG_TO_FLOAT:
+        case OP_DOUBLE_TO_LONG:
+            return genConversionPortable(cUnit, mir);
+        default:
+            return true;
+    }
+    if (longSrc) {
+        rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+        rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+        srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
+    } else {
+        rlSrc = oatGetSrc(cUnit, mir, 0);
+        rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+        srcReg = rlSrc.lowReg;
+    }
+    if (longDest) {
+        rlDest = oatGetDestWide(cUnit, mir, 0, 1);
+        rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
+        newLIR2(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else {
+        rlDest = oatGetDest(cUnit, mir, 0);
+        rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
+        newLIR2(cUnit, (MipsOpCode)op, rlResult.lowReg, srcReg);
+        storeValue(cUnit, rlDest, rlResult);
+    }
+    return false;
+#else
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+    return false;
+#if 0
+    TemplateOpcode templateOpcode;
+    switch (opcode) {
+        case OP_INT_TO_FLOAT:
+            longSrc = false;
+            longDest = false;
+            templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP;
+            break;
+        case OP_FLOAT_TO_INT:
+            longSrc = false;
+            longDest = false;
+            templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP;
+            break;
+        case OP_DOUBLE_TO_FLOAT:
+            longSrc = true;
+            longDest = false;
+            templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
+            break;
+        case OP_FLOAT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
+            break;
+        case OP_INT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
+            templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP;
+            break;
+        case OP_DOUBLE_TO_INT:
+            longSrc = true;
+            longDest = false;
+            templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP;
+            break;
+        case OP_LONG_TO_DOUBLE:
+        case OP_FLOAT_TO_LONG:
+        case OP_LONG_TO_FLOAT:
+        case OP_DOUBLE_TO_LONG:
+            return genConversionPortable(cUnit, mir);
+        default:
+            return true;
+    }
+
+    if (longSrc) {
+        rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+    } else {
+        rlSrc = oatGetSrc(cUnit, mir, 0);
+    }
+
+    if (longDest) {
+        rlDest = oatGetDestWide(cUnit, mir, 0, 1);
+    } else {
+        rlDest = oatGetDest(cUnit, mir, 0);
+    }
+    loadValueAddress(cUnit, rlDest, r_A0);
+    oatClobber(cUnit, r_A0);
+    loadValueAddress(cUnit, rlSrc, r_A1);
+    UNIMP(FATAL) << "Need callout to handler";
+#if 0
+    genDispatchToHandler(cUnit, templateOpcode);
+#endif
+    if (rlDest.wide) {
+        rlDest = oatUpdateLocWide(cUnit, rlDest);
+        oatClobber(cUnit, rlDest.highReg);
+    } else {
+        rlDest = oatUpdateLoc(cUnit, rlDest);
+    }
+    oatClobber(cUnit, rlDest.lowReg);
+    return false;
+#endif
+#endif
+}
+
+static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                     RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+    return false;
+#if 0
+    TemplateOpcode templateOpcode;
+    RegLocation rlResult = oatGetReturn(cUnit);
+    bool wide = true;
+
+    switch(mir->dalvikInsn.opcode) {
+        case OP_CMPL_FLOAT:
+            templateOpcode = TEMPLATE_CMPL_FLOAT_VFP;
+            wide = false;
+            break;
+        case OP_CMPG_FLOAT:
+            templateOpcode = TEMPLATE_CMPG_FLOAT_VFP;
+            wide = false;
+            break;
+        case OP_CMPL_DOUBLE:
+            templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP;
+            break;
+        case OP_CMPG_DOUBLE:
+            templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP;
+            break;
+        default:
+            return true;
+    }
+    loadValueAddress(cUnit, rlSrc1, r_A0);
+    oatClobber(cUnit, r_A0);
+    loadValueAddress(cUnit, rlSrc2, r_A1);
+    UNIMP(FATAL) << "Need callout to handler";
+#if 0
+    genDispatchToHandler(cUnit, templateOpcode);
+#endif
+    storeValue(cUnit, rlDest, rlResult);
+    return false;
+#endif
+}
+
+} //  namespace art
diff --git a/src/compiler/codegen/mips/Mips32/Factory.cc b/src/compiler/codegen/mips/Mips32/Factory.cc
new file mode 100644
index 0000000..ffbb223
--- /dev/null
+++ b/src/compiler/codegen/mips/Mips32/Factory.cc
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+/*
+ * This file contains codegen for the MIPS32 ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+static int coreRegs[] = {r_ZERO, r_AT, 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_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};
+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
+static int fpRegs[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
+                       r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
+static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
+                        r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
+#endif
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg,
+                      int highReg);
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
+static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
+                            int rDest);
+static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc);
+static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
+                              MipsConditionCode cond,
+                              int reg1, int reg2, int dOffset,
+                              MipsLIR *pcrLabel);
+static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
+
+#ifdef __mips_hard_float
+static MipsLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    MipsLIR* res = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    res->operands[0] = rDest;
+    res->operands[1] = rSrc;
+    if (rDest == rSrc) {
+        res->flags.isNop = true;
+    } 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;
+                }
+            } else {
+                DCHECK(SINGLEREG(rSrc));
+                res->opcode = kMipsMfc1;
+            }
+        }
+    }
+    setupResourceMasks(res);
+    return res;
+}
+#endif
+
+/*
+ * Load a immediate using a shortcut if possible; otherwise
+ * grab from the per-translation literal pool.  If target is
+ * a high register, build constant into a low register and copy.
+ *
+ * No additional register clobbering operation performed. Use this version when
+ * 1) rDest is freshly returned from oatAllocTemp or
+ * 2) The codegen is under fixed register usage
+ */
+static MipsLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
+                                     int value)
+{
+    MipsLIR *res;
+
+#ifdef __mips_hard_float
+    int rDestSave = rDest;
+    int isFpReg = FPREG(rDest);
+    if (isFpReg) {
+        DCHECK(SINGLEREG(rDest));
+        rDest = oatAllocTemp(cUnit);
+    }
+#endif
+
+    /* See if the value can be constructed cheaply */
+    if (value == 0) {
+        res = newLIR2(cUnit, kMipsMove, rDest, r_ZERO);
+    } else if ((value > 0) && (value <= 65535)) {
+        res = newLIR3(cUnit, kMipsOri, rDest, r_ZERO, value);
+    } else if ((value < 0) && (value >= -32768)) {
+        res = newLIR3(cUnit, kMipsAddiu, rDest, r_ZERO, value);
+    } else {
+        res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
+        if (value & 0xffff)
+            newLIR3(cUnit, kMipsOri, rDest, rDest, value);
+    }
+
+#ifdef __mips_hard_float
+    if (isFpReg) {
+        newLIR2(cUnit, kMipsMtc1, rDest, rDestSave);
+        oatFreeTemp(cUnit, rDest);
+    }
+#endif
+
+    return res;
+}
+
+/*
+ * Load an immediate value into a fixed or temp register.  Target
+ * register is clobbered, and marked inUse.
+ */
+static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
+{
+    if (oatIsTemp(cUnit, rDest)) {
+        oatClobber(cUnit, rDest);
+        oatMarkInUse(cUnit, rDest);
+    }
+    return loadConstantNoClobber(cUnit, rDest, value);
+}
+
+/*
+ * Load a class pointer value into a fixed or temp register.  Target
+ * register is clobbered, and marked inUse.
+ */
+static MipsLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
+{
+    MipsLIR *res;
+    if (oatIsTemp(cUnit, rDest)) {
+        oatClobber(cUnit, rDest);
+        oatMarkInUse(cUnit, rDest);
+    }
+    res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
+    if (value & 0xffff)
+        newLIR3(cUnit, kMipsOri, rDest, rDest, value);
+    return res;
+}
+
+static MipsLIR *opNone(CompilationUnit *cUnit, OpKind op)
+{
+    MipsLIR *res;
+    MipsOpCode opcode = kMipsNop;
+    switch (op) {
+        case kOpUncondBr:
+            opcode = kMipsB;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in opNone";
+    }
+    res = newLIR0(cUnit, opcode);
+    return res;
+}
+
+static MipsLIR *opCompareBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt)
+{
+    MipsLIR *res;
+    if (rt < 0) {
+      DCHECK(opc >= kMipsBeqz && opc <= kMipsBnez);
+      res = newLIR1(cUnit, opc, rs);
+    } else  {
+      DCHECK(opc == kMipsBeq || opc == kMipsBne);
+      res = newLIR2(cUnit, opc, rs, rt);
+    }
+    return res;
+}
+
+static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
+
+static MipsLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
+{
+    MipsOpCode opcode = kMipsNop;
+    switch (op) {
+        case kOpBlx:
+            opcode = kMipsJalr;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in opReg";
+    }
+    return newLIR2(cUnit, opcode, r_RA, rDestSrc);
+}
+
+static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int value);
+MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                  int value)
+{
+    MipsLIR *res;
+    bool neg = (value < 0);
+    int absValue = (neg) ? -value : value;
+    bool shortForm = (absValue & 0xff) == absValue;
+    MipsOpCode opcode = kMipsNop;
+    switch (op) {
+        case kOpAdd:
+            return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
+            break;
+        case kOpSub:
+            return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
+            break;
+        default:
+            LOG(FATAL) << "Bad case in opRegImm";
+            break;
+    }
+    if (shortForm)
+        res = newLIR2(cUnit, opcode, rDestSrc1, absValue);
+    else {
+        int rScratch = oatAllocTemp(cUnit);
+        res = loadConstant(cUnit, rScratch, value);
+        if (op == kOpCmp)
+            newLIR2(cUnit, opcode, rDestSrc1, rScratch);
+        else
+            newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rScratch);
+    }
+    return res;
+}
+
+static MipsLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int rSrc2)
+{
+    MipsOpCode opcode = kMipsNop;
+    switch (op) {
+        case kOpAdd:
+            opcode = kMipsAddu;
+            break;
+        case kOpSub:
+            opcode = kMipsSubu;
+            break;
+        case kOpAnd:
+            opcode = kMipsAnd;
+            break;
+        case kOpMul:
+            opcode = kMipsMul;
+            break;
+        case kOpOr:
+            opcode = kMipsOr;
+            break;
+        case kOpXor:
+            opcode = kMipsXor;
+            break;
+        case kOpLsl:
+            opcode = kMipsSllv;
+            break;
+        case kOpLsr:
+            opcode = kMipsSrlv;
+            break;
+        case kOpAsr:
+            opcode = kMipsSrav;
+            break;
+        default:
+            LOG(FATAL) << "bad case in opRegRegReg";
+            break;
+    }
+    return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
+}
+
+static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int value)
+{
+    MipsLIR *res;
+    MipsOpCode opcode = kMipsNop;
+    bool shortForm = true;
+
+    switch(op) {
+        case kOpAdd:
+            if (IS_SIMM16(value)) {
+                opcode = kMipsAddiu;
+            }
+            else {
+                shortForm = false;
+                opcode = kMipsAddu;
+            }
+            break;
+        case kOpSub:
+            if (IS_SIMM16((-value))) {
+                value = -value;
+                opcode = kMipsAddiu;
+            }
+            else {
+                shortForm = false;
+                opcode = kMipsSubu;
+            }
+            break;
+        case kOpLsl:
+                DCHECK(value >= 0 && value <= 31);
+                opcode = kMipsSll;
+                break;
+        case kOpLsr:
+                DCHECK(value >= 0 && value <= 31);
+                opcode = kMipsSrl;
+                break;
+        case kOpAsr:
+                DCHECK(value >= 0 && value <= 31);
+                opcode = kMipsSra;
+                break;
+        case kOpAnd:
+            if (IS_UIMM16((value))) {
+                opcode = kMipsAndi;
+            }
+            else {
+                shortForm = false;
+                opcode = kMipsAnd;
+            }
+            break;
+        case kOpOr:
+            if (IS_UIMM16((value))) {
+                opcode = kMipsOri;
+            }
+            else {
+                shortForm = false;
+                opcode = kMipsOr;
+            }
+            break;
+        case kOpXor:
+            if (IS_UIMM16((value))) {
+                opcode = kMipsXori;
+            }
+            else {
+                shortForm = false;
+                opcode = kMipsXor;
+            }
+            break;
+        case kOpMul:
+            shortForm = false;
+            opcode = kMipsMul;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in opRegRegImm";
+            break;
+    }
+
+    if (shortForm)
+        res = newLIR3(cUnit, opcode, rDest, rSrc1, value);
+    else {
+        if (rDest != rSrc1) {
+            res = loadConstant(cUnit, rDest, value);
+            newLIR3(cUnit, opcode, rDest, rSrc1, rDest);
+        } else {
+            int rScratch = oatAllocTemp(cUnit);
+            res = loadConstant(cUnit, rScratch, value);
+            newLIR3(cUnit, opcode, rDest, rSrc1, rScratch);
+        }
+    }
+    return res;
+}
+
+MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                  int rSrc2)
+{
+    MipsOpCode opcode = kMipsNop;
+    MipsLIR *res;
+    switch (op) {
+        case kOpMov:
+            opcode = kMipsMove;
+            break;
+        case kOpMvn:
+            return newLIR3(cUnit, kMipsNor, rDestSrc1, rSrc2, r_ZERO);
+        case kOpNeg:
+            return newLIR3(cUnit, kMipsSubu, rDestSrc1, r_ZERO, rSrc2);
+        case kOpAdd:
+        case kOpAnd:
+        case kOpMul:
+        case kOpOr:
+        case kOpSub:
+        case kOpXor:
+            return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
+        case kOp2Byte:
+#if __mips_isa_rev>=2
+            res = newLIR2(cUnit, kMipsSeb, rDestSrc1, rSrc2);
+#else
+            res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
+            opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
+#endif
+            return res;
+        case kOp2Short:
+#if __mips_isa_rev>=2
+            res = newLIR2(cUnit, kMipsSeh, rDestSrc1, rSrc2);
+#else
+            res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
+            opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
+#endif
+            return res;
+        case kOp2Char:
+             return newLIR3(cUnit, kMipsAndi, rDestSrc1, rSrc2, 0xFFFF);
+        default:
+            LOG(FATAL) << "Bad case in opRegReg";
+            break;
+    }
+    return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
+}
+
+static MipsLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
+                                     int rDestHi, int valLo, int valHi)
+{
+    MipsLIR *res;
+    res = loadConstantNoClobber(cUnit, rDestLo, valLo);
+    loadConstantNoClobber(cUnit, rDestHi, valHi);
+    return res;
+}
+
+/* Load value from base + scaled index. */
+static MipsLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
+                               int rIndex, int rDest, int scale, OpSize size)
+{
+    MipsLIR *first = NULL;
+    MipsLIR *res;
+    MipsOpCode opcode = kMipsNop;
+    int tReg = oatAllocTemp(cUnit);
+
+#ifdef __mips_hard_float
+    if (FPREG(rDest)) {
+        DCHECK(SINGLEREG(rDest));
+        DCHECK((size == kWord) || (size == kSingle));
+        size = kSingle;
+    } else {
+        if (size == kSingle)
+            size = kWord;
+    }
+#endif
+
+    if (!scale) {
+        first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
+    } else {
+        first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
+        newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
+    }
+
+    switch (size) {
+#ifdef __mips_hard_float
+        case kSingle:
+            opcode = kMipsFlwc1;
+            break;
+#endif
+        case kWord:
+            opcode = kMipsLw;
+            break;
+        case kUnsignedHalf:
+            opcode = kMipsLhu;
+            break;
+        case kSignedHalf:
+            opcode = kMipsLh;
+            break;
+        case kUnsignedByte:
+            opcode = kMipsLbu;
+            break;
+        case kSignedByte:
+            opcode = kMipsLb;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in loadBaseIndexed";
+    }
+
+    res = newLIR3(cUnit, opcode, rDest, 0, tReg);
+    oatFreeTemp(cUnit, tReg);
+    return (first) ? first : res;
+}
+
+/* store value base base + scaled index. */
+static MipsLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
+                                int rIndex, int rSrc, int scale, OpSize size)
+{
+    MipsLIR *first = NULL;
+    MipsLIR *res;
+    MipsOpCode opcode = kMipsNop;
+    int rNewIndex = rIndex;
+    int tReg = oatAllocTemp(cUnit);
+
+#ifdef __mips_hard_float
+    if (FPREG(rSrc)) {
+        DCHECK(SINGLEREG(rSrc));
+        DCHECK((size == kWord) || (size == kSingle));
+        size = kSingle;
+    } else {
+        if (size == kSingle)
+            size = kWord;
+    }
+#endif
+
+    if (!scale) {
+        first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
+    } else {
+        first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
+        newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
+    }
+
+    switch (size) {
+#ifdef __mips_hard_float
+        case kSingle:
+            opcode = kMipsFswc1;
+            break;
+#endif
+        case kWord:
+            opcode = kMipsSw;
+            break;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            opcode = kMipsSh;
+            break;
+        case kUnsignedByte:
+        case kSignedByte:
+            opcode = kMipsSb;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in storeBaseIndexed";
+    }
+    res = newLIR3(cUnit, opcode, rSrc, 0, tReg);
+    oatFreeTemp(cUnit, rNewIndex);
+    return first;
+}
+
+static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    int i;
+    int loadCnt = 0;
+    MipsLIR *res = NULL ;
+    genBarrier(cUnit);
+
+    for (i = 0; i < 8; i++, rMask >>= 1) {
+        if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
+            newLIR3(cUnit, kMipsLw, i+r_A0, loadCnt*4, rBase);
+            loadCnt++;
+        }
+    }
+
+    if (loadCnt) {/* increment after */
+        newLIR3(cUnit, kMipsAddiu, rBase, rBase, loadCnt*4);
+    }
+
+    genBarrier(cUnit);
+    return res; /* NULL always returned which should be ok since no callers use it */
+}
+
+static MipsLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    int i;
+    int storeCnt = 0;
+    MipsLIR *res = NULL ;
+    genBarrier(cUnit);
+
+    for (i = 0; i < 8; i++, rMask >>= 1) {
+        if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
+            newLIR3(cUnit, kMipsSw, i+r_A0, storeCnt*4, rBase);
+            storeCnt++;
+        }
+    }
+
+    if (storeCnt) { /* increment after */
+        newLIR3(cUnit, kMipsAddiu, rBase, rBase, storeCnt*4);
+    }
+
+    genBarrier(cUnit);
+    return res; /* NULL always returned which should be ok since no callers use it */
+}
+
+static MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDest, int rDestHi,
+                                OpSize size, int sReg)
+/*
+ * Load value from base + displacement.  Optionally perform null check
+ * on base (which must have an associated sReg and MIR).  If not
+ * performing null check, incoming MIR can be null. IMPORTANT: this
+ * code must not allocate any new temps.  If a new register is needed
+ * and base and dest are the same, spill some other register to
+ * rlp and then restore.
+ */
+{
+    MipsLIR *res;
+    MipsLIR *load = NULL;
+    MipsLIR *load2 = NULL;
+    MipsOpCode opcode = kMipsNop;
+    bool shortForm = IS_SIMM16(displacement);
+    bool pair = false;
+
+    switch (size) {
+        case kLong:
+        case kDouble:
+            pair = true;
+            opcode = kMipsLw;
+#ifdef __mips_hard_float
+            if (FPREG(rDest)) {
+                opcode = kMipsFlwc1;
+                if (DOUBLEREG(rDest)) {
+                    rDest = rDest - FP_DOUBLE;
+                } else {
+                    DCHECK(FPREG(rDestHi));
+                    DCHECK(rDest == (rDestHi - 1));
+                }
+                rDestHi = rDest + 1;
+            }
+#endif
+            shortForm = IS_SIMM16_2WORD(displacement);
+            DCHECK_EQ((displacement & 0x3), 0);
+            break;
+        case kWord:
+        case kSingle:
+            opcode = kMipsLw;
+#ifdef __mips_hard_float
+            if (FPREG(rDest)) {
+                opcode = kMipsFlwc1;
+                DCHECK(SINGLEREG(rDest));
+            }
+#endif
+            DCHECK_EQ((displacement & 0x3), 0);
+            break;
+        case kUnsignedHalf:
+            opcode = kMipsLhu;
+            DCHECK_EQ((displacement & 0x1), 0);
+            break;
+        case kSignedHalf:
+            opcode = kMipsLh;
+            DCHECK_EQ((displacement & 0x1), 0);
+            break;
+        case kUnsignedByte:
+            opcode = kMipsLbu;
+            break;
+        case kSignedByte:
+            opcode = kMipsLb;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in loadBaseIndexedBody";
+    }
+
+    if (shortForm) {
+        if (!pair) {
+            load = res = newLIR3(cUnit, opcode, rDest, displacement, rBase);
+        } else {
+            load = res = newLIR3(cUnit, opcode, rDest, displacement + LOWORD_OFFSET, rBase);
+            load2 = newLIR3(cUnit, opcode, rDestHi, displacement + HIWORD_OFFSET, rBase);
+        }
+    } else {
+        if (pair) {
+            int rTmp = oatAllocFreeTemp(cUnit);
+            res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
+            load = newLIR3(cUnit, opcode, rDest, LOWORD_OFFSET, rTmp);
+            load2 = newLIR3(cUnit, opcode, rDestHi, HIWORD_OFFSET, rTmp);
+            oatFreeTemp(cUnit, rTmp);
+        } else {
+            int rTmp = (rBase == rDest) ? oatAllocFreeTemp(cUnit)
+                                        : rDest;
+            res = loadConstant(cUnit, rTmp, displacement);
+            load = newLIR3(cUnit, opcode, rDest, rBase, rTmp);
+            if (rTmp != rDest)
+                oatFreeTemp(cUnit, rTmp);
+        }
+    }
+
+    UNIMPLEMENTED(FATAL) << "Needs art conversion";
+#if 0
+    if (rBase == rFP) {
+        if (load != NULL)
+            annotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
+                                    true /* isLoad */);
+        if (load2 != NULL)
+            annotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
+                                    true /* isLoad */);
+    }
+#endif
+    return load;
+}
+
+static MipsLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
+                            int displacement, int rDest, OpSize size,
+                            int sReg)
+{
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
+                            size, sReg);
+}
+
+static MipsLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDestLo, int rDestHi,
+                                int sReg)
+{
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
+                            kLong, sReg);
+}
+
+static MipsLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrc, int rSrcHi,
+                                 OpSize size)
+{
+    MipsLIR *res;
+    MipsLIR *store = NULL;
+    MipsLIR *store2 = NULL;
+    MipsOpCode opcode = kMipsNop;
+    bool shortForm = IS_SIMM16(displacement);
+    bool pair = false;
+
+    switch (size) {
+        case kLong:
+        case kDouble:
+            pair = true;
+            opcode = kMipsSw;
+#ifdef __mips_hard_float
+            if (FPREG(rSrc)) {
+                opcode = kMipsFswc1;
+                if (DOUBLEREG(rSrc)) {
+                    rSrc = rSrc - FP_DOUBLE;
+                } else {
+                    DCHECK(FPREG(rSrcHi));
+                    DCHECK_EQ(rSrc, (rSrcHi - 1));
+                }
+                rSrcHi = rSrc + 1;
+            }
+#endif
+            shortForm = IS_SIMM16_2WORD(displacement);
+            DCHECK_EQ((displacement & 0x3), 0);
+            break;
+        case kWord:
+        case kSingle:
+            opcode = kMipsSw;
+#ifdef __mips_hard_float
+            if (FPREG(rSrc)) {
+                opcode = kMipsFswc1;
+                DCHECK(SINGLEREG(rSrc));
+            }
+#endif
+            DCHECK_EQ((displacement & 0x3), 0);
+            break;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            opcode = kMipsSh;
+            DCHECK_EQ((displacement & 0x1), 0);
+            break;
+        case kUnsignedByte:
+        case kSignedByte:
+            opcode = kMipsSb;
+            break;
+        default:
+            LOG(FATAL) << "Bad case in storeBaseIndexedBody";
+    }
+
+    if (shortForm) {
+        if (!pair) {
+            store = res = newLIR3(cUnit, opcode, rSrc, displacement, rBase);
+        } else {
+            store = res = newLIR3(cUnit, opcode, rSrc, displacement + LOWORD_OFFSET, rBase);
+            store2 = newLIR3(cUnit, opcode, rSrcHi, displacement + HIWORD_OFFSET, rBase);
+        }
+    } else {
+        int rScratch = oatAllocTemp(cUnit);
+        res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
+        if (!pair) {
+            store =  newLIR3(cUnit, opcode, rSrc, 0, rScratch);
+        } else {
+            store =  newLIR3(cUnit, opcode, rSrc, LOWORD_OFFSET, rScratch);
+            store2 = newLIR3(cUnit, opcode, rSrcHi, HIWORD_OFFSET, rScratch);
+        }
+        oatFreeTemp(cUnit, rScratch);
+    }
+
+    UNIMPLEMENTED(FATAL) << "Needs art conversion";
+#if 0
+    if (rBase == rFP) {
+        if (store != NULL)
+            annotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
+                                    false /* isLoad */);
+        if (store2 != NULL)
+            annotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
+                                    false /* isLoad */);
+    }
+#endif
+
+    return res;
+}
+
+static MipsLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc, OpSize size)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
+}
+
+static MipsLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrcLo, int rSrcHi)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
+}
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    storeWordDisp(cUnit, base, LOWORD_OFFSET, lowReg);
+    storeWordDisp(cUnit, base, HIWORD_OFFSET, highReg);
+}
+
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    loadWordDisp(cUnit, base, LOWORD_OFFSET , lowReg);
+    loadWordDisp(cUnit, base, HIWORD_OFFSET , highReg);
+}
+
+static MipsLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    MipsLIR* res;
+    MipsOpCode opcode;
+#ifdef __mips_hard_float
+    if (FPREG(rDest) || FPREG(rSrc))
+        return fpRegCopy(cUnit, rDest, rSrc);
+#endif
+    res = (MipsLIR *) oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    opcode = kMipsMove;
+    DCHECK(LOWREG(rDest) && LOWREG(rSrc));
+    res->operands[0] = rDest;
+    res->operands[1] = rSrc;
+    res->opcode = opcode;
+    setupResourceMasks(res);
+    if (rDest == rSrc) {
+        res->flags.isNop = true;
+    }
+    return res;
+}
+
+static MipsLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
+{
+    MipsLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
+    oatAppendLIR(cUnit, (LIR*)res);
+    return res;
+}
+
+static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+                           int srcLo, int srcHi)
+{
+#ifdef __mips_hard_float
+    bool destFP = FPREG(destLo) && FPREG(destHi);
+    bool srcFP = FPREG(srcLo) && FPREG(srcHi);
+    DCHECK_EQ(FPREG(srcLo), FPREG(srcHi));
+    DCHECK_EQ(FPREG(destLo), FPREG(destHi));
+    if (destFP) {
+        if (srcFP) {
+            genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
+        } else {
+           /* note the operands are swapped for the mtc1 instr */
+            newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
+            newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
+        }
+    } else {
+        if (srcFP) {
+            newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
+            newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
+        } else {
+            // Handle overlap
+            if (srcHi == destLo) {
+                genRegCopy(cUnit, destHi, srcHi);
+                genRegCopy(cUnit, destLo, srcLo);
+            } else {
+                genRegCopy(cUnit, destLo, srcLo);
+                genRegCopy(cUnit, destHi, srcHi);
+            }
+        }
+    }
+#else
+    // Handle overlap
+    if (srcHi == destLo) {
+        genRegCopy(cUnit, destHi, srcHi);
+        genRegCopy(cUnit, destLo, srcLo);
+    } else {
+        genRegCopy(cUnit, destLo, srcLo);
+        genRegCopy(cUnit, destHi, srcHi);
+    }
+#endif
+}
+
+static inline MipsLIR *genRegImmCheck(CompilationUnit *cUnit,
+                                     MipsConditionCode cond, int reg,
+                                     int checkValue, int dOffset,
+                                     MipsLIR *pcrLabel)
+{
+    MipsLIR *branch = NULL;
+
+    if (checkValue == 0) {
+        MipsOpCode opc = kMipsNop;
+        if (cond == kMipsCondEq) {
+            opc = kMipsBeqz;
+        } else if (cond == kMipsCondNe) {
+            opc = kMipsBnez;
+        } else if (cond == kMipsCondLt || cond == kMipsCondMi) {
+            opc = kMipsBltz;
+        } else if (cond == kMipsCondLe) {
+            opc = kMipsBlez;
+        } else if (cond == kMipsCondGt) {
+            opc = kMipsBgtz;
+        } else if (cond == kMipsCondGe) {
+            opc = kMipsBgez;
+        } else {
+            LOG(FATAL) << "Bad case in genRegImmCheck";
+        }
+        branch = opCompareBranch(cUnit, opc, reg, -1);
+    } else if (IS_SIMM16(checkValue)) {
+        if (cond == kMipsCondLt) {
+            int tReg = oatAllocTemp(cUnit);
+            newLIR3(cUnit, kMipsSlti, tReg, reg, checkValue);
+            branch = opCompareBranch(cUnit, kMipsBne, tReg, r_ZERO);
+            oatFreeTemp(cUnit, tReg);
+        } else {
+            LOG(FATAL) << "Bad case in genRegImmCheck";
+        }
+    } else {
+        LOG(FATAL) << "Bad case in genRegImmCheck";
+    }
+
+    UNIMPLEMENTED(FATAL) << "Needs art conversion";
+    return NULL;
+#if 0
+    if (cUnit->jitMode == kJitMethod) {
+        BasicBlock *bb = cUnit->curBlock;
+        if (bb->taken) {
+            MipsLIR  *exceptionLabel = (MipsLIR *) cUnit->blockLabelList;
+            exceptionLabel += bb->taken->id;
+            branch->generic.target = (LIR *) exceptionLabel;
+            return exceptionLabel;
+        } else {
+            LOG(FATAL) <<  "Catch blocks not handled yet";
+            return NULL;
+        }
+    } else {
+        return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+    }
+#endif
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/Mips32/Gen.cc
new file mode 100644
index 0000000..f49cdab
--- /dev/null
+++ b/src/compiler/codegen/mips/Mips32/Gen.cc
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains codegen for the Mips ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+namespace art {
+
+// FIXME: need the following:
+void genSuspendTest(CompilationUnit* cUnit, MIR* mir) {}
+void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
+                   RegLocation rlSrc) {}
+void genNewInstance(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlDest) {}
+void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
+void genConstString(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlDest, RegLocation rlSrc) {}
+void genConstClass(CompilationUnit* cUnit, MIR* mir,
+                          RegLocation rlDest, RegLocation rlSrc) {}
+void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
+                        RegLocation rlArray, RegLocation rlIndex,
+                        RegLocation rlDest, int scale) {}
+void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
+                        RegLocation rlArray, RegLocation rlIndex,
+                        RegLocation rlSrc, int scale) {}
+void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlArray, RegLocation rlIndex,
+                           RegLocation rlSrc, int scale) {}
+void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
+                    RegLocation rlSrc, RegLocation rlObj,
+                    bool isLongOrDouble, bool isObject) {}
+bool genArithOpInt(CompilationUnit* cUnit, MIR* mir,
+                          RegLocation rlDest, RegLocation rlSrc1,
+                          RegLocation rlSrc2) { return 0; }
+bool genArithOpLong(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlDest, RegLocation rlSrc1,
+                           RegLocation rlSrc2) { return 0; }
+bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlDest, RegLocation rlSrc1,
+                           RegLocation rlShift) { return 0; }
+bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir,
+                             RegLocation rlDest, RegLocation rlSrc,
+                             int lit) { return 0; }
+
+
+
+
+
+
+
+
+STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
+
+void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
+  if (field == NULL) {
+    const DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
+    std::string class_name(cUnit->dex_file->GetFieldDeclaringClassDescriptor(field_id));
+    std::string field_name(cUnit->dex_file->GetFieldName(field_id));
+    LOG(INFO) << "Field " << PrettyDescriptor(class_name) << "." << field_name
+              << " unresolved at compile time";
+  } else {
+    // We also use the slow path for wide volatile fields.
+  }
+}
+
+/*
+ * Construct an s4 from two consecutive half-words of switch data.
+ * This needs to check endianness because the DEX optimizer only swaps
+ * half-words in instruction stream.
+ *
+ * "switchData" must be 32-bit aligned.
+ */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+STATIC inline s4 s4FromSwitchData(const void* switchData) {
+    return *(s4*) switchData;
+}
+#else
+STATIC inline s4 s4FromSwitchData(const void* switchData) {
+    u2* data = switchData;
+    return data[0] | (((s4) data[1]) << 16);
+}
+#endif
+/*
+ * Insert a kMipsPseudoCaseLabel at the beginning of the Dalvik
+ * offset vaddr.  This label will be used to fix up the case
+ * branch table during the assembly phase.  Be sure to set
+ * all resource flags on this to prevent code motion across
+ * target boundaries.  KeyVal is just there for debugging.
+ */
+STATIC MipsLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
+{
+    std::map<unsigned int, LIR*>::iterator it;
+    it = cUnit->boundaryMap.find(vaddr);
+    if (it == cUnit->boundaryMap.end()) {
+        LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
+    }
+    MipsLIR* newLabel = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
+    newLabel->generic.dalvikOffset = vaddr;
+    newLabel->opcode = kMipsPseudoCaseLabel;
+    newLabel->operands[0] = keyVal;
+    oatInsertLIRAfter(it->second, (LIR*)newLabel);
+    return newLabel;
+}
+
+STATIC void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
+{
+    const u2* table = tabRec->table;
+    int baseVaddr = tabRec->vaddr;
+    int *targets = (int*)&table[4];
+    int entries = table[1];
+    int lowKey = s4FromSwitchData(&table[2]);
+    for (int i = 0; i < entries; i++) {
+        tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
+                                             i + lowKey);
+    }
+}
+
+STATIC void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
+{
+    const u2* table = tabRec->table;
+    int baseVaddr = tabRec->vaddr;
+    int entries = table[1];
+    int* keys = (int*)&table[2];
+    int* targets = &keys[entries];
+    for (int i = 0; i < entries; i++) {
+        tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
+                                             keys[i]);
+    }
+}
+
+void oatProcessSwitchTables(CompilationUnit* cUnit)
+{
+    GrowableListIterator iterator;
+    oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
+    while (true) {
+        SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
+             &iterator);
+        if (tabRec == NULL) break;
+        if (tabRec->table[0] == kPackedSwitchSignature)
+            markPackedCaseLabels(cUnit, tabRec);
+        else if (tabRec->table[0] == kSparseSwitchSignature)
+            markSparseCaseLabels(cUnit, tabRec);
+        else {
+            LOG(FATAL) << "Invalid switch table";
+        }
+    }
+}
+
+STATIC void dumpSparseSwitchTable(const u2* table)
+    /*
+     * Sparse switch data format:
+     *  ushort ident = 0x0200   magic value
+     *  ushort size             number of entries in the table; > 0
+     *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
+     *  int targets[size]       branch targets, relative to switch opcode
+     *
+     * Total size is (2+size*4) 16-bit code units.
+     */
+{
+    u2 ident = table[0];
+    int entries = table[1];
+    int* keys = (int*)&table[2];
+    int* targets = &keys[entries];
+    LOG(INFO) <<  "Sparse switch table - ident:0x" << std::hex << ident <<
+       ", entries: " << std::dec << entries;
+    for (int i = 0; i < entries; i++) {
+        LOG(INFO) << "    Key[" << keys[i] << "] -> 0x" << std::hex <<
+        targets[i];
+    }
+}
+
+STATIC void dumpPackedSwitchTable(const u2* table)
+    /*
+     * Packed switch data format:
+     *  ushort ident = 0x0100   magic value
+     *  ushort size             number of entries in the table
+     *  int first_key           first (and lowest) switch case value
+     *  int targets[size]       branch targets, relative to switch opcode
+     *
+     * Total size is (4+size*2) 16-bit code units.
+     */
+{
+    u2 ident = table[0];
+    int* targets = (int*)&table[4];
+    int entries = table[1];
+    int lowKey = s4FromSwitchData(&table[2]);
+    LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
+        ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
+    for (int i = 0; i < entries; i++) {
+        LOG(INFO) << "    Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
+            targets[i];
+    }
+}
+
+/*
+ * The sparse table in the literal pool is an array of <key,displacement>
+ * pairs.  For each set, we'll load them as a pair using ldmia.
+ * This means that the register number of the temp we use for the key
+ * must be lower than the reg for the displacement.
+ *
+ * The test loop will look something like:
+ *
+ *   adr   rBase, <table>
+ *   ldr   rVal, [rSP, vRegOff]
+ *   mov   rIdx, #tableSize
+ * lp:
+ *   ldmia rBase!, {rKey, rDisp}
+ *   sub   rIdx, #1
+ *   cmp   rVal, rKey
+ *   ifeq
+ *   add   rPC, rDisp   ; This is the branch from which we compute displacement
+ *   cbnz  rIdx, lp
+ */
+STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir,
+                            RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
+    if (cUnit->printMe) {
+        dumpSparseSwitchTable(table);
+    }
+    // Add the table to the list - we'll process it later
+    SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
+                         true, kAllocData);
+    tabRec->table = table;
+    tabRec->vaddr = mir->offset;
+    int size = table[1];
+    tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true,
+                                        kAllocLIR);
+    oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
+
+    // Get the switch value
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    int rBase = oatAllocTemp(cUnit);
+    /* Allocate key and disp temps */
+    int rKey = oatAllocTemp(cUnit);
+    int rDisp = oatAllocTemp(cUnit);
+    // Make sure rKey's register number is less than rDisp's number for ldmia
+    if (rKey > rDisp) {
+        int tmp = rDisp;
+        rDisp = rKey;
+        rKey = tmp;
+    }
+    // Materialize a pointer to the switch table
+    newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
+    // Set up rIdx
+    int rIdx = oatAllocTemp(cUnit);
+    loadConstant(cUnit, rIdx, size);
+    // Establish loop branch target
+    MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    // Load next key/disp
+    newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
+    opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
+    // Go if match. NOTE: No instruction set switch here - must stay Thumb2
+    genIT(cUnit, kMipsCondEq, "");
+    MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
+    tabRec->bxInst = switchBranch;
+    // Needs to use setflags encoding here
+    newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
+    MipsLIR* branch = opCondBranch(cUnit, kMipsCondNe);
+    branch->generic.target = (LIR*)target;
+#endif
+}
+
+STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir,
+                            RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
+    if (cUnit->printMe) {
+        dumpPackedSwitchTable(table);
+    }
+    // Add the table to the list - we'll process it later
+    SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
+                                                true, kAllocData);
+    tabRec->table = table;
+    tabRec->vaddr = mir->offset;
+    int size = table[1];
+    tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true,
+                                        kAllocLIR);
+    oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
+
+    // Get the switch value
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    int tableBase = oatAllocTemp(cUnit);
+    // Materialize a pointer to the switch table
+    newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
+    int lowKey = s4FromSwitchData(&table[2]);
+    int keyReg;
+    // Remove the bias, if necessary
+    if (lowKey == 0) {
+        keyReg = rlSrc.lowReg;
+    } else {
+        keyReg = oatAllocTemp(cUnit);
+        opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
+    }
+    // Bounds check - if < 0 or >= size continue following switch
+    opRegImm(cUnit, kOpCmp, keyReg, size-1);
+    MipsLIR* branchOver = opCondBranch(cUnit, kMipsCondHi);
+
+    // Load the displacement from the switch table
+    int dispReg = oatAllocTemp(cUnit);
+    loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
+
+    // ..and go! NOTE: No instruction set switch here - must stay Thumb2
+    MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
+    tabRec->bxInst = switchBranch;
+
+    /* branchOver target here */
+    MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR*)target;
+#endif
+}
+
+/*
+ * Array data table format:
+ *  ushort ident = 0x0300   magic value
+ *  ushort width            width of each element in the table
+ *  uint   size             number of elements in the table
+ *  ubyte  data[size*width] table of data values (may contain a single-byte
+ *                          padding at the end)
+ *
+ * Total size is 4+(width * size + 1)/2 16-bit code units.
+ */
+STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir,
+                              RegLocation rlSrc)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
+    // Add the table to the list - we'll process it later
+    FillArrayData *tabRec = (FillArrayData *)
+         oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
+    tabRec->table = table;
+    tabRec->vaddr = mir->offset;
+    u2 width = tabRec->table[1];
+    u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
+    tabRec->size = (size * width) + 8;
+
+    oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
+
+    // Making a call - use explicit registers
+    oatFlushAllRegs(cUnit);   /* Everything to home location */
+    loadValueDirectFixed(cUnit, rlSrc, r0);
+    loadWordDisp(cUnit, rSELF,
+                 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
+    // Materialize a pointer to the fill data image
+    newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
+    callRuntimeHelper(cUnit, rLR);
+#endif
+}
+
+STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
+                    RegLocation rlDest, RegLocation rlObj,
+                    bool isLongOrDouble, bool isObject)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    int fieldOffset;
+    bool isVolatile;
+    uint32_t fieldIdx = mir->dalvikInsn.vC;
+    bool fastPath =
+        cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, cUnit,
+                                                  fieldOffset, isVolatile, false);
+    if (fastPath && !SLOW_FIELD_PATH) {
+        RegLocation rlResult;
+        RegisterClass regClass = oatRegClassBySize(size);
+        DCHECK_GE(fieldOffset, 0);
+        rlObj = loadValue(cUnit, rlObj, kCoreReg);
+        if (isLongOrDouble) {
+            DCHECK(rlDest.wide);
+            genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
+            int regPtr = oatAllocTemp(cUnit);
+            opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
+            rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
+            loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
+            if (isVolatile) {
+                oatGenMemBarrier(cUnit, kSY);
+            }
+            oatFreeTemp(cUnit, regPtr);
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
+            genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
+            loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
+                         kWord, rlObj.sRegLow);
+            if (isVolatile) {
+                oatGenMemBarrier(cUnit, kSY);
+            }
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    } else {
+        int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
+                           (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
+                                     : OFFSETOF_MEMBER(Thread, pGet32Instance));
+        loadWordDisp(cUnit, rSELF, getterOffset, rLR);
+        loadValueDirect(cUnit, rlObj, r1);
+        loadConstant(cUnit, r0, fieldIdx);
+        callRuntimeHelper(cUnit, rLR);
+        if (isLongOrDouble) {
+            RegLocation rlResult = oatGetReturnWide(cUnit);
+            storeValueWide(cUnit, rlDest, rlResult);
+        } else {
+            RegLocation rlResult = oatGetReturn(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+        }
+    }
+#endif
+}
+
+/*
+ * Perform a "reg cmp imm" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+STATIC void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
+                        RegLocation rlSrc)
+{
+    RegLocation rlResult;
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+    opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
+                rlSrc.lowReg, 0x80000000);
+    storeValue(cUnit, rlDest, rlResult);
+}
+
+STATIC void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
+                         RegLocation rlSrc)
+{
+    RegLocation rlResult;
+    rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+    rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+    opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
+                        0x80000000);
+    genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+STATIC void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
+                       RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    RegLocation rlResult;
+    loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+    loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
+    genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
+    rlResult = oatGetReturnWide(cUnit);
+    storeValueWide(cUnit, rlDest, rlResult);
+#endif
+}
+
+STATIC bool partialOverlap(int sreg1, int sreg2)
+{
+    return abs(sreg1 - sreg2) == 1;
+}
+
+STATIC void withCarryHelper(CompilationUnit *cUnit, MipsOpCode opc,
+                            RegLocation rlDest, RegLocation rlSrc1,
+                            RegLocation rlSrc2, int sltuSrc1, int sltuSrc2)
+{
+    int tReg = oatAllocTemp(cUnit);
+    newLIR3(cUnit, opc, rlDest.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+    newLIR3(cUnit, kMipsSltu, tReg, sltuSrc1, sltuSrc2);
+    newLIR3(cUnit, opc, rlDest.highReg, rlSrc1.highReg, rlSrc2.highReg);
+    newLIR3(cUnit, opc, rlDest.highReg, rlDest.highReg, tReg);
+    oatFreeTemp(cUnit, tReg);
+}
+
+STATIC void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
+                         OpKind secondOp, RegLocation rlDest,
+                         RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    RegLocation rlResult;
+    int carryOp = (secondOp == kOpAdc || secondOp == kOpSbc);
+
+    if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
+        partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
+        partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
+        // Rare case - not enough registers to properly handle
+        genInterpSingleStep(cUnit, mir);
+    } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
+        rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+        rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+        if (!carryOp) {
+            opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlResult.lowReg, rlSrc2.lowReg);
+            opRegRegReg(cUnit, secondOp, rlResult.highReg, rlResult.highReg, rlSrc2.highReg);
+        } else if (secondOp == kOpAdc) {
+            withCarryHelper(cUnit, kMipsAddu, rlResult, rlResult, rlSrc2,
+                            rlResult.lowReg, rlSrc2.lowReg);
+        } else {
+            int tReg = oatAllocTemp(cUnit);
+            newLIR2(cUnit, kMipsMove, tReg, rlResult.lowReg);
+            withCarryHelper(cUnit, kMipsSubu, rlResult, rlResult, rlSrc2,
+                            tReg, rlResult.lowReg);
+            oatFreeTemp(cUnit, tReg);
+        }
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
+        rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+        rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+        if (!carryOp) {
+            opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlResult.lowReg);
+            opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlResult.highReg);
+        } else if (secondOp == kOpAdc) {
+            withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlResult,
+                            rlResult.lowReg, rlSrc1.lowReg);
+        } else {
+            withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlResult,
+                            rlSrc1.lowReg, rlResult.lowReg);
+        }
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else {
+        rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+        rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+        rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+        if (!carryOp) {
+            opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+            opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
+        } else if (secondOp == kOpAdc) {
+            withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlSrc2,
+                            rlResult.lowReg, rlSrc1.lowReg);
+        } else {
+            withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlSrc2,
+                            rlSrc1.lowReg, rlResult.lowReg);
+        }
+        storeValueWide(cUnit, rlDest, rlResult);
+    }
+#endif
+}
+
+void oatInitializeRegAlloc(CompilationUnit* cUnit)
+{
+    int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
+    int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
+    int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
+#ifdef __mips_hard_float
+    int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
+    int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
+#else
+    int numFPRegs = 0;
+    int numFPTemps = 0;
+#endif
+    RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true,
+                                                kAllocRegAlloc);
+    cUnit->regPool = pool;
+    pool->numCoreRegs = numRegs;
+    pool->coreRegs = (RegisterInfo *)
+            oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs),
+                   true, kAllocRegAlloc);
+    pool->numFPRegs = numFPRegs;
+    pool->FPRegs = numFPRegs == 0 ? NULL : (RegisterInfo *)
+            oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true,
+                   kAllocRegAlloc);
+    oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
+    oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
+    // Keep special registers from being allocated
+    for (int i = 0; i < numReserved; i++) {
+        if (NO_SUSPEND && !cUnit->genDebugger &&
+            (reservedRegs[i] == rSUSPEND)) {
+            //To measure cost of suspend check
+            continue;
+        }
+        oatMarkInUse(cUnit, reservedRegs[i]);
+    }
+    // Mark temp regs - all others not in use can be used for promotion
+    for (int i = 0; i < numTemps; i++) {
+        oatMarkTemp(cUnit, coreTemps[i]);
+    }
+    for (int i = 0; i < numFPTemps; i++) {
+        oatMarkTemp(cUnit, fpTemps[i]);
+    }
+    // Construct the alias map.
+    cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs *
+                                      sizeof(cUnit->phiAliasMap[0]), false,
+                                      kAllocDFInfo);
+    for (int i = 0; i < cUnit->numSSARegs; i++) {
+        cUnit->phiAliasMap[i] = i;
+    }
+    for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
+        int defReg = phi->ssaRep->defs[0];
+        for (int i = 0; i < phi->ssaRep->numUses; i++) {
+           for (int j = 0; j < cUnit->numSSARegs; j++) {
+               if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
+                   cUnit->phiAliasMap[j] = defReg;
+               }
+           }
+        }
+    }
+}
+
+STATIC void genMonitor(CompilationUnit *cUnit, MIR *mir)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    genMonitorPortable(cUnit, mir);
+#endif
+}
+
+STATIC void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                       RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    UNIMPLEMENTED(FATAL) << "Need Mips implementation";
+#if 0
+    RegLocation rlResult;
+    loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
+    loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
+    genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
+    rlResult = oatGetReturn(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
+#endif
+}
+
+STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit,
+        RegLocation rlSrc, RegLocation rlResult, int lit,
+        int firstBit, int secondBit)
+{
+    // We can't implement "add src, src, src, lsl#shift" on Thumb, so we have
+    // to do a regular multiply.
+    opRegRegImm(cUnit, kOpMul, rlResult.lowReg, rlSrc.lowReg, lit);
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/Mips32/Ralloc.cc b/src/compiler/codegen/mips/Mips32/Ralloc.cc
new file mode 100644
index 0000000..e0912d77b
--- /dev/null
+++ b/src/compiler/codegen/mips/Mips32/Ralloc.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+/*
+ * This file contains codegen for the Mips ISA and is intended to be
+ * includes by:
+ *
+ *        Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+/*
+ * Alloc a pair of core registers, or a double.  Low reg in low byte,
+ * high reg in next byte.
+ */
+int oatAllocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
+                                  int regClass)
+{
+    int highReg;
+    int lowReg;
+    int res = 0;
+
+#ifdef __mips_hard_float
+    if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
+        lowReg = oatAllocTempDouble(cUnit);
+        highReg = lowReg + 1;
+        res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+        return res;
+    }
+#endif
+
+    lowReg = oatAllocTemp(cUnit);
+    highReg = oatAllocTemp(cUnit);
+    res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+    return res;
+}
+
+int oatAllocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
+{
+#ifdef __mips_hard_float
+    if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
+{
+        return oatAllocTempFloat(cUnit);
+}
+#endif
+    return oatAllocTemp(cUnit);
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/MipsLIR.h b/src/compiler/codegen/mips/MipsLIR.h
new file mode 100644
index 0000000..a6f426e
--- /dev/null
+++ b/src/compiler/codegen/mips/MipsLIR.h
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_COMPILER_CODEGEN_MIPS_MIPSLIR_H_
+#define ART_COMPILER_COMPILER_CODEGEN_MIPS_MIPSLIR_H_
+
+#include "../../Dalvik.h"
+#include "../../CompilerInternals.h"
+
+namespace art {
+
+// Set to 1 to measure cost of suspend check
+#define NO_SUSPEND 0
+
+/*
+ * Runtime register conventions.
+ *
+ * zero is always the value 0
+ * at is scratch (normally used as temp reg by assembler)
+ * v0, v1 are scratch (normally hold subroutine return values)
+ * a0-a3 are scratch (normally hold subroutine arguments)
+ * t0-t8 are scratch
+ * t9 is scratch (normally used for function calls)
+ * s0 (rSUSPEND) is reserved [holds suspend-check counter]
+ * s1 (rSELF) is reserved [holds current &Thread]
+ * s2-s7 are callee save (promotion target)
+ * k0, k1 are reserved for use by interrupt handlers
+ * gp is reserved for global pointer
+ * sp is reserved
+ * s8 is callee save (promotion target)
+ * ra is scratch (normally holds the return addr)
+ *
+ * Preserved across C calls: s0-s8
+ * Trashed across C calls: at, v0-v1, a0-a3, t0-t9, gp, ra
+ *
+ * Floating pointer registers
+ * NOTE: there are 32 fp registers (16 df pairs), but currently
+ *       only support 16 fp registers (8 df pairs).
+ * f0-f15
+ * df0-df7, where df0={f0,f1}, df1={f2,f3}, ... , df7={f14,f15}
+ *
+ * f0-f15 (df0-df7) trashed across C calls
+ *
+ * For mips32 code use:
+ *      a0-a3 to hold operands
+ *      v0-v1 to hold results
+ *      t0-t9 for temps
+ *
+ * All jump/branch instructions have a delay slot after it.
+ *
+ *  Stack frame diagram (stack grows down, higher addresses at top):
+ *
+ * +------------------------+
+ * | IN[ins-1]              |  {Note: resides in caller's frame}
+ * |       .                |
+ * | IN[0]                  |
+ * | caller's Method*       |
+ * +========================+  {Note: start of callee's frame}
+ * | spill region           |  {variable sized - will include lr if non-leaf.}
+ * +------------------------+
+ * | ...filler word...      |  {Note: used as 2nd word of V[locals-1] if long]
+ * +------------------------+
+ * | V[locals-1]            |
+ * | V[locals-2]            |
+ * |      .                 |
+ * |      .                 |
+ * | V[1]                   |
+ * | V[0]                   |
+ * +------------------------+
+ * |  0 to 3 words padding  |
+ * +------------------------+
+ * | OUT[outs-1]            |
+ * | OUT[outs-2]            |
+ * |       .                |
+ * | OUT[0]                 |
+ * | curMethod*             | <<== sp w/ 16-byte alignment
+ * +========================+
+ */
+
+/* Offset to distingish FP regs */
+#define FP_REG_OFFSET 32
+/* Offset to distinguish DP FP regs */
+#define FP_DOUBLE 64
+/* Offset to distingish the extra regs */
+#define EXTRA_REG_OFFSET 128
+/* Reg types */
+#define REGTYPE(x) (x & (FP_REG_OFFSET | FP_DOUBLE))
+#define FPREG(x) ((x & FP_REG_OFFSET) == FP_REG_OFFSET)
+#define EXTRAREG(x) ((x & EXTRA_REG_OFFSET) == EXTRA_REG_OFFSET)
+#define LOWREG(x) ((x & 0x1f) == x)
+#define DOUBLEREG(x) ((x & FP_DOUBLE) == FP_DOUBLE)
+#define SINGLEREG(x) (FPREG(x) && !DOUBLEREG(x))
+/*
+ * Note: the low register of a floating point pair is sufficient to
+ * create the name of a double, but require both names to be passed to
+ * allow for asserts to verify that the pair is consecutive if significant
+ * rework is done in this area.  Also, it is a good reminder in the calling
+ * code that reg locations always describe doubles as a pair of singles.
+ */
+#define S2D(x,y) ((x) | FP_DOUBLE)
+/* Mask to strip off fp flags */
+#define FP_REG_MASK (FP_REG_OFFSET-1)
+/* non-existent Dalvik register */
+#define vNone   (-1)
+/* non-existant physical register */
+#define rNone   (-1)
+
+#ifdef HAVE_LITTLE_ENDIAN
+#define LOWORD_OFFSET 0
+#define HIWORD_OFFSET 4
+#define r_ARG0 r_A0
+#define r_ARG1 r_A1
+#define r_ARG2 r_A2
+#define r_ARG3 r_A3
+#define r_RESULT0 r_V0
+#define r_RESULT1 r_V1
+#else
+#define LOWORD_OFFSET 4
+#define HIWORD_OFFSET 0
+#define r_ARG0 r_A1
+#define r_ARG1 r_A0
+#define r_ARG2 r_A3
+#define r_ARG3 r_A2
+#define r_RESULT0 r_V1
+#define r_RESULT1 r_V0
+#endif
+
+/* These are the same for both big and little endian. */
+#define r_FARG0 r_F12
+#define r_FARG1 r_F13
+#define r_FRESULT0 r_F0
+#define r_FRESULT1 r_F1
+
+/* RegisterLocation templates return values (r_V0, or r_V0/r_V1) */
+#define LOC_C_RETURN {kLocPhysReg, 0, 0, 0, 0, 0, 1, r_V0, INVALID_REG, \
+                      INVALID_SREG}
+#define LOC_C_RETURN_ALT {kLocPhysReg, 0, 0, 0, 0, 0, 1, r_F0, INVALID_REG, \
+                      INVALID_SREG}
+#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, 0, 0, 0, 1, r_V0, r_V1,\
+                           INVALID_SREG}
+#define LOC_C_RETURN_WIDE_ALT {kLocPhysReg, 1, 0, 0, 0, 0, 1, r_F0, r_F1,\
+                           INVALID_SREG}
+
+typedef enum ResourceEncodingPos {
+    kGPReg0     = 0,
+    kRegSP      = 29,
+    kRegLR      = 31,
+    kFPReg0     = 32, /* only 16 fp regs supported currently */
+    kFPRegEnd   = 48,
+    kRegHI      = kFPRegEnd,
+    kRegLO,
+    kRegPC,
+    kRegEnd     = 51,
+    kCCode      = kRegEnd,
+    kFPStatus,          // FP status word
+    // The following four bits are for memory disambiguation
+    kDalvikReg,         // 1 Dalvik Frame (can be fully disambiguated)
+    kLiteral,           // 2 Literal pool (can be fully disambiguated)
+    kHeapRef,           // 3 Somewhere on the heap (alias with any other heap)
+    kMustNotAlias,      // 4 Guaranteed to be non-alias (eg *(r6+x))
+} ResourceEncodingPos;
+
+#define ENCODE_REG_LIST(N)      ((u8) N)
+#define ENCODE_REG_SP           (1ULL << kRegSP)
+#define ENCODE_REG_LR           (1ULL << kRegLR)
+#define ENCODE_REG_PC           (1ULL << kRegPC)
+#define ENCODE_CCODE            (1ULL << kCCode)
+#define ENCODE_FP_STATUS        (1ULL << kFPStatus)
+
+/* Abstract memory locations */
+#define ENCODE_DALVIK_REG       (1ULL << kDalvikReg)
+#define ENCODE_LITERAL          (1ULL << kLiteral)
+#define ENCODE_HEAP_REF         (1ULL << kHeapRef)
+#define ENCODE_MUST_NOT_ALIAS   (1ULL << kMustNotAlias)
+
+#define ENCODE_ALL              (~0ULL)
+#define ENCODE_MEM              (ENCODE_DALVIK_REG | ENCODE_LITERAL | \
+                                 ENCODE_HEAP_REF | ENCODE_MUST_NOT_ALIAS)
+
+#define DECODE_ALIAS_INFO_REG(X)        (X & 0xffff)
+#define DECODE_ALIAS_INFO_WIDE(X)       ((X & 0x80000000) ? 1 : 0)
+
+typedef enum OpKind {
+    kOpMov,
+    kOpMvn,
+    kOpCmp,
+    kOpLsl,
+    kOpLsr,
+    kOpAsr,
+    kOpRor,
+    kOpNot,
+    kOpAnd,
+    kOpOr,
+    kOpXor,
+    kOpNeg,
+    kOpAdd,
+    kOpAdc,
+    kOpSub,
+    kOpSbc,
+    kOpRsub,
+    kOpMul,
+    kOpDiv,
+    kOpRem,
+    kOpBic,
+    kOpCmn,
+    kOpTst,
+    kOpBkpt,
+    kOpBlx,
+    kOpPush,
+    kOpPop,
+    kOp2Char,
+    kOp2Short,
+    kOp2Byte,
+    kOpCondBr,
+    kOpUncondBr,
+    kOpInvalid,
+} OpKind;
+
+/*
+ * FIXME:
+ * Originally had r4PC as r_S0, rFP as r_S1, rSELF as r_S2, rINST as r_S4
+ * Remap - don't need r4PC, rFP or rINST.  Might make sense to keep
+ * Method* in one of these since we have so many registers to play with.
+ */
+
+#define rSUSPEND r_S0
+#define rSELF r_S1
+#define rSP r_SP
+
+/* FIXME: don't do this - find and fix all rLR's */
+#define rLR r_RA
+
+/*
+ * Annotate special-purpose core registers:
+ */
+
+typedef enum NativeRegisterPool {
+    r_ZERO = 0,
+    r_AT = 1,
+    r_V0 = 2,
+    r_V1 = 3,
+    r_A0 = 4,
+    r_A1 = 5,
+    r_A2 = 6,
+    r_A3 = 7,
+    r_T0 = 8,
+    r_T1 = 9,
+    r_T2 = 10,
+    r_T3 = 11,
+    r_T4 = 12,
+    r_T5 = 13,
+    r_T6 = 14,
+    r_T7 = 15,
+    r_S0 = 16,
+    r_S1 = 17,
+    r_S2 = 18,
+    r_S3 = 19,
+    r_S4 = 20,
+    r_S5 = 21,
+    r_S6 = 22,
+    r_S7 = 23,
+    r_T8 = 24,
+    r_T9 = 25,
+    r_K0 = 26,
+    r_K1 = 27,
+    r_GP = 28,
+    r_SP = 29,
+    r_FP = 30,
+    r_RA = 31,
+
+    r_F0 = 0 + FP_REG_OFFSET,
+    r_F1,
+    r_F2,
+    r_F3,
+    r_F4,
+    r_F5,
+    r_F6,
+    r_F7,
+    r_F8,
+    r_F9,
+    r_F10,
+    r_F11,
+    r_F12,
+    r_F13,
+    r_F14,
+    r_F15,
+#if 0 /* only 16 fp regs supported currently */
+    r_F16,
+    r_F17,
+    r_F18,
+    r_F19,
+    r_F20,
+    r_F21,
+    r_F22,
+    r_F23,
+    r_F24,
+    r_F25,
+    r_F26,
+    r_F27,
+    r_F28,
+    r_F29,
+    r_F30,
+    r_F31,
+#endif
+    r_DF0 = r_F0 + FP_DOUBLE,
+    r_DF1 = r_F2 + FP_DOUBLE,
+    r_DF2 = r_F4 + FP_DOUBLE,
+    r_DF3 = r_F6 + FP_DOUBLE,
+    r_DF4 = r_F8 + FP_DOUBLE,
+    r_DF5 = r_F10 + FP_DOUBLE,
+    r_DF6 = r_F12 + FP_DOUBLE,
+    r_DF7 = r_F14 + FP_DOUBLE,
+#if 0 /* only 16 fp regs supported currently */
+    r_DF8 = r_F16 + FP_DOUBLE,
+    r_DF9 = r_F18 + FP_DOUBLE,
+    r_DF10 = r_F20 + FP_DOUBLE,
+    r_DF11 = r_F22 + FP_DOUBLE,
+    r_DF12 = r_F24 + FP_DOUBLE,
+    r_DF13 = r_F26 + FP_DOUBLE,
+    r_DF14 = r_F28 + FP_DOUBLE,
+    r_DF15 = r_F30 + FP_DOUBLE,
+#endif
+    r_HI = EXTRA_REG_OFFSET,
+    r_LO,
+    r_PC,
+} NativeRegisterPool;
+
+/* Shift encodings */
+typedef enum MipsShiftEncodings {
+    kMipsLsl = 0x0,
+    kMipsLsr = 0x1,
+    kMipsAsr = 0x2,
+    kMipsRor = 0x3
+} MipsShiftEncodings;
+
+/* condition encodings */
+typedef enum MipsConditionCode {
+    kMipsCondEq = 0x0,    /* 0000 */
+    kMipsCondNe = 0x1,    /* 0001 */
+    kMipsCondCs = 0x2,    /* 0010 */
+    kMipsCondCc = 0x3,    /* 0011 */
+    kMipsCondMi = 0x4,    /* 0100 */
+    kMipsCondPl = 0x5,    /* 0101 */
+    kMipsCondVs = 0x6,    /* 0110 */
+    kMipsCondVc = 0x7,    /* 0111 */
+    kMipsCondHi = 0x8,    /* 1000 */
+    kMipsCondLs = 0x9,    /* 1001 */
+    kMipsCondGe = 0xa,    /* 1010 */
+    kMipsCondLt = 0xb,    /* 1011 */
+    kMipsCondGt = 0xc,    /* 1100 */
+    kMipsCondLe = 0xd,    /* 1101 */
+    kMipsCondAl = 0xe,    /* 1110 */
+    kMipsCondNv = 0xf,    /* 1111 */
+} MipsConditionCode;
+
+typedef enum MipsThrowKind {
+    kMipsThrowNullPointer,
+    kMipsThrowDivZero,
+    kMipsThrowArrayBounds,
+    kMipsThrowVerificationError,
+    kMipsThrowNegArraySize,
+    kMipsThrowNoSuchMethod,
+    kMipsThrowStackOverflow,
+} MipsThrowKind;
+
+#define isPseudoOpCode(opCode) ((int)(opCode) < 0)
+
+/*
+ * The following enum defines the list of supported Thumb instructions by the
+ * assembler. Their corresponding snippet positions will be defined in
+ * Assemble.c.
+ */
+typedef enum MipsOpCode {
+    kMipsPseudoSuspendTarget = -15,
+    kMipsPseudoThrowTarget = -14,
+    kMipsPseudoCaseLabel = -13,
+    kMipsPseudoMethodEntry = -12,
+    kMipsPseudoMethodExit = -11,
+    kMipsPseudoBarrier = -10,
+    kMipsPseudoExtended = -9,
+    kMipsPseudoSSARep = -8,
+    kMipsPseudoEntryBlock = -7,
+    kMipsPseudoExitBlock = -6,
+    kMipsPseudoTargetLabel = -5,
+    kMipsPseudoDalvikByteCodeBoundary = -4,
+    kMipsPseudoPseudoAlign4 = -3,
+    kMipsPseudoEHBlockLabel = -2,
+    kMipsPseudoNormalBlockLabel = -1,
+
+    kMipsFirst,
+    kMips32BitData = kMipsFirst, /* data [31..0] */
+    kMipsAddiu,   /* addiu t,s,imm16 [001001] s[25..21] t[20..16] imm16[15..0] */
+    kMipsAddu,    /* add d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100001] */
+    kMipsAnd,     /* and d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100100] */
+    kMipsAndi,    /* andi t,s,imm16 [001100] s[25..21] t[20..16] imm16[15..0] */
+    kMipsB,       /* b o   [0001000000000000] o[15..0] */
+    kMipsBal,     /* bal o [0000010000010001] o[15..0] */
+    /* NOTE: the code tests the range kMipsBeq thru kMipsBne, so
+             adding an instruction in this range may require updates */
+    kMipsBeq,     /* beq s,t,o [000100] s[25..21] t[20..16] o[15..0] */
+    kMipsBeqz,    /* beqz s,o [000100] s[25..21] [00000] o[15..0] */
+    kMipsBgez,    /* bgez s,o [000001] s[25..21] [00001] o[15..0] */
+    kMipsBgtz,    /* bgtz s,o [000111] s[25..21] [00000] o[15..0] */
+    kMipsBlez,    /* blez s,o [000110] s[25..21] [00000] o[15..0] */
+    kMipsBltz,    /* bltz s,o [000001] s[25..21] [00000] o[15..0] */
+    kMipsBnez,    /* bnez s,o [000101] s[25..21] [00000] o[15..0] */
+    kMipsBne,     /* bne s,t,o [000101] s[25..21] t[20..16] o[15..0] */
+    kMipsDiv,     /* div s,t [000000] s[25..21] t[20..16] [0000000000011010] */
+#if __mips_isa_rev>=2
+    kMipsExt,     /* ext t,s,p,z [011111] s[25..21] t[20..16] z[15..11] p[10..6] [000000] */
+#endif
+    kMipsJal,     /* jal t [000011] t[25..0] */
+    kMipsJalr,    /* jalr d,s [000000] s[25..21] [00000] d[15..11]
+                                  hint[10..6] [001001] */
+    kMipsJr,      /* jr s [000000] s[25..21] [0000000000] hint[10..6] [001000] */
+    kMipsLahi,    /* lui t,imm16 [00111100000] t[20..16] imm16[15..0] load addr hi */
+    kMipsLalo,    /* ori t,s,imm16 [001001] s[25..21] t[20..16] imm16[15..0] load addr lo */
+    kMipsLui,     /* lui t,imm16 [00111100000] t[20..16] imm16[15..0] */
+    kMipsLb,      /* lb t,o(b) [100000] b[25..21] t[20..16] o[15..0] */
+    kMipsLbu,     /* lbu t,o(b) [100100] b[25..21] t[20..16] o[15..0] */
+    kMipsLh,      /* lh t,o(b) [100001] b[25..21] t[20..16] o[15..0] */
+    kMipsLhu,     /* lhu t,o(b) [100101] b[25..21] t[20..16] o[15..0] */
+    kMipsLw,      /* lw t,o(b) [100011] b[25..21] t[20..16] o[15..0] */
+    kMipsMfhi,    /* mfhi d [0000000000000000] d[15..11] [00000010000] */
+    kMipsMflo,    /* mflo d [0000000000000000] d[15..11] [00000010010] */
+    kMipsMove,    /* move d,s [000000] s[25..21] [00000] d[15..11] [00000100101] */
+    kMipsMovz,    /* movz d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000001010] */
+    kMipsMul,     /* mul d,s,t [011100] s[25..21] t[20..16] d[15..11] [00000000010] */
+    kMipsNop,     /* nop [00000000000000000000000000000000] */
+    kMipsNor,     /* nor d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100111] */
+    kMipsOr,      /* or d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100101] */
+    kMipsOri,     /* ori t,s,imm16 [001001] s[25..21] t[20..16] imm16[15..0] */
+    kMipsPref,    /* pref h,o(b) [101011] b[25..21] h[20..16] o[15..0] */
+    kMipsSb,      /* sb t,o(b) [101000] b[25..21] t[20..16] o[15..0] */
+#if __mips_isa_rev>=2
+    kMipsSeb,     /* seb d,t [01111100000] t[20..16] d[15..11] [10000100000] */
+    kMipsSeh,     /* seh d,t [01111100000] t[20..16] d[15..11] [11000100000] */
+#endif
+    kMipsSh,      /* sh t,o(b) [101001] b[25..21] t[20..16] o[15..0] */
+    kMipsSll,     /* sll d,t,a [00000000000] t[20..16] d[15..11] a[10..6] [000000] */
+    kMipsSllv,    /* sllv d,t,s [000000] s[25..21] t[20..16] d[15..11] [00000000100] */
+    kMipsSlt,     /* slt d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000101010] */
+    kMipsSlti,    /* slti t,s,imm16 [001010] s[25..21] t[20..16] imm16[15..0] */
+    kMipsSltu,    /* sltu d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000101011] */
+    kMipsSra,     /* sra d,s,imm5 [00000000000] t[20..16] d[15..11] imm5[10..6] [000011] */
+    kMipsSrav,    /* srav d,t,s [000000] s[25..21] t[20..16] d[15..11] [00000000111] */
+    kMipsSrl,     /* srl d,t,a [00000000000] t[20..16] d[20..16] a[10..6] [000010] */
+    kMipsSrlv,    /* srlv d,t,s [000000] s[25..21] t[20..16] d[15..11] [00000000110] */
+    kMipsSubu,    /* subu d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100011] */
+    kMipsSw,      /* sw t,o(b) [101011] b[25..21] t[20..16] o[15..0] */
+    kMipsXor,     /* xor d,s,t [000000] s[25..21] t[20..16] d[15..11] [00000100110] */
+    kMipsXori,    /* xori t,s,imm16 [001110] s[25..21] t[20..16] imm16[15..0] */
+#ifdef __mips_hard_float
+    kMipsFadds,   /* add.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000000] */
+    kMipsFsubs,   /* sub.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000001] */
+    kMipsFmuls,   /* mul.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000010] */
+    kMipsFdivs,   /* div.s d,s,t [01000110000] t[20..16] s[15..11] d[10..6] [000011] */
+    kMipsFaddd,   /* add.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000000] */
+    kMipsFsubd,   /* sub.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000001] */
+    kMipsFmuld,   /* mul.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000010] */
+    kMipsFdivd,   /* div.d d,s,t [01000110001] t[20..16] s[15..11] d[10..6] [000011] */
+    kMipsFcvtsd,  /* cvt.s.d d,s [01000110001] [00000] s[15..11] d[10..6] [100000] */
+    kMipsFcvtsw,  /* cvt.s.w d,s [01000110100] [00000] s[15..11] d[10..6] [100000] */
+    kMipsFcvtds,  /* cvt.d.s d,s [01000110000] [00000] s[15..11] d[10..6] [100001] */
+    kMipsFcvtdw,  /* cvt.d.w d,s [01000110100] [00000] s[15..11] d[10..6] [100001] */
+    kMipsFcvtws,  /* cvt.w.d d,s [01000110000] [00000] s[15..11] d[10..6] [100100] */
+    kMipsFcvtwd,  /* cvt.w.d d,s [01000110001] [00000] s[15..11] d[10..6] [100100] */
+    kMipsFmovs,   /* mov.s d,s [01000110000] [00000] s[15..11] d[10..6] [000110] */
+    kMipsFmovd,   /* mov.d d,s [01000110001] [00000] s[15..11] d[10..6] [000110] */
+    kMipsFlwc1,   /* lwc1 t,o(b) [110001] b[25..21] t[20..16] o[15..0] */
+    kMipsFldc1,   /* ldc1 t,o(b) [110101] b[25..21] t[20..16] o[15..0] */
+    kMipsFswc1,   /* swc1 t,o(b) [111001] b[25..21] t[20..16] o[15..0] */
+    kMipsFsdc1,   /* sdc1 t,o(b) [111101] b[25..21] t[20..16] o[15..0] */
+    kMipsMfc1,    /* mfc1 t,s [01000100000] t[20..16] s[15..11] [00000000000] */
+    kMipsMtc1,    /* mtc1 t,s [01000100100] t[20..16] s[15..11] [00000000000] */
+#endif
+    kMipsUndefined,  /* undefined [011001xxxxxxxxxxxxxxxx] */
+    kMipsLast
+} MipsOpCode;
+
+/* Bit flags describing the behavior of each native opcode */
+typedef enum MipsOpFeatureFlags {
+    kIsBranch = 0,
+    kRegDef0,
+    kRegDef1,
+    kRegDefSP,
+    kRegDefLR,
+    kRegDefList0,
+    kRegDefList1,
+    kRegUse0,
+    kRegUse1,
+    kRegUse2,
+    kRegUse3,
+    kRegUseSP,
+    kRegUsePC,
+    kRegUseList0,
+    kRegUseList1,
+    kNoOperand,
+    kIsUnaryOp,
+    kIsBinaryOp,
+    kIsTertiaryOp,
+    kIsQuadOp,
+    kIsIT,
+    kSetsCCodes,
+    kUsesCCodes,
+    kMemLoad,
+    kMemStore,
+} MipsOpFeatureFlags;
+
+#define IS_LOAD         (1 << kMemLoad)
+#define IS_STORE        (1 << kMemStore)
+#define IS_BRANCH       (1 << kIsBranch)
+#define REG_DEF0        (1 << kRegDef0)
+#define REG_DEF1        (1 << kRegDef1)
+#define REG_DEF_SP      (1 << kRegDefSP)
+#define REG_DEF_LR      (1 << kRegDefLR)
+#define REG_DEF_LIST0   (1 << kRegDefList0)
+#define REG_DEF_LIST1   (1 << kRegDefList1)
+#define REG_USE0        (1 << kRegUse0)
+#define REG_USE1        (1 << kRegUse1)
+#define REG_USE2        (1 << kRegUse2)
+#define REG_USE3        (1 << kRegUse3)
+#define REG_USE_SP      (1 << kRegUseSP)
+#define REG_USE_PC      (1 << kRegUsePC)
+#define REG_USE_LIST0   (1 << kRegUseList0)
+#define REG_USE_LIST1   (1 << kRegUseList1)
+#define NO_OPERAND      (1 << kNoOperand)
+#define IS_UNARY_OP     (1 << kIsUnaryOp)
+#define IS_BINARY_OP    (1 << kIsBinaryOp)
+#define IS_TERTIARY_OP  (1 << kIsTertiaryOp)
+#define IS_QUAD_OP      (1 << kIsQuadOp)
+#define IS_IT           (1 << kIsIT)
+#define SETS_CCODES     (1 << kSetsCCodes)
+#define USES_CCODES     (1 << kUsesCCodes)
+
+/* Common combo register usage patterns */
+#define REG_USE01       (REG_USE0 | REG_USE1)
+#define REG_USE02       (REG_USE0 | REG_USE2)
+#define REG_USE012      (REG_USE01 | REG_USE2)
+#define REG_USE12       (REG_USE1 | REG_USE2)
+#define REG_USE23       (REG_USE2 | REG_USE3)
+#define REG_DEF01       (REG_DEF0 | REG_DEF1)
+#define REG_DEF0_USE0   (REG_DEF0 | REG_USE0)
+#define REG_DEF0_USE1   (REG_DEF0 | REG_USE1)
+#define REG_DEF0_USE2   (REG_DEF0 | REG_USE2)
+#define REG_DEF0_USE01  (REG_DEF0 | REG_USE01)
+#define REG_DEF0_USE12  (REG_DEF0 | REG_USE12)
+#define REG_DEF01_USE2  (REG_DEF0 | REG_DEF1 | REG_USE2)
+
+/* Instruction assembly fieldLoc kind */
+typedef enum MipsEncodingKind {
+    kFmtUnused,
+    kFmtBitBlt,        /* Bit string using end/start */
+    kFmtDfp,           /* Double FP reg */
+    kFmtSfp,           /* Single FP reg */
+} MipsEncodingKind;
+
+/* Struct used to define the snippet positions for each Thumb opcode */
+typedef struct MipsEncodingMap {
+    u4 skeleton;
+    struct {
+        MipsEncodingKind kind;
+        int end;   /* end for kFmtBitBlt, 1-bit slice end for FP regs */
+        int start; /* start for kFmtBitBlt, 4-bit slice end for FP regs */
+    } fieldLoc[4];
+    MipsOpCode opcode;
+    int flags;
+    const char *name;
+    const char* fmt;
+    int size;
+} MipsEncodingMap;
+
+/* Keys for target-specific scheduling and other optimization hints */
+typedef enum MipsTargetOptHints {
+    kMaxHoistDistance,
+} MipsTargetOptHints;
+
+extern MipsEncodingMap EncodingMap[kMipsLast];
+
+/*
+ * Each instance of this struct holds a pseudo or real LIR instruction:
+ * - pseudo ones (eg labels and marks) and will be discarded by the assembler.
+ * - real ones will be assembled
+ *
+ * FIXME: notes below are Arm-specific.  We have 32 core registers instead
+ * of 16, and no IT blocks.  Must widen this or overload in order to
+ * support all 32 FP regs.  Perhaps use r0 for ccodes, eliminate IT block
+ * and overload gp with fp status word? (or just use a single bit for
+ * both core and fp condition code/status word?
+ *
+ * Machine resources are encoded into a 64-bit vector, where the encodings are
+ * as following:
+ * - [ 0..15]: general purpose registers including PC, SP, and LR
+ * - [16..47]: floating-point registers where d0 is expanded to s[01] and s0
+ *   starts at bit 16
+ * - [48]: IT block
+ * - [49]: integer condition code
+ * - [50]: floatint-point status word
+ */
+typedef struct MipsLIR {
+    LIR generic;
+    MipsOpCode opcode;
+    int operands[4];            // [0..3] = [dest, src1, src2, extra]
+    struct {
+        bool isNop:1;           // LIR is optimized away
+        bool pcRelFixup:1;      // May need pc-relative fixup
+        unsigned int age:4;     // default is 0, set lazily by the optimizer
+        unsigned int size:3;    // in bytes
+        unsigned int unused:23;
+    } flags;
+    int aliasInfo;              // For Dalvik register access & litpool disambiguation
+    u8 useMask;                 // Resource mask for use
+    u8 defMask;                 // Resource mask for def
+} MipsLIR;
+
+typedef struct SwitchTable {
+    int offset;
+    const u2* table;            // Original dex table
+    int vaddr;                  // Dalvik offset of switch opcode
+    MipsLIR* bxInst;             // Switch indirect branch instruction
+    MipsLIR** targets;           // Array of case targets
+} SwitchTable;
+
+typedef struct FillArrayData {
+    int offset;
+    const u2* table;           // Original dex table
+    int size;
+    int vaddr;                 // Dalvik offset of OP_FILL_ARRAY_DATA opcode
+} FillArrayData;
+
+/* Utility macros to traverse the LIR/MipsLIR list */
+#define NEXT_LIR(lir) ((MipsLIR *) lir->generic.next)
+#define PREV_LIR(lir) ((MipsLIR *) lir->generic.prev)
+
+#define NEXT_LIR_LVALUE(lir) (lir)->generic.next
+#define PREV_LIR_LVALUE(lir) (lir)->generic.prev
+
+#define IS_UIMM16(v) ((0 <= (v)) && ((v) <= 65535))
+#define IS_SIMM16(v) ((-32768 <= (v)) && ((v) <= 32766))
+#define IS_SIMM16_2WORD(v) ((-32764 <= (v)) && ((v) <= 32763)) /* 2 offsets must fit */
+
+}  // namespace art
+
+#endif  // ART_COMPILER_COMPILER_CODEGEN_MIPS_MIPSLIR_H_
diff --git a/src/compiler/codegen/mips/MipsRallocUtil.cc b/src/compiler/codegen/mips/MipsRallocUtil.cc
new file mode 100644
index 0000000..a243415
--- /dev/null
+++ b/src/compiler/codegen/mips/MipsRallocUtil.cc
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains Mips-specific register allocation support.
+ */
+
+#include "../../CompilerUtility.h"
+#include "../../CompilerIR.h"
+#include "../..//Dataflow.h"
+#include "MipsLIR.h"
+#include "Codegen.h"
+#include "../Ralloc.h"
+
+namespace art {
+
+/*
+ * Mark a callee-save fp register as promoted.  Note that
+ * vpush/vpop uses contiguous register lists so we must
+ * include any holes in the mask.  Associate holes with
+ * Dalvik register INVALID_VREG (0xFFFFU).
+ */
+STATIC void markPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
+{
+    UNIMPLEMENTED(FATAL) << "No support yet for promoted FP regs";
+#if 0
+    DCHECK_GE(reg, FP_REG_MASK + FP_CALLEE_SAVE_BASE);
+    reg = (reg & FP_REG_MASK) - FP_CALLEE_SAVE_BASE;
+    // Ensure fpVmapTable is large enough
+    int tableSize = cUnit->fpVmapTable.size();
+    for (int i = tableSize; i < (reg + 1); i++) {
+        cUnit->fpVmapTable.push_back(INVALID_VREG);
+    }
+    // Add the current mapping
+    cUnit->fpVmapTable[reg] = sReg;
+    // Size of fpVmapTable is high-water mark, use to set mask
+    cUnit->numFPSpills = cUnit->fpVmapTable.size();
+    cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << FP_CALLEE_SAVE_BASE;
+#endif
+}
+
+void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
+{
+    RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
+    RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
+    DCHECK(info1 && info2 && info1->pair && info2->pair &&
+           (info1->partner == info2->reg) &&
+           (info2->partner == info1->reg));
+    if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
+        if (!(info1->isTemp && info2->isTemp)) {
+            /* Should not happen.  If it does, there's a problem in evalLoc */
+            LOG(FATAL) << "Long half-temp, half-promoted";
+        }
+
+        info1->dirty = false;
+        info2->dirty = false;
+        if (oatS2VReg(cUnit, info2->sReg) <
+            oatS2VReg(cUnit, info1->sReg))
+            info1 = info2;
+        int vReg = oatS2VReg(cUnit, info1->sReg);
+        oatFlushRegWideImpl(cUnit, rSP,
+                                    oatVRegOffset(cUnit, vReg),
+                                    info1->reg, info1->partner);
+    }
+}
+
+void oatFlushReg(CompilationUnit* cUnit, int reg)
+{
+    RegisterInfo* info = oatGetRegInfo(cUnit, reg);
+    if (info->live && info->dirty) {
+        info->dirty = false;
+        int vReg = oatS2VReg(cUnit, info->sReg);
+        oatFlushRegImpl(cUnit, rSP,
+                                oatVRegOffset(cUnit, vReg),
+                                reg, kWord);
+    }
+}
+
+/* Give access to the target-dependent FP register encoding to common code */
+bool oatIsFpReg(int reg) {
+    return FPREG(reg);
+}
+
+uint32_t oatFpRegMask() {
+    return FP_REG_MASK;
+}
+
+/* Clobber all regs that might be used by an external C call */
+extern void oatClobberCalleeSave(CompilationUnit *cUnit)
+{
+    oatClobber(cUnit, r_ZERO);
+    oatClobber(cUnit, r_AT);
+    oatClobber(cUnit, r_V0);
+    oatClobber(cUnit, r_V1);
+    oatClobber(cUnit, r_A0);
+    oatClobber(cUnit, r_A1);
+    oatClobber(cUnit, r_A2);
+    oatClobber(cUnit, r_A3);
+    oatClobber(cUnit, r_T0);
+    oatClobber(cUnit, r_T1);
+    oatClobber(cUnit, r_T2);
+    oatClobber(cUnit, r_T3);
+    oatClobber(cUnit, r_T4);
+    oatClobber(cUnit, r_T5);
+    oatClobber(cUnit, r_T6);
+    oatClobber(cUnit, r_T7);
+    oatClobber(cUnit, r_T8);
+    oatClobber(cUnit, r_T9);
+    oatClobber(cUnit, r_K0);
+    oatClobber(cUnit, r_K1);
+    oatClobber(cUnit, r_GP);
+    oatClobber(cUnit, r_FP);
+    oatClobber(cUnit, r_RA);
+    oatClobber(cUnit, r_HI);
+    oatClobber(cUnit, r_LO);
+    oatClobber(cUnit, r_F0);
+    oatClobber(cUnit, r_F1);
+    oatClobber(cUnit, r_F2);
+    oatClobber(cUnit, r_F3);
+    oatClobber(cUnit, r_F4);
+    oatClobber(cUnit, r_F5);
+    oatClobber(cUnit, r_F6);
+    oatClobber(cUnit, r_F7);
+    oatClobber(cUnit, r_F8);
+    oatClobber(cUnit, r_F9);
+    oatClobber(cUnit, r_F10);
+    oatClobber(cUnit, r_F11);
+    oatClobber(cUnit, r_F12);
+    oatClobber(cUnit, r_F13);
+    oatClobber(cUnit, r_F14);
+    oatClobber(cUnit, r_F15);
+}
+
+extern RegLocation oatGetReturnWide(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN_WIDE;
+    oatClobber(cUnit, r_V0);
+    oatClobber(cUnit, r_V1);
+    oatMarkInUse(cUnit, r_V0);
+    oatMarkInUse(cUnit, r_V1);
+    oatMarkPair(cUnit, res.lowReg, res.highReg);
+    return res;
+}
+
+extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN_WIDE_ALT;
+    oatClobber(cUnit, r_F0);
+    oatClobber(cUnit, r_F1);
+    oatMarkInUse(cUnit, r_F0);
+    oatMarkInUse(cUnit, r_F1);
+    oatMarkPair(cUnit, res.lowReg, res.highReg);
+    return res;
+}
+
+extern RegLocation oatGetReturn(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN;
+    oatClobber(cUnit, r_V0);
+    oatMarkInUse(cUnit, r_V0);
+    return res;
+}
+
+extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
+{
+    RegLocation res = LOC_C_RETURN_ALT;
+    oatClobber(cUnit, r_F0);
+    oatMarkInUse(cUnit, r_F0);
+    return res;
+}
+
+extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
+{
+    return FPREG(reg) ? &cUnit->regPool->FPRegs[reg & FP_REG_MASK]
+                      : &cUnit->regPool->coreRegs[reg];
+}
+
+/* To be used when explicitly managing register use */
+extern void oatLockCallTemps(CompilationUnit* cUnit)
+{
+    oatLockTemp(cUnit, r_A0);
+    oatLockTemp(cUnit, r_A1);
+    oatLockTemp(cUnit, r_A2);
+    oatLockTemp(cUnit, r_A3);
+}
+
+/* To be used when explicitly managing register use */
+extern void oatFreeCallTemps(CompilationUnit* cUnit)
+{
+    oatFreeTemp(cUnit, r_A0);
+    oatFreeTemp(cUnit, r_A1);
+    oatFreeTemp(cUnit, r_A2);
+    oatFreeTemp(cUnit, r_A3);
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/mips/ArchVariant.cc b/src/compiler/codegen/mips/mips/ArchVariant.cc
new file mode 100644
index 0000000..5eca74b
--- /dev/null
+++ b/src/compiler/codegen/mips/mips/ArchVariant.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace art {
+
+/*
+ * This file is included by Codegen-mips.c, and implements architecture
+ * variant-specific code.
+ */
+
+/*
+ * Determine the initial instruction set to be used for this trace.
+ * Later components may decide to change this.
+ */
+JitInstructionSetType oatInstructionSet(void)
+{
+    return DALVIK_OAT_MIPS;
+}
+
+/* Architecture-specific initializations and checks go here */
+bool oatArchVariantInit(void)
+{
+    return true;
+}
+
+int dvmCompilerTargetOptHint(int key)
+{
+    int res;
+    switch (key) {
+        case kMaxHoistDistance:
+            res = 2;
+            break;
+        default:
+            LOG(FATAL) << "Unknown target optimization hint key: " << key;
+    }
+    return res;
+}
+
+void dvmCompilerGenMemBarrier(CompilationUnit *cUnit, int barrierKind)
+{
+#if ANDROID_SMP != 0
+    // FIXME: what to do here for Mips?
+#endif
+}
+
+}  // namespace art
diff --git a/src/compiler/codegen/mips/mips/Codegen.cc b/src/compiler/codegen/mips/mips/Codegen.cc
new file mode 100644
index 0000000..2b71b04
--- /dev/null
+++ b/src/compiler/codegen/mips/mips/Codegen.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _CODEGEN_C
+#define TGT_LIR MipsLIR
+
+/* For testing */
+#define __mips_hard_float
+
+#include "../../../Dalvik.h"
+#include "../../../CompilerInternals.h"
+#include "../MipsLIR.h"
+#include "../../Ralloc.h"
+#include "../Codegen.h"
+
+/* Mips codegen building blocks */
+#include "../CodegenCommon.cc"
+
+/* Mips-specific factory utilities */
+#include "../Mips32/Factory.cc"
+/* Target indepedent factory utilities */
+#include "../../CodegenFactory.cc"
+/* Mips-specific factory utilities */
+#include "../ArchFactory.cc"
+
+/* Mips32-specific codegen routines */
+#include "../Mips32/Gen.cc"
+/* FP codegen routines */
+#include "../FP/MipsFP.cc"
+
+/* Mips32-specific register allocation */
+#include "../Mips32/Ralloc.cc"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../../MethodCodegenDriver.cc"
+
+/* Target-independent local optimizations */
+#include "../../LocalOptimizations.cc"
+
+/* Common codegen utility code */
+#include "../../CodegenUtil.cc"
+
+/* Architecture manifest */
+#include "ArchVariant.cc"