Many Thumb2 instructions can reference the full ARM register set (i.e.,

have 4 bits per register in the operand encoding), but have undefined
behavior when the operand value is 13 or 15 (SP and PC, respectively).
The trivial coalescer in linear scan sometimes will merge a copy from
SP into a subsequent instruction which uses the copy, and if that
instruction cannot legally reference SP, we get bad code such as:
  mls r0,r9,r0,sp
instead of:
  mov r2, sp
  mls r0, r9, r0, r2

This patch adds a new register class for use by Thumb2 that excludes
the problematic registers (SP and PC) and is used instead of GPR
for those operands which cannot legally reference PC or SP. The
trivial coalescer explicitly requires that the register class
of the destination for the COPY instruction contain the source
register for the COPY to be considered for coalescing. This prevents
errant instructions like that above.

PR7499

llvm-svn: 109842
This commit is contained in:
Jim Grosbach 2010-07-30 02:41:01 +00:00
parent d5cd0f3fac
commit d343166a0b
9 changed files with 492 additions and 338 deletions

View File

@ -721,8 +721,9 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
Align);
// tGPR is used sometimes in ARM instructions that need to avoid using
// certain registers. Just treat it as GPR here.
if (RC == ARM::tGPRRegisterClass || RC == ARM::tcGPRRegisterClass)
// certain registers. Just treat it as GPR here. Likewise, rGPR.
if (RC == ARM::tGPRRegisterClass || RC == ARM::tcGPRRegisterClass
|| RC == ARM::rGPRRegisterClass)
RC = ARM::GPRRegisterClass;
switch (RC->getID()) {
@ -823,7 +824,8 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
// tGPR is used sometimes in ARM instructions that need to avoid using
// certain registers. Just treat it as GPR here.
if (RC == ARM::tGPRRegisterClass || RC == ARM::tcGPRRegisterClass)
if (RC == ARM::tGPRRegisterClass || RC == ARM::tcGPRRegisterClass
|| RC == ARM::rGPRRegisterClass)
RC = ARM::GPRRegisterClass;
switch (RC->getID()) {

File diff suppressed because it is too large Load Diff

View File

@ -318,6 +318,115 @@ def GPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6,
}];
}
// restricted GPR register class. Many Thumb2 instructions allow the full
// register range for operands, but have undefined behaviours when PC
// or SP (R13 or R15) are used. The ARM ARM refers to these operands
// via the BadReg() pseudo-code description.
def rGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6,
R7, R8, R9, R10, R11, R12, LR]> {
let MethodProtos = [{
iterator allocation_order_begin(const MachineFunction &MF) const;
iterator allocation_order_end(const MachineFunction &MF) const;
}];
let MethodBodies = [{
// FP is R11, R9 is available.
static const unsigned ARM_rGPRAO_1[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3,
ARM::R12,ARM::LR,
ARM::R4, ARM::R5, ARM::R6, ARM::R7,
ARM::R8, ARM::R9, ARM::R10,
ARM::R11 };
// FP is R11, R9 is not available.
static const unsigned ARM_rGPRAO_2[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3,
ARM::R12,ARM::LR,
ARM::R4, ARM::R5, ARM::R6, ARM::R7,
ARM::R8, ARM::R10,
ARM::R11 };
// FP is R7, R9 is available as non-callee-saved register.
// This is used by Darwin.
static const unsigned ARM_rGPRAO_3[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3,
ARM::R9, ARM::R12,ARM::LR,
ARM::R4, ARM::R5, ARM::R6,
ARM::R8, ARM::R10,ARM::R11,ARM::R7 };
// FP is R7, R9 is not available.
static const unsigned ARM_rGPRAO_4[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3,
ARM::R12,ARM::LR,
ARM::R4, ARM::R5, ARM::R6,
ARM::R8, ARM::R10,ARM::R11,
ARM::R7 };
// FP is R7, R9 is available as callee-saved register.
// This is used by non-Darwin platform in Thumb mode.
static const unsigned ARM_rGPRAO_5[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3,
ARM::R12,ARM::LR,
ARM::R4, ARM::R5, ARM::R6,
ARM::R8, ARM::R9, ARM::R10,ARM::R11,ARM::R7 };
// For Thumb1 mode, we don't want to allocate hi regs at all, as we
// don't know how to spill them. If we make our prologue/epilogue code
// smarter at some point, we can go back to using the above allocation
// orders for the Thumb1 instructions that know how to use hi regs.
static const unsigned THUMB_rGPRAO[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3,
ARM::R4, ARM::R5, ARM::R6, ARM::R7 };
rGPRClass::iterator
rGPRClass::allocation_order_begin(const MachineFunction &MF) const {
const TargetMachine &TM = MF.getTarget();
const ARMSubtarget &Subtarget = TM.getSubtarget<ARMSubtarget>();
if (Subtarget.isThumb1Only())
return THUMB_rGPRAO;
if (Subtarget.isTargetDarwin()) {
if (Subtarget.isR9Reserved())
return ARM_rGPRAO_4;
else
return ARM_rGPRAO_3;
} else {
if (Subtarget.isR9Reserved())
return ARM_rGPRAO_2;
else if (Subtarget.isThumb())
return ARM_rGPRAO_5;
else
return ARM_rGPRAO_1;
}
}
rGPRClass::iterator
rGPRClass::allocation_order_end(const MachineFunction &MF) const {
const TargetMachine &TM = MF.getTarget();
const TargetRegisterInfo *RI = TM.getRegisterInfo();
const ARMSubtarget &Subtarget = TM.getSubtarget<ARMSubtarget>();
GPRClass::iterator I;
if (Subtarget.isThumb1Only()) {
I = THUMB_rGPRAO + (sizeof(THUMB_rGPRAO)/sizeof(unsigned));
// Mac OS X requires FP not to be clobbered for backtracing purpose.
return (Subtarget.isTargetDarwin() || RI->hasFP(MF)) ? I-1 : I;
}
if (Subtarget.isTargetDarwin()) {
if (Subtarget.isR9Reserved())
I = ARM_rGPRAO_4 + (sizeof(ARM_rGPRAO_4)/sizeof(unsigned));
else
I = ARM_rGPRAO_3 + (sizeof(ARM_rGPRAO_3)/sizeof(unsigned));
} else {
if (Subtarget.isR9Reserved())
I = ARM_rGPRAO_2 + (sizeof(ARM_rGPRAO_2)/sizeof(unsigned));
else if (Subtarget.isThumb())
I = ARM_rGPRAO_5 + (sizeof(ARM_rGPRAO_5)/sizeof(unsigned));
else
I = ARM_rGPRAO_1 + (sizeof(ARM_rGPRAO_1)/sizeof(unsigned));
}
// Mac OS X requires FP not to be clobbered for backtracing purpose.
return (Subtarget.isTargetDarwin() || RI->hasFP(MF)) ? I-1 : I;
}
}];
}
// Thumb registers are R0-R7 normally. Some instructions can still use
// the general GPR register class above (MOV, e.g.)
def tGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, R7]> {

View File

@ -93,6 +93,9 @@ static unsigned getRegisterEnum(BO B, unsigned RegClassID, unsigned RawRegister,
RegClassID = ARM::DPRRegClassID;
}
// For this purpose, we can treat rGPR as if it were GPR.
if (RegClassID == ARM::rGPRRegClassID) RegClassID = ARM::GPRRegClassID;
// See also decodeNEONRd(), decodeNEONRn(), decodeNEONRm().
unsigned RegNum =
RegClassID == ARM::QPRRegClassID ? RawRegister >> 1 : RawRegister;

View File

@ -103,7 +103,7 @@ static inline unsigned getT1Cond(uint32_t insn) {
}
static inline bool IsGPR(unsigned RegClass) {
return RegClass == ARM::GPRRegClassID;
return RegClass == ARM::GPRRegClassID || RegClass == ARM::rGPRRegClassID;
}
// Utilities for 32-bit Thumb instructions.
@ -1324,7 +1324,7 @@ static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn,
&& OpInfo[1].RegClass == ARM::GPRRegClassID
&& OpInfo[2].RegClass < 0
&& OpInfo[3].RegClass < 0
&& "Exactlt 4 operands expect and first two as reg operands");
&& "Exactly 4 operands expect and first two as reg operands");
// Only need to populate the src reg operand.
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
decodeRm(insn))));
@ -1338,17 +1338,20 @@ static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn,
OpIdx = 0;
assert(NumOps >= 2
&& OpInfo[0].RegClass == ARM::GPRRegClassID
&& OpInfo[1].RegClass == ARM::GPRRegClassID
&& (OpInfo[0].RegClass == ARM::GPRRegClassID ||
OpInfo[0].RegClass == ARM::rGPRRegClassID)
&& (OpInfo[1].RegClass == ARM::GPRRegClassID ||
OpInfo[1].RegClass == ARM::rGPRRegClassID)
&& "Expect >= 2 operands and first two as reg operands");
bool ThreeReg = (NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID);
bool ThreeReg = (NumOps > 2 && (OpInfo[2].RegClass == ARM::GPRRegClassID ||
OpInfo[2].RegClass == ARM::rGPRRegClassID));
bool NoDstReg = (decodeRs(insn) == 0xF);
// Build the register operands, followed by the constant shift specifier.
MI.addOperand(MCOperand::CreateReg(
getRegisterEnum(B, ARM::GPRRegClassID,
getRegisterEnum(B, OpInfo[0].RegClass,
NoDstReg ? decodeRn(insn) : decodeRs(insn))));
++OpIdx;
@ -1359,7 +1362,7 @@ static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn,
MI.addOperand(MI.getOperand(Idx));
++OpIdx;
} else if (!NoDstReg) {
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[1].RegClass,
decodeRn(insn))));
++OpIdx;
} else {
@ -1368,7 +1371,7 @@ static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn,
}
}
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass,
decodeRm(insn))));
++OpIdx;
@ -1416,16 +1419,20 @@ static bool DisassembleThumb2DPModImm(MCInst &MI, unsigned Opcode,
OpIdx = 0;
assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID
unsigned RdRegClassID = OpInfo[0].RegClass;
assert(NumOps >= 2 && (RdRegClassID == ARM::GPRRegClassID ||
RdRegClassID == ARM::rGPRRegClassID)
&& "Expect >= 2 operands and first one as reg operand");
bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID);
unsigned RnRegClassID = OpInfo[1].RegClass;
bool TwoReg = (RnRegClassID == ARM::GPRRegClassID
|| RnRegClassID == ARM::rGPRRegClassID);
bool NoDstReg = (decodeRs(insn) == 0xF);
// Build the register operands, followed by the modified immediate.
MI.addOperand(MCOperand::CreateReg(
getRegisterEnum(B, ARM::GPRRegClassID,
getRegisterEnum(B, RdRegClassID,
NoDstReg ? decodeRn(insn) : decodeRs(insn))));
++OpIdx;
@ -1434,7 +1441,7 @@ static bool DisassembleThumb2DPModImm(MCInst &MI, unsigned Opcode,
DEBUG(errs()<<"Thumb2 encoding error: d==15 for DPModImm 2-reg instr.\n");
return false;
}
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RnRegClassID,
decodeRn(insn))));
++OpIdx;
}
@ -1506,14 +1513,18 @@ static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode,
OpIdx = 0;
assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID
unsigned RdRegClassID = OpInfo[0].RegClass;
assert(NumOps >= 2 && (RdRegClassID == ARM::GPRRegClassID ||
RdRegClassID == ARM::rGPRRegClassID)
&& "Expect >= 2 operands and first one as reg operand");
bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID);
unsigned RnRegClassID = OpInfo[1].RegClass;
bool TwoReg = (RnRegClassID == ARM::GPRRegClassID
|| RnRegClassID == ARM::rGPRRegClassID);
// Build the register operand(s), followed by the immediate(s).
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RdRegClassID,
decodeRs(insn))));
++OpIdx;
@ -1521,7 +1532,7 @@ static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode,
if (Thumb2SaturateOpcode(Opcode)) {
MI.addOperand(MCOperand::CreateImm(decodeThumb2SaturatePos(Opcode, insn)));
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RnRegClassID,
decodeRn(insn))));
if (Opcode == ARM::t2SSAT16 || Opcode == ARM::t2USAT16) {
@ -1549,7 +1560,7 @@ static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode,
MI.addOperand(MI.getOperand(Idx));
} else {
// Add src reg operand.
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RnRegClassID,
decodeRn(insn))));
}
++OpIdx;
@ -1557,7 +1568,7 @@ static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode,
if (Opcode == ARM::t2BFI) {
// Add val reg operand.
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RnRegClassID,
decodeRn(insn))));
++OpIdx;
}
@ -1959,25 +1970,25 @@ static bool DisassembleThumb2DPReg(MCInst &MI, unsigned Opcode, uint32_t insn,
OpIdx = 0;
assert(NumOps >= 2 &&
OpInfo[0].RegClass == ARM::GPRRegClassID &&
OpInfo[1].RegClass == ARM::GPRRegClassID &&
OpInfo[0].RegClass == ARM::rGPRRegClassID &&
OpInfo[1].RegClass == ARM::rGPRRegClassID &&
"Expect >= 2 operands and first two as reg operands");
// Build the register operands, followed by the optional rotation amount.
bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID;
bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::rGPRRegClassID;
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRs(insn))));
++OpIdx;
if (ThreeReg) {
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRn(insn))));
++OpIdx;
}
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRm(insn))));
++OpIdx;
@ -2009,26 +2020,26 @@ static bool DisassembleThumb2Mul(MCInst &MI, unsigned Opcode, uint32_t insn,
const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
assert(NumOps >= 3 &&
OpInfo[0].RegClass == ARM::GPRRegClassID &&
OpInfo[1].RegClass == ARM::GPRRegClassID &&
OpInfo[2].RegClass == ARM::GPRRegClassID &&
OpInfo[0].RegClass == ARM::rGPRRegClassID &&
OpInfo[1].RegClass == ARM::rGPRRegClassID &&
OpInfo[2].RegClass == ARM::rGPRRegClassID &&
"Expect >= 3 operands and first three as reg operands");
// Build the register operands.
bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID;
bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::rGPRRegClassID;
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRs(insn))));
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRn(insn))));
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRm(insn))));
if (FourReg)
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRd(insn))));
NumOpsAdded = FourReg ? 4 : 3;
@ -2054,26 +2065,26 @@ static bool DisassembleThumb2LongMul(MCInst &MI, unsigned Opcode, uint32_t insn,
const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo;
assert(NumOps >= 3 &&
OpInfo[0].RegClass == ARM::GPRRegClassID &&
OpInfo[1].RegClass == ARM::GPRRegClassID &&
OpInfo[2].RegClass == ARM::GPRRegClassID &&
OpInfo[0].RegClass == ARM::rGPRRegClassID &&
OpInfo[1].RegClass == ARM::rGPRRegClassID &&
OpInfo[2].RegClass == ARM::rGPRRegClassID &&
"Expect >= 3 operands and first three as reg operands");
bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID;
bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::rGPRRegClassID;
// Build the register operands.
if (FourReg)
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRd(insn))));
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRs(insn))));
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRn(insn))));
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID,
decodeRm(insn))));
if (FourReg)

