Multi-target support

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

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

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

Change-Id: Ia66b2847e22644a1ec63e66bf5f2fee722f963d4
diff --git a/src/compiler/codegen/arm/ArmRallocUtil.cc b/src/compiler/codegen/arm/ArmRallocUtil.cc
index 1986b0f..38f1b88 100644
--- a/src/compiler/codegen/arm/ArmRallocUtil.cc
+++ b/src/compiler/codegen/arm/ArmRallocUtil.cc
@@ -28,262 +28,87 @@
 namespace art {
 
 /*
- * Placeholder routine until we do proper register allocation.
+ * TUNING: is leaf?  Can't just use "hasInvoke" to determine as some
+ * instructions might call out to C/assembly helper functions.  Until
+ * machinery is in place, always spill lr.
  */
 
-typedef struct RefCounts {
-    int count;
-    int sReg;
-    bool doubleStart;   // Starting vReg for a double
-} RefCounts;
-
-/* USE SSA names to count references of base Dalvik vRegs. */
-STATIC void countRefs(CompilationUnit *cUnit, BasicBlock* bb,
-                      RefCounts* coreCounts, RefCounts* fpCounts)
+void oatAdjustSpillMask(CompilationUnit* cUnit)
 {
-    MIR* mir;
-    if (bb->blockType != kDalvikByteCode && bb->blockType != kEntryBlock &&
-        bb->blockType != kExitBlock)
-        return;
-
-    for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
-        SSARepresentation *ssaRep = mir->ssaRep;
-        if (ssaRep) {
-            for (int i = 0; i < ssaRep->numDefs;) {
-                RegLocation loc = cUnit->regLocation[ssaRep->defs[i]];
-                RefCounts* counts = loc.fp ? fpCounts : coreCounts;
-                int vReg = oatS2VReg(cUnit, ssaRep->defs[i]);
-                if (loc.defined) {
-                    counts[vReg].count++;
-                }
-                if (loc.wide) {
-                    if (loc.defined) {
-                        if (loc.fp) {
-                            counts[vReg].doubleStart = true;
-                        }
-                        counts[vReg+1].count++;
-                    }
-                    i += 2;
-                } else {
-                    i++;
-                }
-            }
-            for (int i = 0; i < ssaRep->numUses;) {
-                RegLocation loc = cUnit->regLocation[ssaRep->uses[i]];
-                RefCounts* counts = loc.fp ? fpCounts : coreCounts;
-                int vReg = oatS2VReg(cUnit, ssaRep->uses[i]);
-                if (loc.defined) {
-                    counts[vReg].count++;
-                }
-                if (loc.wide) {
-                    if (loc.defined) {
-                        if (loc.fp) {
-                            counts[vReg].doubleStart = true;
-                        }
-                        counts[vReg+1].count++;
-                    }
-                    i += 2;
-                } else {
-                    i++;
-                }
-            }
-        }
-    }
-}
-
-/* qsort callback function, sort descending */
-STATIC int sortCounts(const void *val1, const void *val2)
-{
-    const RefCounts* op1 = (const RefCounts*)val1;
-    const RefCounts* op2 = (const RefCounts*)val2;
-    return (op1->count == op2->count) ? 0 : (op1->count < op2->count ? 1 : -1);
-}
-
-STATIC void dumpCounts(const RefCounts* arr, int size, const char* msg)
-{
-    LOG(INFO) << msg;
-    for (int i = 0; i < size; i++) {
-        LOG(INFO) << "sReg[" << arr[i].sReg << "]: " << arr[i].count;
-    }
+    cUnit->coreSpillMask |= (1 << rLR);
+    cUnit->numCoreSpills++;
 }
 
 /*
- * Note: some portions of this code required even if the kPromoteRegs
- * optimization is disabled.
+ * Mark a callee-save fp register as promoted.  Note that
+ * vpush/vpop uses contiguous register lists so we must
+ * include any holes in the mask.  Associate holes with
+ * Dalvik register INVALID_VREG (0xFFFFU).
  */
