forked from OSchip/llvm-project
Spill / restore should avoid modifying the condition register.
llvm-svn: 33971
This commit is contained in:
parent
dc0a9a7b4a
commit
ec13f826a2
|
@ -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) {
|
||||||
|
|
|
@ -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", []>;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
|
|
Loading…
Reference in New Issue