summaryrefslogtreecommitdiff
path: root/lib/Target/ARM
diff options
context:
space:
mode:
authorDavid Goodwin <david_goodwin@apple.com>2009-07-23 17:06:46 +0000
committerDavid Goodwin <david_goodwin@apple.com>2009-07-23 17:06:46 +0000
commitb53cc014d0f47b898c9daca34566c16dda6c4c1e (patch)
treeef76f8a93008a2a0a10870625f92dd7528a084ad /lib/Target/ARM
parent0dcde10f5eac406c3897b4ca9d944f1ebd7aaf49 (diff)
downloadllvm-b53cc014d0f47b898c9daca34566c16dda6c4c1e.tar.gz
llvm-b53cc014d0f47b898c9daca34566c16dda6c4c1e.tar.bz2
llvm-b53cc014d0f47b898c9daca34566c16dda6c4c1e.tar.xz
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
Diffstat (limited to 'lib/Target/ARM')
-rw-r--r--lib/Target/ARM/ARMBaseInstrInfo.h7
-rw-r--r--lib/Target/ARM/ARMBaseRegisterInfo.cpp71
-rw-r--r--lib/Target/ARM/ARMBaseRegisterInfo.h7
-rw-r--r--lib/Target/ARM/ARMInstrInfo.cpp5
-rw-r--r--lib/Target/ARM/ARMInstrInfo.h7
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td2
-rw-r--r--lib/Target/ARM/Thumb1InstrInfo.cpp6
-rw-r--r--lib/Target/ARM/Thumb1InstrInfo.h7
-rw-r--r--lib/Target/ARM/Thumb2InstrInfo.cpp23
-rw-r--r--lib/Target/ARM/Thumb2InstrInfo.h7
10 files changed, 124 insertions, 18 deletions
diff --git a/lib/Target/ARM/ARMBaseInstrInfo.h b/lib/Target/ARM/ARMBaseInstrInfo.h
index 63e08da9b6..be952d8b8c 100644
--- a/lib/Target/ARM/ARMBaseInstrInfo.h
+++ b/lib/Target/ARM/ARMBaseInstrInfo.h
@@ -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;
diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/lib/Target/ARM/ARMBaseRegisterInfo.cpp
index 9e21f3cf71..ec5e89f045 100644
--- a/lib/Target/ARM/ARMBaseRegisterInfo.cpp
+++ b/lib/Target/ARM/ARMBaseRegisterInfo.cpp
@@ -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
diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.h b/lib/Target/ARM/ARMBaseRegisterInfo.h
index 9165bbc883..ac5e6b6733 100644
--- a/lib/Target/ARM/ARMBaseRegisterInfo.h
+++ b/lib/Target/ARM/ARMBaseRegisterInfo.h
@@ -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
diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp
index 688dc31c13..45b77c83be 100644
--- a/lib/Target/ARM/ARMInstrInfo.cpp
+++ b/lib/Target/ARM/ARMInstrInfo.cpp
@@ -30,6 +30,11 @@ ARMInstrInfo::ARMInstrInfo(const ARMSubtarget &STI)
}
unsigned ARMInstrInfo::
+unsignedOffsetOpcodeToSigned(unsigned opcode, unsigned *NumBits) const {
+ return 0;
+}
+
+unsigned ARMInstrInfo::
getUnindexedOpcode(unsigned Opc) const {
switch (Opc) {
default: break;
diff --git a/lib/Target/ARM/ARMInstrInfo.h b/lib/Target/ARM/ARMInstrInfo.h
index 3e9f0204fe..8ff09123da 100644
--- a/lib/Target/ARM/ARMInstrInfo.h
+++ b/lib/Target/ARM/ARMInstrInfo.h
@@ -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;
diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td
index 5361bb59cf..80b0d68aa2 100644
--- a/lib/Target/ARM/ARMInstrThumb2.td
+++ b/lib/Target/ARM/ARMInstrThumb2.td
@@ -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";
diff --git a/lib/Target/ARM/Thumb1InstrInfo.cpp b/lib/Target/ARM/Thumb1InstrInfo.cpp
index ddc6e0d154..7bec736503 100644
--- a/lib/Target/ARM/Thumb1InstrInfo.cpp
+++ b/lib/Target/ARM/Thumb1InstrInfo.cpp
@@ -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;
diff --git a/lib/Target/ARM/Thumb1InstrInfo.h b/lib/Target/ARM/Thumb1InstrInfo.h
index 67b78fbedf..a1c9f04ef7 100644
--- a/lib/Target/ARM/Thumb1InstrInfo.h
+++ b/lib/Target/ARM/Thumb1InstrInfo.h
@@ -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;
diff --git a/lib/Target/ARM/Thumb2InstrInfo.cpp b/lib/Target/ARM/Thumb2InstrInfo.cpp
index 081cf4f550..d92856cf0c 100644
--- a/lib/Target/ARM/Thumb2InstrInfo.cpp
+++ b/lib/Target/ARM/Thumb2InstrInfo.cpp
@@ -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,
diff --git a/lib/Target/ARM/Thumb2InstrInfo.h b/lib/Target/ARM/Thumb2InstrInfo.h
index ac31707ab7..43ea56e792 100644
--- a/lib/Target/ARM/Thumb2InstrInfo.h
+++ b/lib/Target/ARM/Thumb2InstrInfo.h
@@ -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;