-extern void oatDoPromotion(CompilationUnit* cUnit)
+void oatMarkPreservedSingle(CompilationUnit* cUnit, int sReg, int reg)
 {
-    int numRegs = cUnit->numDalvikRegisters;
-
-    /*
-     * TUNING: is leaf?  Can't just use "hasInvoke" to determine as some
-     * instructions might call out to C/assembly helper functions.  Until
-     * machinery is in place, always spill lr.
-     */
-    cUnit->coreSpillMask |= (1 << rLR);
-    cUnit->numCoreSpills++;
-    /*
-     * Simple hack for testing register allocation.  Just do a static
-     * count of the uses of Dalvik registers.  Note that we examine
-     * the SSA names, but count based on original Dalvik register name.
-     * Count refs separately based on type in order to give allocation
-     * preference to fp doubles - which must be allocated sequential
-     * physical single fp registers started with an even-numbered
-     * reg.
-     */
-    RefCounts *coreRegs = (RefCounts *)
-          oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
-    RefCounts *fpRegs = (RefCounts *)
-          oatNew(cUnit, sizeof(RefCounts) * numRegs, true, kAllocRegAlloc);
-    for (int i = 0; i < numRegs; i++) {
-        coreRegs[i].sReg = fpRegs[i].sReg = i;
+    DCHECK_GE(reg, FP_REG_MASK + FP_CALLEE_SAVE_BASE);
+    reg = (reg & FP_REG_MASK) - FP_CALLEE_SAVE_BASE;
+    // Ensure fpVmapTable is large enough
+    int tableSize = cUnit->fpVmapTable.size();
+    for (int i = tableSize; i < (reg + 1); i++) {
+        cUnit->fpVmapTable.push_back(INVALID_VREG);
     }
-    GrowableListIterator iterator;
-    oatGrowableListIteratorInit(&cUnit->blockList, &iterator);
-    while (true) {
-        BasicBlock* bb;
-        bb = (BasicBlock*)oatGrowableListIteratorNext(&iterator);
-        if (bb == NULL) break;
-        countRefs(cUnit, bb, coreRegs, fpRegs);
-    }
+    // Add the current mapping
+    cUnit->fpVmapTable[reg] = sReg;
+    // Size of fpVmapTable is high-water mark, use to set mask
+    cUnit->numFPSpills = cUnit->fpVmapTable.size();
+    cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << FP_CALLEE_SAVE_BASE;
+}
 
-    /*
-     * Ideally, we'd allocate doubles starting with an even-numbered
-     * register.  Bias the counts to try to allocate any vreg that's
-     * used as the start of a pair first.
-     */
-    for (int i = 0; i < numRegs; i++) {
-        if (fpRegs[i].doubleStart) {
-            fpRegs[i].count *= 2;
-        }
-    }
-
-    // Sort the count arrays
-    qsort(coreRegs, numRegs, sizeof(RefCounts), sortCounts);
-    qsort(fpRegs, numRegs, sizeof(RefCounts), sortCounts);
-
-    if (cUnit->printMe) {
-        dumpCounts(coreRegs, numRegs, "Core regs after sort");
-        dumpCounts(fpRegs, numRegs, "Fp regs after sort");
-    }
-
-    if (!(cUnit->disableOpt & (1 << kPromoteRegs))) {
-        // Promote fpRegs
-        for (int i = 0; (fpRegs[i].count > 0) && (i < numRegs); i++) {
-            if (cUnit->promotionMap[fpRegs[i].sReg].fpLocation != kLocPhysReg) {
-                if (fpRegs[i].sReg >= cUnit->numRegs) {
-                    // don't promote arg regs
-                    continue;
-                }
-                int reg = oatAllocPreservedFPReg(cUnit, fpRegs[i].sReg,
-                    fpRegs[i].doubleStart);
-                if (reg < 0) {
-                    break;  // No more left
-                }
-            }
+void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
+{
+    RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
+    RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
+    DCHECK(info1 && info2 && info1->pair && info2->pair &&
+           (info1->partner == info2->reg) &&
+           (info2->partner == info1->reg));
+    if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
+        if (!(info1->isTemp && info2->isTemp)) {
+            /* Should not happen.  If it does, there's a problem in evalLoc */
+            LOG(FATAL) << "Long half-temp, half-promoted";
         }
 
-        // Promote core regs
-        for (int i = 0; (coreRegs[i].count > 0) && i < numRegs; i++) {
-            if (cUnit->promotionMap[coreRegs[i].sReg].coreLocation !=
-                    kLocPhysReg) {
-                if (coreRegs[i].sReg >= cUnit->numRegs) {
-                    // don't promote arg regs
-                    continue;
-                }
-                int reg = oatAllocPreservedCoreReg(cUnit, coreRegs[i].sReg);
-                if (reg < 0) {
-                   break;  // No more left
-                }
-            }
-        }
-    }
-
-    // Now, update SSA names to new home locations
-    for (int i = 0; i < cUnit->numSSARegs; i++) {
-        RegLocation *curr = &cUnit->regLocation[i];
-        int baseVReg = oatS2VReg(cUnit, curr->sRegLow);
-        if (!curr->wide) {
-            if (curr->fp) {
-                if (cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) {
-                    curr->location = kLocPhysReg;
-                    curr->lowReg = cUnit->promotionMap[baseVReg].fpReg;
-                    curr->home = true;
-                }
-            } else {
-                if (cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg) {
-                    curr->location = kLocPhysReg;
-                    curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
-                    curr->home = true;
-                }
-            }
-            curr->highReg = INVALID_REG;
-        } else {
-            if (curr->highWord) {
-                continue;
-            }
-            if (curr->fp) {
-                if ((cUnit->promotionMap[baseVReg].fpLocation == kLocPhysReg) &&
-                    (cUnit->promotionMap[baseVReg+1].fpLocation ==
-                    kLocPhysReg)) {
-                    int lowReg = cUnit->promotionMap[baseVReg].fpReg;
-                    int highReg = cUnit->promotionMap[baseVReg+1].fpReg;
-                    // Doubles require pair of singles starting at even reg
-                    if (((lowReg & 0x1) == 0) && ((lowReg + 1) == highReg)) {
-                        curr->location = kLocPhysReg;
-                        curr->lowReg = lowReg;
-                        curr->highReg = highReg;
-                        curr->home = true;
-                    }
-                }
-            } else {
-                if ((cUnit->promotionMap[baseVReg].coreLocation == kLocPhysReg)
-                     && (cUnit->promotionMap[baseVReg+1].coreLocation ==
-                     kLocPhysReg)) {
-                    curr->location = kLocPhysReg;
-                    curr->lowReg = cUnit->promotionMap[baseVReg].coreReg;
-                    curr->highReg = cUnit->promotionMap[baseVReg+1].coreReg;
-                    curr->home = true;
-                }
-            }
-        }
+        info1->dirty = false;
+        info2->dirty = false;
+        if (oatS2VReg(cUnit, info2->sReg) <
+            oatS2VReg(cUnit, info1->sReg))
+            info1 = info2;
+        int vReg = oatS2VReg(cUnit, info1->sReg);
+        oatFlushRegWideImpl(cUnit, rSP,
+                                    oatVRegOffset(cUnit, vReg),
+                                    info1->reg, info1->partner);
     }
 }
 
-/* Returns sp-relative offset in bytes for a VReg */
-extern int oatVRegOffset(CompilationUnit* cUnit, int vReg)
+void oatFlushReg(CompilationUnit* cUnit, int reg)
 {
-    return (vReg < cUnit->numRegs) ? cUnit->regsOffset + (vReg << 2) :
-            cUnit->insOffset + ((vReg - cUnit->numRegs) << 2);
+    RegisterInfo* info = oatGetRegInfo(cUnit, reg);
+    if (info->live && info->dirty) {
+        info->dirty = false;
+        int vReg = oatS2VReg(cUnit, info->sReg);
+        oatFlushRegImpl(cUnit, rSP,
+                                oatVRegOffset(cUnit, vReg),
+                                reg, kWord);
+    }
 }
 
-/* Returns sp-relative offset in bytes for a SReg */
-extern int oatSRegOffset(CompilationUnit* cUnit, int sReg)
-{
-    return oatVRegOffset(cUnit, oatS2VReg(cUnit, sReg));
+/* Give access to the target-dependent FP register encoding to common code */
+bool oatIsFpReg(int reg) {
+    return FPREG(reg);
 }
 
-
-/* Return sp-relative offset in bytes using Method* */
-extern int oatVRegOffset(const DexFile::CodeItem* code_item,
-                         uint32_t core_spills, uint32_t fp_spills,
-                         size_t frame_size, int reg)
-{
-    int numIns = code_item->ins_size_;
-    int numRegs = code_item->registers_size_ - numIns;
-    int numOuts = code_item->outs_size_;
-    int numSpills = __builtin_popcount(core_spills) +
-                    __builtin_popcount(fp_spills);
-    int numPadding = (STACK_ALIGN_WORDS -
-        (numSpills + numRegs + numOuts + 2)) & (STACK_ALIGN_WORDS-1);
-    int regsOffset = (numOuts + numPadding + 1) * 4;
-    int insOffset = frame_size + 4;
-    return (reg < numRegs) ? regsOffset + (reg << 2) :
-           insOffset + ((reg - numRegs) << 2);
+uint32_t oatFpRegMask() {
+    return FP_REG_MASK;
 }
 
 /* Clobber all regs that might be used by an external C call */
-extern void oatClobberCalleeSave(CompilationUnit *cUnit)
+void oatClobberCalleeSave(CompilationUnit *cUnit)
 {
     oatClobber(cUnit, r0);
     oatClobber(cUnit, r1);
@@ -340,4 +165,28 @@
                       : &cUnit->regPool->coreRegs[reg];
 }
 
+/* To be used when explicitly managing register use */
+extern void oatLockCallTemps(CompilationUnit* cUnit)
+{
+    oatLockTemp(cUnit, r0);
+    oatLockTemp(cUnit, r1);
+    oatLockTemp(cUnit, r2);
+    oatLockTemp(cUnit, r3);
+}
+
+/* To be used when explicitly managing register use */
+extern void oatFreeCallTemps(CompilationUnit* cUnit)
+{
+    oatFreeTemp(cUnit, r0);
+    oatFreeTemp(cUnit, r1);
+    oatFreeTemp(cUnit, r2);
+    oatFreeTemp(cUnit, r3);
+}
+
+/* Convert an instruction to a NOP */
+STATIC void oatNopLIR( LIR* lir)
+{
+    ((ArmLIR*)lir)->flags.isNop = true;
+}
+
 }  // namespace art