/*
* 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 "compiler/CompilerUtility.h"
#include "compiler/CompilerIR.h"
#include "compiler/Dataflow.h"
#include "ArmLIR.h"
#include "Codegen.h"
#include "Ralloc.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
*
*/
#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 dvmCompilerResetRegPool(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 */
extern void dvmCompilerInitPool(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 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);
dvmCompilerAbort(cUnit);
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 (dvmCompilerS2VReg(cUnit, info2->sReg) <
dvmCompilerS2VReg(cUnit, info1->sReg))
info1 = info2;
dvmCompilerFlushRegWideImpl(cUnit, rFP,
dvmCompilerS2VReg(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;
dvmCompilerFlushRegImpl(cUnit, rFP,
dvmCompilerS2VReg(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;
/* partners should be in same pool */
clobberRegBody(cUnit, p, numTemps, p[i].partner);
}
return true;
}
}
return false;
}
/* Mark a temp register as dead. Does not affect allocation state. */
void dvmCompilerClobber(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 */
extern void dvmCompilerClobberSReg(CompilationUnit *cUnit, int sReg)
{
clobberSRegBody(cUnit->regPool->coreTemps, cUnit->regPool->numCoreTemps,
sReg);
clobberSRegBody(cUnit->regPool->FPTemps, cUnit->regPool->numFPTemps,
sReg);
}
static int allocTempBody(CompilationUnit *cUnit, RegisterInfo *p, int numTemps,
int *nextTemp, bool required)
{
int i;
int next = *nextTemp;
for (i=0; i< numTemps; i++) {
if (next >= numTemps)
next = 0;
if (!p[next].inUse && !p[next].live) {
dvmCompilerClobber(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< numTemps; i++) {
if (next >= numTemps)
next = 0;
if (!p[next].inUse) {
dvmCompilerClobber(cUnit, p[next].reg);
p[next].inUse = true;
p[next].pair = false;
*nextTemp = next + 1;
return p[next].reg;
}
next++;
}
if (required) {
LOGE("No free temp registers");
dvmCompilerAbort(cUnit);
}
return -1; // No register available
}
//REDO: too many assumptions.
extern int dvmCompilerAllocTempDouble(CompilationUnit *cUnit)
{
RegisterInfo *p = cUnit->regPool->FPTemps;
int numTemps = cUnit->regPool->numFPTemps;
int next = cUnit->regPool->nextFPTemp;
int i;
for (i=0; i < numTemps; i+=2) {
/* Cleanup - not all targets need aligned regs */
if (next & 1)
next++;
if (next >= numTemps)
next = 0;
if ((!p[next].inUse && !p[next].live) &&
(!p[next+1].inUse && !p[next+1].live)) {
dvmCompilerClobber(cUnit, p[next].reg);
dvmCompilerClobber(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->nextFPTemp += 2;
return p[next].reg;
}
next += 2;
}
next = cUnit->regPool->nextFPTemp;
for (i=0; i < numTemps; i+=2) {
if (next >= numTemps)
next = 0;
if (!p[next].inUse && !p[next+1].inUse) {
dvmCompilerClobber(cUnit, p[next].reg);
dvmCompilerClobber(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->nextFPTemp += 2;
return p[next].reg;
}
next += 2;
}
LOGE("No free temp registers");
dvmCompilerAbort(cUnit);
return -1;
}
/* Return a temp if one is available, -1 otherwise */
extern int dvmCompilerAllocFreeTemp(CompilationUnit *cUnit)
{
return allocTempBody(cUnit, cUnit->regPool->coreTemps,
cUnit->regPool->numCoreTemps,
&cUnit->regPool->nextCoreTemp, true);
}
extern int dvmCompilerAllocTemp(CompilationUnit *cUnit)
{
return allocTempBody(cUnit, cUnit->regPool->coreTemps,
cUnit->regPool->numCoreTemps,
&cUnit->regPool->nextCoreTemp, true);
}
extern int dvmCompilerAllocTempFloat(CompilationUnit *cUnit)
{
return allocTempBody(cUnit, cUnit->regPool->FPTemps,
cUnit->regPool->numFPTemps,
&cUnit->regPool->nextFPTemp, 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");
dvmCompilerAbort(cUnit);
}
return res;
}
extern void dvmCompilerFreeTemp(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);
dvmCompilerAbort(cUnit);
}
/*
* FIXME - this needs to also check the preserved pool once we start
* start using preserved registers.
*/
extern RegisterInfo *dvmCompilerIsLive(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;
}
extern RegisterInfo *dvmCompilerIsTemp(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;
}
/*
* Similar to dvmCompilerAllocTemp(), 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 dvmCompilerLockTemp(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);
dvmCompilerAbort(cUnit);
}
/* Clobber all regs that might be used by an external C call */
extern void dvmCompilerClobberCallRegs(CompilationUnit *cUnit)
{
dvmCompilerClobber(cUnit, r0);
dvmCompilerClobber(cUnit, r1);
dvmCompilerClobber(cUnit, r2);
dvmCompilerClobber(cUnit, r3);
dvmCompilerClobber(cUnit, r9); // Need to do this?, be conservative
dvmCompilerClobber(cUnit, r11);
dvmCompilerClobber(cUnit, r12);
dvmCompilerClobber(cUnit, rlr);
}
/* Clobber all of the temps that might be used by a handler. */
extern void dvmCompilerClobberHandlerRegs(CompilationUnit *cUnit)
{
//TUNING: reduce the set of regs used by handlers. Only a few need lots.
dvmCompilerClobberCallRegs(cUnit);
dvmCompilerClobber(cUnit, r4PC);
dvmCompilerClobber(cUnit, r7);
dvmCompilerClobber(cUnit, r8);
dvmCompilerClobber(cUnit, r9);
dvmCompilerClobber(cUnit, r10);
}
extern void dvmCompilerResetDef(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.
*/
extern void dvmCompilerMarkDef(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 dvmCompilerMarkDefWide(CompilationUnit *cUnit, RegLocation rl,
LIR *start, LIR *finish)
{
assert(rl.wide);
assert(start && start->next);
assert(finish);
RegisterInfo *p = getRegInfo(cUnit, rl.lowReg);
dvmCompilerResetDef(cUnit, rl.highReg); // Only track low of pair
p->defStart = start->next;
p->defEnd = finish;
}
extern RegLocation dvmCompilerWideToNarrow(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;
}
extern void dvmCompilerResetDefLoc(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);
}
dvmCompilerResetDef(cUnit, rl.lowReg);
}
extern void dvmCompilerResetDefLocWide(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);
}
dvmCompilerResetDef(cUnit, rl.lowReg);
dvmCompilerResetDef(cUnit, rl.highReg);
}
extern void dvmCompilerResetDefTracking(CompilationUnit *cUnit)
{
int i;
for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
dvmCompilerResetDef(cUnit, cUnit->regPool->coreTemps[i].reg);
}
for (i=0; i< cUnit->regPool->numFPTemps; i++) {
dvmCompilerResetDef(cUnit, cUnit->regPool->FPTemps[i].reg);
}
}
extern void dvmCompilerClobberAllRegs(CompilationUnit *cUnit)
{
int i;
for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
dvmCompilerClobber(cUnit, cUnit->regPool->coreTemps[i].reg);
}
for (i=0; i< cUnit->regPool->numFPTemps; i++) {
dvmCompilerClobber(cUnit, cUnit->regPool->FPTemps[i].reg);
}
}
/* To be used when explicitly managing register use */
extern void dvmCompilerLockAllTemps(CompilationUnit *cUnit)
{
int i;
for (i=0; i< cUnit->regPool->numCoreTemps; i++) {
dvmCompilerLockTemp(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);
}
}
}
}
extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit)
{
flushAllRegsBody(cUnit, cUnit->regPool->coreTemps,
cUnit->regPool->numCoreTemps);
flushAllRegsBody(cUnit, cUnit->regPool->FPTemps,
cUnit->regPool->numFPTemps);
dvmCompilerClobberAllRegs(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 dvmCompilerMarkLive(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) {
dvmCompilerClobberSReg(cUnit, sReg);
info->live = true;
} else {
/* Can't be live if no associated sReg */
info->live = false;
}
info->sReg = sReg;
}
extern void dvmCompilerMarkPair(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 dvmCompilerMarkClean(CompilationUnit *cUnit, int reg)
{
RegisterInfo *info = getRegInfo(cUnit, reg);
info->dirty = false;
}
extern void dvmCompilerMarkDirty(CompilationUnit *cUnit, int reg)
{
RegisterInfo *info = getRegInfo(cUnit, reg);
info->dirty = true;
}
extern void dvmCompilerMarkInUse(CompilationUnit *cUnit, int reg)
{
RegisterInfo *info = getRegInfo(cUnit, reg);
info->inUse = true;
}
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 dvmCompilerUpdateLoc(CompilationUnit *cUnit, RegLocation loc)
{
assert(!loc.wide);
if (loc.location == kLocDalvikFrame) {
RegisterInfo *infoLo = allocLive(cUnit, loc.sRegLow, kAnyReg);
if (infoLo) {
if (infoLo->pair) {
dvmCompilerClobber(cUnit, infoLo->reg);
dvmCompilerClobber(cUnit, infoLo->partner);
} else {
loc.lowReg = infoLo->reg;
loc.location = kLocPhysReg;
}
}
}
return loc;
}
/* see comments for updateLoc */
extern RegLocation dvmCompilerUpdateLocWide(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,
dvmCompilerSRegHi(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;
dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
return loc;
}
// Can't easily reuse - clobber any overlaps
if (infoLo) {
dvmCompilerClobber(cUnit, infoLo->reg);
if (infoLo->pair)
dvmCompilerClobber(cUnit, infoLo->partner);
}
if (infoHi) {
dvmCompilerClobber(cUnit, infoHi->reg);
if (infoHi->pair)
dvmCompilerClobber(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 = dvmCompilerUpdateLocWide(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 = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
lowReg = newRegs & 0xff;
highReg = (newRegs >> 8) & 0xff;
dvmCompilerRegCopyWide(cUnit, lowReg, highReg, loc.lowReg,
loc.highReg);
copyRegInfo(cUnit, lowReg, loc.lowReg);
copyRegInfo(cUnit, highReg, loc.highReg);
dvmCompilerClobber(cUnit, loc.lowReg);
dvmCompilerClobber(cUnit, loc.highReg);
loc.lowReg = lowReg;
loc.highReg = highReg;
dvmCompilerMarkPair(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) ||
(dvmCompilerSRegHi(loc.sRegLow) == INVALID_SREG));
newRegs = dvmCompilerAllocTypedTempPair(cUnit, loc.fp, regClass);
loc.lowReg = newRegs & 0xff;
loc.highReg = (newRegs >> 8) & 0xff;
dvmCompilerMarkPair(cUnit, loc.lowReg, loc.highReg);
if (update) {
loc.location = kLocPhysReg;
dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow);
dvmCompilerMarkLive(cUnit, loc.highReg, dvmCompilerSRegHi(loc.sRegLow));
}
assert(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
return loc;
}
extern RegLocation dvmCompilerEvalLoc(CompilationUnit *cUnit, RegLocation loc,
int regClass, bool update)
{
int newReg;
if (loc.wide)
return evalLocWide(cUnit, loc, regClass, update);
loc = dvmCompilerUpdateLoc(cUnit, loc);
if (loc.location == kLocPhysReg) {
if (!regClassMatches(regClass, loc.lowReg)) {
/* Wrong register class. Realloc, copy and transfer ownership */
newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
dvmCompilerRegCopy(cUnit, newReg, loc.lowReg);
copyRegInfo(cUnit, newReg, loc.lowReg);
dvmCompilerClobber(cUnit, loc.lowReg);
loc.lowReg = newReg;
}
return loc;
}
assert((loc.location != kLocRetval) || (loc.sRegLow == INVALID_SREG));
newReg = dvmCompilerAllocTypedTemp(cUnit, loc.fp, regClass);
loc.lowReg = newReg;
if (update) {
loc.location = kLocPhysReg;
dvmCompilerMarkLive(cUnit, loc.lowReg, loc.sRegLow);
}
return loc;
}
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.
extern RegLocation dvmCompilerGetSrc(CompilationUnit *cUnit, MIR *mir, int num)
{
RegLocation loc = cUnit->regLocation[
SREG(cUnit, dvmCompilerSSASrc(mir, num))];
loc.fp = cUnit->regLocation[dvmCompilerSSASrc(mir, num)].fp;
loc.wide = false;
return loc;
}
// Get the LocRecord associated with an SSA name def.
extern RegLocation dvmCompilerGetDest(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 = dvmCompilerGetSrc(cUnit, mir, low);
highLoc = dvmCompilerGetSrc(cUnit, mir, high);
} else {
lowLoc = dvmCompilerGetDest(cUnit, mir, low);
highLoc = dvmCompilerGetDest(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;
}
extern RegLocation dvmCompilerGetDestWide(CompilationUnit *cUnit, MIR *mir,
int low, int high)
{
return getLocWide(cUnit, mir, low, high, false);
}
extern RegLocation dvmCompilerGetSrcWide(CompilationUnit *cUnit, MIR *mir,
int low, int high)
{
return getLocWide(cUnit, mir, low, high, true);
}
extern RegLocation dvmCompilerGetReturnWide(CompilationUnit *cUnit)
{
RegLocation res = LOC_C_RETURN_WIDE;
dvmCompilerClobber(cUnit, r0);
dvmCompilerClobber(cUnit, r1);
dvmCompilerMarkInUse(cUnit, r0);
dvmCompilerMarkInUse(cUnit, r1);
dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
return res;
}
extern RegLocation dvmCompilerGetReturnWideAlt(CompilationUnit *cUnit)
{
RegLocation res = LOC_C_RETURN_WIDE;
res.lowReg = r2;
res.highReg = r3;
dvmCompilerClobber(cUnit, r2);
dvmCompilerClobber(cUnit, r3);
dvmCompilerMarkInUse(cUnit, r2);
dvmCompilerMarkInUse(cUnit, r3);
dvmCompilerMarkPair(cUnit, res.lowReg, res.highReg);
return res;
}
extern RegLocation dvmCompilerGetReturn(CompilationUnit *cUnit)
{
RegLocation res = LOC_C_RETURN;
dvmCompilerClobber(cUnit, r0);
dvmCompilerMarkInUse(cUnit, r0);
return res;
}
extern RegLocation dvmCompilerGetReturnAlt(CompilationUnit *cUnit)
{
RegLocation res = LOC_C_RETURN;
res.lowReg = r1;
dvmCompilerClobber(cUnit, r1);
dvmCompilerMarkInUse(cUnit, r1);
return res;
}
/* Kill the corresponding bit in the null-checked register list */
extern void dvmCompilerKillNullCheckedLoc(CompilationUnit *cUnit,
RegLocation loc)
{
if (loc.location != kLocRetval) {
assert(loc.sRegLow != INVALID_SREG);
dvmClearBit(cUnit->regPool->nullCheckedRegs, loc.sRegLow);
if (loc.wide) {
assert(dvmCompilerSRegHi(loc.sRegLow) != INVALID_SREG);
dvmClearBit(cUnit->regPool->nullCheckedRegs,
dvmCompilerSRegHi(loc.sRegLow));
}
}
}
extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
int reg1, int reg2)
{
flushRegWide(cUnit, reg1, reg2);
}
extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg)
{
flushReg(cUnit, reg);
}