blob: bf7c1c759ab81fd7646204a606d5c82ef34fecbd [file] [log] [blame]
/*
* 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