mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-07-22 09:29:31 +00:00
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:
parent
0dcde10f5e
commit
b53cc014d0
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user