/* * 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 Arm-specific register allocation support. */ #include "../../CompilerUtility.h" #include "../../CompilerIR.h" #include "../..//Dataflow.h" #include "ArmLIR.h" #include "Codegen.h" #include "../Ralloc.h" namespace art { /* * 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. */ void oatAdjustSpillMask(CompilationUnit* cUnit) { cUnit->coreSpillMask |= (1 << rLR); cUnit->numCoreSpills++; } /* * 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). */ void oatMarkPreservedSingle(CompilationUnit* cUnit, int vReg, int reg) { 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); } // Add the current mapping cUnit->fpVmapTable[reg] = vReg; // 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; } 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"; } info1->dirty = false; info2->dirty = false; if (SRegToVReg(cUnit, info2->sReg) < SRegToVReg(cUnit, info1->sReg)) info1 = info2; int vReg = SRegToVReg(cUnit, info1->sReg); oatFlushRegWideImpl(cUnit, rSP, oatVRegOffset(cUnit, vReg), info1->reg, info1->partner); } } void oatFlushReg(CompilationUnit* cUnit, int reg) { RegisterInfo* info = oatGetRegInfo(cUnit, reg); if (info->live && info->dirty) { info->dirty = false; int vReg = SRegToVReg(cUnit, info->sReg); oatFlushRegImpl(cUnit, rSP, oatVRegOffset(cUnit, vReg), reg, kWord); } } /* Give access to the target-dependent FP register encoding to common code */ bool oatIsFpReg(int reg) { return FPREG(reg); } uint32_t oatFpRegMask() { return FP_REG_MASK; } /* Clobber all regs that might be used by an external C call */ void oatClobberCalleeSave(CompilationUnit *cUnit) { oatClobber(cUnit, r0); oatClobber(cUnit, r1); oatClobber(cUnit, r2); oatClobber(cUnit, r3); oatClobber(cUnit, r12); oatClobber(cUnit, r14lr); oatClobber(cUnit, fr0); oatClobber(cUnit, fr1); oatClobber(cUnit, fr2); oatClobber(cUnit, fr3); oatClobber(cUnit, fr4); oatClobber(cUnit, fr5); oatClobber(cUnit, fr6); oatClobber(cUnit, fr7); oatClobber(cUnit, fr8); oatClobber(cUnit, fr9); oatClobber(cUnit, fr10); oatClobber(cUnit, fr11); oatClobber(cUnit, fr12); oatClobber(cUnit, fr13); oatClobber(cUnit, fr14); oatClobber(cUnit, fr15); } extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit) { RegLocation res = LOC_C_RETURN_WIDE; res.lowReg = r2; res.highReg = r3; oatClobber(cUnit, r2); oatClobber(cUnit, r3); oatMarkInUse(cUnit, r2); oatMarkInUse(cUnit, r3); oatMarkPair(cUnit, res.lowReg, res.highReg); return res; } extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit) { RegLocation res = LOC_C_RETURN; res.lowReg = r1; oatClobber(cUnit, r1); oatMarkInUse(cUnit, r1); return res; } extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg) { return FPREG(reg) ? &cUnit->regPool->FPRegs[reg & FP_REG_MASK] : &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 */ void oatNopLIR( LIR* lir) { ((LIR*)lir)->flags.isNop = true; } } // namespace art