Newer
Older
//===- ARMRegisterInfo.cpp - ARM Register Information -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the "Instituto Nokia de Tecnologia" and
// is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the ARM implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//
#include "ARM.h"
#include "ARMAddressingModes.h"
#include "ARMInstrInfo.h"
#include "ARMMachineFunctionInfo.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLocation.h"
Evan Cheng
committed
#include "llvm/CodeGen/RegisterScavenging.h"
Rafael Espindola
committed
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/ADT/BitVector.h"
Evan Cheng
committed
#include "llvm/Support/CommandLine.h"
Evan Cheng
committed
static cl::opt<bool> EnableScavenging("enable-arm-reg-scavenging", cl::Hidden,
cl::desc("Enable register scavenging on ARM"));
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
unsigned ARMRegisterInfo::getRegisterNumbering(unsigned RegEnum) {
using namespace ARM;
switch (RegEnum) {
case R0: case S0: case D0: return 0;
case R1: case S1: case D1: return 1;
case R2: case S2: case D2: return 2;
case R3: case S3: case D3: return 3;
case R4: case S4: case D4: return 4;
case R5: case S5: case D5: return 5;
case R6: case S6: case D6: return 6;
case R7: case S7: case D7: return 7;
case R8: case S8: case D8: return 8;
case R9: case S9: case D9: return 9;
case R10: case S10: case D10: return 10;
case R11: case S11: case D11: return 11;
case R12: case S12: case D12: return 12;
case SP: case S13: case D13: return 13;
case LR: case S14: case D14: return 14;
case PC: case S15: case D15: return 15;
case S16: return 16;
case S17: return 17;
case S18: return 18;
case S19: return 19;
case S20: return 20;
case S21: return 21;
case S22: return 22;
case S23: return 23;
case S24: return 24;
case S25: return 25;
case S26: return 26;
case S27: return 27;
case S28: return 28;
case S29: return 29;
case S30: return 30;
case S31: return 31;
default:
}
}
ARMRegisterInfo::ARMRegisterInfo(const TargetInstrInfo &tii,
const ARMSubtarget &sti)
: ARMGenRegisterInfo(ARM::ADJCALLSTACKDOWN, ARM::ADJCALLSTACKUP),
TII(tii), STI(sti),
FramePtr(STI.useThumbBacktraces() ? ARM::R7 : ARM::R11) {
Evan Cheng
committed
RS = new RegScavenger();
}
ARMRegisterInfo::~ARMRegisterInfo() {
delete RS;
}
RegScavenger *ARMRegisterInfo::getRegScavenger() const {
return EnableScavenging ? RS : NULL;
}
bool ARMRegisterInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI) const {
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
if (!AFI->isThumbFunction() || CSI.empty())
return false;
MachineInstrBuilder MIB = BuildMI(MBB, MI, TII.get(ARM::tPUSH));
Evan Cheng
committed
for (unsigned i = CSI.size(); i != 0; --i) {
unsigned Reg = CSI[i-1].getReg();
// Add the callee-saved register as live-in. It's killed at the spill.
MBB.addLiveIn(Reg);
MIB.addReg(Reg, false/*isDef*/,false/*isImp*/,true/*isKill*/);
}
return true;
}
bool ARMRegisterInfo::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI) const {
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
if (!AFI->isThumbFunction() || CSI.empty())
return false;
bool isVarArg = AFI->getVarArgsRegSaveSize() > 0;
MachineInstr *PopMI = new MachineInstr(TII.get(ARM::tPOP));
MBB.insert(MI, PopMI);
for (unsigned i = CSI.size(); i != 0; --i) {
unsigned Reg = CSI[i-1].getReg();
if (Reg == ARM::LR) {
// Special epilogue for vararg functions. See emitEpilogue
if (isVarArg)
continue;
Reg = ARM::PC;
PopMI->setInstrDescriptor(TII.get(ARM::tPOP_RET));
MBB.erase(MI);
}
PopMI->addRegOperand(Reg, true);
}
return true;
}
void ARMRegisterInfo::
storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned SrcReg, int FI,
const TargetRegisterClass *RC) const {
if (RC == ARM::GPRRegisterClass) {
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
if (AFI->isThumbFunction())
Evan Cheng
committed
BuildMI(MBB, I, TII.get(ARM::tSpill)).addReg(SrcReg, false, false, true)
.addFrameIndex(FI).addImm(0);
else
Evan Cheng
committed
BuildMI(MBB, I, TII.get(ARM::STR)).addReg(SrcReg, false, false, true)
.addFrameIndex(FI).addReg(0).addImm(0);
} else if (RC == ARM::DPRRegisterClass) {
Evan Cheng
committed
BuildMI(MBB, I, TII.get(ARM::FSTD)).addReg(SrcReg, false, false, true)
.addFrameIndex(FI).addImm(0);
} else {
assert(RC == ARM::SPRRegisterClass && "Unknown regclass!");
Evan Cheng
committed
BuildMI(MBB, I, TII.get(ARM::FSTS)).addReg(SrcReg, false, false, true)
}
void ARMRegisterInfo::
loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned DestReg, int FI,
const TargetRegisterClass *RC) const {
if (RC == ARM::GPRRegisterClass) {
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
if (AFI->isThumbFunction())
BuildMI(MBB, I, TII.get(ARM::tRestore), DestReg)
.addFrameIndex(FI).addImm(0);
else
BuildMI(MBB, I, TII.get(ARM::LDR), DestReg)
.addFrameIndex(FI).addReg(0).addImm(0);
} else if (RC == ARM::DPRRegisterClass) {
BuildMI(MBB, I, TII.get(ARM::FLDD), DestReg)
.addFrameIndex(FI).addImm(0);
} else {
assert(RC == ARM::SPRRegisterClass && "Unknown regclass!");
BuildMI(MBB, I, TII.get(ARM::FLDS), DestReg)
.addFrameIndex(FI).addImm(0);
}
}
void ARMRegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned DestReg, unsigned SrcReg,
const TargetRegisterClass *RC) const {
if (RC == ARM::GPRRegisterClass) {
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
BuildMI(MBB, I, TII.get(AFI->isThumbFunction() ? ARM::tMOVrr : ARM::MOVrr),
DestReg).addReg(SrcReg);
} else if (RC == ARM::SPRRegisterClass)
BuildMI(MBB, I, TII.get(ARM::FCPYS), DestReg).addReg(SrcReg);
BuildMI(MBB, I, TII.get(ARM::FCPYD), DestReg).addReg(SrcReg);
/// isLowRegister - Returns true if the register is low register r0-r7.
///
static bool isLowRegister(unsigned Reg) {
using namespace ARM;
switch (Reg) {
case R0: case R1: case R2: case R3:
case R4: case R5: case R6: case R7:
return true;
default:
return false;
}
}
MachineInstr *ARMRegisterInfo::foldMemoryOperand(MachineInstr *MI,
unsigned OpNum, int FI) const {
unsigned Opc = MI->getOpcode();
MachineInstr *NewMI = NULL;
switch (Opc) {
default: break;
case ARM::MOVrr: {
if (OpNum == 0) { // move -> store
unsigned SrcReg = MI->getOperand(1).getReg();
NewMI = BuildMI(TII.get(ARM::STR)).addReg(SrcReg).addFrameIndex(FI)
.addReg(0).addImm(0);
} else { // move -> load
unsigned DstReg = MI->getOperand(0).getReg();
NewMI = BuildMI(TII.get(ARM::LDR), DstReg).addFrameIndex(FI).addReg(0)
.addImm(0);
}
break;
}
case ARM::tMOVrr: {
if (OpNum == 0) { // move -> store
unsigned SrcReg = MI->getOperand(1).getReg();
if (isPhysicalRegister(SrcReg) && !isLowRegister(SrcReg))
// tSpill cannot take a high register operand.
break;
NewMI = BuildMI(TII.get(ARM::tSpill)).addReg(SrcReg).addFrameIndex(FI)
.addImm(0);
} else { // move -> load
unsigned DstReg = MI->getOperand(0).getReg();
if (isPhysicalRegister(DstReg) && !isLowRegister(DstReg))
// tRestore cannot target a high register operand.
break;
NewMI = BuildMI(TII.get(ARM::tRestore), DstReg).addFrameIndex(FI)
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
.addImm(0);
}
break;
}
case ARM::FCPYS: {
if (OpNum == 0) { // move -> store
unsigned SrcReg = MI->getOperand(1).getReg();
NewMI = BuildMI(TII.get(ARM::FSTS)).addReg(SrcReg).addFrameIndex(FI)
.addImm(0);
} else { // move -> load
unsigned DstReg = MI->getOperand(0).getReg();
NewMI = BuildMI(TII.get(ARM::FLDS), DstReg).addFrameIndex(FI).addImm(0);
}
break;
}
case ARM::FCPYD: {
if (OpNum == 0) { // move -> store
unsigned SrcReg = MI->getOperand(1).getReg();
NewMI = BuildMI(TII.get(ARM::FSTD)).addReg(SrcReg).addFrameIndex(FI)
.addImm(0);
} else { // move -> load
unsigned DstReg = MI->getOperand(0).getReg();
NewMI = BuildMI(TII.get(ARM::FLDD), DstReg).addFrameIndex(FI).addImm(0);
}
break;
}
}
if (NewMI)
NewMI->copyKillDeadInfo(MI);
return NewMI;
const unsigned* ARMRegisterInfo::getCalleeSavedRegs() const {
static const unsigned CalleeSavedRegs[] = {
ARM::LR, ARM::R11, ARM::R10, ARM::R9, ARM::R8,
ARM::R7, ARM::R6, ARM::R5, ARM::R4,
ARM::D15, ARM::D14, ARM::D13, ARM::D12,
ARM::D11, ARM::D10, ARM::D9, ARM::D8,
0
static const unsigned DarwinCalleeSavedRegs[] = {
ARM::LR, ARM::R7, ARM::R6, ARM::R5, ARM::R4,
ARM::R11, ARM::R10, ARM::R9, ARM::R8,
ARM::D15, ARM::D14, ARM::D13, ARM::D12,
ARM::D11, ARM::D10, ARM::D9, ARM::D8,
0
};
return STI.isTargetDarwin() ? DarwinCalleeSavedRegs : CalleeSavedRegs;
}
const TargetRegisterClass* const *
ARMRegisterInfo::getCalleeSavedRegClasses() const {
static const TargetRegisterClass * const CalleeSavedRegClasses[] = {
&ARM::GPRRegClass, &ARM::GPRRegClass, &ARM::GPRRegClass,
&ARM::GPRRegClass, &ARM::GPRRegClass, &ARM::GPRRegClass,
&ARM::GPRRegClass, &ARM::GPRRegClass, &ARM::GPRRegClass,
&ARM::DPRRegClass, &ARM::DPRRegClass, &ARM::DPRRegClass, &ARM::DPRRegClass,
&ARM::DPRRegClass, &ARM::DPRRegClass, &ARM::DPRRegClass, &ARM::DPRRegClass,
0
}
BitVector ARMRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
BitVector Reserved(getNumRegs());
Reserved.set(ARM::SP);
if (STI.isTargetDarwin() || hasFP(MF))
Reserved.set(FramePtr);
// Some targets reserve R9.
if (STI.isR9Reserved())
Reserved.set(ARM::R9);
// At PEI time, if LR is used, it will be spilled upon entry.
if (MF.getUsedPhysregs() && !MF.isPhysRegUsed((unsigned)ARM::LR))
Reserved.set(ARM::LR);
return Reserved;
}
/// hasFP - Return true if the specified function should have a dedicated frame
/// pointer register. This is true if the function has variable sized allocas
/// or if frame pointer elimination is disabled.
///
bool ARMRegisterInfo::hasFP(const MachineFunction &MF) const {
return NoFramePointerElim || MF.getFrameInfo()->hasVarSizedObjects();
}
/// emitARMRegPlusImmediate - Emits a series of instructions to materialize
/// a destreg = basereg + immediate in ARM code.
static
void emitARMRegPlusImmediate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator &MBBI,
unsigned DestReg, unsigned BaseReg,
int NumBytes, const TargetInstrInfo &TII) {
bool isSub = NumBytes < 0;
if (isSub) NumBytes = -NumBytes;
while (NumBytes) {
unsigned RotAmt = ARM_AM::getSOImmValRotate(NumBytes);
unsigned ThisVal = NumBytes & ARM_AM::rotr32(0xFF, RotAmt);
assert(ThisVal && "Didn't extract field correctly");
// We will handle these bits from offset, clear them.
NumBytes &= ~ThisVal;
// Get the properly encoded SOImmVal field.
int SOImmVal = ARM_AM::getSOImmVal(ThisVal);
assert(SOImmVal != -1 && "Bit extraction didn't work?");
// Build the new ADD / SUB.
BuildMI(MBB, MBBI, TII.get(isSub ? ARM::SUBri : ARM::ADDri), DestReg)
Evan Cheng
committed
.addReg(BaseReg, false, false, true).addImm(SOImmVal);
/// calcNumMI - Returns the number of instructions required to materialize
/// the specific add / sub r, c instruction.
static unsigned calcNumMI(int Opc, int ExtraOpc, unsigned Bytes,
unsigned NumBits, unsigned Scale) {
unsigned NumMIs = 0;
unsigned Chunk = ((1 << NumBits) - 1) * Scale;
if (Opc == ARM::tADDrSPi) {
unsigned ThisVal = (Bytes > Chunk) ? Chunk : Bytes;
Bytes -= ThisVal;
NumMIs++;
NumBits = 8;
Scale = 1;
Chunk = ((1 << NumBits) - 1) * Scale;
}
NumMIs += Bytes / Chunk;
if ((Bytes % Chunk) != 0)
NumMIs++;
if (ExtraOpc)
NumMIs++;
return NumMIs;
}
/// emitLoadConstPool - Emits a load from constpool to materialize NumBytes
/// immediate.
static void emitLoadConstPool(MachineBasicBlock &MBB,
MachineBasicBlock::iterator &MBBI,
unsigned DestReg, int NumBytes,
const TargetInstrInfo &TII) {
MachineFunction &MF = *MBB.getParent();
MachineConstantPool *ConstantPool = MF.getConstantPool();
Constant *C = ConstantInt::get(Type::Int32Ty, NumBytes);
unsigned Idx = ConstantPool->getConstantPoolIndex(C, 2);
BuildMI(MBB, MBBI, TII.get(ARM::tLDRpci), DestReg).addConstantPoolIndex(Idx);
}
/// emitThumbRegPlusImmInReg - Emits a series of instructions to materialize
/// a destreg = basereg + immediate in Thumb code. Materialize the immediate
/// in a register using mov / mvn sequences or load the immediate from a
/// constpool entry.
static
MachineBasicBlock::iterator &MBBI,
unsigned DestReg, unsigned BaseReg,
Evan Cheng
committed
int NumBytes, bool CanChangeCC,
const TargetInstrInfo &TII) {
bool isHigh = !isLowRegister(DestReg) ||
(BaseReg != 0 && !isLowRegister(BaseReg));
bool isSub = false;
// Subtract doesn't have high register version. Load the negative value
Evan Cheng
committed
// if either base or dest register is a high register. Also, if do not
// issue sub as part of the sequence if condition register is to be
// preserved.
if (NumBytes < 0 && !isHigh && CanChangeCC) {
isSub = true;
NumBytes = -NumBytes;
}
unsigned LdReg = DestReg;
if (DestReg == ARM::SP) {
assert(BaseReg == ARM::SP && "Unexpected!");
LdReg = ARM::R3;
Evan Cheng
committed
BuildMI(MBB, MBBI, TII.get(ARM::tMOVrr), ARM::R12)
.addReg(ARM::R3, false, false, true);
}
Evan Cheng
committed
if (NumBytes <= 255 && NumBytes >= 0)
BuildMI(MBB, MBBI, TII.get(ARM::tMOVri8), LdReg).addImm(NumBytes);
else if (NumBytes < 0 && NumBytes >= -255) {
BuildMI(MBB, MBBI, TII.get(ARM::tMOVri8), LdReg).addImm(NumBytes);
Evan Cheng
committed
BuildMI(MBB, MBBI, TII.get(ARM::tNEG), LdReg)
.addReg(LdReg, false, false, true);
} else
emitLoadConstPool(MBB, MBBI, LdReg, NumBytes, TII);
// Emit add / sub.
int Opc = (isSub) ? ARM::tSUBrr : (isHigh ? ARM::tADDhirr : ARM::tADDrr);
const MachineInstrBuilder MIB = BuildMI(MBB, MBBI, TII.get(Opc), DestReg);
Evan Cheng
committed
if (DestReg == ARM::SP || isSub)
MIB.addReg(BaseReg).addReg(LdReg, false, false, true);
else
Evan Cheng
committed
MIB.addReg(LdReg).addReg(BaseReg, false, false, true);
if (DestReg == ARM::SP)
Evan Cheng
committed
BuildMI(MBB, MBBI, TII.get(ARM::tMOVrr), ARM::R3)
.addReg(ARM::R12, false, false, true);
}
/// emitThumbRegPlusImmediate - Emits a series of instructions to materialize
/// a destreg = basereg + immediate in Thumb code.
static
void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator &MBBI,
unsigned DestReg, unsigned BaseReg,
int NumBytes, const TargetInstrInfo &TII) {
bool isSub = NumBytes < 0;
unsigned Bytes = (unsigned)NumBytes;
if (isSub) Bytes = -NumBytes;
bool isMul4 = (Bytes & 3) == 0;
bool isTwoAddr = false;
bool DstNotEqBase = false;
int Opc = 0;
int ExtraOpc = 0;
if (DestReg == BaseReg && BaseReg == ARM::SP) {
assert(isMul4 && "Thumb sp inc / dec size must be multiple of 4!");
NumBits = 7;
Opc = isSub ? ARM::tSUBspi : ARM::tADDspi;
isTwoAddr = true;
} else if (!isSub && BaseReg == ARM::SP) {
// r1 = add sp, 403
// =>
// r1 = add sp, 100 * 4
// r1 = add r1, 3
if (!isMul4) {
Bytes &= ~3;
ExtraOpc = ARM::tADDi3;
}
NumBits = 8;
// sp = sub sp, c
// r1 = sub sp, c
// r8 = sub sp, c
if (DestReg != BaseReg)
DstNotEqBase = true;
NumBits = 8;
Opc = isSub ? ARM::tSUBi8 : ARM::tADDi8;
isTwoAddr = true;
}
unsigned NumMIs = calcNumMI(Opc, ExtraOpc, Bytes, NumBits, Scale);
unsigned Threshold = (DestReg == ARM::SP) ? 3 : 2;
if (NumMIs > Threshold) {
// This will expand into too many instructions. Load the immediate from a
// constpool entry.
emitThumbRegPlusImmInReg(MBB, MBBI, DestReg, BaseReg, NumBytes, true, TII);
return;
}
if (DstNotEqBase) {
if (isLowRegister(DestReg) && isLowRegister(BaseReg)) {
// If both are low registers, emit DestReg = add BaseReg, max(Imm, 7)
unsigned Chunk = (1 << 3) - 1;
unsigned ThisVal = (Bytes > Chunk) ? Chunk : Bytes;
Bytes -= ThisVal;
BuildMI(MBB, MBBI, TII.get(isSub ? ARM::tSUBi3 : ARM::tADDi3), DestReg)
Evan Cheng
committed
.addReg(BaseReg, false, false, true).addImm(ThisVal);
} else {
Evan Cheng
committed
BuildMI(MBB, MBBI, TII.get(ARM::tMOVrr), DestReg)
.addReg(BaseReg, false, false, true);
}
BaseReg = DestReg;
}
unsigned Chunk = ((1 << NumBits) - 1) * Scale;
while (Bytes) {
unsigned ThisVal = (Bytes > Chunk) ? Chunk : Bytes;
// Build the new tADD / tSUB.
if (isTwoAddr)
BuildMI(MBB, MBBI, TII.get(Opc), DestReg).addReg(DestReg).addImm(ThisVal);
Evan Cheng
committed
bool isKill = BaseReg != ARM::SP;
BuildMI(MBB, MBBI, TII.get(Opc), DestReg)
.addReg(BaseReg, false, false, isKill).addImm(ThisVal);
BaseReg = DestReg;
if (Opc == ARM::tADDrSPi) {
// r4 = add sp, imm
// r4 = add r4, imm
// ...
NumBits = 8;
Scale = 1;
Chunk = ((1 << NumBits) - 1) * Scale;
Opc = isSub ? ARM::tSUBi8 : ARM::tADDi8;
isTwoAddr = true;
}
}
}
if (ExtraOpc)
Evan Cheng
committed
BuildMI(MBB, MBBI, TII.get(ExtraOpc), DestReg)
.addReg(DestReg, false, false, true)
.addImm(((unsigned)NumBytes) & 3);
}
static
void emitSPUpdate(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI,
int NumBytes, bool isThumb, const TargetInstrInfo &TII) {
if (isThumb)
emitThumbRegPlusImmediate(MBB, MBBI, ARM::SP, ARM::SP, NumBytes, TII);
else
emitARMRegPlusImmediate(MBB, MBBI, ARM::SP, ARM::SP, NumBytes, TII);
}
void ARMRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
// If we have alloca, convert as follows:
// ADJCALLSTACKDOWN -> sub, sp, sp, amount
// ADJCALLSTACKUP -> add, sp, sp, amount
Rafael Espindola
committed
MachineInstr *Old = I;
unsigned Amount = Old->getOperand(0).getImmedValue();
if (Amount != 0) {
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
// We need to keep the stack aligned properly. To do this, we round the
// amount of space needed for the outgoing arguments up to the next
// alignment boundary.
Rafael Espindola
committed
unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
Amount = (Amount+Align-1)/Align*Align;
// Replace the pseudo instruction with a new instruction...
Rafael Espindola
committed
if (Old->getOpcode() == ARM::ADJCALLSTACKDOWN) {
emitSPUpdate(MBB, I, -Amount, AFI->isThumbFunction(), TII);
Rafael Espindola
committed
} else {
assert(Old->getOpcode() == ARM::ADJCALLSTACKUP);
emitSPUpdate(MBB, I, Amount, AFI->isThumbFunction(), TII);
Rafael Espindola
committed
}
}
/// emitThumbConstant - Emit a series of instructions to materialize a
/// constant.
static void emitThumbConstant(MachineBasicBlock &MBB,
MachineBasicBlock::iterator &MBBI,
unsigned DestReg, int Imm,
const TargetInstrInfo &TII) {
bool isSub = Imm < 0;
if (isSub) Imm = -Imm;
int Chunk = (1 << 8) - 1;
int ThisVal = (Imm > Chunk) ? Chunk : Imm;
Imm -= ThisVal;
BuildMI(MBB, MBBI, TII.get(ARM::tMOVri8), DestReg).addImm(ThisVal);
if (Imm > 0)
emitThumbRegPlusImmediate(MBB, MBBI, DestReg, DestReg, Imm, TII);
if (isSub)
Evan Cheng
committed
BuildMI(MBB, MBBI, TII.get(ARM::tNEG), DestReg)
.addReg(DestReg, false, false, true);
}
void ARMRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II) const{
unsigned i = 0;
MachineInstr &MI = *II;
MachineBasicBlock &MBB = *MI.getParent();
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
bool isThumb = AFI->isThumbFunction();
while (!MI.getOperand(i).isFrameIndex()) {
++i;
assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
}
unsigned FrameReg = ARM::SP;
int FrameIndex = MI.getOperand(i).getFrameIndex();
int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
MF.getFrameInfo()->getStackSize();
if (AFI->isGPRCalleeSavedArea1Frame(FrameIndex))
Offset -= AFI->getGPRCalleeSavedArea1Offset();
else if (AFI->isGPRCalleeSavedArea2Frame(FrameIndex))
Offset -= AFI->getGPRCalleeSavedArea2Offset();
else if (AFI->isDPRCalleeSavedAreaFrame(FrameIndex))
Offset -= AFI->getDPRCalleeSavedAreaOffset();
// There is alloca()'s in this function, must reference off the frame
// pointer instead.
FrameReg = getFrameRegister(MF);
Lauro Ramos Venancio
committed
Offset -= AFI->getFramePtrSpillOffset();
}
unsigned Opcode = MI.getOpcode();
const TargetInstrDescriptor &Desc = TII.get(Opcode);
unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
bool isSub = false;
if (Opcode == ARM::ADDri) {
Offset += MI.getOperand(i+1).getImm();
if (Offset == 0) {
// Turn it into a move.
MI.setInstrDescriptor(TII.get(ARM::MOVrr));
MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.RemoveOperand(i+1);
return;
} else if (Offset < 0) {
Offset = -Offset;
isSub = true;
MI.setInstrDescriptor(TII.get(ARM::SUBri));
}
// Common case: small offset, fits into instruction.
int ImmedOffset = ARM_AM::getSOImmVal(Offset);
if (ImmedOffset != -1) {
// Replace the FrameIndex with sp / fp
MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.getOperand(i+1).ChangeToImmediate(ImmedOffset);
return;
}
// Otherwise, we fallback to common code below to form the imm offset with
// a sequence of ADDri instructions. First though, pull as much of the imm
// into this ADDri as possible.
unsigned RotAmt = ARM_AM::getSOImmValRotate(Offset);
unsigned ThisImmVal = Offset & ARM_AM::rotr32(0xFF, (32-RotAmt) & 31);
// We will handle these bits from offset, clear them.
Offset &= ~ThisImmVal;
// Get the properly encoded SOImmVal field.
int ThisSOImmVal = ARM_AM::getSOImmVal(ThisImmVal);
assert(ThisSOImmVal != -1 && "Bit extraction didn't work?");
MI.getOperand(i+1).ChangeToImmediate(ThisSOImmVal);
} else if (Opcode == ARM::tADDrSPi) {
Offset += MI.getOperand(i+1).getImm();
assert((Offset & 3) == 0 &&
"Thumb add/sub sp, #imm immediate must be multiple of 4!");
if (Offset == 0) {
// Turn it into a move.
MI.setInstrDescriptor(TII.get(ARM::tMOVrr));
MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.RemoveOperand(i+1);
return;
}
// Common case: small offset, fits into instruction.
if (((Offset >> 2) & ~255U) == 0) {
// Replace the FrameIndex with sp / fp
MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.getOperand(i+1).ChangeToImmediate(Offset >> 2);
return;
}
unsigned DestReg = MI.getOperand(0).getReg();
unsigned Bytes = (Offset > 0) ? Offset : -Offset;
unsigned NumMIs = calcNumMI(Opcode, 0, Bytes, 8, 1);
// MI would expand into a large number of instructions. Don't try to
// simplify the immediate.
if (NumMIs > 2) {
emitThumbRegPlusImmediate(MBB, II, DestReg, FrameReg, Offset, TII);
MBB.erase(II);
return;
}
if (Offset > 0) {
// Translate r0 = add sp, imm to
// r0 = add sp, 255*4
// r0 = add r0, (imm - 255*4)
MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.getOperand(i+1).ChangeToImmediate(255);
MachineBasicBlock::iterator NII = next(II);
emitThumbRegPlusImmediate(MBB, NII, DestReg, DestReg, Offset, TII);
} else {
// Translate r0 = add sp, -imm to
// r0 = -imm (this is then translated into a series of instructons)
// r0 = add r0, sp
emitThumbConstant(MBB, II, DestReg, Offset, TII);
MI.setInstrDescriptor(TII.get(ARM::tADDhirr));
Evan Cheng
committed
MI.getOperand(i).ChangeToRegister(DestReg, false, false, true);
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
MI.getOperand(i+1).ChangeToRegister(FrameReg, false);
}
return;
} else {
unsigned ImmIdx = 0;
int InstrOffs = 0;
unsigned NumBits = 0;
unsigned Scale = 1;
switch (AddrMode) {
case ARMII::AddrMode2: {
ImmIdx = i+2;
InstrOffs = ARM_AM::getAM2Offset(MI.getOperand(ImmIdx).getImm());
if (ARM_AM::getAM2Op(MI.getOperand(ImmIdx).getImm()) == ARM_AM::sub)
InstrOffs *= -1;
NumBits = 12;
break;
}
case ARMII::AddrMode3: {
ImmIdx = i+2;
InstrOffs = ARM_AM::getAM3Offset(MI.getOperand(ImmIdx).getImm());
if (ARM_AM::getAM3Op(MI.getOperand(ImmIdx).getImm()) == ARM_AM::sub)
InstrOffs *= -1;
NumBits = 8;
break;
}
case ARMII::AddrMode5: {
ImmIdx = i+1;
InstrOffs = ARM_AM::getAM5Offset(MI.getOperand(ImmIdx).getImm());
if (ARM_AM::getAM5Op(MI.getOperand(ImmIdx).getImm()) == ARM_AM::sub)
InstrOffs *= -1;
NumBits = 8;
Scale = 4;
break;
}
case ARMII::AddrModeTs: {
ImmIdx = i+1;
InstrOffs = MI.getOperand(ImmIdx).getImm();
NumBits = (FrameReg == ARM::SP) ? 8 : 5;
Scale = 4;
assert(0 && "Unsupported addressing mode!");
assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
Evan Cheng
committed
if (Offset < 0 && !isThumb) {
Offset = -Offset;
isSub = true;
}
Evan Cheng
committed
// Common case: small offset, fits into instruction.
MachineOperand &ImmOp = MI.getOperand(ImmIdx);
int ImmedOffset = Offset / Scale;
unsigned Mask = (1 << NumBits) - 1;
if ((unsigned)Offset <= Mask * Scale) {
// Replace the FrameIndex with sp
MI.getOperand(i).ChangeToRegister(FrameReg, false);
if (isSub)
ImmedOffset |= 1 << NumBits;
ImmOp.ChangeToImmediate(ImmedOffset);
return;
}
Evan Cheng
committed
bool isThumSpillRestore = Opcode == ARM::tRestore || Opcode == ARM::tSpill;
if (AddrMode == ARMII::AddrModeTs) {
// Thumb tLDRspi, tSTRspi. These will change to instructions that use
// a different base register.
NumBits = 5;
Mask = (1 << NumBits) - 1;
}
Evan Cheng
committed
// If this is a thumb spill / restore, we will be using a constpool load to
// materialize the offset.
Evan Cheng
committed
if (AddrMode == ARMII::AddrModeTs && isThumSpillRestore)
ImmOp.ChangeToImmediate(0);
else {
// Otherwise, it didn't fit. Pull in what we can to simplify the immed.
ImmedOffset = ImmedOffset & Mask;
if (isSub)
ImmedOffset |= 1 << NumBits;
ImmOp.ChangeToImmediate(ImmedOffset);
Offset &= ~(Mask*Scale);
}
}
// If we get here, the immediate doesn't fit into the instruction. We folded
// as much as possible above, handle the rest, providing a register that is
// SP+LargeImm.
assert(Offset && "This code isn't needed if offset already handled!");
if (isThumb) {
if (TII.isLoad(Opcode)) {
// Use the destination register to materialize sp + offset.
unsigned TmpReg = MI.getOperand(0).getReg();
bool UseRR = false;
if (Opcode == ARM::tRestore) {
if (FrameReg == ARM::SP)
emitThumbRegPlusImmInReg(MBB, II, TmpReg, FrameReg,Offset,false,TII);
else {
emitLoadConstPool(MBB, II, TmpReg, Offset, TII);
UseRR = true;
}
} else
Evan Cheng
committed
emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg, Offset, TII);
MI.setInstrDescriptor(TII.get(ARM::tLDR));
Evan Cheng
committed
MI.getOperand(i).ChangeToRegister(TmpReg, false, false, true);
if (UseRR)
MI.addRegOperand(FrameReg, false); // Use [reg, reg] addrmode.
else
Evan Cheng
committed
MI.addRegOperand(0, false); // tLDR has an extra register operand.
} else if (TII.isStore(Opcode)) {
// FIXME! This is horrific!!! We need register scavenging.
// Our temporary workaround has marked r3 unavailable. Of course, r3 is
// also a ABI register so it's possible that is is the register that is
// being storing here. If that's the case, we do the following:
// r12 = r2
// Use r2 to materialize sp + offset
// str r3, r2
unsigned ValReg = MI.getOperand(0).getReg();
bool UseRR = false;
Evan Cheng
committed
BuildMI(MBB, II, TII.get(ARM::tMOVrr), ARM::R12)
.addReg(ARM::R2, false, false, true);
if (TmpReg == ARM::R3 && AFI->isR3IsLiveIn())
Evan Cheng
committed
BuildMI(MBB, II, TII.get(ARM::tMOVrr), ARM::R12)
.addReg(ARM::R3, false, false, true);
if (Opcode == ARM::tSpill) {
if (FrameReg == ARM::SP)
emitThumbRegPlusImmInReg(MBB, II, TmpReg, FrameReg,Offset,false,TII);
else {
emitLoadConstPool(MBB, II, TmpReg, Offset, TII);
UseRR = true;
}
} else
Evan Cheng
committed
emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg, Offset, TII);
MI.setInstrDescriptor(TII.get(ARM::tSTR));
Evan Cheng
committed
MI.getOperand(i).ChangeToRegister(TmpReg, false, false, true);
if (UseRR)
MI.addRegOperand(FrameReg, false); // Use [reg, reg] addrmode.
else
MI.addRegOperand(0, false); // tSTR has an extra register operand.
MachineBasicBlock::iterator NII = next(II);
if (ValReg == ARM::R3)
Evan Cheng
committed
BuildMI(MBB, NII, TII.get(ARM::tMOVrr), ARM::R2)
.addReg(ARM::R12, false, false, true);
if (TmpReg == ARM::R3 && AFI->isR3IsLiveIn())
Evan Cheng
committed
BuildMI(MBB, NII, TII.get(ARM::tMOVrr), ARM::R3)
.addReg(ARM::R12, false, false, true);
} else
assert(false && "Unexpected opcode!");
// Insert a set of r12 with the full address: r12 = sp + offset
// If the offset we have is too large to fit into the instruction, we need
// to form it with a series of ADDri's. Do this by taking 8-bit chunks
// out of 'Offset'.
emitARMRegPlusImmediate(MBB, II, ARM::R12, FrameReg,
isSub ? -Offset : Offset, TII);
Evan Cheng
committed
MI.getOperand(i).ChangeToRegister(ARM::R12, false, false, true);
processFunctionBeforeCalleeSavedScan(MachineFunction &MF) const {
// This tells PEI to spill the FP as if it is any other callee-save register
// to take advantage the eliminateFrameIndex machinery. This also ensures it
// is spilled in the order specified by getCalleeSavedRegs() to make it easier
// to combine multiple loads / stores.
bool CS1Spilled = false;
bool LRSpilled = false;
unsigned NumGPRSpills = 0;
SmallVector<unsigned, 4> UnspilledCS1GPRs;
SmallVector<unsigned, 4> UnspilledCS2GPRs;
// Don't spill FP if the frame can be eliminated. This is determined
// by scanning the callee-save registers to see if any is used.
const unsigned *CSRegs = getCalleeSavedRegs();
const TargetRegisterClass* const *CSRegClasses = getCalleeSavedRegClasses();
for (unsigned i = 0; CSRegs[i]; ++i) {
unsigned Reg = CSRegs[i];
bool Spilled = false;
if (MF.isPhysRegUsed(Reg)) {
Spilled = true;
CanEliminateFrame = false;
} else {
// Check alias registers too.
for (const unsigned *Aliases = getAliasSet(Reg); *Aliases; ++Aliases) {
if (MF.isPhysRegUsed(*Aliases)) {
Spilled = true;
CanEliminateFrame = false;
if (CSRegClasses[i] == &ARM::GPRRegClass) {
if (Spilled) {
NumGPRSpills++;
if (!STI.isTargetDarwin()) {
if (Reg == ARM::LR)
LRSpilled = true;
else
CS1Spilled = true;
continue;
}
// Keep track if LR and any of R4, R5, R6, and R7 is spilled.
switch (Reg) {
case ARM::LR:
LRSpilled = true;
// Fallthrough
case ARM::R4:
case ARM::R5:
case ARM::R6:
case ARM::R7:
CS1Spilled = true;
break;
default:
break;
}
} else {
if (!STI.isTargetDarwin()) {
UnspilledCS1GPRs.push_back(Reg);
continue;
}
switch (Reg) {
case ARM::R4:
case ARM::R5:
case ARM::R6:
case ARM::R7:
case ARM::LR:
UnspilledCS1GPRs.push_back(Reg);
break;
default:
UnspilledCS2GPRs.push_back(Reg);
break;
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
bool ForceLRSpill = false;
if (!LRSpilled && AFI->isThumbFunction()) {
unsigned FnSize = ARM::GetFunctionSize(MF);
// Force LR spill if the Thumb function size is > 2048. This enables the
// use of BL to implement far jump. If it turns out that it's not needed
// the branch fix up path will undo it.
if (FnSize >= (1 << 11)) {
CanEliminateFrame = false;
ForceLRSpill = true;
}
}