/* * 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); }