summaryrefslogtreecommitdiff
path: root/src/compiler/codegen/RallocUtil.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/codegen/RallocUtil.cc')
-rw-r--r--src/compiler/codegen/RallocUtil.cc1028
1 files changed, 1028 insertions, 0 deletions
diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc
new file mode 100644
index 0000000000..30b52804e5
--- /dev/null
+++ b/src/compiler/codegen/RallocUtil.cc
@@ -0,0 +1,1028 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file contains register alloction support and is intended to be
+ * included by:
+ *
+ * Codegen-$(TARGET_ARCH_VARIANT).c
+ *
+ */
+
+#include "../CompilerUtility.h"
+#include "../CompilerIR.h"
+#include "../Dataflow.h"
+#include "Ralloc.h"
+
+#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.
+ */
+
+/*
+ * 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.
+ */
+extern void oatResetRegPool(CompilationUnit* cUnit)
+{
+ int i;
+ for (i=0; i < cUnit->regPool->numCoreRegs; i++) {
+ if (cUnit->regPool->coreRegs[i].isTemp)
+ cUnit->regPool->coreRegs[i].inUse = false;
+ }
+ for (i=0; i < cUnit->regPool->numFPRegs; i++) {
+ if (cUnit->regPool->FPRegs[i].isTemp)
+ cUnit->regPool->FPRegs[i].inUse = false;
+ }
+}
+
+ /* Set up temp & preserved register pools specialized by target */
+extern void oatInitPool(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].isTemp = 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;
+ LOG(INFO) << "================================================";
+ for (i=0; i < numRegs; i++ ){
+ char buf[100];
+ snprintf(buf, 100,
+ "R[%d]: T:%d, U:%d, P:%d, p:%d, LV:%d, D:%d, SR:%d, ST:%x, EN:%x",
+ p[i].reg, p[i].isTemp, 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);
+ LOG(INFO) << buf;
+ }
+ LOG(INFO) << "================================================";
+}
+
+/* Get info for a reg. */
+static RegisterInfo* getRegInfo(CompilationUnit* cUnit, int reg)
+{
+ int numRegs = cUnit->regPool->numCoreRegs;
+ RegisterInfo* p = cUnit->regPool->coreRegs;
+ int i;
+ for (i=0; i< numRegs; i++) {
+ if (p[i].reg == reg) {
+ return &p[i];
+ }
+ }
+ p = cUnit->regPool->FPRegs;
+ numRegs = cUnit->regPool->numFPRegs;
+ for (i=0; i< numRegs; i++) {
+ if (p[i].reg == reg) {
+ return &p[i];
+ }
+ }
+ LOG(FATAL) << "Tried to get info on a non-existant reg :r" << reg;
+ return NULL; // Quiet gcc
+}
+
+void oatFlushRegWide(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)) {
+ if (!(info1->isTemp && info2->isTemp)) {
+ /* Should not happen. If it does, there's a problem in evalLoc */
+ LOG(FATAL) << "Long half-temp, half-promoted";
+ }
+
+ info1->dirty = false;
+ info2->dirty = false;
+ if (oatS2VReg(cUnit, info2->sReg) <
+ oatS2VReg(cUnit, info1->sReg))
+ info1 = info2;
+ int vReg = oatS2VReg(cUnit, info1->sReg);
+ oatFlushRegWideImpl(cUnit, rSP,
+ oatVRegOffset(cUnit, vReg),
+ info1->reg, info1->partner);
+ }
+}
+
+void oatFlushReg(CompilationUnit* cUnit, int reg)
+{
+ RegisterInfo* info = getRegInfo(cUnit, reg);
+ if (info->live && info->dirty) {
+ info->dirty = false;
+ int vReg = oatS2VReg(cUnit, info->sReg);
+ oatFlushRegImpl(cUnit, rSP,
+ oatVRegOffset(cUnit, vReg),
+ reg, kWord);
+ }
+}
+
+/* return true if found reg to clobber */
+static bool clobberRegBody(CompilationUnit* cUnit, RegisterInfo* p,
+ int numRegs, int reg)
+{
+ int i;
+ for (i=0; i< numRegs; i++) {
+ if (p[i].reg == reg) {
+ if (p[i].isTemp) {
+ if (p[i].isTemp && p[i].live && p[i].dirty) {
+ if (p[i].pair) {
+ oatFlushRegWide(cUnit, p[i].reg, p[i].partner);
+ } else {
+ oatFlushReg(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;
+ /* partners should be in same pool */
+ clobberRegBody(cUnit, p, numRegs, p[i].partner);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Mark a temp register as dead. Does not affect allocation state. */
+void oatClobber(CompilationUnit* cUnit, int reg)
+{
+ if (!clobberRegBody(cUnit, cUnit->regPool->coreRegs,
+ cUnit->regPool->numCoreRegs, reg)) {
+ clobberRegBody(cUnit, cUnit->regPool->FPRegs,
+ cUnit->regPool->numFPRegs, reg);
+ }
+}
+
+static void clobberSRegBody(RegisterInfo* p, int numRegs, int sReg)
+{
+ int i;
+ for (i=0; i< numRegs; i++) {
+ if (p[i].sReg == sReg) {
+ if (p[i].isTemp) {
+ p[i].live = false;
+ }
+ p[i].defStart = NULL;
+ p[i].defEnd = NULL;
+ }
+ }
+}
+
+/* Clobber any temp associated with an sReg. Could be in either class */
+extern void oatClobberSReg(CompilationUnit* cUnit, int sReg)
+{
+ clobberSRegBody(cUnit->regPool->coreRegs, cUnit->regPool->numCoreRegs,
+ sReg);
+ clobberSRegBody(cUnit->regPool->FPRegs, cUnit->regPool->numFPRegs,
+ sReg);
+}
+
+/* Reserve a callee-save register. Return -1 if none available */
+extern int oatAllocPreservedCoreReg(CompilationUnit* cUnit, int sReg)
+{
+ int res = -1;
+ RegisterInfo* coreRegs = cUnit->regPool->coreRegs;
+ for (int i = 0; i < cUnit->regPool->numCoreRegs; i++) {
+ if (!coreRegs[i].isTemp && !coreRegs[i].inUse) {
+ res = coreRegs[i].reg;
+ coreRegs[i].inUse = true;
+ cUnit->coreSpillMask |= (1 << res);
+ cUnit->numSpills++;
+ cUnit->regLocation[sReg].location = kLocPhysReg;
+ cUnit->regLocation[sReg].lowReg = res;
+ cUnit->regLocation[sReg].home = true;
+ break;
+ }
+ }
+ return res;
+}
+
+/*
+ * Reserve a callee-save fp single register. Try to fullfill request for
+ * even/odd allocation, but go ahead and allocate anything if not
+ * available. If nothing's available, return -1.
+ */
+static int allocPreservedSingle(CompilationUnit* cUnit, int sReg, bool even)
+{
+ int res = -1;
+ RegisterInfo* FPRegs = cUnit->regPool->FPRegs;
+ for (int i = 0; i < cUnit->regPool->numFPRegs; i++) {
+ if (!FPRegs[i].isTemp && !FPRegs[i].inUse &&
+ ((FPRegs[i].reg & 0x1) == 0) == even) {
+ res = FPRegs[i].reg;
+ FPRegs[i].inUse = true;
+ cUnit->fpSpillMask |= (1 << (res & FP_REG_MASK));
+ cUnit->numSpills++;
+ cUnit->numFPSpills++;
+ cUnit->regLocation[sReg].fpLocation = kLocPhysReg;
+ cUnit->regLocation[sReg].fpLowReg = res;
+ cUnit->regLocation[sReg].home = true;
+ break;
+ }
+ }
+ return res;
+}
+
+/*
+ * Somewhat messy code here. We want to allocate a pair of contiguous
+ * physical single-precision floating point registers starting with
+ * an even numbered reg. It is possible that the paired sReg (sReg+1)
+ * has already been allocated - try to fit if possible. Fail to
+ * allocate if we can't meet the requirements for the pair of
+ * sReg<=sX[even] & (sReg+1)<= sX+1.
+ */
+static int allocPreservedDouble(CompilationUnit* cUnit, int sReg)
+{
+ int res = -1; // Assume failure
+ if (cUnit->regLocation[sReg+1].fpLocation == kLocPhysReg) {
+ // Upper reg is already allocated. Can we fit?
+ int highReg = cUnit->regLocation[sReg+1].fpLowReg;
+ if ((highReg & 1) == 0) {
+ // High reg is even - fail.
+ return res;
+ }
+ // Is the low reg of the pair free?
+ RegisterInfo* p = getRegInfo(cUnit, highReg-1);
+ if (p->inUse || p->isTemp) {
+ // Already allocated or not preserved - fail.
+ return res;
+ }
+ // OK - good to go.
+ res = p->reg;
+ p->inUse = true;
+ assert((res & 1) == 0);
+ cUnit->fpSpillMask |= (1 << (res & FP_REG_MASK));
+ cUnit->numSpills++;
+ cUnit->numFPSpills ++;
+ } else {
+ RegisterInfo* FPRegs = cUnit->regPool->FPRegs;
+ for (int i = 0; i < cUnit->regPool->numFPRegs; i++) {
+ if (!FPRegs[i].isTemp && !FPRegs[i].inUse &&
+ ((FPRegs[i].reg & 0x1) == 0x0) &&
+ !FPRegs[i+1].isTemp && !FPRegs[i+1].inUse &&
+ ((FPRegs[i+1].reg & 0x1) == 0x1) &&
+ (FPRegs[i].reg + 1) == FPRegs[i+1].reg) {
+ res = FPRegs[i].reg;
+ FPRegs[i].inUse = true;
+ cUnit->fpSpillMask |= (1 << (res & FP_REG_MASK));
+ FPRegs[i+1].inUse = true;
+ cUnit->fpSpillMask |= (1 << ((res+1) & FP_REG_MASK));
+ cUnit->numSpills += 2;
+ cUnit->numFPSpills += 2;
+ break;
+ }
+ }
+ }
+ if (res != -1) {
+ cUnit->regLocation[sReg].fpLocation = kLocPhysReg;
+ cUnit->regLocation[sReg].fpLowReg = res;
+ cUnit->regLocation[sReg].home = true;
+ cUnit->regLocation[sReg+1].fpLocation = kLocPhysReg;
+ cUnit->regLocation[sReg+1].fpLowReg = res + 1;
+ cUnit->regLocation[sReg+1].home = true;
+ }
+ return res;
+}
+
+
+/*
+ * Reserve a callee-save fp register. If this register can be used
+ * as the first of a double, attempt to allocate an even pair of fp
+ * single regs (but if can't still attempt to allocate a single, preferring
+ * first to allocate an odd register.
+ */
+extern int oatAllocPreservedFPReg(CompilationUnit* cUnit, int sReg,
+ bool doubleStart)
+{
+ int res = -1;
+ if (doubleStart) {
+ res = allocPreservedDouble(cUnit, sReg);
+ } else {
+ }
+ if (res == -1) {
+ res = allocPreservedSingle(cUnit, sReg, false /* try odd # */);
+ }
+ if (res == -1)
+ res = allocPreservedSingle(cUnit, sReg, true /* try even # */);
+ return res;
+}
+
+static int allocTempBody(CompilationUnit* cUnit, RegisterInfo* p, int numRegs,
+ int* nextTemp, bool required)
+{
+ int i;
+ int next = *nextTemp;
+ for (i=0; i< numRegs; i++) {
+ if (next >= numRegs)
+ next = 0;
+ if (p[next].isTemp && !p[next].inUse && !p[next].live) {
+ oatClobber(cUnit, p[next].reg);
+ p[next].inUse = true;
+ p[next].pair = false;
+ *nextTemp = next + 1;
+ return p[next].reg;
+ }
+ next++;
+ }
+ next = *nextTemp;
+ for (i=0; i< numRegs; i++) {
+ if (next >= numRegs)
+ next = 0;
+ if (p[next].isTemp && !p[next].inUse) {
+ oatClobber(cUnit, p[next].reg);
+ p[next].inUse = true;
+ p[next].pair = false;
+ *nextTemp = next + 1;
+ return p[next].reg;
+ }
+ next++;
+ }
+ if (required) {
+ dumpRegPool(cUnit->regPool->coreRegs,
+ cUnit->regPool->numCoreRegs);
+ LOG(FATAL) << "No free temp registers";
+ }
+ return -1; // No register available
+}
+
+//REDO: too many assumptions.
+extern int oatAllocTempDouble(CompilationUnit* cUnit)
+{
+ RegisterInfo* p = cUnit->regPool->FPRegs;
+ int numRegs = cUnit->regPool->numFPRegs;
+ int next = cUnit->regPool->nextFPReg;
+ int i;
+
+ for (i=0; i < numRegs; i+=2) {
+ /* Cleanup - not all targets need aligned regs */
+ if (next & 1)
+ next++;
+ if (next >= numRegs)
+ next = 0;
+ if ((p[next].isTemp && !p[next].inUse && !p[next].live) &&
+ (p[next+1].isTemp && !p[next+1].inUse && !p[next+1].live)) {
+ oatClobber(cUnit, p[next].reg);
+ oatClobber(cUnit, p[next+1].reg);
+ p[next].inUse = true;
+ p[next+1].inUse = true;
+ assert((p[next].reg+1) == p[next+1].reg);
+ assert((p[next].reg & 0x1) == 0);
+ cUnit->regPool->nextFPReg += 2;
+ return p[next].reg;
+ }
+ next += 2;
+ }
+ next = cUnit->regPool->nextFPReg;
+ for (i=0; i < numRegs; i+=2) {
+ if (next >= numRegs)
+ next = 0;
+ if (p[next].isTemp && !p[next].inUse && p[next+1].isTemp &&
+ !p[next+1].inUse) {
+ oatClobber(cUnit, p[next].reg);
+ oatClobber(cUnit, p[next+1].reg);
+ p[next].inUse = true;
+ p[next+1].inUse = true;
+ assert((p[next].reg+1) == p[next+1].reg);
+ assert((p[next].reg & 0x1) == 0);
+ cUnit->regPool->nextFPReg += 2;
+ return p[next].reg;
+ }
+ next += 2;
+ }
+ LOG(FATAL) << "No free temp registers";
+ return -1;
+}
+
+/* Return a temp if one is available, -1 otherwise */
+extern int oatAllocFreeTemp(CompilationUnit* cUnit)
+{
+ return allocTempBody(cUnit, cUnit->regPool->coreRegs,
+ cUnit->regPool->numCoreRegs,
+ &cUnit->regPool->nextCoreReg, true);
+}
+
+extern int oatAllocTemp(CompilationUnit* cUnit)
+{
+ return allocTempBody(cUnit, cUnit->regPool->coreRegs,
+ cUnit->regPool->numCoreRegs,
+ &cUnit->regPool->nextCoreReg, true);
+}
+
+extern int oatAllocTempFloat(CompilationUnit* cUnit)
+{
+ return allocTempBody(cUnit, cUnit->regPool->FPRegs,
+ cUnit->regPool->numFPRegs,
+ &cUnit->regPool->nextFPReg, true);
+}
+
+static RegisterInfo* allocLiveBody(RegisterInfo* p, int numRegs, int sReg)
+{
+ int i;
+ if (sReg == -1)
+ return NULL;
+ for (i=0; i < numRegs; i++) {
+ if (p[i].live && (p[i].sReg == sReg)) {
+ if (p[i].isTemp)
+ 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->FPRegs,
+ cUnit->regPool->numFPRegs, sReg);
+ if (res)
+ break;
+ /* Intentional fallthrough */
+ case kCoreReg:
+ res = allocLiveBody(cUnit->regPool->coreRegs,
+ cUnit->regPool->numCoreRegs, sReg);
+ break;
+ case kFPReg:
+ res = allocLiveBody(cUnit->regPool->FPRegs,
+ cUnit->regPool->numFPRegs, sReg);
+ break;
+ default:
+ LOG(FATAL) << "Invalid register type";
+ }
+ return res;
+}
+
+extern void oatFreeTemp(CompilationUnit* cUnit, int reg)
+{
+ RegisterInfo* p = cUnit->regPool->coreRegs;
+ int numRegs = cUnit->regPool->numCoreRegs;
+ int i;
+ for (i=0; i< numRegs; i++) {
+ if (p[i].reg == reg) {
+ if (p[i].isTemp) {
+ p[i].inUse = false;
+ }
+ p[i].pair = false;
+ return;
+ }
+ }
+ p = cUnit->regPool->FPRegs;
+ numRegs = cUnit->regPool->numFPRegs;
+ for (i=0; i< numRegs; i++) {
+ if (p[i].reg == reg) {
+ if (p[i].isTemp) {
+ p[i].inUse = false;
+ }
+ p[i].pair = false;
+ return;
+ }
+ }
+ LOG(FATAL) << "Tried to free a non-existant temp: r" << reg;
+}
+
+extern RegisterInfo* oatIsLive(CompilationUnit* cUnit, int reg)
+{
+ RegisterInfo* p = cUnit->regPool->coreRegs;
+ int numRegs = cUnit->regPool->numCoreRegs;
+ int i;
+ for (i=0; i< numRegs; i++) {
+ if (p[i].reg == reg) {
+ return p[i].live ? &p[i] : NULL;
+ }
+ }
+ p = cUnit->regPool->FPRegs;
+ numRegs = cUnit->regPool->numFPRegs;
+ for (i=0; i< numRegs; i++) {
+ if (p[i].reg == reg) {
+ return p[i].live ? &p[i] : NULL;
+ }
+ }
+ return NULL;
+}
+
+extern RegisterInfo* oatIsTemp(CompilationUnit* cUnit, int reg)
+{
+ RegisterInfo* p = getRegInfo(cUnit, reg);
+ return (p->isTemp) ? p : NULL;
+}
+
+extern bool oatIsDirty(CompilationUnit* cUnit, int reg)
+{
+ RegisterInfo* p = getRegInfo(cUnit, reg);
+ return p->dirty;
+}
+
+/*
+ * Similar to oatAllocTemp(), but forces the allocation of a specific
+ * register. No check is made to see if the register was previously
+ * allocated. Use with caution.
+ */
+extern void oatLockTemp(CompilationUnit* cUnit, int reg)
+{
+ RegisterInfo* p = cUnit->regPool->coreRegs;
+ int numRegs = cUnit->regPool->numCoreRegs;
+ int i;
+ for (i=0; i< numRegs; i++) {
+ if (p[i].reg == reg) {
+ assert(p[i].isTemp);
+ p[i].inUse = true;
+ p[i].live = false;
+ return;
+ }
+ }
+ p = cUnit->regPool->FPRegs;
+ numRegs = cUnit->regPool->numFPRegs;
+ for (i=0; i< numRegs; i++) {
+ if (p[i].reg == reg) {
+ assert(p[i].isTemp);
+ p[i].inUse = true;
+ p[i].live = false;
+ return;
+ }
+ }
+ LOG(FATAL) << "Tried to lock a non-existant temp: r" << reg;
+}
+
+extern void oatResetDef(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)->flags.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.
+ */
+extern void oatMarkDef(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.
+ */
+extern void oatMarkDefWide(CompilationUnit* cUnit, RegLocation rl,
+ LIR *start, LIR *finish)
+{
+ assert(rl.wide);
+ assert(start && start->next);
+ assert(finish);
+ RegisterInfo* p = getRegInfo(cUnit, rl.lowReg);
+ oatResetDef(cUnit, rl.highReg); // Only track low of pair
+ p->defStart = start->next;
+ p->defEnd = finish;
+}
+
+extern RegLocation oatWideToNarrow(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->coreRegs,
+ cUnit->regPool->numCoreRegs);
+ assert(infoLo->pair);
+ }
+ if (!infoHi->pair) {
+ dumpRegPool(cUnit->regPool->coreRegs,
+ cUnit->regPool->numCoreRegs);
+ 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;
+}
+
+extern void oatResetDefLoc(CompilationUnit* cUnit, RegLocation rl)
+{
+ assert(!rl.wide);
+ if (!(cUnit->disableOpt & (1 << kSuppressLoads))) {
+ RegisterInfo* p = getRegInfo(cUnit, rl.lowReg);
+ assert(!p->pair);
+ nullifyRange(cUnit, p->defStart, p->defEnd,
+ p->sReg, rl.sRegLow);
+ }
+ oatResetDef(cUnit, rl.lowReg);
+}
+
+extern void oatResetDefLocWide(CompilationUnit* cUnit, RegLocation rl)
+{
+ assert(rl.wide);
+ if (!(cUnit->disableOpt & (1 << kSuppressLoads))) {
+ RegisterInfo* p = getRegInfo(cUnit, rl.lowReg);
+ assert(p->pair);
+ nullifyRange(cUnit, p->defStart, p->defEnd,
+ p->sReg, rl.sRegLow);
+ }
+ oatResetDef(cUnit, rl.lowReg);
+ oatResetDef(cUnit, rl.highReg);
+}
+
+extern void oatResetDefTracking(CompilationUnit* cUnit)
+{
+ int i;
+ for (i=0; i< cUnit->regPool->numCoreRegs; i++) {
+ oatResetDef(cUnit, cUnit->regPool->coreRegs[i].reg);
+ }
+ for (i=0; i< cUnit->regPool->numFPRegs; i++) {
+ oatResetDef(cUnit, cUnit->regPool->FPRegs[i].reg);
+ }
+}
+
+extern void oatClobberAllRegs(CompilationUnit* cUnit)
+{
+ int i;
+ for (i=0; i< cUnit->regPool->numCoreRegs; i++) {
+ oatClobber(cUnit, cUnit->regPool->coreRegs[i].reg);
+ }
+ for (i=0; i< cUnit->regPool->numFPRegs; i++) {
+ oatClobber(cUnit, cUnit->regPool->FPRegs[i].reg);
+ }
+}
+
+/* To be used when explicitly managing register use */
+extern void oatLockAllTemps(CompilationUnit* cUnit)
+{
+ int i;
+ for (i=0; i< cUnit->regPool->numCoreRegs; i++) {
+ oatLockTemp(cUnit, cUnit->regPool->coreRegs[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) {
+ oatFlushRegWide(cUnit, info[i].reg, info[i].partner);
+ } else {
+ oatFlushReg(cUnit, info[i].reg);
+ }
+ }
+ }
+}
+
+extern void oatFlushAllRegs(CompilationUnit* cUnit)
+{
+ flushAllRegsBody(cUnit, cUnit->regPool->coreRegs,
+ cUnit->regPool->numCoreRegs);
+ flushAllRegsBody(cUnit, cUnit->regPool->FPRegs,
+ cUnit->regPool->numFPRegs);
+ oatClobberAllRegs(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);
+ }
+}
+
+extern void oatMarkLive(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) {
+ oatClobberSReg(cUnit, sReg);
+ if (info->isTemp) {
+ info->live = true;
+ }
+ } else {
+ /* Can't be live if no associated sReg */
+ assert(info->isTemp);
+ info->live = false;
+ }
+ info->sReg = sReg;
+}
+
+extern void oatMarkTemp(CompilationUnit* cUnit, int reg)
+{
+ RegisterInfo* info = getRegInfo(cUnit, reg);
+ info->isTemp = true;
+}
+
+extern void oatMarkPair(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;
+}
+
+extern void oatMarkClean(CompilationUnit* cUnit, RegLocation loc)
+{
+ RegisterInfo* info = getRegInfo(cUnit, loc.lowReg);
+ info->dirty = false;
+ if (loc.wide) {
+ info = getRegInfo(cUnit, loc.highReg);
+ info->dirty = false;
+ }
+}
+
+extern void oatMarkDirty(CompilationUnit* cUnit, RegLocation loc)
+{
+ if (loc.home) {
+ // If already home, can't be dirty
+ return;
+ }
+ RegisterInfo* info = getRegInfo(cUnit, loc.lowReg);
+ info->dirty = true;
+ if (loc.wide) {
+ info = getRegInfo(cUnit, loc.highReg);
+ info->dirty = true;
+ }
+}
+
+extern void oatMarkInUse(CompilationUnit* cUnit, int reg)
+{
+ RegisterInfo* info = getRegInfo(cUnit, reg);
+ info->inUse = true;
+}
+
+static 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.
+ */
+
+extern RegLocation oatUpdateLoc(CompilationUnit* cUnit, RegLocation loc)
+{
+ assert(!loc.wide);
+ if (loc.location == kLocDalvikFrame) {
+ RegisterInfo* infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
+ if (infoLo) {
+ if (infoLo->pair) {
+ oatClobber(cUnit, infoLo->reg);
+ oatClobber(cUnit, infoLo->partner);
+ } else {
+ loc.lowReg = infoLo->reg;
+ loc.location = kLocPhysReg;
+ }
+ }
+ }
+
+ return loc;
+}
+
+/* see comments for updateLoc */
+extern RegLocation oatUpdateLocWide(CompilationUnit* cUnit,
+ RegLocation loc)
+{
+ assert(loc.wide);
+ if (loc.location == kLocDalvikFrame) {
+ // Are the dalvik regs already live in physical registers?
+ RegisterInfo* infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
+ RegisterInfo* infoHi = allocLive(cUnit,
+ oatSRegHi(loc.sRegLow), kAnyReg);
+ bool match = true;
+ match = match && (infoLo != NULL);
+ match = match && (infoHi != NULL);
+ // Are they both core or both FP?
+ match = match && (FPREG(infoLo->reg) == FPREG(infoHi->reg));
+ // If a pair of floating point singles, are they properly aligned?
+ if (match && FPREG(infoLo->reg)) {
+ match &= ((infoLo->reg & 0x1) == 0);
+ match &= ((infoHi->reg - infoLo->reg) == 1);
+ }
+ // If previously used as a pair, it is the same pair?
+ if (match && (infoLo->pair || infoHi->pair)) {
+ match = (infoLo->pair == infoHi->pair);
+ match &= ((infoLo->reg == infoHi->partner) &&
+ (infoHi->reg == infoLo->partner));
+ }
+ if (match) {
+ // Can reuse - update the register usage info
+ loc.lowReg = infoLo->reg;
+ loc.highReg = infoHi->reg;
+ loc.location = kLocPhysReg;
+ oatMarkPair(cUnit, loc.lowReg, loc.highReg);
+ assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+ return loc;
+ }
+ // Can't easily reuse - clobber any overlaps
+ if (infoLo) {
+ oatClobber(cUnit, infoLo->reg);
+ if (infoLo->pair)
+ oatClobber(cUnit, infoLo->partner);
+ }
+ if (infoHi) {
+ oatClobber(cUnit, infoHi->reg);
+ if (infoHi->pair)
+ oatClobber(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 = oatUpdateLocWide(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 = oatAllocTypedTempPair(cUnit, loc.fp, regClass);
+ lowReg = newRegs & 0xff;
+ highReg = (newRegs >> 8) & 0xff;
+ oatRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
+ loc.highReg);
+ copyRegInfo(cUnit, lowReg, loc.lowReg);
+ copyRegInfo(cUnit, highReg, loc.highReg);
+ oatClobber(cUnit, loc.lowReg);
+ oatClobber(cUnit, loc.highReg);
+ loc.lowReg = lowReg;
+ loc.highReg = highReg;
+ oatMarkPair(cUnit, loc.lowReg, loc.highReg);
+ assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+ }
+ return loc;
+ }
+
+ assert(loc.sRegLow != INVALID_SREG);
+ assert(oatSRegHi(loc.sRegLow) != INVALID_SREG);
+
+ newRegs = oatAllocTypedTempPair(cUnit, loc.fp, regClass);
+ loc.lowReg = newRegs & 0xff;
+ loc.highReg = (newRegs >> 8) & 0xff;
+
+ oatMarkPair(cUnit, loc.lowReg, loc.highReg);
+ if (update) {
+ loc.location = kLocPhysReg;
+ oatMarkLive(cUnit, loc.lowReg, loc.sRegLow);
+ oatMarkLive(cUnit, loc.highReg, oatSRegHi(loc.sRegLow));
+ }
+ assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
+ return loc;
+}
+
+extern RegLocation oatEvalLoc(CompilationUnit* cUnit, RegLocation loc,
+ int regClass, bool update)
+{
+ int newReg;
+
+ if (loc.wide)
+ return evalLocWide(cUnit, loc, regClass, update);
+
+ loc = oatUpdateLoc(cUnit, loc);
+
+ if (loc.location == kLocPhysReg) {
+ if (!regClassMatches(regClass, loc.lowReg)) {
+ /* Wrong register class. Realloc, copy and transfer ownership */
+ newReg = oatAllocTypedTemp(cUnit, loc.fp, regClass);
+ oatRegCopy(cUnit, newReg, loc.lowReg);
+ copyRegInfo(cUnit, newReg, loc.lowReg);
+ oatClobber(cUnit, loc.lowReg);
+ loc.lowReg = newReg;
+ }
+ return loc;
+ }
+
+ assert(loc.sRegLow != INVALID_SREG);
+
+ newReg = oatAllocTypedTemp(cUnit, loc.fp, regClass);
+ loc.lowReg = newReg;
+
+ if (update) {
+ loc.location = kLocPhysReg;
+ oatMarkLive(cUnit, loc.lowReg, loc.sRegLow);
+ }
+ return loc;
+}
+
+extern RegLocation oatGetDest(CompilationUnit* cUnit, MIR* mir, int num)
+{
+ return cUnit->regLocation[mir->ssaRep->defs[num]];
+}
+extern RegLocation oatGetSrc(CompilationUnit* cUnit, MIR* mir, int num)
+{
+ return cUnit->regLocation[mir->ssaRep->uses[num]];
+}
+extern RegLocation oatGetDestWide(CompilationUnit* cUnit, MIR* mir,
+ int low, int high)
+{
+ return oatGetDest(cUnit, mir, low);
+}
+
+extern RegLocation oatGetSrcWide(CompilationUnit* cUnit, MIR* mir,
+ int low, int high)
+{
+ return oatGetSrc(cUnit, mir, low);
+}
+
+/* Kill the corresponding bit in the null-checked register list */
+extern void oatKillNullCheckedLoc(CompilationUnit* cUnit,
+ RegLocation loc)
+{
+ if (loc.sRegLow == INVALID_SREG)
+ return;
+ oatClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
+ if (loc.wide) {
+ assert(oatSRegHi(loc.sRegLow) != INVALID_SREG);
+ oatClearBit(cUnit->regPool->nullCheckedRegs,
+ oatSRegHi(loc.sRegLow));
+ }
+}