Add Thumb1 support for virtual frame indices.

rdar://8277890



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@111533 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jim Grosbach 2010-08-19 17:52:13 +00:00
parent c546c75459
commit 74d7b0af58
3 changed files with 197 additions and 169 deletions

View File

@ -1385,13 +1385,6 @@ needsFrameBaseReg(MachineInstr *MI, unsigned operand) const {
// FIXME: For testing, return true for all loads/stores and false for
// everything else. We want to create lots of base regs to shake out bugs.
//
// FIXME: This is Thumb2/ARM only for now to keep it simpler.
ARMFunctionInfo *AFI =
MI->getParent()->getParent()->getInfo<ARMFunctionInfo>();
if (AFI->isThumb1OnlyFunction())
return false;
unsigned Opc = MI->getOpcode();
switch (Opc) {
@ -1401,6 +1394,7 @@ needsFrameBaseReg(MachineInstr *MI, unsigned operand) const {
case ARM::t2STRi12: case ARM::t2STRi8:
case ARM::VLDRS: case ARM::VLDRD:
case ARM::VSTRS: case ARM::VSTRD:
case ARM::tSTRspi: case ARM::tLDRspi:
return true;
default:
return false;
@ -1414,14 +1408,14 @@ materializeFrameBaseRegister(MachineBasicBlock::iterator I,
unsigned BaseReg, int FrameIdx) const {
ARMFunctionInfo *AFI =
I->getParent()->getParent()->getInfo<ARMFunctionInfo>();
unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : ARM::t2ADDri;
assert(!AFI->isThumb1OnlyFunction() &&
"This materializeFrameBaseRegister does not support Thumb1!");
unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri :
(AFI->isThumb1OnlyFunction() ? ARM::tADDrSPi : ARM::t2ADDri);
MachineInstrBuilder MIB =
BuildMI(*I->getParent(), I, I->getDebugLoc(), TII.get(ADDriOpc), BaseReg)
.addFrameIndex(FrameIdx).addImm(0);
AddDefaultCC(AddDefaultPred(MIB));
if (!AFI->isThumb1OnlyFunction())
AddDefaultCC(AddDefaultPred(MIB));
}
void
@ -1469,13 +1463,14 @@ bool ARMBaseRegisterInfo::isBaseRegInRange(const MachineInstr *MI,
unsigned NumBits = 0;
unsigned Scale = 1;
unsigned ImmIdx = 0;
int InstrOffs;
int InstrOffs = 0;;
switch(AddrMode) {
case ARMII::AddrModeT2_i8:
case ARMII::AddrModeT2_i12:
// i8 supports only negative, and i12 supports only positive, so
// based on Offset sign, consider the appropriate instruction
Offset += MI->getOperand(i+1).getImm();
InstrOffs = MI->getOperand(i+1).getImm();
Scale = 1;
if (Offset < 0) {
NumBits = 8;
Offset = -Offset;
@ -1509,6 +1504,13 @@ bool ARMBaseRegisterInfo::isBaseRegInRange(const MachineInstr *MI,
NumBits = 8;
break;
}
case ARMII::AddrModeT1_s: {
ImmIdx = i+1;
InstrOffs = MI->getOperand(ImmIdx).getImm();
NumBits = 5;
Scale = 4;
break;
}
default:
llvm_unreachable("Unsupported addressing mode!");
break;

View File

@ -363,14 +363,173 @@ static void removeOperands(MachineInstr &MI, unsigned i) {
MI.RemoveOperand(Op);
}
int Thumb1RegisterInfo::
rewriteFrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
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;
bool Thumb1RegisterInfo::
rewriteFrameIndex(MachineBasicBlock::iterator II, unsigned FrameRegIdx,
unsigned FrameReg, int &Offset,
const ARMBaseInstrInfo &TII) const {
MachineInstr &MI = *II;
MachineBasicBlock &MBB = *MI.getParent();
DebugLoc dl = MI.getDebugLoc();
unsigned Opcode = MI.getOpcode();
const TargetInstrDesc &Desc = MI.getDesc();
unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
if (Opcode == ARM::tADDrSPi) {
Offset += MI.getOperand(FrameRegIdx+1).getImm();
// Can't use tADDrSPi if it's based off the frame pointer.
unsigned NumBits = 0;
unsigned Scale = 1;
if (FrameReg != ARM::SP) {
Opcode = ARM::tADDi3;
MI.setDesc(TII.get(Opcode));
NumBits = 3;
} else {
NumBits = 8;
Scale = 4;
assert((Offset & 3) == 0 &&
"Thumb add/sub sp, #imm immediate must be multiple of 4!");
}
unsigned PredReg;
if (Offset == 0 && getInstrPredicate(&MI, PredReg) == ARMCC::AL) {
// Turn it into a move.
MI.setDesc(TII.get(ARM::tMOVgpr2tgpr));
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
// Remove offset and remaining explicit predicate operands.
do MI.RemoveOperand(FrameRegIdx+1);
while (MI.getNumOperands() > FrameRegIdx+1 &&
(!MI.getOperand(FrameRegIdx+1).isReg() ||
!MI.getOperand(FrameRegIdx+1).isImm()));
return true;
}
// Common case: small offset, fits into instruction.
unsigned Mask = (1 << NumBits) - 1;
if (((Offset / Scale) & ~Mask) == 0) {
// Replace the FrameIndex with sp / fp
if (Opcode == ARM::tADDi3) {
removeOperands(MI, FrameRegIdx);
MachineInstrBuilder MIB(&MI);
AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg)
.addImm(Offset / Scale));
} else {
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset / Scale);
}
return true;
}
unsigned DestReg = MI.getOperand(0).getReg();
unsigned Bytes = (Offset > 0) ? Offset : -Offset;
unsigned NumMIs = calcNumMI(Opcode, 0, Bytes, NumBits, Scale);
// 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,
*this, dl);
MBB.erase(II);
return true;
}
if (Offset > 0) {
// Translate r0 = add sp, imm to
// r0 = add sp, 255*4
// r0 = add r0, (imm - 255*4)
if (Opcode == ARM::tADDi3) {
removeOperands(MI, FrameRegIdx);
MachineInstrBuilder MIB(&MI);
AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg).addImm(Mask));
} else {
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Mask);
}
Offset = (Offset - Mask * Scale);
MachineBasicBlock::iterator NII = llvm::next(II);
emitThumbRegPlusImmediate(MBB, NII, DestReg, DestReg, Offset, TII,
*this, dl);
} 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, *this, dl);
MI.setDesc(TII.get(ARM::tADDhirr));
MI.getOperand(FrameRegIdx).ChangeToRegister(DestReg, false, false, true);
MI.getOperand(FrameRegIdx+1).ChangeToRegister(FrameReg, false);
if (Opcode == ARM::tADDi3) {
MachineInstrBuilder MIB(&MI);
AddDefaultPred(MIB);
}
}
return true;
} else {
unsigned ImmIdx = 0;
int InstrOffs = 0;
unsigned NumBits = 0;
unsigned Scale = 1;
switch (AddrMode) {
case ARMII::AddrModeT1_s: {
ImmIdx = FrameRegIdx+1;
InstrOffs = MI.getOperand(ImmIdx).getImm();
NumBits = (FrameReg == ARM::SP) ? 8 : 5;
Scale = 4;
break;
}
default:
llvm_unreachable("Unsupported addressing mode!");
break;
}
Offset += InstrOffs * Scale;
assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
// 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(FrameRegIdx).ChangeToRegister(FrameReg, false);
ImmOp.ChangeToImmediate(ImmedOffset);
return true;
}
bool isThumSpillRestore = Opcode == ARM::tRestore || Opcode == ARM::tSpill;
if (AddrMode == ARMII::AddrModeT1_s) {
// Thumb tLDRspi, tSTRspi. These will change to instructions that use
// a different base register.
NumBits = 5;
Mask = (1 << NumBits) - 1;
}
// If this is a thumb spill / restore, we will be using a constpool load to
// materialize the offset.
if (AddrMode == ARMII::AddrModeT1_s && isThumSpillRestore)
ImmOp.ChangeToImmediate(0);
else {
// Otherwise, it didn't fit. Pull in what we can to simplify the immed.
ImmedOffset = ImmedOffset & Mask;
ImmOp.ChangeToImmediate(ImmedOffset);
Offset &= ~(Mask*Scale);
}
}
return Offset == 0;
}
void
Thumb1RegisterInfo::resolveFrameIndex(MachineBasicBlock::iterator I,
unsigned BaseReg, int64_t Offset) const {
MachineInstr &MI = *I;
int Off = Offset; // ARM doesn't need the general 64-bit offsets
unsigned i = 0;
while (!MI.getOperand(i).isFI()) {
++i;
assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
}
bool Done = false;
Done = rewriteFrameIndex(MI, i, BaseReg, Off, TII);
assert (Done && "Unable to resolve frame index!");
}
/// saveScavengerRegister - Spill the register so it can be used by the
@ -458,154 +617,20 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
return 0;
}
unsigned Opcode = MI.getOpcode();
const TargetInstrDesc &Desc = MI.getDesc();
unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
if (Opcode == ARM::tADDrSPi) {
Offset += MI.getOperand(i+1).getImm();
// Can't use tADDrSPi if it's based off the frame pointer.
unsigned NumBits = 0;
unsigned Scale = 1;
if (FrameReg != ARM::SP) {
Opcode = ARM::tADDi3;
MI.setDesc(TII.get(Opcode));
NumBits = 3;
} else {
NumBits = 8;
Scale = 4;
assert((Offset & 3) == 0 &&
"Thumb add/sub sp, #imm immediate must be multiple of 4!");
}
unsigned PredReg;
if (Offset == 0 && getInstrPredicate(&MI, PredReg) == ARMCC::AL) {
// Turn it into a move.
MI.setDesc(TII.get(ARM::tMOVgpr2tgpr));
MI.getOperand(i).ChangeToRegister(FrameReg, false);
// 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.
unsigned Mask = (1 << NumBits) - 1;
if (((Offset / Scale) & ~Mask) == 0) {
// Replace the FrameIndex with sp / fp
if (Opcode == ARM::tADDi3) {
removeOperands(MI, i);
MachineInstrBuilder MIB(&MI);
AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg)
.addImm(Offset / Scale));
} else {
MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.getOperand(i+1).ChangeToImmediate(Offset / Scale);
}
return 0;
}
unsigned DestReg = MI.getOperand(0).getReg();
unsigned Bytes = (Offset > 0) ? Offset : -Offset;
unsigned NumMIs = calcNumMI(Opcode, 0, Bytes, NumBits, Scale);
// 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,
*this, dl);
MBB.erase(II);
return 0;
}
if (Offset > 0) {
// Translate r0 = add sp, imm to
// r0 = add sp, 255*4
// r0 = add r0, (imm - 255*4)
if (Opcode == ARM::tADDi3) {
removeOperands(MI, i);
MachineInstrBuilder MIB(&MI);
AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg).addImm(Mask));
} else {
MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.getOperand(i+1).ChangeToImmediate(Mask);
}
Offset = (Offset - Mask * Scale);
MachineBasicBlock::iterator NII = llvm::next(II);
emitThumbRegPlusImmediate(MBB, NII, DestReg, DestReg, Offset, TII,
*this, dl);
} 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, *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);
}
}
// Modify MI as necessary to handle as much of 'Offset' as possible
assert(AFI->isThumbFunction() &&
"This eliminateFrameIndex only supports Thumb1!");
if (rewriteFrameIndex(MI, i, FrameReg, Offset, TII))
return 0;
} else {
unsigned ImmIdx = 0;
int InstrOffs = 0;
unsigned NumBits = 0;
unsigned Scale = 1;
switch (AddrMode) {
case ARMII::AddrModeT1_s: {
ImmIdx = i+1;
InstrOffs = MI.getOperand(ImmIdx).getImm();
NumBits = (FrameReg == ARM::SP) ? 8 : 5;
Scale = 4;
break;
}
default:
llvm_unreachable("Unsupported addressing mode!");
break;
}
Offset += InstrOffs * Scale;
assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
// 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);
ImmOp.ChangeToImmediate(ImmedOffset);
return 0;
}
bool isThumSpillRestore = Opcode == ARM::tRestore || Opcode == ARM::tSpill;
if (AddrMode == ARMII::AddrModeT1_s) {
// Thumb tLDRspi, tSTRspi. These will change to instructions that use
// a different base register.
NumBits = 5;
Mask = (1 << NumBits) - 1;
}
// If this is a thumb spill / restore, we will be using a constpool load to
// materialize the offset.
if (AddrMode == ARMII::AddrModeT1_s && isThumSpillRestore)
ImmOp.ChangeToImmediate(0);
else {
// Otherwise, it didn't fit. Pull in what we can to simplify the immed.
ImmedOffset = ImmedOffset & Mask;
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!");
unsigned Opcode = MI.getOpcode();
const TargetInstrDesc &Desc = MI.getDesc();
// Remove predicate first.
int PIdx = MI.findFirstPredOperandIdx();
if (PIdx != -1)

View File

@ -44,13 +44,14 @@ public:
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const;
// rewrite MI to access 'Offset' bytes from the FP. Return the offset that
// could not be handled directly in MI.
int rewriteFrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
unsigned FrameReg, int Offset,
unsigned MOVOpc, unsigned ADDriOpc,
unsigned SUBriOpc) const;
// rewrite MI to access 'Offset' bytes from the FP. Update Offset to be
// however much remains to be handled. Return 'true' if no further
// work is required.
bool rewriteFrameIndex(MachineBasicBlock::iterator II, unsigned FrameRegIdx,
unsigned FrameReg, int &Offset,
const ARMBaseInstrInfo &TII) const;
void resolveFrameIndex(MachineBasicBlock::iterator I,
unsigned BaseReg, int64_t Offset) const;
bool saveScavengerRegister(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
MachineBasicBlock::iterator &UseMI,