View File

@ -147,8 +147,8 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned SrcReg, bool isKill, int FI,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
if (RC == ARM::GPRRegisterClass || RC == ARM::tGPRRegisterClass ||
RC == ARM::tcGPRRegisterClass) {
if (RC == ARM::GPRRegisterClass || RC == ARM::tGPRRegisterClass ||
RC == ARM::tcGPRRegisterClass || RC == ARM::rGPRRegisterClass) {
DebugLoc DL;
if (I != MBB.end()) DL = I->getDebugLoc();
@ -173,8 +173,8 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned DestReg, int FI,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
if (RC == ARM::GPRRegisterClass || RC == ARM::tGPRRegisterClass ||
RC == ARM::tcGPRRegisterClass) {
if (RC == ARM::GPRRegisterClass || RC == ARM::tGPRRegisterClass ||
RC == ARM::tcGPRRegisterClass || RC == ARM::rGPRRegisterClass) {
DebugLoc DL;
if (I != MBB.end()) DL = I->getDebugLoc();

View File

@ -7,13 +7,17 @@
define void @t() nounwind ssp {
entry:
; CHECK: t:
; CHECK: bic r0, sp, #7
; CHECK: subs r0, #16
; CHECK: mov sp, r0
; Yes, this is stupid codegen, but it's correct.
; CHECK: bic r0, sp, #7
; CHECK: subs r0, #16
; CHECK: mov sp, r0
; CHECK: push {r4, r7}
; CHECK: mov r0, sp
; CHECK: add r7, sp, #4
; CHECK: bic r0, r0, #7
; CHECK: subs r0, #16
; CHECK: mov sp, r0
; CHECK: mov r0, sp
; CHECK: bic r0, r0, #7
; CHECK: subs r0, #16
; CHECK: mov sp, r0
%size = mul i32 8, 2
%vla_a = alloca i8, i32 %size, align 8
%vla_b = alloca i8, i32 %size, align 8

View File

@ -0,0 +1,15 @@
; RUN: llc < %s -mtriple=thumbv7-apple-darwin10 | FileCheck %s
define void @b(i32 %x) nounwind optsize {
entry:
; CHECK: b
; CHECK: mov r2, sp
; CHECK: mls r0, r0, r1, r2
; CHECK: mov sp, r0
%0 = mul i32 %x, 24 ; <i32> [#uses=1]
%vla = alloca i8, i32 %0, align 1 ; <i8*> [#uses=1]
call arm_aapcscc void @a(i8* %vla) nounwind optsize
ret void
}
declare void @a(i8*) optsize

View File

@ -578,6 +578,7 @@ static void X86ExtractSemantics(
static int ARMFlagFromOpName(LiteralConstantEmitter *type,
const std::string &name) {
REG("GPR");
REG("rGPR");
REG("tcGPR");
REG("cc_out");
REG("s_cc_out");