OSDN Git Service

Major registor allocation rework - stage 1.
authorBill Buzbee <buzbee@google.com>
Thu, 24 Sep 2009 00:17:35 +0000 (17:17 -0700)
committerBill Buzbee <buzbee@google.com>
Fri, 30 Oct 2009 21:33:08 +0000 (14:33 -0700)
Direct usage of registers abstracted out.
Live values tracked locally.  Redundant loads and stores suppressed.
Address of registers and register pairs unified w/ single "location" mechanism
Register types inferred using existing dataflow analysis pass.
Interim (i.e. Hack) mechanism for storing register liveness info. Rewrite TBD.
Stubbed-out code for linear scan allocation (for loop and long traces)
Moved optimistic lock check for monitor-enter/exit inline for Thumb2
Minor restructuring, renaming and general cleanup of codegen
Renaming of enums to follow coding convention
Formatting fixes introduced by the enum renaming

Rewrite of RallocUtil.c and addition of linear scan to come in stage 2.

40 files changed:
vm/Dvm.mk
vm/compiler/Compiler.c
vm/compiler/CompilerIR.h
vm/compiler/CompilerUtility.h
vm/compiler/Dataflow.c
vm/compiler/Dataflow.h
vm/compiler/Frontend.c
vm/compiler/Loop.c
vm/compiler/Ralloc.c [new file with mode: 0644]
vm/compiler/codegen/CompilerCodegen.h
vm/compiler/codegen/Optimizer.h
vm/compiler/codegen/arm/ArchUtility.c
vm/compiler/codegen/arm/ArmLIR.h
vm/compiler/codegen/arm/Assemble.c
vm/compiler/codegen/arm/Codegen-armv5te-vfp.c
vm/compiler/codegen/arm/Codegen-armv5te.c
vm/compiler/codegen/arm/Codegen-armv7-a.c
vm/compiler/codegen/arm/Codegen.c
vm/compiler/codegen/arm/Codegen.h
vm/compiler/codegen/arm/GlobalOptimizations.c
vm/compiler/codegen/arm/RallocUtil.c [new file with mode: 0644]
vm/compiler/codegen/arm/Thumb2Util.c
vm/compiler/codegen/arm/ThumbUtil.c
vm/compiler/codegen/arm/armv5te-vfp/ArchVariant.c
vm/compiler/codegen/arm/armv5te/ArchVariant.c
vm/compiler/codegen/arm/armv7-a/ArchVariant.c
vm/compiler/template/armv5te-vfp/TEMPLATE_RESTORE_STATE.S [new file with mode: 0644]
vm/compiler/template/armv5te-vfp/TEMPLATE_SAVE_STATE.S [new file with mode: 0644]
vm/compiler/template/armv5te-vfp/TemplateOpList.h
vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S
vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S
vm/compiler/template/armv5te/TEMPLATE_RESTORE_STATE.S [new file with mode: 0644]
vm/compiler/template/armv5te/TEMPLATE_SAVE_STATE.S [new file with mode: 0644]
vm/compiler/template/armv5te/TemplateOpList.h
vm/compiler/template/armv7-a/TemplateOpList.h
vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
vm/interp/InterpDefs.h
vm/interp/Jit.c

index 96298f0..96340a2 100644 (file)
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -209,6 +209,7 @@ ifeq ($(WITH_JIT),true)
        compiler/IntermediateRep.c \
        compiler/Dataflow.c \
        compiler/Loop.c \
+       compiler/Ralloc.c \
        interp/Jit.c
 endif
 
index 21d7367..a44e1c3 100644 (file)
@@ -193,7 +193,7 @@ bool dvmCompilerSetupCodeCache(void)
 bool dvmCompilerStartup(void)
 {
     /* Make sure the BBType enum is in sane state */
-    assert(CHAINING_CELL_NORMAL == 0);
+    assert(kChainingCellNormal == 0);
 
     /* Architecture-specific chores to initialize */
     if (!dvmCompilerArchInit())
index d5f60b6..35611a3 100644 (file)
 
 #include "codegen/Optimizer.h"
 
+typedef enum RegisterClass {
+    kCoreReg,
+    kFPReg,
+    kAnyReg,
+} RegisterClass;
+
+typedef enum RegLocationType {
+    kLocDalvikFrame = 0,
+    kLocPhysReg,
+    kLocRetval,          // Return region in interpState
+    kLocSpill,
+} RegLocationType;
+
+typedef struct RegLocation {
+    RegLocationType location:2;
+    unsigned wide:1;
+    unsigned fp:1;      // Hint for float/double
+    u1 lowReg:6;        // First physical register
+    u1 highReg:6;       // 2nd physical register (if wide)
+    s2 sRegLow;         // SSA name for low Dalvik word
+} RegLocation;
+
+#define INVALID_SREG (-1)
+#define INVALID_REG (-1)
+
 typedef enum BBType {
     /* For coding convenience reasons chaining cell types should appear first */
-    CHAINING_CELL_NORMAL = 0,
-    CHAINING_CELL_HOT,
-    CHAINING_CELL_INVOKE_SINGLETON,
-    CHAINING_CELL_INVOKE_PREDICTED,
-    CHAINING_CELL_BACKWARD_BRANCH,
-    CHAINING_CELL_LAST,
-    ENTRY_BLOCK,
-    DALVIK_BYTECODE,
-    EXIT_BLOCK,
-    PC_RECONSTRUCTION,
-    EXCEPTION_HANDLING,
+    kChainingCellNormal = 0,
+    kChainingCellHot,
+    kChainingCellInvokeSingleton,
+    kChainingCellInvokePredicted,
+    kChainingCellBackwardBranch,
+    kChainingCellLast,
+    kEntryBlock,
+    kDalvikByteCode,
+    kExitBlock,
+    kPCReconstruction,
+    kExceptionHandling,
 } BBType;
 
 typedef struct ChainCellCounts {
     union {
-        u1 count[CHAINING_CELL_LAST];
+        u1 count[kChainingCellLast];
         u4 dummyForAlignment;
     } u;
 } ChainCellCounts;
@@ -49,13 +74,13 @@ typedef struct LIR {
 } LIR;
 
 enum ExtendedMIROpcode {
-    MIR_OP_FIRST = 256,
-    MIR_OP_PHI = MIR_OP_FIRST,
-    MIR_OP_NULL_N_RANGE_UP_CHECK,
-    MIR_OP_NULL_N_RANGE_DOWN_CHECK,
-    MIR_OP_LOWER_BOUND_CHECK,
-    MIR_OP_PUNT,
-    MIR_OP_LAST,
+    kMirOpFirst = 256,
+    kMirOpPhi = kMirOpFirst,
+    kMirOpNullNRangeUpCheck,
+    kMirOpNullNRangeDownCheck,
+    kMirOpLowerBound,
+    kMirOpPunt,
+    kMirOpLast,
 };
 
 struct SSARepresentation;
@@ -80,6 +105,7 @@ typedef struct MIR {
     struct MIR *next;
     struct SSARepresentation *ssaRep;
     int OptimizationFlags;
+    int seqNum;
 } MIR;
 
 struct BasicBlockDataFlow;
@@ -100,6 +126,7 @@ typedef struct BasicBlock {
 } BasicBlock;
 
 struct LoopAnalysis;
+struct RegisterPool;
 
 typedef struct CompilationUnit {
     int numInsts;
@@ -122,9 +149,9 @@ typedef struct CompilationUnit {
     bool halveInstCount;
     bool executionCount;                // Add code to count trace executions
     bool hasLoop;
-    int numChainingCells[CHAINING_CELL_LAST];
-    LIR *firstChainingLIR[CHAINING_CELL_LAST];
-    RegisterScoreboard registerScoreboard;      // Track register dependency
+    int numChainingCells[kChainingCellLast];
+    LIR *firstChainingLIR[kChainingCellLast];
+    struct RegisterPool *regPool;
     int optRound;                       // round number to tell an LIR's age
     JitInstructionSetType instructionSet;
     /* Number of total regs used in the whole cUnit after SSA transformation */
@@ -140,6 +167,10 @@ typedef struct CompilationUnit {
 
     /* Data structure for loop analysis and optimizations */
     struct LoopAnalysis *loopAnalysis;
+
+    /* Map SSA names to location */
+    RegLocation *regLocation;
+    int sequenceNumber;
 } CompilationUnit;
 
 BasicBlock *dvmCompilerNewBB(BBType blockType);
index 409de29..d5a9d84 100644 (file)
@@ -39,6 +39,8 @@ typedef struct GrowableList {
 } GrowableList;
 
 #define GET_ELEM_N(LIST, TYPE, N) (((TYPE*) LIST->elemList)[N])
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
 
 struct LIR;
 
index f8e736b..8525540 100644 (file)
@@ -27,7 +27,7 @@
  * TODO - many optimization flags are incomplete - they will only limit the
  * scope of optimizations but will not cause mis-optimizations.
  */
-int dvmCompilerDataFlowAttributes[MIR_OP_LAST] = {
+int dvmCompilerDataFlowAttributes[kMirOpLast] = {
     // 00 OP_NOP
     DF_NOP,
 
@@ -164,19 +164,19 @@ int dvmCompilerDataFlowAttributes[MIR_OP_LAST] = {
     DF_UA,
 
     // 2D OP_CMPL_FLOAT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC,
+    DF_DA | DF_UB | DF_UC | DF_FP_B | DF_FP_C,
 
     // 2E OP_CMPG_FLOAT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC,
+    DF_DA | DF_UB | DF_UC | DF_FP_B | DF_FP_C,
 
     // 2F OP_CMPL_DOUBLE vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA | DF_UB_WIDE | DF_UC_WIDE | DF_FP_B | DF_FP_C,
 
     // 30 OP_CMPG_DOUBLE vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA | DF_UB_WIDE | DF_UC_WIDE | DF_FP_B | DF_FP_C,
 
     // 31 OP_CMP_LONG vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA | DF_UB_WIDE | DF_UC_WIDE,
 
     // 32 OP_IF_EQ vA, vB, +CCCC
     DF_UA | DF_UB,
@@ -411,46 +411,46 @@ int dvmCompilerDataFlowAttributes[MIR_OP_LAST] = {
     DF_DA_WIDE | DF_UB_WIDE,
 
     // 7F OP_NEG_FLOAT vA, vB
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_FP_A | DF_FP_B,
 
     // 80 OP_NEG_DOUBLE vA, vB
-    DF_DA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
 
     // 81 OP_INT_TO_LONG vA, vB
     DF_DA_WIDE | DF_UB,
 
     // 82 OP_INT_TO_FLOAT vA, vB
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_FP_A,
 
     // 83 OP_INT_TO_DOUBLE vA, vB
-    DF_DA_WIDE | DF_UB,
+    DF_DA_WIDE | DF_UB | DF_FP_A,
 
     // 84 OP_LONG_TO_INT vA, vB
     DF_DA | DF_UB_WIDE,
 
     // 85 OP_LONG_TO_FLOAT vA, vB
-    DF_DA | DF_UB_WIDE,
+    DF_DA | DF_UB_WIDE | DF_FP_A,
 
     // 86 OP_LONG_TO_DOUBLE vA, vB
-    DF_DA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_FP_A,
 
     // 87 OP_FLOAT_TO_INT vA, vB
-    DF_DA | DF_UB,
+    DF_DA | DF_UB | DF_FP_B,
 
     // 88 OP_FLOAT_TO_LONG vA, vB
-    DF_DA_WIDE | DF_UB,
+    DF_DA_WIDE | DF_UB | DF_FP_B,
 
     // 89 OP_FLOAT_TO_DOUBLE vA, vB
-    DF_DA_WIDE | DF_UB,
+    DF_DA_WIDE | DF_UB | DF_FP_A | DF_FP_B,
 
     // 8A OP_DOUBLE_TO_INT vA, vB
-    DF_DA | DF_UB_WIDE,
+    DF_DA | DF_UB_WIDE | DF_FP_B,
 
     // 8B OP_DOUBLE_TO_LONG vA, vB
-    DF_DA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_FP_B,
 
     // 8C OP_DOUBLE_TO_FLOAT vA, vB
-    DF_DA | DF_UB_WIDE,
+    DF_DA | DF_UB_WIDE | DF_FP_A | DF_FP_B,
 
     // 8D OP_INT_TO_BYTE vA, vB
     DF_DA | DF_UB,
@@ -519,43 +519,43 @@ int dvmCompilerDataFlowAttributes[MIR_OP_LAST] = {
     DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
 
     // A3 OP_SHL_LONG vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC,
 
     // A4 OP_SHR_LONG vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC,
 
     // A5 OP_USHR_LONG vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC,
 
     // A6 OP_ADD_FLOAT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC,
+    DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
 
     // A7 OP_SUB_FLOAT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC,
+    DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
 
     // A8 OP_MUL_FLOAT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC,
+    DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
 
     // A9 OP_DIV_FLOAT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC,
+    DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
 
     // AA OP_REM_FLOAT vAA, vBB, vCC
-    DF_DA | DF_UB | DF_UC,
+    DF_DA | DF_UB | DF_UC | DF_FP_A | DF_FP_B | DF_FP_C,
 
     // AB OP_ADD_DOUBLE vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
 
     // AC OP_SUB_DOUBLE vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
 
     // AD OP_MUL_DOUBLE vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
 
     // AE OP_DIV_DOUBLE vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
 
     // AF OP_REM_DOUBLE vAA, vBB, vCC
-    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE,
+    DF_DA_WIDE | DF_UB_WIDE | DF_UC_WIDE | DF_FP_A | DF_FP_B | DF_FP_C,
 
     // B0 OP_ADD_INT_2ADDR vA, vB
     DF_DA | DF_UA | DF_UB,
@@ -615,43 +615,43 @@ int dvmCompilerDataFlowAttributes[MIR_OP_LAST] = {
     DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
 
     // C3 OP_SHL_LONG_2ADDR vA, vB
-    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB,
 
     // C4 OP_SHR_LONG_2ADDR vA, vB
-    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB,
 
     // C5 OP_USHR_LONG_2ADDR vA, vB
-    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB,
 
     // C6 OP_ADD_FLOAT_2ADDR vA, vB
-    DF_DA | DF_UA | DF_UB,
+    DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
 
     // C7 OP_SUB_FLOAT_2ADDR vA, vB
-    DF_DA | DF_UA | DF_UB,
+    DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
 
     // C8 OP_MUL_FLOAT_2ADDR vA, vB
-    DF_DA | DF_UA | DF_UB,
+    DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
 
     // C9 OP_DIV_FLOAT_2ADDR vA, vB
-    DF_DA | DF_UA | DF_UB,
+    DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
 
     // CA OP_REM_FLOAT_2ADDR vA, vB
-    DF_DA | DF_UA | DF_UB,
+    DF_DA | DF_UA | DF_UB | DF_FP_A | DF_FP_B,
 
     // CB OP_ADD_DOUBLE_2ADDR vA, vB
-    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
 
     // CC OP_SUB_DOUBLE_2ADDR vA, vB
-    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
 
     // CD OP_MUL_DOUBLE_2ADDR vA, vB
-    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
 
     // CE OP_DIV_DOUBLE_2ADDR vA, vB
-    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
 
     // CF OP_REM_DOUBLE_2ADDR vA, vB
-    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE,
+    DF_DA_WIDE | DF_UA_WIDE | DF_UB_WIDE | DF_FP_A | DF_FP_B,
 
     // D0 OP_ADD_INT_LIT16 vA, vB, #+CCCC
     DF_DA | DF_UB,
@@ -933,8 +933,8 @@ void dvmCompilerFindLiveIn(CompilationUnit *cUnit, BasicBlock *bb)
     MIR *mir;
     BitVector *useV, *defV, *liveInV;
 
-    if (bb->blockType != DALVIK_BYTECODE &&
-        bb->blockType != ENTRY_BLOCK) {
+    if (bb->blockType != kDalvikByteCode &&
+        bb->blockType != kEntryBlock) {
         return;
     }
 
@@ -1041,7 +1041,7 @@ void dvmCompilerDoSSAConversion(CompilationUnit *cUnit, BasicBlock *bb)
 {
     MIR *mir;
 
-    if (bb->blockType != DALVIK_BYTECODE && bb->blockType != ENTRY_BLOCK) {
+    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock) {
         return;
     }
 
@@ -1084,6 +1084,7 @@ void dvmCompilerDoSSAConversion(CompilationUnit *cUnit, BasicBlock *bb)
         if (numUses) {
             mir->ssaRep->numUses = numUses;
             mir->ssaRep->uses = dvmCompilerNew(sizeof(int) * numUses, false);
+            mir->ssaRep->fpUse = dvmCompilerNew(sizeof(bool) * numUses, false);
         }
 
         int numDefs = 0;
@@ -1098,6 +1099,7 @@ void dvmCompilerDoSSAConversion(CompilationUnit *cUnit, BasicBlock *bb)
         if (numDefs) {
             mir->ssaRep->numDefs = numDefs;
             mir->ssaRep->defs = dvmCompilerNew(sizeof(int) * numDefs, false);
+            mir->ssaRep->fpDef = dvmCompilerNew(sizeof(bool) * numDefs, false);
         }
 
         DecodedInstruction *dInsn = &mir->dalvikInsn;
@@ -1105,27 +1107,38 @@ void dvmCompilerDoSSAConversion(CompilationUnit *cUnit, BasicBlock *bb)
         if (dfAttributes & DF_HAS_USES) {
             numUses = 0;
             if (dfAttributes & DF_UA) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_A;
                 handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vA, numUses++);
             } else if (dfAttributes & DF_UA_WIDE) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_A;
                 handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vA, numUses++);
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_A;
                 handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vA+1, numUses++);
             }
             if (dfAttributes & DF_UB) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_B;
                 handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vB, numUses++);
             } else if (dfAttributes & DF_UB_WIDE) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_B;
                 handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vB, numUses++);
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_B;
                 handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vB+1, numUses++);
             }
             if (dfAttributes & DF_UC) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_C;
                 handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vC, numUses++);
             } else if (dfAttributes & DF_UC_WIDE) {
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_C;
                 handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vC, numUses++);
+                mir->ssaRep->fpUse[numUses] = dfAttributes & DF_FP_C;
                 handleSSAUse(cUnit, mir->ssaRep->uses, dInsn->vC+1, numUses++);
             }
         }
         if (dfAttributes & DF_HAS_DEFS) {
+            mir->ssaRep->fpDef[0] = dfAttributes & DF_FP_A;
             handleSSADef(cUnit, mir->ssaRep->defs, dInsn->vA, 0);
             if (dfAttributes & DF_DA_WIDE) {
+                mir->ssaRep->fpDef[1] = dfAttributes & DF_FP_A;
                 handleSSADef(cUnit, mir->ssaRep->defs, dInsn->vA+1, 1);
             }
         }
@@ -1228,14 +1241,14 @@ void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit,
     GrowableList *ivList = cUnit->loopAnalysis->ivList;
     MIR *mir;
 
-    if (bb->blockType != DALVIK_BYTECODE &&
-        bb->blockType != ENTRY_BLOCK) {
+    if (bb->blockType != kDalvikByteCode &&
+        bb->blockType != kEntryBlock) {
         return;
     }
 
     /* If the bb doesn't have a phi it cannot contain an induction variable */
     if (bb->firstMIRInsn == NULL ||
-        bb->firstMIRInsn->dalvikInsn.opCode != MIR_OP_PHI) {
+        bb->firstMIRInsn->dalvikInsn.opCode != kMirOpPhi) {
         return;
     }
 
@@ -1254,7 +1267,7 @@ void dvmCompilerFindInductionVariables(struct CompilationUnit *cUnit,
          */
         MIR *phi;
         for (phi = bb->firstMIRInsn; phi; phi = phi->next) {
-            if (phi->dalvikInsn.opCode != MIR_OP_PHI) break;
+            if (phi->dalvikInsn.opCode != kMirOpPhi) break;
 
             if (phi->ssaRep->defs[0] == mir->ssaRep->uses[0] &&
                 phi->ssaRep->uses[1] == mir->ssaRep->defs[0]) {
@@ -1424,8 +1437,8 @@ void dvmInitializeSSAConversion(CompilationUnit *cUnit)
      */
     for (i = 0; i < cUnit->numBlocks; i++) {
         BasicBlock *bb = cUnit->blockList[i];
-        if (bb->blockType == DALVIK_BYTECODE ||
-            bb->blockType == ENTRY_BLOCK) {
+        if (bb->blockType == kDalvikByteCode ||
+            bb->blockType == kEntryBlock) {
             bb->dataFlowInfo = dvmCompilerNew(sizeof(BasicBlockDataFlow), true);
         }
     }
index 384d430..72c8b25 100644 (file)
@@ -38,6 +38,9 @@ typedef enum DataFlowAttributePos {
     kNullNRangeCheck0,
     kNullNRangeCheck1,
     kNullNRangeCheck2,
+    kFPA,
+    kFPB,
+    kFPC,
 } DataFlowAttributes;
 
 #define DF_NOP                  0
@@ -58,6 +61,9 @@ typedef enum DataFlowAttributePos {
 #define DF_NULL_N_RANGE_CHECK_0 (1 << kNullNRangeCheck0)
 #define DF_NULL_N_RANGE_CHECK_1 (1 << kNullNRangeCheck1)
 #define DF_NULL_N_RANGE_CHECK_2 (1 << kNullNRangeCheck2)
+#define DF_FP_A                 (1 << kFPA)
+#define DF_FP_B                 (1 << kFPB)
+#define DF_FP_C                 (1 << kFPC)
 
 #define DF_HAS_USES             (DF_UA | DF_UB | DF_UC | DF_UA_WIDE | \
                                  DF_UB_WIDE | DF_UC_WIDE)
@@ -72,7 +78,7 @@ typedef enum DataFlowAttributePos {
 #define DF_B_IS_REG             (DF_UB | DF_UB_WIDE)
 #define DF_C_IS_REG             (DF_UC | DF_UC_WIDE)
 
-extern int dvmCompilerDataFlowAttributes[MIR_OP_LAST];
+extern int dvmCompilerDataFlowAttributes[kMirOpLast];
 
 typedef struct BasicBlockDataFlow {
     BitVector *useV;
@@ -85,8 +91,10 @@ typedef struct BasicBlockDataFlow {
 typedef struct SSARepresentation {
     int numUses;
     int *uses;
+    bool *fpUse;
     int numDefs;
     int *defs;
+    bool *fpDef;
 } SSARepresentation;
 
 typedef struct InductionVariableInfo {
index 959c99a..28d4d9f 100644 (file)
@@ -266,9 +266,6 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
     /* Locate the entry to store compilation statistics for this method */
     methodStats = analyzeMethodBody(desc->method);
 
-    cUnit.registerScoreboard.nullCheckedRegs =
-        dvmCompilerAllocBitVector(desc->method->registersSize, false);
-
     /* Initialize the printMe flag */
     cUnit.printMe = gDvmJit.printMe;
 
@@ -339,11 +336,11 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
     }
 
     /* Allocate the entry block */
-    lastBB = startBB = curBB = dvmCompilerNewBB(ENTRY_BLOCK);
+    lastBB = startBB = curBB = dvmCompilerNewBB(kEntryBlock);
     curBB->startOffset = curOffset;
     curBB->id = numBlocks++;
 
-    curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
+    curBB = dvmCompilerNewBB(kDalvikByteCode);
     curBB->startOffset = curOffset;
     curBB->id = numBlocks++;
 
@@ -382,7 +379,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
             if (currRun->frag.runEnd) {
                 break;
             } else {
-                curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
+                curBB = dvmCompilerNewBB(kDalvikByteCode);
                 lastBB->next = curBB;
                 lastBB = curBB;
                 curBB->id = numBlocks++;
@@ -461,7 +458,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
             if (cUnit.printMe) {
                 LOGD("Natural loop detected!");
             }
-            exitBB = dvmCompilerNewBB(EXIT_BLOCK);
+            exitBB = dvmCompilerNewBB(kExitBlock);
             lastBB->next = exitBB;
             lastBB = exitBB;
 
@@ -472,7 +469,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
             loopBranch->taken = exitBB;
 #if defined(WITH_SELF_VERIFICATION)
             BasicBlock *backwardCell =
-                dvmCompilerNewBB(CHAINING_CELL_BACKWARD_BRANCH);
+                dvmCompilerNewBB(kChainingCellBackwardBranch);
             lastBB->next = backwardCell;
             lastBB = backwardCell;
 
@@ -482,7 +479,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
 #elif defined(WITH_JIT_TUNING)
             if (gDvmJit.profile) {
                 BasicBlock *backwardCell =
-                    dvmCompilerNewBB(CHAINING_CELL_BACKWARD_BRANCH);
+                    dvmCompilerNewBB(kChainingCellBackwardBranch);
                 lastBB->next = backwardCell;
                 lastBB = backwardCell;
 
@@ -497,7 +494,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
 #endif
 
             /* Create the chaining cell as the fallthrough of the exit block */
-            exitChainingCell = dvmCompilerNewBB(CHAINING_CELL_NORMAL);
+            exitChainingCell = dvmCompilerNewBB(kChainingCellNormal);
             lastBB->next = exitChainingCell;
             lastBB = exitChainingCell;
 
@@ -517,9 +514,9 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
              * chaining cell.
              */
             if (isInvoke || curBB->needFallThroughBranch) {
-                lastBB->next = dvmCompilerNewBB(CHAINING_CELL_HOT);
+                lastBB->next = dvmCompilerNewBB(kChainingCellHot);
             } else {
-                lastBB->next = dvmCompilerNewBB(CHAINING_CELL_NORMAL);
+                lastBB->next = dvmCompilerNewBB(kChainingCellNormal);
             }
             lastBB = lastBB->next;
             lastBB->id = numBlocks++;
@@ -535,30 +532,30 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
             if (isInvoke) {
                 /* Monomorphic callee */
                 if (callee) {
-                    newBB = dvmCompilerNewBB(CHAINING_CELL_INVOKE_SINGLETON);
+                    newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
                     newBB->startOffset = 0;
                     newBB->containingMethod = callee;
                 /* Will resolve at runtime */
                 } else {
-                    newBB = dvmCompilerNewBB(CHAINING_CELL_INVOKE_PREDICTED);
+                    newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
                     newBB->startOffset = 0;
                 }
             /* For unconditional branches, request a hot chaining cell */
             } else {
 #if !defined(WITH_SELF_VERIFICATION)
                 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
-                                                  CHAINING_CELL_HOT :
-                                                  CHAINING_CELL_NORMAL);
+                                                  kChainingCellHot :
+                                                  kChainingCellNormal);
                 newBB->startOffset = targetOffset;
 #else
                 /* Handle branches that branch back into the block */
                 if (targetOffset >= curBB->firstMIRInsn->offset &&
                     targetOffset <= curBB->lastMIRInsn->offset) {
-                    newBB = dvmCompilerNewBB(CHAINING_CELL_BACKWARD_BRANCH);
+                    newBB = dvmCompilerNewBB(kChainingCellBackwardBranch);
                 } else {
                     newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
-                                                      CHAINING_CELL_HOT :
-                                                      CHAINING_CELL_NORMAL);
+                                                      kChainingCellHot :
+                                                      kChainingCellNormal);
                 }
                 newBB->startOffset = targetOffset;
 #endif
@@ -571,12 +568,12 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
     }
 
     /* Now create a special block to host PC reconstruction code */
-    lastBB->next = dvmCompilerNewBB(PC_RECONSTRUCTION);
+    lastBB->next = dvmCompilerNewBB(kPCReconstruction);
     lastBB = lastBB->next;
     lastBB->id = numBlocks++;
 
     /* And one final block that publishes the PC and raise the exception */
-    lastBB->next = dvmCompilerNewBB(EXCEPTION_HANDLING);
+    lastBB->next = dvmCompilerNewBB(kExceptionHandling);
     lastBB = lastBB->next;
     lastBB->id = numBlocks++;
 
@@ -613,6 +610,7 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
     /* Preparation for SSA conversion */
     dvmInitializeSSAConversion(&cUnit);
 
+
     if (cUnit.hasLoop) {
         dvmCompilerLoopOpt(&cUnit);
     }
@@ -620,6 +618,8 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
         dvmCompilerNonLoopAnalysis(&cUnit);
     }
 
+    dvmCompilerInitializeRegAlloc(&cUnit);  // Needs to happen after SSA naming
+
     if (cUnit.printMe) {
         dvmCompilerDumpCompilationUnit(&cUnit);
     }
@@ -627,6 +627,9 @@ bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
     /* Set the instruction set to use (NOTE: later components may change it) */
     cUnit.instructionSet = dvmCompilerInstructionSet(&cUnit);
 
+    /* Allocate Registers */
+    dvmCompilerRegAlloc(&cUnit);
+
     /* Convert MIR to LIR, etc. */
     dvmCompilerMIR2LIR(&cUnit);
 
@@ -673,7 +676,7 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
     int blockID = 0;
     unsigned int curOffset = 0;
 
-    BasicBlock *firstBlock = dvmCompilerNewBB(DALVIK_BYTECODE);
+    BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
     firstBlock->id = blockID++;
 
     /* Allocate the bit-vector to track the beginning of basic blocks */
@@ -763,7 +766,7 @@ bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
 
                 /* Block not split yet - do it now */
                 if (j == cUnit.numBlocks) {
-                    BasicBlock *newBB = dvmCompilerNewBB(DALVIK_BYTECODE);
+                    BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
                     newBB->id = blockID++;
                     newBB->firstMIRInsn = insn;
                     newBB->startOffset = insn->offset;
index ffd5883..e996ca2 100644 (file)
@@ -58,7 +58,7 @@ static void handlePhiPlacement(CompilationUnit *cUnit)
             continue;
         }
         MIR *phi = dvmCompilerNew(sizeof(MIR), true);
-        phi->dalvikInsn.opCode = MIR_OP_PHI;
+        phi->dalvikInsn.opCode = kMirOpPhi;
         phi->dalvikInsn.vA = i;
         dvmCompilerPrependMIR(loopBody, phi);
     }
@@ -72,7 +72,7 @@ static void fillPhiNodeContents(CompilationUnit *cUnit)
     MIR *mir;
 
     for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
-        if (mir->dalvikInsn.opCode != MIR_OP_PHI) break;
+        if (mir->dalvikInsn.opCode != kMirOpPhi) break;
         int dalvikReg = mir->dalvikInsn.vA;
 
         mir->ssaRep->numUses = 2;
@@ -395,7 +395,7 @@ static void genHoistedChecks(CompilationUnit *cUnit)
 
         MIR *rangeCheckMIR = dvmCompilerNew(sizeof(MIR), true);
         rangeCheckMIR->dalvikInsn.opCode = (loopAnalysis->isCountUpLoop) ?
-            MIR_OP_NULL_N_RANGE_UP_CHECK : MIR_OP_NULL_N_RANGE_DOWN_CHECK;
+            kMirOpNullNRangeUpCheck : kMirOpNullNRangeDownCheck;
         rangeCheckMIR->dalvikInsn.vA = arrayReg;
         rangeCheckMIR->dalvikInsn.vB = idxReg;
         rangeCheckMIR->dalvikInsn.vC = loopAnalysis->endConditionReg;
@@ -414,7 +414,7 @@ static void genHoistedChecks(CompilationUnit *cUnit)
     if (loopAnalysis->arrayAccessInfo->numUsed != 0) {
         if (loopAnalysis->isCountUpLoop) {
             MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
-            boundCheckMIR->dalvikInsn.opCode = MIR_OP_LOWER_BOUND_CHECK;
+            boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound;
             boundCheckMIR->dalvikInsn.vA = idxReg;
             boundCheckMIR->dalvikInsn.vB = globalMinC;
             dvmCompilerAppendMIR(entry, boundCheckMIR);
@@ -422,7 +422,7 @@ static void genHoistedChecks(CompilationUnit *cUnit)
             if (loopAnalysis->loopBranchOpcode == OP_IF_LT ||
                 loopAnalysis->loopBranchOpcode == OP_IF_LE) {
                 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
-                boundCheckMIR->dalvikInsn.opCode = MIR_OP_LOWER_BOUND_CHECK;
+                boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound;
                 boundCheckMIR->dalvikInsn.vA = loopAnalysis->endConditionReg;
                 boundCheckMIR->dalvikInsn.vB = globalMinC;
                 /*
@@ -438,14 +438,14 @@ static void genHoistedChecks(CompilationUnit *cUnit)
                 /* Array index will fall below 0 */
                 if (globalMinC < 0) {
                     MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
-                    boundCheckMIR->dalvikInsn.opCode = MIR_OP_PUNT;
+                    boundCheckMIR->dalvikInsn.opCode = kMirOpPunt;
                     dvmCompilerAppendMIR(entry, boundCheckMIR);
                 }
             } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) {
                 /* Array index will fall below 0 */
                 if (globalMinC < -1) {
                     MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
-                    boundCheckMIR->dalvikInsn.opCode = MIR_OP_PUNT;
+                    boundCheckMIR->dalvikInsn.opCode = kMirOpPunt;
                     dvmCompilerAppendMIR(entry, boundCheckMIR);
                 }
             } else {
@@ -462,9 +462,9 @@ void dvmCompilerLoopOpt(CompilationUnit *cUnit)
     int numDalvikReg = cUnit->method->registersSize;
     LoopAnalysis *loopAnalysis = dvmCompilerNew(sizeof(LoopAnalysis), true);
 
-    assert(cUnit->blockList[0]->blockType == ENTRY_BLOCK);
-    assert(cUnit->blockList[2]->blockType == DALVIK_BYTECODE);
-    assert(cUnit->blockList[3]->blockType == EXIT_BLOCK);
+    assert(cUnit->blockList[0]->blockType == kEntryBlock);
+    assert(cUnit->blockList[2]->blockType == kDalvikByteCode);
+    assert(cUnit->blockList[3]->blockType == kExitBlock);
 
     cUnit->loopAnalysis = loopAnalysis;
     /*
diff --git a/vm/compiler/Ralloc.c b/vm/compiler/Ralloc.c
new file mode 100644 (file)
index 0000000..1a3e27e
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2009 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 "Dataflow.h"
+
+typedef struct LiveRange {
+    int ssaName;
+    bool active;
+    int first;
+    int last;
+} LiveRange;
+
+int computeLiveRange(LiveRange *list, BasicBlock *bb, int seqNum)
+{
+    MIR *mir;
+    int i;
+
+    if (bb->blockType != kDalvikByteCode &&
+        bb->blockType != kEntryBlock)
+        return seqNum;
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        SSARepresentation *ssaRep = mir->ssaRep;
+        mir->seqNum = seqNum;
+        if (ssaRep) {
+            for (i=0; i< ssaRep->numUses; i++) {
+                int reg = ssaRep->uses[i];
+                list[reg].first = MIN(list[reg].first, seqNum);
+                list[reg].active = true;
+            }
+            for (i=0; i< ssaRep->numDefs; i++) {
+                int reg = ssaRep->defs[i];
+                list[reg].last = MAX(list[reg].last, seqNum + 1);
+                list[reg].active = true;
+            }
+            seqNum += 2;
+        }
+    }
+    return seqNum;
+}
+
+/*
+ * Quick & dirty - make FP usage sticky.  This is strictly a hint - local
+ * code generation will handle misses.  It might be worthwhile to collaborate
+ * with dx/dexopt to avoid reusing the same Dalvik temp for values of
+ * different types.
+ */
+static void inferTypes(CompilationUnit *cUnit, BasicBlock *bb)
+{
+    MIR *mir;
+    if (bb->blockType != kDalvikByteCode &&
+        bb->blockType != kEntryBlock)
+        return;
+
+    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
+        SSARepresentation *ssaRep = mir->ssaRep;
+        if (ssaRep) {
+            int i;
+            for (i=0; ssaRep->fpUse && i< ssaRep->numUses; i++) {
+                if (ssaRep->fpUse[i])
+                    cUnit->regLocation[ssaRep->uses[i]].fp = true;
+            }
+            for (i=0; ssaRep->fpDef && i< ssaRep->numDefs; i++) {
+                if (ssaRep->fpDef[i])
+                    cUnit->regLocation[ssaRep->defs[i]].fp = true;
+            }
+        }
+    }
+}
+
+/*
+ * Determine whether to use simple or aggressive register allocation.  In
+ * general, loops and full methods will get aggressive.
+ */
+static bool simpleTrace(CompilationUnit *cUnit)
+{
+    //TODO: flesh out
+    return true;
+}
+
+/*
+ * Target-independent register allocation.  Requires target-dependent
+ * helper functions and assumes free list, temp list and spill region.
+ * Uses a variant of linear scan and produces a mapping between SSA names
+ * and location.  Location may be original Dalvik register, hardware
+ * register or spill location.
+ *
+ * Method:
+ *    0.  Allocate the structure to hold the SSA name life ranges
+ *    1.  Number each MIR instruction, counting by 2.
+ *        +0 -> The "read" of the operands
+ *        +1 -> The definition of the target resource
+ *    2.  Compute live ranges for all SSA names *not* including the
+ *        subscript 0 original Dalvik names.  Phi functions ignored
+ *        at this point.
+ *    3.  Sort the live range list by lowest range start.
+ *    4.  Process and remove all Phi functions.
+ *        o If there is no live range collisions among all operands and
+ *          the target of a Phi function, collapse operands and target
+ *          and rewrite using target SSA name.
+ *        o If there is a collision, introduce copies.
+ *    5.  Allocate in order of increasing live range start.
+ */
+static const RegLocation freshLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
+                                     INVALID_REG, INVALID_SREG};
+void dvmCompilerRegAlloc(CompilationUnit *cUnit)
+{
+    int i;
+    int seqNum = 0;
+    LiveRange *ranges;
+    RegLocation *loc;
+    int *ssaToDalvikMap = (int *) cUnit->ssaToDalvikMap->elemList;
+
+    /* Allocate the location map */
+    loc = (RegLocation*)dvmCompilerNew(cUnit->numSSARegs * sizeof(*loc), true);
+    for (i=0; i< cUnit->numSSARegs; i++) {
+        loc[i] = freshLoc;
+        loc[i].sRegLow = i;
+    }
+    cUnit->regLocation = loc;
+
+    /* Do type inference pass */
+    for (i=0; i < cUnit->numBlocks; i++) {
+        inferTypes(cUnit, cUnit->blockList[i]);
+    }
+
+    if (simpleTrace(cUnit)) {
+        /*
+         * Just rename everything back to subscript 0 names and don't do
+         * any explicit promotion.  Local allocator will opportunistically
+         * promote on the fly.
+         */
+        for (i=0; i < cUnit->numSSARegs; i++) {
+            cUnit->regLocation[i].sRegLow =
+                DECODE_REG(dvmConvertSSARegToDalvik(cUnit, loc[i].sRegLow));
+        }
+    } else {
+        // Compute live ranges
+        ranges = dvmCompilerNew(cUnit->numSSARegs * sizeof(*ranges), true);
+        for (i=0; i < cUnit->numSSARegs; i++)
+            ranges[i].active = false;
+        seqNum = computeLiveRange(ranges, cUnit->blockList[i], seqNum);
+        //TODO: phi squash & linear scan promotion
+    }
+}
index 28e13a5..8f138a6 100644 (file)
@@ -36,6 +36,12 @@ void* dvmJitChain(void *tgtAddr, u4* branchAddr);
 u4* dvmJitUnchain(void *codeAddr);
 void dvmJitUnchainAll(void);
 
+/* Implemented in codegen/<target>/Ralloc.c */
+void dvmCompilerRegAlloc(CompilationUnit *cUnit);
+
+/* Implemented in codegen/<target>/Thumb<version>Util.c */
+void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit);
+
 /* Implemented in codegen/<target>/<target_variant>/ArchVariant.c */
 JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit);
 
index 487e864..713aa41 100644 (file)
 typedef enum optControlVector {
     kLoadStoreElimination = 0,
     kLoadHoisting,
+    kTrackLiveTemps,
+    kSuppressLoads,
 } optControlVector;
 
 /* Forward declarations */
 struct CompilationUnit;
 struct LIR;
 
-/*
- * 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 RegisterScoreboard {
-    BitVector *nullCheckedRegs; // Track which registers have been null-checked
-    int liveDalvikReg;          // Track which Dalvik register is live
-    int nativeReg;              // And the mapped native register
-    int nativeRegHi;            // And the mapped native register
-    bool isWide;                // Whether a pair of registers are alive
-    int fp[32];                 // Track the Dalvik register held in a SFP reg
-    int nextFP;                 // Next index for FP register allocation
-} RegisterScoreboard;
-
 void dvmCompilerApplyLocalOptimizations(struct CompilationUnit *cUnit,
                                         struct LIR *head,
                                         struct LIR *tail);
index 57d5d74..d8cac49 100644 (file)
@@ -118,28 +118,28 @@ static void buildInsnString(char *fmt, ArmLIR *lir, char* buf,
                        break;
                    case 'c':
                        switch (operand) {
-                           case ARM_COND_EQ:
+                           case kArmCondEq:
                                strcpy(tbuf, "eq");
                                break;
-                           case ARM_COND_NE:
+                           case kArmCondNe:
                                strcpy(tbuf, "ne");
                                break;
-                           case ARM_COND_LT:
+                           case kArmCondLt:
                                strcpy(tbuf, "lt");
                                break;
-                           case ARM_COND_GE:
+                           case kArmCondGe:
                                strcpy(tbuf, "ge");
                                break;
-                           case ARM_COND_GT:
+                           case kArmCondGt:
                                strcpy(tbuf, "gt");
                                break;
-                           case ARM_COND_LE:
+                           case kArmCondLe:
                                strcpy(tbuf, "le");
                                break;
-                           case ARM_COND_CS:
+                           case kArmCondCs:
                                strcpy(tbuf, "cs");
                                break;
-                           case ARM_COND_MI:
+                           case kArmCondMi:
                                strcpy(tbuf, "mi");
                                break;
                            default:
@@ -244,57 +244,57 @@ void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
 
     /* Handle pseudo-ops individually, and all regular insns as a group */
     switch(lir->opCode) {
-        case ARM_PSEUDO_BARRIER:
+        case kArmPseudoBarrier:
             LOGD("-------- BARRIER");
             break;
-        case ARM_PSEUDO_EXTENDED_MIR:
+        case kArmPseudoExtended:
             /* intentional fallthrough */
-        case ARM_PSEUDO_SSA_REP:
+        case kArmPseudoSSARep:
             DUMP_SSA_REP(LOGD("-------- %s\n", (char *) dest));
             break;
-        case ARM_PSEUDO_TARGET_LABEL:
+        case kArmPseudoTargetLabel:
             break;
-        case ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH:
+        case ARM_PSEUDO_kChainingCellBackwardBranch:
             LOGD("-------- chaining cell (backward branch): 0x%04x\n", dest);
             break;
-        case ARM_PSEUDO_CHAINING_CELL_NORMAL:
+        case ARM_PSEUDO_kChainingCellNormal:
             LOGD("-------- chaining cell (normal): 0x%04x\n", dest);
             break;
-        case ARM_PSEUDO_CHAINING_CELL_HOT:
+        case ARM_PSEUDO_kChainingCellHot:
             LOGD("-------- chaining cell (hot): 0x%04x\n", dest);
             break;
-        case ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED:
+        case ARM_PSEUDO_kChainingCellInvokePredicted:
             LOGD("-------- chaining cell (predicted)\n");
             break;
-        case ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON:
+        case ARM_PSEUDO_kChainingCellInvokeSingleton:
             LOGD("-------- chaining cell (invoke singleton): %s/%p\n",
                  ((Method *)dest)->name,
                  ((Method *)dest)->insns);
             break;
-        case ARM_PSEUDO_ENTRY_BLOCK:
+        case ARM_PSEUDO_kEntryBlock:
             LOGD("-------- entry offset: 0x%04x\n", dest);
             break;
-        case ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY:
+        case ARM_PSEUDO_kDalvikByteCode_BOUNDARY:
             LOGD("-------- dalvik offset: 0x%04x @ %s\n", dest,
                  (char *) lir->operands[1]);
             break;
-        case ARM_PSEUDO_EXIT_BLOCK:
+        case ARM_PSEUDO_kExitBlock:
             LOGD("-------- exit offset: 0x%04x\n", dest);
             break;
-        case ARM_PSEUDO_ALIGN4:
+        case kArmPseudoPseudoAlign4:
             LOGD("%p (%04x): .align4\n", baseAddr + offset, offset);
             break;
-        case ARM_PSEUDO_PC_RECONSTRUCTION_CELL:
+        case ARM_PSEUDO_kPCReconstruction_CELL:
             LOGD("-------- reconstruct dalvik PC : 0x%04x @ +0x%04x\n", dest,
                  lir->operands[1]);
             break;
-        case ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL:
+        case ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL:
             /* Do nothing */
             break;
-        case ARM_PSEUDO_EH_BLOCK_LABEL:
+        case kArmPseudoEHBlockLabel:
             LOGD("Exception_Handling:\n");
             break;
-        case ARM_PSEUDO_NORMAL_BLOCK_LABEL:
+        case kArmPseudoNormalBlockLabel:
             LOGD("L%#06x:\n", dest);
             break;
         default:
index 4e97499..bff6cc8 100644 (file)
 #define LOWREG(x) ((x & 0x7) == 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 */
 /* non-existant physical register */
 #define rNone   (-1)
 
+/* RegisterLocation templates return values (r0, or r0/r1) */
+#define LOC_C_RETURN {kLocPhysReg, 0, 0, r0, 0, -1}
+#define LOC_C_RETURN_WIDE {kLocPhysReg, 1, 0, r0, r1, -1}
+/* RegisterLocation templates for interpState->retVal; */
+#define LOC_DALVIK_RETURN_VAL {kLocRetval, 0, 0, 0, 0, -1}
+#define LOC_DALVIK_RETURN_VAL_WIDE {kLocRetval, 1, 0, 0, 0, -1}
+
+ /*
+ * 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 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 {
+    BitVector *nullCheckedRegs; // Track which registers have been null-checked
+    int numCoreTemps;
+    RegisterInfo *coreTemps;
+    int numFPTemps;
+    RegisterInfo *FPTemps;
+    int numCoreRegs;
+    RegisterInfo *coreRegs;
+    int numFPRegs;
+    RegisterInfo *FPRegs;
+} RegisterPool;
+
 typedef enum ResourceEncodingPos {
     kGPReg0     = 0,
     kRegSP      = 13,
@@ -103,49 +148,49 @@ typedef enum ResourceEncodingPos {
 #define DECODE_ALIAS_INFO_WIDE(X)       ((X & 0x80000000) ? 1 : 0)
 
 typedef enum OpSize {
-    WORD,
-    LONG,
-    SINGLE,
-    DOUBLE,
-    UNSIGNED_HALF,
-    SIGNED_HALF,
-    UNSIGNED_BYTE,
-    SIGNED_BYTE,
+    kWord,
+    kLong,
+    kSingle,
+    kDouble,
+    kUnsignedHalf,
+    kSignedHalf,
+    kUnsignedByte,
+    kSignedByte,
 } OpSize;
 
 typedef enum OpKind {
-    OP_MOV,
-    OP_MVN,
-    OP_CMP,
-    OP_LSL,
-    OP_LSR,
-    OP_ASR,
-    OP_ROR,
-    OP_NOT,
-    OP_AND,
-    OP_OR,
-    OP_XOR,
-    OP_NEG,
-    OP_ADD,
-    OP_ADC,
-    OP_SUB,
-    OP_SBC,
-    OP_RSUB,
-    OP_MUL,
-    OP_DIV,
-    OP_REM,
-    OP_BIC,
-    OP_CMN,
-    OP_TST,
-    OP_BKPT,
-    OP_BLX,
-    OP_PUSH,
-    OP_POP,
-    OP_2CHAR,
-    OP_2SHORT,
-    OP_2BYTE,
-    OP_COND_BR,
-    OP_UNCOND_BR,
+    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,
 } OpKind;
 
 typedef enum NativeRegisterPool {
@@ -215,24 +260,32 @@ typedef enum NativeRegisterPool {
     dr15 = fr30 + FP_DOUBLE,
 } NativeRegisterPool;
 
+/* Shift encodings */
+typedef enum ArmShiftEncodings {
+    kArmLsl = 0x0,
+    kArmLsr = 0x1,
+    kArmAsr = 0x2,
+    kArmRor = 0x3
+} ArmShiftEncodings;
+
 /* Thumb condition encodings */
 typedef enum ArmConditionCode {
-    ARM_COND_EQ = 0x0,    /* 0000 */
-    ARM_COND_NE = 0x1,    /* 0001 */
-    ARM_COND_CS = 0x2,    /* 0010 */
-    ARM_COND_CC = 0x3,    /* 0011 */
-    ARM_COND_MI = 0x4,    /* 0100 */
-    ARM_COND_PL = 0x5,    /* 0101 */
-    ARM_COND_VS = 0x6,    /* 0110 */
-    ARM_COND_VC = 0x7,    /* 0111 */
-    ARM_COND_HI = 0x8,    /* 1000 */
-    ARM_COND_LS = 0x9,    /* 1001 */
-    ARM_COND_GE = 0xa,    /* 1010 */
-    ARM_COND_LT = 0xb,    /* 1011 */
-    ARM_COND_GT = 0xc,    /* 1100 */
-    ARM_COND_LE = 0xd,    /* 1101 */
-    ARM_COND_AL = 0xe,    /* 1110 */
-    ARM_COND_NV = 0xf,    /* 1111 */
+    kArmCondEq = 0x0,    /* 0000 */
+    kArmCondNe = 0x1,    /* 0001 */
+    kArmCondCs = 0x2,    /* 0010 */
+    kArmCondCc = 0x3,    /* 0011 */
+    kArmCondMi = 0x4,    /* 0100 */
+    kArmCondPl = 0x5,    /* 0101 */
+    kArmCondVs = 0x6,    /* 0110 */
+    kArmCondVc = 0x7,    /* 0111 */
+    kArmCondHi = 0x8,    /* 1000 */
+    kArmCondLs = 0x9,    /* 1001 */
+    kArmCondGe = 0xa,    /* 1010 */
+    kArmCondLt = 0xb,    /* 1011 */
+    kArmCondGt = 0xc,    /* 1100 */
+    kArmCondLe = 0xd,    /* 1101 */
+    kArmCondAl = 0xe,    /* 1110 */
+    kArmCondNv = 0xf,    /* 1111 */
 } ArmConditionCode;
 
 #define isPseudoOpCode(opCode) ((int)(opCode) < 0)
@@ -243,290 +296,311 @@ typedef enum ArmConditionCode {
  * Assemble.c.
  */
 typedef enum ArmOpCode {
-    ARM_PSEUDO_BARRIER = -17,
-    ARM_PSEUDO_EXTENDED_MIR = -16,
-    ARM_PSEUDO_SSA_REP = -15,
-    ARM_PSEUDO_ENTRY_BLOCK = -14,
-    ARM_PSEUDO_EXIT_BLOCK = -13,
-    ARM_PSEUDO_TARGET_LABEL = -12,
-    ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH = -11,
-    ARM_PSEUDO_CHAINING_CELL_HOT = -10,
-    ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED = -9,
-    ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON = -8,
-    ARM_PSEUDO_CHAINING_CELL_NORMAL = -7,
-    ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY = -6,
-    ARM_PSEUDO_ALIGN4 = -5,
-    ARM_PSEUDO_PC_RECONSTRUCTION_CELL = -4,
-    ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL = -3,
-    ARM_PSEUDO_EH_BLOCK_LABEL = -2,
-    ARM_PSEUDO_NORMAL_BLOCK_LABEL = -1,
+    kArmPseudoBarrier = -17,
+    kArmPseudoExtended = -16,
+    kArmPseudoSSARep = -15,
+    ARM_PSEUDO_kEntryBlock = -14,
+    ARM_PSEUDO_kExitBlock = -13,
+    kArmPseudoTargetLabel = -12,
+    ARM_PSEUDO_kChainingCellBackwardBranch = -11,
+    ARM_PSEUDO_kChainingCellHot = -10,
+    ARM_PSEUDO_kChainingCellInvokePredicted = -9,
+    ARM_PSEUDO_kChainingCellInvokeSingleton = -8,
+    ARM_PSEUDO_kChainingCellNormal = -7,
+    ARM_PSEUDO_kDalvikByteCode_BOUNDARY = -6,
+    kArmPseudoPseudoAlign4 = -5,
+    ARM_PSEUDO_kPCReconstruction_CELL = -4,
+    ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL = -3,
+    kArmPseudoEHBlockLabel = -2,
+    kArmPseudoNormalBlockLabel = -1,
     /************************************************************************/
-    ARM_16BIT_DATA,       /* DATA   [0] rd[15..0] */
-    THUMB_ADC_RR,         /* adc     [0100000101] rm[5..3] rd[2..0] */
-    THUMB_ADD_RRI3,       /* add(1)  [0001110] imm_3[8..6] rn[5..3] rd[2..0]*/
-    THUMB_ADD_RI8,        /* add(2)  [00110] rd[10..8] imm_8[7..0] */
-    THUMB_ADD_RRR,        /* add(3)  [0001100] rm[8..6] rn[5..3] rd[2..0] */
-    THUMB_ADD_RR_LH,      /* add(4)  [01000100] H12[01] rm[5..3] rd[2..0] */
-    THUMB_ADD_RR_HL,      /* add(4)  [01001000] H12[10] rm[5..3] rd[2..0] */
-    THUMB_ADD_RR_HH,      /* add(4)  [01001100] H12[11] rm[5..3] rd[2..0] */
-    THUMB_ADD_PC_REL,     /* add(5)  [10100] rd[10..8] imm_8[7..0] */
-    THUMB_ADD_SP_REL,     /* add(6)  [10101] rd[10..8] imm_8[7..0] */
-    THUMB_ADD_SPI7,       /* add(7)  [101100000] imm_7[6..0] */
-    THUMB_AND_RR,         /* and     [0100000000] rm[5..3] rd[2..0] */
-    THUMB_ASR_RRI5,       /* asr(1)  [00010] imm_5[10..6] rm[5..3] rd[2..0] */
-    THUMB_ASR_RR,         /* asr(2)  [0100000100] rs[5..3] rd[2..0] */
-    THUMB_B_COND,         /* b(1)    [1101] cond[11..8] offset_8[7..0] */
-    THUMB_B_UNCOND,       /* b(2)    [11100] offset_11[10..0] */
-    THUMB_BIC_RR,         /* bic     [0100001110] rm[5..3] rd[2..0] */
-    THUMB_BKPT,           /* bkpt    [10111110] imm_8[7..0] */
-    THUMB_BLX_1,          /* blx(1)  [111] H[10] offset_11[10..0] */
-    THUMB_BLX_2,          /* blx(1)  [111] H[01] offset_11[10..0] */
-    THUMB_BL_1,           /* blx(1)  [111] H[10] offset_11[10..0] */
-    THUMB_BL_2,           /* blx(1)  [111] H[11] offset_11[10..0] */
-    THUMB_BLX_R,          /* blx(2)  [010001111] rm[6..3] [000] */
-    THUMB_BX,             /* bx      [010001110] H2[6..6] rm[5..3] SBZ[000] */
-    THUMB_CMN_RR,         /* cmn     [0100001011] rm[5..3] rd[2..0] */
-    THUMB_CMP_RI8,        /* cmp(1)  [00101] rn[10..8] imm_8[7..0] */
-    THUMB_CMP_RR,         /* cmp(2)  [0100001010] rm[5..3] rd[2..0] */
-    THUMB_CMP_LH,         /* cmp(3)  [01000101] H12[01] rm[5..3] rd[2..0] */
-    THUMB_CMP_HL,         /* cmp(3)  [01000110] H12[10] rm[5..3] rd[2..0] */
-    THUMB_CMP_HH,         /* cmp(3)  [01000111] H12[11] rm[5..3] rd[2..0] */
-    THUMB_EOR_RR,         /* eor     [0100000001] rm[5..3] rd[2..0] */
-    THUMB_LDMIA,          /* ldmia   [11001] rn[10..8] reglist [7..0] */
-    THUMB_LDR_RRI5,       /* ldr(1)  [01101] imm_5[10..6] rn[5..3] rd[2..0] */
-    THUMB_LDR_RRR,        /* ldr(2)  [0101100] rm[8..6] rn[5..3] rd[2..0] */
-    THUMB_LDR_PC_REL,     /* ldr(3)  [01001] rd[10..8] imm_8[7..0] */
-    THUMB_LDR_SP_REL,     /* ldr(4)  [10011] rd[10..8] imm_8[7..0] */
-    THUMB_LDRB_RRI5,      /* ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0] */
-    THUMB_LDRB_RRR,       /* ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0] */
-    THUMB_LDRH_RRI5,      /* ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0] */
-    THUMB_LDRH_RRR,       /* ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0] */
-    THUMB_LDRSB_RRR,      /* ldrsb   [0101011] rm[8..6] rn[5..3] rd[2..0] */
-    THUMB_LDRSH_RRR,      /* ldrsh   [0101111] rm[8..6] rn[5..3] rd[2..0] */
-    THUMB_LSL_RRI5,       /* lsl(1)  [00000] imm_5[10..6] rm[5..3] rd[2..0] */
-    THUMB_LSL_RR,         /* lsl(2)  [0100000010] rs[5..3] rd[2..0] */
-    THUMB_LSR_RRI5,       /* lsr(1)  [00001] imm_5[10..6] rm[5..3] rd[2..0] */
-    THUMB_LSR_RR,         /* lsr(2)  [0100000011] rs[5..3] rd[2..0] */
-    THUMB_MOV_IMM,        /* mov(1)  [00100] rd[10..8] imm_8[7..0] */
-    THUMB_MOV_RR,         /* mov(2)  [0001110000] rn[5..3] rd[2..0] */
-    THUMB_MOV_RR_H2H,     /* mov(3)  [01000111] H12[11] rm[5..3] rd[2..0] */
-    THUMB_MOV_RR_H2L,     /* mov(3)  [01000110] H12[01] rm[5..3] rd[2..0] */
-    THUMB_MOV_RR_L2H,     /* mov(3)  [01000101] H12[10] rm[5..3] rd[2..0] */
-    THUMB_MUL,            /* mul     [0100001101] rm[5..3] rd[2..0] */
-    THUMB_MVN,            /* mvn     [0100001111] rm[5..3] rd[2..0] */
-    THUMB_NEG,            /* neg     [0100001001] rm[5..3] rd[2..0] */
-    THUMB_ORR,            /* orr     [0100001100] rm[5..3] rd[2..0] */
-    THUMB_POP,            /* pop     [1011110] r[8..8] rl[7..0] */
-    THUMB_PUSH,           /* push    [1011010] r[8..8] rl[7..0] */
-    THUMB_ROR_RR,         /* ror     [0100000111] rs[5..3] rd[2..0] */
-    THUMB_SBC,            /* sbc     [0100000110] rm[5..3] rd[2..0] */
-    THUMB_STMIA,          /* stmia   [11000] rn[10..8] reglist [7.. 0] */
-    THUMB_STR_RRI5,       /* str(1)  [01100] imm_5[10..6] rn[5..3] rd[2..0] */
-    THUMB_STR_RRR,        /* str(2)  [0101000] rm[8..6] rn[5..3] rd[2..0] */
-    THUMB_STR_SP_REL,     /* str(3)  [10010] rd[10..8] imm_8[7..0] */
-    THUMB_STRB_RRI5,      /* strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0] */
-    THUMB_STRB_RRR,       /* strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0] */
-    THUMB_STRH_RRI5,      /* strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0] */
-    THUMB_STRH_RRR,       /* strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0] */
-    THUMB_SUB_RRI3,       /* sub(1)  [0001111] imm_3[8..6] rn[5..3] rd[2..0]*/
-    THUMB_SUB_RI8,        /* sub(2)  [00111] rd[10..8] imm_8[7..0] */
-    THUMB_SUB_RRR,        /* sub(3)  [0001101] rm[8..6] rn[5..3] rd[2..0] */
-    THUMB_SUB_SPI7,       /* sub(4)  [101100001] imm_7[6..0] */
-    THUMB_SWI,            /* swi     [11011111] imm_8[7..0] */
-    THUMB_TST,            /* tst     [0100001000] rm[5..3] rn[2..0] */
-    THUMB2_VLDRS,         /* vldr low  sx [111011011001] rn[19..16] rd[15-12]
-                                       [1010] imm_8[7..0] */
-    THUMB2_VLDRD,         /* vldr low  dx [111011011001] rn[19..16] rd[15-12]
-                                       [1011] imm_8[7..0] */
-    THUMB2_VMULS,         /* vmul vd, vn, vm [111011100010] rn[19..16]
-                                       rd[15-12] [10100000] rm[3..0] */
-    THUMB2_VMULD,         /* vmul vd, vn, vm [111011100010] rn[19..16]
-                                       rd[15-12] [10110000] rm[3..0] */
-    THUMB2_VSTRS,         /* vstr low  sx [111011011000] rn[19..16] rd[15-12]
-                                       [1010] imm_8[7..0] */
-    THUMB2_VSTRD,         /* vstr low  dx [111011011000] rn[19..16] rd[15-12]
-                                       [1011] imm_8[7..0] */
-    THUMB2_VSUBS,         /* vsub vd, vn, vm [111011100011] rn[19..16]
-                                       rd[15-12] [10100040] rm[3..0] */
-    THUMB2_VSUBD,         /* vsub vd, vn, vm [111011100011] rn[19..16]
-                                       rd[15-12] [10110040] rm[3..0] */
-    THUMB2_VADDS,         /* vadd vd, vn, vm [111011100011] rn[19..16]
-                                       rd[15-12] [10100000] rm[3..0] */
-    THUMB2_VADDD,         /* vadd vd, vn, vm [111011100011] rn[19..16]
-                                       rd[15-12] [10110000] rm[3..0] */
-    THUMB2_VDIVS,         /* vdiv vd, vn, vm [111011101000] rn[19..16]
-                                       rd[15-12] [10100000] rm[3..0] */
-    THUMB2_VDIVD,         /* vdiv vd, vn, vm [111011101000] rn[19..16]
-                                       rd[15-12] [10110000] rm[3..0] */
-    THUMB2_VCVTIF,        /* vcvt.F32 vd, vm [1110111010111000] vd[15..12]
-                                       [10101100] vm[3..0] */
-    THUMB2_VCVTID,        /* vcvt.F64 vd, vm [1110111010111000] vd[15..12]
+    kArm16BitData,       /* DATA   [0] rd[15..0] */
+    kThumbAdcRR,         /* adc     [0100000101] rm[5..3] rd[2..0] */
+    kThumbAddRRI3,       /* add(1)  [0001110] imm_3[8..6] rn[5..3] rd[2..0]*/
+    kThumbAddRI8,        /* add(2)  [00110] rd[10..8] imm_8[7..0] */
+    kThumbAddRRR,        /* add(3)  [0001100] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbAddRRLH,       /* add(4)  [01000100] H12[01] rm[5..3] rd[2..0] */
+    kThumbAddRRHL,       /* add(4)  [01001000] H12[10] rm[5..3] rd[2..0] */
+    kThumbAddRRHH,       /* add(4)  [01001100] H12[11] rm[5..3] rd[2..0] */
+    kThumbAddPcRel,      /* add(5)  [10100] rd[10..8] imm_8[7..0] */
+    kThumbAddSpRel,      /* add(6)  [10101] rd[10..8] imm_8[7..0] */
+    kThumbAddSpI7,       /* add(7)  [101100000] imm_7[6..0] */
+    kThumbAndRR,         /* and     [0100000000] rm[5..3] rd[2..0] */
+    kThumbAsrRRI5,       /* asr(1)  [00010] imm_5[10..6] rm[5..3] rd[2..0] */
+    kThumbAsrRR,         /* asr(2)  [0100000100] rs[5..3] rd[2..0] */
+    kThumbBCond,         /* b(1)    [1101] cond[11..8] offset_8[7..0] */
+    kThumbBUncond,       /* b(2)    [11100] offset_11[10..0] */
+    kThumbBicRR,         /* bic     [0100001110] rm[5..3] rd[2..0] */
+    kThumbBkpt,          /* bkpt    [10111110] imm_8[7..0] */
+    kThumbBlx1,          /* blx(1)  [111] H[10] offset_11[10..0] */
+    kThumbBlx2,          /* blx(1)  [111] H[01] offset_11[10..0] */
+    kThumbBl1,           /* blx(1)  [111] H[10] offset_11[10..0] */
+    kThumbBl2,           /* blx(1)  [111] H[11] offset_11[10..0] */
+    kThumbBlxR,          /* blx(2)  [010001111] rm[6..3] [000] */
+    kThumbBx,            /* bx      [010001110] H2[6..6] rm[5..3] SBZ[000] */
+    kThumbCmnRR,         /* cmn     [0100001011] rm[5..3] rd[2..0] */
+    kThumbCmpRI8,        /* cmp(1)  [00101] rn[10..8] imm_8[7..0] */
+    kThumbCmpRR,         /* cmp(2)  [0100001010] rm[5..3] rd[2..0] */
+    kThumbCmpLH,         /* cmp(3)  [01000101] H12[01] rm[5..3] rd[2..0] */
+    kThumbCmpHL,         /* cmp(3)  [01000110] H12[10] rm[5..3] rd[2..0] */
+    kThumbCmpHH,         /* cmp(3)  [01000111] H12[11] rm[5..3] rd[2..0] */
+    kThumbEorRR,         /* eor     [0100000001] rm[5..3] rd[2..0] */
+    kThumbLdmia,         /* ldmia   [11001] rn[10..8] reglist [7..0] */
+    kThumbLdrRRI5,       /* ldr(1)  [01101] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbLdrRRR,        /* ldr(2)  [0101100] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbLdrPcRel,      /* ldr(3)  [01001] rd[10..8] imm_8[7..0] */
+    kThumbLdrSpRel,      /* ldr(4)  [10011] rd[10..8] imm_8[7..0] */
+    kThumbLdrbRRI5,      /* ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbLdrbRRR,       /* ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbLdrhRRI5,      /* ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbLdrhRRR,       /* ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbLdrsbRRR,      /* ldrsb   [0101011] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbLdrshRRR,      /* ldrsh   [0101111] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbLslRRI5,       /* lsl(1)  [00000] imm_5[10..6] rm[5..3] rd[2..0] */
+    kThumbLslRR,         /* lsl(2)  [0100000010] rs[5..3] rd[2..0] */
+    kThumbLsrRRI5,       /* lsr(1)  [00001] imm_5[10..6] rm[5..3] rd[2..0] */
+    kThumbLsrRR,         /* lsr(2)  [0100000011] rs[5..3] rd[2..0] */
+    kThumbMovImm,        /* mov(1)  [00100] rd[10..8] imm_8[7..0] */
+    kThumbMovRR,         /* mov(2)  [0001110000] rn[5..3] rd[2..0] */
+    kThumbMovRR_H2H,     /* mov(3)  [01000111] H12[11] rm[5..3] rd[2..0] */
+    kThumbMovRR_H2L,     /* mov(3)  [01000110] H12[01] rm[5..3] rd[2..0] */
+    kThumbMovRR_L2H,     /* mov(3)  [01000101] H12[10] rm[5..3] rd[2..0] */
+    kThumbMul,           /* mul     [0100001101] rm[5..3] rd[2..0] */
+    kThumbMvn,           /* mvn     [0100001111] rm[5..3] rd[2..0] */
+    kThumbNeg,           /* neg     [0100001001] rm[5..3] rd[2..0] */
+    kThumbOrr,           /* orr     [0100001100] rm[5..3] rd[2..0] */
+    kThumbPop,           /* pop     [1011110] r[8..8] rl[7..0] */
+    kThumbPush,          /* push    [1011010] r[8..8] rl[7..0] */
+    kThumbRorR,          /* ror     [0100000111] rs[5..3] rd[2..0] */
+    kThumbSbc,           /* sbc     [0100000110] rm[5..3] rd[2..0] */
+    kThumbStmia,         /* stmia   [11000] rn[10..8] reglist [7.. 0] */
+    kThumbStrRRI5,       /* str(1)  [01100] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbStrRRR,        /* str(2)  [0101000] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbStrSpRel,      /* str(3)  [10010] rd[10..8] imm_8[7..0] */
+    kThumbStrbRRI5,      /* strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbStrbRRR,       /* strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbStrhRRI5,      /* strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0] */
+    kThumbStrhRRR,       /* strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbSubRRI3,       /* sub(1)  [0001111] imm_3[8..6] rn[5..3] rd[2..0]*/
+    kThumbSubRI8,        /* sub(2)  [00111] rd[10..8] imm_8[7..0] */
+    kThumbSubRRR,        /* sub(3)  [0001101] rm[8..6] rn[5..3] rd[2..0] */
+    kThumbSubSpI7,       /* sub(4)  [101100001] imm_7[6..0] */
+    kThumbSwi,           /* swi     [11011111] imm_8[7..0] */
+    kThumbTst,           /* tst     [0100001000] rm[5..3] rn[2..0] */
+    kThumb2Vldrs,        /* vldr low  sx [111011011001] rn[19..16] rd[15-12]
+                                    [1010] imm_8[7..0] */
+    kThumb2Vldrd,        /* vldr low  dx [111011011001] rn[19..16] rd[15-12]
+                                    [1011] imm_8[7..0] */
+    kThumb2Vmuls,        /* vmul vd, vn, vm [111011100010] rn[19..16]
+                                    rd[15-12] [10100000] rm[3..0] */
+    kThumb2Vmuld,        /* vmul vd, vn, vm [111011100010] rn[19..16]
+                                    rd[15-12] [10110000] rm[3..0] */
+    kThumb2Vstrs,        /* vstr low  sx [111011011000] rn[19..16] rd[15-12]
+                                    [1010] imm_8[7..0] */
+    kThumb2Vstrd,        /* vstr low  dx [111011011000] rn[19..16] rd[15-12]
+                                    [1011] imm_8[7..0] */
+    kThumb2Vsubs,        /* vsub vd, vn, vm [111011100011] rn[19..16]
+                                    rd[15-12] [10100040] rm[3..0] */
+    kThumb2Vsubd,        /* vsub vd, vn, vm [111011100011] rn[19..16]
+                                    rd[15-12] [10110040] rm[3..0] */
+    kThumb2Vadds,        /* vadd vd, vn, vm [111011100011] rn[19..16]
+                                    rd[15-12] [10100000] rm[3..0] */
+    kThumb2Vaddd,        /* vadd vd, vn, vm [111011100011] rn[19..16]
+                                    rd[15-12] [10110000] rm[3..0] */
+    kThumb2Vdivs,        /* vdiv vd, vn, vm [111011101000] rn[19..16]
+                                    rd[15-12] [10100000] rm[3..0] */
+    kThumb2Vdivd,        /* vdiv vd, vn, vm [111011101000] rn[19..16]
+                                    rd[15-12] [10110000] rm[3..0] */
+    kThumb2VcvtIF,       /* vcvt.F32 vd, vm [1110111010111000] vd[15..12]
+                                    [10101100] vm[3..0] */
+    kThumb2VcvtID,       /* vcvt.F64 vd, vm [1110111010111000] vd[15..12]
                                        [10111100] vm[3..0] */
-    THUMB2_VCVTFI,        /* vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12]
+    kThumb2VcvtFI,       /* vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12]
                                        [10101100] vm[3..0] */
-    THUMB2_VCVTDI,        /* vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12]
+    kThumb2VcvtDI,       /* vcvt.S32.F32 vd, vm [1110111010111101] vd[15..12]
                                        [10111100] vm[3..0] */
-    THUMB2_VCVTFD,        /* vcvt.F64.F32 vd, vm [1110111010110111] vd[15..12]
+    kThumb2VcvtFd,       /* vcvt.F64.F32 vd, vm [1110111010110111] vd[15..12]
                                        [10101100] vm[3..0] */
-    THUMB2_VCVTDF,        /* vcvt.F32.F64 vd, vm [1110111010110111] vd[15..12]
+    kThumb2VcvtDF,       /* vcvt.F32.F64 vd, vm [1110111010110111] vd[15..12]
                                        [10111100] vm[3..0] */
-    THUMB2_VSQRTS,        /* vsqrt.f32 vd, vm [1110111010110001] vd[15..12]
+    kThumb2Vsqrts,       /* vsqrt.f32 vd, vm [1110111010110001] vd[15..12]
                                        [10101100] vm[3..0] */
-    THUMB2_VSQRTD,        /* vsqrt.f64 vd, vm [1110111010110001] vd[15..12]
+    kThumb2Vsqrtd,       /* vsqrt.f64 vd, vm [1110111010110001] vd[15..12]
                                        [10111100] vm[3..0] */
-    THUMB2_MOV_IMM_SHIFT, /* mov(T2) rd, #<const> [11110] i [00001001111]
+    kThumb2MovImmShift,  /* mov(T2) rd, #<const> [11110] i [00001001111]
                                        imm3 rd[11..8] imm8 */
-    THUMB2_MOV_IMM16,     /* mov(T3) rd, #<const> [11110] i [0010100] imm4 [0]
+    kThumb2MovImm16,     /* mov(T3) rd, #<const> [11110] i [0010100] imm4 [0]
                                        imm3 rd[11..8] imm8 */
-    THUMB2_STR_RRI12,     /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
+    kThumb2StrRRI12,     /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
                                        rn[19..16] rt[15..12] imm12[11..0] */
-    THUMB2_LDR_RRI12,     /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
+    kThumb2LdrRRI12,     /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
                                        rn[19..16] rt[15..12] imm12[11..0] */
-    THUMB2_STR_RRI8_PREDEC, /* str(Imm,T4) rd,[rn,#-imm8] [111110000100]
+    kThumb2StrRRI8Predec, /* str(Imm,T4) rd,[rn,#-imm8] [111110000100]
                                        rn[19..16] rt[15..12] [1100] imm[7..0]*/
-    THUMB2_LDR_RRI8_PREDEC, /* ldr(Imm,T4) rd,[rn,#-imm8] [111110000101]
+    kThumb2LdrRRI8Predec, /* ldr(Imm,T4) rd,[rn,#-imm8] [111110000101]
                                        rn[19..16] rt[15..12] [1100] imm[7..0]*/
-    THUMB2_CBNZ,          /* cbnz rd,<label> [101110] i [1] imm5[7..3]
+    kThumb2Cbnz,         /* cbnz rd,<label> [101110] i [1] imm5[7..3]
                                        rn[2..0] */
-    THUMB2_CBZ,           /* cbn rd,<label> [101100] i [1] imm5[7..3]
+    kThumb2Cbz,          /* cbn rd,<label> [101100] i [1] imm5[7..3]
                                        rn[2..0] */
-    THUMB2_ADD_RRI12,     /* add rd, rn, #imm12 [11110] i [100000] rn[19..16]
+    kThumb2AddRRI12,     /* add rd, rn, #imm12 [11110] i [100000] rn[19..16]
                                        [0] imm3[14..12] rd[11..8] imm8[7..0] */
-    THUMB2_MOV_RR,        /* mov rd, rm [11101010010011110000] rd[11..8]
+    kThumb2MovRR,        /* mov rd, rm [11101010010011110000] rd[11..8]
                                        [0000] rm[3..0] */
-    THUMB2_VMOVS,         /* vmov.f32 vd, vm [111011101] D [110000]
+    kThumb2Vmovs,        /* vmov.f32 vd, vm [111011101] D [110000]
                                        vd[15..12] 101001] M [0] vm[3..0] */
-    THUMB2_VMOVD,         /* vmov.f64 vd, vm [111011101] D [110000]
+    kThumb2Vmovd,        /* vmov.f64 vd, vm [111011101] D [110000]
                                        vd[15..12] 101101] M [0] vm[3..0] */
-    THUMB2_LDMIA,         /* ldmia  [111010001001[ rn[19..16] mask[15..0] */
-    THUMB2_STMIA,         /* stmia  [111010001000[ rn[19..16] mask[15..0] */
-    THUMB2_ADD_RRR,       /* add [111010110000] rn[19..16] [0000] rd[11..8]
+    kThumb2Ldmia,        /* ldmia  [111010001001[ rn[19..16] mask[15..0] */
+    kThumb2Stmia,        /* stmia  [111010001000[ rn[19..16] mask[15..0] */
+    kThumb2AddRRR,       /* add [111010110000] rn[19..16] [0000] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_SUB_RRR,       /* sub [111010111010] rn[19..16] [0000] rd[11..8]
+    kThumb2SubRRR,       /* sub [111010111010] rn[19..16] [0000] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_SBC_RRR,       /* sbc [111010110110] rn[19..16] [0000] rd[11..8]
+    kThumb2SbcRRR,       /* sbc [111010110110] rn[19..16] [0000] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_CMP_RR,        /* cmp [111010111011] rn[19..16] [0000] [1111]
+    kThumb2CmpRR,        /* cmp [111010111011] rn[19..16] [0000] [1111]
                                    [0000] rm[3..0] */
-    THUMB2_SUB_RRI12,     /* sub rd, rn, #imm12 [11110] i [01010] rn[19..16]
+    kThumb2SubRRI12,     /* sub rd, rn, #imm12 [11110] i [01010] rn[19..16]
                                        [0] imm3[14..12] rd[11..8] imm8[7..0] */
-    THUMB2_MVN_IMM_SHIFT, /* mov(T2) rd, #<const> [11110] i [00011011110]
+    kThumb2MvnImmShift,  /* mov(T2) rd, #<const> [11110] i [00011011110]
                                        imm3 rd[11..8] imm8 */
-    THUMB2_SEL,           /* sel rd, rn, rm [111110101010] rn[19-16] rd[11-8]
+    kThumb2Sel,          /* sel rd, rn, rm [111110101010] rn[19-16] rd[11-8]
                                        rm[3-0] */
-    THUMB2_UBFX,          /* ubfx rd,rn,#lsb,#width [111100111100] rn[19..16]
+    kThumb2Ubfx,         /* ubfx rd,rn,#lsb,#width [111100111100] rn[19..16]
                                        [0] imm3[14-12] rd[11-8] w[4-0] */
-    THUMB2_SBFX,          /* ubfx rd,rn,#lsb,#width [111100110100] rn[19..16]
+    kThumb2Sbfx,         /* ubfx rd,rn,#lsb,#width [111100110100] rn[19..16]
                                        [0] imm3[14-12] rd[11-8] w[4-0] */
-    THUMB2_LDR_RRR,       /* ldr rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
+    kThumb2LdrRRR,       /* ldr rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
-    THUMB2_LDRH_RRR,      /* ldrh rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
+    kThumb2LdrhRRR,      /* ldrh rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
-    THUMB2_LDRSH_RRR,     /* ldrsh rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
+    kThumb2LdrshRRR,     /* ldrsh rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
-    THUMB2_LDRB_RRR,      /* ldrb rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
+    kThumb2LdrbRRR,      /* ldrb rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
-    THUMB2_LDRSB_RRR,     /* ldrsb rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
+    kThumb2LdrsbRRR,     /* ldrsb rt,[rn,rm,LSL #imm] [111110000101] rn[19-16]
                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
-    THUMB2_STR_RRR,       /* str rt,[rn,rm,LSL #imm] [111110000100] rn[19-16]
+    kThumb2StrRRR,       /* str rt,[rn,rm,LSL #imm] [111110000100] rn[19-16]
                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
-    THUMB2_STRH_RRR,      /* str rt,[rn,rm,LSL #imm] [111110000010] rn[19-16]
+    kThumb2StrhRRR,      /* str rt,[rn,rm,LSL #imm] [111110000010] rn[19-16]
                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
-    THUMB2_STRB_RRR,      /* str rt,[rn,rm,LSL #imm] [111110000000] rn[19-16]
+    kThumb2StrbRRR,      /* str rt,[rn,rm,LSL #imm] [111110000000] rn[19-16]
                                        rt[15-12] [000000] imm[5-4] rm[3-0] */
-    THUMB2_LDRH_RRI12,    /* ldrh rt,[rn,#imm12] [111110001011]
+    kThumb2LdrhRRI12,    /* ldrh rt,[rn,#imm12] [111110001011]
                                        rt[15..12] rn[19..16] imm12[11..0] */
-    THUMB2_LDRSH_RRI12,   /* ldrsh rt,[rn,#imm12] [111110011011]
+    kThumb2LdrshRRI12,   /* ldrsh rt,[rn,#imm12] [111110011011]
                                        rt[15..12] rn[19..16] imm12[11..0] */
-    THUMB2_LDRB_RRI12,    /* ldrb rt,[rn,#imm12] [111110001001]
+    kThumb2LdrbRRI12,    /* ldrb rt,[rn,#imm12] [111110001001]
                                        rt[15..12] rn[19..16] imm12[11..0] */
-    THUMB2_LDRSB_RRI12,   /* ldrsb rt,[rn,#imm12] [111110011001]
+    kThumb2LdrsbRRI12,   /* ldrsb rt,[rn,#imm12] [111110011001]
                                        rt[15..12] rn[19..16] imm12[11..0] */
-    THUMB2_STRH_RRI12,    /* strh rt,[rn,#imm12] [111110001010]
+    kThumb2StrhRRI12,    /* strh rt,[rn,#imm12] [111110001010]
                                        rt[15..12] rn[19..16] imm12[11..0] */
-    THUMB2_STRB_RRI12,    /* strb rt,[rn,#imm12] [111110001000]
+    kThumb2StrbRRI12,    /* strb rt,[rn,#imm12] [111110001000]
                                        rt[15..12] rn[19..16] imm12[11..0] */
-    THUMB2_POP,           /* pop     [1110100010111101] list[15-0]*/
-    THUMB2_PUSH,          /* push    [1110100010101101] list[15-0]*/
-    THUMB2_CMP_RI8,       /* cmp rn, #<const> [11110] i [011011] rn[19-16] [0]
+    kThumb2Pop,          /* pop     [1110100010111101] list[15-0]*/
+    kThumb2Push,         /* push    [1110100010101101] list[15-0]*/
+    kThumb2CmpRI8,       /* cmp rn, #<const> [11110] i [011011] rn[19-16] [0]
                                        imm3 [1111] imm8[7..0] */
-    THUMB2_ADC_RRR,       /* adc [111010110101] rn[19..16] [0000] rd[11..8]
+    kThumb2AdcRRR,       /* adc [111010110101] rn[19..16] [0000] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_AND_RRR,       /* and [111010100000] rn[19..16] [0000] rd[11..8]
+    kThumb2AndRRR,       /* and [111010100000] rn[19..16] [0000] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_BIC_RRR,       /* bic [111010100010] rn[19..16] [0000] rd[11..8]
+    kThumb2BicRRR,       /* bic [111010100010] rn[19..16] [0000] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_CMN_RR,        /* cmn [111010110001] rn[19..16] [0000] [1111]
+    kThumb2CmnRR,        /* cmn [111010110001] rn[19..16] [0000] [1111]
                                    [0000] rm[3..0] */
-    THUMB2_EOR_RRR,       /* eor [111010101000] rn[19..16] [0000] rd[11..8]
+    kThumb2EorRRR,       /* eor [111010101000] rn[19..16] [0000] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_MUL_RRR,       /* mul [111110110000] rn[19..16] [1111] rd[11..8]
+    kThumb2MulRRR,       /* mul [111110110000] rn[19..16] [1111] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_MVN_RR,        /* mvn [11101010011011110] rd[11-8] [0000]
+    kThumb2MnvRR,        /* mvn [11101010011011110] rd[11-8] [0000]
                                    rm[3..0] */
-    THUMB2_RSUB_RRI8,     /* rsub [111100011100] rn[19..16] [0000] rd[11..8]
+    kThumb2RsubRRI8,     /* rsub [111100011100] rn[19..16] [0000] rd[11..8]
                                    imm8[7..0] */
-    THUMB2_NEG_RR,        /* actually rsub rd, rn, #0 */
-    THUMB2_ORR_RRR,       /* orr [111010100100] rn[19..16] [0000] rd[11..8]
+    kThumb2NegRR,        /* actually rsub rd, rn, #0 */
+    kThumb2OrrRRR,       /* orr [111010100100] rn[19..16] [0000] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_TST_RR,        /* tst [111010100001] rn[19..16] [0000] [1111]
+    kThumb2TstRR,        /* tst [111010100001] rn[19..16] [0000] [1111]
                                    [0000] rm[3..0] */
-    THUMB2_LSL_RRR,       /* lsl [111110100000] rn[19..16] [1111] rd[11..8]
+    kThumb2LslRRR,       /* lsl [111110100000] rn[19..16] [1111] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_LSR_RRR,       /* lsr [111110100010] rn[19..16] [1111] rd[11..8]
+    kThumb2LsrRRR,       /* lsr [111110100010] rn[19..16] [1111] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_ASR_RRR,       /* asr [111110100100] rn[19..16] [1111] rd[11..8]
+    kThumb2AsrRRR,       /* asr [111110100100] rn[19..16] [1111] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_ROR_RRR,       /* ror [111110100110] rn[19..16] [1111] rd[11..8]
+    kThumb2RorRRR,       /* ror [111110100110] rn[19..16] [1111] rd[11..8]
                                    [0000] rm[3..0] */
-    THUMB2_LSL_RRI5,      /* lsl [11101010010011110] imm[14.12] rd[11..8]
+    kThumb2LslRRI5,      /* lsl [11101010010011110] imm[14.12] rd[11..8]
                                    [00] rm[3..0] */
-    THUMB2_LSR_RRI5,      /* lsr [11101010010011110] imm[14.12] rd[11..8]
+    kThumb2LsrRRI5,      /* lsr [11101010010011110] imm[14.12] rd[11..8]
                                    [01] rm[3..0] */
-    THUMB2_ASR_RRI5,      /* asr [11101010010011110] imm[14.12] rd[11..8]
+    kThumb2AsrRRI5,      /* asr [11101010010011110] imm[14.12] rd[11..8]
                                    [10] rm[3..0] */
-    THUMB2_ROR_RRI5,      /* ror [11101010010011110] imm[14.12] rd[11..8]
+    kThumb2RorRRI5,      /* ror [11101010010011110] imm[14.12] rd[11..8]
                                    [11] rm[3..0] */
-    THUMB2_BIC_RRI8,      /* bic [111100000010] rn[19..16] [0] imm3
+    kThumb2BicRRI8,      /* bic [111100000010] rn[19..16] [0] imm3
                                    rd[11..8] imm8 */
-    THUMB2_AND_RRI8,      /* bic [111100000000] rn[19..16] [0] imm3
+    kThumb2AndRRI8,      /* bic [111100000000] rn[19..16] [0] imm3
                                    rd[11..8] imm8 */
-    THUMB2_ORR_RRI8,      /* orr [111100000100] rn[19..16] [0] imm3
+    kThumb2OrrRRI8,      /* orr [111100000100] rn[19..16] [0] imm3
                                    rd[11..8] imm8 */
-    THUMB2_EOR_RRI8,      /* eor [111100001000] rn[19..16] [0] imm3
+    kThumb2EorRRI8,      /* eor [111100001000] rn[19..16] [0] imm3
                                    rd[11..8] imm8 */
-    THUMB2_ADD_RRI8,      /* add [111100001000] rn[19..16] [0] imm3
+    kThumb2AddRRI8,      /* add [111100001000] rn[19..16] [0] imm3
                                    rd[11..8] imm8 */
-    THUMB2_ADC_RRI8,      /* adc [111100010101] rn[19..16] [0] imm3
+    kThumb2AdcRRI8,      /* adc [111100010101] rn[19..16] [0] imm3
                                    rd[11..8] imm8 */
-    THUMB2_SUB_RRI8,      /* sub [111100011011] rn[19..16] [0] imm3
+    kThumb2SubRRI8,      /* sub [111100011011] rn[19..16] [0] imm3
                                    rd[11..8] imm8 */
-    THUMB2_SBC_RRI8,      /* sbc [111100010111] rn[19..16] [0] imm3
+    kThumb2SbcRRI8,      /* sbc [111100010111] rn[19..16] [0] imm3
                                    rd[11..8] imm8 */
-    THUMB2_IT,            /* it [10111111] firstcond[7-4] mask[3-0] */
-    THUMB2_FMSTAT,        /* fmstat [11101110111100011111101000010000] */
-    THUMB2_VCMPD,         /* vcmp [111011101] D [11011] rd[15-12] [1011]
+    kThumb2It,           /* it [10111111] firstcond[7-4] mask[3-0] */
+    kThumb2Fmstat,       /* fmstat [11101110111100011111101000010000] */
+    kThumb2Vcmpd,        /* vcmp [111011101] D [11011] rd[15-12] [1011]
                                    E [1] M [0] rm[3-0] */
-    THUMB2_VCMPS,         /* vcmp [111011101] D [11010] rd[15-12] [1011]
+    kThumb2Vcmps,        /* vcmp [111011101] D [11010] rd[15-12] [1011]
                                    E [1] M [0] rm[3-0] */
-    THUMB2_LDR_PC_REL12,  /* ldr rd,[pc,#imm12] [1111100011011111] rt[15-12]
-                                     imm12[11-0] */
-    THUMB2_B_COND,        /* b<c> [1110] S cond[25-22] imm6[21-16] [10]
+    kThumb2LdrPcRel12,   /* ldr rd,[pc,#imm12] [1111100011011111] rt[15-12]
+                                  imm12[11-0] */
+    kThumb2BCond,        /* b<c> [1110] S cond[25-22] imm6[21-16] [10]
                                   J1 [0] J2 imm11[10..0] */
-    THUMB2_VMOVD_RR,      /* vmov [111011101] D [110000] vd[15-12 [101101]
+    kThumb2Vmovd_RR,     /* vmov [111011101] D [110000] vd[15-12 [101101]
                                   M [0] vm[3-0] */
-    THUMB2_VMOVS_RR,      /* vmov [111011101] D [110000] vd[15-12 [101001]
+    kThumb2Vmovs_RR,     /* vmov [111011101] D [110000] vd[15-12 [101001]
                                   M [0] vm[3-0] */
-    THUMB2_FMRS,          /* vmov [111011100000] vn[19-16] rt[15-12] [1010]
+    kThumb2Fmrs,         /* vmov [111011100000] vn[19-16] rt[15-12] [1010]
                                   N [0010000] */
-    THUMB2_FMSR,          /* vmov [111011100001] vn[19-16] rt[15-12] [1010]
+    kThumb2Fmsr,         /* vmov [111011100001] vn[19-16] rt[15-12] [1010]
                                   N [0010000] */
-    THUMB2_FMRRD,         /* vmov [111011000100] rt2[19-16] rt[15-12]
+    kThumb2Fmrrd,        /* vmov [111011000100] rt2[19-16] rt[15-12]
                                   [101100] M [1] vm[3-0] */
-    THUMB2_FMDRR,         /* vmov [111011000101] rt2[19-16] rt[15-12]
+    kThumb2Fmdrr,        /* vmov [111011000101] rt2[19-16] rt[15-12]
                                   [101100] M [1] vm[3-0] */
+    kThumb2Vabsd,        /* vabs.f64 [111011101] D [110000] rd[15-12]
+                                  [1011110] M [0] vm[3-0] */
+    kThumb2Vabss,        /* vabs.f32 [111011101] D [110000] rd[15-12]
+                                  [1010110] M [0] vm[3-0] */
+    kThumb2Vnegd,        /* vneg.f64 [111011101] D [110000] rd[15-12]
+                                  [1011110] M [0] vm[3-0] */
+    kThumb2Vnegs,        /* vneg.f32 [111011101] D [110000] rd[15-12]
+                                 [1010110] M [0] vm[3-0] */
+    kThumb2Vmovs_IMM8,   /* vmov.f32 [111011101] D [11] imm4h[19-16] vd[15-12]
+                                  [10100000] imm4l[3-0] */
+    kThumb2Vmovd_IMM8,   /* vmov.f64 [111011101] D [11] imm4h[19-16] vd[15-12]
+                                  [10110000] imm4l[3-0] */
+    kThumb2Mla,          /* mla [111110110000] rn[19-16] ra[15-12] rd[7-4]
+                                  [0000] rm[3-0] */
+    kThumb2Umull,        /* umull [111110111010] rn[19-16], rdlo[15-12]
+                                  rdhi[11-8] [0000] rm[3-0] */
+    kThumb2Ldrex,        /* ldrex [111010000101] rn[19-16] rt[11-8] [1111]
+                                  imm8[7-0] */
+    kThumb2Strex,        /* strex [111010000100] rn[19-16] rt[11-8] rd[11-8]
+                                  imm8[7-0] */
+    kThumb2Clrex,       /* clrex [111100111011111110000111100101111\ */
 
-    ARM_LAST,
+    kArmLast,
 } ArmOpCode;
 
 /* Bit flags describing the behavior of each native opcode */
@@ -541,6 +615,7 @@ typedef enum ArmOpFeatureFlags {
     kRegUse0,
     kRegUse1,
     kRegUse2,
+    kRegUse3,
     kRegUseSP,
     kRegUsePC,
     kRegUseList0,
@@ -565,6 +640,7 @@ typedef enum ArmOpFeatureFlags {
 #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)
@@ -590,19 +666,20 @@ typedef enum ArmOpFeatureFlags {
 
 /* Instruction assembly fieldLoc kind */
 typedef enum ArmEncodingKind {
-    UNUSED,
-    BITBLT,        /* Bit string using end/start */
-    DFP,           /* Double FP reg */
-    SFP,           /* Single FP reg */
-    MODIMM,        /* Shifted 8-bit immediate using [26,14..12,7..0] */
-    IMM16,         /* Zero-extended immediate using [26,19..16,14..12,7..0] */
-    IMM6,          /* Encoded branch target using [9,7..3]0 */
-    IMM12,         /* Zero-extended immediate using [26,14..12,7..0] */
-    SHIFT,         /* Shift descriptor, [14..12,7..4] */
-    LSB,           /* least significant bit using [14..12][7..6] */
-    BWIDTH,        /* bit-field width, encoded as width-1 */
-    SHIFT5,        /* Shift count, [14..12,7..6] */
-    BROFFSET,      /* Signed extended [26,11,13,21-16,10-0]:0 */
+    kFmtUnused,
+    kFmtBitBlt,        /* Bit string using end/start */
+    kFmtDfp,           /* Double FP reg */
+    kFmtSfp,           /* Single FP reg */
+    kFmtModImm,        /* Shifted 8-bit immed using [26,14..12,7..0] */
+    kFmtImm16,         /* Zero-extended immed using [26,19..16,14..12,7..0] */
+    kFmtImm6,          /* Encoded branch target using [9,7..3]0 */
+    kFmtImm12,         /* Zero-extended immediate using [26,14..12,7..0] */
+    kFmtShift,         /* Shift descriptor, [14..12,7..4] */
+    kFmtLsb,           /* least significant bit using [14..12][7..6] */
+    kFmtBWidth,        /* bit-field width, encoded as width-1 */
+    kFmtShift5,        /* Shift count, [14..12,7..6] */
+    kFmtBrOffset,      /* Signed extended [26,11,13,21-16,10-0]:0 */
+    kFmtFPImm,         /* Encoded floating point immediate */
 } ArmEncodingKind;
 
 /* Struct used to define the snippet positions for each Thumb opcode */
@@ -610,8 +687,8 @@ typedef struct ArmEncodingMap {
     u4 skeleton;
     struct {
         ArmEncodingKind kind;
-        int end;   /* end for BITBLT, 1-bit slice end for FP regs */
-        int start; /* start for BITBLT, 4-bit slice end for FP regs */
+        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];
     ArmOpCode opCode;
     int flags;
@@ -620,7 +697,7 @@ typedef struct ArmEncodingMap {
     int size;
 } ArmEncodingMap;
 
-extern ArmEncodingMap EncodingMap[ARM_LAST];
+extern ArmEncodingMap EncodingMap[kArmLast];
 
 /*
  * Each instance of this struct holds a pseudo or real LIR instruction:
index 799142f..b390885 100644 (file)
  *  [!] escape.  To insert "!", use "!!"
  */
 /* NOTE: must be kept in sync with enum ArmOpcode from ArmLIR.h */
-ArmEncodingMap EncodingMap[ARM_LAST] = {
-    ENCODING_MAP(ARM_16BIT_DATA,    0x0000,
-                 BITBLT, 15, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_UNARY_OP,
-                 "data", "0x!0h(!0d)", 1),
-    ENCODING_MAP(THUMB_ADC_RR,        0x4140,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+ArmEncodingMap EncodingMap[kArmLast] = {
+    ENCODING_MAP(kArm16BitData,    0x0000,
+                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP, "data", "0x!0h(!0d)", 1),
+    ENCODING_MAP(kThumbAdcRR,        0x4140,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES | USES_CCODES,
                  "adcs", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_ADD_RRI3,      0x1c00,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbAddRRI3,      0x1c00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "adds", "r!0d, r!1d, #!2d", 1),
-    ENCODING_MAP(THUMB_ADD_RI8,       0x3000,
-                 BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbAddRI8,       0x3000,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES,
                  "adds", "r!0d, r!0d, #!1d", 1),
-    ENCODING_MAP(THUMB_ADD_RRR,       0x1800,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbAddRRR,       0x1800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES,
                  "adds", "r!0d, r!1d, r!2d", 1),
-    ENCODING_MAP(THUMB_ADD_RR_LH,     0x4440,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE01,
+    ENCODING_MAP(kThumbAddRRLH,     0x4440,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
                  "add", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_ADD_RR_HL,     0x4480,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE01,
+    ENCODING_MAP(kThumbAddRRHL,     0x4480,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
                  "add", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_ADD_RR_HH,     0x44c0,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE01,
+    ENCODING_MAP(kThumbAddRRHH,     0x44c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE01,
                  "add", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_ADD_PC_REL,    0xa000,
-                 BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | IS_BRANCH,
+    ENCODING_MAP(kThumbAddPcRel,    0xa000,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | IS_BRANCH,
                  "add", "r!0d, pc, #!1E", 1),
-    ENCODING_MAP(THUMB_ADD_SP_REL,    0xa800,
-                 BITBLT, 10, 8, UNUSED, -1, -1, BITBLT, 7, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF_SP | REG_USE_SP,
+    ENCODING_MAP(kThumbAddSpRel,    0xa800,
+                 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF_SP | REG_USE_SP,
                  "add", "r!0d, sp, #!2E", 1),
-    ENCODING_MAP(THUMB_ADD_SPI7,      0xb000,
-                 BITBLT, 6, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_UNARY_OP | REG_DEF_SP | REG_USE_SP,
+    ENCODING_MAP(kThumbAddSpI7,      0xb000,
+                 kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | REG_DEF_SP | REG_USE_SP,
                  "add", "sp, #!0d*4", 1),
-    ENCODING_MAP(THUMB_AND_RR,        0x4000,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbAndRR,        0x4000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
                  "ands", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_ASR_RRI5,      0x1000,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 10, 6, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbAsrRRI5,      0x1000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "asrs", "r!0d, r!1d, #!2d", 1),
-    ENCODING_MAP(THUMB_ASR_RR,        0x4100,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbAsrRR,        0x4100,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
                  "asrs", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_B_COND,        0xd000,
-                 BITBLT, 7, 0, BITBLT, 11, 8, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | IS_BRANCH | USES_CCODES,
+    ENCODING_MAP(kThumbBCond,        0xd000,
+                 kFmtBitBlt, 7, 0, kFmtBitBlt, 11, 8, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | USES_CCODES,
                  "b!1c", "!0t", 1),
-    ENCODING_MAP(THUMB_B_UNCOND,      0xe000,
-                 BITBLT, 10, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 NO_OPERAND | IS_BRANCH,
+    ENCODING_MAP(kThumbBUncond,      0xe000,
+                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
                  "b", "!0t", 1),
-    ENCODING_MAP(THUMB_BIC_RR,        0x4380,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbBicRR,        0x4380,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
                  "bics", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_BKPT,          0xbe00,
-                 BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_UNARY_OP | IS_BRANCH,
+    ENCODING_MAP(kThumbBkpt,          0xbe00,
+                 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
                  "bkpt", "!0d", 1),
-    ENCODING_MAP(THUMB_BLX_1,         0xf000,
-                 BITBLT, 10, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
+    ENCODING_MAP(kThumbBlx1,         0xf000,
+                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
                  "blx_1", "!0u", 1),
-    ENCODING_MAP(THUMB_BLX_2,         0xe800,
-                 BITBLT, 10, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
+    ENCODING_MAP(kThumbBlx2,         0xe800,
+                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF_LR,
                  "blx_2", "!0v", 1),
-    ENCODING_MAP(THUMB_BL_1,          0xf000,
-                 BITBLT, 10, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
+    ENCODING_MAP(kThumbBl1,          0xf000,
+                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
                  "bl_1", "!0u", 1),
-    ENCODING_MAP(THUMB_BL_2,          0xf800,
-                 BITBLT, 10, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
+    ENCODING_MAP(kThumbBl2,          0xf800,
+                 kFmtBitBlt, 10, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
                  "bl_2", "!0v", 1),
-    ENCODING_MAP(THUMB_BLX_R,         0x4780,
-                 BITBLT, 6, 3, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbBlxR,         0x4780,
+                 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_UNARY_OP | REG_USE0 | IS_BRANCH | REG_DEF_LR,
                  "blx", "r!0d", 1),
-    ENCODING_MAP(THUMB_BX,            0x4700,
-                 BITBLT, 6, 3, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_UNARY_OP | IS_BRANCH,
+    ENCODING_MAP(kThumbBx,            0x4700,
+                 kFmtBitBlt, 6, 3, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
                  "bx", "r!0d", 1),
-    ENCODING_MAP(THUMB_CMN_RR,        0x42c0,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_USE01 | SETS_CCODES,
+    ENCODING_MAP(kThumbCmnRR,        0x42c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
                  "cmn", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_CMP_RI8,       0x2800,
-                 BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_USE0 | SETS_CCODES,
+    ENCODING_MAP(kThumbCmpRI8,       0x2800,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | SETS_CCODES,
                  "cmp", "r!0d, #!1d", 1),
-    ENCODING_MAP(THUMB_CMP_RR,        0x4280,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_USE01 | SETS_CCODES,
+    ENCODING_MAP(kThumbCmpRR,        0x4280,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
                  "cmp", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_CMP_LH,        0x4540,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_USE01 | SETS_CCODES,
+    ENCODING_MAP(kThumbCmpLH,        0x4540,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
                  "cmp", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_CMP_HL,        0x4580,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_USE01 | SETS_CCODES,
+    ENCODING_MAP(kThumbCmpHL,        0x4580,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
                  "cmp", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_CMP_HH,        0x45c0,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_USE01 | SETS_CCODES,
+    ENCODING_MAP(kThumbCmpHH,        0x45c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01 | SETS_CCODES,
                  "cmp", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_EOR_RR,        0x4040,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbEorRR,        0x4040,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
                  "eors", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_LDMIA,         0xc800,
-                 BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbLdmia,         0xc800,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1,
                  "ldmia", "r!0d!!, <!1R>", 1),
-    ENCODING_MAP(THUMB_LDR_RRI5,      0x6800,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 10, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumbLdrRRI5,      0x6800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "ldr", "r!0d, [r!1d, #!2E]", 1),
-    ENCODING_MAP(THUMB_LDR_RRR,       0x5800,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumbLdrRRR,       0x5800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "ldr", "r!0d, [r!1d, r!2d]", 1),
-    ENCODING_MAP(THUMB_LDR_PC_REL,    0x4800,
-                 BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC,
+    ENCODING_MAP(kThumbLdrPcRel,    0x4800,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC,
                  "ldr", "r!0d, [pc, #!1E]", 1),
-    ENCODING_MAP(THUMB_LDR_SP_REL,    0x9800,
-                 BITBLT, 10, 8, UNUSED, -1, -1, BITBLT, 7, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0 | REG_USE_SP,
+    ENCODING_MAP(kThumbLdrSpRel,    0x9800,
+                 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0 | REG_USE_SP,
                  "ldr", "r!0d, [sp, #!2E]", 1),
-    ENCODING_MAP(THUMB_LDRB_RRI5,     0x7800,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 10, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumbLdrbRRI5,     0x7800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "ldrb", "r!0d, [r!1d, #2d]", 1),
-    ENCODING_MAP(THUMB_LDRB_RRR,      0x5c00,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumbLdrbRRR,      0x5c00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "ldrb", "r!0d, [r!1d, r!2d]", 1),
-    ENCODING_MAP(THUMB_LDRH_RRI5,     0x8800,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 10, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumbLdrhRRI5,     0x8800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "ldrh", "r!0d, [r!1d, #!2F]", 1),
-    ENCODING_MAP(THUMB_LDRH_RRR,      0x5a00,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumbLdrhRRR,      0x5a00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "ldrh", "r!0d, [r!1d, r!2d]", 1),
-    ENCODING_MAP(THUMB_LDRSB_RRR,     0x5600,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumbLdrsbRRR,     0x5600,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "ldrsb", "r!0d, [r!1d, r!2d]", 1),
-    ENCODING_MAP(THUMB_LDRSH_RRR,     0x5e00,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumbLdrshRRR,     0x5e00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "ldrsh", "r!0d, [r!1d, r!2d]", 1),
-    ENCODING_MAP(THUMB_LSL_RRI5,      0x0000,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 10, 6, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbLslRRI5,      0x0000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "lsls", "r!0d, r!1d, #!2d", 1),
-    ENCODING_MAP(THUMB_LSL_RR,        0x4080,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbLslRR,        0x4080,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
                  "lsls", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_LSR_RRI5,      0x0800,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 10, 6, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbLsrRRI5,      0x0800,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "lsrs", "r!0d, r!1d, #!2d", 1),
-    ENCODING_MAP(THUMB_LSR_RR,        0x40c0,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbLsrRR,        0x40c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
                  "lsrs", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_MOV_IMM,       0x2000,
-                 BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbMovImm,       0x2000,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0 | SETS_CCODES,
                  "movs", "r!0d, #!1d", 1),
-    ENCODING_MAP(THUMB_MOV_RR,        0x1c00,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbMovRR,        0x1c00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "movs", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_MOV_RR_H2H,    0x46c0,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumbMovRR_H2H,    0x46c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "mov", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_MOV_RR_H2L,    0x4640,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumbMovRR_H2L,    0x4640,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "mov", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_MOV_RR_L2H,    0x4680,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumbMovRR_L2H,    0x4680,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "mov", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_MUL,           0x4340,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbMul,           0x4340,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
                  "muls", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_MVN,           0x43c0,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbMvn,           0x43c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "mvns", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_NEG,           0x4240,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbNeg,           0x4240,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "negs", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_ORR,           0x4300,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbOrr,           0x4300,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
                  "orrs", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_POP,           0xbc00,
-                 BITBLT, 8, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbPop,           0xbc00,
+                 kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0,
                  "pop", "<!0R>", 1),
-    ENCODING_MAP(THUMB_PUSH,          0xb400,
-                 BITBLT, 8, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbPush,          0xb400,
+                 kFmtBitBlt, 8, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0,
                  "push", "<!0R>", 1),
-    ENCODING_MAP(THUMB_ROR_RR,        0x41c0,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbRorRR,        0x41c0,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | SETS_CCODES,
                  "rors", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_SBC,           0x4180,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbSbc,           0x4180,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE01 | USES_CCODES | SETS_CCODES,
                  "sbcs", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB_STMIA,         0xc000,
-                 BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbStmia,         0xc000,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0 | REG_USE0 | REG_USE_LIST1,
                  "stmia", "r!0d!!, <!1R>", 1),
-    ENCODING_MAP(THUMB_STR_RRI5,      0x6000,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 10, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE01,
+    ENCODING_MAP(kThumbStrRRI5,      0x6000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01,
                  "str", "r!0d, [r!1d, #!2E]", 1),
-    ENCODING_MAP(THUMB_STR_RRR,       0x5000,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE012,
+    ENCODING_MAP(kThumbStrRRR,       0x5000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012,
                  "str", "r!0d, [r!1d, r!2d]", 1),
-    ENCODING_MAP(THUMB_STR_SP_REL,    0x9000,
-                 BITBLT, 10, 8, UNUSED, -1, -1, BITBLT, 7, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE0 | REG_USE_SP,
+    ENCODING_MAP(kThumbStrSpRel,    0x9000,
+                 kFmtBitBlt, 10, 8, kFmtUnused, -1, -1, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE0 | REG_USE_SP,
                  "str", "r!0d, [sp, #!2E]", 1),
-    ENCODING_MAP(THUMB_STRB_RRI5,     0x7000,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 10, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE01,
+    ENCODING_MAP(kThumbStrbRRI5,     0x7000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01,
                  "strb", "r!0d, [r!1d, #!2d]", 1),
-    ENCODING_MAP(THUMB_STRB_RRR,      0x5400,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE012,
+    ENCODING_MAP(kThumbStrbRRR,      0x5400,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012,
                  "strb", "r!0d, [r!1d, r!2d]", 1),
-    ENCODING_MAP(THUMB_STRH_RRI5,     0x8000,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 10, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE01,
+    ENCODING_MAP(kThumbStrhRRI5,     0x8000,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 10, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01,
                  "strh", "r!0d, [r!1d, #!2F]", 1),
-    ENCODING_MAP(THUMB_STRH_RRR,      0x5200,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE012,
+    ENCODING_MAP(kThumbStrhRRR,      0x5200,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE012,
                  "strh", "r!0d, [r!1d, r!2d]", 1),
-    ENCODING_MAP(THUMB_SUB_RRI3,      0x1e00,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbSubRRI3,      0x1e00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "subs", "r!0d, r!1d, #!2d]", 1),
-    ENCODING_MAP(THUMB_SUB_RI8,       0x3800,
-                 BITBLT, 10, 8, BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbSubRI8,       0x3800,
+                 kFmtBitBlt, 10, 8, kFmtBitBlt, 7, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE0 | SETS_CCODES,
                  "subs", "r!0d, #!1d", 1),
-    ENCODING_MAP(THUMB_SUB_RRR,       0x1a00,
-                 BITBLT, 2, 0, BITBLT, 5, 3, BITBLT, 8, 6, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbSubRRR,       0x1a00,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtBitBlt, 8, 6,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE12 | SETS_CCODES,
                  "subs", "r!0d, r!1d, r!2d", 1),
-    ENCODING_MAP(THUMB_SUB_SPI7,      0xb080,
-                 BITBLT, 6, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumbSubSpI7,      0xb080,
+                 kFmtBitBlt, 6, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_UNARY_OP | REG_DEF_SP | REG_USE_SP,
                  "sub", "sp, #!0d", 1),
-    ENCODING_MAP(THUMB_SWI,           0xdf00,
-                 BITBLT, 7, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_UNARY_OP | IS_BRANCH,
+    ENCODING_MAP(kThumbSwi,           0xdf00,
+                 kFmtBitBlt, 7, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,                       kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH,
                  "swi", "!0d", 1),
-    ENCODING_MAP(THUMB_TST,           0x4200,
-                 BITBLT, 2, 0, BITBLT, 5, 3, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_UNARY_OP | REG_USE01 | SETS_CCODES,
+    ENCODING_MAP(kThumbTst,           0x4200,
+                 kFmtBitBlt, 2, 0, kFmtBitBlt, 5, 3, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_UNARY_OP | REG_USE01 | SETS_CCODES,
                  "tst", "r!0d, r!1d", 1),
-    ENCODING_MAP(THUMB2_VLDRS,       0xed900a00,
-                 SFP, 22, 12, BITBLT, 19, 16, BITBLT, 7, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Vldrs,       0xed900a00,
+                 kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "vldr", "!0s, [r!1d, #!2E]", 2),
-    ENCODING_MAP(THUMB2_VLDRD,       0xed900b00,
-                 DFP, 22, 12, BITBLT, 19, 16, BITBLT, 7, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Vldrd,       0xed900b00,
+                 kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "vldr", "!0S, [r!1d, #!2E]", 2),
-    ENCODING_MAP(THUMB2_VMULS,        0xee200a00,
-                 SFP, 22, 12, SFP, 7, 16, SFP, 5, 0, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2Vmuls,        0xee200a00,
+                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE12,
                  "vmuls", "!0s, !1s, !2s", 2),
-    ENCODING_MAP(THUMB2_VMULD,        0xee200b00,
-                 DFP, 22, 12, DFP, 7, 16, DFP, 5, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2Vmuld,        0xee200b00,
+                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "vmuld", "!0S, !1S, !2S", 2),
-    ENCODING_MAP(THUMB2_VSTRS,       0xed800a00,
-                 SFP, 22, 12, BITBLT, 19, 16, BITBLT, 7, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE01,
+    ENCODING_MAP(kThumb2Vstrs,       0xed800a00,
+                 kFmtSfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01,
                  "vstr", "!0s, [r!1d, #!2E]", 2),
-    ENCODING_MAP(THUMB2_VSTRD,       0xed800b00,
-                 DFP, 22, 12, BITBLT, 19, 16, BITBLT, 7, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE01,
+    ENCODING_MAP(kThumb2Vstrd,       0xed800b00,
+                 kFmtDfp, 22, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01,
                  "vstr", "!0S, [r!1d, #!2E]", 2),
-    ENCODING_MAP(THUMB2_VSUBS,        0xee300a40,
-                 SFP, 22, 12, SFP, 7, 16, SFP, 5, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2Vsubs,        0xee300a40,
+                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "vsub", "!0s, !1s, !2s", 2),
-    ENCODING_MAP(THUMB2_VSUBD,        0xee300b40,
-                 DFP, 22, 12, DFP, 7, 16, DFP, 5, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2Vsubd,        0xee300b40,
+                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "vsub", "!0S, !1S, !2S", 2),
-    ENCODING_MAP(THUMB2_VADDS,        0xee300a00,
-                 SFP, 22, 12, SFP, 7, 16, SFP, 5, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2Vadds,        0xee300a00,
+                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "vadd", "!0s, !1s, !2s", 2),
-    ENCODING_MAP(THUMB2_VADDD,        0xee300b00,
-                 DFP, 22, 12, DFP, 7, 16, DFP, 5, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2Vaddd,        0xee300b00,
+                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "vadd", "!0S, !1S, !2S", 2),
-    ENCODING_MAP(THUMB2_VDIVS,        0xee800a00,
-                 SFP, 22, 12, SFP, 7, 16, SFP, 5, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2Vdivs,        0xee800a00,
+                 kFmtSfp, 22, 12, kFmtSfp, 7, 16, kFmtSfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "vdivs", "!0s, !1s, !2s", 2),
-    ENCODING_MAP(THUMB2_VDIVD,        0xee800b00,
-                 DFP, 22, 12, DFP, 7, 16, DFP, 5, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2Vdivd,        0xee800b00,
+                 kFmtDfp, 22, 12, kFmtDfp, 7, 16, kFmtDfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "vdivd", "!0S, !1S, !2S", 2),
-    ENCODING_MAP(THUMB2_VCVTIF,       0xeeb80ac0,
-                 SFP, 22, 12, SFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2VcvtIF,       0xeeb80ac0,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vcvt.f32", "!0s, !1s", 2),
-    ENCODING_MAP(THUMB2_VCVTID,       0xeeb80bc0,
-                 DFP, 22, 12, SFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2VcvtID,       0xeeb80bc0,
+                 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vcvt.f64", "!0S, !1s", 2),
-    ENCODING_MAP(THUMB2_VCVTFI,       0xeebd0ac0,
-                 SFP, 22, 12, SFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2VcvtFI,       0xeebd0ac0,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vcvt.s32.f32 ", "!0s, !1s", 2),
-    ENCODING_MAP(THUMB2_VCVTDI,       0xeebd0bc0,
-                 SFP, 22, 12, DFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2VcvtDI,       0xeebd0bc0,
+                 kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vcvt.s32.f64 ", "!0s, !1S", 2),
-    ENCODING_MAP(THUMB2_VCVTFD,       0xeeb70ac0,
-                 DFP, 22, 12, SFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2VcvtFd,       0xeeb70ac0,
+                 kFmtDfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vcvt.f64.f32 ", "!0S, !1s", 2),
-    ENCODING_MAP(THUMB2_VCVTDF,       0xeeb70bc0,
-                 SFP, 22, 12, DFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2VcvtDF,       0xeeb70bc0,
+                 kFmtSfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vcvt.f32.f64 ", "!0s, !1S", 2),
-    ENCODING_MAP(THUMB2_VSQRTS,       0xeeb10ac0,
-                 SFP, 22, 12, SFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Vsqrts,       0xeeb10ac0,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vsqrt.f32 ", "!0s, !1s", 2),
-    ENCODING_MAP(THUMB2_VSQRTD,       0xeeb10bc0,
-                 DFP, 22, 12, DFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Vsqrtd,       0xeeb10bc0,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vsqrt.f64 ", "!0S, !1S", 2),
-    ENCODING_MAP(THUMB2_MOV_IMM_SHIFT, 0xf04f0000, /* no setflags encoding */
-                 BITBLT, 11, 8, MODIMM, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0,
+    ENCODING_MAP(kThumb2MovImmShift, 0xf04f0000, /* no setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
                  "mov", "r!0d, #!1m", 2),
-    ENCODING_MAP(THUMB2_MOV_IMM16,       0xf2400000,
-                 BITBLT, 11, 8, IMM16, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0,
+    ENCODING_MAP(kThumb2MovImm16,       0xf2400000,
+                 kFmtBitBlt, 11, 8, kFmtImm16, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
                  "mov", "r!0d, #!1M", 2),
-    ENCODING_MAP(THUMB2_STR_RRI12,       0xf8c00000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 11, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE01,
+    ENCODING_MAP(kThumb2StrRRI12,       0xf8c00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01,
                  "str", "r!0d,[r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_LDR_RRI12,       0xf8d00000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 11, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2LdrRRI12,       0xf8d00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "ldr", "r!0d,[r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_STR_RRI8_PREDEC,       0xf8400c00,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 8, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE01,
+    ENCODING_MAP(kThumb2StrRRI8Predec,       0xf8400c00,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01,
                  "str", "r!0d,[r!1d, #-!2d]", 2),
-    ENCODING_MAP(THUMB2_LDR_RRI8_PREDEC,       0xf8500c00,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 8, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2LdrRRI8Predec,       0xf8500c00,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 8, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "ldr", "r!0d,[r!1d, #-!2d]", 2),
-    ENCODING_MAP(THUMB2_CBNZ,       0xb900, /* Note: does not affect flags */
-                 BITBLT, 2, 0, IMM6, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_USE0 | IS_BRANCH,
+    ENCODING_MAP(kThumb2Cbnz,       0xb900, /* Note: does not affect flags */
+                 kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH,
                  "cbnz", "r!0d,!1t", 1),
-    ENCODING_MAP(THUMB2_CBZ,       0xb100, /* Note: does not affect flags */
-                 BITBLT, 2, 0, IMM6, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_USE0 | IS_BRANCH,
+    ENCODING_MAP(kThumb2Cbz,       0xb100, /* Note: does not affect flags */
+                 kFmtBitBlt, 2, 0, kFmtImm6, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | IS_BRANCH,
                  "cbz", "r!0d,!1t", 1),
-    ENCODING_MAP(THUMB2_ADD_RRI12,       0xf2000000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, IMM12, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2AddRRI12,       0xf2000000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */
                  "add", "r!0d,r!1d,#!2d", 2),
-    ENCODING_MAP(THUMB2_MOV_RR,       0xea4f0000, /* no setflags encoding */
-                 BITBLT, 11, 8, BITBLT, 3, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2MovRR,       0xea4f0000, /* no setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "mov", "r!0d, r!1d", 2),
-    ENCODING_MAP(THUMB2_VMOVS,       0xeeb00a40,
-                 SFP, 22, 12, SFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Vmovs,       0xeeb00a40,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vmov.f32 ", " !0s, !1s", 2),
-    ENCODING_MAP(THUMB2_VMOVD,       0xeeb00b40,
-                 DFP, 22, 12, DFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Vmovd,       0xeeb00b40,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vmov.f64 ", " !0S, !1S", 2),
-    ENCODING_MAP(THUMB2_LDMIA,         0xe8900000,
-                 BITBLT, 19, 16, BITBLT, 15, 0, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2Ldmia,         0xe8900000,
+                 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE0 | REG_DEF_LIST1,
                  "ldmia", "r!0d!!, <!1R>", 2),
-    ENCODING_MAP(THUMB2_STMIA,         0xe8800000,
-                 BITBLT, 19, 16, BITBLT, 15, 0, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2Stmia,         0xe8800000,
+                 kFmtBitBlt, 19, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE0 | REG_USE_LIST1,
                  "stmia", "r!0d!!, <!1R>", 2),
-    ENCODING_MAP(THUMB2_ADD_RRR,  0xeb100000, /* setflags encoding */
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1,
+    ENCODING_MAP(kThumb2AddRRR,  0xeb100000, /* setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1,
                  IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
                  "adds", "r!0d, r!1d, r!2d", 2),
-    ENCODING_MAP(THUMB2_SUB_RRR,       0xebb00000, /* setflags enconding */
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1,
+    ENCODING_MAP(kThumb2SubRRR,       0xebb00000, /* setflags enconding */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1,
                  IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
                  "subs", "r!0d, r!1d, r!2d", 2),
-    ENCODING_MAP(THUMB2_SBC_RRR,       0xeb700000, /* setflags encoding */
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1,
+    ENCODING_MAP(kThumb2SbcRRR,       0xeb700000, /* setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1,
                  IS_QUAD_OP | REG_DEF0_USE12 | USES_CCODES | SETS_CCODES,
                  "sbcs", "r!0d, r!1d, r!2d", 2),
-    ENCODING_MAP(THUMB2_CMP_RR,       0xebb00f00,
-                 BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2CmpRR,       0xebb00f00,
+                 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_USE01 | SETS_CCODES,
                  "cmp", "r!0d, r!1d", 2),
-    ENCODING_MAP(THUMB2_SUB_RRI12,       0xf2a00000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, IMM12, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2SubRRI12,       0xf2a00000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtImm12, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */
                  "sub", "r!0d,r!1d,#!2d", 2),
-    ENCODING_MAP(THUMB2_MVN_IMM_SHIFT,  0xf06f0000, /* no setflags encoding */
-                 BITBLT, 11, 8, MODIMM, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0,
+    ENCODING_MAP(kThumb2MvnImmShift,  0xf06f0000, /* no setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
                  "mvn", "r!0d, #!1n", 2),
-    ENCODING_MAP(THUMB2_SEL,       0xfaa0f080,
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2Sel,       0xfaa0f080,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE12 | USES_CCODES,
                  "sel", "r!0d, r!1d, r!2d", 2),
-    ENCODING_MAP(THUMB2_UBFX,       0xf3c00000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, LSB, -1, -1, BWIDTH, 4, 0,
-                 IS_QUAD_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Ubfx,       0xf3c00000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1,
+                 kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
                  "ubfx", "r!0d, r!1d, #!2d, #!3d", 2),
-    ENCODING_MAP(THUMB2_SBFX,       0xf3400000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, LSB, -1, -1, BWIDTH, 4, 0,
-                 IS_QUAD_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Sbfx,       0xf3400000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtLsb, -1, -1,
+                 kFmtBWidth, 4, 0, IS_QUAD_OP | REG_DEF0_USE1,
                  "sbfx", "r!0d, r!1d, #!2d, #!3d", 2),
-    ENCODING_MAP(THUMB2_LDR_RRR,    0xf8500000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 3, 0, BITBLT, 5, 4,
-                 IS_QUAD_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2LdrRRR,    0xf8500000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12,
                  "ldr", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
-    ENCODING_MAP(THUMB2_LDRH_RRR,    0xf8300000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 3, 0, BITBLT, 5, 4,
-                 IS_QUAD_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2LdrhRRR,    0xf8300000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12,
                  "ldrh", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
-    ENCODING_MAP(THUMB2_LDRSH_RRR,    0xf9300000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 3, 0, BITBLT, 5, 4,
-                 IS_QUAD_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2LdrshRRR,    0xf9300000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12,
                  "ldrsh", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
-    ENCODING_MAP(THUMB2_LDRB_RRR,    0xf8100000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 3, 0, BITBLT, 5, 4,
-                 IS_QUAD_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2LdrbRRR,    0xf8100000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12,
                  "ldrb", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
-    ENCODING_MAP(THUMB2_LDRSB_RRR,    0xf9100000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 3, 0, BITBLT, 5, 4,
-                 IS_QUAD_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2LdrsbRRR,    0xf9100000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_DEF0_USE12,
                  "ldrsb", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
-    ENCODING_MAP(THUMB2_STR_RRR,    0xf8400000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 3, 0, BITBLT, 5, 4,
-                 IS_QUAD_OP | REG_USE012,
+    ENCODING_MAP(kThumb2StrRRR,    0xf8400000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012,
                  "str", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
-    ENCODING_MAP(THUMB2_STRH_RRR,    0xf8200000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 3, 0, BITBLT, 5, 4,
-                 IS_QUAD_OP | REG_USE012,
+    ENCODING_MAP(kThumb2StrhRRR,    0xf8200000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012,
                  "strh", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
-    ENCODING_MAP(THUMB2_STRB_RRR,    0xf8000000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 3, 0, BITBLT, 5, 4,
-                 IS_QUAD_OP | REG_USE012,
+    ENCODING_MAP(kThumb2StrbRRR,    0xf8000000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 5, 4, IS_QUAD_OP | REG_USE012,
                  "strb", "r!0d,[r!1d, r!2d, LSL #!3d]", 2),
-    ENCODING_MAP(THUMB2_LDRH_RRI12,       0xf8b00000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 11, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
-                 "ldrh", "r!0d,[r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_LDRSH_RRI12,       0xf9b00000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 11, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
-                 "ldrsh", "r!0d,[r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_LDRB_RRI12,       0xf8900000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 11, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
-                 "ldrb", "r!0d,[r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_LDRSB_RRI12,       0xf9900000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 11, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
-                 "ldrsb", "r!0d,[r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_STRH_RRI12,       0xf8a00000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 11, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE01,
-                 "strh", "r!0d,[r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_STRB_RRI12,       0xf8800000,
-                 BITBLT, 15, 12, BITBLT, 19, 16, BITBLT, 11, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_USE01,
-                 "strb", "r!0d,[r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_POP,           0xe8bd0000,
-                 BITBLT, 15, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2LdrhRRI12,       0xf8b00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "ldrh", "r!0d,[r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2LdrshRRI12,       0xf9b00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "ldrsh", "r!0d,[r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2LdrbRRI12,       0xf8900000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "ldrb", "r!0d,[r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2LdrsbRRI12,       0xf9900000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "ldrsb", "r!0d,[r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2StrhRRI12,       0xf8a00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01,
+                 "strh", "r!0d,[r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2StrbRRI12,       0xf8800000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 11, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE01,
+                 "strb", "r!0d,[r!1d, #!2d]", 2),
+    ENCODING_MAP(kThumb2Pop,           0xe8bd0000,
+                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0,
                  "pop", "<!0R>", 2),
-    ENCODING_MAP(THUMB2_PUSH,          0xe8ad0000,
-                 BITBLT, 15, 0, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2Push,          0xe8ad0000,
+                 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_UNARY_OP | REG_DEF_SP | REG_USE_SP | REG_USE_LIST0,
                  "push", "<!0R>", 2),
-    ENCODING_MAP(THUMB2_CMP_RI8, 0xf1b00f00,
-                 BITBLT, 19, 16, MODIMM, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2CmpRI8, 0xf1b00f00,
+                 kFmtBitBlt, 19, 16, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_USE0 | SETS_CCODES,
                  "cmp", "r!0d, #!1m", 2),
-    ENCODING_MAP(THUMB2_ADC_RRR,  0xeb500000, /* setflags encoding */
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1,
+    ENCODING_MAP(kThumb2AdcRRR,  0xeb500000, /* setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1,
                  IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
                  "acds", "r!0d, r!1d, r!2d, shift !3d", 2),
-    ENCODING_MAP(THUMB2_AND_RRR,  0xea000000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1,
-                 IS_QUAD_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2AndRRR,  0xea000000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
                  "and", "r!0d, r!1d, r!2d, shift !3d", 2),
-    ENCODING_MAP(THUMB2_BIC_RRR,  0xea200000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1,
-                 IS_QUAD_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2BicRRR,  0xea200000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
                  "bic", "r!0d, r!1d, r!2d, shift !3d", 2),
-    ENCODING_MAP(THUMB2_CMN_RR,  0xeb000000,
-                 BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2CmnRR,  0xeb000000,
+                 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "cmn", "r!0d, r!1d, shift !2d", 2),
-    ENCODING_MAP(THUMB2_EOR_RRR,  0xea800000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1,
-                 IS_QUAD_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2EorRRR,  0xea800000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
                  "eor", "r!0d, r!1d, r!2d, shift !3d", 2),
-    ENCODING_MAP(THUMB2_MUL_RRR,  0xfb00f000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2MulRRR,  0xfb00f000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "mul", "r!0d, r!1d, r!2d", 2),
-    ENCODING_MAP(THUMB2_MVN_RR,  0xea6f0000,
-                 BITBLT, 11, 8, BITBLT, 3, 0, SHIFT, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2MnvRR,  0xea6f0000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "mvn", "r!0d, r!1d, shift !2d", 2),
-    ENCODING_MAP(THUMB2_RSUB_RRI8,       0xf1d00000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, MODIMM, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2RsubRRI8,       0xf1d00000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "rsb", "r!0d,r!1d,#!2m", 2),
-    ENCODING_MAP(THUMB2_NEG_RR,       0xf1d00000, /* instance of rsub */
-                 BITBLT, 11, 8, BITBLT, 19, 16, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2NegRR,       0xf1d00000, /* instance of rsub */
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "neg", "r!0d,r!1d", 2),
-    ENCODING_MAP(THUMB2_ORR_RRR,  0xea400000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1,
-                 IS_QUAD_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2OrrRRR,  0xea400000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12,
                  "orr", "r!0d, r!1d, r!2d, shift !3d", 2),
-    ENCODING_MAP(THUMB2_TST_RR,       0xea100f00,
-                 BITBLT, 19, 16, BITBLT, 3, 0, SHIFT, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2TstRR,       0xea100f00,
+                 kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtShift, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_USE01 | SETS_CCODES,
                  "tst", "r!0d, r!1d, shift !2d", 2),
-    ENCODING_MAP(THUMB2_LSL_RRR,  0xfa00f000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2LslRRR,  0xfa00f000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "lsl", "r!0d, r!1d, r!2d", 2),
-    ENCODING_MAP(THUMB2_LSR_RRR,  0xfa20f000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2LsrRRR,  0xfa20f000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "lsr", "r!0d, r!1d, r!2d", 2),
-    ENCODING_MAP(THUMB2_ASR_RRR,  0xfa40f000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2AsrRRR,  0xfa40f000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "asr", "r!0d, r!1d, r!2d", 2),
-    ENCODING_MAP(THUMB2_ROR_RRR,  0xfa60f000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, BITBLT, 3, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2RorRRR,  0xfa60f000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "ror", "r!0d, r!1d, r!2d", 2),
-    ENCODING_MAP(THUMB2_LSL_RRI5,  0xea4f0000,
-                 BITBLT, 11, 8, BITBLT, 3, 0, SHIFT5, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2LslRRI5,  0xea4f0000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "lsl", "r!0d, r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_LSR_RRI5,  0xea4f0010,
-                 BITBLT, 11, 8, BITBLT, 3, 0, SHIFT5, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2LsrRRI5,  0xea4f0010,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "lsr", "r!0d, r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_ASR_RRI5,  0xea4f0020,
-                 BITBLT, 11, 8, BITBLT, 3, 0, SHIFT5, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2AsrRRI5,  0xea4f0020,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "asr", "r!0d, r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_ROR_RRI5,  0xea4f0030,
-                 BITBLT, 11, 8, BITBLT, 3, 0, SHIFT5, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2RorRRI5,  0xea4f0030,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift5, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "ror", "r!0d, r!1d, #!2d", 2),
-    ENCODING_MAP(THUMB2_BIC_RRI8,  0xf0200000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, MODIMM, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2BicRRI8,  0xf0200000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "bic", "r!0d, r!1d, #!2m", 2),
-    ENCODING_MAP(THUMB2_AND_RRI8,  0xf0000000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, MODIMM, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2AndRRI8,  0xf0000000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "and", "r!0d, r!1d, #!2m", 2),
-    ENCODING_MAP(THUMB2_ORR_RRI8,  0xf0400000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, MODIMM, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2OrrRRI8,  0xf0400000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "orr", "r!0d, r!1d, #!2m", 2),
-    ENCODING_MAP(THUMB2_EOR_RRI8,  0xf0800000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, MODIMM, -1, -1, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2EorRRI8,  0xf0800000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
                  "eor", "r!0d, r!1d, #!2m", 2),
-    ENCODING_MAP(THUMB2_ADD_RRI8,  0xf1100000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, MODIMM, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2AddRRI8,  0xf1100000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "adds", "r!0d, r!1d, #!2m", 2),
-    ENCODING_MAP(THUMB2_ADC_RRI8,  0xf1500000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, MODIMM, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2AdcRRI8,  0xf1500000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES,
                  "adcs", "r!0d, r!1d, #!2m", 2),
-    ENCODING_MAP(THUMB2_SUB_RRI8,  0xf1b00000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, MODIMM, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2SubRRI8,  0xf1b00000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "subs", "r!0d, r!1d, #!2m", 2),
-    ENCODING_MAP(THUMB2_SBC_RRI8,  0xf1700000,
-                 BITBLT, 11, 8, BITBLT, 19, 16, MODIMM, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2SbcRRI8,  0xf1700000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES | USES_CCODES,
                  "sbcs", "r!0d, r!1d, #!2m", 2),
-    ENCODING_MAP(THUMB2_IT,  0xbf00,
-                 BITBLT, 7, 4, BITBLT, 3, 0, MODIMM, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | IS_IT | USES_CCODES,
+    ENCODING_MAP(kThumb2It,  0xbf00,
+                 kFmtBitBlt, 7, 4, kFmtBitBlt, 3, 0, kFmtModImm, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | IS_IT | USES_CCODES,
                  "it:!1b", "!0c", 1),
-    ENCODING_MAP(THUMB2_FMSTAT,  0xeef1fa10,
-                 UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1, UNUSED, -1, -1,
-                 NO_OPERAND | SETS_CCODES,
+    ENCODING_MAP(kThumb2Fmstat,  0xeef1fa10,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND | SETS_CCODES,
                  "fmstat", "", 2),
-    ENCODING_MAP(THUMB2_VCMPD,        0xeeb40b40,
-                 DFP, 22, 12, DFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_USE01,
+    ENCODING_MAP(kThumb2Vcmpd,        0xeeb40b40,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01,
                  "vcmp.f64", "!0S, !1S", 2),
-    ENCODING_MAP(THUMB2_VCMPS,        0xeeb40a40,
-                 SFP, 22, 12, SFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_USE01,
+    ENCODING_MAP(kThumb2Vcmps,        0xeeb40a40,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE01,
                  "vcmp.f32", "!0s, !1s", 2),
-    ENCODING_MAP(THUMB2_LDR_PC_REL12,       0xf8df0000,
-                 BITBLT, 15, 12, BITBLT, 11, 0, UNUSED, -1, -1, UNUSED, -1, -1,
+    ENCODING_MAP(kThumb2LdrPcRel12,       0xf8df0000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0 | REG_USE_PC,
-                 "ldr", "r!0d,[rpc, #!1d", 2),
-    ENCODING_MAP(THUMB2_B_COND,        0xf0008000,
-                 BROFFSET, -1, -1, BITBLT, 25, 22, UNUSED, -1, -1,
-                 UNUSED, -1, -1,
+                 "ldr", "r!0d,[rpc, #!1d]", 2),
+    ENCODING_MAP(kThumb2BCond,        0xf0008000,
+                 kFmtBrOffset, -1, -1, kFmtBitBlt, 25, 22, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1,
                  IS_BINARY_OP | IS_BRANCH | USES_CCODES,
                  "b!1c", "!0t", 2),
-    ENCODING_MAP(THUMB2_VMOVD_RR,       0xeeb00b40,
-                 DFP, 22, 12, DFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Vmovd_RR,       0xeeb00b40,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "vmov.f64", "!0S, !1S", 2),
-    ENCODING_MAP(THUMB2_VMOVS_RR,       0xeeb00a40,
-                 SFP, 22, 12, SFP, 5, 0, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
-                 "vmov.f32", "!0S, !1S", 2),
-    ENCODING_MAP(THUMB2_FMRS,       0xee100a10,
-                 BITBLT, 15, 12, SFP, 8, 16, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Vmovs_RR,       0xeeb00a40,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vmov.f32", "!0s, !1s", 2),
+    ENCODING_MAP(kThumb2Fmrs,       0xee100a10,
+                 kFmtBitBlt, 15, 12, kFmtSfp, 7, 16, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "fmrs", "r!0d, !1s", 2),
-    ENCODING_MAP(THUMB2_FMSR,       0xee000a10,
-                 SFP, 8, 16, BITBLT, 15, 12, UNUSED, -1, -1, UNUSED, -1, -1,
-                 IS_BINARY_OP | REG_DEF0_USE1,
+    ENCODING_MAP(kThumb2Fmsr,       0xee000a10,
+                 kFmtSfp, 7, 16, kFmtBitBlt, 15, 12, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
                  "fmsr", "!0s, r!1d", 2),
-    ENCODING_MAP(THUMB2_FMRRD,       0xec500b10,
-                 BITBLT, 15, 12, BITBLT, 19, 16, DFP, 5, 0, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF01_USE2,
+    ENCODING_MAP(kThumb2Fmrrd,       0xec500b10,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtDfp, 5, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF01_USE2,
                  "fmrrd", "r!0d, r!1d, !2S", 2),
-    ENCODING_MAP(THUMB2_FMDRR,       0xec400b10,
-                 DFP, 5, 0, BITBLT, 15, 12, BITBLT, 19, 16, UNUSED, -1, -1,
-                 IS_TERTIARY_OP | REG_DEF0_USE12,
+    ENCODING_MAP(kThumb2Fmdrr,       0xec400b10,
+                 kFmtDfp, 5, 0, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
                  "fmdrr", "!0S, r!1d, r!2d", 2),
+    ENCODING_MAP(kThumb2Vabsd,       0xeeb00bc0,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vabs.f64", "!0S, !1S", 2),
+    ENCODING_MAP(kThumb2Vabss,       0xeeb00ac0,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vabs.f32", "!0s, !1s", 2),
+    ENCODING_MAP(kThumb2Vnegd,       0xeeb10b40,
+                 kFmtDfp, 22, 12, kFmtDfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vneg.f64", "!0S, !1S", 2),
+    ENCODING_MAP(kThumb2Vnegs,       0xeeb10a40,
+                 kFmtSfp, 22, 12, kFmtSfp, 5, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
+                 "vneg.f32", "!0s, !1s", 2),
+    ENCODING_MAP(kThumb2Vmovs_IMM8,       0xeeb00a00,
+                 kFmtSfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "vmov.f32", "!0s, #0x!1h", 2),
+    ENCODING_MAP(kThumb2Vmovd_IMM8,       0xeeb00b00,
+                 kFmtDfp, 22, 12, kFmtFPImm, 16, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
+                 "vmov.f64", "!0S, #0x!1h", 2),
+    ENCODING_MAP(kThumb2Mla,  0xfb000000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtBitBlt, 15, 12,
+                 IS_QUAD_OP | REG_DEF0 | REG_USE1 | REG_USE2 | REG_USE3,
+                 "mla", "r!0d, r!1d, r!2d, r!3d", 2),
+    ENCODING_MAP(kThumb2Umull,  0xfba00000,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16,
+                 kFmtBitBlt, 3, 0,
+                 IS_QUAD_OP | REG_DEF0 | REG_DEF1 | REG_USE2 | REG_USE3,
+                 "umull", "r!0d, r!1d, r!2d, r!3d", 2),
+    ENCODING_MAP(kThumb2Ldrex,       0xe8500f00,
+                 kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16, kFmtBitBlt, 7, 0,
+                 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
+                 "ldrex", "r!0d,[r!1d, #!2E]", 2),
+    ENCODING_MAP(kThumb2Strex,       0xe8400000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 15, 12, kFmtBitBlt, 19, 16,
+                 kFmtBitBlt, 7, 0, IS_QUAD_OP | REG_DEF0_USE12,
+                 "strex", "r!0d,r!1d, [r!2d, #!2E]", 2),
+    ENCODING_MAP(kThumb2Clrex,       0xf3bf8f2f,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND, "clrex", "", 2),
 };
 
 /*
@@ -802,7 +898,7 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
 
     for (lir = (ArmLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
         if (lir->opCode < 0) {
-            if ((lir->opCode == ARM_PSEUDO_ALIGN4) &&
+            if ((lir->opCode == kArmPseudoPseudoAlign4) &&
                 /* 1 means padding is needed */
                 (lir->operands[0] == 1)) {
                 *bufferAddr++ = PADDING_MOV_R5_R5;
@@ -814,9 +910,10 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
             continue;
         }
 
-        if (lir->opCode == THUMB_LDR_PC_REL ||
-            lir->opCode == THUMB2_LDR_PC_REL12 ||
-            lir->opCode == THUMB_ADD_PC_REL) {
+        if (lir->opCode == kThumbLdrPcRel ||
+            lir->opCode == kThumb2LdrPcRel12 ||
+            lir->opCode == kThumbAddPcRel ||
+            ((lir->opCode == kThumb2Vldrs) && (lir->operands[1] == rpc))) {
             ArmLIR *lirTarget = (ArmLIR *) lir->generic.target;
             intptr_t pc = (lir->generic.offset + 4) & ~3;
             /*
@@ -830,14 +927,18 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
                 LOGE("PC-rel distance is not multiples of 4: %d\n", delta);
                 dvmAbort();
             }
-            if ((lir->opCode == THUMB2_LDR_PC_REL12) && (delta > 4091)) {
+            if ((lir->opCode == kThumb2LdrPcRel12) && (delta > 4091)) {
                 return true;
             } else if (delta > 1020) {
                 return true;
             }
-            lir->operands[1] = (lir->opCode == THUMB2_LDR_PC_REL12) ?
-                                delta : delta >> 2;
-        } else if (lir->opCode == THUMB2_CBNZ || lir->opCode == THUMB2_CBZ) {
+            if (lir->opCode == kThumb2Vldrs) {
+                lir->operands[2] = delta >> 2;
+            } else {
+                lir->operands[1] = (lir->opCode == kThumb2LdrPcRel12) ?
+                                    delta : delta >> 2;
+            }
+        } else if (lir->opCode == kThumb2Cbnz || lir->opCode == kThumb2Cbz) {
             ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
             intptr_t pc = lir->generic.offset + 4;
             intptr_t target = targetLIR->generic.offset;
@@ -851,17 +952,17 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
             } else {
                 lir->operands[1] = delta >> 1;
             }
-        } else if (lir->opCode == THUMB_B_COND ||
-                   lir->opCode == THUMB2_B_COND) {
+        } else if (lir->opCode == kThumbBCond ||
+                   lir->opCode == kThumb2BCond) {
             ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
             intptr_t pc = lir->generic.offset + 4;
             intptr_t target = targetLIR->generic.offset;
             int delta = target - pc;
-            if ((lir->opCode == THUMB_B_COND) && (delta > 254 || delta < -256)) {
+            if ((lir->opCode == kThumbBCond) && (delta > 254 || delta < -256)) {
                 return true;
             }
             lir->operands[0] = delta >> 1;
-        } else if (lir->opCode == THUMB_B_UNCOND) {
+        } else if (lir->opCode == kThumbBUncond) {
             ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
             intptr_t pc = lir->generic.offset + 4;
             intptr_t target = targetLIR->generic.offset;
@@ -871,8 +972,8 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
                 dvmAbort();
             }
             lir->operands[0] = delta >> 1;
-        } else if (lir->opCode == THUMB_BLX_1) {
-            assert(NEXT_LIR(lir)->opCode == THUMB_BLX_2);
+        } else if (lir->opCode == kThumbBlx1) {
+            assert(NEXT_LIR(lir)->opCode == kThumbBlx2);
             /* curPC is Thumb */
             intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3;
             intptr_t target = lir->operands[1];
@@ -896,45 +997,59 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
             u4 value;
             operand = lir->operands[i];
             switch(encoder->fieldLoc[i].kind) {
-                case UNUSED:
+                case kFmtUnused:
+                    break;
+                case kFmtFPImm:
+                    value = ((operand & 0xF0) >> 4) << encoder->fieldLoc[i].end;
+                    value |= (operand & 0x0F) << encoder->fieldLoc[i].start;
+                    bits |= value;
                     break;
-                case BROFFSET:
-                    value = ((operand  & 0x80000) >> 19) << 26;
-                    value |= ((operand & 0x40000) >> 18) << 11;
-                    value |= ((operand & 0x20000) >> 17) << 13;
-                    value |= ((operand & 0x1f800) >> 11) << 16;
-                    value |= (operand  & 0x007ff);
+                case kFmtBrOffset:
+                    /*
+                     * NOTE: branch offsets are not handled here, but
+                     * in the main assembly loop (where label values
+                     * are known).  For reference, here is what the
+                     * encoder handing would be:
+                         value = ((operand  & 0x80000) >> 19) << 26;
+                         value |= ((operand & 0x40000) >> 18) << 11;
+                         value |= ((operand & 0x20000) >> 17) << 13;
+                         value |= ((operand & 0x1f800) >> 11) << 16;
+                         value |= (operand  & 0x007ff);
+                         bits |= value;
+                     */
                     break;
-                case SHIFT5:
+                case kFmtShift5:
                     value = ((operand & 0x1c) >> 2) << 12;
                     value |= (operand & 0x03) << 6;
                     bits |= value;
                     break;
-                case SHIFT:
+                case kFmtShift:
                     value = ((operand & 0x70) >> 4) << 12;
                     value |= (operand & 0x0f) << 4;
                     bits |= value;
                     break;
-                case BWIDTH:
+                case kFmtBWidth:
                     value = operand - 1;
                     bits |= value;
                     break;
-                case LSB:
+                case kFmtLsb:
                     value = ((operand & 0x1c) >> 2) << 12;
                     value |= (operand & 0x03) << 6;
                     bits |= value;
                     break;
-                case IMM6:
+                case kFmtImm6:
                     value = ((operand & 0x20) >> 5) << 9;
                     value |= (operand & 0x1f) << 3;
                     bits |= value;
                     break;
-                case BITBLT:
+                case kFmtBitBlt:
                     value = (operand << encoder->fieldLoc[i].start) &
                             ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
                     bits |= value;
                     break;
-                case DFP: {
+                case kFmtDfp: {
+                    assert(DOUBLEREG(operand));
+                    assert((operand & 0x1) == 0);
                     int regName = (operand & FP_REG_MASK) >> 1;
                     /* Snag the 1-bit slice and position it */
                     value = ((regName & 0x10) >> 4) <<
@@ -945,7 +1060,8 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
                     bits |= value;
                     break;
                 }
-                case SFP:
+                case kFmtSfp:
+                    assert(SINGLEREG(operand));
                     /* Snag the 1-bit slice and position it */
                     value = (operand & 0x1) <<
                             encoder->fieldLoc[i].end;
@@ -954,14 +1070,14 @@ static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
                             encoder->fieldLoc[i].start;
                     bits |= value;
                     break;
-                case IMM12:
-                case MODIMM:
+                case kFmtImm12:
+                case kFmtModImm:
                     value = ((operand & 0x800) >> 11) << 26;
                     value |= ((operand & 0x700) >> 8) << 12;
                     value |= operand & 0x0ff;
                     bits |= value;
                     break;
-                case IMM16:
+                case kFmtImm16:
                     value = ((operand & 0x0800) >> 11) << 26;
                     value |= ((operand & 0xf000) >> 12) << 16;
                     value |= ((operand & 0x0700) >> 8) << 12;
@@ -1037,7 +1153,7 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
         if (armLIR->opCode >= 0 && !armLIR->isNop) {
             armLIR->size = EncodingMap[armLIR->opCode].size * 2;
             offset += armLIR->size;
-        } else if (armLIR->opCode == ARM_PSEUDO_ALIGN4) {
+        } else if (armLIR->opCode == kArmPseudoPseudoAlign4) {
             if (offset & 0x2) {
                 offset += 2;
                 armLIR->operands[0] = 1;
@@ -1056,7 +1172,7 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
     ArmLIR *chainCellOffsetLIR = (ArmLIR *) cUnit->chainCellOffsetLIR;
     assert(chainCellOffsetLIR);
     assert(chainCellOffset < 0x10000);
-    assert(chainCellOffsetLIR->opCode == ARM_16BIT_DATA &&
+    assert(chainCellOffsetLIR->opCode == kArm16BitData &&
            chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG);
 
     /*
@@ -1119,7 +1235,7 @@ void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
     gDvmJit.numCompilations++;
 
     /* Install the chaining cell counts */
-    for (i=0; i< CHAINING_CELL_LAST; i++) {
+    for (i=0; i< kChainingCellLast; i++) {
         chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
     }
     memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
@@ -1314,8 +1430,8 @@ u4* dvmJitUnchain(void* codeAddr)
     PredictedChainingCell *predChainCell;
 
     /* Get total count of chain cells */
-    for (i = 0, cellSize = 0; i < CHAINING_CELL_LAST; i++) {
-        if (i != CHAINING_CELL_INVOKE_PREDICTED) {
+    for (i = 0, cellSize = 0; i < kChainingCellLast; i++) {
+        if (i != kChainingCellInvokePredicted) {
             cellSize += pChainCellCounts->u.count[i] * 2;
         } else {
             cellSize += pChainCellCounts->u.count[i] * 4;
@@ -1326,25 +1442,25 @@ u4* dvmJitUnchain(void* codeAddr)
     pStart = pChainCells = ((u4 *) pChainCellCounts) - cellSize;
 
     /* The cells are sorted in order - walk through them and reset */
-    for (i = 0; i < CHAINING_CELL_LAST; i++) {
+    for (i = 0; i < kChainingCellLast; i++) {
         int elemSize = 2; /* Most chaining cell has two words */
-        if (i == CHAINING_CELL_INVOKE_PREDICTED) {
+        if (i == kChainingCellInvokePredicted) {
             elemSize = 4;
         }
 
         for (j = 0; j < pChainCellCounts->u.count[i]; j++) {
             int targetOffset;
             switch(i) {
-                case CHAINING_CELL_NORMAL:
+                case kChainingCellNormal:
                     targetOffset = offsetof(InterpState,
                           jitToInterpEntries.dvmJitToInterpNormal);
                     break;
-                case CHAINING_CELL_HOT:
-                case CHAINING_CELL_INVOKE_SINGLETON:
+                case kChainingCellHot:
+                case kChainingCellInvokeSingleton:
                     targetOffset = offsetof(InterpState,
                           jitToInterpEntries.dvmJitToTraceSelect);
                     break;
-                case CHAINING_CELL_INVOKE_PREDICTED:
+                case kChainingCellInvokePredicted:
                     targetOffset = 0;
                     predChainCell = (PredictedChainingCell *) pChainCells;
                     /* Reset the cell to the init state */
@@ -1354,12 +1470,12 @@ u4* dvmJitUnchain(void* codeAddr)
                     predChainCell->counter = PREDICTED_CHAIN_COUNTER_INIT;
                     break;
 #if defined(WITH_SELF_VERIFICATION)
-                case CHAINING_CELL_BACKWARD_BRANCH:
+                case kChainingCellBackwardBranch:
                     targetOffset = offsetof(InterpState,
                           jitToInterpEntries.dvmJitToBackwardBranch);
                     break;
 #elif defined(WITH_JIT_TUNING)
-                case CHAINING_CELL_BACKWARD_BRANCH:
+                case kChainingCellBackwardBranch:
                     targetOffset = offsetof(InterpState,
                           jitToInterpEntries.dvmJitToInterpNormal);
                     break;
@@ -1374,7 +1490,7 @@ u4* dvmJitUnchain(void* codeAddr)
              *     ldr  r0, rGLUE, #<word offset>
              *     blx  r0
              */
-            if (i != CHAINING_CELL_INVOKE_PREDICTED) {
+            if (i != kChainingCellInvokePredicted) {
                 targetOffset = targetOffset >> 2;  /* convert to word offset */
                 thumb1 = 0x6800 | (targetOffset << 6) |
                          (rGLUE << 3) | (r0 << 0);
index c3a60e4..506ac9e 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "armv5te-vfp/ArchVariant.h"
 
+#include "RallocUtil.c"
 #include "ThumbUtil.c"
 #include "Codegen.c"
 #include "armv5te-vfp/ArchVariant.c"
index baf9dc9..aec19f2 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "armv5te/ArchVariant.h"
 
+#include "RallocUtil.c"
 #include "ThumbUtil.c"
 #include "Codegen.c"
 #include "armv5te/ArchVariant.c"
index a691231..eb18b1a 100644 (file)
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #include "Dalvik.h"
 #include "interp/InterpDefs.h"
 #include "libdex/OpCode.h"
@@ -24,6 +23,7 @@
 
 #include "armv7-a/ArchVariant.h"
 
+#include "RallocUtil.c"
 #include "Thumb2Util.c"
 #include "Codegen.c"
 #include "armv7-a/ArchVariant.c"
index 2713a12..9563df1 100644 (file)
@@ -56,24 +56,13 @@ static inline bool selfVerificationPuntOps(OpCode op)
 /* Decode contents of heapArgSpace to determine addr to load from */
 static void selfVerificationLoadDecode(HeapArgSpace* heapArgSpace, int* addr)
 {
-    int reg = heapArgSpace->regMap & 0xF;
-
-    switch (reg) {
-        case 0:
-            *addr = heapArgSpace->r0;
-            break;
-        case 1:
-            *addr = heapArgSpace->r1;
-            break;
-        case 2:
-            *addr = heapArgSpace->r2;
-            break;
-        case 3:
-            *addr = heapArgSpace->r3;
-            break;
-        default:
-            LOGE("ERROR: bad reg used in selfVerificationLoadDecode: %d", reg);
-            break;
+    int reg = heapArgSpace->regMap & 0xFF;
+    if (!FPREG(reg)) {
+        assert(reg < 16);
+        *addr = heapArgSpace->coreRegs[reg];
+    } else {
+        assert(!DOUBLEREG(reg));
+        *addr = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
     }
 }
 
@@ -81,23 +70,12 @@ static void selfVerificationLoadDecode(HeapArgSpace* heapArgSpace, int* addr)
 static void selfVerificationLoadDecodeData(HeapArgSpace* heapArgSpace,
                                            int data, int reg)
 {
-    switch (reg) {
-        case 0:
-            heapArgSpace->r0 = data;
-            break;
-        case 1:
-            heapArgSpace->r1 = data;
-            break;
-        case 2:
-            heapArgSpace->r2 = data;
-            break;
-        case 3:
-            heapArgSpace->r3 = data;
-            break;
-        default:
-            LOGE("ERROR: bad reg passed to selfVerificationLoadDecodeData: %d",
-                reg);
-            break;
+    if (!FPREG(reg)) {
+        assert(reg < 16);
+        heapArgSpace->coreRegs[reg] = data;
+    } else {
+        assert(!DOUBLEREG(reg));
+        heapArgSpace->fpRegs[(reg & FP_REG_MASK)] = data;
     }
 }
 
@@ -122,9 +100,9 @@ static void selfVerificationLoad(InterpState* interpState)
     if (heapSpacePtr == shadowSpace->heapSpaceTail)
         data = *((unsigned int*) addr);
 
-    int reg = (heapArgSpace->regMap >> 4) & 0xF;
+    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
 
-    //LOGD("*** HEAP LOAD: Reg:%d Addr: 0x%x Data: 0x%x", reg, addr, data);
+    // LOGD("*** HEAP LOAD: Reg:%d Addr: 0x%x Data: 0x%x", reg, addr, data);
 
     selfVerificationLoadDecodeData(heapArgSpace, data, reg);
 }
@@ -156,7 +134,7 @@ static void selfVerificationLoadByte(InterpState* interpState)
 
     //LOGD("*** HEAP LOAD BYTE: Addr: 0x%x Data: 0x%x", addr, data);
 
-    int reg = (heapArgSpace->regMap >> 4) & 0xF;
+    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
     selfVerificationLoadDecodeData(heapArgSpace, data, reg);
 }
 
@@ -185,9 +163,9 @@ static void selfVerificationLoadHalfword(InterpState* interpState)
     if (heapSpacePtr == shadowSpace->heapSpaceTail)
         data = *((unsigned short*) addr);
 
-    //LOGD("*** HEAP LOAD HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
+    //LOGD("*** HEAP LOAD kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
 
-    int reg = (heapArgSpace->regMap >> 4) & 0xF;
+    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
     selfVerificationLoadDecodeData(heapArgSpace, data, reg);
 }
 
@@ -218,7 +196,7 @@ static void selfVerificationLoadSignedByte(InterpState* interpState)
 
     //LOGD("*** HEAP LOAD SIGNED BYTE: Addr: 0x%x Data: 0x%x", addr, data);
 
-    int reg = (heapArgSpace->regMap >> 4) & 0xF;
+    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
     selfVerificationLoadDecodeData(heapArgSpace, data, reg);
 }
 
@@ -247,9 +225,9 @@ static void selfVerificationLoadSignedHalfword(InterpState* interpState)
     if (heapSpacePtr == shadowSpace->heapSpaceTail)
         data = *((signed short*) addr);
 
-    //LOGD("*** HEAP LOAD SIGNED HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
+    //LOGD("*** HEAP LOAD SIGNED kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
 
-    int reg = (heapArgSpace->regMap >> 4) & 0xF;
+    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
     selfVerificationLoadDecodeData(heapArgSpace, data, reg);
 }
 
@@ -276,11 +254,11 @@ static void selfVerificationLoadDoubleword(InterpState* interpState)
         }
     }
 
-    //LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
+    // LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
     //    addr, data, data2);
 
-    int reg = (heapArgSpace->regMap >> 4) & 0xF;
-    int reg2 = (heapArgSpace->regMap >> 8) & 0xF;
+    int reg = (heapArgSpace->regMap >> 8) & 0xFF;
+    int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
     selfVerificationLoadDecodeData(heapArgSpace, data, reg);
     selfVerificationLoadDecodeData(heapArgSpace, data2, reg2);
 }
@@ -289,23 +267,12 @@ static void selfVerificationLoadDoubleword(InterpState* interpState)
 static void selfVerificationStoreDecode(HeapArgSpace* heapArgSpace,
                                         int* value, int reg)
 {
-    switch (reg) {
-        case 0:
-            *value = heapArgSpace->r0;
-            break;
-        case 1:
-            *value = heapArgSpace->r1;
-            break;
-        case 2:
-            *value = heapArgSpace->r2;
-            break;
-        case 3:
-            *value = heapArgSpace->r3;
-            break;
-        default:
-            LOGE("ERROR: bad reg passed to selfVerificationStoreDecode: %d",
-                reg);
-            break;
+    if (!FPREG(reg)) {
+        assert(reg < 16);
+        *value = heapArgSpace->coreRegs[reg];
+    } else {
+        assert(!DOUBLEREG(reg));
+        *value = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
     }
 }
 
@@ -317,8 +284,8 @@ static void selfVerificationStore(InterpState* interpState)
     HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
 
     int addr, data;
-    int reg0 = heapArgSpace->regMap & 0xF;
-    int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
+    int reg0 = heapArgSpace->regMap & 0xFF;
+    int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
     selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
     selfVerificationStoreDecode(heapArgSpace, &data, reg1);
 
@@ -345,8 +312,8 @@ static void selfVerificationStoreByte(InterpState* interpState)
     HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
 
     int addr, data;
-    int reg0 = heapArgSpace->regMap & 0xF;
-    int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
+    int reg0 = heapArgSpace->regMap & 0xFF;
+    int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
     selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
     selfVerificationStoreDecode(heapArgSpace, &data, reg1);
 
@@ -381,15 +348,15 @@ static void selfVerificationStoreHalfword(InterpState* interpState)
     HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
 
     int addr, data;
-    int reg0 = heapArgSpace->regMap & 0xF;
-    int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
+    int reg0 = heapArgSpace->regMap & 0xFF;
+    int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
     selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
     selfVerificationStoreDecode(heapArgSpace, &data, reg1);
 
     int maskedAddr = addr & 0xFFFFFFFC;
     int alignment = addr & 0x2;
 
-    //LOGD("*** HEAP STORE HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
+    //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
 
     for (heapSpacePtr = shadowSpace->heapSpace;
          heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
@@ -405,7 +372,7 @@ static void selfVerificationStoreHalfword(InterpState* interpState)
     addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
     *((unsigned short*) addr) = (short) data;
 
-    //LOGD("*** HEAP STORE HALFWORD: Addr: 0x%x Final Data: 0x%x",
+    //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Final Data: 0x%x",
     //    addr, heapSpacePtr->data);
 }
 
@@ -417,9 +384,9 @@ static void selfVerificationStoreDoubleword(InterpState* interpState)
     HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
 
     int addr, data, data2;
-    int reg0 = heapArgSpace->regMap & 0xF;
-    int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
-    int reg2 = (heapArgSpace->regMap >> 8) & 0xF;
+    int reg0 = heapArgSpace->regMap & 0xFF;
+    int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
+    int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
     selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
     selfVerificationStoreDecode(heapArgSpace, &data, reg1);
     selfVerificationStoreDecode(heapArgSpace, &data2, reg2);
@@ -457,33 +424,263 @@ static void selfVerificationStoreDoubleword(InterpState* interpState)
 static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
                                          void* funct)
 {
-    int regMask = (1 << r4PC) | (1 << r3) | (1 << r2) | (1 << r1) | (1 << r0);
-
-    /* r7 <- InterpState->heapArgSpace */
-    loadConstant(cUnit, r4PC, offsetof(InterpState, heapArgSpace));
-    newLIR3(cUnit, THUMB_ADD_RRR, r7, rGLUE, r4PC);
+    /* push r0 and r7 to give us a foothold */
+    newLIR1(cUnit, kThumbPush, (1 << r0) | (1 << r7));
 
-    /* Save out values to heapArgSpace */
-    loadConstant(cUnit, r4PC, regMap);
-    newLIR2(cUnit, THUMB_STMIA, r7, regMask);
+    /* Let the save handler know where the save record is */
+    loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace));
 
-    /* Pass interpState pointer to function */
-    newLIR2(cUnit, THUMB_MOV_RR, r0, rGLUE);
+    /* Load the regMap and call the save handler [note: handler pops r0/r7] */
+    loadConstant(cUnit, r7, regMap);
+    genDispatchToHandler(cUnit, TEMPLATE_SAVE_STATE);
 
-    /* Set function pointer and branch */
+    /* Set function pointer, pass rGLUE and branch */
     loadConstant(cUnit, r1, (int) funct);
-    newLIR1(cUnit, THUMB_BLX_R, r1);
-
-    /* r7 <- InterpState->heapArgSpace */
-    loadConstant(cUnit, r4PC, offsetof(InterpState, heapArgSpace));
-    newLIR3(cUnit, THUMB_ADD_RRR, r7, rGLUE, r4PC);
+    newLIR2(cUnit, kThumbMovRR, r0, rGLUE);
+    newLIR1(cUnit, kThumbBlxR, r1);
 
-    /* Restore register state */
-    newLIR2(cUnit, THUMB_LDMIA, r7, regMask);
+    /* Let the recover handler know where coreRegs[0] and restore regs */
+    loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace) +
+                            offsetof(HeapArgSpace, coreRegs));
+    genDispatchToHandler(cUnit, TEMPLATE_RESTORE_STATE);
 }
 #endif
 
 /*
+ * Load a Dalvik register into a physical register.  Take care when
+ * using this routine, as it doesn't perform any bookkeeping regarding
+ * register liveness.  That is the responsibility of the caller.
+ */
+static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
+                                int reg1)
+{
+    rlSrc = updateLoc(cUnit, rlSrc);  /* Is our value hiding in a live temp? */
+    if (rlSrc.location == kLocPhysReg) {
+        genRegCopy(cUnit, reg1, rlSrc.lowReg);
+    } else  if (rlSrc.location == kLocRetval) {
+        loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), reg1);
+    } else {
+        assert(rlSrc.location == kLocDalvikFrame);
+        loadWordDisp(cUnit, rFP, sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
+                     reg1);
+    }
+}
+
+/*
+ * Similar to loadValueDirect, but clobbers and allocates the target
+ * register.  Should be used when loading to a fixed register (for example,
+ * loading arguments to an out of line call.
+ */
+static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
+                                 int reg1)
+{
+    clobberReg(cUnit, reg1);
+    markRegInUse(cUnit, reg1);
+    loadValueDirect(cUnit, rlSrc, reg1);
+}
+
+/*
+ * Load a Dalvik register pair into a physical register[s].  Take care when
+ * using this routine, as it doesn't perform any bookkeeping regarding
+ * register liveness.  That is the responsibility of the caller.
+ */
+static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
+                                int regLo, int regHi)
+{
+    rlSrc = updateLocWide(cUnit, rlSrc);
+    if (rlSrc.location == kLocPhysReg) {
+        genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
+    } else if (rlSrc.location == kLocRetval) {
+        loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
+                         regLo, regHi, false, INVALID_SREG);
+    } else {
+        assert(rlSrc.location == kLocDalvikFrame);
+            loadBaseDispWide(cUnit, NULL, rFP,
+                             sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
+                             regLo, regHi, false, INVALID_SREG);
+    }
+}
+
+/*
+ * Similar to loadValueDirect, but clobbers and allocates the target
+ * registers.  Should be used when loading to a fixed registers (for example,
+ * loading arguments to an out of line call.
+ */
+static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
+                                     int regLo, int regHi)
+{
+    clobberReg(cUnit, regLo);
+    clobberReg(cUnit, regHi);
+    markRegInUse(cUnit, regLo);
+    markRegInUse(cUnit, regHi);
+    loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
+}
+
+static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
+                             RegisterClass opKind)
+{
+    RegisterInfo *pReg;
+    rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
+    if (rlSrc.location == kLocDalvikFrame) {
+        loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
+        rlSrc.location = kLocPhysReg;
+        markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
+    } else if (rlSrc.location == kLocRetval) {
+        loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg);
+        rlSrc.location = kLocPhysReg;
+        clobberReg(cUnit, rlSrc.lowReg);
+    }
+    return rlSrc;
+}
+
+static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
+                                 RegisterClass opKind)
+{
+    RegisterInfo *pRegLo;
+    RegisterInfo *pRegHi;
+    assert(rlSrc.wide);
+    rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
+    if (rlSrc.location == kLocDalvikFrame) {
+        loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
+        rlSrc.location = kLocPhysReg;
+        markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
+        markRegLive(cUnit, rlSrc.highReg, hiSReg(rlSrc.sRegLow));
+    } else if (rlSrc.location == kLocRetval) {
+        loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
+                         rlSrc.lowReg, rlSrc.highReg, false, INVALID_SREG);
+        rlSrc.location = kLocPhysReg;
+        clobberReg(cUnit, rlSrc.lowReg);
+        clobberReg(cUnit, rlSrc.highReg);
+    }
+    return rlSrc;
+}
+
+static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
+                       RegLocation rlSrc)
+{
+    RegisterInfo *pRegLo;
+    LIR *defStart;
+    LIR *defEnd;
+    assert(!rlDest.wide);
+    assert(!rlSrc.wide);
+    killNullCheckedLocation(cUnit, rlDest);
+    rlSrc = updateLoc(cUnit, rlSrc);
+    rlDest = updateLoc(cUnit, rlDest);
+    if (rlSrc.location == kLocPhysReg) {
+        if (isLive(cUnit, rlSrc.lowReg) || (rlDest.location == kLocPhysReg)) {
+            // Src is live or Dest has assigned reg.
+            rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
+            genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
+        } else {
+            // Just re-assign the registers.  Dest gets Src's regs
+            rlDest.lowReg = rlSrc.lowReg;
+            clobberReg(cUnit, rlSrc.lowReg);
+        }
+    } else {
+        // Load Src either into promoted Dest or temps allocated for Dest
+        rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
+        loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
+    }
+
+    // Dest is now live and dirty (until/if we flush it to home location)
+    markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
+    markRegDirty(cUnit, rlDest.lowReg);
+
+
+    if (rlDest.location == kLocRetval) {
+        storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval),
+                      rlDest.lowReg, kWord);
+        clobberReg(cUnit, rlDest.lowReg);
+    } else {
+        resetDefLoc(cUnit, rlDest);
+        if (liveOut(cUnit, rlDest.sRegLow)) {
+            defStart = (LIR *)cUnit->lastLIRInsn;
+            int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
+            storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
+            markRegClean(cUnit, rlDest.lowReg);
+            defEnd = (LIR *)cUnit->lastLIRInsn;
+            markDef(cUnit, rlDest, defStart, defEnd);
+        }
+    }
+}
+
+static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
+                       RegLocation rlSrc)
+{
+    RegisterInfo *pRegLo;
+    RegisterInfo *pRegHi;
+    LIR *defStart;
+    LIR *defEnd;
+    bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg);
+    assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
+    assert(rlDest.wide);
+    assert(rlSrc.wide);
+    killNullCheckedLocation(cUnit, rlDest);
+    if (rlSrc.location == kLocPhysReg) {
+        if (isLive(cUnit, rlSrc.lowReg) || isLive(cUnit, rlSrc.highReg) ||
+            (rlDest.location == kLocPhysReg)) {
+            // Src is live or Dest has assigned reg.
+            rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
+            genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
+                           rlSrc.lowReg, rlSrc.highReg);
+        } else {
+            // Just re-assign the registers.  Dest gets Src's regs
+            rlDest.lowReg = rlSrc.lowReg;
+            rlDest.highReg = rlSrc.highReg;
+            clobberReg(cUnit, rlSrc.lowReg);
+            clobberReg(cUnit, rlSrc.highReg);
+        }
+    } else {
+        // Load Src either into promoted Dest or temps allocated for Dest
+        rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
+        loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
+                            rlDest.highReg);
+    }
+
+    // Dest is now live and dirty (until/if we flush it to home location)
+    markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
+    markRegLive(cUnit, rlDest.highReg, hiSReg(rlDest.sRegLow));
+    markRegDirty(cUnit, rlDest.lowReg);
+    markRegDirty(cUnit, rlDest.highReg);
+    markRegPair(cUnit, rlDest.lowReg, rlDest.highReg);
+
+
+    if (rlDest.location == kLocRetval) {
+        storeBaseDispWide(cUnit, rGLUE, offsetof(InterpState, retval),
+                          rlDest.lowReg, rlDest.highReg);
+        clobberReg(cUnit, rlDest.lowReg);
+        clobberReg(cUnit, rlDest.highReg);
+    } else {
+        resetDefLocWide(cUnit, rlDest);
+        if (liveOut(cUnit, rlDest.sRegLow) ||
+            liveOut(cUnit, hiSReg(rlDest.sRegLow))) {
+            defStart = (LIR *)cUnit->lastLIRInsn;
+            int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
+            assert((vReg+1) == sReg2vReg(cUnit, hiSReg(rlDest.sRegLow)));
+            storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
+                              rlDest.highReg);
+            markRegClean(cUnit, rlDest.lowReg);
+            markRegClean(cUnit, rlDest.highReg);
+            defEnd = (LIR *)cUnit->lastLIRInsn;
+            markDefWide(cUnit, rlDest, defStart, defEnd);
+        }
+    }
+}
+
+/*
+ * Load an immediate value into a fixed or temp register.  Target
+ * register is clobbered, and marked inUse.
+ */
+static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
+{
+    if (isTemp(cUnit, rDest)) {
+        clobberReg(cUnit, rDest);
+        markRegInUse(cUnit, rDest);
+    }
+    return loadConstantValue(cUnit, rDest, value);
+}
+
+/*
  * Mark load/store instructions that access Dalvik registers through rFP +
  * offset.
  */
@@ -584,10 +781,10 @@ static void setupResourceMasks(ArmLIR *lir)
         lir->useMask |= ENCODE_REG_PC;
     }
 
-    if (flags & (REG_USE0 | REG_USE1 | REG_USE2)) {
+    if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
         int i;
 
-        for (i = 0; i < 3; i++) {
+        for (i = 0; i < 4; i++) {
             if (flags & (1 << (kRegUse0 + i))) {
                 setupRegMask(&lir->useMask, lir->operands[i]);
             }
@@ -659,6 +856,9 @@ static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
                            int dest, int src1, int src2)
 {
     ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
+    if (!(EncodingMap[opCode].flags & IS_TERTIARY_OP)) {
+        LOGE("Bad LIR3: %s[%d]",EncodingMap[opCode].name,opCode);
+    }
     assert(isPseudoOpCode(opCode) ||
            (EncodingMap[opCode].flags & IS_TERTIARY_OP));
     insn->opCode = opCode;
@@ -688,23 +888,37 @@ static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
 
 /*
  * If the next instruction is a move-result or move-result-long,
- * return the target Dalvik instruction and convert the next to a
- * nop.  Otherwise, return -1.  Used to optimize method inlining.
+ * return the target Dalvik sReg[s] and convert the next to a
+ * nop.  Otherwise, return INVALID_SREG.  Used to optimize method inlining.
  */
-static int inlinedTarget(MIR *mir)
+static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
+                                  bool fpHint)
 {
     if (mir->next &&
         ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
-         (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT) ||
-         (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE))) {
+         (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT))) {
         mir->next->dalvikInsn.opCode = OP_NOP;
-        return mir->next->dalvikInsn.vA;
+        return getDestLoc(cUnit, mir->next, 0);
     } else {
-        return -1;
+        RegLocation res = LOC_DALVIK_RETURN_VAL;
+        res.fp = fpHint;
+        return res;
     }
 }
 
-
+static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
+                                      bool fpHint)
+{
+    if (mir->next &&
+        (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE)) {
+        mir->next->dalvikInsn.opCode = OP_NOP;
+        return getDestLocWide(cUnit, mir->next, 0, 1);
+    } else {
+        RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
+        res.fp = fpHint;
+        return res;
+    }
+}
 
 /*
  * The following are building blocks to insert constants into the pool or
@@ -723,8 +937,8 @@ static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
         return newValue;
     } else {
         /* Add the constant in the middle of code stream */
-        newLIR1(cUnit, ARM_16BIT_DATA, (value & 0xffff));
-        newLIR1(cUnit, ARM_16BIT_DATA, (value >> 16));
+        newLIR1(cUnit, kArm16BitData, (value & 0xffff));
+        newLIR1(cUnit, kArm16BitData, (value >> 16));
     }
     return NULL;
 }
@@ -746,38 +960,6 @@ static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
     return NULL;
 }
 
-/*
- * Generate an ARM_PSEUDO_BARRIER marker to indicate the boundary of special
- * blocks.
- */
-static void genBarrier(CompilationUnit *cUnit)
-{
-    ArmLIR *barrier = newLIR0(cUnit, ARM_PSEUDO_BARRIER);
-    /* Mark all resources as being clobbered */
-    barrier->defMask = -1;
-}
-
-/* Perform the actual operation for OP_RETURN_* */
-static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
-{
-    genDispatchToHandler(cUnit, TEMPLATE_RETURN);
-#if defined(INVOKE_STATS)
-    gDvmJit.returnOp++;
-#endif
-    int dPC = (int) (cUnit->method->insns + mir->offset);
-    /* Insert branch, but defer setting of target */
-    ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
-    /* Set up the place holder to reconstruct this Dalvik PC */
-    ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
-    pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
-    pcrLabel->operands[0] = dPC;
-    pcrLabel->operands[1] = mir->offset;
-    /* Insert the place holder to the growable list */
-    dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
-    /* Branch to the PC reconstruction code */
-    branch->generic.target = (LIR *) pcrLabel;
-}
-
 /* Create the PC reconstruction slot if not already done */
 static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
                                          ArmLIR *branch,
@@ -787,7 +969,7 @@ static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
     if (pcrLabel == NULL) {
         int dPC = (int) (cUnit->method->insns + dOffset);
         pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
-        pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
+        pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
         pcrLabel->operands[0] = dPC;
         pcrLabel->operands[1] = dOffset;
         /* Insert the place holder to the growable list */
@@ -809,26 +991,26 @@ static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
                                      ArmLIR *pcrLabel)
 {
     ArmLIR *res;
-    res = opRegReg(cUnit, OP_CMP, reg1, reg2);
+    res = opRegReg(cUnit, kOpCmp, reg1, reg2);
     ArmLIR *branch = opCondBranch(cUnit, cond);
     genCheckCommon(cUnit, dOffset, branch, pcrLabel);
     return res;
 }
 
 /*
- * Perform null-check on a register. vReg is the Dalvik register being checked,
+ * Perform null-check on a register. sReg is the ssa register being checked,
  * and mReg is the machine register holding the actual value. If internal state
- * indicates that vReg has been checked before the check request is ignored.
+ * indicates that sReg has been checked before the check request is ignored.
  */
-static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
+static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
                                 int dOffset, ArmLIR *pcrLabel)
 {
     /* This particular Dalvik register has been null-checked */
-    if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
+    if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
         return pcrLabel;
     }
-    dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
-    return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
+    dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
+    return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
 }
 
 /*
@@ -838,14 +1020,14 @@ static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
 static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
                                 int dOffset, ArmLIR *pcrLabel)
 {
-    return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
+    return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
 }
 
 /* Perform bound check on two registers */
 static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
                                   int rBound, int dOffset, ArmLIR *pcrLabel)
 {
-    return genRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
+    return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
                             pcrLabel);
 }
 
@@ -853,7 +1035,7 @@ static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
 static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
                                   ArmLIR *pcrLabel)
 {
-    ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
+    ArmLIR *branch = opNone(cUnit, kOpUncondBr);
     return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
 }
 
@@ -861,66 +1043,50 @@ static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
 static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
 {
     DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int reg0, reg1, reg2, reg3;
-
-    /* Allocate reg0..reg3 into physical registers r0..r3 */
-
-    /* See if vB is in a native register. If so, reuse it. */
-    reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
-    /* Ping reg3 to the other register of the same pair containing reg2 */
-    reg3 = reg2 ^ 0x1;
-    /*
-     * Ping reg0 to the first register of the alternate register pair
-     */
-    reg0 = (reg2 + 2) & 0xa;
-    reg1 = NEXT_REG(reg0);
-
-    loadValue(cUnit, dInsn->vB, reg2);
-    loadConstant(cUnit, reg3, fieldOffset);
-    genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
-    opRegReg(cUnit, OP_ADD, reg2, reg3);
+    RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
+    RegLocation rlResult;
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    int regPtr = allocTemp(cUnit);
+
+    assert(rlDest.wide);
+
+    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+                 NULL);/* null object? */
+    opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
+    rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
 #if !defined(WITH_SELF_VERIFICATION)
-    loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
+    loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
 #else
-    int regMap = reg1 << 8 | reg0 << 4 | reg2;
+    int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
     selfVerificationMemOpWrapper(cUnit, regMap,
         &selfVerificationLoadDoubleword);
 #endif
-    storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
+    freeTemp(cUnit, regPtr);
+    storeValueWide(cUnit, rlDest, rlResult);
 }
 
 /* Store a wide field to an object instance */
 static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
 {
     DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int reg0, reg1, reg2, reg3;
-
-    /* Allocate reg0..reg3 into physical registers r0..r3 */
-
-    /* See if vB is in a native register. If so, reuse it. */
-    reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
-    /* Ping reg3 to the other register of the same pair containing reg2 */
-    reg3 = reg2 ^ 0x1;
-    /*
-     * Ping reg0 to the first register of the alternate register pair
-     */
-    reg0 = (reg2 + 2) & 0xa;
-    reg1 = NEXT_REG(reg0);
-
-
-    loadValue(cUnit, dInsn->vB, reg2);
-    loadValuePair(cUnit, dInsn->vA, reg0, reg1);
-    updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
-    loadConstant(cUnit, reg3, fieldOffset);
-    genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
-    opRegReg(cUnit, OP_ADD, reg2, reg3);
+    RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+    RegLocation rlObj = getSrcLoc(cUnit, mir, 2);
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    int regPtr;
+    rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+                 NULL);/* null object? */
+    regPtr = allocTemp(cUnit);
+    opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
 #if !defined(WITH_SELF_VERIFICATION)
-    storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
+    storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
 #else
-    int regMap = reg1 << 8 | reg0 << 4 | reg2;
+    int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
     selfVerificationMemOpWrapper(cUnit, regMap,
         &selfVerificationStoreDoubleword);
 #endif
+    freeTemp(cUnit, regPtr);
 }
 
 /*
@@ -930,24 +1096,28 @@ static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
 static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
                     int fieldOffset)
 {
+    int regPtr;
+    RegLocation rlResult;
     DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int reg0, reg1;
-
-    reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
-    reg1 = NEXT_REG(reg0);
-    loadValue(cUnit, dInsn->vB, reg0);
+    RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlDest = getDestLoc(cUnit, mir, 0);
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
 #if !defined(WITH_SELF_VERIFICATION)
-    loadBaseDisp(cUnit, mir, reg0, fieldOffset, reg1, size, true, dInsn->vB);
+    loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
+                 size, true, rlObj.sRegLow);
 #else
-    genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
+    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+                 NULL);/* null object? */
     /* Combine address and offset */
-    loadConstant(cUnit, reg1, fieldOffset);
-    opRegReg(cUnit, OP_ADD, reg0, reg1);
+    regPtr = allocTemp(cUnit);
+    opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
 
-    int regMap = reg1 << 4 | reg0;
+    int regMap = rlResult.lowReg << 8 | regPtr;
     selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
+    freeTemp(cUnit, regPtr);
 #endif
-    storeValue(cUnit, reg1, dInsn->vA, reg0);
+    storeValue(cUnit, rlDest, rlResult);
 }
 
 /*
@@ -958,101 +1128,105 @@ static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
                     int fieldOffset)
 {
     DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int reg0, reg1, reg2;
-
-    reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
-    reg1 = NEXT_REG(reg0);
-    reg2 = NEXT_REG(reg1);
-
-    loadValue(cUnit, dInsn->vB, reg0);
-    loadValue(cUnit, dInsn->vA, reg2);
-    updateLiveRegister(cUnit, dInsn->vA, reg2);
-    genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
+    RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlObj = getSrcLoc(cUnit, mir, 1);
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+    int regPtr;
+    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+                 NULL);/* null object? */
 #if !defined(WITH_SELF_VERIFICATION)
-    storeBaseDisp(cUnit, reg0, fieldOffset, reg2, size, reg1);
+    storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
 #else
     /* Combine address and offset */
-    loadConstant(cUnit, reg1, fieldOffset);
-    opRegReg(cUnit, OP_ADD, reg0, reg1);
+    regPtr = allocTemp(cUnit);
+    opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
 
-    int regMap = reg2 << 4 | reg0;
+    int regMap = rlSrc.lowReg << 8 | regPtr;
     selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
-
-    opRegReg(cUnit, OP_SUB, reg0, reg1);
 #endif
 }
 
 
 /*
  * Generate array load
- *
  */
 static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
-                        int vArray, int vIndex, int vDest, int scale)
+                        RegLocation rlArray, RegLocation rlIndex,
+                        RegLocation rlDest, int scale)
 {
     int lenOffset = offsetof(ArrayObject, length);
     int dataOffset = offsetof(ArrayObject, contents);
-    int reg0, reg1, reg2, reg3;
-
-    reg0 = selectFirstRegister(cUnit, vArray,
-                               (size == LONG) || (size == DOUBLE));
-    reg1 = NEXT_REG(reg0);
-    reg2 = NEXT_REG(reg1);
-    reg3 = NEXT_REG(reg2);
-
-    loadValue(cUnit, vArray, reg2);
-    loadValue(cUnit, vIndex, reg3);
+    RegLocation rlResult;
+    rlArray = loadValue(cUnit, rlArray, kCoreReg);
+    rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
+    int regPtr;
 
     /* null object? */
     ArmLIR * pcrLabel = NULL;
 
     if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
-        pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
+        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
+                                rlArray.lowReg, mir->offset, NULL);
     }
 
+    regPtr = allocTemp(cUnit);
+
     if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+        int regLen = allocTemp(cUnit);
         /* Get len */
-        loadWordDisp(cUnit, reg2, lenOffset, reg0);
-        /* reg2 -> array data */
-        opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
-        genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
+        loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
+        /* regPtr -> array data */
+        opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
+        genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
+                       pcrLabel);
+        freeTemp(cUnit, regLen);
     } else {
-        /* reg2 -> array data */
-        opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
+        /* regPtr -> array data */
+        opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
     }
 #if !defined(WITH_SELF_VERIFICATION)
-    if ((size == LONG) || (size == DOUBLE)) {
-        //TUNING: redo.  Make specific wide routine, perhaps use ldmia/fp regs
-        opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
-        loadBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
-        opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
-        loadBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
-        storeValuePair(cUnit, reg0, reg1, vDest, reg3);
+    if ((size == kLong) || (size == kDouble)) {
+        if (scale) {
+            int rNewIndex = allocTemp(cUnit);
+            opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
+            opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
+            freeTemp(cUnit, rNewIndex);
+        } else {
+            opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
+        }
+        rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
+        loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
+        freeTemp(cUnit, regPtr);
+        storeValueWide(cUnit, rlDest, rlResult);
     } else {
-        loadBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
-        storeValue(cUnit, reg0, vDest, reg3);
+        rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
+        loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
+                        scale, size);
+        freeTemp(cUnit, regPtr);
+        storeValue(cUnit, rlDest, rlResult);
     }
 #else
     //TODO: probably want to move this into loadBaseIndexed
     void *funct = NULL;
     switch(size) {
-        case LONG:
-        case DOUBLE:
+        case kLong:
+        case kDouble:
             funct = (void*) &selfVerificationLoadDoubleword;
             break;
-        case WORD:
+        case kWord:
             funct = (void*) &selfVerificationLoad;
             break;
-        case UNSIGNED_HALF:
+        case kUnsignedHalf:
             funct = (void*) &selfVerificationLoadHalfword;
             break;
-        case SIGNED_HALF:
+        case kSignedHalf:
             funct = (void*) &selfVerificationLoadSignedHalfword;
             break;
-        case UNSIGNED_BYTE:
+        case kUnsignedByte:
             funct = (void*) &selfVerificationLoadByte;
             break;
-        case SIGNED_BYTE:
+        case kSignedByte:
             funct = (void*) &selfVerificationLoadSignedByte;
             break;
         default:
@@ -1060,19 +1234,24 @@ static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
             dvmAbort();
     }
     /* Combine address and index */
-    if (scale)
-        opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
-    opRegReg(cUnit, OP_ADD, reg2, reg3);
+    if (scale) {
+        int regTmp = allocTemp(cUnit);
+        opRegRegImm(cUnit, kOpLsl, regTmp, rlIndex.lowReg, scale);
+        opRegReg(cUnit, kOpAdd, regPtr, regTmp);
+        freeTemp(cUnit, regTmp);
+    } else {
+        opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
+    }
 
-    int regMap = reg1 << 8 | reg0 << 4 | reg2;
+    rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
+    int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
     selfVerificationMemOpWrapper(cUnit, regMap, funct);
 
-    opRegReg(cUnit, OP_SUB, reg2, reg3);
-
-    if ((size == LONG) || (size == DOUBLE))
-        storeValuePair(cUnit, reg0, reg1, vDest, reg3);
+    freeTemp(cUnit, regPtr);
+    if ((size == kLong) || (size == kDouble))
+        storeValueWide(cUnit, rlDest, rlResult);
     else
-        storeValue(cUnit, reg0, vDest, reg3);
+        storeValue(cUnit, rlDest, rlResult);
 #endif
 }
 
@@ -1081,72 +1260,83 @@ static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
  *
  */
 static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
-                        int vArray, int vIndex, int vSrc, int scale)
+                        RegLocation rlArray, RegLocation rlIndex,
+                        RegLocation rlSrc, int scale)
 {
     int lenOffset = offsetof(ArrayObject, length);
     int dataOffset = offsetof(ArrayObject, contents);
-    int reg0, reg1, reg2, reg3;
 
-    reg0 = selectFirstRegister(cUnit, vArray,
-                               (size == LONG) || (size == DOUBLE));
-    reg1 = NEXT_REG(reg0);
-    reg2 = NEXT_REG(reg1);
-    reg3 = NEXT_REG(reg2);
+    int regPtr;
+    rlArray = loadValue(cUnit, rlArray, kCoreReg);
+    rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
 
-    loadValue(cUnit, vArray, reg2);
-    loadValue(cUnit, vIndex, reg3);
+    if (isTemp(cUnit, rlArray.lowReg)) {
+        clobberReg(cUnit, rlArray.lowReg);
+        regPtr = rlArray.lowReg;
+    } else {
+        regPtr = allocTemp(cUnit);
+        genRegCopy(cUnit, regPtr, rlArray.lowReg);
+    }
 
     /* null object? */
     ArmLIR * pcrLabel = NULL;
 
     if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
-        pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
+        pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
+                                mir->offset, NULL);
     }
 
     if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
+        int regLen = allocTemp(cUnit);
+        //NOTE: max live temps(4) here.
         /* Get len */
-        loadWordDisp(cUnit, reg2, lenOffset, reg0);
-        /* reg2 -> array data */
-        opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
-        genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
+        loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
+        /* regPtr -> array data */
+        opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
+        genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
+                       pcrLabel);
+        freeTemp(cUnit, regLen);
     } else {
-        /* reg2 -> array data */
-        opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
+        /* regPtr -> array data */
+        opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
     }
-
-    /* at this point, reg2 points to array, reg3 is unscaled index */
+    /* at this point, regPtr points to array, 2 live temps */
 #if !defined(WITH_SELF_VERIFICATION)
-    if ((size == LONG) || (size == DOUBLE)) {
-        //TUNING: redo.  Make specific wide routine, perhaps use ldmia/fp regs
-        loadValuePair(cUnit, vSrc, reg0, reg1);
-        updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
-        if (scale)
-            opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
-        storeBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
-        opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
-        storeBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
+    if ((size == kLong) || (size == kDouble)) {
+        //TODO: need specific wide routine that can handle fp regs
+        if (scale) {
+            int rNewIndex = allocTemp(cUnit);
+            opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
+            opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
+            freeTemp(cUnit, rNewIndex);
+        } else {
+            opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
+        }
+        rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+        storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
+        freeTemp(cUnit, regPtr);
     } else {
-        loadValue(cUnit, vSrc, reg0);
-        updateLiveRegister(cUnit, vSrc, reg0);
-        storeBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
+        rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+        storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
+                         scale, size);
     }
 #else
     //TODO: probably want to move this into storeBaseIndexed
     void *funct = NULL;
     switch(size) {
-        case LONG:
-        case DOUBLE:
+        case kLong:
+        case kDouble:
             funct = (void*) &selfVerificationStoreDoubleword;
             break;
-        case WORD:
+        case kWord:
             funct = (void*) &selfVerificationStore;
             break;
-        case SIGNED_HALF:
-        case UNSIGNED_HALF:
+        case kSignedHalf:
+        case kUnsignedHalf:
             funct = (void*) &selfVerificationStoreHalfword;
             break;
-        case SIGNED_BYTE:
-        case UNSIGNED_BYTE:
+        case kSignedByte:
+        case kUnsignedByte:
             funct = (void*) &selfVerificationStoreByte;
             break;
         default:
@@ -1154,34 +1344,40 @@ static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
             dvmAbort();
     }
 
+    if (scale) {
+        int regTmpIndex = allocTemp(cUnit);
+        // 3 live temps
+        opRegRegImm(cUnit, kOpLsl, regTmpIndex, rlIndex.lowReg, scale);
+        opRegReg(cUnit, kOpAdd, regPtr, regTmpIndex);
+        freeTemp(cUnit, regTmpIndex);
+    } else {
+        opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
+    }
     /* Combine address and index */
-    if ((size == LONG) || (size == DOUBLE)) {
-        loadValuePair(cUnit, vSrc, reg0, reg1);
-        updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
+    if ((size == kLong) || (size == kDouble)) {
+        rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
     } else {
-        loadValue(cUnit, vSrc, reg0);
-        updateLiveRegister(cUnit, vSrc, reg0);
+        rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
     }
-    if (scale)
-        opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
-    opRegReg(cUnit, OP_ADD, reg2, reg3);
 
-    int regMap = reg1 << 8 | reg0 << 4 | reg2;
+    int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
     selfVerificationMemOpWrapper(cUnit, regMap, funct);
 
-    opRegReg(cUnit, OP_SUB, reg2, reg3);
 #endif
 }
 
-static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
-                           int vSrc1, int vShift)
+static bool handleShiftOpLong(CompilationUnit *cUnit, MIR *mir,
+                              RegLocation rlDest, RegLocation rlSrc1,
+                              RegLocation rlShift)
 {
     /*
      * Don't mess with the regsiters here as there is a particular calling
      * convention to the out-of-line handler.
      */
-    loadValue(cUnit, vShift, r2);
-    loadValuePair(cUnit, vSrc1, r0, r1);
+    RegLocation rlResult;
+
+    loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+    loadValueDirect(cUnit, rlShift, r2);
     switch( mir->dalvikInsn.opCode) {
         case OP_SHL_LONG:
         case OP_SHL_LONG_2ADDR:
@@ -1198,18 +1394,16 @@ static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
         default:
             return true;
     }
-    storeValuePair(cUnit, r0, r1, vDest, r2);
+    rlResult = getReturnLocWide(cUnit);
+    storeValueWide(cUnit, rlDest, rlResult);
     return false;
 }
-bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
-                             int vDest, int vSrc1, int vSrc2)
+bool handleArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+                                RegLocation rlDest, RegLocation rlSrc1,
+                                RegLocation rlSrc2)
 {
-    /*
-     * Don't optimize the regsiter usage here as they are governed by the EABI
-     * calling convention.
-     */
+    RegLocation rlResult;
     void* funct;
-    int reg0, reg1;
 
     /* TODO: use a proper include file to define these */
     float __aeabi_fadd(float a, float b);
@@ -1218,9 +1412,6 @@ bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
     float __aeabi_fmul(float a, float b);
     float fmodf(float a, float b);
 
-    reg0 = selectFirstRegister(cUnit, vSrc2, false);
-    reg1 = NEXT_REG(reg0);
-
     switch (mir->dalvikInsn.opCode) {
         case OP_ADD_FLOAT_2ADDR:
         case OP_ADD_FLOAT:
@@ -1243,27 +1434,28 @@ bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
             funct = (void*) fmodf;
             break;
         case OP_NEG_FLOAT: {
-            loadValue(cUnit, vSrc2, reg0);
-            opRegImm(cUnit, OP_ADD, reg0, 0x80000000, reg1);
-            storeValue(cUnit, reg0, vDest, reg1);
+            genNegFloat(cUnit, rlDest, rlSrc1);
             return false;
         }
         default:
             return true;
     }
+    loadValueDirectFixed(cUnit, rlSrc1, r0);
+    loadValueDirectFixed(cUnit, rlSrc2, r1);
     loadConstant(cUnit, r2, (int)funct);
-    loadValue(cUnit, vSrc1, r0);
-    loadValue(cUnit, vSrc2, r1);
-    opReg(cUnit, OP_BLX, r2);
-    storeValue(cUnit, r0, vDest, r1);
+    opReg(cUnit, kOpBlx, r2);
+    clobberCallRegs(cUnit);
+    rlResult = getReturnLoc(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
     return false;
 }
 
-bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
-                              int vDest, int vSrc1, int vSrc2)
+bool handleArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+                                 RegLocation rlDest, RegLocation rlSrc1,
+                                 RegLocation rlSrc2)
 {
+    RegLocation rlResult;
     void* funct;
-    int reg0, reg1, reg2;
 
     /* TODO: use a proper include file to define these */
     double __aeabi_dadd(double a, double b);
@@ -1272,10 +1464,6 @@ bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
     double __aeabi_dmul(double a, double b);
     double fmod(double a, double b);
 
-    reg0 = selectFirstRegister(cUnit, vSrc2, true);
-    reg1 = NEXT_REG(reg0);
-    reg2 = NEXT_REG(reg1);
-
     switch (mir->dalvikInsn.opCode) {
         case OP_ADD_DOUBLE_2ADDR:
         case OP_ADD_DOUBLE:
@@ -1298,61 +1486,58 @@ bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
             funct = (void*) fmod;
             break;
         case OP_NEG_DOUBLE: {
-            loadValuePair(cUnit, vSrc2, reg0, reg1);
-            opRegImm(cUnit, OP_ADD, reg1, 0x80000000, reg2);
-            storeValuePair(cUnit, reg0, reg1, vDest, reg2);
+            genNegDouble(cUnit, rlDest, rlSrc1);
             return false;
         }
         default:
             return true;
     }
-    /*
-     * Don't optimize the regsiter usage here as they are governed by the EABI
-     * calling convention.
-     */
-    loadConstant(cUnit, r4PC, (int)funct);
-    loadValuePair(cUnit, vSrc1, r0, r1);
-    loadValuePair(cUnit, vSrc2, r2, r3);
-    opReg(cUnit, OP_BLX, r4PC);
-    storeValuePair(cUnit, r0, r1, vDest, r2);
+    loadConstant(cUnit, rlr, (int)funct);
+    loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+    loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+    opReg(cUnit, kOpBlx, rlr);
+    clobberCallRegs(cUnit);
+    rlResult = getReturnLocWide(cUnit);
+    storeValueWide(cUnit, rlDest, rlResult);
     return false;
 }
 
-static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
-                           int vSrc1, int vSrc2)
+static bool handleArithOpLong(CompilationUnit *cUnit, MIR *mir,
+                              RegLocation rlDest, RegLocation rlSrc1,
+                              RegLocation rlSrc2)
 {
-    OpKind firstOp = OP_BKPT;
-    OpKind secondOp = OP_BKPT;
+    RegLocation rlResult;
+    OpKind firstOp = kOpBkpt;
+    OpKind secondOp = kOpBkpt;
     bool callOut = false;
     void *callTgt;
     int retReg = r0;
-    int reg0, reg1, reg2, reg3;
     /* TODO - find proper .h file to declare these */
     long long __aeabi_ldivmod(long long op1, long long op2);
 
     switch (mir->dalvikInsn.opCode) {
         case OP_NOT_LONG:
-            firstOp = OP_MVN;
-            secondOp = OP_MVN;
+            rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
+            opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
+            storeValueWide(cUnit, rlDest, rlResult);
+            return false;
             break;
         case OP_ADD_LONG:
         case OP_ADD_LONG_2ADDR:
-            firstOp = OP_ADD;
-            secondOp = OP_ADC;
+            firstOp = kOpAdd;
+            secondOp = kOpAdc;
             break;
         case OP_SUB_LONG:
         case OP_SUB_LONG_2ADDR:
-            firstOp = OP_SUB;
-            secondOp = OP_SBC;
+            firstOp = kOpSub;
+            secondOp = kOpSbc;
             break;
         case OP_MUL_LONG:
         case OP_MUL_LONG_2ADDR:
-            loadValuePair(cUnit, vSrc1, r0, r1);
-            loadValuePair(cUnit, vSrc2, r2, r3);
-            genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
-            storeValuePair(cUnit, r0, r1, vDest, r2);
+            genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
             return false;
-            break;
         case OP_DIV_LONG:
         case OP_DIV_LONG_2ADDR:
             callOut = true;
@@ -1366,32 +1551,29 @@ static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
             callTgt = (void*)__aeabi_ldivmod;
             retReg = r2;
             break;
-        case OP_AND_LONG:
         case OP_AND_LONG_2ADDR:
-            firstOp = OP_AND;
-            secondOp = OP_AND;
+        case OP_AND_LONG:
+            firstOp = kOpAnd;
+            secondOp = kOpAnd;
             break;
         case OP_OR_LONG:
         case OP_OR_LONG_2ADDR:
-            firstOp = OP_OR;
-            secondOp = OP_OR;
+            firstOp = kOpOr;
+            secondOp = kOpOr;
             break;
         case OP_XOR_LONG:
         case OP_XOR_LONG_2ADDR:
-            firstOp = OP_XOR;
-            secondOp = OP_XOR;
+            firstOp = kOpXor;
+            secondOp = kOpXor;
             break;
         case OP_NEG_LONG: {
-            reg0 = selectFirstRegister(cUnit, vSrc2, true);
-            reg1 = NEXT_REG(reg0);
-            reg2 = NEXT_REG(reg1);
-            reg3 = NEXT_REG(reg2);
-
-            loadValuePair(cUnit, vSrc2, reg0, reg1);
-            loadConstant(cUnit, reg3, 0);
-            opRegRegReg(cUnit, OP_SUB, reg2, reg3, reg0);
-            opRegReg(cUnit, OP_SBC, reg3, reg1);
-            storeValuePair(cUnit, reg2, reg3, vDest, reg0);
+            rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            loadConstantValue(cUnit, rlResult.highReg, 0);
+            opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
+                        rlResult.highReg, rlSrc2.lowReg);
+            opRegReg(cUnit, kOpSbc, rlResult.highReg, rlSrc2.highReg);
+            storeValueWide(cUnit, rlDest, rlResult);
             return false;
         }
         default:
@@ -1399,40 +1581,34 @@ static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
             dvmAbort();
     }
     if (!callOut) {
-        reg0 = selectFirstRegister(cUnit, vSrc1, true);
-        reg1 = NEXT_REG(reg0);
-        reg2 = NEXT_REG(reg1);
-        reg3 = NEXT_REG(reg2);
-
-        loadValuePair(cUnit, vSrc1, reg0, reg1);
-        loadValuePair(cUnit, vSrc2, reg2, reg3);
-        opRegReg(cUnit, firstOp, reg0, reg2);
-        opRegReg(cUnit, secondOp, reg1, reg3);
-        storeValuePair(cUnit, reg0, reg1, vDest, reg2);
-    /*
-     * Don't optimize the register usage here as they are governed by the EABI
-     * calling convention.
-     */
+        genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
     } else {
-        loadValuePair(cUnit, vSrc2, r2, r3);
-        loadConstant(cUnit, r4PC, (int) callTgt);
-        loadValuePair(cUnit, vSrc1, r0, r1);
-        opReg(cUnit, OP_BLX, r4PC);
-        storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
+        // Adjust return regs in to handle case of rem returning r2/r3
+        loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+        loadConstant(cUnit, rlr, (int) callTgt);
+        loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+        opReg(cUnit, kOpBlx, rlr);
+        clobberCallRegs(cUnit);
+        if (retReg == r0)
+            rlResult = getReturnLocWide(cUnit);
+        else
+            rlResult = getReturnLocWideAlt(cUnit);
+        storeValueWide(cUnit, rlDest, rlResult);
     }
     return false;
 }
 
-static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
-                          int vSrc1, int vSrc2)
+static bool handleArithOpInt(CompilationUnit *cUnit, MIR *mir,
+                             RegLocation rlDest, RegLocation rlSrc1,
+                             RegLocation rlSrc2)
 {
-    OpKind op = OP_BKPT;
+    OpKind op = kOpBkpt;
     bool callOut = false;
     bool checkZero = false;
-    bool threeOperand = false;
+    bool unary = false;
     int retReg = r0;
     void *callTgt;
-    int reg0, reg1, regDest;
+    RegLocation rlResult;
 
     /* TODO - find proper .h file to declare these */
     int __aeabi_idivmod(int op1, int op2);
@@ -1440,24 +1616,24 @@ static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
 
     switch (mir->dalvikInsn.opCode) {
         case OP_NEG_INT:
-            op = OP_NEG;
+            op = kOpNeg;
+            unary = true;
             break;
         case OP_NOT_INT:
-            op = OP_MVN;
+            op = kOpMvn;
+            unary = true;
             break;
         case OP_ADD_INT:
         case OP_ADD_INT_2ADDR:
-            op = OP_ADD;
-            threeOperand = true;
+            op = kOpAdd;
             break;
         case OP_SUB_INT:
         case OP_SUB_INT_2ADDR:
-            op = OP_SUB;
-            threeOperand = true;
+            op = kOpSub;
             break;
         case OP_MUL_INT:
         case OP_MUL_INT_2ADDR:
-            op = OP_MUL;
+            op = kOpMul;
             break;
         case OP_DIV_INT:
         case OP_DIV_INT_2ADDR:
@@ -1476,27 +1652,27 @@ static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
             break;
         case OP_AND_INT:
         case OP_AND_INT_2ADDR:
-            op = OP_AND;
+            op = kOpAnd;
             break;
         case OP_OR_INT:
         case OP_OR_INT_2ADDR:
-            op = OP_OR;
+            op = kOpOr;
             break;
         case OP_XOR_INT:
         case OP_XOR_INT_2ADDR:
-            op = OP_XOR;
+            op = kOpXor;
             break;
         case OP_SHL_INT:
         case OP_SHL_INT_2ADDR:
-            op = OP_LSL;
+            op = kOpLsl;
             break;
         case OP_SHR_INT:
         case OP_SHR_INT_2ADDR:
-            op = OP_ASR;
+            op = kOpAsr;
             break;
         case OP_USHR_INT:
         case OP_USHR_INT_2ADDR:
-            op = OP_LSR;
+            op = kOpLsr;
             break;
         default:
             LOGE("Invalid word arith op: 0x%x(%d)",
@@ -1504,105 +1680,145 @@ static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
             dvmAbort();
     }
     if (!callOut) {
-         /* Try to allocate reg0 to the currently cached source operand  */
-        if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
-            reg0 = selectFirstRegister(cUnit, vSrc1, false);
-            reg1 = NEXT_REG(reg0);
-            regDest = NEXT_REG(reg1);
-
-            loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
-            loadValue(cUnit, vSrc2, reg1);
-            if (threeOperand) {
-                opRegRegReg(cUnit, op, regDest, reg0, reg1);
-                storeValue(cUnit, regDest, vDest, reg1);
-            } else {
-                opRegReg(cUnit, op, reg0, reg1);
-                storeValue(cUnit, reg0, vDest, reg1);
-            }
+        rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+        if (unary) {
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegReg(cUnit, op, rlResult.lowReg,
+                     rlSrc1.lowReg);
         } else {
-            reg0 = selectFirstRegister(cUnit, vSrc2, false);
-            reg1 = NEXT_REG(reg0);
-            regDest = NEXT_REG(reg1);
-
-            loadValue(cUnit, vSrc1, reg1); /* Load this value first */
-            loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
-            if (threeOperand) {
-                opRegRegReg(cUnit, op, regDest, reg1, reg0);
-                storeValue(cUnit, regDest, vDest, reg1);
-            } else {
-                opRegReg(cUnit, op, reg1, reg0);
-                storeValue(cUnit, reg1, vDest, reg0);
-            }
+            rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegRegReg(cUnit, op, rlResult.lowReg,
+                        rlSrc1.lowReg, rlSrc2.lowReg);
         }
+        storeValue(cUnit, rlDest, rlResult);
     } else {
-        /*
-         * Load the callout target first since it will never be eliminated
-         * and its value will be used first.
-         */
+        RegLocation rlResult;
+        loadValueDirectFixed(cUnit, rlSrc2, r1);
         loadConstant(cUnit, r2, (int) callTgt);
-        /*
-         * Load vSrc2 first if it is not cached in a native register or it
-         * is in r0 which will be clobbered if vSrc1 is loaded first.
-         */
-        if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
-            cUnit->registerScoreboard.nativeReg == r0) {
-            /* Cannot be optimized and won't clobber r0 */
-            loadValue(cUnit, vSrc2, r1);
-            /* May be optimized if vSrc1 is cached */
-            loadValue(cUnit, vSrc1, r0);
-        } else {
-            loadValue(cUnit, vSrc1, r0);
-            loadValue(cUnit, vSrc2, r1);
-        }
+        loadValueDirectFixed(cUnit, rlSrc1, r0);
         if (checkZero) {
-            genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
+            genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
         }
-        opReg(cUnit, OP_BLX, r2);
-        storeValue(cUnit, retReg, vDest, r2);
+        opReg(cUnit, kOpBlx, r2);
+        clobberCallRegs(cUnit);
+        if (retReg == r0)
+            rlResult = getReturnLoc(cUnit);
+        else
+            rlResult = getReturnLocAlt(cUnit);
+        storeValue(cUnit, rlDest, rlResult);
     }
     return false;
 }
 
-static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
+static bool handleArithOp(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode opCode = mir->dalvikInsn.opCode;
-    int vA = mir->dalvikInsn.vA;
-    int vB = mir->dalvikInsn.vB;
-    int vC = mir->dalvikInsn.vC;
+    RegLocation rlDest;
+    RegLocation rlSrc1;
+    RegLocation rlSrc2;
+    /* Deduce sizes of operands */
+    if (mir->ssaRep->numUses == 2) {
+        rlSrc1 = getSrcLoc(cUnit, mir, 0);
+        rlSrc2 = getSrcLoc(cUnit, mir, 1);
+    } else if (mir->ssaRep->numUses == 3) {
+        rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
+        rlSrc2 = getSrcLoc(cUnit, mir, 2);
+    } else {
+        rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
+        rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
+        assert(mir->ssaRep->numUses == 4);
+    }
+    if (mir->ssaRep->numDefs == 1) {
+        rlDest = getDestLoc(cUnit, mir, 0);
+    } else {
+        assert(mir->ssaRep->numDefs == 2);
+        rlDest = getDestLocWide(cUnit, mir, 0, 1);
+    }
 
     if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
-        return genArithOpLong(cUnit,mir, vA, vA, vB);
+        return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
     }
     if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
-        return genArithOpLong(cUnit,mir, vA, vB, vC);
+        return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
     }
     if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
-        return genShiftOpLong(cUnit,mir, vA, vA, vB);
+        return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
     }
     if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
-        return genShiftOpLong(cUnit,mir, vA, vB, vC);
+        return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
     }
     if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
-        return genArithOpInt(cUnit,mir, vA, vA, vB);
+        return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
     }
     if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
-        return genArithOpInt(cUnit,mir, vA, vB, vC);
+        return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
     }
     if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
-        return genArithOpFloat(cUnit,mir, vA, vA, vB);
+        return handleArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
     }
     if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
-        return genArithOpFloat(cUnit, mir, vA, vB, vC);
+        return handleArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
     }
     if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
-        return genArithOpDouble(cUnit,mir, vA, vA, vB);
+        return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
     }
     if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
-        return genArithOpDouble(cUnit,mir, vA, vB, vC);
+        return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
     }
     return true;
 }
 
+/* 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;
+}
+
+/*
+ * Generate an kArmPseudoBarrier marker to indicate the boundary of special
+ * blocks.
+ */
+static void genBarrier(CompilationUnit *cUnit)
+{
+    ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
+    /* Mark all resources as being clobbered */
+    barrier->defMask = -1;
+}
+
+/* Perform the actual operation for OP_RETURN_* */
+static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
+{
+    genDispatchToHandler(cUnit, TEMPLATE_RETURN);
+#if defined(INVOKE_STATS)
+    gDvmJit.returnOp++;
+#endif
+    int dPC = (int) (cUnit->method->insns + mir->offset);
+    /* Insert branch, but defer setting of target */
+    ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
+    /* Set up the place holder to reconstruct this Dalvik PC */
+    ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
+    pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
+    pcrLabel->operands[0] = dPC;
+    pcrLabel->operands[1] = mir->offset;
+    /* Insert the place holder to the growable list */
+    dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
+    /* Branch to the PC reconstruction code */
+    branch->generic.target = (LIR *) pcrLabel;
+}
+
 static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
                                      int srcSize, int tgtSize)
 {
@@ -1610,17 +1826,28 @@ static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
      * Don't optimize the register usage since it calls out to template
      * functions
      */
-    loadConstant(cUnit, r2, (int)funct);
+    RegLocation rlSrc;
+    RegLocation rlDest;
     if (srcSize == 1) {
-        loadValue(cUnit, mir->dalvikInsn.vB, r0);
+        rlSrc = getSrcLoc(cUnit, mir, 0);
+        loadValueDirectFixed(cUnit, rlSrc, r0);
     } else {
-        loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
+        rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+        loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
     }
-    opReg(cUnit, OP_BLX, r2);
+    loadConstant(cUnit, r2, (int)funct);
+    opReg(cUnit, kOpBlx, r2);
+    clobberCallRegs(cUnit);
     if (tgtSize == 1) {
-        storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+        RegLocation rlResult;
+        rlDest = getDestLoc(cUnit, mir, 0);
+        rlResult = getReturnLoc(cUnit);
+        storeValue(cUnit, rlDest, rlResult);
     } else {
-        storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
+        RegLocation rlResult;
+        rlDest = getDestLocWide(cUnit, mir, 0, 1);
+        rlResult = getReturnLocWide(cUnit);
+        storeValueWide(cUnit, rlDest, rlResult);
     }
     return false;
 }
@@ -1631,20 +1858,28 @@ static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
 {
     unsigned int i;
     unsigned int regMask = 0;
+    RegLocation rlArg;
+    int numDone = 0;
 
-    /* Load arguments to r0..r4 */
+    /*
+     * Load arguments to r0..r4.  Note that these registers may contain
+     * live values, so we clobber them immediately after loading to prevent
+     * them from being used as sources for subsequent loads.
+     */
+    lockAllTemps(cUnit);
     for (i = 0; i < dInsn->vA; i++) {
         regMask |= 1 << i;
-        loadValue(cUnit, dInsn->arg[i], i);
+        rlArg = getSrcLoc(cUnit, mir, numDone++);
+        loadValueDirectFixed(cUnit, rlArg, i);
     }
     if (regMask) {
         /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
-        opRegRegImm(cUnit, OP_SUB, r7, rFP,
-                    sizeof(StackSaveArea) + (dInsn->vA << 2), rNone);
+        opRegRegImm(cUnit, kOpSub, r7, rFP,
+                    sizeof(StackSaveArea) + (dInsn->vA << 2));
         /* generate null check */
         if (pcrLabel) {
-            *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
-                                     NULL);
+            *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
+                                     mir->offset, NULL);
         }
         storeMultiple(cUnit, r7, regMask);
     }
@@ -1657,26 +1892,35 @@ static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
     int srcOffset = dInsn->vC << 2;
     int numArgs = dInsn->vA;
     int regMask;
+
+    /*
+     * Note: here, all promoted registers will have been flushed
+     * back to the Dalvik base locations, so register usage restrictins
+     * are lifted.  All parms loaded from original Dalvik register
+     * region - even though some might conceivably have valid copies
+     * cached in a preserved register.
+     */
+    lockAllTemps(cUnit);
+
     /*
      * r4PC     : &rFP[vC]
      * r7: &newFP[0]
      */
-    opRegRegImm(cUnit, OP_ADD, r4PC, rFP, srcOffset, rNone);
+    opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
     /* load [r0 .. min(numArgs,4)] */
     regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
     /*
      * Protect the loadMultiple instruction from being reordered with other
      * Dalvik stack accesses.
      */
-    genBarrier(cUnit);
     loadMultiple(cUnit, r4PC, regMask);
-    genBarrier(cUnit);
 
-    opRegRegImm(cUnit, OP_SUB, r7, rFP,
-                sizeof(StackSaveArea) + (numArgs << 2), rNone);
+    opRegRegImm(cUnit, kOpSub, r7, rFP,
+                sizeof(StackSaveArea) + (numArgs << 2));
     /* generate null check */
     if (pcrLabel) {
-        *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
+        *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
+                                 mir->offset, NULL);
     }
 
     /*
@@ -1689,11 +1933,11 @@ static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
          * r0 contains "this" and it will be used later, so push it to the stack
          * first. Pushing r5 (rFP) is just for stack alignment purposes.
          */
-        opImm(cUnit, OP_PUSH, (1 << r0 | 1 << rFP));
+        opImm(cUnit, kOpPush, (1 << r0 | 1 << rFP));
         /* No need to generate the loop structure if numArgs <= 11 */
         if (numArgs > 11) {
             loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
-            loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+            loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
             loopLabel->defMask = ENCODE_ALL;
         }
         storeMultiple(cUnit, r7, regMask);
@@ -1701,13 +1945,11 @@ static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
          * Protect the loadMultiple instruction from being reordered with other
          * Dalvik stack accesses.
          */
-        genBarrier(cUnit);
         loadMultiple(cUnit, r4PC, regMask);
-        genBarrier(cUnit);
         /* No need to generate the loop structure if numArgs <= 11 */
         if (numArgs > 11) {
-            opRegImm(cUnit, OP_SUB, rFP, 4, rNone);
-            genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
+            opRegImm(cUnit, kOpSub, rFP, 4);
+            genConditionalBranch(cUnit, kArmCondNe, loopLabel);
         }
     }
 
@@ -1721,12 +1963,10 @@ static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
          * Protect the loadMultiple instruction from being reordered with other
          * Dalvik stack accesses.
          */
-        genBarrier(cUnit);
         loadMultiple(cUnit, r4PC, regMask);
-        genBarrier(cUnit);
     }
     if (numArgs >= 8)
-        opImm(cUnit, OP_POP, (1 << r0 | 1 << rFP));
+        opImm(cUnit, kOpPop, (1 << r0 | 1 << rFP));
 
     /* Save the modulo 4 arguments */
     if ((numArgs > 4) && (numArgs % 4)) {
@@ -1743,10 +1983,17 @@ static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
                                      ArmLIR *pcrLabel,
                                      const Method *calleeMethod)
 {
+    /*
+     * Note: all Dalvik register state should be flushed to
+     * memory by the point, so register usage restrictions no
+     * longer apply.  All temp & preserved registers may be used.
+     */
+    lockAllTemps(cUnit);
     ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
 
     /* r1 = &retChainingCell */
-    ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
+    lockTemp(cUnit, r1);
+    ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
     /* r4PC = dalvikCallsite */
     loadConstant(cUnit, r4PC,
                  (int) (cUnit->method->insns + mir->offset));
@@ -1799,6 +2046,14 @@ static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
                                    ArmLIR *predChainingCell,
                                    ArmLIR *pcrLabel)
 {
+    /*
+     * Note: all Dalvik register state should be flushed to
+     * memory by the point, so register usage restrictions no
+     * longer apply.  Lock temps to prevent them from being
+     * allocated by utility routines.
+     */
+    lockAllTemps(cUnit);
+
     /* "this" is already left in r0 by genProcessArgs* */
 
     /* r4PC = dalvikCallsite */
@@ -1806,12 +2061,11 @@ static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
                  (int) (cUnit->method->insns + mir->offset));
 
     /* r1 = &retChainingCell */
-    ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
+    ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
     addrRetChain->generic.target = (LIR *) retChainingCell;
 
     /* r2 = &predictedChainingCell */
-    ArmLIR *predictedChainingCell = opRegRegImm(cUnit, OP_ADD, r2, rpc, 0,
-                                                rNone);
+    ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
     predictedChainingCell->generic.target = (LIR *) predChainingCell;
 
     genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
@@ -1826,7 +2080,7 @@ static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
     if (pcrLabel == NULL) {
         int dPC = (int) (cUnit->method->insns + mir->offset);
         pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
-        pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
+        pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
         pcrLabel->operands[0] = dPC;
         pcrLabel->operands[1] = mir->offset;
         /* Insert the place holder to the growable list */
@@ -1849,9 +2103,9 @@ static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
     loadWordDisp(cUnit, r7, methodIndex * 4, r0);
 
     /* Check if rechain limit is reached */
-    opRegImm(cUnit, OP_CMP, r1, 0, rNone);
+    opRegImm(cUnit, kOpCmp, r1, 0);
 
-    ArmLIR *bypassRechaining = opCondBranch(cUnit, ARM_COND_GT);
+    ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
 
     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                  jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
@@ -1865,10 +2119,10 @@ static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
      * when patching the chaining cell and will be clobbered upon
      * returning so it will be reconstructed again.
      */
-    opReg(cUnit, OP_BLX, r7);
+    opReg(cUnit, kOpBlx, r7);
 
     /* r1 = &retChainingCell */
-    addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
+    addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
     addrRetChain->generic.target = (LIR *) retChainingCell;
 
     bypassRechaining->generic.target = (LIR *) addrRetChain;
@@ -1899,6 +2153,13 @@ static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
                                           ArmLIR *retChainingCell,
                                           MIR *mir)
 {
+    /*
+     * Note: all Dalvik register state should be flushed to
+     * memory by the point, so register usage restrictions no
+     * longer apply.  All temp & preserved registers may be used.
+     */
+    lockAllTemps(cUnit);
+
     /* r3 now contains this->clazz */
     loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
 
@@ -1929,24 +2190,25 @@ static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
                  (int) (cUnit->method->insns + mir->offset));
 
     /* r1 = &retChainingCell */
-    ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
+    ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
     addrRetChain->generic.target = (LIR *) retChainingCell;
 
     /* Check if r2 (predicted class) == r3 (actual class) */
-    opRegReg(cUnit, OP_CMP, r2, r3);
+    opRegReg(cUnit, kOpCmp, r2, r3);
 
-    return opCondBranch(cUnit, ARM_COND_EQ);
+    return opCondBranch(cUnit, kArmCondEq);
 }
 
 /* Geneate a branch to go back to the interpreter */
 static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
 {
     /* r0 = dalvik pc */
+    flushAllRegs(cUnit);
     loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
     loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                  jitToInterpEntries.dvmJitToInterpPunt), r1);
-    opReg(cUnit, OP_BLX, r1);
+    opReg(cUnit, kOpBlx, r1);
 }
 
 /*
@@ -1958,6 +2220,10 @@ static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
     int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
     int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
                        kInstrCanThrow;
+
+    //Ugly, but necessary.  Flush all Dalvik regs so Interp can find them
+    flushAllRegs(cUnit);
+
     if ((mir->next == NULL) || (flags & flagsToCheck)) {
        genPuntToInterp(cUnit, mir->offset);
        return;
@@ -1969,115 +2235,38 @@ static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
     loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
     /* r1 = dalvik pc of following instruction */
     loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
-    opReg(cUnit, OP_BLX, r2);
-}
-
-/* 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, OP_UNCOND_BR);
-    branch->generic.target = (LIR *) target;
-    return branch;
+    opReg(cUnit, kOpBlx, r2);
 }
 
-/* Load the address of a Dalvik register on the frame */
-static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
+static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir)
 {
-    return opRegRegImm(cUnit, OP_ADD, rDest, rFP, vSrc*4, rNone);
-}
-
-/* Load a single value from rFP[src] and store them into rDest */
-static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
-{
-    return loadBaseDisp(cUnit, NULL, rFP, vSrc * 4, rDest, WORD, false, -1);
+    genExportPC(cUnit, mir);
+    RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+    loadValueDirectFixed(cUnit, rlSrc, r1);
+    loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
+    if (mir->dalvikInsn.opCode == OP_MONITOR_ENTER) {
+        loadConstant(cUnit, r2, (int)dvmLockObject);
+    } else {
+        loadConstant(cUnit, r2, (int)dvmUnlockObject);
+    }
+    genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
+    /* Do the call */
+    opReg(cUnit, kOpBlx, r2);
+    clobberCallRegs(cUnit);
 }
 
 /* Load a word at base + displacement.  Displacement must be word multiple */
 static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
                             int rDest)
 {
-    return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, WORD, false,
-                        -1);
+    return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord, false,
+                        INVALID_SREG);
 }
 
 static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
-                             int displacement, int rSrc, int rScratch)
+                             int displacement, int rSrc)
 {
-    return storeBaseDisp(cUnit, rBase, displacement, rSrc, WORD, rScratch);
-}
-
-/* Store a value from rSrc to vDest */
-static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
-                          int rScratch)
-{
-    killNullCheckedRegister(cUnit, vDest);
-    updateLiveRegister(cUnit, vDest, rSrc);
-    return storeBaseDisp(cUnit, rFP, vDest * 4, rSrc, WORD, rScratch);
-}
-/*
- * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
- * rDestHi
- */
-static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
-                             int rDestHi)
-{
-    ArmLIR *res;
-    /* Use reg + imm5*4 to load the values if possible */
-    if (vSrc <= 30) {
-        res = loadWordDisp(cUnit, rFP, vSrc*4, rDestLo);
-        loadWordDisp(cUnit, rFP, (vSrc+1)*4, rDestHi);
-    } else {
-        assert(rDestLo < rDestHi);
-        res = loadValueAddress(cUnit, vSrc, rDestLo);
-        /*
-         * Protect the loadMultiple instruction from being reordered with other
-         * Dalvik stack accesses.
-         */
-        genBarrier(cUnit);
-        loadMultiple(cUnit, rDestLo, (1<<rDestLo) | (1<<rDestHi));
-        genBarrier(cUnit);
-    }
-    return res;
-}
-
-/*
- * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
- * vDest+1
- */
-static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
-                              int vDest, int rScratch)
-{
-    ArmLIR *res;
-    killNullCheckedRegister(cUnit, vDest);
-    killNullCheckedRegister(cUnit, vDest+1);
-    updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
-
-    /* Use reg + imm5*4 to store the values if possible */
-    if (vDest <= 30) {
-        res = storeWordDisp(cUnit, rFP, vDest*4, rSrcLo, rScratch);
-        storeWordDisp(cUnit, rFP, (vDest+1)*4, rSrcHi, rScratch);
-    } else {
-        assert(rSrcLo < rSrcHi);
-        res = loadValueAddress(cUnit, vDest, rScratch);
-        /*
-         * Protect the storeMultiple instruction from being reordered with
-         * other Dalvik stack accesses.
-         */
-        genBarrier(cUnit);
-        storeMultiple(cUnit, rScratch, (1<<rSrcLo) | (1 << rSrcHi));
-        genBarrier(cUnit);
-    }
-    return res;
+    return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
 }
 
 static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
@@ -2128,26 +2317,29 @@ static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
 
 static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
 {
-    int reg0, reg1, reg2;
+    RegLocation rlDest;
+    RegLocation rlResult;
+    if (mir->ssaRep->numDefs == 2) {
+        rlDest = getDestLocWide(cUnit, mir, 0, 1);
+    } else {
+        rlDest = getDestLoc(cUnit, mir, 0);
+    }
 
     switch (mir->dalvikInsn.opCode) {
         case OP_CONST:
         case OP_CONST_4: {
-            /* Avoid using the previously used register */
-            reg0 = selectFirstRegister(cUnit, vNone, false);
-            reg1 = NEXT_REG(reg0);
-            loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
-            storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
+            rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         }
         case OP_CONST_WIDE_32: {
-            /* Avoid using the previously used register */
-            reg0 = selectFirstRegister(cUnit, vNone, true);
-            reg1 = NEXT_REG(reg0);
-            reg2 = NEXT_REG(reg1);
-            loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
-            opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
-            storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
+            //TUNING: single routine to load constant pair for support doubles
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
+            opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
+                        rlResult.lowReg, 31);
+            storeValueWide(cUnit, rlDest, rlResult);
             break;
         }
         default:
@@ -2158,24 +2350,25 @@ static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
 
 static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
 {
-    int reg0, reg1, reg2;
+    RegLocation rlDest;
+    RegLocation rlResult;
+    if (mir->ssaRep->numDefs == 2) {
+        rlDest = getDestLocWide(cUnit, mir, 0, 1);
+    } else {
+        rlDest = getDestLoc(cUnit, mir, 0);
+    }
+    rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
 
-    /* Avoid using the previously used register */
     switch (mir->dalvikInsn.opCode) {
         case OP_CONST_HIGH16: {
-            reg0 = selectFirstRegister(cUnit, vNone, false);
-            reg1 = NEXT_REG(reg0);
-            loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
-            storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
+            loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         }
         case OP_CONST_WIDE_HIGH16: {
-            reg0 = selectFirstRegister(cUnit, vNone, true);
-            reg1 = NEXT_REG(reg0);
-            reg2 = NEXT_REG(reg1);
-            loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
-            loadConstant(cUnit, reg0, 0);
-            storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
+            loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
+                                  0, mir->dalvikInsn.vB << 16);
+            storeValueWide(cUnit, rlDest, rlResult);
             break;
         }
         default:
@@ -2193,14 +2386,9 @@ static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
 
 static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
 {
-    /* Native register to use if the interested value is vA */
-    int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
-    /* Native register to use if source is not from Dalvik registers */
-    int regvNone = selectFirstRegister(cUnit, vNone, false);
-    /* Similar to regvA but for 64-bit values */
-    int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
-    /* Similar to regvNone but for 64-bit values */
-    int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
+    RegLocation rlResult;
+    RegLocation rlDest;
+    RegLocation rlSrc;
 
     switch (mir->dalvikInsn.opCode) {
         case OP_CONST_STRING_JUMBO:
@@ -2208,16 +2396,20 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
             void *strPtr = (void*)
               (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
             assert(strPtr != NULL);
-            loadConstant(cUnit, regvNone, (int) strPtr );
-            storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
+            rlDest = getDestLoc(cUnit, mir, 0);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            loadConstantValue(cUnit, rlResult.lowReg, (int) strPtr );
+            storeValue(cUnit, rlDest, rlResult);
             break;
         }
         case OP_CONST_CLASS: {
             void *classPtr = (void*)
               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
             assert(classPtr != NULL);
-            loadConstant(cUnit, regvNone, (int) classPtr );
-            storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
+            rlDest = getDestLoc(cUnit, mir, 0);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            loadConstantValue(cUnit, rlResult.lowReg, (int) classPtr );
+            storeValue(cUnit, rlDest, rlResult);
             break;
         }
         case OP_SGET_OBJECT:
@@ -2227,40 +2419,42 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
         case OP_SGET_SHORT:
         case OP_SGET: {
             int valOffset = offsetof(StaticField, value);
+            int tReg = allocTemp(cUnit);
             void *fieldPtr = (void*)
               (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
             assert(fieldPtr != NULL);
-            loadConstant(cUnit, regvNone,  (int) fieldPtr + valOffset);
+            rlDest = getDestLoc(cUnit, mir, 0);
+            rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
 #if !defined(WITH_SELF_VERIFICATION)
-            loadWordDisp(cUnit, regvNone, 0, regvNone);
+            loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
 #else
-            int regMap = regvNone << 4 | regvNone;
+            int regMap = rlResult.lowReg << 8 | tReg;
             selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
 
 #endif
-            storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
+            storeValue(cUnit, rlDest, rlResult);
             break;
         }
         case OP_SGET_WIDE: {
             int valOffset = offsetof(StaticField, value);
             void *fieldPtr = (void*)
               (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
-            int reg0, reg1, reg2;
-
+            int tReg = allocTemp(cUnit);
             assert(fieldPtr != NULL);
-            reg0 = regvNoneWide;
-            reg1 = NEXT_REG(reg0);
-            reg2 = NEXT_REG(reg1);
-            loadConstant(cUnit, reg2,  (int) fieldPtr + valOffset);
+            rlDest = getDestLocWide(cUnit, mir, 0, 1);
+            rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
+            loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
 #if !defined(WITH_SELF_VERIFICATION)
-            loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
+            loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
 #else
-            int regMap = reg1 << 8 | reg0 << 4 | reg2;
+            int regMap = rlResult.highReg << 16 |
+                         rlResult.lowReg << 8 | tReg;
             selfVerificationMemOpWrapper(cUnit, regMap,
                 &selfVerificationLoadDoubleword);
 
 #endif
-            storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
+            storeValueWide(cUnit, rlDest, rlResult);
             break;
         }
         case OP_SPUT_OBJECT:
@@ -2270,38 +2464,36 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
         case OP_SPUT_SHORT:
         case OP_SPUT: {
             int valOffset = offsetof(StaticField, value);
+            int tReg = allocTemp(cUnit);
             void *fieldPtr = (void*)
               (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
 
             assert(fieldPtr != NULL);
-            loadValue(cUnit, mir->dalvikInsn.vA, regvA);
-            updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
-            loadConstant(cUnit, NEXT_REG(regvA),  (int) fieldPtr + valOffset);
+            rlSrc = getSrcLoc(cUnit, mir, 0);
+            rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
+            loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
 #if !defined(WITH_SELF_VERIFICATION)
-            storeWordDisp(cUnit, NEXT_REG(regvA), 0 , regvA, -1);
+            storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
 #else
-            int regMap = regvA << 4 | NEXT_REG(regvA);
+            int regMap = rlSrc.lowReg << 8 | tReg;
             selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
 #endif
             break;
         }
         case OP_SPUT_WIDE: {
-            int reg0, reg1, reg2;
+            int tReg = allocTemp(cUnit);
             int valOffset = offsetof(StaticField, value);
             void *fieldPtr = (void*)
               (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
 
             assert(fieldPtr != NULL);
-            reg0 = regvAWide;
-            reg1 = NEXT_REG(reg0);
-            reg2 = NEXT_REG(reg1);
-            loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
-            updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
-            loadConstant(cUnit, reg2,  (int) fieldPtr + valOffset);
+            rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+            rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+            loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
 #if !defined(WITH_SELF_VERIFICATION)
-            storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
+            storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
 #else
-            int regMap = reg1 << 8 | reg0 << 4 | reg2;
+            int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | tReg;
             selfVerificationMemOpWrapper(cUnit, regMap,
                 &selfVerificationStoreDoubleword);
 #endif
@@ -2318,17 +2510,18 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
             assert(classPtr->status & CLASS_INITIALIZED);
             /*
              * If it is going to throw, it should not make to the trace to begin
-             * with.
+             * with.  However, Alloc might throw, so we need to genExportPC()
              */
             assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
-            loadConstant(cUnit, r4PC, (int)dvmAllocObject);
+            genExportPC(cUnit, mir);
+            loadConstant(cUnit, r2, (int)dvmAllocObject);
             loadConstant(cUnit, r0, (int) classPtr);
-            genExportPC(cUnit, mir, r2, r3 );
             loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
-            opReg(cUnit, OP_BLX, r4PC);
+            opReg(cUnit, kOpBlx, r2);
+            clobberCallRegs(cUnit);
             /* generate a branch over if allocation is successful */
-            opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
-            ArmLIR *branchOver = opCondBranch(cUnit, ARM_COND_NE);
+            opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
+            ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
             /*
              * OOM exception needs to be thrown here and cannot re-execute
              */
@@ -2337,10 +2530,12 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
             /* noreturn */
 
-            ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
             target->defMask = ENCODE_ALL;
             branchOver->generic.target = (LIR *) target;
-            storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+            rlDest = getDestLoc(cUnit, mir, 0);
+            rlResult = getReturnLoc(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         }
         case OP_CHECK_CAST: {
@@ -2351,19 +2546,31 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
             ClassObject *classPtr =
               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
             loadConstant(cUnit, r1, (int) classPtr );
-            loadValue(cUnit, mir->dalvikInsn.vA, r0);  /* Ref */
-            opRegImm(cUnit, OP_CMP, r0, 0, rNone);   /* Null? */
-            ArmLIR *branch1 = opCondBranch(cUnit, ARM_COND_EQ);
+            rlSrc = getSrcLoc(cUnit, mir, 0);
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);   /* Null? */
+            ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
+            /*
+             *  rlSrc.lowReg now contains object->clazz.  Note that
+             *  it could have been allocated r0, but we're okay so long
+             *  as we don't do anything desctructive until r0 is loaded
+             *  with clazz.
+             */
             /* r0 now contains object->clazz */
-            loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
-            loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
-            opRegReg(cUnit, OP_CMP, r0, r1);
-            ArmLIR *branch2 = opCondBranch(cUnit, ARM_COND_EQ);
-            opReg(cUnit, OP_BLX, r4PC);
-            /* check cast failed - punt to the interpreter */
+            loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
+            loadConstant(cUnit, r2, (int)dvmInstanceofNonTrivial);
+            opRegReg(cUnit, kOpCmp, r0, r1);
+            ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
+            opReg(cUnit, kOpBlx, r2);
+            clobberCallRegs(cUnit);
+            /*
+             * If null, check cast failed - punt to the interpreter.  Because
+             * interpreter will be the one throwing, we don't need to
+             * genExportPC() here.
+             */
             genZeroCheck(cUnit, r0, mir->offset, NULL);
             /* check cast passed - branch target here */
-            ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
             target->defMask = ENCODE_ALL;
             branch1->generic.target = (LIR *)target;
             branch2->generic.target = (LIR *)target;
@@ -2378,67 +2585,59 @@ static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
+    RegLocation rlResult;
     switch (dalvikOpCode) {
         case OP_MOVE_EXCEPTION: {
             int offset = offsetof(InterpState, self);
             int exOffset = offsetof(Thread, exception);
-            loadWordDisp(cUnit, rGLUE, offset, r1);
-            loadWordDisp(cUnit, r1, exOffset, r0);
-            storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+            int selfReg = allocTemp(cUnit);
+            RegLocation rlDest = getDestLoc(cUnit, mir, 0);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            loadWordDisp(cUnit, rGLUE, offset, selfReg);
+            loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
            break;
         }
         case OP_MOVE_RESULT:
         case OP_MOVE_RESULT_OBJECT: {
-            int offset = offsetof(InterpState, retval);
-            loadWordDisp(cUnit, rGLUE, offset, r0);
-            storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+            RegLocation rlDest = getDestLoc(cUnit, mir, 0);
+            RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
+            rlSrc.fp = rlDest.fp;
+            storeValue(cUnit, rlDest, rlSrc);
             break;
         }
         case OP_MOVE_RESULT_WIDE: {
-            int offset = offsetof(InterpState, retval);
-            loadWordDisp(cUnit, rGLUE, offset, r0);
-            loadWordDisp(cUnit, rGLUE, offset+4, r1);
-            storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
+            RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
+            RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
+            rlSrc.fp = rlDest.fp;
+            storeValueWide(cUnit, rlDest, rlSrc);
             break;
         }
         case OP_RETURN_WIDE: {
-            int vSrc = mir->dalvikInsn.vA;
-            int reg0 = selectFirstRegister(cUnit, vSrc, true);
-            int reg1 = NEXT_REG(reg0);
-            int rScratch = NEXT_REG(reg1);
-            int offset = offsetof(InterpState, retval);
-            loadValuePair(cUnit, vSrc, reg0, reg1);
-            storeWordDisp(cUnit, rGLUE, offset, reg0, rScratch);
-            storeWordDisp(cUnit, rGLUE, offset + 4, reg1, rScratch);
+            RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+            RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
+            rlDest.fp = rlSrc.fp;
+            storeValueWide(cUnit, rlDest, rlSrc);
             genReturnCommon(cUnit,mir);
             break;
         }
         case OP_RETURN:
         case OP_RETURN_OBJECT: {
-            int vSrc = mir->dalvikInsn.vA;
-            int reg0 = selectFirstRegister(cUnit, vSrc, false);
-            int rScratch = NEXT_REG(reg0);
-            loadValue(cUnit, vSrc, reg0);
-            storeWordDisp(cUnit, rGLUE, offsetof(InterpState, retval),
-                          reg0, rScratch);
+            RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+            RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
+            rlDest.fp = rlSrc.fp;
+            storeValue(cUnit, rlDest, rlSrc);
             genReturnCommon(cUnit,mir);
             break;
         }
+        case OP_MONITOR_EXIT:
         case OP_MONITOR_ENTER:
-        case OP_MONITOR_EXIT: {
-            int offset = offsetof(InterpState, self);
-            loadValue(cUnit, mir->dalvikInsn.vA, r1);
-            loadWordDisp(cUnit, rGLUE, offset, r0);
-            if (dalvikOpCode == OP_MONITOR_ENTER) {
-                loadConstant(cUnit, r2, (int)dvmLockObject);
-            } else {
-                loadConstant(cUnit, r2, (int)dvmUnlockObject);
-            }
-            genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
-            /* Do the call */
-            opReg(cUnit, OP_BLX, r2);
+#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
+            handleMonitorPortable(cUnit, mir);
+#else
+            handleMonitor(cUnit, mir);
+#endif
             break;
-        }
         case OP_THROW: {
             genInterpSingleStep(cUnit, mir);
             break;
@@ -2449,7 +2648,7 @@ static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
     return false;
 }
 
-static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
+static bool handleConversionPortable(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode opCode = mir->dalvikInsn.opCode;
 
@@ -2494,90 +2693,95 @@ static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
 static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode opCode = mir->dalvikInsn.opCode;
-    int vSrc1Dest = mir->dalvikInsn.vA;
-    int vSrc2 = mir->dalvikInsn.vB;
-    int reg0, reg1, reg2;
+    RegLocation rlDest;
+    RegLocation rlSrc;
+    RegLocation rlResult;
 
     if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
-        return genArithOp( cUnit, mir );
+        return handleArithOp( cUnit, mir );
     }
 
-    /*
-     * If data type is 64-bit, re-calculate the register numbers in the
-     * corresponding cases.
-     */
-    reg0 = selectFirstRegister(cUnit, vSrc2, false);
-    reg1 = NEXT_REG(reg0);
-    reg2 = NEXT_REG(reg1);
+    if (mir->ssaRep->numUses == 2)
+        rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+    else
+        rlSrc = getSrcLoc(cUnit, mir, 0);
+    if (mir->ssaRep->numDefs == 2)
+        rlDest = getDestLocWide(cUnit, mir, 0, 1);
+    else
+        rlDest = getDestLoc(cUnit, mir, 0);
 
     switch (opCode) {
+        case OP_DOUBLE_TO_INT:
         case OP_INT_TO_FLOAT:
         case OP_FLOAT_TO_INT:
         case OP_DOUBLE_TO_FLOAT:
         case OP_FLOAT_TO_DOUBLE:
         case OP_INT_TO_DOUBLE:
-        case OP_DOUBLE_TO_INT:
         case OP_FLOAT_TO_LONG:
         case OP_LONG_TO_FLOAT:
         case OP_DOUBLE_TO_LONG:
         case OP_LONG_TO_DOUBLE:
-            return genConversion(cUnit, mir);
+            return handleConversion(cUnit, mir);
         case OP_NEG_INT:
         case OP_NOT_INT:
-            return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
+            return handleArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
         case OP_NEG_LONG:
         case OP_NOT_LONG:
-            return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
+            return handleArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
         case OP_NEG_FLOAT:
-            return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
+            return handleArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
         case OP_NEG_DOUBLE:
-            return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
-        case OP_MOVE_WIDE: {
-            reg0 = selectFirstRegister(cUnit, vSrc2, true);
-            reg1 = NEXT_REG(reg0);
-            reg2 = NEXT_REG(reg1);
-
-            loadValuePair(cUnit, vSrc2, reg0, reg1);
-            storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
-            break;
-        }
-        case OP_INT_TO_LONG: {
-            reg0 = selectFirstRegister(cUnit, vSrc2, true);
-            reg1 = NEXT_REG(reg0);
-            reg2 = NEXT_REG(reg1);
-
-            loadValue(cUnit, vSrc2, reg0);
-            opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
-            storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
+            return handleArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
+        case OP_MOVE_WIDE:
+            storeValueWide(cUnit, rlDest, rlSrc);
+            break;
+        case OP_INT_TO_LONG:
+            rlSrc = updateLoc(cUnit, rlSrc);
+            rlResult = evalLoc(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);
             break;
-        }
+        case OP_LONG_TO_INT:
+            rlSrc = updateLocWide(cUnit, rlSrc);
+            rlSrc = wideToNarrowLoc(cUnit, rlSrc);
+            // Intentional fallthrough
         case OP_MOVE:
         case OP_MOVE_OBJECT:
-        case OP_LONG_TO_INT:
-            loadValue(cUnit, vSrc2, reg0);
-            storeValue(cUnit, reg0, vSrc1Dest, reg1);
+            storeValue(cUnit, rlDest, rlSrc);
             break;
         case OP_INT_TO_BYTE:
-            loadValue(cUnit, vSrc2, reg0);
-            opRegReg(cUnit, OP_2BYTE, reg1, reg0);
-            storeValue(cUnit, reg1, vSrc1Dest, reg2);
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         case OP_INT_TO_SHORT:
-            loadValue(cUnit, vSrc2, reg0);
-            opRegReg(cUnit, OP_2SHORT, reg1, reg0);
-            storeValue(cUnit, reg1, vSrc1Dest, reg2);
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         case OP_INT_TO_CHAR:
-            loadValue(cUnit, vSrc2, reg0);
-            opRegReg(cUnit, OP_2CHAR, reg1, reg0);
-            storeValue(cUnit, reg1, vSrc1Dest, reg2);
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         case OP_ARRAY_LENGTH: {
             int lenOffset = offsetof(ArrayObject, length);
-            loadValue(cUnit, vSrc2, reg1);
-            genNullCheck(cUnit, vSrc2, reg1, mir->offset, NULL);
-            loadWordDisp(cUnit, reg1, lenOffset, reg0);
-            storeValue(cUnit, reg0, vSrc1Dest, reg1);
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
+                         mir->offset, NULL);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
+                         rlResult.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         }
         default:
@@ -2589,34 +2793,22 @@ static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
 static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
-    int reg0, reg1, reg2;
-
-    /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
+    RegLocation rlDest;
+    RegLocation rlResult;
+    int BBBB = mir->dalvikInsn.vB;
     if (dalvikOpCode == OP_CONST_WIDE_16) {
-        int vDest = mir->dalvikInsn.vA;
-        int BBBB = mir->dalvikInsn.vB;
-
-        reg0 = selectFirstRegister(cUnit, vNone, true);
-        reg1 = NEXT_REG(reg0);
-        reg2 = NEXT_REG(reg1);
-
-        loadConstant(cUnit, reg0, BBBB);
-        opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
-
-        /* Save the long values to the specified Dalvik register pair */
-        storeValuePair(cUnit, reg0, reg1, vDest, reg2);
+        rlDest = getDestLocWide(cUnit, mir, 0, 1);
+        rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+        loadConstantValue(cUnit, rlResult.lowReg, BBBB);
+        opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
+        storeValueWide(cUnit, rlDest, rlResult);
     } else if (dalvikOpCode == OP_CONST_16) {
-        int vDest = mir->dalvikInsn.vA;
-        int BBBB = mir->dalvikInsn.vB;
-
-        reg0 = selectFirstRegister(cUnit, vNone, false);
-        reg1 = NEXT_REG(reg0);
-
-        loadConstant(cUnit, reg0, BBBB);
-        storeValue(cUnit, reg0, vDest, reg1);
-    } else {
+        rlDest = getDestLoc(cUnit, mir, 0);
+        rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
+        loadConstantValue(cUnit, rlResult.lowReg, BBBB);
+        storeValue(cUnit, rlDest, rlResult);
+    } else
         return true;
-    }
     return false;
 }
 
@@ -2626,30 +2818,29 @@ static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
 {
     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
     ArmConditionCode cond;
-    int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
-
-    loadValue(cUnit, mir->dalvikInsn.vA, reg0);
-    opRegImm(cUnit, OP_CMP, reg0, 0, rNone);
+    RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
 
 //TUNING: break this out to allow use of Thumb2 CB[N]Z
     switch (dalvikOpCode) {
         case OP_IF_EQZ:
-            cond = ARM_COND_EQ;
+            cond = kArmCondEq;
             break;
         case OP_IF_NEZ:
-            cond = ARM_COND_NE;
+            cond = kArmCondNe;
             break;
         case OP_IF_LTZ:
-            cond = ARM_COND_LT;
+            cond = kArmCondLt;
             break;
         case OP_IF_GEZ:
-            cond = ARM_COND_GE;
+            cond = kArmCondGe;
             break;
         case OP_IF_GTZ:
-            cond = ARM_COND_GT;
+            cond = kArmCondGt;
             break;
         case OP_IF_LEZ:
-            cond = ARM_COND_LE;
+            cond = kArmCondLe;
             break;
         default:
             cond = 0;
@@ -2665,124 +2856,107 @@ static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
 static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
-    int vSrc = mir->dalvikInsn.vB;
-    int vDest = mir->dalvikInsn.vA;
+    RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlDest = getDestLoc(cUnit, mir, 0);
+    RegLocation rlResult;
     int lit = mir->dalvikInsn.vC;
     OpKind op = 0;      /* Make gcc happy */
-    int reg0, reg1, regDest;
-
-    reg0 = selectFirstRegister(cUnit, vSrc, false);
-    reg1 = NEXT_REG(reg0);
-    regDest = NEXT_REG(reg1);
+    int shiftOp = false;
+    bool isDiv = false;
 
     int __aeabi_idivmod(int op1, int op2);
     int __aeabi_idiv(int op1, int op2);
 
     switch (dalvikOpCode) {
-        case OP_ADD_INT_LIT8:
-        case OP_ADD_INT_LIT16:
-            loadValue(cUnit, vSrc, reg0);
-            opRegImm(cUnit, OP_ADD, reg0, lit, reg1);
-            storeValue(cUnit, reg0, vDest, reg1);
-            break;
-
         case OP_RSUB_INT_LIT8:
-        case OP_RSUB_INT:
-            loadValue(cUnit, vSrc, reg1);
-            loadConstant(cUnit, reg0, lit);
-            opRegRegReg(cUnit, OP_SUB, regDest, reg0, reg1);
-            storeValue(cUnit, regDest, vDest, reg1);
+        case OP_RSUB_INT: {
+            int tReg;
+            //TUNING: add support for use of Arm rsub op
+            rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+            tReg = allocTemp(cUnit);
+            loadConstant(cUnit, tReg, lit);
+            rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+            opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
+                        tReg, rlSrc.lowReg);
+            storeValue(cUnit, rlDest, rlResult);
+            return false;
             break;
+        }
 
+        case OP_ADD_INT_LIT8:
+        case OP_ADD_INT_LIT16:
+            op = kOpAdd;
+            break;
         case OP_MUL_INT_LIT8:
         case OP_MUL_INT_LIT16:
+            op = kOpMul;
+            break;
         case OP_AND_INT_LIT8:
         case OP_AND_INT_LIT16:
+            op = kOpAnd;
+            break;
         case OP_OR_INT_LIT8:
         case OP_OR_INT_LIT16:
+            op = kOpOr;
+            break;
         case OP_XOR_INT_LIT8:
         case OP_XOR_INT_LIT16:
-            loadValue(cUnit, vSrc, reg0);
-            switch (dalvikOpCode) {
-                case OP_MUL_INT_LIT8:
-                case OP_MUL_INT_LIT16:
-                    op = OP_MUL;
-                    break;
-                case OP_AND_INT_LIT8:
-                case OP_AND_INT_LIT16:
-                    op = OP_AND;
-                    break;
-                case OP_OR_INT_LIT8:
-                case OP_OR_INT_LIT16:
-                    op = OP_OR;
-                    break;
-                case OP_XOR_INT_LIT8:
-                case OP_XOR_INT_LIT16:
-                    op = OP_XOR;
-                    break;
-                default:
-                    dvmAbort();
-            }
-            opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
-            storeValue(cUnit, regDest, vDest, reg1);
+            op = kOpXor;
             break;
-
         case OP_SHL_INT_LIT8:
+            shiftOp = true;
+            op = kOpLsl;
+            break;
         case OP_SHR_INT_LIT8:
+            shiftOp = true;
+            op = kOpAsr;
+            break;
         case OP_USHR_INT_LIT8:
-            loadValue(cUnit, vSrc, reg0);
-            switch (dalvikOpCode) {
-                case OP_SHL_INT_LIT8:
-                    op = OP_LSL;
-                    break;
-                case OP_SHR_INT_LIT8:
-                    op = OP_ASR;
-                    break;
-                case OP_USHR_INT_LIT8:
-                    op = OP_LSR;
-                    break;
-                default: dvmAbort();
-            }
-            if (lit != 0) {
-                opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
-                storeValue(cUnit, regDest, vDest, reg1);
-            } else {
-                storeValue(cUnit, reg0, vDest, reg1);
-            }
+            shiftOp = true;
+            op = kOpLsr;
             break;
 
         case OP_DIV_INT_LIT8:
         case OP_DIV_INT_LIT16:
-            /* Register usage based on the calling convention */
-            if (lit == 0) {
-                /* Let the interpreter deal with div by 0 */
-                genInterpSingleStep(cUnit, mir);
-                return false;
-            }
-            loadConstant(cUnit, r2, (int)__aeabi_idiv);
-            loadConstant(cUnit, r1, lit);
-            loadValue(cUnit, vSrc, r0);
-            opReg(cUnit, OP_BLX, r2);
-            storeValue(cUnit, r0, vDest, r2);
-            break;
-
         case OP_REM_INT_LIT8:
         case OP_REM_INT_LIT16:
-            /* Register usage based on the calling convention */
             if (lit == 0) {
                 /* Let the interpreter deal with div by 0 */
                 genInterpSingleStep(cUnit, mir);
                 return false;
             }
-            loadConstant(cUnit, r2, (int)__aeabi_idivmod);
+            loadValueDirectFixed(cUnit, rlSrc, r0);
+            clobberReg(cUnit, r0);
+            if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
+                (dalvikOpCode == OP_DIV_INT_LIT16)) {
+                loadConstant(cUnit, r2, (int)__aeabi_idiv);
+                isDiv = true;
+            } else {
+                loadConstant(cUnit, r2, (int)__aeabi_idivmod);
+                isDiv = false;
+            }
             loadConstant(cUnit, r1, lit);
-            loadValue(cUnit, vSrc, r0);
-            opReg(cUnit, OP_BLX, r2);
-            storeValue(cUnit, r1, vDest, r2);
+            opReg(cUnit, kOpBlx, r2);
+            clobberCallRegs(cUnit);
+            if (isDiv)
+                rlResult = getReturnLoc(cUnit);
+            else
+                rlResult = getReturnLocAlt(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
+            return false;
             break;
         default:
             return true;
     }
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+    // Avoid shifts by literal 0 - no support in Thumb.  Change to copy
+    if (shiftOp && (lit == 0)) {
+        genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
+    } else {
+        opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
+    }
+    storeValue(cUnit, rlDest, rlResult);
     return false;
 }
 
@@ -2803,24 +2977,29 @@ static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
     }
     switch (dalvikOpCode) {
         case OP_NEW_ARRAY: {
+            // Generates a call - use explicit registers
+            RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+            RegLocation rlDest = getDestLoc(cUnit, mir, 0);
+            RegLocation rlResult;
             void *classPtr = (void*)
               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
             assert(classPtr != NULL);
-            loadValue(cUnit, mir->dalvikInsn.vB, r1);  /* Len */
+            genExportPC(cUnit, mir);
+            loadValueDirectFixed(cUnit, rlSrc, r1);   /* Len */
             loadConstant(cUnit, r0, (int) classPtr );
-            loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
+            loadConstant(cUnit, r3, (int)dvmAllocArrayByClass);
             /*
              * "len < 0": bail to the interpreter to re-execute the
              * instruction
              */
             ArmLIR *pcrLabel =
-                genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
-            genExportPC(cUnit, mir, r2, r3 );
+                genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
             loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
-            opReg(cUnit, OP_BLX, r4PC);
+            opReg(cUnit, kOpBlx, r3);
+            clobberCallRegs(cUnit);
             /* generate a branch over if allocation is successful */
-            opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
-            ArmLIR *branchOver = opCondBranch(cUnit, ARM_COND_NE);
+            opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
+            ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
             /*
              * OOM exception needs to be thrown here and cannot re-execute
              */
@@ -2829,35 +3008,43 @@ static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
             /* noreturn */
 
-            ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
             target->defMask = ENCODE_ALL;
             branchOver->generic.target = (LIR *) target;
-            storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+            rlResult = getReturnLoc(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         }
         case OP_INSTANCE_OF: {
+            // May generate a call - use explicit registers
+            RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+            RegLocation rlDest = getDestLoc(cUnit, mir, 0);
+            RegLocation rlResult;
             ClassObject *classPtr =
               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
             assert(classPtr != NULL);
-            loadValue(cUnit, mir->dalvikInsn.vB, r0);  /* Ref */
+            loadValueDirectFixed(cUnit, rlSrc, r0);  /* Ref */
             loadConstant(cUnit, r2, (int) classPtr );
 //TUNING: compare to 0 primative to allow use of CB[N]Z
-            opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
+            opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
             /* When taken r0 has NULL which can be used for store directly */
-            ArmLIR *branch1 = opCondBranch(cUnit, ARM_COND_EQ);
+            ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
             /* r1 now contains object->clazz */
             loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
-            loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
+            /* r1 now contains object->clazz */
+            loadConstant(cUnit, r3, (int)dvmInstanceofNonTrivial);
             loadConstant(cUnit, r0, 1);                /* Assume true */
-            opRegReg(cUnit, OP_CMP, r1, r2);
-            ArmLIR *branch2 = opCondBranch(cUnit, ARM_COND_EQ);
-            opRegReg(cUnit, OP_MOV, r0, r1);
-            opRegReg(cUnit, OP_MOV, r1, r2);
-            opReg(cUnit, OP_BLX, r4PC);
+            opRegReg(cUnit, kOpCmp, r1, r2);
+            ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
+            genRegCopy(cUnit, r0, r1);
+            genRegCopy(cUnit, r1, r2);
+            opReg(cUnit, kOpBlx, r3);
+            clobberCallRegs(cUnit);
             /* branch target here */
-            ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+            ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
             target->defMask = ENCODE_ALL;
-            storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+            rlResult = getReturnLoc(cUnit);
+            storeValue(cUnit, rlDest, rlResult);
             branch1->generic.target = (LIR *)target;
             branch2->generic.target = (LIR *)target;
             break;
@@ -2867,34 +3054,34 @@ static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
             break;
         case OP_IGET:
         case OP_IGET_OBJECT:
-            genIGet(cUnit, mir, WORD, fieldOffset);
+            genIGet(cUnit, mir, kWord, fieldOffset);
             break;
         case OP_IGET_BOOLEAN:
-            genIGet(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
+            genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
             break;
         case OP_IGET_BYTE:
-            genIGet(cUnit, mir, SIGNED_BYTE, fieldOffset);
+            genIGet(cUnit, mir, kSignedByte, fieldOffset);
             break;
         case OP_IGET_CHAR:
-            genIGet(cUnit, mir, UNSIGNED_HALF, fieldOffset);
+            genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
             break;
         case OP_IGET_SHORT:
-            genIGet(cUnit, mir, SIGNED_HALF, fieldOffset);
+            genIGet(cUnit, mir, kSignedHalf, fieldOffset);
             break;
         case OP_IPUT_WIDE:
             genIPutWide(cUnit, mir, fieldOffset);
             break;
         case OP_IPUT:
         case OP_IPUT_OBJECT:
-            genIPut(cUnit, mir, WORD, fieldOffset);
+            genIPut(cUnit, mir, kWord, fieldOffset);
             break;
         case OP_IPUT_SHORT:
         case OP_IPUT_CHAR:
-            genIPut(cUnit, mir, UNSIGNED_HALF, fieldOffset);
+            genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
             break;
         case OP_IPUT_BYTE:
         case OP_IPUT_BOOLEAN:
-            genIPut(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
+            genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
             break;
         default:
             return true;
@@ -2909,11 +3096,11 @@ static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
     switch (dalvikOpCode) {
         case OP_IGET_QUICK:
         case OP_IGET_OBJECT_QUICK:
-            genIGet(cUnit, mir, WORD, fieldOffset);
+            genIGet(cUnit, mir, kWord, fieldOffset);
             break;
         case OP_IPUT_QUICK:
         case OP_IPUT_OBJECT_QUICK:
-            genIPut(cUnit, mir, WORD, fieldOffset);
+            genIPut(cUnit, mir, kWord, fieldOffset);
             break;
         case OP_IGET_WIDE_QUICK:
             genIGetWide(cUnit, mir, fieldOffset);
@@ -2934,41 +3121,31 @@ static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
 {
     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
     ArmConditionCode cond;
-    int reg0, reg1;
-
-    if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
-        reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
-        reg1 = NEXT_REG(reg0);
-        /* Load vB first since vA can be fetched via a move */
-        loadValue(cUnit, mir->dalvikInsn.vB, reg1);
-        loadValue(cUnit, mir->dalvikInsn.vA, reg0);
-    } else {
-        reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
-        reg1 = NEXT_REG(reg0);
-        /* Load vA first since vB can be fetched via a move */
-        loadValue(cUnit, mir->dalvikInsn.vA, reg0);
-        loadValue(cUnit, mir->dalvikInsn.vB, reg1);
-    }
-    opRegReg(cUnit, OP_CMP, reg0, reg1);
+    RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
+
+    rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+    opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
 
     switch (dalvikOpCode) {
         case OP_IF_EQ:
-            cond = ARM_COND_EQ;
+            cond = kArmCondEq;
             break;
         case OP_IF_NE:
-            cond = ARM_COND_NE;
+            cond = kArmCondNe;
             break;
         case OP_IF_LT:
-            cond = ARM_COND_LT;
+            cond = kArmCondLt;
             break;
         case OP_IF_GE:
-            cond = ARM_COND_GE;
+            cond = kArmCondGe;
             break;
         case OP_IF_GT:
-            cond = ARM_COND_GT;
+            cond = kArmCondGt;
             break;
         case OP_IF_LE:
-            cond = ARM_COND_LE;
+            cond = kArmCondLe;
             break;
         default:
             cond = 0;
@@ -2984,28 +3161,20 @@ static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
 static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode opCode = mir->dalvikInsn.opCode;
-    int vSrc1Dest = mir->dalvikInsn.vA;
-    int vSrc2 = mir->dalvikInsn.vB;
-    int reg0, reg1, reg2;
 
     switch (opCode) {
         case OP_MOVE_16:
         case OP_MOVE_OBJECT_16:
         case OP_MOVE_FROM16:
         case OP_MOVE_OBJECT_FROM16: {
-            reg0 = selectFirstRegister(cUnit, vSrc2, false);
-            reg1 = NEXT_REG(reg0);
-            loadValue(cUnit, vSrc2, reg0);
-            storeValue(cUnit, reg0, vSrc1Dest, reg1);
+            storeValue(cUnit, getDestLoc(cUnit, mir, 0),
+                       getSrcLoc(cUnit, mir, 0));
             break;
         }
         case OP_MOVE_WIDE_16:
         case OP_MOVE_WIDE_FROM16: {
-            reg0 = selectFirstRegister(cUnit, vSrc2, true);
-            reg1 = NEXT_REG(reg0);
-            reg2 = NEXT_REG(reg1);
-            loadValuePair(cUnit, vSrc2, reg0, reg1);
-            storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
+            storeValueWide(cUnit, getDestLocWide(cUnit, mir, 0, 1),
+                           getSrcLocWide(cUnit, mir, 0, 1));
             break;
         }
         default:
@@ -3017,57 +3186,87 @@ static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
 static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode opCode = mir->dalvikInsn.opCode;
-    int vA = mir->dalvikInsn.vA;
-    int vB = mir->dalvikInsn.vB;
-    int vC = mir->dalvikInsn.vC;
+    RegLocation rlSrc1;
+    RegLocation rlSrc2;
+    RegLocation rlDest;
 
-    /* Don't optimize for register usage since out-of-line handlers are used */
     if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
-        return genArithOp( cUnit, mir );
+        return handleArithOp( cUnit, mir );
     }
 
+    /* APUTs have 3 sources and no targets */
+    if (mir->ssaRep->numDefs == 0) {
+        if (mir->ssaRep->numUses == 3) {
+            rlDest = getSrcLoc(cUnit, mir, 0);
+            rlSrc1 = getSrcLoc(cUnit, mir, 1);
+            rlSrc2 = getSrcLoc(cUnit, mir, 2);
+        } else {
+            assert(mir->ssaRep->numUses == 4);
+            rlDest = getSrcLocWide(cUnit, mir, 0, 1);
+            rlSrc1 = getSrcLoc(cUnit, mir, 2);
+            rlSrc2 = getSrcLoc(cUnit, mir, 3);
+        }
+    } else {
+        /* Two sources and 1 dest.  Deduce the operand sizes */
+        if (mir->ssaRep->numUses == 4) {
+            rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
+            rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
+        } else {
+            assert(mir->ssaRep->numUses == 2);
+            rlSrc1 = getSrcLoc(cUnit, mir, 0);
+            rlSrc2 = getSrcLoc(cUnit, mir, 1);
+        }
+        if (mir->ssaRep->numDefs == 2) {
+            rlDest = getDestLocWide(cUnit, mir, 0, 1);
+        } else {
+            assert(mir->ssaRep->numDefs == 1);
+            rlDest = getDestLoc(cUnit, mir, 0);
+        }
+    }
+
+
     switch (opCode) {
         case OP_CMPL_FLOAT:
         case OP_CMPG_FLOAT:
         case OP_CMPL_DOUBLE:
         case OP_CMPG_DOUBLE:
-            return genCmpX(cUnit, mir, vA, vB, vC);
+            return handleCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
         case OP_CMP_LONG:
-            genCmpLong(cUnit, mir, vA, vB, vC);
+            genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
             break;
         case OP_AGET_WIDE:
-            genArrayGet(cUnit, mir, LONG, vB, vC, vA, 3);
+            genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
             break;
         case OP_AGET:
         case OP_AGET_OBJECT:
-            genArrayGet(cUnit, mir, WORD, vB, vC, vA, 2);
+            genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
             break;
         case OP_AGET_BOOLEAN:
-            genArrayGet(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
+            genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
             break;
         case OP_AGET_BYTE:
-            genArrayGet(cUnit, mir, SIGNED_BYTE, vB, vC, vA, 0);
+            genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
             break;
         case OP_AGET_CHAR:
-            genArrayGet(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
+            genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
             break;
         case OP_AGET_SHORT:
-            genArrayGet(cUnit, mir, SIGNED_HALF, vB, vC, vA, 1);
+            genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
             break;
         case OP_APUT_WIDE:
-            genArrayPut(cUnit, mir, LONG, vB, vC, vA, 3);
+            genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
             break;
         case OP_APUT:
         case OP_APUT_OBJECT:
-            genArrayPut(cUnit, mir, WORD, vB, vC, vA, 2);
+            genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
             break;
         case OP_APUT_SHORT:
         case OP_APUT_CHAR:
-            genArrayPut(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
+            genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
             break;
         case OP_APUT_BYTE:
         case OP_APUT_BOOLEAN:
-            genArrayPut(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
+            genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
             break;
         default:
             return true;
@@ -3080,12 +3279,15 @@ static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
     OpCode dalvikOpCode = mir->dalvikInsn.opCode;
     switch (dalvikOpCode) {
         case OP_FILL_ARRAY_DATA: {
-            loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
-            loadValue(cUnit, mir->dalvikInsn.vA, r0);
+            RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+            // Making a call - use explicit registers
+            genExportPC(cUnit, mir);
+            loadValueDirectFixed(cUnit, rlSrc, r0);
+            loadConstant(cUnit, r3, (int)dvmInterpHandleFillArrayData);
             loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
                  (int) (cUnit->method->insns + mir->offset));
-            genExportPC(cUnit, mir, r2, r3 );
-            opReg(cUnit, OP_BLX, r4PC);
+            opReg(cUnit, kOpBlx, r2);
+            clobberCallRegs(cUnit);
             genZeroCheck(cUnit, r0, mir->offset, NULL);
             break;
         }
@@ -3093,25 +3295,31 @@ static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
          * TODO
          * - Add a 1 to 3-entry per-location cache here to completely
          *   bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
-         * - Use out-of-line handlers for both of these
+         * - Use out-of-line handlers for both of these.  These ops
+         *   handle their own register allocation.
          */
         case OP_PACKED_SWITCH:
         case OP_SPARSE_SWITCH: {
+            RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+            loadValueDirectFixed(cUnit, rlSrc, r1);
+            lockAllTemps(cUnit);
+            // Exit to the interpreter, setting up r4PC
             if (dalvikOpCode == OP_PACKED_SWITCH) {
                 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
             } else {
                 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
             }
-            loadValue(cUnit, mir->dalvikInsn.vA, r1);
             loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
                  (int) (cUnit->method->insns + mir->offset));
-            opReg(cUnit, OP_BLX, r4PC);
+            opReg(cUnit, kOpBlx, r4PC);
+            clobberCallRegs(cUnit);
             loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
             loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                          jitToInterpEntries.dvmJitToInterpNoChain), r2);
-            opRegReg(cUnit, OP_ADD, r0, r0);
-            opRegRegReg(cUnit, OP_ADD, r4PC, r0, r1);
-            opReg(cUnit, OP_BLX, r2);
+            opRegReg(cUnit, kOpAdd, r0, r0);
+            opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
+            opReg(cUnit, kOpBlx, r2);
+            clobberCallRegs(cUnit);
             break;
         }
         default:
@@ -3216,12 +3424,7 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
                                      calleeMethod);
             break;
         }
-/*
- * TODO:  When we move to using upper registers in Thumb2, make sure
- *        the register allocater is told that r8, r9, & r10 are killed
- *        here.
- */
-        /*
+    /*
          * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
          *                    BBBB, method, method->clazz->pDvmDex)
          *
@@ -3290,6 +3493,9 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
             ArmLIR *predChainingCell = &labelList[bb->taken->id];
             int methodIndex = dInsn->vB;
 
+            /* Ensure that nothing is both live and dirty */
+            flushAllRegs(cUnit);
+
             if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
             else
@@ -3303,12 +3509,12 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
 
             /* r1 = &retChainingCell */
             ArmLIR *addrRetChain =
-                opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
+                opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
             addrRetChain->generic.target = (LIR *) retChainingCell;
 
             /* r2 = &predictedChainingCell */
             ArmLIR *predictedChainingCell =
-                opRegRegImm(cUnit, OP_ADD, r2, rpc, 0, rNone);
+                opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
             predictedChainingCell->generic.target = (LIR *) predChainingCell;
 
             genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
@@ -3323,7 +3529,7 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
             if (pcrLabel == NULL) {
                 int dPC = (int) (cUnit->method->insns + mir->offset);
                 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
-                pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
+                pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
                 pcrLabel->operands[0] = dPC;
                 pcrLabel->operands[1] = mir->offset;
                 /* Insert the place holder to the growable list */
@@ -3343,12 +3549,12 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
              */
 
             /* Save count, &predictedChainCell, and class to high regs first */
-            opRegReg(cUnit, OP_MOV, r8, r1);
-            opRegReg(cUnit, OP_MOV, r9, r2);
-            opRegReg(cUnit, OP_MOV, r10, r3);
+            genRegCopy(cUnit, r8, r1);
+            genRegCopy(cUnit, r9, r2);
+            genRegCopy(cUnit, r10, r3);
 
             /* r0 now contains this->clazz */
-            opRegReg(cUnit, OP_MOV, r0, r3);
+            genRegCopy(cUnit, r0, r3);
 
             /* r1 = BBBB */
             loadConstant(cUnit, r1, dInsn->vB);
@@ -3361,22 +3567,22 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
 
             loadConstant(cUnit, r7,
                          (intptr_t) dvmFindInterfaceMethodInCache);
-            opReg(cUnit, OP_BLX, r7);
+            opReg(cUnit, kOpBlx, r7);
 
             /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
 
-            opRegReg(cUnit, OP_MOV, r1, r8);
+            genRegCopy(cUnit, r1, r8);
 
             /* Check if rechain limit is reached */
-            opRegImm(cUnit, OP_CMP, r1, 0, rNone);
+            opRegImm(cUnit, kOpCmp, r1, 0);
 
-            ArmLIR *bypassRechaining = opCondBranch(cUnit, ARM_COND_GT);
+            ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
 
             loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                          jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
 
-            opRegReg(cUnit, OP_MOV, r2, r9);
-            opRegReg(cUnit, OP_MOV, r3, r10);
+            genRegCopy(cUnit, r2, r9);
+            genRegCopy(cUnit, r3, r10);
 
             /*
              * r0 = calleeMethod
@@ -3387,10 +3593,10 @@ static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
              * when patching the chaining cell and will be clobbered upon
              * returning so it will be reconstructed again.
              */
-            opReg(cUnit, OP_BLX, r7);
+            opReg(cUnit, kOpBlx, r7);
 
             /* r1 = &retChainingCell */
-            addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
+            addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
             addrRetChain->generic.target = (LIR *) retChainingCell;
 
             bypassRechaining->generic.target = (LIR *) addrRetChain;
@@ -3489,7 +3695,8 @@ static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
             const InlineOperation* inLineTable = dvmGetInlineOpsTable();
             int offset = offsetof(InterpState, retval);
             int operation = dInsn->vB;
-
+            int tReg1;
+            int tReg2;
             switch (operation) {
                 case INLINE_EMPTYINLINEMETHOD:
                     return false;  /* Nop */
@@ -3514,9 +3721,15 @@ static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
                 case INLINE_MATH_SIN:
                         break;   /* Handle with C routine */
                 case INLINE_MATH_ABS_FLOAT:
-                    return genInlinedAbsFloat(cUnit, mir);
+                    if (genInlinedAbsFloat(cUnit, mir))
+                        return false;
+                    else
+                        break;
                 case INLINE_MATH_ABS_DOUBLE:
-                    return genInlinedAbsDouble(cUnit, mir);
+                    if (genInlinedAbsDouble(cUnit, mir))
+                        return false;
+                    else
+                        break;
                 case INLINE_STRING_COMPARETO:
                 case INLINE_STRING_EQUALS:
                 case INLINE_STRING_INDEXOF_I:
@@ -3525,34 +3738,19 @@ static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
                 default:
                     dvmAbort();
             }
-
-            /* Materialize pointer to retval & push */
-            opRegReg(cUnit, OP_MOV, r4PC, rGLUE);
-            opRegImm(cUnit, OP_ADD, r4PC, offset, rNone);
-
-            /* Push r4 and (just to take up space) r5) */
-            opImm(cUnit, OP_PUSH, (1 << r4PC | 1 << rFP));
-
-            /* Get code pointer to inline routine */
+            clobberCallRegs(cUnit);
+            clobberReg(cUnit, r4PC);
+            clobberReg(cUnit, r7);
+            opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
+            opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
             loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
-
-            /* Export PC */
-            genExportPC(cUnit, mir, r0, r1 );
-
-            /* Load arguments to r0 through r3 as applicable */
+            genExportPC(cUnit, mir);
             for (i=0; i < dInsn->vA; i++) {
-                loadValue(cUnit, dInsn->arg[i], i);
+                loadValueDirect(cUnit, getSrcLoc(cUnit, mir, i), i);
             }
-            /* Call inline routine */
-            opReg(cUnit, OP_BLX, r4PC);
-
-            /* Strip frame */
-            opRegImm(cUnit, OP_ADD, r13, 8, rNone);
-
-            /* Did we throw? If so, redo under interpreter*/
+            opReg(cUnit, kOpBlx, r4PC);
+            opRegImm(cUnit, kOpAdd, r13, 8);
             genZeroCheck(cUnit, r0, mir->offset, NULL);
-
-            resetRegisterScoreboard(cUnit);
             break;
         }
         default:
@@ -3563,9 +3761,14 @@ static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
 
 static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
 {
-    loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
-    loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
-    storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
+    //TUNING: We're using core regs here - not optimal when target is a double
+    RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
+    RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+    loadConstantValue(cUnit, rlResult.lowReg,
+                      mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
+    loadConstantValue(cUnit, rlResult.highReg,
+                      (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
+    storeValueWide(cUnit, rlDest, rlResult);
     return false;
 }
 
@@ -3581,7 +3784,7 @@ static void handleNormalChainingCell(CompilationUnit *cUnit,
 {
     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                  jitToInterpEntries.dvmJitToInterpNormal), r0);
-    opReg(cUnit, OP_BLX, r0);
+    opReg(cUnit, kOpBlx, r0);
     addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
 }
 
@@ -3594,7 +3797,7 @@ static void handleHotChainingCell(CompilationUnit *cUnit,
 {
     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                  jitToInterpEntries.dvmJitToTraceSelect), r0);
-    opReg(cUnit, OP_BLX, r0);
+    opReg(cUnit, kOpBlx, r0);
     addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
 }
 
@@ -3604,13 +3807,13 @@ static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
                                              unsigned int offset)
 {
 #if defined(WITH_SELF_VERIFICATION)
-    newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
+    newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
         offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
 #else
-    newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
+    newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
         offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
 #endif
-    newLIR1(cUnit, THUMB_BLX_R, r0);
+    newLIR1(cUnit, kThumbBlxR, r0);
     addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
 }
 
@@ -3621,7 +3824,7 @@ static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
 {
     loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                  jitToInterpEntries.dvmJitToTraceSelect), r0);
-    opReg(cUnit, OP_BLX, r0);
+    opReg(cUnit, kOpBlx, r0);
     addWordData(cUnit, (int) (callee->insns), true);
 }
 
@@ -3658,12 +3861,12 @@ static void handlePCReconstruction(CompilationUnit *cUnit,
     }
 }
 
-static char *extendedMIROpNames[MIR_OP_LAST - MIR_OP_FIRST] = {
-    "MIR_OP_PHI",
-    "MIR_OP_NULL_N_RANGE_UP_CHECK",
-    "MIR_OP_NULL_N_RANGE_DOWN_CHECK",
-    "MIR_OP_LOWER_BOUND_CHECK",
-    "MIR_OP_PUNT",
+static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
+    "kMirOpPhi",
+    "kMirOpNullNRangeUpCheck",
+    "kMirOpNullNRangeDownCheck",
+    "kMirOpLowerBound",
+    "kMirOpPunt",
 };
 
 /*
@@ -3676,22 +3879,29 @@ static char *extendedMIROpNames[MIR_OP_LAST - MIR_OP_FIRST] = {
  */
 static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
 {
+    /*
+     * NOTE: these synthesized blocks don't have ssa names assigned
+     * for Dalvik registers.  However, because they dominate the following
+     * blocks we can simply use the Dalvik name w/ subscript 0 as the
+     * ssa name.
+     */
     DecodedInstruction *dInsn = &mir->dalvikInsn;
     const int lenOffset = offsetof(ArrayObject, length);
-    const int regArray = 0;
-    const int regIdxEnd = NEXT_REG(regArray);
-    const int regLength = regArray;
     const int maxC = dInsn->arg[0];
     const int minC = dInsn->arg[1];
+    int regLength;
+    RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
+    RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
 
     /* regArray <- arrayRef */
-    loadValue(cUnit, mir->dalvikInsn.vA, regArray);
-    loadValue(cUnit, mir->dalvikInsn.vC, regIdxEnd);
-    genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
+    rlArray = loadValue(cUnit, rlArray, kCoreReg);
+    rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
+    genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
 
     /* regLength <- len(arrayRef) */
-    loadWordDisp(cUnit, regArray, lenOffset, regLength);
+    regLength = allocTemp(cUnit);
+    loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
 
     int delta = maxC;
     /*
@@ -3703,10 +3913,13 @@ static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
     }
 
     if (delta) {
-        opRegImm(cUnit, OP_ADD, regIdxEnd, delta, regIdxEnd);
+        int tReg = allocTemp(cUnit);
+        opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
+        rlIdxEnd.lowReg = tReg;
+        freeTemp(cUnit, tReg);
     }
     /* Punt if "regIdxEnd < len(Array)" is false */
-    genRegRegCheck(cUnit, ARM_COND_GE, regIdxEnd, regLength, 0,
+    genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
 }
 
@@ -3722,27 +3935,30 @@ static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
 {
     DecodedInstruction *dInsn = &mir->dalvikInsn;
     const int lenOffset = offsetof(ArrayObject, length);
-    const int regArray = 0;
-    const int regIdxInit = NEXT_REG(regArray);
-    const int regLength = regArray;
+    const int regLength = allocTemp(cUnit);
     const int maxC = dInsn->arg[0];
     const int minC = dInsn->arg[1];
+    RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
+    RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
 
     /* regArray <- arrayRef */
-    loadValue(cUnit, mir->dalvikInsn.vA, regArray);
-    loadValue(cUnit, mir->dalvikInsn.vB, regIdxInit);
-    genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
+    rlArray = loadValue(cUnit, rlArray, kCoreReg);
+    rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
+    genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
 
     /* regLength <- len(arrayRef) */
-    loadWordDisp(cUnit, regArray, lenOffset, regLength);
+    loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
 
     if (maxC) {
-        opRegImm(cUnit, OP_ADD, regIdxInit, maxC, regIdxInit);
+        int tReg = allocTemp(cUnit);
+        opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
+        rlIdxInit.lowReg = tReg;
+        freeTemp(cUnit, tReg);
     }
 
     /* Punt if "regIdxInit < len(Array)" is false */
-    genRegRegCheck(cUnit, ARM_COND_GE, regIdxInit, regLength, 0,
+    genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
 }
 
@@ -3753,45 +3969,45 @@ static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
 static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
 {
     DecodedInstruction *dInsn = &mir->dalvikInsn;
-    const int regIdx = 0;
     const int minC = dInsn->vB;
+    RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
 
     /* regIdx <- initial index value */
-    loadValue(cUnit, mir->dalvikInsn.vA, regIdx);
+    rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
 
     /* Punt if "regIdxInit + minC >= 0" is false */
-    genRegImmCheck(cUnit, ARM_COND_LT, regIdx, -minC, 0,
+    genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
 }
 
 /* Extended MIR instructions like PHI */
 static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
 {
-    int opOffset = mir->dalvikInsn.opCode - MIR_OP_FIRST;
+    int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
     char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
                                false);
     strcpy(msg, extendedMIROpNames[opOffset]);
-    newLIR1(cUnit, ARM_PSEUDO_EXTENDED_MIR, (int) msg);
+    newLIR1(cUnit, kArmPseudoExtended, (int) msg);
 
     switch (mir->dalvikInsn.opCode) {
-        case MIR_OP_PHI: {
+        case kMirOpPhi: {
             char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
-            newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
+            newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
             break;
         }
-        case MIR_OP_NULL_N_RANGE_UP_CHECK: {
+        case kMirOpNullNRangeUpCheck: {
             genHoistedChecksForCountUpLoop(cUnit, mir);
             break;
         }
-        case MIR_OP_NULL_N_RANGE_DOWN_CHECK: {
+        case kMirOpNullNRangeDownCheck: {
             genHoistedChecksForCountDownLoop(cUnit, mir);
             break;
         }
-        case MIR_OP_LOWER_BOUND_CHECK: {
+        case kMirOpLowerBound: {
             genHoistedLowerBoundCheck(cUnit, mir);
             break;
         }
-        case MIR_OP_PUNT: {
+        case kMirOpPunt: {
             genUnconditionalBranch(cUnit,
                                    (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
             break;
@@ -3813,7 +4029,7 @@ static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
 {
     /* Set up the place holder to reconstruct this Dalvik PC */
     ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
-    pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
+    pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
     pcrLabel->operands[0] =
         (int) (cUnit->method->insns + entry->startOffset);
     pcrLabel->operands[1] = entry->startOffset;
@@ -3825,13 +4041,13 @@ static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
      * other branch to the PCR cell to punt.
      */
     ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
-    branchToBody->opCode = THUMB_B_UNCOND;
+    branchToBody->opCode = kThumbBUncond;
     branchToBody->generic.target = (LIR *) bodyLabel;
     setupResourceMasks(branchToBody);
     cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
 
     ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
-    branchToPCR->opCode = THUMB_B_UNCOND;
+    branchToPCR->opCode = kThumbBUncond;
     branchToPCR->generic.target = (LIR *) pcrLabel;
     setupResourceMasks(branchToPCR);
     cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
@@ -3842,13 +4058,13 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
     /* Used to hold the labels of each block */
     ArmLIR *labelList =
         dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
-    GrowableList chainingListByType[CHAINING_CELL_LAST];
+    GrowableList chainingListByType[kChainingCellLast];
     int i;
 
     /*
      * Initialize various types chaining lists.
      */
-    for (i = 0; i < CHAINING_CELL_LAST; i++) {
+    for (i = 0; i < kChainingCellLast; i++) {
         dvmInitGrowableList(&chainingListByType[i], 2);
     }
 
@@ -3870,21 +4086,21 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
          *       add   r1, #1
          *       str   r1, [r0]
          */
-        newLIR1(cUnit, ARM_16BIT_DATA, 0);
-        newLIR1(cUnit, ARM_16BIT_DATA, 0);
+        newLIR1(cUnit, kArm16BitData, 0);
+        newLIR1(cUnit, kArm16BitData, 0);
         cUnit->chainCellOffsetLIR =
-            (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
+            (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
         cUnit->headerSize = 6;
         /* Thumb instruction used directly here to ensure correct size */
-        newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc);
-        newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
-        newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
-        newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
-        newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
+        newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc);
+        newLIR2(cUnit, kThumbSubRI8, r0, 10);
+        newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
+        newLIR2(cUnit, kThumbAddRI8, r1, 1);
+        newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
     } else {
          /* Just reserve 2 bytes for the chain cell offset */
         cUnit->chainCellOffsetLIR =
-            (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
+            (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
         cUnit->headerSize = 2;
     }
 
@@ -3895,7 +4111,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
 
         labelList[i].operands[0] = blockList[i]->startOffset;
 
-        if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
+        if (blockList[i]->blockType >= kChainingCellLast) {
             /*
              * Append the label pseudo LIR first. Chaining cells will be handled
              * separately afterwards.
@@ -3903,78 +4119,80 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
             dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
         }
 
-        if (blockList[i]->blockType == ENTRY_BLOCK) {
-            labelList[i].opCode = ARM_PSEUDO_ENTRY_BLOCK;
+        if (blockList[i]->blockType == kEntryBlock) {
+            labelList[i].opCode = ARM_PSEUDO_kEntryBlock;
             if (blockList[i]->firstMIRInsn == NULL) {
                 continue;
             } else {
               setupLoopEntryBlock(cUnit, blockList[i],
                                   &labelList[blockList[i]->fallThrough->id]);
             }
-        } else if (blockList[i]->blockType == EXIT_BLOCK) {
-            labelList[i].opCode = ARM_PSEUDO_EXIT_BLOCK;
+        } else if (blockList[i]->blockType == kExitBlock) {
+            labelList[i].opCode = ARM_PSEUDO_kExitBlock;
             goto gen_fallthrough;
-        } else if (blockList[i]->blockType == DALVIK_BYTECODE) {
-            labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
+        } else if (blockList[i]->blockType == kDalvikByteCode) {
+            labelList[i].opCode = kArmPseudoNormalBlockLabel;
             /* Reset the register state */
-            resetRegisterScoreboard(cUnit);
+            resetRegPool(cUnit);
+            clobberAllRegs(cUnit);
+            resetNullCheckTracker(cUnit);
         } else {
             switch (blockList[i]->blockType) {
-                case CHAINING_CELL_NORMAL:
-                    labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
+                case kChainingCellNormal:
+                    labelList[i].opCode = ARM_PSEUDO_kChainingCellNormal;
                     /* handle the codegen later */
                     dvmInsertGrowableList(
-                        &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
+                        &chainingListByType[kChainingCellNormal], (void *) i);
                     break;
-                case CHAINING_CELL_INVOKE_SINGLETON:
+                case kChainingCellInvokeSingleton:
                     labelList[i].opCode =
-                        ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
+                        ARM_PSEUDO_kChainingCellInvokeSingleton;
                     labelList[i].operands[0] =
                         (int) blockList[i]->containingMethod;
                     /* handle the codegen later */
                     dvmInsertGrowableList(
-                        &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
+                        &chainingListByType[kChainingCellInvokeSingleton],
                         (void *) i);
                     break;
-                case CHAINING_CELL_INVOKE_PREDICTED:
+                case kChainingCellInvokePredicted:
                     labelList[i].opCode =
-                        ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
+                        ARM_PSEUDO_kChainingCellInvokePredicted;
                     /* handle the codegen later */
                     dvmInsertGrowableList(
-                        &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
+                        &chainingListByType[kChainingCellInvokePredicted],
                         (void *) i);
                     break;
-                case CHAINING_CELL_HOT:
+                case kChainingCellHot:
                     labelList[i].opCode =
-                        ARM_PSEUDO_CHAINING_CELL_HOT;
+                        ARM_PSEUDO_kChainingCellHot;
                     /* handle the codegen later */
                     dvmInsertGrowableList(
-                        &chainingListByType[CHAINING_CELL_HOT],
+                        &chainingListByType[kChainingCellHot],
                         (void *) i);
                     break;
-                case PC_RECONSTRUCTION:
+                case kPCReconstruction:
                     /* Make sure exception handling block is next */
                     labelList[i].opCode =
-                        ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
+                        ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL;
                     assert (i == cUnit->numBlocks - 2);
                     handlePCReconstruction(cUnit, &labelList[i+1]);
                     break;
-                case EXCEPTION_HANDLING:
-                    labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
+                case kExceptionHandling:
+                    labelList[i].opCode = kArmPseudoEHBlockLabel;
                     if (cUnit->pcReconstructionList.numUsed) {
                         loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
                                      jitToInterpEntries.dvmJitToInterpPunt),
                                      r1);
-                        opReg(cUnit, OP_BLX, r1);
+                        opReg(cUnit, kOpBlx, r1);
                     }
                     break;
 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
-                case CHAINING_CELL_BACKWARD_BRANCH:
+                case kChainingCellBackwardBranch:
                     labelList[i].opCode =
-                        ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
+                        ARM_PSEUDO_kChainingCellBackwardBranch;
                     /* handle the codegen later */
                     dvmInsertGrowableList(
-                        &chainingListByType[CHAINING_CELL_BACKWARD_BRANCH],
+                        &chainingListByType[kChainingCellBackwardBranch],
                         (void *) i);
                     break;
 #endif
@@ -3987,22 +4205,33 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
         ArmLIR *headLIR = NULL;
 
         for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
-            if (mir->dalvikInsn.opCode >= MIR_OP_FIRST) {
+
+            resetRegPool(cUnit);
+            if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
+                clobberAllRegs(cUnit);
+            }
+
+            if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
+                resetDefTracking(cUnit);
+            }
+
+            if (mir->dalvikInsn.opCode >= kMirOpFirst) {
                 handleExtendedMIR(cUnit, mir);
                 continue;
             }
 
+
             OpCode dalvikOpCode = mir->dalvikInsn.opCode;
             InstructionFormat dalvikFormat =
                 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
             ArmLIR *boundaryLIR =
-                newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
+                newLIR2(cUnit, ARM_PSEUDO_kDalvikByteCode_BOUNDARY,
                         mir->offset,
                         (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
                        );
             if (mir->ssaRep) {
                 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
-                newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
+                newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
             }
 
             /* Remember the first LIR for this block */
@@ -4124,7 +4353,7 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
             }
         }
 
-        if (blockList[i]->blockType == ENTRY_BLOCK) {
+        if (blockList[i]->blockType == kEntryBlock) {
             dvmCompilerAppendLIR(cUnit,
                                  (LIR *) cUnit->loopAnalysis->branchToBody);
             dvmCompilerAppendLIR(cUnit,
@@ -4153,7 +4382,7 @@ gen_fallthrough:
     }
 
     /* Handle the chaining cells in predefined order */
-    for (i = 0; i < CHAINING_CELL_LAST; i++) {
+    for (i = 0; i < kChainingCellLast; i++) {
         size_t j;
         int *blockIdList = (int *) chainingListByType[i].elemList;
 
@@ -4170,35 +4399,36 @@ gen_fallthrough:
             int blockId = blockIdList[j];
 
             /* Align this chaining cell first */
-            newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
+            newLIR0(cUnit, kArmPseudoPseudoAlign4);
 
             /* Insert the pseudo chaining instruction */
             dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
 
 
             switch (blockList[blockId]->blockType) {
-                case CHAINING_CELL_NORMAL:
+                case kChainingCellNormal:
                     handleNormalChainingCell(cUnit,
                       blockList[blockId]->startOffset);
                     break;
-                case CHAINING_CELL_INVOKE_SINGLETON:
+                case kChainingCellInvokeSingleton:
                     handleInvokeSingletonChainingCell(cUnit,
                         blockList[blockId]->containingMethod);
                     break;
-                case CHAINING_CELL_INVOKE_PREDICTED:
+                case kChainingCellInvokePredicted:
                     handleInvokePredictedChainingCell(cUnit);
                     break;
-                case CHAINING_CELL_HOT:
+                case kChainingCellHot:
                     handleHotChainingCell(cUnit,
                         blockList[blockId]->startOffset);
                     break;
 #if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
-                case CHAINING_CELL_BACKWARD_BRANCH:
+                case kChainingCellBackwardBranch:
                     handleBackwardBranchChainingCell(cUnit,
                         blockList[blockId]->startOffset);
                     break;
 #endif
                 default:
+                    LOGE("Bad blocktype %d", blockList[blockId]->blockType);
                     dvmAbort();
                     break;
             }
@@ -4291,7 +4521,7 @@ bool dvmCompilerArchInit()
 {
     int i;
 
-    for (i = 0; i < ARM_LAST; i++) {
+    for (i = 0; i < kArmLast; i++) {
         if (EncodingMap[i].opCode != i) {
             LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
                  EncodingMap[i].name, i, EncodingMap[i].opCode);
index b484cd2..414c343 100644 (file)
@@ -40,19 +40,52 @@ static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
                                          ArmLIR *branch,
                                          ArmLIR *pcrLabel);
 static void genBarrier(CompilationUnit *cUnit);
+static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
+                             RegisterClass opKind);
+static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
+                             RegisterClass opKind);
+static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
+static void storeValue(CompilationUnit *cUnit, RegLocation rlDst,
+                       RegLocation rlSrc);
+static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDst,
+                           RegLocation rlSrc);
+static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
+                                 int reg1);
+static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
+                                int regLo, int regHi);
+static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
+                                     int regLo, int regHi);
+static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
+                            int dOffset, ArmLIR *pcrLabel);
+static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
+                            int displacement, int rDest);
+static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
+                            int displacement, int rDest);
+static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir, bool fpHint);
+static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
+                                      bool fpHint);
+static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
+                              int rBound, int dOffset, ArmLIR *pcrLabel);
+static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir);
+static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
+                                     ArmConditionCode cond,
+                                     int reg1, int reg2, int dOffset,
+                                     ArmLIR *pcrLabel);
 
 /* Routines which must be supplied by the variant-specific code */
 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode);
 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir);
 static bool genInlineCos(CompilationUnit *cUnit, MIR *mir);
 static bool genInlineSin(CompilationUnit *cUnit, MIR *mir);
-static bool genConversion(CompilationUnit *cUnit, MIR *mir);
-static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
-                            int vSrc1, int vSrc2);
-static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
-                             int vSrc1, int vSrc2);
-static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
-                    int vSrc2);
+static bool handleConversion(CompilationUnit *cUnit, MIR *mir);
 static bool compilerArchVariantInit();
+static bool handleArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+                               RegLocation rlDest, RegLocation rlSrc1,
+                               RegLocation rlSrc2);
+static bool handleArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+                                RegLocation rlDest, RegLocation rlSrc1,
+                                RegLocation rlSrc2);
+static bool handleCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                        RegLocation rlSrc1, RegLocation rlSrc2);
 
 #endif /* _DALVIK_VM_COMPILER_CODEGEN_ARM_CODEGEN_H */
index 687b7d2..1cfa32b 100644 (file)
@@ -31,7 +31,7 @@ static void applyRedundantBranchElimination(CompilationUnit *cUnit)
          thisLIR = NEXT_LIR(thisLIR)) {
 
         /* Branch to the next instruction */
-        if (thisLIR->opCode == THUMB_B_UNCOND) {
+        if (thisLIR->opCode == kThumbBUncond) {
             ArmLIR *nextLIR = thisLIR;
 
             while (true) {
diff --git a/vm/compiler/codegen/arm/RallocUtil.c b/vm/compiler/codegen/arm/RallocUtil.c
new file mode 100644 (file)
index 0000000..8aa5fc7
--- /dev/null
@@ -0,0 +1,1005 @@
+/*
+ * Copyright (C) 2009 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 "Codegen.h"
+#include "../../Dataflow.h"
+
+/*
+ * Register usage for 16-bit Thumb systems:
+ *     r0-r3: Temp/argument
+ *     lr(r14):      Temp for translations, return address for handlers
+ *     rGLUE(r6):    Pointer to InterpState
+ *     rFP(r5):      Dalvik frame pointer
+ *     r4, r7:       Temp for translations
+ *     r8, r9, r10:   Temp preserved across C calls
+ *     r11, ip(r12):  Temp not preserved across C calls
+ *
+ * Register usage for 32-bit Thumb systems:
+ *     r0-r3: Temp/argument
+ *     lr(r14):      Temp for translations, return address for handlers
+ *     rGLUE(r6):    Pointer to InterpState
+ *     rFP(r5):      Dalvik frame pointer
+ *     r4, r7:       Temp for translations
+ *     r8, r9, r10   Temp preserved across C calls
+ *     r11, ip(r12):      Temp not preserved across C calls
+ *     fp0-fp15:     Hot temps, not preserved across C calls
+ *     fp16-fp31:    Promotion pool
+ *
+ */
+
+static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc, OpSize size);
+static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrcLo, int rSrcHi);
+static int allocTypedTempPair(CompilationUnit *cUnit, bool fpHint,
+                              int regClass);
+static int allocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass);
+void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+                    int srcLo, int srcHi);
+static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
+static void clobberReg(CompilationUnit *cUnit, int reg);
+static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg);
+
+#define SREG(c, s) ((c)->regLocation[(s)].sRegLow)
+/*
+ * Get the "real" sreg number associated with an sReg slot.  In general,
+ * sReg values passed through codegen are the SSA names created by
+ * dataflow analysis and refer to slot numbers in the cUnit->regLocation
+ * array.  However, renaming is accomplished by simply replacing RegLocation
+ * entries in the cUnit->reglocation[] array.  Therefore, when location
+ * records for operands are first created, we need to ask the locRecord
+ * identified by the dataflow pass what it's new name is.
+ */
+
+static inline int hiSReg(int lowSreg) {
+    return (lowSreg == INVALID_SREG) ? INVALID_SREG : lowSreg + 1;
+}
+
+static int sReg2vReg(CompilationUnit *cUnit, int sReg)
+{
+    assert(sReg != INVALID_SREG);
+    return DECODE_REG(dvmConvertSSARegToDalvik(cUnit, sReg));
+}
+
+static bool liveOut(CompilationUnit *cUnit, int sReg)
+{
+    //TODO: fully implement
+    return true;
+}
+
+/*
+ * Free all allocated temps in the temp pools.  Note that this does
+ * not affect the "liveness" of a temp register, which will stay
+ * live until it is either explicitly killed or reallocated.
+ */
+static void resetRegPool(CompilationUnit *cUnit)
+{
+    int i;
+    for (i=0; i < cUnit->regPool->numCoreTemps; i++) {
+        cUnit->regPool->coreTemps[i].inUse = false;
+    }
+    for (i=0; i < cUnit->regPool->numFPTemps; i++) {
+        cUnit->regPool->FPTemps[i].inUse = false;
+    }
+}
+
+ /* Set up temp & preserved register pools specialized by target */
+static void initPool(RegisterInfo *regs, int *regNums, int num)
+{
+    int i;
+    for (i=0; i < num; i++) {
+        regs[i].reg = regNums[i];
+        regs[i].inUse = false;
+        regs[i].pair = false;
+        regs[i].live = false;
+        regs[i].dirty = false;
+        regs[i].sReg = INVALID_SREG;
+    }
+}
+
+static void dumpRegPool(RegisterInfo *p, int numRegs)
+{
+    int i;
+    LOGE("================================================");
+    for (i=0; i < numRegs; i++ ){
+        LOGE("R[%d]: U:%d, P:%d, part:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x",
+           p[i].reg, p[i].inUse, p[i].pair, p[i].partner, p[i].live,
+           p[i].dirty, p[i].sReg,(int)p[i].defStart, (int)p[i].defEnd);
+    }
+    LOGE("================================================");
+}
+
+static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps,
+                         bool required)
+{
+    int i;
+    //Tuning: redo this to widen the live window on freed temps
+    for (i=0; i< numTemps; i++) {
+        if (!p[i].inUse && !p[i].live) {
+            clobberReg(cUnit, p[i].reg);
+            p[i].inUse = true;
+            p[i].pair = false;
+            return p[i].reg;
+        }
+    }
+    for (i=0; i< numTemps; i++) {
+        if (!p[i].inUse) {
+            clobberReg(cUnit, p[i].reg);
+            p[i].inUse = true;
+            p[i].pair = false;
+            return p[i].reg;
+        }
+    }
+    if (required) {
+        LOGE("No free temp registers");
+        assert(0);
+    }
+    return -1;  // No register available
+}
+
+//REDO: too many assumptions.
+static int allocTempDouble(CompilationUnit *cUnit)
+{
+    RegisterInfo *p = cUnit->regPool->FPTemps;
+    int numTemps = cUnit->regPool->numFPTemps;
+    int i;
+
+    for (i=0; i < numTemps; i+=2) {
+        if ((!p[i].inUse && !p[i].live) &&
+            (!p[i+1].inUse && !p[i+1].live)) {
+            clobberReg(cUnit, p[i].reg);
+            clobberReg(cUnit, p[i+1].reg);
+            p[i].inUse = true;
+            p[i+1].inUse = true;
+            assert((p[i].reg+1) == p[i+1].reg);
+            assert((p[i].reg & 0x1) == 0);
+            return p[i].reg;
+        }
+    }
+    for (i=0; i < numTemps; i+=2) {
+        if (!p[i].inUse && !p[i+1].inUse) {
+            clobberReg(cUnit, p[i].reg);
+            clobberReg(cUnit, p[i+1].reg);
+            p[i].inUse = true;
+            p[i+1].inUse = true;
+            assert((p[i].reg+1) == p[i+1].reg);
+            assert((p[i].reg & 0x1) == 0);
+            return p[i].reg;
+        }
+    }
+    LOGE("No free temp registers");
+    *((int*)0) = 0;  //For development, die instantly.  Later abort translation
+    dvmAbort();
+    return -1;
+}
+
+/* Return a temp if one is available, -1 otherwise */
+static int allocFreeTemp(CompilationUnit *cUnit)
+{
+    return allocTempBody(cUnit, cUnit->regPool->coreTemps,
+                         cUnit->regPool->numCoreTemps, true);
+}
+
+static int allocTemp(CompilationUnit *cUnit)
+{
+    return allocTempBody(cUnit, cUnit->regPool->coreTemps,
+                         cUnit->regPool->numCoreTemps, true);
+}
+
+static int allocTempFloat(CompilationUnit *cUnit)
+{
+    return allocTempBody(cUnit, cUnit->regPool->FPTemps,
+                         cUnit->regPool->numFPTemps, true);
+}
+
+static RegisterInfo *allocLiveBody(RegisterInfo *p, int numTemps, int sReg)
+{
+    int i;
+    if (sReg == -1)
+        return NULL;
+    for (i=0; i < numTemps; i++) {
+        if (p[i].live && (p[i].sReg == sReg)) {
+            p[i].inUse = true;
+            return &p[i];
+        }
+    }
+    return NULL;
+}
+
+static RegisterInfo *allocLive(CompilationUnit *cUnit, int sReg,
+                               int regClass)
+{
+    RegisterInfo *res = NULL;
+    switch(regClass) {
+        case kAnyReg:
+            res = allocLiveBody(cUnit->regPool->FPTemps,
+                                cUnit->regPool->numFPTemps, sReg);
+            if (res)
+                break;
+            /* Intentional fallthrough */
+        case kCoreReg:
+            res = allocLiveBody(cUnit->regPool->coreTemps,
+                                cUnit->regPool->numCoreTemps, sReg);
+            break;
+        case kFPReg:
+            res = allocLiveBody(cUnit->regPool->FPTemps,
+                                cUnit->regPool->numFPTemps, sReg);
+            break;
+        default:
+            LOGE("Invalid register type");
+            assert(0);
+            dvmAbort();
+    }
+    return res;
+}
+
+static void freeTemp(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *p = cUnit->regPool->coreTemps;
+    int numTemps = cUnit->regPool->numCoreTemps;
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            p[i].inUse = false;
+            p[i].pair = false;
+            return;
+        }
+    }
+    p = cUnit->regPool->FPTemps;
+    numTemps = cUnit->regPool->numFPTemps;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            p[i].inUse = false;
+            p[i].pair = false;
+            return;
+        }
+    }
+    LOGE("Tried to free a non-existant temp: r%d",reg);
+    dvmAbort();
+}
+
+//FIXME - this needs to also check the preserved pool.
+static RegisterInfo *isLive(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *p = cUnit->regPool->coreTemps;
+    int numTemps = cUnit->regPool->numCoreTemps;
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return p[i].live ? &p[i] : NULL;
+        }
+    }
+    p = cUnit->regPool->FPTemps;
+    numTemps = cUnit->regPool->numFPTemps;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return p[i].live ? &p[i] : NULL;
+        }
+    }
+    return NULL;
+}
+
+static RegisterInfo *isTemp(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *p = cUnit->regPool->coreTemps;
+    int numTemps = cUnit->regPool->numCoreTemps;
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return &p[i];
+        }
+    }
+    p = cUnit->regPool->FPTemps;
+    numTemps = cUnit->regPool->numFPTemps;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return &p[i];
+        }
+    }
+    return NULL;
+}
+
+static void flushRegWide(CompilationUnit *cUnit, int reg1, int reg2)
+{
+    RegisterInfo *info1 = getRegInfo(cUnit, reg1);
+    RegisterInfo *info2 = getRegInfo(cUnit, reg2);
+    assert(info1 && info2 && info1->pair && info2->pair &&
+           (info1->partner == info2->reg) &&
+           (info2->partner == info1->reg));
+    if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
+        info1->dirty = false;
+        info2->dirty = false;
+        if (sReg2vReg(cUnit, info2->sReg) < sReg2vReg(cUnit, info1->sReg))
+            info1 = info2;
+        storeBaseDispWide(cUnit, rFP, sReg2vReg(cUnit, info1->sReg) << 2,
+                          info1->reg, info1->partner);
+    }
+}
+
+static void flushReg(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    if (info->live && info->dirty) {
+        info->dirty = false;
+        storeBaseDisp(cUnit, rFP, sReg2vReg(cUnit, info->sReg) << 2, reg,
+                      kWord);
+    }
+}
+
+/* return true if found reg to clobber */
+static bool clobberRegBody(CompilationUnit *cUnit, RegisterInfo *p,
+                           int numTemps, int reg)
+{
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            if (p[i].live && p[i].dirty) {
+                if (p[i].pair) {
+                    flushRegWide(cUnit, p[i].reg, p[i].partner);
+                } else {
+                    flushReg(cUnit, p[i].reg);
+                }
+            }
+            p[i].live = false;
+            p[i].sReg = INVALID_SREG;
+            p[i].defStart = NULL;
+            p[i].defEnd = NULL;
+            if (p[i].pair) {
+                p[i].pair = false;
+                clobberReg(cUnit, p[i].partner);
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+/* Mark a temp register as dead.  Does not affect allocation state. */
+static void clobberReg(CompilationUnit *cUnit, int reg)
+{
+    if (!clobberRegBody(cUnit, cUnit->regPool->coreTemps,
+                        cUnit->regPool->numCoreTemps, reg)) {
+        clobberRegBody(cUnit, cUnit->regPool->FPTemps,
+                       cUnit->regPool->numFPTemps, reg);
+    }
+}
+
+static void clobberSRegBody(RegisterInfo *p, int numTemps, int sReg)
+{
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].sReg == sReg) {
+            p[i].live = false;
+            p[i].defStart = NULL;
+            p[i].defEnd = NULL;
+        }
+    }
+}
+
+/* Clobber any temp associated with an sReg.  Could be in either class */
+static void clobberSReg(CompilationUnit *cUnit, int sReg)
+{
+    clobberSRegBody(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps,
+                    sReg);
+    clobberSRegBody(cUnit->regPool->FPTemps, cUnit->regPool->numFPTemps,
+                    sReg);
+}
+
+static RegisterInfo *getRegInfo(CompilationUnit *cUnit, int reg)
+{
+    int numTemps = cUnit->regPool->numCoreTemps;
+    RegisterInfo *p = cUnit->regPool->coreTemps;
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return &p[i];
+        }
+    }
+    p = cUnit->regPool->FPTemps;
+    numTemps = cUnit->regPool->numFPTemps;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            return &p[i];
+        }
+    }
+    LOGE("Tried to get info on a non-existant temp: r%d",reg);
+    dvmAbort();
+    return NULL;
+}
+
+/*
+ * Similar to allocTemp(), but forces the allocation of a specific
+ * register.  No check is made to see if the register was previously
+ * allocated.  Use with caution.
+ */
+static void lockTemp(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *p = cUnit->regPool->coreTemps;
+    int numTemps = cUnit->regPool->numCoreTemps;
+    int i;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            p[i].inUse = true;
+            p[i].live = false;
+            return;
+        }
+    }
+    p = cUnit->regPool->FPTemps;
+    numTemps = cUnit->regPool->numFPTemps;
+    for (i=0; i< numTemps; i++) {
+        if (p[i].reg == reg) {
+            p[i].inUse = true;
+            p[i].live = false;
+            return;
+        }
+    }
+    LOGE("Tried to lock a non-existant temp: r%d",reg);
+    dvmAbort();
+}
+
+static void lockArgRegs(CompilationUnit *cUnit)
+{
+    lockTemp(cUnit, r0);
+    lockTemp(cUnit, r1);
+    lockTemp(cUnit, r2);
+    lockTemp(cUnit, r3);
+}
+
+/* Clobber all regs that might be used by an external C call */
+static void clobberCallRegs(CompilationUnit *cUnit)
+{
+    clobberReg(cUnit, r0);
+    clobberReg(cUnit, r1);
+    clobberReg(cUnit, r2);
+    clobberReg(cUnit, r3);
+    clobberReg(cUnit, r9); // Not sure we need to do this, be convervative
+    clobberReg(cUnit, r11);
+    clobberReg(cUnit, r12);
+    clobberReg(cUnit, rlr);
+}
+
+/* Clobber all of the temps that might be used by a handler. */
+static void clobberHandlerRegs(CompilationUnit *cUnit)
+{
+    //TUNING: reduce the set of regs used by handlers.  Only a few need lots.
+    clobberCallRegs(cUnit);
+    clobberReg(cUnit, r9);
+    clobberReg(cUnit, r10);
+}
+
+static void resetDef(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *p = getRegInfo(cUnit, reg);
+    p->defStart = NULL;
+    p->defEnd = NULL;
+}
+
+static void nullifyRange(CompilationUnit *cUnit, LIR *start, LIR *finish,
+                         int sReg1, int sReg2)
+{
+    if (start && finish) {
+        LIR *p;
+        assert(sReg1 == sReg2);
+        for (p = start; ;p = p->next) {
+            ((ArmLIR *)p)->isNop = true;
+            if (p == finish)
+                break;
+        }
+    }
+}
+
+/*
+ * Mark the beginning and end LIR of a def sequence.  Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+static void markDef(CompilationUnit *cUnit, RegLocation rl,
+                    LIR *start, LIR *finish)
+{
+    assert(!rl.wide);
+    assert(start && start->next);
+    assert(finish);
+    RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+    p->defStart = start->next;
+    p->defEnd = finish;
+}
+
+/*
+ * Mark the beginning and end LIR of a def sequence.  Note that
+ * on entry start points to the LIR prior to the beginning of the
+ * sequence.
+ */
+static void markDefWide(CompilationUnit *cUnit, RegLocation rl,
+                        LIR *start, LIR *finish)
+{
+    assert(rl.wide);
+    assert(start && start->next);
+    assert(finish);
+    RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+    resetDef(cUnit, rl.highReg);  // Only track low of pair
+    p->defStart = start->next;
+    p->defEnd = finish;
+}
+
+static RegLocation wideToNarrowLoc(CompilationUnit *cUnit, RegLocation rl)
+{
+    assert(rl.wide);
+    if (rl.location == kLocPhysReg) {
+        RegisterInfo *infoLo = getRegInfo(cUnit, rl.lowReg);
+        RegisterInfo *infoHi = getRegInfo(cUnit, rl.highReg);
+        if (!infoLo->pair) {
+            dumpRegPool(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps);
+            assert(infoLo->pair);
+        }
+        if (!infoHi->pair) {
+            dumpRegPool(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps);
+            assert(infoHi->pair);
+        }
+        assert(infoLo->pair);
+        assert(infoHi->pair);
+        assert(infoLo->partner == infoHi->reg);
+        assert(infoHi->partner == infoLo->reg);
+        infoLo->pair = false;
+        infoHi->pair = false;
+        infoLo->defStart = NULL;
+        infoLo->defEnd = NULL;
+        infoHi->defStart = NULL;
+        infoHi->defEnd = NULL;
+    }
+    rl.wide = false;
+    return rl;
+}
+
+static void resetDefLoc(CompilationUnit *cUnit, RegLocation rl)
+{
+    assert(!rl.wide);
+    if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
+        RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+        assert(!p->pair);
+        nullifyRange(cUnit, p->defStart, p->defEnd,
+                     p->sReg, rl.sRegLow);
+    }
+    resetDef(cUnit, rl.lowReg);
+}
+
+static void resetDefLocWide(CompilationUnit *cUnit, RegLocation rl)
+{
+    assert(rl.wide);
+    if (!(gDvmJit.disableOpt & (1 << kSuppressLoads))) {
+        RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
+        assert(p->pair);
+        nullifyRange(cUnit, p->defStart, p->defEnd,
+                     p->sReg, rl.sRegLow);
+    }
+    resetDef(cUnit, rl.lowReg);
+    resetDef(cUnit, rl.highReg);
+}
+
+static void resetDefTracking(CompilationUnit *cUnit)
+{
+    int i;
+    for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
+        resetDef(cUnit, cUnit->regPool->coreTemps[i].reg);
+    }
+    for (i=0; i< cUnit->regPool->numFPTemps; i++) {
+        resetDef(cUnit, cUnit->regPool->FPTemps[i].reg);
+    }
+}
+
+static void clobberAllRegs(CompilationUnit *cUnit)
+{
+    int i;
+    for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
+        clobberReg(cUnit, cUnit->regPool->coreTemps[i].reg);
+    }
+    for (i=0; i< cUnit->regPool->numFPTemps; i++) {
+        clobberReg(cUnit, cUnit->regPool->FPTemps[i].reg);
+    }
+}
+
+/* To be used when explicitly managing register use */
+static void lockAllTemps(CompilationUnit *cUnit)
+{
+    int i;
+    for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
+        lockTemp(cUnit, cUnit->regPool->coreTemps[i].reg);
+    }
+}
+
+// Make sure nothing is live and dirty
+static void flushAllRegsBody(CompilationUnit *cUnit, RegisterInfo *info,
+                             int numRegs)
+{
+    int i;
+    for (i=0; i < numRegs; i++) {
+        if (info[i].live && info[i].dirty) {
+            if (info[i].pair) {
+                flushRegWide(cUnit, info[i].reg, info[i].partner);
+            } else {
+                flushReg(cUnit, info[i].reg);
+            }
+        }
+    }
+}
+
+static void flushAllRegs(CompilationUnit *cUnit)
+{
+    flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
+                     cUnit->regPool->numCoreTemps);
+    flushAllRegsBody(cUnit, cUnit->regPool->FPTemps,
+                     cUnit->regPool->numFPTemps);
+    clobberAllRegs(cUnit);
+}
+
+
+//TUNING: rewrite all of this reg stuff.  Probably use an attribute table
+static bool regClassMatches(int regClass, int reg)
+{
+    if (regClass == kAnyReg) {
+        return true;
+    } else if (regClass == kCoreReg) {
+        return !FPREG(reg);
+    } else {
+        return FPREG(reg);
+    }
+}
+
+static void markRegLive(CompilationUnit *cUnit, int reg, int sReg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    if ((info->reg == reg) && (info->sReg == sReg) && info->live) {
+        return;  /* already live */
+    } else if (sReg != INVALID_SREG) {
+        clobberSReg(cUnit, sReg);
+        info->live = true;
+    } else {
+        /* Can't be live if no associated sReg */
+        info->live = false;
+    }
+    info->sReg = sReg;
+}
+
+static void markRegPair(CompilationUnit *cUnit, int lowReg, int highReg)
+{
+    RegisterInfo *infoLo = getRegInfo(cUnit, lowReg);
+    RegisterInfo *infoHi = getRegInfo(cUnit, highReg);
+    infoLo->pair = infoHi->pair = true;
+    infoLo->partner = highReg;
+    infoHi->partner = lowReg;
+}
+
+static void markRegSingle(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    info->pair = false;
+}
+
+static void markRegClean(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    info->dirty = false;
+}
+
+static void markRegDirty(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    info->dirty = true;
+}
+
+static void markRegInUse(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    info->inUse = true;
+}
+
+/* Return true if live & dirty */
+static bool isDirty(CompilationUnit *cUnit, int reg)
+{
+    RegisterInfo *info = getRegInfo(cUnit, reg);
+    return (info && info->live && info->dirty);
+}
+
+void copyRegInfo(CompilationUnit *cUnit, int newReg, int oldReg)
+{
+    RegisterInfo *newInfo = getRegInfo(cUnit, newReg);
+    RegisterInfo *oldInfo = getRegInfo(cUnit, oldReg);
+    *newInfo = *oldInfo;
+    newInfo->reg = newReg;
+}
+
+/*
+ * Return an updated location record with current in-register status.
+ * If the value lives in live temps, reflect that fact.  No code
+ * is generated.  The the live value is part of an older pair,
+ * clobber both low and high.
+ * TUNING: clobbering both is a bit heavy-handed, but the alternative
+ * is a bit complex when dealing with FP regs.  Examine code to see
+ * if it's worthwhile trying to be more clever here.
+ */
+static RegLocation updateLoc(CompilationUnit *cUnit, RegLocation loc)
+{
+    assert(!loc.wide);
+    if (loc.location == kLocDalvikFrame) {
+        RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
+        if (infoLo) {
+            if (infoLo->pair) {
+                clobberReg(cUnit, infoLo->reg);
+                clobberReg(cUnit, infoLo->partner);
+            } else {
+                loc.lowReg = infoLo->reg;
+                loc.location = kLocPhysReg;
+            }
+        }
+    }
+
+    return loc;
+}
+
+/* see comments for updateLoc */
+static RegLocation updateLocWide(CompilationUnit *cUnit, RegLocation loc)
+{
+    assert(loc.wide);
+    if (loc.location == kLocDalvikFrame) {
+        RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
+        RegisterInfo *infoHi = allocLive(cUnit, hiSReg(loc.sRegLow), kAnyReg);
+        bool match = true;
+        match = match && (infoLo != NULL);
+        match = match && (infoHi != NULL);
+        match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
+        if (match && FPREG(infoLo->reg)) {
+            match &= ((infoLo->reg & 0x1) == 0);
+            match &= ((infoHi->reg - infoLo->reg) == 1);
+        }
+        if (match) {
+            loc.lowReg = infoLo->reg;
+            loc.highReg = infoHi->reg;
+            loc.location = kLocPhysReg;
+            markRegPair(cUnit, loc.lowReg, loc.highReg);
+            assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+            return loc;
+        }
+        /* Can't easily reuse - just clobber any overlaps */
+        if (infoLo) {
+            clobberReg(cUnit, infoLo->reg);
+            if (infoLo->pair)
+                clobberReg(cUnit, infoLo->partner);
+        }
+        if (infoHi) {
+            clobberReg(cUnit, infoHi->reg);
+            if (infoHi->pair)
+                clobberReg(cUnit, infoHi->partner);
+        }
+    }
+
+    return loc;
+}
+
+static RegLocation evalLocWide(CompilationUnit *cUnit, RegLocation loc,
+                               int regClass, bool update)
+{
+    assert(loc.wide);
+    int newRegs;
+    int lowReg;
+    int highReg;
+
+    loc = updateLocWide(cUnit, loc);
+
+    /* If already in registers, we can assume proper form.  Right reg class? */
+    if (loc.location == kLocPhysReg) {
+        assert(FPREG(loc.lowReg) == FPREG(loc.highReg));
+        assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+        if (!regClassMatches(regClass, loc.lowReg)) {
+            /* Wrong register class.  Reallocate and copy */
+            newRegs = allocTypedTempPair(cUnit, loc.fp, regClass);
+            lowReg = newRegs & 0xff;
+            highReg = (newRegs >> 8) & 0xff;
+            genRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
+                           loc.highReg);
+            copyRegInfo(cUnit, lowReg, loc.lowReg);
+            copyRegInfo(cUnit, highReg, loc.highReg);
+            clobberReg(cUnit, loc.lowReg);
+            clobberReg(cUnit, loc.highReg);
+            loc.lowReg = lowReg;
+            loc.highReg = highReg;
+            markRegPair(cUnit, loc.lowReg, loc.highReg);
+            assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+        }
+        return loc;
+    }
+
+    assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
+    assert((loc.location != kLocRetval) || (hiSReg(loc.sRegLow) == INVALID_SREG));
+
+    newRegs = allocTypedTempPair(cUnit, loc.fp, regClass);
+    loc.lowReg = newRegs & 0xff;
+    loc.highReg = (newRegs >> 8) & 0xff;
+
+    markRegPair(cUnit, loc.lowReg, loc.highReg);
+    if (update) {
+        loc.location = kLocPhysReg;
+        markRegLive(cUnit, loc.lowReg, loc.sRegLow);
+        markRegLive(cUnit, loc.highReg, hiSReg(loc.sRegLow));
+    }
+    assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+    return loc;
+}
+
+static RegLocation evalLoc(CompilationUnit *cUnit, RegLocation loc,
+                               int regClass, bool update)
+{
+    RegisterInfo *infoLo = NULL;
+    int newReg;
+    if (loc.wide)
+        return evalLocWide(cUnit, loc, regClass, update);
+    loc = updateLoc(cUnit, loc);
+
+    if (loc.location == kLocPhysReg) {
+        if (!regClassMatches(regClass, loc.lowReg)) {
+            /* Wrong register class.  Realloc, copy and transfer ownership */
+            newReg = allocTypedTemp(cUnit, loc.fp, regClass);
+            genRegCopy(cUnit, newReg, loc.lowReg);
+            copyRegInfo(cUnit, newReg, loc.lowReg);
+            clobberReg(cUnit, loc.lowReg);
+            loc.lowReg = newReg;
+        }
+        return loc;
+    }
+
+    assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
+
+    newReg = allocTypedTemp(cUnit, loc.fp, regClass);
+    loc.lowReg = newReg;
+
+    if (update) {
+        loc.location = kLocPhysReg;
+        markRegLive(cUnit, loc.lowReg, loc.sRegLow);
+    }
+    return loc;
+}
+
+static inline int getSrcSSAName(MIR *mir, int num)
+{
+    assert(mir->ssaRep->numUses > num);
+    return mir->ssaRep->uses[num];
+}
+
+static inline int getDestSSAName(MIR *mir, int num)
+{
+    assert(mir->ssaRep->numDefs > num);
+    return mir->ssaRep->defs[num];
+}
+
+// Get the LocRecord associated with an SSA name use.
+static inline RegLocation getSrcLoc(CompilationUnit *cUnit, MIR *mir, int num)
+{
+    RegLocation loc = cUnit->regLocation[SREG(cUnit, getSrcSSAName(mir, num))];
+    loc.fp = cUnit->regLocation[getSrcSSAName(mir, num)].fp;
+    loc.wide = false;
+    return loc;
+}
+
+// Get the LocRecord associated with an SSA name def.
+static inline RegLocation getDestLoc(CompilationUnit *cUnit, MIR *mir, int num)
+{
+    RegLocation loc = cUnit->regLocation[SREG(cUnit, getDestSSAName(mir, num))];
+    loc.fp = cUnit->regLocation[getDestSSAName(mir, num)].fp;
+    loc.wide = false;
+    return loc;
+}
+
+static RegLocation getLocWide(CompilationUnit *cUnit, MIR *mir,
+                                         int low, int high, bool isSrc)
+{
+    RegLocation lowLoc;
+    RegLocation highLoc;
+    /* Copy loc record for low word and patch in data from high word */
+    if (isSrc) {
+        lowLoc = getSrcLoc(cUnit, mir, low);
+        highLoc = getSrcLoc(cUnit, mir, high);
+    } else {
+        lowLoc = getDestLoc(cUnit, mir, low);
+        highLoc = getDestLoc(cUnit, mir, high);
+    }
+    /* Avoid this case by either promoting both or neither. */
+    assert(lowLoc.location == highLoc.location);
+    if (lowLoc.location == kLocPhysReg) {
+        /* This case shouldn't happen if we've named correctly */
+        assert(lowLoc.fp == highLoc.fp);
+    }
+    lowLoc.wide = true;
+    lowLoc.highReg = highLoc.lowReg;
+    return lowLoc;
+}
+static RegLocation getDestLocWide(CompilationUnit *cUnit, MIR *mir,
+                                         int low, int high)
+{
+    return getLocWide(cUnit, mir, low, high, false);
+}
+
+static RegLocation getSrcLocWide(CompilationUnit *cUnit, MIR *mir,
+                                         int low, int high)
+{
+    return getLocWide(cUnit, mir, low, high, true);
+}
+
+/* Reset the tracker to unknown state */
+static inline void resetNullCheckTracker(CompilationUnit *cUnit)
+{
+    dvmClearAllBits(cUnit->regPool->nullCheckedRegs);
+}
+
+static RegLocation getReturnLocWide(CompilationUnit *cUnit)
+{
+    RegLocation res = LOC_C_RETURN_WIDE;
+    clobberReg(cUnit, r0);
+    clobberReg(cUnit, r1);
+    markRegInUse(cUnit, r0);
+    markRegInUse(cUnit, r1);
+    markRegPair(cUnit, res.lowReg, res.highReg);
+    return res;
+}
+
+static RegLocation getReturnLocWideAlt(CompilationUnit *cUnit)
+{
+    RegLocation res = LOC_C_RETURN_WIDE;
+    res.lowReg = r2;
+    res.highReg = r3;
+    clobberReg(cUnit, r2);
+    clobberReg(cUnit, r3);
+    markRegInUse(cUnit, r2);
+    markRegInUse(cUnit, r3);
+    markRegPair(cUnit, res.lowReg, res.highReg);
+    return res;
+}
+
+static RegLocation getReturnLoc(CompilationUnit *cUnit)
+{
+    RegLocation res = LOC_C_RETURN;
+    clobberReg(cUnit, r0);
+    markRegInUse(cUnit, r0);
+    return res;
+}
+
+static RegLocation getReturnLocAlt(CompilationUnit *cUnit)
+{
+    RegLocation res = LOC_C_RETURN;
+    res.lowReg = r1;
+    clobberReg(cUnit, r1);
+    markRegInUse(cUnit, r1);
+    return res;
+}
+
+/* Kill the corresponding bit in the null-checked register list */
+static inline void killNullCheckedLocation(CompilationUnit *cUnit,
+                                           RegLocation loc)
+{
+    if (loc.location != kLocRetval) {
+        assert(loc.sRegLow != INVALID_SREG);
+        dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
+        if (loc.wide) {
+            assert(hiSReg(loc.sRegLow) != INVALID_SREG);
+            dvmClearBit(cUnit->regPool->nullCheckedRegs, hiSReg(loc.sRegLow));
+        }
+    }
+}
index dfbb030..d553aae 100644 (file)
  */
 
 #include "Codegen.h"
-/* Forward decls */
-static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
-                            int dOffset, ArmLIR *pcrLabel);
-static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest);
-static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest);
-static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
-                            int displacement, int rDest);
-static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
-                             int displacement, int rSrc, int rScratch);
-static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
-                          int rScratch);
-static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
-                                    ArmConditionCode cond,
-                                    ArmLIR *target);
-static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target);
-static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
-                             int rDestHi);
-static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
-                              int vDest, int rScratch);
-static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
-                              int rBound, int dOffset, ArmLIR *pcrLabel);
-static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
-static int inlinedTarget(MIR *mir);
-
-
-/* Routines which must be supplied here */
-static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
-static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
-                           int rAddr);
-static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
-                            int displacement, int rDest, OpSize size,
-                            bool nullCheck, int vReg);
-static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
-                             int displacement, int rSrc, OpSize size,
-                             int rScratch);
-static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
-                                     ArmConditionCode cond, int reg,
-                                     int checkValue, int dOffset,
-                                     ArmLIR *pcrLabel);
-ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
-static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
-static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask);
-
-static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op);
-static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value);
-static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc);
-static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc);
-static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
-                        int rSrc2);
-static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
-                        int value, int rScratch);
-static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
-                           int rSrc1, int value, int rScratch);
-static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
-                           int rSrc1, int rSrc2);
-static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
-                               int rIndex, int rDest, int scale, OpSize size);
-static void genCmpLong(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
-                       int vSrc2);
-
-static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir);
-static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir);
-static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir);
-static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir);
-static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir);
-static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin);
-static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir);
+
+static int leadingZeros(u4 val)
+{
+    u4 alt;
+    int n;
+    int count;
+
+    count = 16;
+    n = 32;
+    do {
+        alt = val >> count;
+        if (alt != 0) {
+            n = n - count;
+            val = alt;
+        }
+        count >>= 1;
+    } while (count);
+    return n - val;
+}
 
 /*
- * Support for register allocation
+ * Determine whether value can be encoded as a Thumb2 modified
+ * immediate.  If not, return -1.  If so, return i:imm3:a:bcdefgh form.
  */
+static int modifiedImmediate(u4 value)
+{
+   int zLeading;
+   int zTrailing;
+   u4 b0 = value & 0xff;
+
+   /* Note: case of value==0 must use 0:000:0:0000000 encoding */
+   if (value <= 0xFF)
+       return b0;  // 0:000:a:bcdefgh
+   if (value == ((b0 << 16) | b0))
+       return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
+   if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
+       return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
+   b0 = (value >> 8) & 0xff;
+   if (value == ((b0 << 24) | (b0 << 8)))
+       return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
+   /* Can we do it with rotation? */
+   zLeading = leadingZeros(value);
+   zTrailing = 32 - leadingZeros(~value & (value - 1));
+   /* A run of eight or fewer active bits? */
+   if ((zLeading + zTrailing) < 24)
+       return -1;  /* No - bail */
+   /* left-justify the constant, discarding msb (known to be 1) */
+   value <<= zLeading + 1;
+   /* Create bcdefgh */
+   value >>= 25;
+   /* Put it all together */
+   return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
+}
 
-/* get the next register in r0..r3 in a round-robin fashion */
-#define NEXT_REG(reg) ((reg + 1) & 3)
 /*
- * The following are utility routines to help maintain the RegisterScoreboard
- * state to facilitate register renaming.
+ * Determine whether value can be encoded as a Thumb2 floating point
+ * immediate.  If not, return -1.  If so return encoded 8-bit value.
  */
-
-/* Reset the tracker to unknown state */
-static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
+static int encodeImmDoubleHigh(int value)
 {
-    RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
-    int i;
-
-    dvmClearAllBits(registerScoreboard->nullCheckedRegs);
-    registerScoreboard->liveDalvikReg = vNone;
-    registerScoreboard->nativeReg = vNone;
-    registerScoreboard->nativeRegHi = vNone;
-    for (i = 0; i < 32; i++) {
-        registerScoreboard->fp[i] = vNone;
+    int res;
+    int bitA =    (value & 0x80000000) >> 31;
+    int notBitB = (value & 0x40000000) >> 30;
+    int bitB =    (value & 0x20000000) >> 29;
+    int bSmear =  (value & 0x3fc00000) >> 22;
+    int slice =   (value & 0x003f0000) >> 16;
+    int zeroes =  (value & 0x0000ffff);
+    if (zeroes != 0)
+        return -1;
+    if (bitB) {
+        if ((notBitB != 0) || (bSmear != 0x1f))
+            return -1;
+    } else {
+        if ((notBitB != 1) || (bSmear != 0x0))
+            return -1;
     }
-    registerScoreboard->nextFP = 0;
+    res = (bitA << 7) | (bitB << 6) | slice;
+    return res;
 }
 
-/* Kill the corresponding bit in the null-checked register list */
-static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
+static int encodeImmSingle(int value)
 {
-    dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
+    int res;
+    int bitA =    (value & 0x80000000) >> 31;
+    int notBitB = (value & 0x40000000) >> 30;
+    int bitB =    (value & 0x20000000) >> 29;
+    int bSmear =  (value & 0x3e000000) >> 25;
+    int slice =   (value & 0x01f80000) >> 19;
+    int zeroes =  (value & 0x0007ffff);
+    if (zeroes != 0)
+        return -1;
+    if (bitB) {
+        if ((notBitB != 0) || (bSmear != 0x1f))
+            return -1;
+    } else {
+        if ((notBitB != 1) || (bSmear != 0x0))
+            return -1;
+    }
+    res = (bitA << 7) | (bitB << 6) | slice;
+    return res;
 }
 
-/* The Dalvik register pair held in native registers have changed */
-static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
-                                          int vReg, int mRegLo, int mRegHi)
+static int encodeImmDouble(int valLo, int valHi)
+{
+    int res = -1;
+    if (valLo == 0)
+        res = encodeImmDoubleHigh(valHi);
+    return res;
+}
+void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+                    int srcLo, int srcHi)
 {
-    cUnit->registerScoreboard.liveDalvikReg = vReg;
-    cUnit->registerScoreboard.nativeReg = mRegLo;
-    cUnit->registerScoreboard.nativeRegHi = mRegHi;
-    cUnit->registerScoreboard.isWide = true;
+    bool destFP = FPREG(destLo) && FPREG(destHi);
+    bool srcFP = FPREG(srcLo) && FPREG(srcHi);
+    assert(FPREG(srcLo) == FPREG(srcHi));
+    assert(FPREG(destLo) == FPREG(destHi));
+    if (destFP) {
+        if (srcFP) {
+            genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
+        } else {
+            newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
+        }
+    } else {
+        if (srcFP) {
+            newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
+        } else {
+            // Handle overlap
+            if (srcHi == destLo) {
+                genRegCopy(cUnit, destHi, srcHi);
+                genRegCopy(cUnit, destLo, srcLo);
+            } else {
+                genRegCopy(cUnit, destLo, srcLo);
+                genRegCopy(cUnit, destHi, srcHi);
+            }
+        }
+    }
 }
 
-/* The Dalvik register held in a native register has changed */
-static inline void updateLiveRegister(CompilationUnit *cUnit,
-                                      int vReg, int mReg)
+
+static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7, r8, r9, r10, r11, r12};
+static int corePreserved[] = {};
+static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
+                        fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
+static int fpPreserved[] = {};
+void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
 {
-    cUnit->registerScoreboard.liveDalvikReg = vReg;
-    cUnit->registerScoreboard.nativeReg = mReg;
-    cUnit->registerScoreboard.isWide = false;
+    int i;
+    int numTemps = sizeof(coreTemps)/sizeof(int);
+    int numFPTemps = sizeof(fpTemps)/sizeof(int);
+    RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
+    cUnit->regPool = pool;
+    pool->numCoreTemps = numTemps;
+    pool->coreTemps =
+            dvmCompilerNew(numTemps * sizeof(*cUnit->regPool->coreTemps), true);
+    pool->numFPTemps = numFPTemps;
+    pool->FPTemps =
+            dvmCompilerNew(numFPTemps * sizeof(*cUnit->regPool->FPTemps), true);
+    pool->numCoreRegs = 0;
+    pool->coreRegs = NULL;
+    pool->numFPRegs = 0;
+    pool->FPRegs = NULL;
+    initPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
+    initPool(pool->FPTemps, fpTemps, pool->numFPTemps);
+    initPool(pool->coreRegs, NULL, 0);
+    initPool(pool->FPRegs, NULL, 0);
+    pool->nullCheckedRegs =
+        dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
 }
 
+
 /*
- * Given a Dalvik register id vSrc, use a very simple algorithm to increase
- * the lifetime of cached Dalvik value in a native register.
+ * Alloc a pair of core registers, or a double.  Low reg in low byte,
+ * high reg in next byte.
  */
-static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
-                                      bool isWide)
+static int allocTypedTempPair(CompilationUnit *cUnit, bool fpHint, int regClass)
 {
-    RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
-
-    /* No live value - suggest to use r0 */
-    if (registerScoreboard->liveDalvikReg == vNone)
-        return r0;
-
-    /* Reuse the previously used native reg */
-    if (registerScoreboard->liveDalvikReg == vSrc) {
-        if (isWide != true) {
-            return registerScoreboard->nativeReg;
-        } else {
-            /* Return either r0 or r2 */
-            return (registerScoreboard->nativeReg + 1) & 2;
-        }
-    }
-
-    /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
-    if (isWide) {
-        return (registerScoreboard->nativeReg + 2) & 2;
+    int highReg;
+    int lowReg;
+    int res = 0;
+    if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
+        lowReg = allocTempDouble(cUnit);
+        highReg = lowReg + 1;
     } else {
-        return (registerScoreboard->nativeReg + 1) & 3;
+        lowReg = allocTemp(cUnit);
+        highReg = allocTemp(cUnit);
     }
+    res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+    return res;
+}
+
+static int allocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
+{
+    if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
+        return allocTempFloat(cUnit);
+    return allocTemp(cUnit);
+}
+
+static int encodeShift(int code, int amount) {
+    return ((amount & 0x1f) << 2) | code;
 }
 
 /*
@@ -211,7 +261,7 @@ static ArmLIR *genIT(CompilationUnit *cUnit, ArmConditionCode code,
     }
     mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
            (1 << (3 - strlen(guide)));
-    return newLIR2(cUnit, THUMB2_IT, code, mask);
+    return newLIR2(cUnit, kThumb2It, code, mask);
 }
 
 
@@ -223,13 +273,16 @@ static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
     if (rDest == rSrc) {
         res->isNop = true;
     } else {
-        // TODO: support copy between FP and gen regs
+        assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
         if (DOUBLEREG(rDest)) {
-            assert(DOUBLEREG(rSrc));
-            res->opCode = THUMB2_VMOVD;
+            res->opCode = kThumb2Vmovd;
         } else {
-            assert(SINGLEREG(rSrc));
-            res->opCode = THUMB2_VMOVS;
+            if (SINGLEREG(rDest)) {
+                res->opCode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
+            } else {
+                assert(SINGLEREG(rSrc));
+                res->opCode = kThumb2Fmrs;
+            }
         }
         res->operands[0] = rDest;
         res->operands[1] = rSrc;
@@ -246,13 +299,13 @@ ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
         return fpRegCopy(cUnit, rDest, rSrc);
     res = dvmCompilerNew(sizeof(ArmLIR), true);
     if (LOWREG(rDest) && LOWREG(rSrc))
-        opCode = THUMB_MOV_RR;
+        opCode = kThumbMovRR;
     else if (!LOWREG(rDest) && !LOWREG(rSrc))
-         opCode = THUMB_MOV_RR_H2H;
+         opCode = kThumbMovRR_H2H;
     else if (LOWREG(rDest))
-         opCode = THUMB_MOV_RR_H2L;
+         opCode = kThumbMovRR_H2L;
     else
-         opCode = THUMB_MOV_RR_L2H;
+         opCode = kThumbMovRR_L2H;
 
     res->operands[0] = rDest;
     res->operands[1] = rSrc;
@@ -264,666 +317,162 @@ ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
     return res;
 }
 
-static int leadingZeros(u4 val)
-{
-    u4 alt;
-    int n;
-    int count;
-
-    count = 16;
-    n = 32;
-    do {
-        alt = val >> count;
-        if (alt != 0) {
-            n = n - count;
-            val = alt;
-        }
-        count >>= 1;
-    } while (count);
-    return n - val;
-}
-
-/*
- * Determine whether value can be encoded as a Thumb2 modified
- * immediate.  If not, return -1.  If so, return i:imm3:a:bcdefgh form.
- */
-static int modifiedImmediate(u4 value)
-{
-   int zLeading;
-   int zTrailing;
-   u4 b0 = value & 0xff;
-
-   /* Note: case of value==0 must use 0:000:0:0000000 encoding */
-   if (value <= 0xFF)
-       return b0;  // 0:000:a:bcdefgh
-   if (value == ((b0 << 16) | b0))
-       return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
-   if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
-       return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
-   b0 = (value >> 8) & 0xff;
-   if (value == ((b0 << 24) | (b0 << 8)))
-       return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
-   /* Can we do it with rotation? */
-   zLeading = leadingZeros(value);
-   zTrailing = 32 - leadingZeros(~value & (value - 1));
-   /* A run of eight or fewer active bits? */
-   if ((zLeading + zTrailing) < 24)
-       return -1;  /* No - bail */
-   /* left-justify the constant, discarding msb (known to be 1) */
-   value <<= zLeading + 1;
-   /* Create bcdefgh */
-   value >>= 25;
-   /* Put it all together */
-   return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
-}
-
-/*
- * Load a immediate using a shortcut if possible; otherwise
- * grab from the per-translation literal pool
- */
-static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
-{
-    ArmLIR *res;
-    int modImm;
-    /* See if the value can be constructed cheaply */
-    if ((value >= 0) && (value <= 255)) {
-        return newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
-    }
-    /* Check Modified immediate special cases */
-    modImm = modifiedImmediate(value);
-    if (modImm >= 0) {
-        res = newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, rDest, modImm);
-        return res;
-    }
-    modImm = modifiedImmediate(~value);
-    if (modImm >= 0) {
-        res = newLIR2(cUnit, THUMB2_MVN_IMM_SHIFT, rDest, modImm);
-        return res;
-    }
-    /* 16-bit immediate? */
-    if ((value & 0xffff) == value) {
-        res = newLIR2(cUnit, THUMB2_MOV_IMM16, rDest, value);
-        return res;
-    }
-    /* No shortcut - go ahead and use literal pool */
-    ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
-    if (dataTarget == NULL) {
-        dataTarget = addWordData(cUnit, value, false);
-    }
-    ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
-    loadPcRel->opCode = THUMB_LDR_PC_REL;
-    loadPcRel->generic.target = (LIR *) dataTarget;
-    loadPcRel->operands[0] = rDest;
-    setupResourceMasks(loadPcRel);
-    res = loadPcRel;
-    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
-
-    /*
-     * To save space in the constant pool, we use the ADD_RRI8 instruction to
-     * add up to 255 to an existing constant value.
-     */
-    if (dataTarget->operands[0] != value) {
-        newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
-    }
-    return res;
-}
-
 /* Export the Dalvik PC assicated with an instruction to the StackSave area */
-static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
-                           int rAddr)
+static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
 {
     ArmLIR *res;
     int offset = offsetof(StackSaveArea, xtra.currentPc);
+    int rDPC = allocTemp(cUnit);
     res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
-    newLIR3(cUnit, THUMB2_STR_RRI8_PREDEC, rDPC, rFP,
+    newLIR3(cUnit, kThumb2StrRRI8Predec, rDPC, rFP,
             sizeof(StackSaveArea) - offset);
+    freeTemp(cUnit, rDPC);
     return res;
 }
 
-/* Load value from base + scaled index. Note: index reg killed */
-static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
-                               int rIndex, int rDest, int scale, OpSize size)
+static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
 {
-    bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
-    ArmOpCode opCode = THUMB_BKPT;
-    bool thumbForm = (allLowRegs && (scale == 0));
-    switch (size) {
-        case WORD:
-            opCode = (thumbForm) ? THUMB_LDR_RRR : THUMB2_LDR_RRR;
-            break;
-        case UNSIGNED_HALF:
-            opCode = (thumbForm) ? THUMB_LDRH_RRR : THUMB2_LDRH_RRR;
-            break;
-        case SIGNED_HALF:
-            opCode = (thumbForm) ? THUMB_LDRSH_RRR : THUMB2_LDRSH_RRR;
-            break;
-        case UNSIGNED_BYTE:
-            opCode = (thumbForm) ? THUMB_LDRB_RRR : THUMB2_LDRB_RRR;
-            break;
-        case SIGNED_BYTE:
-            opCode = (thumbForm) ? THUMB_LDRSB_RRR : THUMB2_LDRSB_RRR;
+    ArmOpCode opCode = kThumbBkpt;
+    switch (op) {
+        case kOpUncondBr:
+            opCode = kThumbBUncond;
             break;
         default:
             assert(0);
     }
-    if (thumbForm)
-        return newLIR3(cUnit, opCode, rDest, rBase, rIndex);
-    else
-        return newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
+    return newLIR0(cUnit, opCode);
 }
 
-/* store value base base + scaled index. Note: index reg killed */
-static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
-                                int rIndex, int rSrc, int scale, OpSize size)
+static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
 {
-    bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
-    ArmOpCode opCode = THUMB_BKPT;
-    bool thumbForm = (allLowRegs && (scale == 0));
-    switch (size) {
-        case WORD:
-            opCode = (thumbForm) ? THUMB_STR_RRR : THUMB2_STR_RRR;
-            break;
-        case UNSIGNED_HALF:
-        case SIGNED_HALF:
-            opCode = (thumbForm) ? THUMB_STRH_RRR : THUMB2_STRH_RRR;
+    return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc);
+}
+
+static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
+{
+    ArmOpCode opCode = kThumbBkpt;
+    switch (op) {
+        case kOpPush:
+            opCode = ((value & 0xff00) != 0) ? kThumb2Push : kThumbPush;
             break;
-        case UNSIGNED_BYTE:
-        case SIGNED_BYTE:
-            opCode = (thumbForm) ? THUMB_STRB_RRR : THUMB2_STRB_RRR;
+        case kOpPop:
+            opCode = ((value & 0xff00) != 0) ? kThumb2Pop : kThumbPop;
             break;
         default:
             assert(0);
     }
-    if (thumbForm)
-        return newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
-    else
-        return newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
-}
-
-/*
- * Load a float from a Dalvik register.  Note: using fixed r7 here
- * when operation is out of range.  Revisit this when registor allocation
- * strategy changes.
- */
-static ArmLIR *fpVarAccess(CompilationUnit *cUnit, int vSrcDest,
-                           int rSrcDest, ArmOpCode opCode)
-{
-    ArmLIR *res;
-    if (vSrcDest > 255) {
-        opRegRegImm(cUnit, OP_ADD, r7, rFP, vSrcDest * 4, rNone);
-        res = newLIR3(cUnit, opCode, rSrcDest, r7, 0);
-    } else {
-        res = newLIR3(cUnit, opCode, rSrcDest, rFP, vSrcDest);
-    }
-    return res;
-}
-
-static int nextFPReg(CompilationUnit *cUnit, int dalvikReg, bool isDouble)
-{
-    RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
-    int reg;
-
-    if (isDouble) {
-        reg = ((registerScoreboard->nextFP + 1) & ~1) % 32;
-        registerScoreboard->nextFP = reg + 2;
-        registerScoreboard->nextFP %= 32;
-        registerScoreboard->fp[reg] = dalvikReg;
-        return dr0 + reg;
-    }
-    else {
-        reg = registerScoreboard->nextFP++;
-        registerScoreboard->nextFP %= 32;
-        registerScoreboard->fp[reg] = dalvikReg;
-        return fr0 + reg;
-    }
+    return newLIR1(cUnit, opCode, value);
 }
 
-/*
- * Select a SFP register for the dalvikReg
- */
-static int selectSFPReg(CompilationUnit *cUnit, int dalvikReg)
+static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
 {
-    RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
-    int i;
-
-    if (dalvikReg == vNone) {
-        return nextFPReg(cUnit, dalvikReg, false);;
-    }
-
-    for (i = 0; i < 32; i++) {
-        if (registerScoreboard->fp[i] == dalvikReg) {
-            return fr0 + i;
-        }
+    ArmOpCode opCode = kThumbBkpt;
+    switch (op) {
+        case kOpBlx:
+            opCode = kThumbBlxR;
+            break;
+        default:
+            assert(0);
     }
-    return nextFPReg(cUnit, dalvikReg, false);;
+    return newLIR1(cUnit, opCode, rDestSrc);
 }
 
-/*
- * Select a DFP register for the dalvikReg
- */
-static int selectDFPReg(CompilationUnit *cUnit, int dalvikReg)
-{
-    RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
-    int i;
-
-    if (dalvikReg == vNone) {
-        return nextFPReg(cUnit, dalvikReg, true);;
-    }
-
-    for (i = 0; i < 32; i += 2) {
-        if (registerScoreboard->fp[i] == dalvikReg) {
-            return dr0 + i;
-        }
-    }
-    return nextFPReg(cUnit, dalvikReg, true);
-}
-
-static ArmLIR *loadFloat(CompilationUnit *cUnit, int vSrc, int rDest)
-{
-    assert(SINGLEREG(rDest));
-    ArmLIR *lir = fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRS);
-    annotateDalvikRegAccess(lir, vSrc, true /* isLoad */);
-    return lir;
-}
-
-/* Store a float to a Dalvik register */
-static ArmLIR *storeFloat(CompilationUnit *cUnit, int rSrc, int vDest)
-{
-    RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
-
-    assert(SINGLEREG(rSrc));
-    registerScoreboard->fp[rSrc % 32] = vDest;
-
-    ArmLIR *lir = fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRS);
-    annotateDalvikRegAccess(lir, vDest, false /* isLoad */);
-    return lir;
-}
-
-/* Load a double from a Dalvik register */
-static ArmLIR *loadDouble(CompilationUnit *cUnit, int vSrc, int rDest)
-{
-    assert(DOUBLEREG(rDest));
-    ArmLIR *lir = fpVarAccess(cUnit, vSrc, rDest, THUMB2_VLDRD);
-    annotateDalvikRegAccess(lir, vSrc, true /* isLoad */);
-    return lir;
-}
-
-/* Store a double to a Dalvik register */
-static ArmLIR *storeDouble(CompilationUnit *cUnit, int rSrc, int vDest)
-{
-    RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
-
-    assert(DOUBLEREG(rSrc));
-    registerScoreboard->fp[rSrc % 32] = vDest;
-
-    ArmLIR *lir = fpVarAccess(cUnit, vDest, rSrc, THUMB2_VSTRD);
-    annotateDalvikRegAccess(lir, vDest, false /* isLoad */);
-    return lir;
-}
-
-/*
- * Load value from base + displacement.  Optionally perform null check
- * on base (which must have an associated vReg and MIR).  If not
- * performing null check, incoming MIR can be null. Note: base and
- * dest must not be the same if there is any chance that the long
- * form must be used.
- * TODO: revisit, perhaps use hot temp reg in (base == dest) case.
- */
-static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
-                            int displacement, int rDest, OpSize size,
-                            bool nullCheck, int vReg)
-{
-    ArmLIR *first = NULL;
-    ArmLIR *res, *load;
-    ArmOpCode opCode = THUMB_BKPT;
-    bool shortForm = false;
-    bool thumb2Form = (displacement < 4092 && displacement >= 0);
-    int shortMax = 128;
-    bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
-    int encodedDisp = displacement;
-
-    switch (size) {
-        case WORD:
-            if (LOWREG(rDest) && (rBase == rpc) &&
-                (displacement <= 1020) && (displacement >= 0)) {
-                shortForm = true;
-                encodedDisp >>= 2;
-                opCode = THUMB_LDR_PC_REL;
-            } else if (LOWREG(rDest) && (rBase == r13) &&
-                      (displacement <= 1020) && (displacement >= 0)) {
-                shortForm = true;
-                encodedDisp >>= 2;
-                opCode = THUMB_LDR_SP_REL;
-            } else if (allLowRegs && displacement < 128 && displacement >= 0) {
-                assert((displacement & 0x3) == 0);
-                shortForm = true;
-                encodedDisp >>= 2;
-                opCode = THUMB_LDR_RRI5;
-            } else if (thumb2Form) {
-                shortForm = true;
-                opCode = THUMB2_LDR_RRI12;
-            }
-            break;
-        case UNSIGNED_HALF:
-            if (allLowRegs && displacement < 64 && displacement >= 0) {
-                assert((displacement & 0x1) == 0);
-                shortForm = true;
-                encodedDisp >>= 1;
-                opCode = THUMB_LDRH_RRI5;
-            } else if (displacement < 4092 && displacement >= 0) {
-                shortForm = true;
-                opCode = THUMB2_LDRH_RRI12;
-            }
-            break;
-        case SIGNED_HALF:
-            if (thumb2Form) {
-                shortForm = true;
-                opCode = THUMB2_LDRSH_RRI12;
-            }
-            break;
-        case UNSIGNED_BYTE:
-            if (allLowRegs && displacement < 32 && displacement >= 0) {
-                shortForm = true;
-                opCode = THUMB_LDRB_RRI5;
-            } else if (thumb2Form) {
-                shortForm = true;
-                opCode = THUMB2_LDRB_RRI12;
-            }
-            break;
-        case SIGNED_BYTE:
-            if (thumb2Form) {
-                shortForm = true;
-                opCode = THUMB2_LDRSB_RRI12;
-            }
-            break;
-        default:
-            assert(0);
-    }
-    if (nullCheck)
-        first = genNullCheck(cUnit, vReg, rBase, mir->offset, NULL);
-    if (shortForm) {
-        load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
-    } else {
-        assert(rBase != rDest);
-        res = loadConstant(cUnit, rDest, encodedDisp);
-        load = loadBaseIndexed(cUnit, rBase, rDest, rDest, 0, size);
-    }
-
-    if (rBase == rFP) {
-        annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
-    }
-    return (first) ? first : res;
-}
-
-static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
-                             int displacement, int rSrc, OpSize size,
-                             int rScratch)
-{
-    ArmLIR *res, *store;
-    ArmOpCode opCode = THUMB_BKPT;
-    bool shortForm = false;
-    bool thumb2Form = (displacement < 4092 && displacement >= 0);
-    int shortMax = 128;
-    bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
-    int encodedDisp = displacement;
-
-    if (rScratch != -1)
-        allLowRegs &= LOWREG(rScratch);
-    switch (size) {
-        case WORD:
-            if (allLowRegs && displacement < 128 && displacement >= 0) {
-                assert((displacement & 0x3) == 0);
-                shortForm = true;
-                encodedDisp >>= 2;
-                opCode = THUMB_STR_RRI5;
-            } else if (thumb2Form) {
-                shortForm = true;
-                opCode = THUMB2_STR_RRI12;
-            }
-            break;
-        case UNSIGNED_HALF:
-        case SIGNED_HALF:
-            if (displacement < 64 && displacement >= 0) {
-                assert((displacement & 0x1) == 0);
-                shortForm = true;
-                encodedDisp >>= 1;
-                opCode = THUMB_STRH_RRI5;
-            } else if (thumb2Form) {
-                shortForm = true;
-                opCode = THUMB2_STRH_RRI12;
-            }
-            break;
-        case UNSIGNED_BYTE:
-        case SIGNED_BYTE:
-            if (displacement < 32 && displacement >= 0) {
-                shortForm = true;
-                opCode = THUMB_STRB_RRI5;
-            } else if (thumb2Form) {
-                shortForm = true;
-                opCode = THUMB2_STRH_RRI12;
-            }
-            break;
-        default:
-            assert(0);
-    }
-    if (shortForm) {
-        store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
-    } else {
-        assert(rScratch != -1);
-        res = loadConstant(cUnit, rScratch, encodedDisp);
-        store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
-    }
-
-    if (rBase == rFP) {
-        annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
-    }
-    return res;
-}
-
-/*
- * Perform a "reg cmp imm" operation and jump to the PCR region if condition
- * satisfies.
- */
-static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
-                                         ArmConditionCode cond, int reg,
-                                         int checkValue, int dOffset,
-                                         ArmLIR *pcrLabel)
-{
-    ArmLIR *branch;
-    int modImm;
-    /*
-     * TODO: re-enable usage of THUMB2_CBZ & THUMB2_CBNZ once assembler is
-     * enhanced to allow us to replace code patterns when instructions don't
-     * reach.  Currently, CB[N]Z is causing too many assembler aborts.
-     * What we want to do is emit the short forms, and then replace them with
-     * longer versions when needed.
-     */
-    if (0 && (LOWREG(reg)) && (checkValue == 0) &&
-       ((cond == ARM_COND_EQ) || (cond == ARM_COND_NE))) {
-        branch = newLIR2(cUnit,
-                         (cond == ARM_COND_EQ) ? THUMB2_CBZ : THUMB2_CBNZ,
-                         reg, 0);
-    } else {
-        modImm = modifiedImmediate(checkValue);
-        if ((checkValue & 0xff) == checkValue) {
-            newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
-        } else if (modImm >= 0) {
-            newLIR2(cUnit, THUMB2_CMP_RI8, reg, modImm);
-        } else {
-            /* Note: direct use of hot temp r7 here. Revisit. */
-            loadConstant(cUnit, r7, checkValue);
-            newLIR2(cUnit, THUMB_CMP_RR, reg, r7);
-        }
-        branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
-    }
-    return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
-}
-
-static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
-{
-    ArmLIR *res;
-    if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
-        res = newLIR2(cUnit, THUMB_LDMIA, rBase, rMask);
-    } else {
-        res = newLIR2(cUnit, THUMB2_LDMIA, rBase, rMask);
-    }
-    return res;
-}
-
-static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
-{
-    ArmLIR *res;
-    if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
-        res = newLIR2(cUnit, THUMB_STMIA, rBase, rMask);
-    } else {
-        res = newLIR2(cUnit, THUMB2_STMIA, rBase, rMask);
-    }
-    return res;
-}
-
-static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
-{
-    ArmOpCode opCode = THUMB_BKPT;
-    switch (op) {
-        case OP_UNCOND_BR:
-            opCode = THUMB_B_UNCOND;
-            break;
-        default:
-            assert(0);
-    }
-    return newLIR0(cUnit, opCode);
-}
-
-static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
-{
-    return newLIR2(cUnit, THUMB_B_COND, 0 /* offset to be patched */, cc);
-}
-
-static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
-{
-    ArmOpCode opCode = THUMB_BKPT;
-    switch (op) {
-        case OP_PUSH:
-            opCode = ((value & 0xff00) != 0) ? THUMB2_PUSH : THUMB_PUSH;
-            break;
-        case OP_POP:
-            opCode = ((value & 0xff00) != 0) ? THUMB2_POP : THUMB_POP;
-            break;
-        default:
-            assert(0);
-    }
-    return newLIR1(cUnit, opCode, value);
-}
-
-static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
-{
-    ArmOpCode opCode = THUMB_BKPT;
-    switch (op) {
-        case OP_BLX:
-            opCode = THUMB_BLX_R;
-            break;
-        default:
-            assert(0);
-    }
-    return newLIR1(cUnit, opCode, rDestSrc);
-}
-
-static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
-                        int rSrc2, int shift)
+static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                        int rSrc2, int shift)
 {
     bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
-    ArmOpCode opCode = THUMB_BKPT;
+    ArmOpCode opCode = kThumbBkpt;
     switch (op) {
-        case OP_ADC:
-            opCode = (thumbForm) ? THUMB_ADC_RR : THUMB2_ADC_RRR;
+        case kOpAdc:
+            opCode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
             break;
-        case OP_AND:
-            opCode = (thumbForm) ? THUMB_AND_RR : THUMB2_AND_RRR;
+        case kOpAnd:
+            opCode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
             break;
-        case OP_BIC:
-            opCode = (thumbForm) ? THUMB_BIC_RR : THUMB2_BIC_RRR;
+        case kOpBic:
+            opCode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
             break;
-        case OP_CMN:
+        case kOpCmn:
             assert(shift == 0);
-            opCode = (thumbForm) ? THUMB_CMN_RR : THUMB2_CMN_RR;
+            opCode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
             break;
-        case OP_CMP:
+        case kOpCmp:
             if (thumbForm)
-                opCode = THUMB_CMP_RR;
+                opCode = kThumbCmpRR;
             else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
-                opCode = THUMB_CMP_HH;
+                opCode = kThumbCmpHH;
             else if ((shift == 0) && LOWREG(rDestSrc1))
-                opCode = THUMB_CMP_LH;
+                opCode = kThumbCmpLH;
             else if (shift == 0)
-                opCode = THUMB_CMP_HL;
+                opCode = kThumbCmpHL;
             else
-                opCode = THUMB2_CMP_RR;
+                opCode = kThumb2CmpRR;
             break;
-        case OP_XOR:
-            opCode = (thumbForm) ? THUMB_EOR_RR : THUMB2_EOR_RRR;
+        case kOpXor:
+            opCode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
             break;
-        case OP_MOV:
+        case kOpMov:
             assert(shift == 0);
             if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
-                opCode = THUMB_MOV_RR;
+                opCode = kThumbMovRR;
             else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
-                opCode = THUMB_MOV_RR_H2H;
+                opCode = kThumbMovRR_H2H;
             else if (LOWREG(rDestSrc1))
-                opCode = THUMB_MOV_RR_H2L;
+                opCode = kThumbMovRR_H2L;
             else
-                opCode = THUMB_MOV_RR_L2H;
+                opCode = kThumbMovRR_L2H;
             break;
-        case OP_MUL:
+        case kOpMul:
             assert(shift == 0);
-            opCode = (thumbForm) ? THUMB_MUL : THUMB2_MUL_RRR;
+            opCode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
             break;
-        case OP_MVN:
-            opCode = (thumbForm) ? THUMB_MVN : THUMB2_MVN_RR;
+        case kOpMvn:
+            opCode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
             break;
-        case OP_NEG:
+        case kOpNeg:
             assert(shift == 0);
-            opCode = (thumbForm) ? THUMB_NEG : THUMB2_NEG_RR;
+            opCode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
             break;
-        case OP_OR:
-            opCode = (thumbForm) ? THUMB_ORR : THUMB2_ORR_RRR;
+        case kOpOr:
+            opCode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
             break;
-        case OP_SBC:
-            opCode = (thumbForm) ? THUMB_SBC : THUMB2_SBC_RRR;
+        case kOpSbc:
+            opCode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
             break;
-        case OP_TST:
-            opCode = (thumbForm) ? THUMB_TST : THUMB2_TST_RR;
+        case kOpTst:
+            opCode = (thumbForm) ? kThumbTst : kThumb2TstRR;
             break;
-        case OP_LSL:
+        case kOpLsl:
             assert(shift == 0);
-            opCode = (thumbForm) ? THUMB_LSL_RR : THUMB2_LSL_RRR;
+            opCode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
             break;
-        case OP_LSR:
+        case kOpLsr:
             assert(shift == 0);
-            opCode = (thumbForm) ? THUMB_LSR_RR : THUMB2_LSR_RRR;
+            opCode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
             break;
-        case OP_ASR:
+        case kOpAsr:
             assert(shift == 0);
-            opCode = (thumbForm) ? THUMB_ASR_RR : THUMB2_ASR_RRR;
+            opCode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
             break;
-        case OP_ROR:
+        case kOpRor:
             assert(shift == 0);
-            opCode = (thumbForm) ? THUMB_ROR_RR : THUMB2_ROR_RRR;
+            opCode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
             break;
-        case OP_ADD:
-            opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
+        case kOpAdd:
+            opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
             break;
-        case OP_SUB:
-            opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
+        case kOpSub:
+            opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
             break;
-        case OP_2BYTE:
+        case kOp2Byte:
             assert(shift == 0);
-            return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 8);
-        case OP_2SHORT:
+            return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
+        case kOp2Short:
             assert(shift == 0);
-            return newLIR4(cUnit, THUMB2_SBFX, rDestSrc1, rSrc2, 0, 16);
-        case OP_2CHAR:
+            return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
+        case kOp2Char:
             assert(shift == 0);
-            return newLIR4(cUnit, THUMB2_UBFX, rDestSrc1, rSrc2, 0, 16);
+            return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
         default:
             assert(0);
             break;
@@ -932,7 +481,7 @@ static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
     if (EncodingMap[opCode].flags & IS_BINARY_OP)
         return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
     else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) {
-        if (EncodingMap[opCode].fieldLoc[2].kind == SHIFT)
+        if (EncodingMap[opCode].fieldLoc[2].kind == kFmtShift)
             return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift);
         else
             return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2);
@@ -950,40 +499,246 @@ static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
     return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
 }
 
+static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
+                                int rDest, int rSrc1, int rSrc2, int shift)
+{
+    ArmOpCode opCode = kThumbBkpt;
+    bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
+                      LOWREG(rSrc2);
+    switch (op) {
+        case kOpAdd:
+            opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
+            break;
+        case kOpSub:
+            opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
+            break;
+        case kOpAdc:
+            opCode = kThumb2AdcRRR;
+            break;
+        case kOpAnd:
+            opCode = kThumb2AndRRR;
+            break;
+        case kOpBic:
+            opCode = kThumb2BicRRR;
+            break;
+        case kOpXor:
+            opCode = kThumb2EorRRR;
+            break;
+        case kOpMul:
+            assert(shift == 0);
+            opCode = kThumb2MulRRR;
+            break;
+        case kOpOr:
+            opCode = kThumb2OrrRRR;
+            break;
+        case kOpSbc:
+            opCode = kThumb2SbcRRR;
+            break;
+        case kOpLsl:
+            assert(shift == 0);
+            opCode = kThumb2LslRRR;
+            break;
+        case kOpLsr:
+            assert(shift == 0);
+            opCode = kThumb2LsrRRR;
+            break;
+        case kOpAsr:
+            assert(shift == 0);
+            opCode = kThumb2AsrRRR;
+            break;
+        case kOpRor:
+            assert(shift == 0);
+            opCode = kThumb2RorRRR;
+            break;
+        default:
+            assert(0);
+            break;
+    }
+    assert(opCode >= 0);
+    if (EncodingMap[opCode].flags & IS_QUAD_OP)
+        return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift);
+    else {
+        assert(EncodingMap[opCode].flags & IS_TERTIARY_OP);
+        return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
+    }
+}
+
+static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int rSrc2)
+{
+    return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
+}
+
+static void genLong3Addr(CompilationUnit *cUnit, OpKind firstOp,
+                         OpKind secondOp, RegLocation rlDest,
+                         RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+    rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+    opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+    opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
+                rlSrc2.highReg);
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int value)
+{
+    ArmLIR *res;
+    bool neg = (value < 0);
+    int absValue = (neg) ? -value : value;
+    ArmOpCode opCode = kThumbBkpt;
+    ArmOpCode altOpCode = kThumbBkpt;
+    bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
+    int modImm = modifiedImmediate(value);
+    int modImmNeg = modifiedImmediate(-value);
+
+    switch(op) {
+        case kOpLsl:
+            if (allLowRegs)
+                return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
+            else
+                return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
+        case kOpLsr:
+            if (allLowRegs)
+                return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
+            else
+                return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
+        case kOpAsr:
+            if (allLowRegs)
+                return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
+            else
+                return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
+        case kOpRor:
+            return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
+        case kOpAdd:
+            if (LOWREG(rDest) && (rSrc1 == 13) &&
+                (value <= 1020) && ((value & 0x3)==0)) {
+                return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1,
+                               value >> 2);
+            } else if (LOWREG(rDest) && (rSrc1 == rpc) &&
+                       (value <= 1020) && ((value & 0x3)==0)) {
+                return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1,
+                               value >> 2);
+            }
+            opCode = kThumb2AddRRI8;
+            altOpCode = kThumb2AddRRR;
+            // Note: intentional fallthrough
+        case kOpSub:
+            if (allLowRegs && ((absValue & 0x7) == absValue)) {
+                if (op == kOpAdd)
+                    opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
+                else
+                    opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
+                return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
+            } else if ((absValue & 0xff) == absValue) {
+                if (op == kOpAdd)
+                    opCode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
+                else
+                    opCode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
+                return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
+            }
+            if (modImmNeg >= 0) {
+                op = (op == kOpAdd) ? kOpSub : kOpAdd;
+                modImm = modImmNeg;
+            }
+            if (op == kOpSub) {
+                opCode = kThumb2SubRRI8;
+                altOpCode = kThumb2SubRRR;
+            }
+            break;
+        case kOpAdc:
+            opCode = kThumb2AdcRRI8;
+            altOpCode = kThumb2AdcRRR;
+            break;
+        case kOpSbc:
+            opCode = kThumb2SbcRRI8;
+            altOpCode = kThumb2SbcRRR;
+            break;
+        case kOpOr:
+            opCode = kThumb2OrrRRI8;
+            altOpCode = kThumb2OrrRRR;
+            break;
+        case kOpAnd:
+            opCode = kThumb2AndRRI8;
+            altOpCode = kThumb2AndRRR;
+            break;
+        case kOpXor:
+            opCode = kThumb2EorRRI8;
+            altOpCode = kThumb2EorRRR;
+            break;
+        case kOpMul:
+            //TUNING: power of 2, shift & add
+            modImm = -1;
+            altOpCode = kThumb2MulRRR;
+            break;
+        case kOpCmp: {
+            int modImm = modifiedImmediate(value);
+            ArmLIR *res;
+            if (modImm >= 0) {
+                res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm);
+            } else {
+                int rTmp = allocTemp(cUnit);
+                res = loadConstant(cUnit, rTmp, value);
+                opRegReg(cUnit, kOpCmp, rSrc1, rTmp);
+                freeTemp(cUnit, rTmp);
+            }
+            return res;
+        }
+        default:
+            assert(0);
+    }
+
+    if (modImm >= 0) {
+        return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
+    } else {
+        int rScratch = allocTemp(cUnit);
+        loadConstant(cUnit, rScratch, value);
+        if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
+            res = newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
+        else
+            res = newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
+        freeTemp(cUnit, rScratch);
+        return res;
+    }
+}
+
 /* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
 static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
-                        int value, int rScratch)
+                        int value)
 {
     ArmLIR *res;
     bool neg = (value < 0);
     int absValue = (neg) ? -value : value;
     bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
-    ArmOpCode opCode = THUMB_BKPT;
+    ArmOpCode opCode = kThumbBkpt;
     switch (op) {
-        case OP_ADD:
+        case kOpAdd:
             if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
                 assert((value & 0x3) == 0);
-                return newLIR1(cUnit, THUMB_ADD_SPI7, value >> 2);
+                return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
             } else if (shortForm) {
-                opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
+                opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
             }
             break;
-        case OP_SUB:
+        case kOpSub:
             if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
                 assert((value & 0x3) == 0);
-                return newLIR1(cUnit, THUMB_SUB_SPI7, value >> 2);
+                return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
             } else if (shortForm) {
-                opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
+                opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
             }
             break;
-        case OP_CMP:
+        case kOpCmp:
             if (LOWREG(rDestSrc1) && shortForm)
-                opCode = (shortForm) ?  THUMB_CMP_RI8 : THUMB_CMP_RR;
+                opCode = (shortForm) ?  kThumbCmpRI8 : kThumbCmpRR;
             else if (LOWREG(rDestSrc1))
-                opCode = THUMB_CMP_RR;
+                opCode = kThumbCmpRR;
             else {
                 shortForm = false;
-                opCode = THUMB_CMP_HL;
+                opCode = kThumbCmpHL;
             }
             break;
         default:
@@ -993,395 +748,829 @@ static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
     }
     if (shortForm)
         return newLIR2(cUnit, opCode, rDestSrc1, absValue);
-    else
-        return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value, rScratch);
+    else {
+        return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
+    }
 }
 
-static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
-                                int rDest, int rSrc1, int rSrc2, int shift)
+static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
+                        RegLocation rlSrc)
 {
-    ArmOpCode opCode = THUMB_BKPT;
-    bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
-                      LOWREG(rSrc2);
-    switch (op) {
-        case OP_ADD:
-            opCode = (thumbForm) ? THUMB_ADD_RRR : THUMB2_ADD_RRR;
+    RegLocation rlResult;
+    rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+    rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
+    storeValue(cUnit, rlDest, rlResult);
+}
+
+static void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
+                        RegLocation rlSrc)
+{
+    RegLocation rlResult;
+    rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+    rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlSrc.lowReg, rlSrc.highReg));
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+/*
+ * To avoid possible conflicts, we use a lot of temps here.  Note that
+ * our usage of Thumb2 instruction forms avoids the problems with register
+ * reuse for multiply instructions prior to arm6.
+ */
+static void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
+                       RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    int resLo = allocTemp(cUnit);
+    int resHi = allocTemp(cUnit);
+    int tmp1 = allocTemp(cUnit);
+
+    rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+
+    newLIR3(cUnit, kThumb2MulRRR, tmp1, rlSrc2.lowReg, rlSrc1.highReg);
+    newLIR4(cUnit, kThumb2Umull, resLo, resHi, rlSrc2.lowReg, rlSrc1.lowReg);
+    newLIR4(cUnit, kThumb2Mla, tmp1, rlSrc1.lowReg, rlSrc2.highReg, tmp1);
+    newLIR4(cUnit, kThumb2AddRRR, resHi, tmp1, resHi, 0);
+    freeTemp(cUnit, tmp1);
+
+    rlResult = getReturnLocWide(cUnit);  // Just as a template, will patch
+    rlResult.lowReg = resLo;
+    rlResult.highReg = resHi;
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+/*
+ * Handle simple case (thin lock) inline.  If it's complicated, bail
+ * out to the heavyweight lock/unlock routines.  We'll use dedicated
+ * registers here in order to be in the right position in case we
+ * to bail to dvm[Lock/Unlock]Object(self, object)
+ *
+ * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
+ * r1 -> object [arg1 for dvm[Lock/Unlock]Object
+ * r2 -> intial contents of object->lock.thin, later result of strex
+ * r3 -> self->threadId
+ * r7 -> temp to hold new lock value [unlock only]
+ * r4 -> allow to be used by utilities as general temp
+ *
+ * The result of the strex is 0 if we acquire the lock.
+ */
+static void handleMonitor(CompilationUnit *cUnit, MIR *mir)
+{
+#if defined (THIN_LOCKING)
+    RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+    bool enter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
+    ArmLIR *target;
+    ArmLIR *branch;
+
+    loadValueDirectFixed(cUnit, rlSrc, r1);  // Get obj
+    lockAllTemps(cUnit);  // Prepare for explicit register usage
+    freeTemp(cUnit, r4PC);  // Free up r4 for general use
+    loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0); // Get self
+    genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
+    loadWordDisp(cUnit, r0, offsetof(Thread, threadId), r3); // Get threadId
+    newLIR3(cUnit, kThumb2Ldrex, r2, r1,
+            offsetof(Object, lock.thin) >> 2); // Get object->lock.thin
+    // Is lock.thin unheld on lock or held by us (==threadId) on unlock?
+    if (enter) {
+        opRegImm(cUnit, kOpSub, r2, DVM_LOCK_INITIAL_THIN_VALUE);
+    } else {
+        loadConstant(cUnit, r7, DVM_LOCK_INITIAL_THIN_VALUE);
+        opRegReg(cUnit, kOpSub, r2, r3);
+    }
+    // Note: start of IT block.  If last sub result != clear, else strex
+    genIT(cUnit, kArmCondNe, "E");
+    newLIR0(cUnit, kThumb2Clrex);
+    if (enter) {
+        newLIR4(cUnit, kThumb2Strex, r2, r3, r1,
+                offsetof(Object, lock.thin) >> 2);
+    } else {
+        newLIR4(cUnit, kThumb2Strex, r2, r7, r1,
+                offsetof(Object, lock.thin) >> 2);
+    }
+    // Note: end of IT block
+
+    branch = newLIR2(cUnit, kThumb2Cbz, r2, 0);
+
+    if (enter) {
+        loadConstant(cUnit, r7, (int)dvmLockObject);
+    } else {
+        loadConstant(cUnit, r7, (int)dvmUnlockObject);
+    }
+    genExportPC(cUnit, mir);
+    opReg(cUnit, kOpBlx, r7);
+
+    clobberCallRegs(cUnit);
+
+    // Resume here
+    target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branch->generic.target = (LIR *)target;
+#else
+    handleMonitorPortable(cUnit, mir);
+#endif
+}
+
+/*
+ * 64-bit 3way compare function.
+ *     mov   r7, #-1
+ *     cmp   op1hi, op2hi
+ *     blt   done
+ *     bgt   flip
+ *     sub   r7, op1lo, op2lo (treat as unsigned)
+ *     beq   done
+ *     ite   hi
+ *     mov(hi)   r7, #-1
+ *     mov(!hi)  r7, #1
+ * flip:
+ *     neg   r7
+ * done:
+ */
+static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
+                       RegLocation rlDest, RegLocation rlSrc1,
+                       RegLocation rlSrc2)
+{
+    RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
+    ArmLIR *target1;
+    ArmLIR *target2;
+    rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+    rlTemp.lowReg = allocTemp(cUnit);
+    loadConstant(cUnit, rlTemp.lowReg, -1);
+    opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
+    ArmLIR *branch1 = opCondBranch(cUnit, kArmCondLt);
+    ArmLIR *branch2 = opCondBranch(cUnit, kArmCondGt);
+    opRegRegReg(cUnit, kOpSub, rlTemp.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+    ArmLIR *branch3 = opCondBranch(cUnit, kArmCondEq);
+
+    genIT(cUnit, kArmCondHi, "E");
+    newLIR2(cUnit, kThumb2MovImmShift, rlTemp.lowReg, modifiedImmediate(-1));
+    loadConstant(cUnit, rlTemp.lowReg, 1);
+    genBarrier(cUnit);
+
+    target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target2->defMask = -1;
+    opRegReg(cUnit, kOpNeg, rlTemp.lowReg, rlTemp.lowReg);
+
+    target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target1->defMask = -1;
+
+    storeValue(cUnit, rlDest, rlTemp);
+
+    branch1->generic.target = (LIR *)target1;
+    branch2->generic.target = (LIR *)target2;
+    branch3->generic.target = branch1->generic.target;
+}
+
+static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
+                               int rIndex, int rDest, int scale, OpSize size)
+{
+    bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
+    ArmOpCode opCode = kThumbBkpt;
+    bool thumbForm = (allLowRegs && (scale == 0));
+    int regPtr;
+
+    if (FPREG(rDest)) {
+        assert(SINGLEREG(rDest));
+        assert((size == kWord) || (size == kSingle));
+        opCode = kThumb2Vldrs;
+        size = kSingle;
+    } else {
+        if (size == kSingle)
+            size = kWord;
+    }
+
+    switch (size) {
+        case kSingle:
+            regPtr = allocTemp(cUnit);
+            if (scale) {
+                newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
+                        encodeShift(kArmLsl, scale));
+            } else {
+                opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
+            }
+            return newLIR3(cUnit, opCode, rDest, regPtr, 0);
+        case kWord:
+            opCode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
             break;
-        case OP_SUB:
-            opCode = (thumbForm) ? THUMB_SUB_RRR : THUMB2_SUB_RRR;
+        case kUnsignedHalf:
+            opCode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR;
             break;
-        case OP_ADC:
-            opCode = THUMB2_ADC_RRR;
+        case kSignedHalf:
+            opCode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR;
             break;
-        case OP_AND:
-            opCode = THUMB2_AND_RRR;
+        case kUnsignedByte:
+            opCode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR;
             break;
-        case OP_BIC:
-            opCode = THUMB2_BIC_RRR;
+        case kSignedByte:
+            opCode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
             break;
-        case OP_XOR:
-            opCode = THUMB2_EOR_RRR;
+        default:
+            assert(0);
+    }
+    if (thumbForm)
+        return newLIR3(cUnit, opCode, rDest, rBase, rIndex);
+    else
+        return newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
+}
+
+static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
+                                int rIndex, int rSrc, int scale, OpSize size)
+{
+    bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
+    ArmOpCode opCode = kThumbBkpt;
+    bool thumbForm = (allLowRegs && (scale == 0));
+    int regPtr;
+
+    if (FPREG(rSrc)) {
+        assert(SINGLEREG(rSrc));
+        assert((size == kWord) || (size == kSingle));
+        opCode = kThumb2Vstrs;
+        size = kSingle;
+    } else {
+        if (size == kSingle)
+            size = kWord;
+    }
+
+    switch (size) {
+        case kSingle:
+            regPtr = allocTemp(cUnit);
+            if (scale) {
+                newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
+                        encodeShift(kArmLsl, scale));
+            } else {
+                opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
+            }
+            return newLIR3(cUnit, opCode, rSrc, regPtr, 0);
+        case kWord:
+            opCode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
             break;
-        case OP_MUL:
-            assert(shift == 0);
-            opCode = THUMB2_MUL_RRR;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            opCode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR;
             break;
-        case OP_OR:
-            opCode = THUMB2_ORR_RRR;
+        case kUnsignedByte:
+        case kSignedByte:
+            opCode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR;
             break;
-        case OP_SBC:
-            opCode = THUMB2_SBC_RRR;
+        default:
+            assert(0);
+    }
+    if (thumbForm)
+        return newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
+    else
+        return newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
+}
+
+/* Load a float to a Dalvik register. */
+static ArmLIR *fpVarAccess(CompilationUnit *cUnit, int vSrcDest,
+                           int rSrcDest, ArmOpCode opCode)
+{
+    ArmLIR *res;
+    if (vSrcDest > 255) {
+        int rTmp = allocTemp(cUnit);
+        opRegRegImm(cUnit, kOpAdd, rTmp, rFP, vSrcDest * 4);
+        res = newLIR3(cUnit, opCode, rSrcDest, rTmp, 0);
+        freeTemp(cUnit, rTmp);
+    } else {
+        res = newLIR3(cUnit, opCode, rSrcDest, rFP, vSrcDest);
+    }
+    return res;
+}
+
+/*
+ * 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.
+ */
+static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDest, int rDestHi,
+                                OpSize size, bool nullCheck, int sReg)
+{
+    ArmLIR *first = NULL;
+    ArmLIR *res, *load;
+    ArmOpCode opCode = kThumbBkpt;
+    bool shortForm = false;
+    bool thumb2Form = (displacement < 4092 && displacement >= 0);
+    int shortMax = 128;
+    bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
+    int encodedDisp = displacement;
+
+    switch (size) {
+        case kDouble:
+        case kLong:
+            if (FPREG(rDest)) {
+                if (SINGLEREG(rDest)) {
+                    assert(FPREG(rDestHi));
+                    rDest = S2D(rDest, rDestHi);
+                }
+                opCode = kThumb2Vldrd;
+                if (displacement <= 1020) {
+                    shortForm = true;
+                    encodedDisp >>= 2;
+                }
+                break;
+            } else {
+                res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest,
+                                       -1, kWord, nullCheck, sReg);
+                loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi,
+                                 -1, kWord, false, INVALID_SREG);
+                return res;
+            }
+        case kSingle:
+        case kWord:
+            if (FPREG(rDest)) {
+                opCode = kThumb2Vldrs;
+                if (displacement <= 1020) {
+                    shortForm = true;
+                    encodedDisp >>= 2;
+                }
+                break;
+            }
+            if (LOWREG(rDest) && (rBase == rpc) &&
+                (displacement <= 1020) && (displacement >= 0)) {
+                shortForm = true;
+                encodedDisp >>= 2;
+                opCode = kThumbLdrPcRel;
+            } else if (LOWREG(rDest) && (rBase == r13) &&
+                      (displacement <= 1020) && (displacement >= 0)) {
+                shortForm = true;
+                encodedDisp >>= 2;
+                opCode = kThumbLdrSpRel;
+            } else if (allLowRegs && displacement < 128 && displacement >= 0) {
+                assert((displacement & 0x3) == 0);
+                shortForm = true;
+                encodedDisp >>= 2;
+                opCode = kThumbLdrRRI5;
+            } else if (thumb2Form) {
+                shortForm = true;
+                opCode = kThumb2LdrRRI12;
+            }
             break;
-        case OP_LSL:
-            assert(shift == 0);
-            opCode = THUMB2_LSL_RRR;
+        case kUnsignedHalf:
+            if (allLowRegs && displacement < 64 && displacement >= 0) {
+                assert((displacement & 0x1) == 0);
+                shortForm = true;
+                encodedDisp >>= 1;
+                opCode = kThumbLdrhRRI5;
+            } else if (displacement < 4092 && displacement >= 0) {
+                shortForm = true;
+                opCode = kThumb2LdrhRRI12;
+            }
             break;
-        case OP_LSR:
-            assert(shift == 0);
-            opCode = THUMB2_LSR_RRR;
+        case kSignedHalf:
+            if (thumb2Form) {
+                shortForm = true;
+                opCode = kThumb2LdrshRRI12;
+            }
             break;
-        case OP_ASR:
-            assert(shift == 0);
-            opCode = THUMB2_ASR_RRR;
+        case kUnsignedByte:
+            if (allLowRegs && displacement < 32 && displacement >= 0) {
+                shortForm = true;
+                opCode = kThumbLdrbRRI5;
+            } else if (thumb2Form) {
+                shortForm = true;
+                opCode = kThumb2LdrbRRI12;
+            }
             break;
-        case OP_ROR:
-            assert(shift == 0);
-            opCode = THUMB2_ROR_RRR;
+        case kSignedByte:
+            if (thumb2Form) {
+                shortForm = true;
+                opCode = kThumb2LdrsbRRI12;
+            }
             break;
         default:
             assert(0);
-            break;
     }
-    assert(opCode >= 0);
-    if (EncodingMap[opCode].flags & IS_QUAD_OP)
-        return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift);
-    else {
-        assert(EncodingMap[opCode].flags & IS_TERTIARY_OP);
-        return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
+    if (nullCheck)
+        first = genNullCheck(cUnit, sReg, rBase, mir->offset, NULL);
+    if (shortForm) {
+        load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
+    } else {
+        int regOffset = allocTemp(cUnit);
+        res = loadConstant(cUnit, regOffset, encodedDisp);
+        load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size);
+        freeTemp(cUnit, regOffset);
+    }
+
+    if (rBase == rFP) {
+        annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
     }
+    return (first) ? first : res;
 }
 
-static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
-                           int rSrc1, int rSrc2)
+static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
+                            int displacement, int rDest, OpSize size,
+                            bool nullCheck, int sReg)
 {
-    return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
+                            size, nullCheck, sReg);
 }
 
-static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
-                           int rSrc1, int value, int rScratch)
+static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDestLo, int rDestHi,
+                                bool nullCheck, int sReg)
 {
-    ArmLIR *res;
-    bool neg = (value < 0);
-    int absValue = (neg) ? -value : value;
-    ArmOpCode opCode = THUMB_BKPT;
-    ArmOpCode altOpCode = THUMB_BKPT;
-    bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
-    int modImm = modifiedImmediate(value);
-    int modImmNeg = modifiedImmediate(-value);
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
+                            kLong, nullCheck, sReg);
+}
 
-    switch(op) {
-        case OP_LSL:
-            if (allLowRegs)
-                return newLIR3(cUnit, THUMB_LSL_RRI5, rDest, rSrc1, value);
-            else
-                return newLIR3(cUnit, THUMB2_LSL_RRI5, rDest, rSrc1, value);
-        case OP_LSR:
-            if (allLowRegs)
-                return newLIR3(cUnit, THUMB_LSR_RRI5, rDest, rSrc1, value);
-            else
-                return newLIR3(cUnit, THUMB2_LSR_RRI5, rDest, rSrc1, value);
-        case OP_ASR:
-            if (allLowRegs)
-                return newLIR3(cUnit, THUMB_ASR_RRI5, rDest, rSrc1, value);
-            else
-                return newLIR3(cUnit, THUMB2_ASR_RRI5, rDest, rSrc1, value);
-        case OP_ROR:
-            return newLIR3(cUnit, THUMB2_ROR_RRI5, rDest, rSrc1, value);
-        case OP_ADD:
-            if (LOWREG(rDest) && (rSrc1 == 13) &&
-                (value <= 1020) && ((value & 0x3)==0)) {
-                return newLIR3(cUnit, THUMB_ADD_SP_REL, rDest, rSrc1,
-                               value >> 2);
-            } else if (LOWREG(rDest) && (rSrc1 == rpc) &&
-                       (value <= 1020) && ((value & 0x3)==0)) {
-                return newLIR3(cUnit, THUMB_ADD_PC_REL, rDest, rSrc1,
-                               value >> 2);
-            }
-            opCode = THUMB2_ADD_RRI8;
-            altOpCode = THUMB2_ADD_RRR;
-            // Note: intentional fallthrough
-        case OP_SUB:
-            if (allLowRegs && ((absValue & 0x7) == absValue)) {
-                if (op == OP_ADD)
-                    opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
-                else
-                    opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
-                return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
-            } else if ((absValue & 0xff) == absValue) {
-                if (op == OP_ADD)
-                    opCode = (neg) ? THUMB2_SUB_RRI12 : THUMB2_ADD_RRI12;
-                else
-                    opCode = (neg) ? THUMB2_ADD_RRI12 : THUMB2_SUB_RRI12;
-                return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
+
+static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc, int rSrcHi,
+                             OpSize size)
+{
+    ArmLIR *res, *store;
+    ArmOpCode opCode = kThumbBkpt;
+    bool shortForm = false;
+    bool thumb2Form = (displacement < 4092 && displacement >= 0);
+    int shortMax = 128;
+    bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
+    int encodedDisp = displacement;
+
+    switch (size) {
+        case kLong:
+        case kDouble:
+            if (!FPREG(rSrc)) {
+                res = storeBaseDispBody(cUnit, rBase, displacement, rSrc,
+                                        -1, kWord);
+                storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi,
+                                  -1, kWord);
+                return res;
             }
-            if (modImmNeg >= 0) {
-                op = (op == OP_ADD) ? OP_SUB : OP_ADD;
-                modImm = modImmNeg;
+            if (SINGLEREG(rSrc)) {
+                assert(FPREG(rSrcHi));
+                rSrc = S2D(rSrc, rSrcHi);
             }
-            if (op == OP_SUB) {
-                opCode = THUMB2_SUB_RRI8;
-                altOpCode = THUMB2_SUB_RRR;
+            opCode = kThumb2Vstrd;
+            if (displacement <= 1020) {
+                shortForm = true;
+                encodedDisp >>= 2;
             }
             break;
-        case OP_ADC:
-            opCode = THUMB2_ADC_RRI8;
-            altOpCode = THUMB2_ADC_RRR;
-            break;
-        case OP_SBC:
-            opCode = THUMB2_SBC_RRI8;
-            altOpCode = THUMB2_SBC_RRR;
+        case kSingle:
+        case kWord:
+            if (FPREG(rSrc)) {
+                assert(SINGLEREG(rSrc));
+                opCode = kThumb2Vstrs;
+                if (displacement <= 1020) {
+                    shortForm = true;
+                    encodedDisp >>= 2;
+                }
             break;
-        case OP_OR:
-            opCode = THUMB2_ORR_RRI8;
-            altOpCode = THUMB2_ORR_RRR;
-            break;
-        case OP_AND:
-            opCode = THUMB2_AND_RRI8;
-            altOpCode = THUMB2_AND_RRR;
+            }
+            if (allLowRegs && displacement < 128 && displacement >= 0) {
+                assert((displacement & 0x3) == 0);
+                shortForm = true;
+                encodedDisp >>= 2;
+                opCode = kThumbStrRRI5;
+            } else if (thumb2Form) {
+                shortForm = true;
+                opCode = kThumb2StrRRI12;
+            }
             break;
-        case OP_XOR:
-            opCode = THUMB2_EOR_RRI8;
-            altOpCode = THUMB2_EOR_RRR;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            if (allLowRegs && displacement < 64 && displacement >= 0) {
+                assert((displacement & 0x1) == 0);
+                shortForm = true;
+                encodedDisp >>= 1;
+                opCode = kThumbStrhRRI5;
+            } else if (thumb2Form) {
+                shortForm = true;
+                opCode = kThumb2StrhRRI12;
+            }
             break;
-        case OP_MUL:
-            //TUNING: power of 2, shift & add
-            modImm = -1;
-            altOpCode = THUMB2_MUL_RRR;
+        case kUnsignedByte:
+        case kSignedByte:
+            if (allLowRegs && displacement < 32 && displacement >= 0) {
+                shortForm = true;
+                opCode = kThumbStrbRRI5;
+            } else if (thumb2Form) {
+                shortForm = true;
+                opCode = kThumb2StrhRRI12;
+            }
             break;
         default:
             assert(0);
     }
+    if (shortForm) {
+        store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
+    } else {
+        int rScratch = allocTemp(cUnit);
+        res = loadConstant(cUnit, rScratch, encodedDisp);
+        store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
+        freeTemp(cUnit, rScratch);
+    }
+
+    if (rBase == rFP) {
+        annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
+    }
+    return res;
+}
+
+static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc, OpSize size)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
+}
+
+static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrcLo, int rSrcHi)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
+}
+
+static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    ArmLIR *res;
+    genBarrier(cUnit);
+    if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
+        res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
+    } else {
+        res = newLIR2(cUnit, kThumb2Ldmia, rBase, rMask);
+    }
+    genBarrier(cUnit);
+    return res;
+}
+
+static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    ArmLIR *res;
+    genBarrier(cUnit);
+    if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
+        res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
+    } else {
+        res = newLIR2(cUnit, kThumb2Stmia, rBase, rMask);
+    }
+    genBarrier(cUnit);
+    return res;
+}
+
+static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest,
+                                   int value)
+{
+    int encodedImm = encodeImmSingle(value);
+    assert(SINGLEREG(rDest));
+    if (encodedImm >= 0) {
+        return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
+    }
+    ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
+    if (dataTarget == NULL) {
+        dataTarget = addWordData(cUnit, value, false);
+    }
+    ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
+    loadPcRel->opCode = kThumb2Vldrs;
+    loadPcRel->generic.target = (LIR *) dataTarget;
+    loadPcRel->operands[0] = rDest;
+    loadPcRel->operands[1] = rpc;
+    setupResourceMasks(loadPcRel);
+    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
+    return loadPcRel;
+}
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
+}
+
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, false,
+                     INVALID_SREG);
+}
+
+
+/*
+ * Load a immediate using a shortcut if possible; otherwise
+ * grab from the per-translation literal pool.
+ */
+static ArmLIR *loadConstantValue(CompilationUnit *cUnit, int rDest, int value)
+{
+    ArmLIR *res;
+    int modImm;
+
+    if (FPREG(rDest)) {
+        return loadFPConstantValue(cUnit, rDest, value);
+    }
 
+    /* See if the value can be constructed cheaply */
+    if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
+        return newLIR2(cUnit, kThumbMovImm, rDest, value);
+    }
+    /* Check Modified immediate special cases */
+    modImm = modifiedImmediate(value);
     if (modImm >= 0) {
-        return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
+        res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
+        return res;
+    }
+    modImm = modifiedImmediate(~value);
+    if (modImm >= 0) {
+        res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm);
+        return res;
+    }
+    /* 16-bit immediate? */
+    if ((value & 0xffff) == value) {
+        res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
+        return res;
+    }
+    /* No shortcut - go ahead and use literal pool */
+    ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
+    if (dataTarget == NULL) {
+        dataTarget = addWordData(cUnit, value, false);
+    }
+    ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
+    loadPcRel->opCode = LOWREG(rDest) ? kThumbLdrPcRel : kThumb2LdrPcRel12;
+    loadPcRel->generic.target = (LIR *) dataTarget;
+    loadPcRel->operands[0] = rDest;
+    setupResourceMasks(loadPcRel);
+    res = loadPcRel;
+    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
+
+    /*
+     * To save space in the constant pool, we use the ADD_RRI8 instruction to
+     * add up to 255 to an existing constant value.
+     */
+    if (dataTarget->operands[0] != value) {
+        opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
+    }
+    return res;
+}
+
+static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
+                                     int rDestHi, int valLo, int valHi)
+{
+    int encodedImm = encodeImmDouble(valLo, valHi);
+    ArmLIR *res;
+    if (FPREG(rDestLo) && (encodedImm >= 0)) {
+        res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi),
+                      encodedImm);
     } else {
-        loadConstant(cUnit, rScratch, value);
-        if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
-            return newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
-        else
-            return newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
+        res = loadConstantValue(cUnit, rDestLo, valLo);
+        loadConstantValue(cUnit, rDestHi, valHi);
     }
+    return res;
 }
 
 /*
- * 64-bit 3way compare function.
- *     mov   r7, #-1
- *     cmp   op1hi, op2hi
- *     blt   done
- *     bgt   flip
- *     sub   r7, op1lo, op2lo (treat as unsigned)
- *     beq   done
- *     ite   hi
- *     mov(hi)   r7, #-1
- *     mov(!hi)  r7, #1
- * flip:
- *     neg   r7
- * done:
+ * Perform a "reg cmp imm" operation and jump to the PCR region if condition
+ * satisfies.
  */
-static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
-                               int vDest, int vSrc1, int vSrc2)
+static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
+                                         ArmConditionCode cond, int reg,
+                                         int checkValue, int dOffset,
+                                         ArmLIR *pcrLabel)
 {
-    int op1lo = selectFirstRegister(cUnit, vSrc1, true);
-    int op1hi = NEXT_REG(op1lo);
-    int op2lo = NEXT_REG(op1hi);
-    int op2hi = NEXT_REG(op2lo);
-    loadValuePair(cUnit, vSrc1, op1lo, op1hi);
-    loadValuePair(cUnit, vSrc2, op2lo, op2hi);
-    /* Note: using hardcoded r7 & r4PC for now.  revisit */
-    loadConstant(cUnit, r7, -1);
-    opRegReg(cUnit, OP_CMP, op1hi, op2hi);
-    ArmLIR *branch1 = opCondBranch(cUnit, ARM_COND_LT);
-    ArmLIR *branch2 = opCondBranch(cUnit, ARM_COND_GT);
-    opRegRegReg(cUnit, OP_SUB, r7, op1lo, op2lo);
-    ArmLIR *branch3 = opCondBranch(cUnit, ARM_COND_EQ);
-
-    // TODO: need assert mechanism to verify IT block size
-    branch1->generic.target = (LIR *) genIT(cUnit, ARM_COND_HI, "E");
-    newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, r7, modifiedImmediate(-1));
-    newLIR2(cUnit, THUMB_MOV_IMM, r7, 1);
-    genBarrier(cUnit);
+    ArmLIR *branch;
+    int modImm;
+    /*
+     * TODO: re-enable usage of kThumb2Cbz & kThumb2Cbnz once assembler is
+     * enhanced to allow us to replace code patterns when instructions don't
+     * reach.  Currently, CB[N]Z is causing too many assembler aborts.
+     * What we want to do is emit the short forms, and then replace them with
+     * longer versions when needed.
+     */
 
-    branch2->generic.target = (LIR *) opRegReg(cUnit, OP_NEG, r7, r7);
-    branch1->generic.target = (LIR *) storeValue(cUnit, r7, vDest, r4PC);
-    branch3->generic.target = branch1->generic.target;
+    if (0 && (LOWREG(reg)) && (checkValue == 0) &&
+       ((cond == kArmCondEq) || (cond == kArmCondNe))) {
+        branch = newLIR2(cUnit,
+                         (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
+                         reg, 0);
+    } else {
+        modImm = modifiedImmediate(checkValue);
+        if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
+            newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
+        } else if (modImm >= 0) {
+            newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
+        } else {
+            int tReg = allocTemp(cUnit);
+            loadConstant(cUnit, tReg, checkValue);
+            opRegReg(cUnit, kOpCmp, reg, tReg);
+        }
+        branch = newLIR2(cUnit, kThumbBCond, 0, cond);
+    }
+    return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
 }
 
 static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
 {
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int offset = offsetof(InterpState, retval);
-    int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
-    int reg1 = NEXT_REG(regObj);
-    int vDest = inlinedTarget(mir);
-    loadValue(cUnit, dInsn->arg[0], regObj);
-    genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
-    loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
-    if (vDest >= 0)
-        storeValue(cUnit, reg1, vDest, regObj);
-    else
-        storeWordDisp(cUnit, rGLUE, offset, reg1, rNone);
+    RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+    genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
+    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
+                 rlResult.lowReg);
+    storeValue(cUnit, rlDest, rlResult);
     return false;
 }
 
 static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
 {
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int offset = offsetof(InterpState, retval);
     int contents = offsetof(ArrayObject, contents);
-    int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
-    int regIdx = NEXT_REG(regObj);
-    int regMax = NEXT_REG(regIdx);
-    int regOff = NEXT_REG(regMax);
-    int vDest = inlinedTarget(mir);
-    loadValue(cUnit, dInsn->arg[0], regObj);
-    loadValue(cUnit, dInsn->arg[1], regIdx);
-    ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
-                                         mir->offset, NULL);
-    loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
-    loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
-    loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
-    genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
-    opRegImm(cUnit, OP_ADD, regObj, contents, rNone);
-    opRegReg(cUnit, OP_ADD, regIdx, regOff);
-    loadBaseIndexed(cUnit, regObj, regIdx, regMax, 1, UNSIGNED_HALF);
-    if (vDest >= 0)
-        storeValue(cUnit, regMax, vDest, regObj);
-    else
-        storeWordDisp(cUnit, rGLUE, offset, regMax, rNone);
+    RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlIdx = getSrcLoc(cUnit, mir, 1);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+    RegLocation rlResult;
+    rlObj = loadValue(cUnit, rlObj, kCoreReg);
+    rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
+    int regMax = allocTemp(cUnit);
+    int regOff = allocTemp(cUnit);
+    int regPtr = allocTemp(cUnit);
+    ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
+                                    mir->offset, NULL);
+    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
+    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
+    loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
+    genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
+    freeTemp(cUnit, regMax);
+    opRegImm(cUnit, kOpAdd, regPtr, contents);
+    opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
+    rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+    loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
+    storeValue(cUnit, rlDest, rlResult);
     return false;
 }
 
 static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
 {
-    int offset = offsetof(InterpState, retval);
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
-    int sign = NEXT_REG(reg0);
-    int vDest = inlinedTarget(mir);
-    /* abs(x) = y<=x>>31, (x+y)^y.  */
-    loadValue(cUnit, dInsn->arg[0], reg0);
+    RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, false);;
+    RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+    int signReg = allocTemp(cUnit);
     /*
+     * abs(x) = y<=x>>31, (x+y)^y.
      * Thumb2's IT block also yields 3 instructions, but imposes
      * scheduling constraints.
      */
-    opRegRegImm(cUnit, OP_ASR, sign, reg0, 31, rNone);
-    opRegReg(cUnit, OP_ADD, reg0, sign);
-    opRegReg(cUnit, OP_XOR, reg0, sign);
-    if (vDest >= 0)
-        storeValue(cUnit, reg0, vDest, sign);
-    else
-        storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
+    opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
+    opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
+    opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
+    storeValue(cUnit, rlDest, rlResult);
     return false;
 }
 
 static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
 {
-    int offset = offsetof(InterpState, retval);
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
-    int signMask = NEXT_REG(reg0);
-    int vDest = inlinedTarget(mir);
-    // TUNING: handle case of src already in FP reg
-    loadValue(cUnit, dInsn->arg[0], reg0);
-    loadConstant(cUnit, signMask, 0x7fffffff);
-    newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
-    if (vDest >= 0)
-        storeValue(cUnit, reg0, vDest, signMask);
-    else
-        storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
-    return false;
+    RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, true);
+    rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+    RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR2(cUnit, kThumb2Vabss, rlResult.lowReg, rlSrc.lowReg);
+    storeValue(cUnit, rlDest, rlResult);
+    return true;
 }
 
 static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
 {
-    int offset = offsetof(InterpState, retval);
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
-    int ophi = NEXT_REG(oplo);
-    int signMask = NEXT_REG(ophi);
-    int vSrc = dInsn->arg[0];
-    int vDest = inlinedTarget(mir);
-    // TUNING: handle case of src already in FP reg
-    if (vDest >= 0) {
-        /*
-         * FIXME: disable this case to to work around bug until after
-         * new schedule/ralloc mechanisms are done.
-         */
-        if (0 && (vDest == vSrc)) {
-            loadValue(cUnit, vSrc+1, ophi);
-            opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
-            storeValue(cUnit, ophi, vDest + 1, signMask);
-        } else {
-            loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
-            opRegRegImm(cUnit, OP_AND, ophi, ophi, 0x7fffffff, signMask);
-            storeValuePair(cUnit, oplo, ophi, vDest, signMask);
-        }
-    } else {
-        loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
-        loadConstant(cUnit, signMask, 0x7fffffff);
-        storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
-        opRegReg(cUnit, OP_AND, ophi, signMask);
-        storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
-    }
-    return false;
+    RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+    RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
+    rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+    RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR2(cUnit, kThumb2Vabsd, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlSrc.lowReg, rlSrc.highReg));
+    storeValueWide(cUnit, rlDest, rlResult);
+    return true;
 }
 
 static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
 {
-    int offset = offsetof(InterpState, retval);
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
-    int reg1 = NEXT_REG(reg0);
-    int vDest = inlinedTarget(mir);
-    loadValue(cUnit, dInsn->arg[0], reg0);
-    loadValue(cUnit, dInsn->arg[1], reg1);
-    opRegReg(cUnit, OP_CMP, reg0, reg1);
-    //TODO: need assertion mechanism to validate IT region size
-    genIT(cUnit, (isMin) ? ARM_COND_GT : ARM_COND_LT, "");
-    opRegReg(cUnit, OP_MOV, reg0, reg1);
+    RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
+    rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
+    RegLocation rlDest = inlinedTarget(cUnit, mir, false);
+    RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+    opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
+    genIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E");
+    opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg);
+    opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg);
     genBarrier(cUnit);
-    if (vDest >= 0)
-        storeValue(cUnit, reg0, vDest, reg1);
-    else
-        storeWordDisp(cUnit, rGLUE, offset, reg0, rNone);
+    storeValue(cUnit, rlDest, rlResult);
     return false;
 }
 
 static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
 {
-    int offset = offsetof(InterpState, retval);
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
-    int ophi = NEXT_REG(oplo);
-    int sign = NEXT_REG(ophi);
-    int vDest = inlinedTarget(mir);
-    /* abs(x) = y<=x>>31, (x+y)^y. */
-    loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
+    RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+    RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
+    rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+    RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+    int signReg = allocTemp(cUnit);
     /*
+     * abs(x) = y<=x>>31, (x+y)^y.
      * Thumb2 IT block allows slightly shorter sequence,
      * but introduces a scheduling barrier.  Stick with this
      * mechanism for now.
      */
-    opRegRegImm(cUnit, OP_ASR, sign, ophi, 31, rNone);
-    opRegReg(cUnit, OP_ADD, oplo, sign);
-    opRegReg(cUnit, OP_ADC, ophi, sign);
-    opRegReg(cUnit, OP_XOR, oplo, sign);
-    opRegReg(cUnit, OP_XOR, ophi, sign);
-    if (vDest >= 0) {
-        storeValuePair(cUnit, oplo, ophi, vDest, sign);
-    } else {
-        storeWordDisp(cUnit, rGLUE, offset, oplo, rNone);
-        storeWordDisp(cUnit, rGLUE, offset + 4, ophi, rNone);
-    }
+    opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
+    opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
+    opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg);
+    opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
+    opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
+    storeValueWide(cUnit, rlDest, rlResult);
     return false;
 }
index 4065865..a626fc7 100644 (file)
  */
 
 #include "Codegen.h"
-/* Forward decls */
-static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
-                            int dOffset, ArmLIR *pcrLabel);
-static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest);
-static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest);
-static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
-                            int displacement, int rDest);
-static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
-                             int displacement, int rSrc, int rScratch);
-static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
-                          int rScratch);
-static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
-                                    ArmConditionCode cond,
-                                    ArmLIR *target);
-static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target);
-static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
-                             int rDestHi);
-static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
-                              int vDest, int rScratch);
-static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
-                              int rBound, int dOffset, ArmLIR *pcrLabel);
-static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
-static int inlinedTarget(MIR *mir);
-
-
-/* Routines which must be supplied here */
-static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
-static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
-                           int rAddr);
-static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
-                            int displacement, int rDest, OpSize size,
-                            bool nullCheck, int vReg);
-static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
-                             int displacement, int rSrc, OpSize size,
-                             int rScratch);
-static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
-                                     ArmConditionCode cond, int reg,
-                                     int checkValue, int dOffset,
-                                     ArmLIR *pcrLabel);
-static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
-                                     ArmConditionCode cond,
-                                     int reg1, int reg2, int dOffset,
-                                     ArmLIR *pcrLabel);
-ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc);
-static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
-static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask);
-
-static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op);
-static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value);
-static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc);
-static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc);
-static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
-                        int rSrc2);
-static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
-                        int value, int rScratch);
-static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
-                           int rSrc1, int value, int rScratch);
-static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
-                           int rSrc1, int rSrc2);
-static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
-                               int rIndex, int rDest, int scale, OpSize size);
-static void genCmpLong(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
-                       int vSrc2);
-
-static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir);
-static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir);
-static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir);
-static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir);
-static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir);
-static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin);
-static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir);
-
-/*
- * Support for register allocation
- */
-
-/* get the next register in r0..r3 in a round-robin fashion */
-#define NEXT_REG(reg) ((reg + 1) & 3)
-/*
- * The following are utility routines to help maintain the RegisterScoreboard
- * state to facilitate register renaming.
- */
-
-/* Reset the tracker to unknown state */
-static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
-{
-    RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
-
-    dvmClearAllBits(registerScoreboard->nullCheckedRegs);
-    registerScoreboard->liveDalvikReg = vNone;
-    registerScoreboard->nativeReg = vNone;
-    registerScoreboard->nativeRegHi = vNone;
-}
-
-/* Kill the corresponding bit in the null-checked register list */
-static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
-{
-    dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
-}
-
-/* The Dalvik register pair held in native registers have changed */
-static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
-                                          int vReg, int mRegLo, int mRegHi)
-{
-    cUnit->registerScoreboard.liveDalvikReg = vReg;
-    cUnit->registerScoreboard.nativeReg = mRegLo;
-    cUnit->registerScoreboard.nativeRegHi = mRegHi;
-    cUnit->registerScoreboard.isWide = true;
-}
 
-/* The Dalvik register held in a native register has changed */
-static inline void updateLiveRegister(CompilationUnit *cUnit,
-                                      int vReg, int mReg)
+static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7};
+static int corePreserved[] = {};
+void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit)
 {
-    cUnit->registerScoreboard.liveDalvikReg = vReg;
-    cUnit->registerScoreboard.nativeReg = mReg;
-    cUnit->registerScoreboard.isWide = false;
+    int i;
+    int numTemps = sizeof(coreTemps)/sizeof(int);
+    RegisterPool *pool = dvmCompilerNew(sizeof(*pool), true);
+    cUnit->regPool = pool;
+    pool->numCoreTemps = numTemps;
+    pool->coreTemps =
+            dvmCompilerNew(numTemps * sizeof(*pool->coreTemps), true);
+    pool->numFPTemps = 0;
+    pool->FPTemps = NULL;
+    pool->numCoreRegs = 0;
+    pool->coreRegs = NULL;
+    pool->numFPRegs = 0;
+    pool->FPRegs = NULL;
+    initPool(pool->coreTemps, coreTemps, pool->numCoreTemps);
+    initPool(pool->FPTemps, NULL, 0);
+    initPool(pool->coreRegs, NULL, 0);
+    initPool(pool->FPRegs, NULL, 0);
+    pool->nullCheckedRegs =
+        dvmCompilerAllocBitVector(cUnit->numSSARegs, false);
 }
 
 /*
- * Given a Dalvik register id vSrc, use a very simple algorithm to increase
- * the lifetime of cached Dalvik value in a native register.
+ * Alloc a pair of core registers, or a double.  Low reg in low byte,
+ * high reg in next byte.
  */
-static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
-                                      bool isWide)
+static int allocTypedTempPair(CompilationUnit *cUnit, bool fpHint, int regClass)
 {
-    RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
-
-    /* No live value - suggest to use r0 */
-    if (registerScoreboard->liveDalvikReg == vNone)
-        return r0;
-
-    /* Reuse the previously used native reg */
-    if (registerScoreboard->liveDalvikReg == vSrc) {
-        if (isWide != true) {
-            return registerScoreboard->nativeReg;
-        } else {
-            /* Return either r0 or r2 */
-            return (registerScoreboard->nativeReg + 1) & 2;
-        }
-    }
-
-    /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
-    if (isWide) {
-        return (registerScoreboard->nativeReg + 2) & 2;
-    } else {
-        return (registerScoreboard->nativeReg + 1) & 3;
-    }
+    int highReg;
+    int lowReg;
+    int res = 0;
+    lowReg = allocTemp(cUnit);
+    highReg = allocTemp(cUnit);
+    res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
+    return res;
+}
 
+static int allocTypedTemp(CompilationUnit *cUnit, bool fpHint, int regClass)
+{
+    return allocTemp(cUnit);
 }
 
 ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
@@ -180,13 +75,13 @@ ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
     ArmOpCode opCode;
     res = dvmCompilerNew(sizeof(ArmLIR), true);
     if (LOWREG(rDest) && LOWREG(rSrc))
-        opCode = THUMB_MOV_RR;
+        opCode = kThumbMovRR;
     else if (!LOWREG(rDest) && !LOWREG(rSrc))
-         opCode = THUMB_MOV_RR_H2H;
+         opCode = kThumbMovRR_H2H;
     else if (LOWREG(rDest))
-         opCode = THUMB_MOV_RR_H2L;
+         opCode = kThumbMovRR_H2L;
     else
-         opCode = THUMB_MOV_RR_L2H;
+         opCode = kThumbMovRR_L2H;
 
     res->operands[0] = rDest;
     res->operands[1] = rSrc;
@@ -198,293 +93,39 @@ ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
     return res;
 }
 
-/*
- * Load a immediate using a shortcut if possible; otherwise
- * grab from the per-translation literal pool
- */
-static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
+void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
+                    int srcLo, int srcHi)
 {
-    ArmLIR *res;
-    /* See if the value can be constructed cheaply */
-    if ((value >= 0) && (value <= 255)) {
-        return newLIR2(cUnit, THUMB_MOV_IMM, rDest, value);
-    } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
-        res = newLIR2(cUnit, THUMB_MOV_IMM, rDest, ~value);
-        newLIR2(cUnit, THUMB_MVN, rDest, rDest);
-        return res;
-    }
-    /* No shortcut - go ahead and use literal pool */
-    ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
-    if (dataTarget == NULL) {
-        dataTarget = addWordData(cUnit, value, false);
-    }
-    ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
-    loadPcRel->opCode = THUMB_LDR_PC_REL;
-    loadPcRel->generic.target = (LIR *) dataTarget;
-    loadPcRel->operands[0] = rDest;
-    setupResourceMasks(loadPcRel);
-    res = loadPcRel;
-    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
-
-    /*
-     * To save space in the constant pool, we use the ADD_RRI8 instruction to
-     * add up to 255 to an existing constant value.
-     */
-    if (dataTarget->operands[0] != value) {
-        newLIR2(cUnit, THUMB_ADD_RI8, rDest, value - dataTarget->operands[0]);
+    // Handle overlap
+    if (srcHi == destLo) {
+        genRegCopy(cUnit, destHi, srcHi);
+        genRegCopy(cUnit, destLo, srcLo);
+    } else {
+        genRegCopy(cUnit, destLo, srcLo);
+        genRegCopy(cUnit, destHi, srcHi);
     }
-    return res;
 }
 
 /* Export the Dalvik PC assicated with an instruction to the StackSave area */
-static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC,
-                           int rAddr)
+static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
 {
     ArmLIR *res;
+    int rDPC = allocTemp(cUnit);
+    int rAddr = allocTemp(cUnit);
     int offset = offsetof(StackSaveArea, xtra.currentPc);
     res = loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
-    newLIR2(cUnit, THUMB_MOV_RR, rAddr, rFP);
-    newLIR2(cUnit, THUMB_SUB_RI8, rAddr, sizeof(StackSaveArea) - offset);
-    storeWordDisp( cUnit, rAddr, 0, rDPC, -1);
-    return res;
-}
-
-/* Load value from base + scaled index. Note: index reg killed */
-static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
-                               int rIndex, int rDest, int scale, OpSize size)
-{
-    ArmLIR *first = NULL;
-    ArmLIR *res;
-    ArmOpCode opCode = THUMB_BKPT;
-    if (scale)
-        first = opRegRegImm(cUnit, OP_LSL, rIndex, rIndex, scale, rNone);
-    switch (size) {
-        case WORD:
-            opCode = THUMB_LDR_RRR;
-            break;
-        case UNSIGNED_HALF:
-            opCode = THUMB_LDRH_RRR;
-            break;
-        case SIGNED_HALF:
-            opCode = THUMB_LDRSH_RRR;
-            break;
-        case UNSIGNED_BYTE:
-            opCode = THUMB_LDRB_RRR;
-            break;
-        case SIGNED_BYTE:
-            opCode = THUMB_LDRSB_RRR;
-            break;
-        default:
-            assert(0);
-    }
-    res = newLIR3(cUnit, opCode, rDest, rBase, rIndex);
-    return (first) ? first : res;
-}
-
-/* store value base base + scaled index. Note: index reg killed */
-static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
-                                int rIndex, int rSrc, int scale, OpSize size)
-{
-    ArmLIR *first = NULL;
-    ArmLIR *res;
-    ArmOpCode opCode = THUMB_BKPT;
-    if (scale)
-        first = opRegRegImm(cUnit, OP_LSL, rIndex, rIndex, scale, rNone);
-    switch (size) {
-        case WORD:
-            opCode = THUMB_STR_RRR;
-            break;
-        case UNSIGNED_HALF:
-        case SIGNED_HALF:
-            opCode = THUMB_STRH_RRR;
-            break;
-        case UNSIGNED_BYTE:
-        case SIGNED_BYTE:
-            opCode = THUMB_STRB_RRR;
-            break;
-        default:
-            assert(0);
-    }
-    res = newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
-    return (first) ? first : res;
-}
-
-/*
- * Load value from base + displacement.  Optionally perform null check
- * on base (which must have an associated vReg and MIR).  If not
- * performing null check, incoming MIR can be null. Note: base and
- * dest must not be the same if there is any chance that the long
- * form must be used.
- */
-static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
-                            int displacement, int rDest, OpSize size,
-                            bool nullCheck, int vReg)
-{
-    ArmLIR *first = NULL;
-    ArmLIR *res, *load;
-    ArmOpCode opCode = THUMB_BKPT;
-    bool shortForm = false;
-    int shortMax = 128;
-    int encodedDisp = displacement;
-
-    switch (size) {
-        case WORD:
-            if (LOWREG(rDest) && (rBase == rpc) &&
-                (displacement <= 1020) && (displacement >= 0)) {
-                shortForm = true;
-                encodedDisp >>= 2;
-                opCode = THUMB_LDR_PC_REL;
-            } else if (LOWREG(rDest) && (rBase == r13) &&
-                      (displacement <= 1020) && (displacement >= 0)) {
-                shortForm = true;
-                encodedDisp >>= 2;
-                opCode = THUMB_LDR_SP_REL;
-            } else if (displacement < 128 && displacement >= 0) {
-                assert((displacement & 0x3) == 0);
-                shortForm = true;
-                encodedDisp >>= 2;
-                opCode = THUMB_LDR_RRI5;
-            } else {
-                opCode = THUMB_LDR_RRR;
-            }
-            break;
-        case UNSIGNED_HALF:
-            if (displacement < 64 && displacement >= 0) {
-                assert((displacement & 0x1) == 0);
-                shortForm = true;
-                encodedDisp >>= 1;
-                opCode = THUMB_LDRH_RRI5;
-            } else {
-                opCode = THUMB_LDRH_RRR;
-            }
-            break;
-        case SIGNED_HALF:
-            opCode = THUMB_LDRSH_RRR;
-            break;
-        case UNSIGNED_BYTE:
-            if (displacement < 32 && displacement >= 0) {
-                shortForm = true;
-                opCode = THUMB_LDRB_RRI5;
-            } else {
-                opCode = THUMB_LDRB_RRR;
-            }
-            break;
-        case SIGNED_BYTE:
-            opCode = THUMB_LDRSB_RRR;
-            break;
-        default:
-            assert(0);
-    }
-    if (nullCheck)
-        first = genNullCheck(cUnit, vReg, rBase, mir->offset, NULL);
-    if (shortForm) {
-        load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
-    } else {
-        assert(rBase != rDest);
-        res = loadConstant(cUnit, rDest, encodedDisp);
-        load = newLIR3(cUnit, opCode, rDest, rBase, rDest);
-    }
-
-    if (rBase == rFP) {
-        annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
-    }
-
-    return (first) ? first : res;
-}
-
-static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
-                             int displacement, int rSrc, OpSize size,
-                             int rScratch)
-{
-    ArmLIR *res, *store;
-    ArmOpCode opCode = THUMB_BKPT;
-    bool shortForm = false;
-    int shortMax = 128;
-    int encodedDisp = displacement;
-
-    switch (size) {
-        case WORD:
-            if (displacement < 128 && displacement >= 0) {
-                assert((displacement & 0x3) == 0);
-                shortForm = true;
-                encodedDisp >>= 2;
-                opCode = THUMB_STR_RRI5;
-            } else {
-                opCode = THUMB_STR_RRR;
-            }
-            break;
-        case UNSIGNED_HALF:
-        case SIGNED_HALF:
-            if (displacement < 64 && displacement >= 0) {
-                assert((displacement & 0x1) == 0);
-                shortForm = true;
-                encodedDisp >>= 1;
-                opCode = THUMB_STRH_RRI5;
-            } else {
-                opCode = THUMB_STRH_RRR;
-            }
-            break;
-        case UNSIGNED_BYTE:
-        case SIGNED_BYTE:
-            if (displacement < 32 && displacement >= 0) {
-                shortForm = true;
-                opCode = THUMB_STRB_RRI5;
-            } else {
-                opCode = THUMB_STRB_RRR;
-            }
-            break;
-        default:
-            assert(0);
-    }
-    if (shortForm) {
-        store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
-    } else {
-        assert(rScratch != -1);
-        res = loadConstant(cUnit, rScratch, encodedDisp);
-        store = newLIR3(cUnit, opCode, rSrc, rBase, rScratch);
-    }
-
-    if (rBase == rFP) {
-        annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
-    }
+    newLIR2(cUnit, kThumbMovRR, rAddr, rFP);
+    newLIR2(cUnit, kThumbSubRI8, rAddr, sizeof(StackSaveArea) - offset);
+    storeWordDisp( cUnit, rAddr, 0, rDPC);
     return res;
 }
 
-/*
- * Perform a "reg cmp imm" operation and jump to the PCR region if condition
- * satisfies.
- */
-static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
-                                         ArmConditionCode cond, int reg,
-                                         int checkValue, int dOffset,
-                                         ArmLIR *pcrLabel)
-{
-    if ((checkValue & 0xff) != checkValue) {
-        /* NOTE: direct use of hot temp r7 here. Revisit. */
-        loadConstant(cUnit, r7, checkValue);
-        return genRegRegCheck(cUnit, cond, reg, r7, dOffset, pcrLabel);
-    }
-    newLIR2(cUnit, THUMB_CMP_RI8, reg, checkValue);
-    ArmLIR *branch = newLIR2(cUnit, THUMB_B_COND, 0, cond);
-    return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
-}
-
-static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
-{
-    return newLIR2(cUnit, THUMB_LDMIA, rBase, rMask);
-}
-
-static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
-{
-    return newLIR2(cUnit, THUMB_STMIA, rBase, rMask);
-}
-
 static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
 {
-    ArmOpCode opCode = THUMB_BKPT;
+    ArmOpCode opCode = kThumbBkpt;
     switch (op) {
-        case OP_UNCOND_BR:
-            opCode = THUMB_B_UNCOND;
+        case kOpUncondBr:
+            opCode = kThumbBUncond;
             break;
         default:
             assert(0);
@@ -494,18 +135,18 @@ static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
 
 static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
 {
-    return newLIR2(cUnit, THUMB_B_COND, 0 /* offset to be patched */, cc);
+    return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc);
 }
 
 static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
 {
-    ArmOpCode opCode = THUMB_BKPT;
+    ArmOpCode opCode = kThumbBkpt;
     switch (op) {
-        case OP_PUSH:
-            opCode = THUMB_PUSH;
+        case kOpPush:
+            opCode = kThumbPush;
             break;
-        case OP_POP:
-            opCode = THUMB_POP;
+        case kOpPop:
+            opCode = kThumbPop;
             break;
         default:
             assert(0);
@@ -515,10 +156,10 @@ static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
 
 static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
 {
-    ArmOpCode opCode = THUMB_BKPT;
+    ArmOpCode opCode = kThumbBkpt;
     switch (op) {
-        case OP_BLX:
-            opCode = THUMB_BLX_R;
+        case kOpBlx:
+            opCode = kThumbBlxR;
             break;
         default:
             assert(0);
@@ -526,126 +167,43 @@ static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
     return newLIR1(cUnit, opCode, rDestSrc);
 }
 
-static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
-                        int rSrc2)
-{
-    ArmLIR *res;
-    ArmOpCode opCode = THUMB_BKPT;
-    switch (op) {
-        case OP_ADC:
-            opCode = THUMB_ADC_RR;
-            break;
-        case OP_AND:
-            opCode = THUMB_AND_RR;
-            break;
-        case OP_BIC:
-            opCode = THUMB_BIC_RR;
-            break;
-        case OP_CMN:
-            opCode = THUMB_CMN_RR;
-            break;
-        case OP_CMP:
-            opCode = THUMB_CMP_RR;
-            break;
-        case OP_XOR:
-            opCode = THUMB_EOR_RR;
-            break;
-        case OP_MOV:
-            if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
-                opCode = THUMB_MOV_RR;
-            else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
-                opCode = THUMB_MOV_RR_H2H;
-            else if (LOWREG(rDestSrc1))
-                opCode = THUMB_MOV_RR_H2L;
-            else
-                opCode = THUMB_MOV_RR_L2H;
-            break;
-        case OP_MUL:
-            opCode = THUMB_MUL;
-            break;
-        case OP_MVN:
-            opCode = THUMB_MVN;
-            break;
-        case OP_NEG:
-            opCode = THUMB_NEG;
-            break;
-        case OP_OR:
-            opCode = THUMB_ORR;
-            break;
-        case OP_SBC:
-            opCode = THUMB_SBC;
-            break;
-        case OP_TST:
-            opCode = THUMB_TST;
-            break;
-        case OP_LSL:
-            opCode = THUMB_LSL_RR;
-            break;
-        case OP_LSR:
-            opCode = THUMB_LSR_RR;
-            break;
-        case OP_ASR:
-            opCode = THUMB_ASR_RR;
-            break;
-        case OP_ROR:
-            opCode = THUMB_ROR_RR;
-        case OP_ADD:
-        case OP_SUB:
-            return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
-        case OP_2BYTE:
-             res = opRegRegImm(cUnit, OP_LSL, rDestSrc1, rSrc2, 24, rNone);
-             opRegRegImm(cUnit, OP_ASR, rDestSrc1, rDestSrc1, 24, rNone);
-             return res;
-        case OP_2SHORT:
-             res = opRegRegImm(cUnit, OP_LSL, rDestSrc1, rSrc2, 16, rNone);
-             opRegRegImm(cUnit, OP_ASR, rDestSrc1, rDestSrc1, 16, rNone);
-             return res;
-        case OP_2CHAR:
-             res = opRegRegImm(cUnit, OP_LSL, rDestSrc1, rSrc2, 16, rNone);
-             opRegRegImm(cUnit, OP_LSR, rDestSrc1, rDestSrc1, 16, rNone);
-             return res;
-        default:
-            assert(0);
-            break;
-    }
-    return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
-}
-
 static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
-                        int value, int rScratch)
+                        int value)
 {
     ArmLIR *res;
     bool neg = (value < 0);
     int absValue = (neg) ? -value : value;
     bool shortForm = (absValue & 0xff) == absValue;
-    ArmOpCode opCode = THUMB_BKPT;
+    ArmOpCode opCode = kThumbBkpt;
     switch (op) {
-        case OP_ADD:
+        case kOpAdd:
             if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
                 assert((value & 0x3) == 0);
-                return newLIR1(cUnit, THUMB_ADD_SPI7, value >> 2);
+                return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
             } else if (shortForm) {
-                opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
+                opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
             } else
-                opCode = THUMB_ADD_RRR;
+                opCode = kThumbAddRRR;
             break;
-        case OP_SUB:
+        case kOpSub:
             if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
                 assert((value & 0x3) == 0);
-                return newLIR1(cUnit, THUMB_SUB_SPI7, value >> 2);
+                return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
             } else if (shortForm) {
-                opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
+                opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
             } else
-                opCode = THUMB_SUB_RRR;
+                opCode = kThumbSubRRR;
             break;
-        case OP_CMP:
-            if (LOWREG(rDestSrc1) && shortForm)
-                opCode = (shortForm) ?  THUMB_CMP_RI8 : THUMB_CMP_RR;
-            else if (LOWREG(rDestSrc1))
-                opCode = THUMB_CMP_RR;
-            else {
+        case kOpCmp:
+            if (neg)
+               shortForm = false;
+            if (LOWREG(rDestSrc1) && shortForm) {
+                opCode = kThumbCmpRI8;
+            } else if (LOWREG(rDestSrc1)) {
+                opCode = kThumbCmpRR;
+            } else {
                 shortForm = false;
-                opCode = THUMB_CMP_HL;
+                opCode = kThumbCmpHL;
             }
             break;
         default:
@@ -655,94 +213,155 @@ static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
     if (shortForm)
         res = newLIR2(cUnit, opCode, rDestSrc1, absValue);
     else {
-        assert(rScratch != rNone);
+        int rScratch = allocTemp(cUnit);
         res = loadConstant(cUnit, rScratch, value);
-        newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rScratch);
+        if (op == kOpCmp)
+            newLIR2(cUnit, opCode, rDestSrc1, rScratch);
+        else
+            newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rScratch);
     }
     return res;
 }
 
+static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
+                        int rSrc);
+
 static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
                            int rSrc1, int rSrc2)
 {
-    ArmOpCode opCode = THUMB_BKPT;
+    ArmOpCode opCode = kThumbBkpt;
     switch (op) {
-        case OP_ADD:
-            opCode = THUMB_ADD_RRR;
+        case kOpAdd:
+            opCode = kThumbAddRRR;
             break;
-        case OP_SUB:
-            opCode = THUMB_SUB_RRR;
+        case kOpSub:
+            opCode = kThumbSubRRR;
             break;
         default:
-            assert(0);
+            if (rDest == rSrc1) {
+                return opRegReg(cUnit, op, rDest, rSrc2);
+            } else if (rDest == rSrc2) {
+                assert(isTemp(cUnit, rSrc1));
+                clobberReg(cUnit, rSrc1);
+                opRegReg(cUnit, op, rSrc1, rSrc2);
+                return opRegReg(cUnit, kOpMov, rDest, rSrc1);
+            } else {
+                opRegReg(cUnit, kOpMov, rDest, rSrc1);
+                return opRegReg(cUnit, op, rDest, rSrc2);
+            }
             break;
     }
     return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
 }
 
-static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
-                           int rSrc1, int value, int rScratch)
+static void genLong3Addr(CompilationUnit *cUnit, OpKind firstOp,
+                         OpKind secondOp, RegLocation rlDest,
+                         RegLocation rlSrc1, RegLocation rlSrc2)
 {
-    ArmLIR *res;
+    RegLocation rlResult;
+   if (rlDest.sRegLow == rlSrc1.sRegLow) {
+        // Already 2-operand
+        rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+        rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+        opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
+        opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
+        storeValueWide(cUnit, rlDest, rlResult);
+    } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
+        // Bad case - must use/clobber Src1 and reassign Dest
+        rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
+        rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
+        opRegReg(cUnit, firstOp, rlSrc1.lowReg, rlResult.lowReg);
+        opRegReg(cUnit, secondOp, rlSrc1.highReg, rlResult.highReg);
+        // Old reg assignments are now invalid
+        clobberReg(cUnit, rlResult.lowReg);
+        clobberReg(cUnit, rlResult.highReg);
+        clobberReg(cUnit, rlSrc1.lowReg);
+        clobberReg(cUnit, rlSrc1.highReg);
+        rlDest.location = kLocDalvikFrame;
+        assert(rlSrc1.location == kLocPhysReg);
+        // Reassign registers - rlDest will now get rlSrc1's old regs
+        storeValueWide(cUnit, rlDest, rlSrc1);
+    } else {
+        // Copy Src1 to Dest
+        rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
+        rlResult = evalLoc(cUnit, rlDest, kCoreReg, false);
+        loadValueDirectWide(cUnit, rlSrc1, rlResult.lowReg,
+                            rlResult.highReg);
+        rlResult.location = kLocPhysReg;
+        opRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc2.lowReg);
+        opRegReg(cUnit, secondOp, rlResult.highReg, rlSrc2.highReg);
+        storeValueWide(cUnit, rlDest, rlResult);
+    }
+}
+
+static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
+                           int rSrc1, int value)
+{
+    ArmLIR *res;
     bool neg = (value < 0);
     int absValue = (neg) ? -value : value;
-    ArmOpCode opCode = THUMB_BKPT;
+    ArmOpCode opCode = kThumbBkpt;
     bool shortForm = (absValue & 0x7) == absValue;
     switch(op) {
-        case OP_ADD:
+        case kOpAdd:
+            if (rDest == rSrc1)
+                return opRegImm(cUnit, op, rDest, value);
             if ((rSrc1 == 13) && (value <= 1020)) { /* sp */
                 assert((value & 0x3) == 0);
                 shortForm = true;
-                opCode = THUMB_ADD_SP_REL;
+                opCode = kThumbAddSpRel;
                 value >>= 2;
             } else if ((rSrc1 == 15) && (value <= 1020)) { /* pc */
                 assert((value & 0x3) == 0);
                 shortForm = true;
-                opCode = THUMB_ADD_PC_REL;
+                opCode = kThumbAddPcRel;
                 value >>= 2;
             } else if (shortForm) {
-                opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
+                opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
             } else if ((absValue > 0) && (absValue <= (255 + 7))) {
                 /* Two shots - 1st handle the 7 */
-                opCode = (neg) ? THUMB_SUB_RRI3 : THUMB_ADD_RRI3;
+                opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
                 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7);
-                opCode = (neg) ? THUMB_SUB_RI8 : THUMB_ADD_RI8;
+                opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
                 newLIR2(cUnit, opCode, rDest, absValue - 7);
                 return res;
             } else
-                opCode = THUMB_ADD_RRR;
+                opCode = kThumbAddRRR;
             break;
 
-        case OP_SUB:
+        case kOpSub:
+            if (rDest == rSrc1)
+                return opRegImm(cUnit, op, rDest, value);
             if (shortForm) {
-                opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
+                opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
             } else if ((absValue > 0) && (absValue <= (255 + 7))) {
                 /* Two shots - 1st handle the 7 */
-                opCode = (neg) ? THUMB_ADD_RRI3 : THUMB_SUB_RRI3;
+                opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
                 res = newLIR3(cUnit, opCode, rDest, rSrc1, 7);
-                opCode = (neg) ? THUMB_ADD_RI8 : THUMB_SUB_RI8;
+                opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
                 newLIR2(cUnit, opCode, rDest, absValue - 7);
                 return res;
             } else
-                opCode = THUMB_SUB_RRR;
+                opCode = kThumbSubRRR;
             break;
-        case OP_LSL:
+        case kOpLsl:
                 shortForm = (!neg && value <= 31);
-                opCode = THUMB_LSL_RRI5;
+                opCode = kThumbLslRRI5;
                 break;
-        case OP_LSR:
+        case kOpLsr:
                 shortForm = (!neg && value <= 31);
-                opCode = THUMB_LSR_RRI5;
+                opCode = kThumbLsrRRI5;
                 break;
-        case OP_ASR:
+        case kOpAsr:
                 shortForm = (!neg && value <= 31);
-                opCode = THUMB_ASR_RRI5;
+                opCode = kThumbAsrRRI5;
                 break;
-        case OP_MUL:
-        case OP_AND:
-        case OP_OR:
-        case OP_XOR:
+        case kOpMul:
+        case kOpAnd:
+        case kOpOr:
+        case kOpXor:
                 if (rDest == rSrc1) {
+                    int rScratch = allocTemp(cUnit);
                     res = loadConstant(cUnit, rScratch, value);
                     opRegReg(cUnit, op, rDest, rScratch);
                 } else {
@@ -761,7 +380,7 @@ static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
             res = loadConstant(cUnit, rDest, value);
             newLIR3(cUnit, opCode, rDest, rSrc1, rDest);
         } else {
-            assert(rScratch != rNone);
+            int rScratch = allocTemp(cUnit);
             res = loadConstant(cUnit, rScratch, value);
             newLIR3(cUnit, opCode, rDest, rSrc1, rScratch);
         }
@@ -769,25 +388,518 @@ static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
     return res;
 }
 
-static void genCmpLong(CompilationUnit *cUnit, MIR *mir,
-                               int vDest, int vSrc1, int vSrc2)
+static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
+                        int rSrc2)
+{
+    ArmLIR *res;
+    ArmOpCode opCode = kThumbBkpt;
+    switch (op) {
+        case kOpAdc:
+            opCode = kThumbAdcRR;
+            break;
+        case kOpAnd:
+            opCode = kThumbAndRR;
+            break;
+        case kOpBic:
+            opCode = kThumbBicRR;
+            break;
+        case kOpCmn:
+            opCode = kThumbCmnRR;
+            break;
+        case kOpCmp:
+            opCode = kThumbCmpRR;
+            break;
+        case kOpXor:
+            opCode = kThumbEorRR;
+            break;
+        case kOpMov:
+            if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
+                opCode = kThumbMovRR;
+            else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
+                opCode = kThumbMovRR_H2H;
+            else if (LOWREG(rDestSrc1))
+                opCode = kThumbMovRR_H2L;
+            else
+                opCode = kThumbMovRR_L2H;
+            break;
+        case kOpMul:
+            opCode = kThumbMul;
+            break;
+        case kOpMvn:
+            opCode = kThumbMvn;
+            break;
+        case kOpNeg:
+            opCode = kThumbNeg;
+            break;
+        case kOpOr:
+            opCode = kThumbOrr;
+            break;
+        case kOpSbc:
+            opCode = kThumbSbc;
+            break;
+        case kOpTst:
+            opCode = kThumbTst;
+            break;
+        case kOpLsl:
+            opCode = kThumbLslRR;
+            break;
+        case kOpLsr:
+            opCode = kThumbLsrRR;
+            break;
+        case kOpAsr:
+            opCode = kThumbAsrRR;
+            break;
+        case kOpRor:
+            opCode = kThumbRorRR;
+        case kOpAdd:
+        case kOpSub:
+            return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
+        case kOp2Byte:
+             res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
+             opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
+             return res;
+        case kOp2Short:
+             res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
+             opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
+             return res;
+        case kOp2Char:
+             res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
+             opRegRegImm(cUnit, kOpLsr, rDestSrc1, rDestSrc1, 16);
+             return res;
+        default:
+            assert(0);
+            break;
+    }
+    return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
+}
+
+
+static void handleMonitor(CompilationUnit *cUnit, MIR *mir)
 {
-    loadValuePair(cUnit, vSrc1, r0, r1);
-    loadValuePair(cUnit, vSrc2, r2, r3);
+    handleMonitorPortable(cUnit, mir);
+}
+
+static void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
+                        RegLocation rlSrc)
+{
+    RegLocation rlResult;
+    rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
+    rlResult = evalLoc(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 = evalLoc(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)
+{
+    RegLocation rlResult;
+    loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+    loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+    genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
+    rlResult = getReturnLocWide(cUnit);
+    storeValueWide(cUnit, rlDest, rlResult);
+}
+
+static void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                       RegLocation rlSrc1, RegLocation rlSrc2)
+{
+    RegLocation rlResult;
+    loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+    loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
     genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
-    storeValue(cUnit, r0, vDest, r1);
+    rlResult = getReturnLoc(cUnit);
+    storeValue(cUnit, rlDest, rlResult);
+}
+
+/* Load value from base + scaled index. */
+static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
+                               int rIndex, int rDest, int scale, OpSize size)
+{
+    ArmLIR *first = NULL;
+    ArmLIR *res;
+    ArmOpCode opCode = kThumbBkpt;
+    int rNewIndex = rIndex;
+    if (scale) {
+        // Scale the index, but can't trash the original.
+        rNewIndex = allocTemp(cUnit);
+        first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale);
+    }
+    switch (size) {
+        case kWord:
+            opCode = kThumbLdrRRR;
+            break;
+        case kUnsignedHalf:
+            opCode = kThumbLdrhRRR;
+            break;
+        case kSignedHalf:
+            opCode = kThumbLdrshRRR;
+            break;
+        case kUnsignedByte:
+            opCode = kThumbLdrbRRR;
+            break;
+        case kSignedByte:
+            opCode = kThumbLdrsbRRR;
+            break;
+        default:
+            assert(0);
+    }
+    res = newLIR3(cUnit, opCode, rDest, rBase, rNewIndex);
+    if (scale)
+        freeTemp(cUnit, rNewIndex);
+    return (first) ? first : res;
+}
+
+/* store value base base + scaled index. */
+static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
+                                int rIndex, int rSrc, int scale, OpSize size)
+{
+    ArmLIR *first = NULL;
+    ArmLIR *res;
+    ArmOpCode opCode = kThumbBkpt;
+    int rNewIndex = rIndex;
+    if (scale) {
+        rNewIndex = allocTemp(cUnit);
+        first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale);
+    }
+    switch (size) {
+        case kWord:
+            opCode = kThumbStrRRR;
+            break;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            opCode = kThumbStrhRRR;
+            break;
+        case kUnsignedByte:
+        case kSignedByte:
+            opCode = kThumbStrbRRR;
+            break;
+        default:
+            assert(0);
+    }
+    res = newLIR3(cUnit, opCode, rSrc, rBase, rNewIndex);
+    if (scale)
+        freeTemp(cUnit, rNewIndex);
+    return (first) ? first : res;
+}
+
+static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    ArmLIR *res;
+    genBarrier(cUnit);
+    res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
+    genBarrier(cUnit);
+    return res;
+}
+
+static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
+{
+    ArmLIR *res;
+    genBarrier(cUnit);
+    res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
+    genBarrier(cUnit);
+    return res;
+}
+
+
+static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    if (lowReg < highReg) {
+        loadMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
+    } else {
+        loadWordDisp(cUnit, base, 0 , lowReg);
+        loadWordDisp(cUnit, base, 4 , highReg);
+    }
+}
+
+static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDest, int rDestHi,
+                                OpSize size, bool nullCheck, 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.
+ */
+{
+    ArmLIR *first = NULL;
+    ArmLIR *res;
+    ArmLIR *load = NULL;
+    ArmLIR *load2 = NULL;
+    ArmOpCode opCode = kThumbBkpt;
+    bool shortForm = false;
+    int shortMax = 128;
+    int encodedDisp = displacement;
+    bool pair = false;
+
+    switch (size) {
+        case kLong:
+        case kDouble:
+            pair = true;
+            if ((displacement < 124) && (displacement >= 0)) {
+                assert((displacement & 0x3) == 0);
+                shortForm = true;
+                encodedDisp >>= 2;
+                opCode = kThumbLdrRRI5;
+            } else {
+                opCode = kThumbLdrRRR;
+            }
+            break;
+        case kWord:
+            if (LOWREG(rDest) && (rBase == rpc) &&
+                (displacement <= 1020) && (displacement >= 0)) {
+                shortForm = true;
+                encodedDisp >>= 2;
+                opCode = kThumbLdrPcRel;
+            } else if (LOWREG(rDest) && (rBase == r13) &&
+                      (displacement <= 1020) && (displacement >= 0)) {
+                shortForm = true;
+                encodedDisp >>= 2;
+                opCode = kThumbLdrSpRel;
+            } else if (displacement < 128 && displacement >= 0) {
+                assert((displacement & 0x3) == 0);
+                shortForm = true;
+                encodedDisp >>= 2;
+                opCode = kThumbLdrRRI5;
+            } else {
+                opCode = kThumbLdrRRR;
+            }
+            break;
+        case kUnsignedHalf:
+            if (displacement < 64 && displacement >= 0) {
+                assert((displacement & 0x1) == 0);
+                shortForm = true;
+                encodedDisp >>= 1;
+                opCode = kThumbLdrhRRI5;
+            } else {
+                opCode = kThumbLdrhRRR;
+            }
+            break;
+        case kSignedHalf:
+            opCode = kThumbLdrshRRR;
+            break;
+        case kUnsignedByte:
+            if (displacement < 32 && displacement >= 0) {
+                shortForm = true;
+                opCode = kThumbLdrbRRI5;
+            } else {
+                opCode = kThumbLdrbRRR;
+            }
+            break;
+        case kSignedByte:
+            opCode = kThumbLdrsbRRR;
+            break;
+        default:
+            assert(0);
+    }
+    if (nullCheck)
+        first = genNullCheck(cUnit, sReg, rBase, mir->offset, NULL);
+    if (shortForm) {
+        load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
+        if (pair) {
+            load2 = newLIR3(cUnit, opCode, rDestHi, rBase, encodedDisp+1);
+        }
+    } else {
+        if (pair) {
+            int rTmp = allocFreeTemp(cUnit);
+            if (rTmp < 0) {
+                //UNIMP: need to spill if no temps.
+                assert(0);
+            }
+            res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
+            //TUNING: how to mark loadPair if Dalvik access?
+            loadPair(cUnit, rTmp, rDest, rDestHi);
+            freeTemp(cUnit, rTmp);
+        } else {
+            int rTmp = (rBase == rDest) ? allocFreeTemp(cUnit) : rDest;
+            if (rTmp < 0) {
+                //UNIMP: need to spill if no temps.
+                assert(0);
+            }
+            res = loadConstant(cUnit, rTmp, displacement);
+            load = newLIR3(cUnit, opCode, rDest, rBase, rTmp);
+            if (rBase == rFP)
+                annotateDalvikRegAccess(load, displacement >> 2,
+                                        true /* isLoad */);
+            if (rTmp != rDest)
+                freeTemp(cUnit, rTmp);
+        }
+    }
+
+    return (first) ? first : res;
+}
+
+static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
+                            int displacement, int rDest, OpSize size,
+                            bool nullCheck, int sReg)
+{
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
+                            size, nullCheck, sReg);
+}
+
+static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
+                                int displacement, int rDestLo, int rDestHi,
+                                bool nullCheck, int sReg)
+{
+    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
+                            kLong, nullCheck, sReg);
+}
+
+static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
+{
+    if (lowReg < highReg) {
+        storeMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
+    } else {
+        storeWordDisp(cUnit, base, 0, lowReg);
+        storeWordDisp(cUnit, base, 4, highReg);
+    }
+}
+
+
+static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrc, int rSrcHi,
+                                 OpSize size)
+{
+    ArmLIR *res;
+    ArmLIR *store = NULL;
+    ArmLIR *store2 = NULL;
+    ArmOpCode opCode = kThumbBkpt;
+    bool shortForm = false;
+    int shortMax = 128;
+    int encodedDisp = displacement;
+    bool pair = false;
+
+    switch (size) {
+        case kLong:
+        case kDouble:
+            pair = true;
+            if ((displacement < 124) && (displacement >= 0)) {
+                assert((displacement & 0x3) == 0);
+                pair = true;
+                shortForm = true;
+                encodedDisp >>= 2;
+                opCode = kThumbStrRRI5;
+            } else {
+                opCode = kThumbStrRRR;
+            }
+            break;
+        case kWord:
+            if (displacement < 128 && displacement >= 0) {
+                assert((displacement & 0x3) == 0);
+                shortForm = true;
+                encodedDisp >>= 2;
+                opCode = kThumbStrRRI5;
+            } else {
+                opCode = kThumbStrRRR;
+            }
+            break;
+        case kUnsignedHalf:
+        case kSignedHalf:
+            if (displacement < 64 && displacement >= 0) {
+                assert((displacement & 0x1) == 0);
+                shortForm = true;
+                encodedDisp >>= 1;
+                opCode = kThumbStrhRRI5;
+            } else {
+                opCode = kThumbStrhRRR;
+            }
+            break;
+        case kUnsignedByte:
+        case kSignedByte:
+            if (displacement < 32 && displacement >= 0) {
+                shortForm = true;
+                opCode = kThumbStrbRRI5;
+            } else {
+                opCode = kThumbStrbRRR;
+            }
+            break;
+        default:
+            assert(0);
+    }
+    if (shortForm) {
+        store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
+        if (pair) {
+            store2 = newLIR3(cUnit, opCode, rSrcHi, rBase, encodedDisp + 1);
+        }
+    } else {
+        int rScratch = allocTemp(cUnit);
+        if (pair) {
+            //TUNING: how to mark storePair as Dalvik access if it is?
+            res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
+            storePair(cUnit, rScratch, rSrc, rSrcHi);
+        } else {
+            res = loadConstant(cUnit, rScratch, displacement);
+            store = newLIR3(cUnit, opCode, rSrc, rBase, rScratch);
+            if (rBase == rFP) {
+                annotateDalvikRegAccess(store, displacement >> 2,
+                                        false /* isLoad */);
+            }
+        }
+        freeTemp(cUnit, rScratch);
+    }
+    return res;
+}
+
+static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
+                             int displacement, int rSrc, OpSize size)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
+}
+
+static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
+                                 int displacement, int rSrcLo, int rSrcHi)
+{
+    return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
+}
+
+
+/*
+ * Perform a "reg cmp imm" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+static inline ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
+                                         ArmConditionCode cond, int reg,
+                                         int checkValue, int dOffset,
+                                         ArmLIR *pcrLabel)
+{
+    int tReg;
+    ArmLIR *res;
+    if ((checkValue & 0xff) != checkValue) {
+        tReg = allocTemp(cUnit);
+        loadConstant(cUnit, tReg, checkValue);
+        res = genRegRegCheck(cUnit, cond, reg, tReg, dOffset, pcrLabel);
+        freeTemp(cUnit, tReg);
+        return res;
+    }
+    newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
+    ArmLIR *branch = newLIR2(cUnit, kThumbBCond, 0, cond);
+    return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
 }
 
 static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
 {
     DecodedInstruction *dInsn = &mir->dalvikInsn;
     int offset = offsetof(InterpState, retval);
-    int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
-    int reg1 = NEXT_REG(regObj);
-    loadValue(cUnit, dInsn->arg[0], regObj);
-    genNullCheck(cUnit, dInsn->arg[0], regObj, mir->offset, NULL);
+    RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
+    int regObj = loadValue(cUnit, rlObj, kCoreReg).lowReg;
+    int reg1 = allocTemp(cUnit);
+    genNullCheck(cUnit, getSrcSSAName(mir, 0), regObj, mir->offset, NULL);
     loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, reg1);
-    storeWordDisp(cUnit, rGLUE, offset, reg1, regObj);
+    storeWordDisp(cUnit, rGLUE, offset, reg1);
     return false;
 }
 
@@ -796,104 +908,184 @@ static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
     DecodedInstruction *dInsn = &mir->dalvikInsn;
     int offset = offsetof(InterpState, retval);
     int contents = offsetof(ArrayObject, contents);
-    int regObj = selectFirstRegister(cUnit, dInsn->arg[0], false);
-    int regIdx = NEXT_REG(regObj);
-    int regMax = NEXT_REG(regIdx);
-    int regOff = NEXT_REG(regMax);
-    loadValue(cUnit, dInsn->arg[0], regObj);
-    loadValue(cUnit, dInsn->arg[1], regIdx);
-    ArmLIR * pcrLabel = genNullCheck(cUnit, dInsn->arg[0], regObj,
-                                         mir->offset, NULL);
+    RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlIdx = getSrcLoc(cUnit, mir, 1);
+    int regObj = loadValue(cUnit, rlObj, kCoreReg).lowReg;
+    int regIdx = loadValue(cUnit, rlIdx, kCoreReg).lowReg;
+    int regMax = allocTemp(cUnit);
+    int regOff = allocTemp(cUnit);
+    ArmLIR * pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0),
+                                     regObj, mir->offset, NULL);
     loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_count, regMax);
     loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_offset, regOff);
     loadWordDisp(cUnit, regObj, gDvm.offJavaLangString_value, regObj);
     genBoundsCheck(cUnit, regIdx, regMax, mir->offset, pcrLabel);
 
-    newLIR2(cUnit, THUMB_ADD_RI8, regObj, contents);
-    newLIR3(cUnit, THUMB_ADD_RRR, regIdx, regIdx, regOff);
-    newLIR3(cUnit, THUMB_ADD_RRR, regIdx, regIdx, regIdx);
-    newLIR3(cUnit, THUMB_LDRH_RRR, regMax, regObj, regIdx);
-    storeWordDisp(cUnit, rGLUE, offset, regMax, regObj);
+    newLIR2(cUnit, kThumbAddRI8, regObj, contents);
+    newLIR3(cUnit, kThumbAddRRR, regIdx, regIdx, regOff);
+    newLIR3(cUnit, kThumbAddRRR, regIdx, regIdx, regIdx);
+    newLIR3(cUnit, kThumbLdrhRRR, regMax, regObj, regIdx);
+    freeTemp(cUnit, regOff);
+    storeWordDisp(cUnit, rGLUE, offset, regMax);
+//FIXME: rewrite this to not clobber
+    clobberReg(cUnit, regObj);
+    clobberReg(cUnit, regIdx);
     return false;
 }
 
 static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
 {
     int offset = offsetof(InterpState, retval);
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
-    int sign = NEXT_REG(reg0);
+    RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+    int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
+    int sign = allocTemp(cUnit);
     /* abs(x) = y<=x>>31, (x+y)^y.  Shorter in ARM/THUMB2, no skip in THUMB */
-    loadValue(cUnit, dInsn->arg[0], reg0);
-    newLIR3(cUnit, THUMB_ASR_RRI5, sign, reg0, 31);
-    newLIR3(cUnit, THUMB_ADD_RRR, reg0, reg0, sign);
-    newLIR2(cUnit, THUMB_EOR_RR, reg0, sign);
-    storeWordDisp(cUnit, rGLUE, offset, reg0, sign);
+    newLIR3(cUnit, kThumbAsrRRI5, sign, reg0, 31);
+    newLIR3(cUnit, kThumbAddRRR, reg0, reg0, sign);
+    newLIR2(cUnit, kThumbEorRR, reg0, sign);
+    freeTemp(cUnit, sign);
+    storeWordDisp(cUnit, rGLUE, offset, reg0);
+//FIXME: rewrite this to not clobber
+    clobberReg(cUnit, reg0);
     return false;
 }
 
 static bool genInlinedAbsFloat(CompilationUnit *cUnit, MIR *mir)
 {
     int offset = offsetof(InterpState, retval);
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
-    int signMask = NEXT_REG(reg0);
-    loadValue(cUnit, dInsn->arg[0], reg0);
+    RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
+    int reg0 = loadValue(cUnit, rlSrc, kCoreReg).lowReg;
+    int signMask = allocTemp(cUnit);
     loadConstant(cUnit, signMask, 0x7fffffff);
-    newLIR2(cUnit, THUMB_AND_RR, reg0, signMask);
-    storeWordDisp(cUnit, rGLUE, offset, reg0, signMask);
-    return false;
+    newLIR2(cUnit, kThumbAndRR, reg0, signMask);
+    freeTemp(cUnit, signMask);
+    storeWordDisp(cUnit, rGLUE, offset, reg0);
+//FIXME: rewrite this to not clobber
+    clobberReg(cUnit, reg0);
+    return true;
 }
 
 static bool genInlinedAbsDouble(CompilationUnit *cUnit, MIR *mir)
 {
     int offset = offsetof(InterpState, retval);
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
-    int ophi = NEXT_REG(oplo);
-    int signMask = NEXT_REG(ophi);
-    loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
+    RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+    RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+    int reglo = regSrc.lowReg;
+    int reghi = regSrc.highReg;
+    int signMask = allocTemp(cUnit);
     loadConstant(cUnit, signMask, 0x7fffffff);
-    storeWordDisp(cUnit, rGLUE, offset, oplo, ophi);
-    newLIR2(cUnit, THUMB_AND_RR, ophi, signMask);
-    storeWordDisp(cUnit, rGLUE, offset + 4, ophi, oplo);
-    return false;
+    storeWordDisp(cUnit, rGLUE, offset, reglo);
+    newLIR2(cUnit, kThumbAndRR, reghi, signMask);
+    freeTemp(cUnit, signMask);
+    storeWordDisp(cUnit, rGLUE, offset + 4, reghi);
+//FIXME: rewrite this to not clobber
+    clobberReg(cUnit, reghi);
+    return true;
 }
 
- /* No select in thumb, so we need to branch.  Thumb2 will do better */
+/* No select in thumb, so we need to branch.  Thumb2 will do better */
 static bool genInlinedMinMaxInt(CompilationUnit *cUnit, MIR *mir, bool isMin)
 {
     int offset = offsetof(InterpState, retval);
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int reg0 = selectFirstRegister(cUnit, dInsn->arg[0], false);
-    int reg1 = NEXT_REG(reg0);
-    loadValue(cUnit, dInsn->arg[0], reg0);
-    loadValue(cUnit, dInsn->arg[1], reg1);
-    newLIR2(cUnit, THUMB_CMP_RR, reg0, reg1);
-    ArmLIR *branch1 = newLIR2(cUnit, THUMB_B_COND, 2,
-           isMin ? ARM_COND_LT : ARM_COND_GT);
-    newLIR2(cUnit, THUMB_MOV_RR, reg0, reg1);
-    ArmLIR *target =
-        newLIR3(cUnit, THUMB_STR_RRI5, reg0, rGLUE, offset >> 2);
+    RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
+    RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
+    int reg0 = loadValue(cUnit, rlSrc1, kCoreReg).lowReg;
+    int reg1 = loadValue(cUnit, rlSrc2, kCoreReg).lowReg;
+    newLIR2(cUnit, kThumbCmpRR, reg0, reg1);
+    ArmLIR *branch1 = newLIR2(cUnit, kThumbBCond, 2,
+           isMin ? kArmCondLt : kArmCondGt);
+    newLIR2(cUnit, kThumbMovRR, reg0, reg1);
+    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    newLIR3(cUnit, kThumbStrRRI5, reg0, rGLUE, offset >> 2);
     branch1->generic.target = (LIR *)target;
+//FIXME: rewrite this to not clobber
+    clobberReg(cUnit,reg0);
     return false;
 }
 
 static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
 {
     int offset = offsetof(InterpState, retval);
-    DecodedInstruction *dInsn = &mir->dalvikInsn;
-    int oplo = selectFirstRegister(cUnit, dInsn->arg[0], true);
-    int ophi = NEXT_REG(oplo);
-    int sign = NEXT_REG(ophi);
+    RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+    RegLocation regSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
+    int oplo = regSrc.lowReg;
+    int ophi = regSrc.highReg;
+    int sign = allocTemp(cUnit);
     /* abs(x) = y<=x>>31, (x+y)^y.  Shorter in ARM/THUMB2, no skip in THUMB */
-    loadValuePair(cUnit, dInsn->arg[0], oplo, ophi);
-    newLIR3(cUnit, THUMB_ASR_RRI5, sign, ophi, 31);
-    newLIR3(cUnit, THUMB_ADD_RRR, oplo, oplo, sign);
-    newLIR2(cUnit, THUMB_ADC_RR, ophi, sign);
-    newLIR2(cUnit, THUMB_EOR_RR, oplo, sign);
-    newLIR2(cUnit, THUMB_EOR_RR, ophi, sign);
-    storeWordDisp(cUnit, rGLUE, offset, oplo, sign);
-    storeWordDisp(cUnit, rGLUE, offset + 4, ophi, sign);
+    newLIR3(cUnit, kThumbAsrRRI5, sign, ophi, 31);
+    newLIR3(cUnit, kThumbAddRRR, oplo, oplo, sign);
+    newLIR2(cUnit, kThumbAdcRR, ophi, sign);
+    newLIR2(cUnit, kThumbEorRR, oplo, sign);
+    newLIR2(cUnit, kThumbEorRR, ophi, sign);
+    freeTemp(cUnit, sign);
+    storeWordDisp(cUnit, rGLUE, offset, oplo);
+    storeWordDisp(cUnit, rGLUE, offset + 4, ophi);
+//FIXME: rewrite this to not clobber
+    clobberReg(cUnit, oplo);
+    clobberReg(cUnit, ophi);
     return false;
 }
+
+
+/*
+ * 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.
+ */
+static ArmLIR *loadConstantValue(CompilationUnit *cUnit, int rDest, int value)
+{
+    ArmLIR *res;
+    int tDest = LOWREG(rDest) ? rDest : allocTemp(cUnit);
+    /* See if the value can be constructed cheaply */
+    if ((value >= 0) && (value <= 255)) {
+        res = newLIR2(cUnit, kThumbMovImm, tDest, value);
+        if (rDest != tDest) {
+           opRegReg(cUnit, kOpMov, rDest, tDest);
+           freeTemp(cUnit, tDest);
+        }
+        return res;
+    } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
+        res = newLIR2(cUnit, kThumbMovImm, tDest, ~value);
+        newLIR2(cUnit, kThumbMvn, tDest, tDest);
+        if (rDest != tDest) {
+           opRegReg(cUnit, kOpMov, rDest, tDest);
+           freeTemp(cUnit, tDest);
+        }
+        return res;
+    }
+    /* No shortcut - go ahead and use literal pool */
+    ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
+    if (dataTarget == NULL) {
+        dataTarget = addWordData(cUnit, value, false);
+    }
+    ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
+    loadPcRel->opCode = kThumbLdrPcRel;
+    loadPcRel->generic.target = (LIR *) dataTarget;
+    loadPcRel->operands[0] = tDest;
+    setupResourceMasks(loadPcRel);
+    res = loadPcRel;
+    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
+
+    /*
+     * To save space in the constant pool, we use the ADD_RRI8 instruction to
+     * add up to 255 to an existing constant value.
+     */
+    if (dataTarget->operands[0] != value) {
+        newLIR2(cUnit, kThumbAddRI8, tDest, value - dataTarget->operands[0]);
+    }
+    if (rDest != tDest) {
+       opRegReg(cUnit, kOpMov, rDest, tDest);
+       freeTemp(cUnit, tDest);
+    }
+    return res;
+}
+
+static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
+                                     int rDestHi, int valLo, int valHi)
+{
+    ArmLIR *res;
+    res = loadConstantValue(cUnit, rDestLo, valLo);
+    loadConstantValue(cUnit, rDestHi, valHi);
+    return res;
+}
index d07d96e..8c61322 100644 (file)
@@ -19,8 +19,8 @@
  * variant-specific code.
  */
 
-#define USE_IN_CACHE_HANDLER 1
-
+static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc,
+                             int rDest);
 /*
  * Determine the initial instruction set to be used for this trace.
  * Later components may decide to change this.
@@ -36,7 +36,6 @@ JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit)
  */
 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
 {
-#if USE_IN_CACHE_HANDLER
     /*
      * NOTE - In practice BLX only needs one operand, but since the assembler
      * may abort itself and retry due to other out-of-range conditions we
@@ -45,32 +44,13 @@ static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
      * we fake BLX_1 is a two operand instruction and the absolute target
      * address is stored in operand[1].
      */
-    newLIR2(cUnit, THUMB_BLX_1,
+    clobberHandlerRegs(cUnit);
+    newLIR2(cUnit, kThumbBlx1,
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
-    newLIR2(cUnit, THUMB_BLX_2,
+    newLIR2(cUnit, kThumbBlx2,
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
-#else
-    /*
-     * In case we want to access the statically compiled handlers for
-     * debugging purposes, define USE_IN_CACHE_HANDLER to 0
-     */
-    void *templatePtr;
-
-#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
-#include "../../../template/armv5te-vfp/TemplateOpList.h"
-#undef JIT_TEMPLATE
-    switch (opCode) {
-#define JIT_TEMPLATE(X) \
-        case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; }
-#include "../../../template/armv5te-vfp/TemplateOpList.h"
-#undef JIT_TEMPLATE
-        default: templatePtr = NULL;
-    }
-    loadConstant(cUnit, r7, (int) templatePtr);
-    newLIR1(cUnit, THUMB_BLX_R, r7);
-#endif
 }
 
 /* Architecture-specific initializations and checks go here */
@@ -112,21 +92,44 @@ static bool compilerArchVariantInit(void)
     return true;
 }
 
+/* First, flush any registers associated with this value */
+static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc,
+                             int rDest)
+{
+     rlSrc = rlSrc.wide ? updateLocWide(cUnit, rlSrc) : updateLoc(cUnit, rlSrc);
+     if (rlSrc.location == kLocPhysReg) {
+         if (rlSrc.wide) {
+             flushRegWide(cUnit, rlSrc.lowReg, rlSrc.highReg);
+         } else {
+             flushReg(cUnit, rlSrc.lowReg);
+         }
+     }
+     opRegRegImm(cUnit, kOpAdd, rDest, rFP,
+                 sReg2vReg(cUnit, rlSrc.sRegLow) << 2);
+}
+
 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
 {
-    int offset = offsetof(InterpState, retval);
-    OpCode opCode = mir->dalvikInsn.opCode;
-    int vSrc = mir->dalvikInsn.arg[0];
-    loadValueAddress(cUnit, vSrc, r2);
+    RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+    RegLocation rlResult = LOC_C_RETURN_WIDE;
+    RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
+    loadValueAddress(cUnit, rlSrc, r2);
     genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP);
-    newLIR3(cUnit, THUMB_STR_RRI5, r0, rGLUE, offset >> 2);
-    newLIR3(cUnit, THUMB_STR_RRI5, r1, rGLUE, (offset >> 2) + 1);
-    resetRegisterScoreboard(cUnit);
+    storeValueWide(cUnit, rlDest, rlResult);
     return false;
 }
 
-static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
-                                int vSrc1, int vSrc2)
+/*
+ * 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 handleArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+                               RegLocation rlDest, RegLocation rlSrc1,
+                               RegLocation rlSrc2)
 {
     TemplateOpCode opCode;
 
@@ -154,28 +157,31 @@ static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
         case OP_REM_FLOAT_2ADDR:
         case OP_REM_FLOAT:
         case OP_NEG_FLOAT: {
-            return genArithOpFloatPortable(cUnit, mir, vDest,
-                                                      vSrc1, vSrc2);
+            return handleArithOpFloatPortable(cUnit, mir, rlDest,
+                                              rlSrc1, rlSrc2);
         }
         default:
             return true;
     }
-    loadValueAddress(cUnit, vDest, r0);
-    loadValueAddress(cUnit, vSrc1, r1);
-    loadValueAddress(cUnit, vSrc2, r2);
+    loadValueAddress(cUnit, rlDest, r0);
+    clobberReg(cUnit, r0);
+    loadValueAddress(cUnit, rlSrc1, r1);
+    clobberReg(cUnit, r1);
+    loadValueAddress(cUnit, rlSrc2, r2);
     genDispatchToHandler(cUnit, opCode);
+    rlDest = updateLoc(cUnit, rlDest);
+    if (rlDest.location == kLocPhysReg) {
+        clobberReg(cUnit, rlDest.lowReg);
+    }
     return false;
 }
 
-static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
-                             int vSrc1, int vSrc2)
+static bool handleArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+                                RegLocation rlDest, RegLocation rlSrc1,
+                                RegLocation rlSrc2)
 {
     TemplateOpCode opCode;
 
-    /*
-     * Don't attempt to optimize register usage since these opcodes call out to
-     * the handlers.
-     */
     switch (mir->dalvikInsn.opCode) {
         case OP_ADD_DOUBLE_2ADDR:
         case OP_ADD_DOUBLE:
@@ -196,74 +202,114 @@ static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
         case OP_REM_DOUBLE_2ADDR:
         case OP_REM_DOUBLE:
         case OP_NEG_DOUBLE: {
-            return genArithOpDoublePortable(cUnit, mir, vDest,
-                                                       vSrc1, vSrc2);
+            return handleArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
+                                               rlSrc2);
         }
         default:
             return true;
     }
-    loadValueAddress(cUnit, vDest, r0);
-    loadValueAddress(cUnit, vSrc1, r1);
-    loadValueAddress(cUnit, vSrc2, r2);
+    loadValueAddress(cUnit, rlDest, r0);
+    clobberReg(cUnit, r0);
+    loadValueAddress(cUnit, rlSrc1, r1);
+    clobberReg(cUnit, r1);
+    loadValueAddress(cUnit, rlSrc2, r2);
     genDispatchToHandler(cUnit, opCode);
+    rlDest = updateLocWide(cUnit, rlDest);
+    if (rlDest.location == kLocPhysReg) {
+        clobberReg(cUnit, rlDest.lowReg);
+        clobberReg(cUnit, rlDest.highReg);
+    }
     return false;
 }
 
-static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+static bool handleConversion(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode opCode = mir->dalvikInsn.opCode;
-    int vSrc1Dest = mir->dalvikInsn.vA;
-    int vSrc2 = mir->dalvikInsn.vB;
+    bool longSrc = false;
+    bool longDest = false;
+    RegLocation rlSrc;
+    RegLocation rlDest;
     TemplateOpCode template;
-
     switch (opCode) {
         case OP_INT_TO_FLOAT:
+            longSrc = false;
+            longDest = false;
             template = TEMPLATE_INT_TO_FLOAT_VFP;
             break;
         case OP_FLOAT_TO_INT:
+            longSrc = false;
+            longDest = false;
             template = TEMPLATE_FLOAT_TO_INT_VFP;
             break;
         case OP_DOUBLE_TO_FLOAT:
+            longSrc = true;
+            longDest = false;
             template = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
             break;
         case OP_FLOAT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
             template = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
             break;
         case OP_INT_TO_DOUBLE:
+            longSrc = false;
+            longDest = true;
             template = TEMPLATE_INT_TO_DOUBLE_VFP;
             break;
         case OP_DOUBLE_TO_INT:
+            longSrc = true;
+            longDest = false;
             template = 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:
-        case OP_LONG_TO_DOUBLE:
-            return genConversionPortable(cUnit, mir);
+            return handleConversionPortable(cUnit, mir);
         default:
             return true;
     }
-    loadValueAddress(cUnit, vSrc1Dest, r0);
-    loadValueAddress(cUnit, vSrc2, r1);
+
+    if (longSrc) {
+        rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+    } else {
+        rlSrc = getSrcLoc(cUnit, mir, 0);
+    }
+
+    if (longDest) {
+        rlDest = getDestLocWide(cUnit, mir, 0, 1);
+    } else {
+        rlDest = getDestLoc(cUnit, mir, 0);
+    }
+    loadValueAddress(cUnit, rlDest, r0);
+    clobberReg(cUnit, r0);
+    loadValueAddress(cUnit, rlSrc, r1);
     genDispatchToHandler(cUnit, template);
+    if (rlDest.wide) {
+        rlDest = updateLocWide(cUnit, rlDest);
+        clobberReg(cUnit, rlDest.highReg);
+    } else {
+        rlDest = updateLoc(cUnit, rlDest);
+    }
+    clobberReg(cUnit, rlDest.lowReg);
     return false;
 }
 
-static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
-                    int vSrc2)
+static bool handleCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                        RegLocation rlSrc1, RegLocation rlSrc2)
 {
     TemplateOpCode template;
+    RegLocation rlResult = getReturnLoc(cUnit);
+    bool wide = true;
 
-    /*
-     * Don't attempt to optimize register usage since these opcodes call out to
-     * the handlers.
-     */
     switch(mir->dalvikInsn.opCode) {
         case OP_CMPL_FLOAT:
             template = TEMPLATE_CMPL_FLOAT_VFP;
+            wide = false;
             break;
         case OP_CMPG_FLOAT:
             template = TEMPLATE_CMPG_FLOAT_VFP;
+            wide = false;
             break;
         case OP_CMPL_DOUBLE:
             template = TEMPLATE_CMPL_DOUBLE_VFP;
@@ -274,9 +320,10 @@ static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
         default:
             return true;
     }
-    loadValueAddress(cUnit, vSrc1, r0);
-    loadValueAddress(cUnit, vSrc2, r1);
+    loadValueAddress(cUnit, rlSrc1, r0);
+    clobberReg(cUnit, r0);
+    loadValueAddress(cUnit, rlSrc2, r1);
     genDispatchToHandler(cUnit, template);
-    storeValue(cUnit, r0, vDest, r1);
+    storeValue(cUnit, rlDest, rlResult);
     return false;
 }
index b4a3848..a4b9ae3 100644 (file)
@@ -19,8 +19,6 @@
  * variant-specific code.
  */
 
-#define USE_IN_CACHE_HANDLER 1
-
 /*
  * Determine the initial instruction set to be used for this trace.
  * Later components may decide to change this.
@@ -36,7 +34,6 @@ JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit)
  */
 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
 {
-#if USE_IN_CACHE_HANDLER
     /*
      * NOTE - In practice BLX only needs one operand, but since the assembler
      * may abort itself and retry due to other out-of-range conditions we
@@ -45,32 +42,13 @@ static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
      * we fake BLX_1 is a two operand instruction and the absolute target
      * address is stored in operand[1].
      */
-    newLIR2(cUnit, THUMB_BLX_1,
+    clobberHandlerRegs(cUnit);
+    newLIR2(cUnit, kThumbBlx1,
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
-    newLIR2(cUnit, THUMB_BLX_2,
+    newLIR2(cUnit, kThumbBlx2,
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
-#else
-    /*
-     * In case we want to access the statically compiled handlers for
-     * debugging purposes, define USE_IN_CACHE_HANDLER to 0
-     */
-    void *templatePtr;
-
-#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
-#include "../../../template/armv5te/TemplateOpList.h"
-#undef JIT_TEMPLATE
-    switch (opCode) {
-#define JIT_TEMPLATE(X) \
-        case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; }
-#include "../../../template/armv5te/TemplateOpList.h"
-#undef JIT_TEMPLATE
-        default: templatePtr = NULL;
-    }
-    loadConstant(cUnit, r7, (int) templatePtr);
-    newLIR1(cUnit, THUMB_BLX_R, r7);
-#endif
 }
 
 /* Architecture-specific initializations and checks go here */
@@ -117,54 +95,57 @@ static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
     return false;   /* punt to C handler */
 }
 
-static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+static bool handleConversion(CompilationUnit *cUnit, MIR *mir)
 {
-    return genConversionPortable(cUnit, mir);
+    return handleConversionPortable(cUnit, mir);
 }
 
-static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
-                        int vSrc1, int vSrc2)
+static bool handleArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+                               RegLocation rlDest, RegLocation rlSrc1,
+                               RegLocation rlSrc2)
 {
-    return genArithOpFloatPortable(cUnit, mir, vDest, vSrc1, vSrc2);
+    return handleArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
 }
 
-static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
-                      int vSrc1, int vSrc2)
+static bool handleArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+                                RegLocation rlDest, RegLocation rlSrc1,
+                                RegLocation rlSrc2)
 {
-    return genArithOpDoublePortable(cUnit, mir, vDest, vSrc1, vSrc2);
+    return handleArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
 }
 
-static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
-                    int vSrc2)
+static bool handleCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                        RegLocation rlSrc1, RegLocation rlSrc2)
 {
+    RegLocation rlResult = LOC_C_RETURN;
     /*
      * Don't attempt to optimize register usage since these opcodes call out to
      * the handlers.
      */
     switch (mir->dalvikInsn.opCode) {
         case OP_CMPL_FLOAT:
-            loadValue(cUnit, vSrc1, r0);
-            loadValue(cUnit, vSrc2, r1);
+            loadValueDirectFixed(cUnit, rlSrc1, r0);
+            loadValueDirectFixed(cUnit, rlSrc2, r1);
             genDispatchToHandler(cUnit, TEMPLATE_CMPL_FLOAT);
-            storeValue(cUnit, r0, vDest, r1);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         case OP_CMPG_FLOAT:
-            loadValue(cUnit, vSrc1, r0);
-            loadValue(cUnit, vSrc2, r1);
+            loadValueDirectFixed(cUnit, rlSrc1, r0);
+            loadValueDirectFixed(cUnit, rlSrc2, r1);
             genDispatchToHandler(cUnit, TEMPLATE_CMPG_FLOAT);
-            storeValue(cUnit, r0, vDest, r1);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         case OP_CMPL_DOUBLE:
-            loadValueAddress(cUnit, vSrc1, r0);
-            loadValueAddress(cUnit, vSrc2, r1);
+            loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+            loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
             genDispatchToHandler(cUnit, TEMPLATE_CMPL_DOUBLE);
-            storeValue(cUnit, r0, vDest, r1);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         case OP_CMPG_DOUBLE:
-            loadValueAddress(cUnit, vSrc1, r0);
-            loadValueAddress(cUnit, vSrc2, r1);
+            loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+            loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
             genDispatchToHandler(cUnit, TEMPLATE_CMPG_DOUBLE);
-            storeValue(cUnit, r0, vDest, r1);
+            storeValue(cUnit, rlDest, rlResult);
             break;
         default:
             return true;
index fba1e32..0409135 100644 (file)
@@ -22,8 +22,6 @@
  * variant-specific code.
  */
 
-#define USE_IN_CACHE_HANDLER 1
-
 /*
  * Determine the initial instruction set to be used for this trace.
  * Later components may decide to change this.
@@ -39,7 +37,6 @@ JitInstructionSetType dvmCompilerInstructionSet(CompilationUnit *cUnit)
  */
 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
 {
-#if USE_IN_CACHE_HANDLER
     /*
      * NOTE - In practice BLX only needs one operand, but since the assembler
      * may abort itself and retry due to other out-of-range conditions we
@@ -48,32 +45,13 @@ static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
      * we fake BLX_1 is a two operand instruction and the absolute target
      * address is stored in operand[1].
      */
-    newLIR2(cUnit, THUMB_BLX_1,
+    clobberHandlerRegs(cUnit);
+    newLIR2(cUnit, kThumbBlx1,
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
-    newLIR2(cUnit, THUMB_BLX_2,
+    newLIR2(cUnit, kThumbBlx2,
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
             (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
-#else
-    /*
-     * In case we want to access the statically compiled handlers for
-     * debugging purposes, define USE_IN_CACHE_HANDLER to 0
-     */
-    void *templatePtr;
-
-#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
-#include "../../../template/armv5te-vfp/TemplateOpList.h"
-#undef JIT_TEMPLATE
-    switch (opCode) {
-#define JIT_TEMPLATE(X) \
-        case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; }
-#include "../../../template/armv5te-vfp/TemplateOpList.h"
-#undef JIT_TEMPLATE
-        default: templatePtr = NULL;
-    }
-    loadConstant(cUnit, r7, (int) templatePtr);
-    newLIR1(cUnit, THUMB_BLX_R, r7);
-#endif
 }
 
 /* Architecture-specific initializations and checks go here */
@@ -117,36 +95,37 @@ static bool compilerArchVariantInit(void)
 
 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
 {
-    int offset = offsetof(InterpState, retval);
-    int vSrc = mir->dalvikInsn.arg[0];
-    int vDest = inlinedTarget(mir);
     ArmLIR *branch;
-    ArmLIR *target;
-
-    loadDouble(cUnit, vSrc, dr1);
-    newLIR2(cUnit, THUMB2_VSQRTD, dr0, dr1);
-    newLIR2(cUnit, THUMB2_VCMPD, dr0, dr0);
-    newLIR0(cUnit, THUMB2_FMSTAT);
-    branch = newLIR2(cUnit, THUMB_B_COND, 0, ARM_COND_EQ);
+    DecodedInstruction *dInsn = &mir->dalvikInsn;
+    RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+    RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
+    rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+    RegLocation rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR2(cUnit, kThumb2Vsqrtd, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlSrc.lowReg, rlSrc.highReg));
+    newLIR2(cUnit, kThumb2Vcmpd, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlResult.lowReg, rlResult.highReg));
+    newLIR0(cUnit, kThumb2Fmstat);
+    branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq);
+    clobberCallRegs(cUnit);
     loadConstant(cUnit, r2, (int)sqrt);
-    newLIR3(cUnit, THUMB2_FMRRD, r0, r1, dr1);
-    newLIR1(cUnit, THUMB_BLX_R, r2);
-    newLIR3(cUnit, THUMB2_FMDRR, dr0, r0, r1);
-    ArmLIR *label = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
+    newLIR3(cUnit, kThumb2Fmrrd, r0, r1, S2D(rlSrc.lowReg, rlSrc.highReg));
+    newLIR1(cUnit, kThumbBlxR, r2);
+    newLIR3(cUnit, kThumb2Fmdrr, S2D(rlResult.lowReg, rlResult.highReg),
+            r0, r1);
+    ArmLIR *label = newLIR0(cUnit, kArmPseudoTargetLabel);
     label->defMask = ENCODE_ALL;
     branch->generic.target = (LIR *)label;
-    if (vDest >= 0)
-        storeDouble(cUnit, dr0, vDest);
-    else
-        newLIR3(cUnit, THUMB2_VSTRD, dr0, rGLUE, offset >> 2);
-    resetRegisterScoreboard(cUnit);
+    storeValueWide(cUnit, rlDest, rlResult);
     return true;
 }
 
-static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
-                                int vSrc1, int vSrc2)
+static bool handleArithOpFloat(CompilationUnit *cUnit, MIR *mir,
+                               RegLocation rlDest, RegLocation rlSrc1,
+                               RegLocation rlSrc2)
 {
-    int op = THUMB_BKPT;
+    int op = kThumbBkpt;
+    RegLocation rlResult;
 
     /*
      * Don't attempt to optimize register usage since these opcodes call out to
@@ -155,168 +134,165 @@ static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
     switch (mir->dalvikInsn.opCode) {
         case OP_ADD_FLOAT_2ADDR:
         case OP_ADD_FLOAT:
-            op = THUMB2_VADDS;
+            op = kThumb2Vadds;
             break;
         case OP_SUB_FLOAT_2ADDR:
         case OP_SUB_FLOAT:
-            op = THUMB2_VSUBS;
+            op = kThumb2Vsubs;
             break;
         case OP_DIV_FLOAT_2ADDR:
         case OP_DIV_FLOAT:
-            op = THUMB2_VDIVS;
+            op = kThumb2Vdivs;
             break;
         case OP_MUL_FLOAT_2ADDR:
         case OP_MUL_FLOAT:
-            op = THUMB2_VMULS;
+            op = kThumb2Vmuls;
             break;
         case OP_REM_FLOAT_2ADDR:
         case OP_REM_FLOAT:
         case OP_NEG_FLOAT: {
-            return genArithOpFloatPortable(cUnit, mir, vDest, vSrc1, vSrc2);
+            return handleArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1,
+                                              rlSrc2);
         }
         default:
             return true;
     }
-    int reg0, reg1, reg2;
-    reg1 = selectSFPReg(cUnit, vSrc1);
-    reg2 = selectSFPReg(cUnit, vSrc2);
-    /*
-     * The register mapping is overly optimistic and lazily updated so we
-     * need to detect false sharing here.
-     */
-    if (reg1 == reg2 && vSrc1 != vSrc2) {
-        reg2 = nextFPReg(cUnit, vSrc2, false /* isDouble */);
-    }
-    loadFloat(cUnit, vSrc1, reg1);
-    loadFloat(cUnit, vSrc2, reg2);
-    reg0 = selectSFPReg(cUnit, vDest);
-    newLIR3(cUnit, op, reg0, reg1, reg2);
-    storeFloat(cUnit, reg0, vDest);
+    rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
+    rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
+    rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+    newLIR3(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+    storeValue(cUnit, rlDest, rlResult);
     return false;
 }
 
-static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
-                             int vSrc1, int vSrc2)
+static bool handleArithOpDouble(CompilationUnit *cUnit, MIR *mir,
+                                RegLocation rlDest, RegLocation rlSrc1,
+                                RegLocation rlSrc2)
 {
-    int op = THUMB_BKPT;
+    int op = kThumbBkpt;
+    RegLocation rlResult;
 
     switch (mir->dalvikInsn.opCode) {
         case OP_ADD_DOUBLE_2ADDR:
         case OP_ADD_DOUBLE:
-            op = THUMB2_VADDD;
+            op = kThumb2Vaddd;
             break;
         case OP_SUB_DOUBLE_2ADDR:
         case OP_SUB_DOUBLE:
-            op = THUMB2_VSUBD;
+            op = kThumb2Vsubd;
             break;
         case OP_DIV_DOUBLE_2ADDR:
         case OP_DIV_DOUBLE:
-            op = THUMB2_VDIVD;
+            op = kThumb2Vdivd;
             break;
         case OP_MUL_DOUBLE_2ADDR:
         case OP_MUL_DOUBLE:
-            op = THUMB2_VMULD;
+            op = kThumb2Vmuld;
             break;
         case OP_REM_DOUBLE_2ADDR:
         case OP_REM_DOUBLE:
         case OP_NEG_DOUBLE: {
-            return genArithOpDoublePortable(cUnit, mir, vDest, vSrc1, vSrc2);
+            return handleArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
+                                               rlSrc2);
         }
         default:
             return true;
     }
 
-    int reg0, reg1, reg2;
-    reg1 = selectDFPReg(cUnit, vSrc1);
-    reg2 = selectDFPReg(cUnit, vSrc2);
-    if (reg1 == reg2 && vSrc1 != vSrc2) {
-        reg2 = nextFPReg(cUnit, vSrc2, true /* isDouble */);
-    }
-    loadDouble(cUnit, vSrc1, reg1);
-    loadDouble(cUnit, vSrc2, reg2);
-    /* Rename the new vDest to a new register */
-    reg0 = selectDFPReg(cUnit, vNone);
-    newLIR3(cUnit, op, reg0, reg1, reg2);
-    storeDouble(cUnit, reg0, vDest);
+    rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
+    assert(rlSrc1.wide);
+    rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
+    assert(rlSrc2.wide);
+    rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+    assert(rlDest.wide);
+    assert(rlResult.wide);
+    newLIR3(cUnit, op, S2D(rlResult.lowReg, rlResult.highReg),
+            S2D(rlSrc1.lowReg, rlSrc1.highReg),
+            S2D(rlSrc2.lowReg, rlSrc2.highReg));
+    storeValueWide(cUnit, rlDest, rlResult);
     return false;
 }
 
-static bool genConversion(CompilationUnit *cUnit, MIR *mir)
+static bool handleConversion(CompilationUnit *cUnit, MIR *mir)
 {
     OpCode opCode = mir->dalvikInsn.opCode;
-    int vSrc1Dest = mir->dalvikInsn.vA;
-    int vSrc2 = mir->dalvikInsn.vB;
-    int op = THUMB_BKPT;
+    int op = kThumbBkpt;
     bool longSrc = false;
     bool longDest = false;
     int srcReg;
-    int tgtReg;
+    RegLocation rlSrc;
+    RegLocation rlDest;
+    RegLocation rlResult;
 
     switch (opCode) {
         case OP_INT_TO_FLOAT:
             longSrc = false;
             longDest = false;
-            op = THUMB2_VCVTIF;
+            op = kThumb2VcvtIF;
             break;
         case OP_FLOAT_TO_INT:
             longSrc = false;
             longDest = false;
-            op = THUMB2_VCVTFI;
+            op = kThumb2VcvtFI;
             break;
         case OP_DOUBLE_TO_FLOAT:
             longSrc = true;
             longDest = false;
-            op = THUMB2_VCVTDF;
+            op = kThumb2VcvtDF;
             break;
         case OP_FLOAT_TO_DOUBLE:
             longSrc = false;
             longDest = true;
-            op = THUMB2_VCVTFD;
+            op = kThumb2VcvtFd;
             break;
         case OP_INT_TO_DOUBLE:
             longSrc = false;
             longDest = true;
-            op = THUMB2_VCVTID;
+            op = kThumb2VcvtID;
             break;
         case OP_DOUBLE_TO_INT:
             longSrc = true;
             longDest = false;
-            op = THUMB2_VCVTDI;
+            op = kThumb2VcvtDI;
             break;
+        case OP_LONG_TO_DOUBLE:
         case OP_FLOAT_TO_LONG:
         case OP_LONG_TO_FLOAT:
         case OP_DOUBLE_TO_LONG:
-        case OP_LONG_TO_DOUBLE:
-            return genConversionPortable(cUnit, mir);
+            return handleConversionPortable(cUnit, mir);
         default:
             return true;
     }
     if (longSrc) {
-        srcReg = selectDFPReg(cUnit, vSrc2);
-        loadDouble(cUnit, vSrc2, srcReg);
+        rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
+        rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
+        srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
     } else {
-        srcReg = selectSFPReg(cUnit, vSrc2);
-        loadFloat(cUnit, vSrc2, srcReg);
+        rlSrc = getSrcLoc(cUnit, mir, 0);
+        rlSrc = loadValue(cUnit, rlSrc, kFPReg);
+        srcReg = rlSrc.lowReg;
     }
     if (longDest) {
-        int destReg = selectDFPReg(cUnit, vNone);
-        newLIR2(cUnit, op, destReg, srcReg);
-        storeDouble(cUnit, destReg, vSrc1Dest);
+        rlDest = getDestLocWide(cUnit, mir, 0, 1);
+        rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+        newLIR2(cUnit, op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
+        storeValueWide(cUnit, rlDest, rlResult);
     } else {
-        int destReg = selectSFPReg(cUnit, vNone);
-        newLIR2(cUnit, op, destReg, srcReg);
-        storeFloat(cUnit, destReg, vSrc1Dest);
+        rlDest = getDestLoc(cUnit, mir, 0);
+        rlResult = evalLoc(cUnit, rlDest, kFPReg, true);
+        newLIR2(cUnit, op, rlResult.lowReg, srcReg);
+        storeValue(cUnit, rlDest, rlResult);
     }
     return false;
 }
 
-static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
-                    int vSrc2)
+static bool handleCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
+                        RegLocation rlSrc1, RegLocation rlSrc2)
 {
     bool isDouble;
     int defaultResult;
     bool ltNaNBias;
-    int fpReg1, fpReg2;
+    RegLocation rlResult;
 
     switch(mir->dalvikInsn.opCode) {
         case OP_CMPL_FLOAT:
@@ -339,35 +315,26 @@ static bool genCmpX(CompilationUnit *cUnit, MIR *mir, int vDest, int vSrc1,
             return true;
     }
     if (isDouble) {
-        fpReg1 = selectDFPReg(cUnit, vSrc1);
-        fpReg2 = selectDFPReg(cUnit, vSrc2);
-        if (fpReg1 == fpReg2 && vSrc1 != vSrc2) {
-            fpReg2 = nextFPReg(cUnit, vSrc2, true /* isDouble */);
-        }
-        loadDouble(cUnit, vSrc1, fpReg1);
-        loadDouble(cUnit, vSrc2, fpReg2);
-        // Hard-coded use of r7 as temp.  Revisit
-        loadConstant(cUnit, r7, defaultResult);
-        newLIR2(cUnit, THUMB2_VCMPD, fpReg1, fpReg2);
+        rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
+        rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
+        rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+        loadConstant(cUnit, rlResult.lowReg, defaultResult);
+        newLIR2(cUnit, kThumb2Vcmpd, S2D(rlSrc1.lowReg, r1Src2.highReg),
+                S2D(rlSrc2.lowReg, rlSrc2.highReg));
     } else {
-        fpReg1 = selectSFPReg(cUnit, vSrc1);
-        fpReg2 = selectSFPReg(cUnit, vSrc2);
-        if (fpReg1 == fpReg2 && vSrc1 != vSrc2) {
-            fpReg2 = nextFPReg(cUnit, vSrc2, false /* isDouble */);
-        }
-        loadFloat(cUnit, vSrc1, fpReg1);
-        loadFloat(cUnit, vSrc2, fpReg2);
-        // Hard-coded use of r7 as temp.  Revisit
-        loadConstant(cUnit, r7, defaultResult);
-        newLIR2(cUnit, THUMB2_VCMPS, fpReg1, fpReg2);
+        rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
+        rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
+        rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
+        loadConstant(cUnit, rlResult.lowReg, defaultResult);
+        newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg);
     }
-    newLIR0(cUnit, THUMB2_FMSTAT);
-    genIT(cUnit, (defaultResult == -1) ? ARM_COND_GT : ARM_COND_MI, "");
-    newLIR2(cUnit, THUMB2_MOV_IMM_SHIFT, r7,
+    assert(!FPREG(rlResult.lowReg));
+    newLIR0(cUnit, kThumb2Fmstat);
+    genIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, "");
+    newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg,
             modifiedImmediate(-defaultResult)); // Must not alter ccodes
-    genIT(cUnit, ARM_COND_EQ, "");
-    loadConstant(cUnit, r7, 0);
-    // Hard-coded use of r4PC as temp.  Revisit
-    storeValue(cUnit, r7, vDest, r4PC);
+    genIT(cUnit, kArmCondEq, "");
+    loadConstant(cUnit, rlResult.lowReg, 0);
+    storeValue(cUnit, rlDest, rlResult);
     return false;
 }
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_RESTORE_STATE.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_RESTORE_STATE.S
new file mode 100644 (file)
index 0000000..ec80139
--- /dev/null
@@ -0,0 +1,11 @@
+    /*
+     * This handler restores state following a selfVerification memory access.
+     * On entry:
+     *    r0 - offset from rGLUE to the 1st element of the coreRegs save array.
+     */
+    add     r0, r0, rGLUE               @ pointer to heapArgSpace.coreRegs[0]
+    add     r0, #64                     @ pointer to heapArgSpace.fpRegs[0]
+    vldmia  r0, {d0-d15}
+    sub     r0, #64                     @ pointer to heapArgSpace.coreRegs[0]
+    ldmia   r0, {r0-r12}
+    bx      lr
diff --git a/vm/compiler/template/armv5te-vfp/TEMPLATE_SAVE_STATE.S b/vm/compiler/template/armv5te-vfp/TEMPLATE_SAVE_STATE.S
new file mode 100644 (file)
index 0000000..1bd02c8
--- /dev/null
@@ -0,0 +1,23 @@
+    /*
+     * This handler performs a register save for selfVerification mode.
+     * On entry:
+     *    Top of stack + 4: r7 value to save
+     *    Top of stack + 0: r0 value to save
+     *    r0 - offset from rGLUE to the beginning of the heapArgSpace record
+     *    r7 - the value of regMap
+     *
+     * The handler must save regMap, r0-r12 and then return with r0-r12
+     * with their original values (note that this means r0 and r7 must take
+     * the values on the stack - not the ones in those registers on entry.
+     * Finally, the two registers previously pushed must be popped.
+     */
+    add     r0, r0, rGLUE               @ pointer to heapArgSpace
+    stmia   r0!, {r7}                   @ save regMap
+    ldr     r7, [r13, #0]               @ recover r0 value
+    stmia   r0!, {r7}                   @ save r0
+    ldr     r7, [r13, #4]               @ recover r7 value
+    stmia   r0!, {r1-r12}
+    add     r0, #12                     @ move to start of FP save regio
+    vstmia  r0, {d0-d15}
+    pop     {r0, r7}                    @ recover r0, r7
+    bx      lr
index 6d1ce67..8b687d7 100644 (file)
@@ -51,3 +51,5 @@ JIT_TEMPLATE(CMPG_FLOAT_VFP)
 JIT_TEMPLATE(CMPL_FLOAT_VFP)
 JIT_TEMPLATE(SQRT_DOUBLE_VFP)
 JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
+JIT_TEMPLATE(SAVE_STATE)
+JIT_TEMPLATE(RESTORE_STATE)
index dfafd2c..01772b4 100644 (file)
@@ -1,6 +1,6 @@
 %default { "naninst":"mvn     r0, #0" }
     /*
-     * For the JIT: incoming arguments are pointers to the arguments in r0/r1
+     * For the JIT: incoming arguments in r0-r1, r2-r3
      *              result in r0
      *
      * Compare two floating-point values.  Puts 0, 1, or -1 into the
      * For: cmpl-double, cmpg-double
      */
     /* op vAA, vBB, vCC */
-    mov     r4, lr                      @ save return address
-    mov     r9, r0                      @ save copy of &arg1
-    mov     r10, r1                     @ save copy of &arg2
-    ldmia   r9, {r0-r1}                 @ r0/r1<- vBB/vBB+1
-    ldmia   r10, {r2-r3}                @ r2/r3<- vCC/vCC+1
+    push    {r0-r3}                     @ save operands
+    mov     r11, lr                     @ save return address
     LDR_PC_LR ".L__aeabi_cdcmple"       @ PIC way of "bl __aeabi_cdcmple"
     bhi     .L${opcode}_gt_or_nan       @ C set and Z clear, disambiguate
     mvncc   r0, #0                      @ (less than) r1<- -1
     moveq   r0, #0                      @ (equal) r1<- 0, trumps less than
-    bx      r4
+    add     sp, #16                     @ drop unused operands
+    bx      r11
 
     @ Test for NaN with a second comparison.  EABI forbids testing bit
     @ patterns, and we can't represent 0x7fc00000 in immediate form, so
     @ make the library call.
 .L${opcode}_gt_or_nan:
-    ldmia   r10, {r0-r1}                @ reverse order
-    ldmia   r9, {r2-r3}
+    pop     {r2-r3}                     @ restore operands in reverse order
+    pop     {r0-r1}                     @ restore operands in reverse order
     LDR_PC_LR ".L__aeabi_cdcmple"       @ r0<- Z set if eq, C clear if <
     movcc   r0, #1                      @ (greater than) r1<- 1
-    bxcc    r4
+    bxcc    r11
     $naninst                            @ r1<- 1 or -1 for NaN
-    bx      r4
+    bx      r11
 
index 31d4cd8..b63780f 100644 (file)
@@ -1,6 +1,6 @@
 %default { "naninst":"mvn     r0, #0" }
     /*
-     * For the JIT: incoming arguments in r0, r1
+     * For the JIT: incoming arguments in r0-r1, r2-r3
      *              result in r0
      *
      * Compare two floating-point values.  Puts 0, 1, or -1 into the
      * for: cmpl-float, cmpg-float
      */
     /* op vAA, vBB, vCC */
-    mov     r4, lr                      @ save return address
     mov     r9, r0                      @ Save copies - we may need to redo
     mov     r10, r1
+    mov     r11, lr                     @ save return address
     LDR_PC_LR ".L__aeabi_cfcmple"       @ cmp <=: C clear if <, Z set if eq
     bhi     .L${opcode}_gt_or_nan       @ C set and Z clear, disambiguate
     mvncc   r0, #0                      @ (less than) r0<- -1
     moveq   r0, #0                      @ (equal) r0<- 0, trumps less than
-    bx      r4
+    bx      r11
     @ Test for NaN with a second comparison.  EABI forbids testing bit
     @ patterns, and we can't represent 0x7fc00000 in immediate form, so
     @ make the library call.
 .L${opcode}_gt_or_nan:
-    mov     r1, r9                      @ reverse order
-    mov     r0, r10
+    mov     r0, r10                     @ restore in reverse order
+    mov     r1, r9
     LDR_PC_LR ".L__aeabi_cfcmple"       @ r0<- Z set if eq, C clear if <
     movcc   r0, #1                      @ (greater than) r1<- 1
-    bxcc    r4
+    bxcc    r11
     $naninst                            @ r1<- 1 or -1 for NaN
-    bx      r4
+    bx      r11
 
 
diff --git a/vm/compiler/template/armv5te/TEMPLATE_RESTORE_STATE.S b/vm/compiler/template/armv5te/TEMPLATE_RESTORE_STATE.S
new file mode 100644 (file)
index 0000000..e3719db
--- /dev/null
@@ -0,0 +1,8 @@
+    /*
+     * This handler restores state following a selfVerification memory access.
+     * On entry:
+     *    r0 - offset from rGLUE to the 1st element of the coreRegs save array.
+     */
+    add     r0, r0, rGLUE               @ pointer to heapArgSpace.coreRegs[0]
+    ldmia   r0, {r0-r12}
+    bx      lr
diff --git a/vm/compiler/template/armv5te/TEMPLATE_SAVE_STATE.S b/vm/compiler/template/armv5te/TEMPLATE_SAVE_STATE.S
new file mode 100644 (file)
index 0000000..df2d1e6
--- /dev/null
@@ -0,0 +1,21 @@
+    /*
+     * This handler performs a register save for selfVerification mode.
+     * On entry:
+     *    Top of stack + 4: r7 value to save
+     *    Top of stack + 0: r0 value to save
+     *    r0 - offset from rGLUE to the beginning of the heapArgSpace record
+     *    r7 - the value of regMap
+     *
+     * The handler must save regMap, r0-r12 and then return with r0-r12
+     * with their original values (note that this means r0 and r7 must take
+     * the values on the stack - not the ones in those registers on entry.
+     * Finally, the two registers previously pushed must be popped.
+     */
+    add     r0, r0, rGLUE               @ pointer to heapArgSpace
+    stmia   r0!, {r7}                   @ save regMap
+    ldr     r7, [r13, #0]               @ recover r0 value
+    stmia   r0!, {r7}                   @ save r0
+    ldr     r7, [r13, #4]               @ recover r7 value
+    stmia   r0!, {r1-r12}
+    pop     {r0, r7}                    @ recover r0, r7
+    bx      lr
index 20fb7fa..899c511 100644 (file)
@@ -36,3 +36,5 @@ JIT_TEMPLATE(SHL_LONG)
 JIT_TEMPLATE(SHR_LONG)
 JIT_TEMPLATE(USHR_LONG)
 JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
+JIT_TEMPLATE(SAVE_STATE)
+JIT_TEMPLATE(RESTORE_STATE)
index 6d1ce67..8b687d7 100644 (file)
@@ -51,3 +51,5 @@ JIT_TEMPLATE(CMPG_FLOAT_VFP)
 JIT_TEMPLATE(CMPL_FLOAT_VFP)
 JIT_TEMPLATE(SQRT_DOUBLE_VFP)
 JIT_TEMPLATE(THROW_EXCEPTION_COMMON)
+JIT_TEMPLATE(SAVE_STATE)
+JIT_TEMPLATE(RESTORE_STATE)
index 74d6936..64a050b 100644 (file)
@@ -1026,6 +1026,52 @@ dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
      */
     b       .LhandleException
 
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_SAVE_STATE
+dvmCompiler_TEMPLATE_SAVE_STATE:
+/* File: armv5te-vfp/TEMPLATE_SAVE_STATE.S */
+    /*
+     * This handler performs a register save for selfVerification mode.
+     * On entry:
+     *    Top of stack + 4: r7 value to save
+     *    Top of stack + 0: r0 value to save
+     *    r0 - offset from rGLUE to the beginning of the heapArgSpace record
+     *    r7 - the value of regMap
+     *
+     * The handler must save regMap, r0-r12 and then return with r0-r12
+     * with their original values (note that this means r0 and r7 must take
+     * the values on the stack - not the ones in those registers on entry.
+     * Finally, the two registers previously pushed must be popped.
+     */
+    add     r0, r0, rGLUE               @ pointer to heapArgSpace
+    stmia   r0!, {r7}                   @ save regMap
+    ldr     r7, [r13, #0]               @ recover r0 value
+    stmia   r0!, {r7}                   @ save r0
+    ldr     r7, [r13, #4]               @ recover r7 value
+    stmia   r0!, {r1-r12}
+    add     r0, #12                     @ move to start of FP save regio
+    vstmia  r0, {d0-d15}
+    pop     {r0, r7}                    @ recover r0, r7
+    bx      lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_RESTORE_STATE
+dvmCompiler_TEMPLATE_RESTORE_STATE:
+/* File: armv5te-vfp/TEMPLATE_RESTORE_STATE.S */
+    /*
+     * This handler restores state following a selfVerification memory access.
+     * On entry:
+     *    r0 - offset from rGLUE to the 1st element of the coreRegs save array.
+     */
+    add     r0, r0, rGLUE               @ pointer to heapArgSpace.coreRegs[0]
+    add     r0, #64                     @ pointer to heapArgSpace.fpRegs[0]
+    vldmia  r0, {d0-d15}
+    sub     r0, #64                     @ pointer to heapArgSpace.coreRegs[0]
+    ldmia   r0, {r0-r12}
+    bx      lr
+
     .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
 /* File: armv5te/footer.S */
 /*
index d2e6f54..803f53b 100644 (file)
@@ -442,7 +442,7 @@ dvmCompiler_TEMPLATE_CMPG_DOUBLE:
 /* File: armv5te/TEMPLATE_CMPG_DOUBLE.S */
 /* File: armv5te/TEMPLATE_CMPL_DOUBLE.S */
     /*
-     * For the JIT: incoming arguments are pointers to the arguments in r0/r1
+     * For the JIT: incoming arguments in r0-r1, r2-r3
      *              result in r0
      *
      * Compare two floating-point values.  Puts 0, 1, or -1 into the
@@ -456,28 +456,26 @@ dvmCompiler_TEMPLATE_CMPG_DOUBLE:
      * For: cmpl-double, cmpg-double
      */
     /* op vAA, vBB, vCC */
-    mov     r4, lr                      @ save return address
-    mov     r9, r0                      @ save copy of &arg1
-    mov     r10, r1                     @ save copy of &arg2
-    ldmia   r9, {r0-r1}                 @ r0/r1<- vBB/vBB+1
-    ldmia   r10, {r2-r3}                @ r2/r3<- vCC/vCC+1
+    push    {r0-r3}                     @ save operands
+    mov     r11, lr                     @ save return address
     LDR_PC_LR ".L__aeabi_cdcmple"       @ PIC way of "bl __aeabi_cdcmple"
     bhi     .LTEMPLATE_CMPG_DOUBLE_gt_or_nan       @ C set and Z clear, disambiguate
     mvncc   r0, #0                      @ (less than) r1<- -1
     moveq   r0, #0                      @ (equal) r1<- 0, trumps less than
-    bx      r4
+    add     sp, #16                     @ drop unused operands
+    bx      r11
 
     @ Test for NaN with a second comparison.  EABI forbids testing bit
     @ patterns, and we can't represent 0x7fc00000 in immediate form, so
     @ make the library call.
 .LTEMPLATE_CMPG_DOUBLE_gt_or_nan:
-    ldmia   r10, {r0-r1}                @ reverse order
-    ldmia   r9, {r2-r3}
+    pop     {r2-r3}                     @ restore operands in reverse order
+    pop     {r0-r1}                     @ restore operands in reverse order
     LDR_PC_LR ".L__aeabi_cdcmple"       @ r0<- Z set if eq, C clear if <
     movcc   r0, #1                      @ (greater than) r1<- 1
-    bxcc    r4
+    bxcc    r11
     mov     r0, #1                            @ r1<- 1 or -1 for NaN
-    bx      r4
+    bx      r11
 
 
 
@@ -487,7 +485,7 @@ dvmCompiler_TEMPLATE_CMPG_DOUBLE:
 dvmCompiler_TEMPLATE_CMPL_DOUBLE:
 /* File: armv5te/TEMPLATE_CMPL_DOUBLE.S */
     /*
-     * For the JIT: incoming arguments are pointers to the arguments in r0/r1
+     * For the JIT: incoming arguments in r0-r1, r2-r3
      *              result in r0
      *
      * Compare two floating-point values.  Puts 0, 1, or -1 into the
@@ -501,28 +499,26 @@ dvmCompiler_TEMPLATE_CMPL_DOUBLE:
      * For: cmpl-double, cmpg-double
      */
     /* op vAA, vBB, vCC */
-    mov     r4, lr                      @ save return address
-    mov     r9, r0                      @ save copy of &arg1
-    mov     r10, r1                     @ save copy of &arg2
-    ldmia   r9, {r0-r1}                 @ r0/r1<- vBB/vBB+1
-    ldmia   r10, {r2-r3}                @ r2/r3<- vCC/vCC+1
+    push    {r0-r3}                     @ save operands
+    mov     r11, lr                     @ save return address
     LDR_PC_LR ".L__aeabi_cdcmple"       @ PIC way of "bl __aeabi_cdcmple"
     bhi     .LTEMPLATE_CMPL_DOUBLE_gt_or_nan       @ C set and Z clear, disambiguate
     mvncc   r0, #0                      @ (less than) r1<- -1
     moveq   r0, #0                      @ (equal) r1<- 0, trumps less than
-    bx      r4
+    add     sp, #16                     @ drop unused operands
+    bx      r11
 
     @ Test for NaN with a second comparison.  EABI forbids testing bit
     @ patterns, and we can't represent 0x7fc00000 in immediate form, so
     @ make the library call.
 .LTEMPLATE_CMPL_DOUBLE_gt_or_nan:
-    ldmia   r10, {r0-r1}                @ reverse order
-    ldmia   r9, {r2-r3}
+    pop     {r2-r3}                     @ restore operands in reverse order
+    pop     {r0-r1}                     @ restore operands in reverse order
     LDR_PC_LR ".L__aeabi_cdcmple"       @ r0<- Z set if eq, C clear if <
     movcc   r0, #1                      @ (greater than) r1<- 1
-    bxcc    r4
+    bxcc    r11
     mvn     r0, #0                            @ r1<- 1 or -1 for NaN
-    bx      r4
+    bx      r11
 
 
 /* ------------------------------ */
@@ -532,7 +528,7 @@ dvmCompiler_TEMPLATE_CMPG_FLOAT:
 /* File: armv5te/TEMPLATE_CMPG_FLOAT.S */
 /* File: armv5te/TEMPLATE_CMPL_FLOAT.S */
     /*
-     * For the JIT: incoming arguments in r0, r1
+     * For the JIT: incoming arguments in r0-r1, r2-r3
      *              result in r0
      *
      * Compare two floating-point values.  Puts 0, 1, or -1 into the
@@ -565,25 +561,25 @@ dvmCompiler_TEMPLATE_CMPG_FLOAT:
      * for: cmpl-float, cmpg-float
      */
     /* op vAA, vBB, vCC */
-    mov     r4, lr                      @ save return address
     mov     r9, r0                      @ Save copies - we may need to redo
     mov     r10, r1
+    mov     r11, lr                     @ save return address
     LDR_PC_LR ".L__aeabi_cfcmple"       @ cmp <=: C clear if <, Z set if eq
     bhi     .LTEMPLATE_CMPG_FLOAT_gt_or_nan       @ C set and Z clear, disambiguate
     mvncc   r0, #0                      @ (less than) r0<- -1
     moveq   r0, #0                      @ (equal) r0<- 0, trumps less than
-    bx      r4
+    bx      r11
     @ Test for NaN with a second comparison.  EABI forbids testing bit
     @ patterns, and we can't represent 0x7fc00000 in immediate form, so
     @ make the library call.
 .LTEMPLATE_CMPG_FLOAT_gt_or_nan:
-    mov     r1, r9                      @ reverse order
-    mov     r0, r10
+    mov     r0, r10                     @ restore in reverse order
+    mov     r1, r9
     LDR_PC_LR ".L__aeabi_cfcmple"       @ r0<- Z set if eq, C clear if <
     movcc   r0, #1                      @ (greater than) r1<- 1
-    bxcc    r4
+    bxcc    r11
     mov     r0, #1                            @ r1<- 1 or -1 for NaN
-    bx      r4
+    bx      r11
 
 
 
@@ -594,7 +590,7 @@ dvmCompiler_TEMPLATE_CMPG_FLOAT:
 dvmCompiler_TEMPLATE_CMPL_FLOAT:
 /* File: armv5te/TEMPLATE_CMPL_FLOAT.S */
     /*
-     * For the JIT: incoming arguments in r0, r1
+     * For the JIT: incoming arguments in r0-r1, r2-r3
      *              result in r0
      *
      * Compare two floating-point values.  Puts 0, 1, or -1 into the
@@ -627,25 +623,25 @@ dvmCompiler_TEMPLATE_CMPL_FLOAT:
      * for: cmpl-float, cmpg-float
      */
     /* op vAA, vBB, vCC */
-    mov     r4, lr                      @ save return address
     mov     r9, r0                      @ Save copies - we may need to redo
     mov     r10, r1
+    mov     r11, lr                     @ save return address
     LDR_PC_LR ".L__aeabi_cfcmple"       @ cmp <=: C clear if <, Z set if eq
     bhi     .LTEMPLATE_CMPL_FLOAT_gt_or_nan       @ C set and Z clear, disambiguate
     mvncc   r0, #0                      @ (less than) r0<- -1
     moveq   r0, #0                      @ (equal) r0<- 0, trumps less than
-    bx      r4
+    bx      r11
     @ Test for NaN with a second comparison.  EABI forbids testing bit
     @ patterns, and we can't represent 0x7fc00000 in immediate form, so
     @ make the library call.
 .LTEMPLATE_CMPL_FLOAT_gt_or_nan:
-    mov     r1, r9                      @ reverse order
-    mov     r0, r10
+    mov     r0, r10                     @ restore in reverse order
+    mov     r1, r9
     LDR_PC_LR ".L__aeabi_cfcmple"       @ r0<- Z set if eq, C clear if <
     movcc   r0, #1                      @ (greater than) r1<- 1
-    bxcc    r4
+    bxcc    r11
     mvn     r0, #0                            @ r1<- 1 or -1 for NaN
-    bx      r4
+    bx      r11
 
 
 
@@ -760,6 +756,47 @@ dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
      */
     b       .LhandleException
 
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_SAVE_STATE
+dvmCompiler_TEMPLATE_SAVE_STATE:
+/* File: armv5te/TEMPLATE_SAVE_STATE.S */
+    /*
+     * This handler performs a register save for selfVerification mode.
+     * On entry:
+     *    Top of stack + 4: r7 value to save
+     *    Top of stack + 0: r0 value to save
+     *    r0 - offset from rGLUE to the beginning of the heapArgSpace record
+     *    r7 - the value of regMap
+     *
+     * The handler must save regMap, r0-r12 and then return with r0-r12
+     * with their original values (note that this means r0 and r7 must take
+     * the values on the stack - not the ones in those registers on entry.
+     * Finally, the two registers previously pushed must be popped.
+     */
+    add     r0, r0, rGLUE               @ pointer to heapArgSpace
+    stmia   r0!, {r7}                   @ save regMap
+    ldr     r7, [r13, #0]               @ recover r0 value
+    stmia   r0!, {r7}                   @ save r0
+    ldr     r7, [r13, #4]               @ recover r7 value
+    stmia   r0!, {r1-r12}
+    pop     {r0, r7}                    @ recover r0, r7
+    bx      lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_RESTORE_STATE
+dvmCompiler_TEMPLATE_RESTORE_STATE:
+/* File: armv5te/TEMPLATE_RESTORE_STATE.S */
+    /*
+     * This handler restores state following a selfVerification memory access.
+     * On entry:
+     *    r0 - offset from rGLUE to the 1st element of the coreRegs save array.
+     */
+    add     r0, r0, rGLUE               @ pointer to heapArgSpace.coreRegs[0]
+    ldmia   r0, {r0-r12}
+    bx      lr
+
     .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
 /* File: armv5te/footer.S */
 /*
index 4ed5ea1..b597905 100644 (file)
@@ -1026,6 +1026,52 @@ dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
      */
     b       .LhandleException
 
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_SAVE_STATE
+dvmCompiler_TEMPLATE_SAVE_STATE:
+/* File: armv5te-vfp/TEMPLATE_SAVE_STATE.S */
+    /*
+     * This handler performs a register save for selfVerification mode.
+     * On entry:
+     *    Top of stack + 4: r7 value to save
+     *    Top of stack + 0: r0 value to save
+     *    r0 - offset from rGLUE to the beginning of the heapArgSpace record
+     *    r7 - the value of regMap
+     *
+     * The handler must save regMap, r0-r12 and then return with r0-r12
+     * with their original values (note that this means r0 and r7 must take
+     * the values on the stack - not the ones in those registers on entry.
+     * Finally, the two registers previously pushed must be popped.
+     */
+    add     r0, r0, rGLUE               @ pointer to heapArgSpace
+    stmia   r0!, {r7}                   @ save regMap
+    ldr     r7, [r13, #0]               @ recover r0 value
+    stmia   r0!, {r7}                   @ save r0
+    ldr     r7, [r13, #4]               @ recover r7 value
+    stmia   r0!, {r1-r12}
+    add     r0, #12                     @ move to start of FP save regio
+    vstmia  r0, {d0-d15}
+    pop     {r0, r7}                    @ recover r0, r7
+    bx      lr
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_RESTORE_STATE
+dvmCompiler_TEMPLATE_RESTORE_STATE:
+/* File: armv5te-vfp/TEMPLATE_RESTORE_STATE.S */
+    /*
+     * This handler restores state following a selfVerification memory access.
+     * On entry:
+     *    r0 - offset from rGLUE to the 1st element of the coreRegs save array.
+     */
+    add     r0, r0, rGLUE               @ pointer to heapArgSpace.coreRegs[0]
+    add     r0, #64                     @ pointer to heapArgSpace.fpRegs[0]
+    vldmia  r0, {d0-d15}
+    sub     r0, #64                     @ pointer to heapArgSpace.coreRegs[0]
+    ldmia   r0, {r0-r12}
+    bx      lr
+
     .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
 /* File: armv5te/footer.S */
 /*
index 28994b7..f397a34 100644 (file)
@@ -39,12 +39,15 @@ typedef enum InterpEntry {
 
 #if defined(WITH_JIT)
 #if defined(WITH_SELF_VERIFICATION)
+/*
+ * Note: layout is important.  This record hold saved state information
+ * and is used by both C, generated code in the cache, and assembler handlers.
+ */
 typedef struct HeapArgSpace {
-    int r0;
-    int r1;
-    int r2;
-    int r3;
+//FIXME: This is arm-specific.  Need to be able to redefine this by target
     int regMap;
+    int coreRegs[16];
+    int fpRegs[32];
 } HeapArgSpace;
 #endif
 
index c149035..fc770d7 100644 (file)
@@ -486,6 +486,7 @@ void dvmJitStats()
 void dvmJitShutdown(void)
 {
     /* Shutdown the compiler thread */
+
     dvmCompilerShutdown();
 
     dvmCompilerDumpStats();