Spill / restore should avoid modifying the condition register.

llvm-svn: 33971
This commit is contained in:
Evan Cheng 2007-02-07 00:06:56 +00:00
parent dc0a9a7b4a
commit ec13f826a2
4 changed files with 64 additions and 36 deletions

View File

@ -83,7 +83,7 @@ unsigned ARMInstrInfo::isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) co
return MI->getOperand(0).getReg(); return MI->getOperand(0).getReg();
} }
break; break;
case ARM::tLDRspi: case ARM::tRestore:
if (MI->getOperand(1).isFrameIndex() && if (MI->getOperand(1).isFrameIndex() &&
MI->getOperand(2).isImmediate() && MI->getOperand(2).isImmediate() &&
MI->getOperand(2).getImmedValue() == 0) { MI->getOperand(2).getImmedValue() == 0) {
@ -117,7 +117,7 @@ unsigned ARMInstrInfo::isStoreToStackSlot(MachineInstr *MI, int &FrameIndex) con
return MI->getOperand(0).getReg(); return MI->getOperand(0).getReg();
} }
break; break;
case ARM::tSTRspi: case ARM::tSpill:
if (MI->getOperand(1).isFrameIndex() && if (MI->getOperand(1).isFrameIndex() &&
MI->getOperand(2).isImmediate() && MI->getOperand(2).isImmediate() &&
MI->getOperand(2).getImmedValue() == 0) { MI->getOperand(2).getImmedValue() == 0) {

View File

@ -239,6 +239,11 @@ def tLDRspi : TIs<(ops GPR:$dst, t_addrmode_sp:$addr),
"ldr $dst, $addr", "ldr $dst, $addr",
[(set GPR:$dst, (load t_addrmode_sp:$addr))]>; [(set GPR:$dst, (load t_addrmode_sp:$addr))]>;
// Special instruction for restore. It cannot clobber condition register
// when it's expanded by eliminateCallFramePseudoInstr().
def tRestore : TIs<(ops GPR:$dst, t_addrmode_sp:$addr),
"ldr $dst, $addr", []>;
// Load tconstpool // Load tconstpool
def tLDRpci : TIs<(ops GPR:$dst, i32imm:$addr), def tLDRpci : TIs<(ops GPR:$dst, i32imm:$addr),
"ldr $dst, $addr", "ldr $dst, $addr",
@ -261,6 +266,11 @@ def tSTRH : TI2<(ops GPR:$src, t_addrmode_s2:$addr),
def tSTRspi : TIs<(ops GPR:$src, t_addrmode_sp:$addr), def tSTRspi : TIs<(ops GPR:$src, t_addrmode_sp:$addr),
"str $src, $addr", "str $src, $addr",
[(store GPR:$src, t_addrmode_sp:$addr)]>; [(store GPR:$src, t_addrmode_sp:$addr)]>;
// Special instruction for spill. It cannot clobber condition register
// when it's expanded by eliminateCallFramePseudoInstr().
def tSpill : TIs<(ops GPR:$src, t_addrmode_sp:$addr),
"str $src, $addr", []>;
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -130,7 +130,7 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
MachineFunction &MF = *MBB.getParent(); MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
if (AFI->isThumbFunction()) if (AFI->isThumbFunction())
BuildMI(MBB, I, TII.get(ARM::tSTRspi)).addReg(SrcReg) BuildMI(MBB, I, TII.get(ARM::tSpill)).addReg(SrcReg)
.addFrameIndex(FI).addImm(0); .addFrameIndex(FI).addImm(0);
else else
BuildMI(MBB, I, TII.get(ARM::STR)).addReg(SrcReg) BuildMI(MBB, I, TII.get(ARM::STR)).addReg(SrcReg)
@ -153,7 +153,7 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
MachineFunction &MF = *MBB.getParent(); MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
if (AFI->isThumbFunction()) if (AFI->isThumbFunction())
BuildMI(MBB, I, TII.get(ARM::tLDRspi), DestReg) BuildMI(MBB, I, TII.get(ARM::tRestore), DestReg)
.addFrameIndex(FI).addImm(0); .addFrameIndex(FI).addImm(0);
else else
BuildMI(MBB, I, TII.get(ARM::LDR), DestReg) BuildMI(MBB, I, TII.get(ARM::LDR), DestReg)
@ -220,16 +220,16 @@ MachineInstr *ARMRegisterInfo::foldMemoryOperand(MachineInstr *MI,
if (OpNum == 0) { // move -> store if (OpNum == 0) { // move -> store
unsigned SrcReg = MI->getOperand(1).getReg(); unsigned SrcReg = MI->getOperand(1).getReg();
if (!isLowRegister(SrcReg)) if (!isLowRegister(SrcReg))
// tSTRspi cannot take a high register operand. // tSpill cannot take a high register operand.
break; break;
NewMI = BuildMI(TII.get(ARM::tSTRspi)).addReg(SrcReg).addFrameIndex(FI) NewMI = BuildMI(TII.get(ARM::tSpill)).addReg(SrcReg).addFrameIndex(FI)
.addImm(0); .addImm(0);
} else { // move -> load } else { // move -> load
unsigned DstReg = MI->getOperand(0).getReg(); unsigned DstReg = MI->getOperand(0).getReg();
if (!isLowRegister(DstReg)) if (!isLowRegister(DstReg))
// tLDRspi cannot target a high register operand. // tRestore cannot target a high register operand.
break; break;
NewMI = BuildMI(TII.get(ARM::tLDRspi), DstReg).addFrameIndex(FI) NewMI = BuildMI(TII.get(ARM::tRestore), DstReg).addFrameIndex(FI)
.addImm(0); .addImm(0);
} }
break; break;
@ -412,7 +412,7 @@ void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
if (isSub) Bytes = -NumBytes; if (isSub) Bytes = -NumBytes;
bool isMul4 = (Bytes & 3) == 0; bool isMul4 = (Bytes & 3) == 0;
bool isTwoAddr = false; bool isTwoAddr = false;
bool DstNeBase = false; bool DstNotEqBase = false;
unsigned NumBits = 1; unsigned NumBits = 1;
unsigned Scale = 1; unsigned Scale = 1;
int Opc = 0; int Opc = 0;
@ -441,14 +441,14 @@ void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
// r1 = sub sp, c // r1 = sub sp, c
// r8 = sub sp, c // r8 = sub sp, c
if (DestReg != BaseReg) if (DestReg != BaseReg)
DstNeBase = true; DstNotEqBase = true;
NumBits = 8; NumBits = 8;
Opc = isSub ? ARM::tSUBi8 : ARM::tADDi8; Opc = isSub ? ARM::tSUBi8 : ARM::tADDi8;
isTwoAddr = true; isTwoAddr = true;
} }
unsigned NumMIs = calcNumMI(Opc, ExtraOpc, Bytes, NumBits, Scale); unsigned NumMIs = calcNumMI(Opc, ExtraOpc, Bytes, NumBits, Scale);
unsigned Threshold = (DestReg == ARM::SP) ? 4 : 3; unsigned Threshold = (DestReg == ARM::SP) ? 3 : 2;
if (NumMIs > Threshold) { if (NumMIs > Threshold) {
// This will expand into too many instructions. Load the immediate from a // This will expand into too many instructions. Load the immediate from a
// constpool entry. // constpool entry.
@ -456,7 +456,7 @@ void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
return; return;
} }
if (DstNeBase) { if (DstNotEqBase) {
if (isLowRegister(DestReg) && isLowRegister(BaseReg)) { if (isLowRegister(DestReg) && isLowRegister(BaseReg)) {
// If both are low registers, emit DestReg = add BaseReg, max(Imm, 7) // If both are low registers, emit DestReg = add BaseReg, max(Imm, 7)
unsigned Chunk = (1 << 3) - 1; unsigned Chunk = (1 << 3) - 1;
@ -730,27 +730,20 @@ void ARMRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II) const{
isSub = true; isSub = true;
} }
if (!isSub || !isThumb) { MachineOperand &ImmOp = MI.getOperand(ImmIdx);
MachineOperand &ImmOp = MI.getOperand(ImmIdx); int ImmedOffset = Offset / Scale;
int ImmedOffset = Offset / Scale; unsigned Mask = (1 << NumBits) - 1;
unsigned Mask = (1 << NumBits) - 1; if ((unsigned)Offset <= Mask * Scale) {
if ((unsigned)Offset <= Mask * Scale) { // Replace the FrameIndex with sp
// Replace the FrameIndex with sp MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.getOperand(i).ChangeToRegister(FrameReg, false); if (isSub)
if (isSub) ImmedOffset |= 1 << NumBits;
ImmedOffset |= 1 << NumBits; ImmOp.ChangeToImmediate(ImmedOffset);
ImmOp.ChangeToImmediate(ImmedOffset); return;
return; }
}
if (!isThumb) {
// Otherwise, it didn't fit. Pull in what we can to simplify the immed. // Otherwise, it didn't fit. Pull in what we can to simplify the immed.
if (AddrMode == ARMII::AddrModeTs) {
// Thumb tLDRspi, tSTRspi. These will change to instructions that use
// a different base register.
NumBits = 5;
Mask = (1 << NumBits) - 1;
}
ImmedOffset = ImmedOffset & Mask; ImmedOffset = ImmedOffset & Mask;
if (isSub) if (isSub)
ImmedOffset |= 1 << NumBits; ImmedOffset |= 1 << NumBits;
@ -768,8 +761,12 @@ void ARMRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II) const{
if (TII.isLoad(Opcode)) { if (TII.isLoad(Opcode)) {
// Use the destination register to materialize sp + offset. // Use the destination register to materialize sp + offset.
unsigned TmpReg = MI.getOperand(0).getReg(); unsigned TmpReg = MI.getOperand(0).getReg();
emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg, if (Opcode == ARM::tRestore)
isSub ? -Offset : Offset, TII); emitThumbRegPlusConstPool(MBB, II, TmpReg, FrameReg,
isSub ? -Offset : Offset, TII);
else
emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg,
isSub ? -Offset : Offset, TII);
MI.setInstrDescriptor(TII.get(ARM::tLDR)); MI.setInstrDescriptor(TII.get(ARM::tLDR));
MI.getOperand(i).ChangeToRegister(TmpReg, false); MI.getOperand(i).ChangeToRegister(TmpReg, false);
MI.addRegOperand(0, false); // tLDR has an extra register operand. MI.addRegOperand(0, false); // tLDR has an extra register operand.
@ -788,8 +785,12 @@ void ARMRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II) const{
BuildMI(MBB, II, TII.get(ARM::tMOVrr), ARM::R12).addReg(ARM::R2); BuildMI(MBB, II, TII.get(ARM::tMOVrr), ARM::R12).addReg(ARM::R2);
TmpReg = ARM::R2; TmpReg = ARM::R2;
} }
emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg, if (Opcode == ARM::tSpill)
isSub ? -Offset : Offset, TII); emitThumbRegPlusConstPool(MBB, II, TmpReg, FrameReg,
isSub ? -Offset : Offset, TII);
else
emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg,
isSub ? -Offset : Offset, TII);
MI.setInstrDescriptor(TII.get(ARM::tSTR)); MI.setInstrDescriptor(TII.get(ARM::tSTR));
MI.getOperand(i).ChangeToRegister(TmpReg, false); MI.getOperand(i).ChangeToRegister(TmpReg, false);
MI.addRegOperand(0, false); // tSTR has an extra register operand. MI.addRegOperand(0, false); // tSTR has an extra register operand.
@ -1098,7 +1099,7 @@ static bool isCalleeSavedRegister(unsigned Reg, const unsigned *CSRegs) {
static bool isCSRestore(MachineInstr *MI, const unsigned *CSRegs) { static bool isCSRestore(MachineInstr *MI, const unsigned *CSRegs) {
return ((MI->getOpcode() == ARM::FLDD || return ((MI->getOpcode() == ARM::FLDD ||
MI->getOpcode() == ARM::LDR || MI->getOpcode() == ARM::LDR ||
MI->getOpcode() == ARM::tLDRspi) && MI->getOpcode() == ARM::tRestore) &&
MI->getOperand(1).isFrameIndex() && MI->getOperand(1).isFrameIndex() &&
isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs)); isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs));
} }

View File

@ -124,3 +124,20 @@ L12:
.align 2 .align 2
L11: L11:
.long 642 .long 642
//===---------------------------------------------------------------------===//
When spilling in thumb mode and the sp offset is too large to fit in the ldr /
str offset field, we load the offset from a constpool entry and add it to sp:
ldr r2, LCPI
add r2, sp
ldr r2, [r2]
These instructions preserve the condition code which is important if the spill
is between a cmp and a bcc instruction. However, we can use the (potentially)
cheaper sequnce if we know it's ok to clobber the condition register.
add r2, sp, #255 * 4
add r2, #132
ldr r2, [r2, #7 * 4]