-//===- Thumb1RegisterInfo.cpp - Thumb-1 Register Information -------*- C++ -*-===//
+//===- Thumb1RegisterInfo.cpp - Thumb-1 Register Information ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
//
-// This file contains the Thumb-1 implementation of the TargetRegisterInfo class.
+// This file contains the Thumb-1 implementation of the TargetRegisterInfo
+// class.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
-static cl::opt<bool>
-ThumbRegScavenging("enable-thumb-reg-scavenging",
- cl::Hidden,
- cl::desc("Enable register scavenging on Thumb"));
+extern cl::opt<bool> ReuseFrameIndexVals;
Thumb1RegisterInfo::Thumb1RegisterInfo(const ARMBaseInstrInfo &tii,
const ARMSubtarget &sti)
unsigned PredReg) const {
MachineFunction &MF = *MBB.getParent();
MachineConstantPool *ConstantPool = MF.getConstantPool();
- Constant *C = ConstantInt::get(Type::Int32Ty, Val);
+ Constant *C = ConstantInt::get(
+ Type::getInt32Ty(MBB.getParent()->getFunction()->getContext()), Val);
unsigned Idx = ConstantPool->getConstantPoolIndex(C, 4);
BuildMI(MBB, MBBI, dl, TII.get(ARM::tLDRcp))
}
const TargetRegisterClass*
-Thumb1RegisterInfo::getPhysicalRegisterRegClass(unsigned Reg, MVT VT) const {
+Thumb1RegisterInfo::getPhysicalRegisterRegClass(unsigned Reg, EVT VT) const {
if (isARMLowRegister(Reg))
return ARM::tGPRRegisterClass;
switch (Reg) {
return TargetRegisterInfo::getPhysicalRegisterRegClass(Reg, VT);
}
-bool
-Thumb1RegisterInfo::requiresRegisterScavenging(const MachineFunction &MF) const {
- return ThumbRegScavenging;
-}
-
bool Thumb1RegisterInfo::hasReservedCallFrame(MachineFunction &MF) const {
const MachineFrameInfo *FFI = MF.getFrameInfo();
unsigned CFSize = FFI->getMaxCallFrameSize();
const TargetInstrInfo &TII,
const Thumb1RegisterInfo& MRI,
DebugLoc dl) {
+ MachineFunction &MF = *MBB.getParent();
bool isHigh = !isARMLowRegister(DestReg) ||
(BaseReg != 0 && !isARMLowRegister(BaseReg));
bool isSub = false;
unsigned LdReg = DestReg;
if (DestReg == ARM::SP) {
assert(BaseReg == ARM::SP && "Unexpected!");
- LdReg = ARM::R3;
- BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVlor2hir), ARM::R12)
- .addReg(ARM::R3, RegState::Kill);
+ LdReg = MF.getRegInfo().createVirtualRegister(ARM::tGPRRegisterClass);
}
if (NumBytes <= 255 && NumBytes >= 0)
else
MIB.addReg(LdReg).addReg(BaseReg, RegState::Kill);
AddDefaultPred(MIB);
-
- if (DestReg == ARM::SP)
- BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVhir2lor), ARM::R3)
- .addReg(ARM::R12, RegState::Kill);
}
/// calcNumMI - Returns the number of instructions required to materialize
int Thumb1RegisterInfo::
rewriteFrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
- unsigned MOVOpc, unsigned ADDriOpc, unsigned SUBriOpc,
- unsigned FrameReg, int Offset) const
+ unsigned FrameReg, int Offset,
+ unsigned MOVOpc, unsigned ADDriOpc, unsigned SUBriOpc) const
{
// if/when eliminateFrameIndex() conforms with ARMBaseRegisterInfo
// version then can pull out Thumb1 specific parts here
return 0;
}
-void Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
- int SPAdj, RegScavenger *RS) const{
+/// saveScavengerRegister - Spill the register so it can be used by the
+/// register scavenger. Return true.
+bool
+Thumb1RegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ MachineBasicBlock::iterator &UseMI,
+ const TargetRegisterClass *RC,
+ unsigned Reg) const {
+ // Thumb1 can't use the emergency spill slot on the stack because
+ // ldr/str immediate offsets must be positive, and if we're referencing
+ // off the frame pointer (if, for example, there are alloca() calls in
+ // the function, the offset will be negative. Use R12 instead since that's
+ // a call clobbered register that we know won't be used in Thumb1 mode.
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ BuildMI(MBB, I, DL, TII.get(ARM::tMOVtgpr2gpr)).
+ addReg(ARM::R12, RegState::Define).addReg(Reg, RegState::Kill);
+
+ // The UseMI is where we would like to restore the register. If there's
+ // interference with R12 before then, however, we'll need to restore it
+ // before that instead and adjust the UseMI.
+ bool done = false;
+ for (MachineBasicBlock::iterator II = I; !done && II != UseMI ; ++II) {
+ // If this instruction affects R12, adjust our restore point.
+ for (unsigned i = 0, e = II->getNumOperands(); i != e; ++i) {
+ const MachineOperand &MO = II->getOperand(i);
+ if (!MO.isReg() || MO.isUndef() || !MO.getReg() ||
+ TargetRegisterInfo::isVirtualRegister(MO.getReg()))
+ continue;
+ if (MO.getReg() == ARM::R12) {
+ UseMI = II;
+ done = true;
+ break;
+ }
+ }
+ }
+ // Restore the register from R12
+ BuildMI(MBB, UseMI, DL, TII.get(ARM::tMOVgpr2tgpr)).
+ addReg(Reg, RegState::Define).addReg(ARM::R12, RegState::Kill);
+
+ return true;
+}
+
+unsigned
+Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
+ int SPAdj, FrameIndexValue *Value,
+ RegScavenger *RS) const{
+ unsigned VReg = 0;
unsigned i = 0;
MachineInstr &MI = *II;
MachineBasicBlock &MBB = *MI.getParent();
Offset -= AFI->getGPRCalleeSavedArea1Offset();
else if (AFI->isGPRCalleeSavedArea2Frame(FrameIndex))
Offset -= AFI->getGPRCalleeSavedArea2Offset();
- else if (hasFP(MF)) {
- assert(SPAdj == 0 && "Unexpected");
- // There is alloca()'s in this function, must reference off the frame
+ else if (MF.getFrameInfo()->hasVarSizedObjects()) {
+ assert(SPAdj == 0 && hasFP(MF) && "Unexpected");
+ // There are alloca()'s in this function, must reference off the frame
// pointer instead.
FrameReg = getFrameRegister(MF);
Offset -= AFI->getFramePtrSpillOffset();
"Thumb add/sub sp, #imm immediate must be multiple of 4!");
}
- if (Offset == 0) {
+ unsigned PredReg;
+ if (Offset == 0 && getInstrPredicate(&MI, PredReg) == ARMCC::AL) {
// Turn it into a move.
- MI.setDesc(TII.get(ARM::tMOVhir2lor));
+ MI.setDesc(TII.get(ARM::tMOVgpr2tgpr));
MI.getOperand(i).ChangeToRegister(FrameReg, false);
- MI.RemoveOperand(i+1);
- return;
+ // Remove offset and remaining explicit predicate operands.
+ do MI.RemoveOperand(i+1);
+ while (MI.getNumOperands() > i+1 &&
+ (!MI.getOperand(i+1).isReg() || !MI.getOperand(i+1).isImm()));
+ return 0;
}
// Common case: small offset, fits into instruction.
MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.getOperand(i+1).ChangeToImmediate(Offset / Scale);
}
- return;
+ return 0;
}
unsigned DestReg = MI.getOperand(0).getReg();
emitThumbRegPlusImmediate(MBB, II, DestReg, FrameReg, Offset, TII,
*this, dl);
MBB.erase(II);
- return;
+ return 0;
}
if (Offset > 0) {
MI.getOperand(i+1).ChangeToImmediate(Mask);
}
Offset = (Offset - Mask * Scale);
- MachineBasicBlock::iterator NII = next(II);
+ MachineBasicBlock::iterator NII = llvm::next(II);
emitThumbRegPlusImmediate(MBB, NII, DestReg, DestReg, Offset, TII,
*this, dl);
} else {
// r0 = -imm (this is then translated into a series of instructons)
// r0 = add r0, sp
emitThumbConstant(MBB, II, DestReg, Offset, TII, *this, dl);
+
MI.setDesc(TII.get(ARM::tADDhirr));
MI.getOperand(i).ChangeToRegister(DestReg, false, false, true);
MI.getOperand(i+1).ChangeToRegister(FrameReg, false);
+ if (Opcode == ARM::tADDi3) {
+ MachineInstrBuilder MIB(&MI);
+ AddDefaultPred(MIB);
+ }
}
- return;
+ return 0;
} else {
unsigned ImmIdx = 0;
int InstrOffs = 0;
// Replace the FrameIndex with sp
MI.getOperand(i).ChangeToRegister(FrameReg, false);
ImmOp.ChangeToImmediate(ImmedOffset);
- return;
+ return 0;
}
bool isThumSpillRestore = Opcode == ARM::tRestore || Opcode == ARM::tSpill;
else // tLDR has an extra register operand.
MI.addOperand(MachineOperand::CreateReg(0, false));
} else if (Desc.mayStore()) {
- // 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
- // r2 = r12
- unsigned ValReg = MI.getOperand(0).getReg();
- unsigned TmpReg = ARM::R3;
- bool UseRR = false;
- if (ValReg == ARM::R3) {
- BuildMI(MBB, II, dl, TII.get(ARM::tMOVlor2hir), ARM::R12)
- .addReg(ARM::R2, RegState::Kill);
- TmpReg = ARM::R2;
- }
- if (TmpReg == ARM::R3 && AFI->isR3LiveIn())
- BuildMI(MBB, II, dl, TII.get(ARM::tMOVlor2hir), ARM::R12)
- .addReg(ARM::R3, RegState::Kill);
- if (Opcode == ARM::tSpill) {
- if (FrameReg == ARM::SP)
- emitThumbRegPlusImmInReg(MBB, II, TmpReg, FrameReg,
- Offset, false, TII, *this, dl);
- else {
- emitLoadConstPool(MBB, II, dl, TmpReg, 0, Offset);
- UseRR = true;
- }
- } else
- emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg, Offset, TII,
- *this, dl);
- MI.setDesc(TII.get(ARM::tSTR));
- MI.getOperand(i).ChangeToRegister(TmpReg, false, false, true);
- if (UseRR) // Use [reg, reg] addrmode.
- MI.addOperand(MachineOperand::CreateReg(FrameReg, false));
- else // tSTR has an extra register operand.
- MI.addOperand(MachineOperand::CreateReg(0, false));
-
- MachineBasicBlock::iterator NII = next(II);
- if (ValReg == ARM::R3)
- BuildMI(MBB, NII, dl, TII.get(ARM::tMOVhir2lor), ARM::R2)
- .addReg(ARM::R12, RegState::Kill);
- if (TmpReg == ARM::R3 && AFI->isR3LiveIn())
- BuildMI(MBB, NII, dl, TII.get(ARM::tMOVhir2lor), ARM::R3)
- .addReg(ARM::R12, RegState::Kill);
+ VReg = MF.getRegInfo().createVirtualRegister(ARM::tGPRRegisterClass);
+ assert (Value && "Frame index virtual allocated, but Value arg is NULL!");
+ bool UseRR = false;
+ bool TrackVReg = true;
+ Value->first = FrameReg; // use the frame register as a kind indicator
+ Value->second = Offset;
+
+ if (Opcode == ARM::tSpill) {
+ if (FrameReg == ARM::SP)
+ emitThumbRegPlusImmInReg(MBB, II, VReg, FrameReg,
+ Offset, false, TII, *this, dl);
+ else {
+ emitLoadConstPool(MBB, II, dl, VReg, 0, Offset);
+ UseRR = true;
+ TrackVReg = false;
+ }
+ } else
+ emitThumbRegPlusImmediate(MBB, II, VReg, FrameReg, Offset, TII,
+ *this, dl);
+ MI.setDesc(TII.get(ARM::tSTR));
+ MI.getOperand(i).ChangeToRegister(VReg, false, false, true);
+ if (UseRR) // Use [reg, reg] addrmode.
+ MI.addOperand(MachineOperand::CreateReg(FrameReg, false));
+ else // tSTR has an extra register operand.
+ MI.addOperand(MachineOperand::CreateReg(0, false));
+ if (!ReuseFrameIndexVals || !TrackVReg)
+ VReg = 0;
} else
assert(false && "Unexpected opcode!");
MachineInstrBuilder MIB(&MI);
AddDefaultPred(MIB);
}
+ return VReg;
}
void Thumb1RegisterInfo::emitPrologue(MachineFunction &MF) const {
DebugLoc dl = (MBBI != MBB.end() ?
MBBI->getDebugLoc() : DebugLoc::getUnknownLoc());
- // Check if R3 is live in. It might have to be used as a scratch register.
- for (MachineRegisterInfo::livein_iterator I =MF.getRegInfo().livein_begin(),
- E = MF.getRegInfo().livein_end(); I != E; ++I) {
- if (I->first == ARM::R3) {
- AFI->setR3IsLiveIn(true);
- break;
- }
- }
-
// Thumb add/sub sp, imm8 instructions implicitly multiply the offset by 4.
NumBytes = (NumBytes + 3) & ~3;
MFI->setStackSize(NumBytes);
// Darwin ABI requires FP to point to the stack slot that contains the
// previous FP.
if (STI.isTargetDarwin() || hasFP(MF)) {
- MachineInstrBuilder MIB =
- BuildMI(MBB, MBBI, dl, TII.get(ARM::tADDrSPi), FramePtr)
+ BuildMI(MBB, MBBI, dl, TII.get(ARM::tADDrSPi), FramePtr)
.addFrameIndex(FramePtrSpillFI).addImm(0);
}
}
static bool isCSRestore(MachineInstr *MI, const unsigned *CSRegs) {
- return (MI->getOpcode() == ARM::tRestore &&
- MI->getOperand(1).isFI() &&
- isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs));
+ if (MI->getOpcode() == ARM::tRestore &&
+ MI->getOperand(1).isFI() &&
+ isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs))
+ return true;
+ else if (MI->getOpcode() == ARM::tPOP) {
+ // The first three operands are predicates and such. The last two are
+ // imp-def and imp-use of SP. Check everything in between.
+ for (int i = 3, e = MI->getNumOperands() - 2; i != e; ++i)
+ if (!isCalleeSavedRegister(MI->getOperand(i).getReg(), CSRegs))
+ return false;
+ return true;
+ }
+ return false;
}
void Thumb1RegisterInfo::emitEpilogue(MachineFunction &MF,
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
unsigned VARegSaveSize = AFI->getVarArgsRegSaveSize();
int NumBytes = (int)MFI->getStackSize();
+ const unsigned *CSRegs = getCalleeSavedRegs();
if (!AFI->hasStackFrame()) {
if (NumBytes != 0)
emitSPUpdate(MBB, MBBI, TII, dl, *this, NumBytes);
} else {
- // Unwind MBBI to point to first LDR / FLDD.
- const unsigned *CSRegs = getCalleeSavedRegs();
+ // Unwind MBBI to point to first LDR / VLDRD.
if (MBBI != MBB.begin()) {
do
--MBBI;
emitThumbRegPlusImmediate(MBB, MBBI, ARM::SP, FramePtr, -NumBytes,
TII, *this, dl);
else
- BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVlor2hir), ARM::SP)
+ BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVtgpr2gpr), ARM::SP)
.addReg(FramePtr);
} else {
if (MBBI->getOpcode() == ARM::tBX_RET &&
}
if (VARegSaveSize) {
+ // Unlike T2 and ARM mode, the T1 pop instruction cannot restore
+ // to LR, and we can't pop the value directly to the PC since
+ // we need to update the SP after popping the value. Therefore, we
+ // pop the old LR into R3 as a temporary.
+
+ // Move back past the callee-saved register restoration
+ while (MBBI != MBB.end() && isCSRestore(MBBI, CSRegs))
+ ++MBBI;
// Epilogue for vararg functions: pop LR to R3 and branch off it.
- // FIXME: Verify this is still ok when R3 is no longer being reserved.
- BuildMI(MBB, MBBI, dl, TII.get(ARM::tPOP)).addReg(ARM::R3);
+ AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tPOP)))
+ .addReg(0) // No write back.
+ .addReg(ARM::R3, RegState::Define);
emitSPUpdate(MBB, MBBI, TII, dl, *this, VARegSaveSize);
- BuildMI(MBB, MBBI, dl, TII.get(ARM::tBX_RET_vararg)).addReg(ARM::R3);
+ BuildMI(MBB, MBBI, dl, TII.get(ARM::tBX_RET_vararg))
+ .addReg(ARM::R3, RegState::Kill);
+ // erase the old tBX_RET instruction
MBB.erase(MBBI);
}
}