mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-22 19:49:49 +00:00
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:
parent
d85a524ba1
commit
1718345a30
@ -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
@ -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]> {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
15
test/CodeGen/Thumb2/thumb2-badreg-operands.ll
Normal file
15
test/CodeGen/Thumb2/thumb2-badreg-operands.ll
Normal 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
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user