Fix frame index elimination to correctly handle thumb-2 addressing modes that don't allow negative offsets. During frame elimination convert *i12 opcode to a *i8 when necessary due to a negative offset.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@76883 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
David Goodwin 2009-07-23 17:06:46 +00:00
parent 0dcde10f5e
commit b53cc014d0
10 changed files with 124 additions and 18 deletions

View File

@ -215,6 +215,13 @@ public:
// Return the opcode that implements 'Op', or 0 if no opcode
virtual unsigned getOpcode(ARMII::Op Op) const =0;
// If 'opcode' is an instruction with an unsigned offset that also
// has a version with a signed offset, return the opcode for the
// version with the signed offset. In 'NumBits' return the number of
// bits for the signed offset.
virtual unsigned unsignedOffsetOpcodeToSigned(unsigned opcode,
unsigned *NumBits) const = 0;
// Return true if the block does not fall through.
virtual bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const =0;

View File

@ -142,6 +142,11 @@ getOpcode(int Op) const {
return TII.getOpcode((ARMII::Op)Op);
}
unsigned ARMBaseRegisterInfo::
unsignedOffsetOpcodeToSigned(unsigned opcode, unsigned *NumBits) const {
return TII.unsignedOffsetOpcodeToSigned(opcode, NumBits);
}
const unsigned*
ARMBaseRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
static const unsigned CalleeSavedRegs[] = {
@ -1109,6 +1114,8 @@ eliminateFrameIndex(MachineBasicBlock::iterator II,
int InstrOffs = 0;
unsigned NumBits = 0;
unsigned Scale = 1;
bool encodedOffset = true;
bool HandlesNeg = true;
switch (AddrMode) {
case ARMII::AddrMode2: {
ImmIdx = i+2;
@ -1139,17 +1146,21 @@ eliminateFrameIndex(MachineBasicBlock::iterator II,
ImmIdx = i+1;
InstrOffs = MI.getOperand(ImmIdx).getImm();
NumBits = 12;
encodedOffset = false;
HandlesNeg = false;
break;
}
case ARMII::AddrModeT2_i8: {
ImmIdx = i+1;
InstrOffs = MI.getOperand(ImmIdx).getImm();
NumBits = 8;
encodedOffset = false;
break;
}
case ARMII::AddrModeT2_so: {
ImmIdx = i+2;
InstrOffs = MI.getOperand(ImmIdx).getImm();
encodedOffset = false;
break;
}
default:
@ -1160,29 +1171,55 @@ eliminateFrameIndex(MachineBasicBlock::iterator II,
Offset += InstrOffs * Scale;
assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
if (Offset < 0) {
// For addrmodes that cannot handle negative offsets, convert to
// an opcode that can, or set NumBits == 0 to avoid folding
// address computation
if (!HandlesNeg) {
unsigned usop = unsignedOffsetOpcodeToSigned(Opcode, &NumBits);
if (usop != 0) {
MI.setDesc(TII.get(usop));
HandlesNeg = true;
Opcode = usop;
}
else {
NumBits = 0;
}
}
Offset = -Offset;
isSub = true;
}
// 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;
// Attempt to fold address comp. if opcode has offset bits
if (NumBits > 0) {
// 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) {
if (encodedOffset)
ImmedOffset |= 1 << NumBits;
else
ImmedOffset = -ImmedOffset;
}
ImmOp.ChangeToImmediate(ImmedOffset);
return;
}
// Otherwise, it didn't fit. Pull in what we can to simplify the immed.
ImmedOffset = ImmedOffset & Mask;
if (isSub) {
if (encodedOffset)
ImmedOffset |= 1 << NumBits;
else
ImmedOffset = -ImmedOffset;
}
ImmOp.ChangeToImmediate(ImmedOffset);
return;
Offset &= ~(Mask*Scale);
}
// 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

View File

@ -59,6 +59,13 @@ protected:
// Return the opcode that implements 'Op', or 0 if no opcode
unsigned getOpcode(int Op) const;
// If 'opcode' is an instruction with an unsigned offset that also
// has a version with a signed offset, return the opcode for the
// version with the signed offset. In 'NumBits' return the number of
// bits for the signed offset.
unsigned unsignedOffsetOpcodeToSigned(unsigned opcode,
unsigned *NumBits) const;
public:
/// getRegisterNumbering - Given the enum value for some register, e.g.
/// ARM::LR, return the number that it corresponds to (e.g. 14). It

View File

@ -29,6 +29,11 @@ ARMInstrInfo::ARMInstrInfo(const ARMSubtarget &STI)
: ARMBaseInstrInfo(STI), RI(*this, STI) {
}
unsigned ARMInstrInfo::
unsignedOffsetOpcodeToSigned(unsigned opcode, unsigned *NumBits) const {
return 0;
}
unsigned ARMInstrInfo::
getUnindexedOpcode(unsigned Opc) const {
switch (Opc) {

View File

@ -35,6 +35,13 @@ public:
// Return the opcode that implements 'Op', or 0 if no opcode
unsigned getOpcode(ARMII::Op Op) const;
// If 'opcode' is an instruction with an unsigned offset that also
// has a version with a signed offset, return the opcode for the
// version with the signed offset. In 'NumBits' return the number of
// bits for the signed offset.
unsigned unsignedOffsetOpcodeToSigned(unsigned opcode,
unsigned *NumBits) const;
// Return true if the block does not fall through.
bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const;

View File

@ -109,7 +109,7 @@ def t2addrmode_imm12 : Operand<i32>,
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
}
// t2addrmode_imm8 := reg - imm8
// t2addrmode_imm8 := reg +/- imm8
def t2addrmode_imm8 : Operand<i32>,
ComplexPattern<i32, 2, "SelectT2AddrModeImm8", []> {
let PrintMethod = "printT2AddrModeImm8Operand";

View File

@ -30,6 +30,12 @@ unsigned Thumb1InstrInfo::getUnindexedOpcode(unsigned Opc) const {
return 0;
}
unsigned
Thumb1InstrInfo::unsignedOffsetOpcodeToSigned(unsigned opcode,
unsigned *NumBits) const {
return 0;
}
unsigned Thumb1InstrInfo::getOpcode(ARMII::Op Op) const {
switch (Op) {
case ARMII::ADDri: return ARM::tADDi8;

View File

@ -34,6 +34,13 @@ public:
// Return the opcode that implements 'Op', or 0 if no opcode
unsigned getOpcode(ARMII::Op Op) const;
// If 'opcode' is an instruction with an unsigned offset that also
// has a version with a signed offset, return the opcode for the
// version with the signed offset. In 'NumBits' return the number of
// bits for the signed offset.
unsigned unsignedOffsetOpcodeToSigned(unsigned opcode,
unsigned *NumBits) const;
// Return true if the block does not fall through.
bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const;

View File

@ -88,6 +88,29 @@ Thumb2InstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const {
return false;
}
unsigned
Thumb2InstrInfo::unsignedOffsetOpcodeToSigned(unsigned opcode,
unsigned *NumBits) const
{
if (NumBits != NULL)
*NumBits = 8;
switch (opcode) {
case ARM::t2LDRi12: return ARM::t2LDRi8;
case ARM::t2LDRHi12: return ARM::t2LDRHi8;
case ARM::t2LDRBi12: return ARM::t2LDRBi8;
case ARM::t2LDRSHi12: return ARM::t2LDRSHi8;
case ARM::t2LDRSBi12: return ARM::t2LDRSBi8;
case ARM::t2STRi12: return ARM::t2STRi8;
case ARM::t2STRBi12: return ARM::t2STRBi8;
case ARM::t2STRHi12: return ARM::t2STRHi8;
default:
break;
}
return 0;
}
bool
Thumb2InstrInfo::copyRegToReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,

View File

@ -34,6 +34,13 @@ public:
// Return the opcode that implements 'Op', or 0 if no opcode
unsigned getOpcode(ARMII::Op Op) const;
// If 'opcode' is an instruction with an unsigned offset that also
// has a version with a signed offset, return the opcode for the
// version with the signed offset. In 'NumBits' return the number of
// bits for the signed offset.
unsigned unsignedOffsetOpcodeToSigned(unsigned opcode,
unsigned *NumBits) const;
// Return true if the block does not fall through.
bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const;