MIPS switch table support

And 64-bit neg/add/sub (ouch! Mips has no carry bit...)

Change-Id: Ifb94324a0052d6069977fb8f22679b95890445d8
diff --git a/src/compiler/codegen/mips/Assemble.cc b/src/compiler/codegen/mips/Assemble.cc
index 0021318..5f215ef 100644
--- a/src/compiler/codegen/mips/Assemble.cc
+++ b/src/compiler/codegen/mips/Assemble.cc
@@ -221,7 +221,7 @@
     ENCODING_MAP(kMipsNop, 0x00000000,
                  kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, NO_OPERAND,
-                 "nop", "", 4),
+                 "nop", ";", 4),
     ENCODING_MAP(kMipsNor, 0x00000027, /* used for "not" too */
                  kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
                  kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
@@ -398,6 +398,22 @@
                  kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
                  "mtc1", "!0r,!1s", 4),
 #endif
+    ENCODING_MAP(kMipsDelta, 0x27e00000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, 15, 0,
+                 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0 | REG_USE_LR,
+                 "addiu", "!0r,r_ra,0x!1h(!1d)", 4),
+    ENCODING_MAP(kMipsDeltaHi, 0x3C000000,
+                 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0,
+                 "lui", "!0r,0x!1h(!1d)", 4),
+    ENCODING_MAP(kMipsDeltaLo, 0x34000000,
+                 kFmtBlt5_2, 16, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, IS_QUAD_OP | REG_DEF0_USE0,
+                 "ori", "!0r,!0r,0x!1h(!1d)", 4),
+    ENCODING_MAP(kMipsCurrPC, 0x0c000000,
+                 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
+                 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
+                 "pc2ra", "; r_ra <- .+8", 4),
     ENCODING_MAP(kMipsUndefined, 0x64000000,
                  kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, NO_OPERAND,
@@ -426,7 +442,56 @@
             continue;
         }
 
-        if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
+// TODO: check for lir->flags.pcRelFixup
+
+        if (lir->opcode == kMipsDelta) {
+            int offset1 = ((LIR*)lir->operands[2])->offset;
+            SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
+            int offset2 = tabRec ? tabRec->offset : lir->target->offset;
+            int delta = offset2 - offset1;
+            if ((delta & 0xffff) == delta) {
+                // Fits
+                lir->operands[1] = delta;
+            } else {
+                // Doesn't fit - must expand to kMipsDelta[Hi|Lo] pair
+                LIR *newDeltaHi =
+                    (LIR *)oatNew(cUnit, sizeof(LIR), true,
+                    kAllocLIR);
+                newDeltaHi->dalvikOffset = lir->dalvikOffset;
+                newDeltaHi->target = lir->target;
+                newDeltaHi->opcode = kMipsDeltaHi;
+                newDeltaHi->operands[0] = lir->operands[0];
+                newDeltaHi->operands[2] = lir->operands[2];
+                newDeltaHi->operands[3] = lir->operands[3];
+                oatSetupResourceMasks(newDeltaHi);
+                oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaHi);
+                LIR *newDeltaLo =
+                    (LIR *)oatNew(cUnit, sizeof(LIR), true,
+                    kAllocLIR);
+                newDeltaLo->dalvikOffset = lir->dalvikOffset;
+                newDeltaLo->target = lir->target;
+                newDeltaLo->opcode = kMipsDeltaLo;
+                newDeltaLo->operands[0] = lir->operands[0];
+                newDeltaLo->operands[2] = lir->operands[2];
+                newDeltaLo->operands[3] = lir->operands[3];
+                oatSetupResourceMasks(newDeltaLo);
+                oatInsertLIRBefore((LIR*)lir, (LIR*)newDeltaLo);
+                lir->flags.isNop = true;
+                res = kRetryAll;
+            }
+        } else if (lir->opcode == kMipsDeltaLo) {
+            int offset1 = ((LIR*)lir->operands[2])->offset;
+            SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
+            int offset2 = tabRec ? tabRec->offset : lir->target->offset;
+            int delta = offset2 - offset1;
+            lir->operands[1] = delta & 0xffff;
+        } else if (lir->opcode == kMipsDeltaHi) {
+            int offset1 = ((LIR*)lir->operands[2])->offset;
+            SwitchTable *tabRec = (SwitchTable*)lir->operands[3];
+            int offset2 = tabRec ? tabRec->offset : lir->target->offset;
+            int delta = offset2 - offset1;
+            lir->operands[1] = (delta >> 16) & 0xffff;
+        } else if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
             LIR *targetLIR = (LIR *) lir->target;
             intptr_t pc = lir->offset + 4;
             intptr_t target = targetLIR->offset;
@@ -508,6 +573,11 @@
                     }
                     bits |= value;
                     break;
+                case kFmtBlt5_2:
+                    value = (operand & 0x1f);
+                    bits |= (value << encoder->fieldLoc[i].start);
+                    bits |= (value << encoder->fieldLoc[i].end);
+                    break;
                 case kFmtDfp: {
                     DCHECK(DOUBLEREG(operand));
                     DCHECK((operand & 0x1) == 0);