Remove hard coded registers in ARM ldrexd and strexd instructions

This patch replaces the hard coded GPR pair [R0, R1] of
Intrinsic:arm_ldrexd and [R2, R3] of Intrinsic:arm_strexd with
even/odd GPRPair reg class.
Similar to the lowering of atomic_64 operation.

llvm-svn: 168207
This commit is contained in:
Weiming Zhao 2012-11-16 21:55:34 +00:00
parent dddfc51397
commit 8f56f88661
8 changed files with 227 additions and 103 deletions

View File

@ -266,6 +266,7 @@ private:
std::vector<SDValue> &OutOps);
// Form pairs of consecutive S, D, or Q registers.
SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);
SDNode *PairSRegs(EVT VT, SDValue V0, SDValue V1);
SDNode *PairDRegs(EVT VT, SDValue V0, SDValue V1);
SDNode *PairQRegs(EVT VT, SDValue V0, SDValue V1);
@ -1444,6 +1445,17 @@ SDNode *ARMDAGToDAGISel::SelectT2IndexedLoad(SDNode *N) {
return NULL;
}
/// \brief Form a GPRPair pseudo register from a pair of GPR regs.
SDNode *ARMDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
DebugLoc dl = V0.getNode()->getDebugLoc();
SDValue RegClass =
CurDAG->getTargetConstant(ARM::GPRPairRegClassID, MVT::i32);
SDValue SubReg0 = CurDAG->getTargetConstant(ARM::gsub_0, MVT::i32);
SDValue SubReg1 = CurDAG->getTargetConstant(ARM::gsub_1, MVT::i32);
const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 5);
}
/// PairSRegs - Form a D register from a pair of S registers.
///
SDNode *ARMDAGToDAGISel::PairSRegs(EVT VT, SDValue V0, SDValue V1) {
@ -3009,17 +3021,19 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
DebugLoc dl = N->getDebugLoc();
SDValue Chain = N->getOperand(0);
unsigned NewOpc = ARM::LDREXD;
if (Subtarget->isThumb() && Subtarget->hasThumb2())
NewOpc = ARM::t2LDREXD;
bool isThumb = Subtarget->isThumb() && Subtarget->hasThumb2();
unsigned NewOpc = isThumb ? ARM::t2LDREXD :ARM::LDREXD;
// arm_ldrexd returns a i64 value in {i32, i32}
std::vector<EVT> ResTys;
ResTys.push_back(MVT::i32);
ResTys.push_back(MVT::i32);
if (isThumb) {
ResTys.push_back(MVT::i32);
ResTys.push_back(MVT::i32);
} else
ResTys.push_back(MVT::Untyped);
ResTys.push_back(MVT::Other);
// place arguments in the right order
// Place arguments in the right order.
SmallVector<SDValue, 7> Ops;
Ops.push_back(MemAddr);
Ops.push_back(getAL(CurDAG));
@ -3032,30 +3046,35 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
cast<MachineSDNode>(Ld)->setMemRefs(MemOp, MemOp + 1);
// Until there's support for specifing explicit register constraints
// like the use of even/odd register pair, hardcode ldrexd to always
// use the pair [R0, R1] to hold the load result.
Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, ARM::R0,
SDValue(Ld, 0), SDValue(0,0));
Chain = CurDAG->getCopyToReg(Chain, dl, ARM::R1,
SDValue(Ld, 1), Chain.getValue(1));
// Remap uses.
SDValue Glue = Chain.getValue(1);
SDValue Glue = isThumb ? SDValue(Ld, 2) : SDValue(Ld, 1);
if (!SDValue(N, 0).use_empty()) {
SDValue Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
ARM::R0, MVT::i32, Glue);
Glue = Result.getValue(2);
SDValue Result;
if (isThumb)
Result = SDValue(Ld, 0);
else {
SDValue SubRegIdx = CurDAG->getTargetConstant(ARM::gsub_0, MVT::i32);
SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
dl, MVT::i32, MVT::Glue, SDValue(Ld, 0), SubRegIdx, Glue);
Result = SDValue(ResNode,0);
Glue = Result.getValue(1);
}
ReplaceUses(SDValue(N, 0), Result);
}
if (!SDValue(N, 1).use_empty()) {
SDValue Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
ARM::R1, MVT::i32, Glue);
Glue = Result.getValue(2);
SDValue Result;
if (isThumb)
Result = SDValue(Ld, 1);
else {
SDValue SubRegIdx = CurDAG->getTargetConstant(ARM::gsub_1, MVT::i32);
SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
dl, MVT::i32, MVT::Glue, SDValue(Ld, 0), SubRegIdx, Glue);
Result = SDValue(ResNode,0);
Glue = Result.getValue(1);
}
ReplaceUses(SDValue(N, 1), Result);
}
ReplaceUses(SDValue(N, 2), SDValue(Ld, 2));
ReplaceUses(SDValue(N, 2), Glue);
return NULL;
}
@ -3066,38 +3085,27 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
SDValue Val1 = N->getOperand(3);
SDValue MemAddr = N->getOperand(4);
// Until there's support for specifing explicit register constraints
// like the use of even/odd register pair, hardcode strexd to always
// use the pair [R2, R3] to hold the i64 (i32, i32) value to be stored.
Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, ARM::R2, Val0,
SDValue(0, 0));
Chain = CurDAG->getCopyToReg(Chain, dl, ARM::R3, Val1, Chain.getValue(1));
SDValue Glue = Chain.getValue(1);
Val0 = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
ARM::R2, MVT::i32, Glue);
Glue = Val0.getValue(1);
Val1 = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
ARM::R3, MVT::i32, Glue);
// Store exclusive double return a i32 value which is the return status
// of the issued store.
std::vector<EVT> ResTys;
ResTys.push_back(MVT::i32);
ResTys.push_back(MVT::Other);
// place arguments in the right order
bool isThumb = Subtarget->isThumb() && Subtarget->hasThumb2();
// Place arguments in the right order.
SmallVector<SDValue, 7> Ops;
Ops.push_back(Val0);
Ops.push_back(Val1);
if (isThumb) {
Ops.push_back(Val0);
Ops.push_back(Val1);
} else
// arm_strexd uses GPRPair.
Ops.push_back(SDValue(createGPRPairNode(MVT::Untyped, Val0, Val1), 0));
Ops.push_back(MemAddr);
Ops.push_back(getAL(CurDAG));
Ops.push_back(CurDAG->getRegister(0, MVT::i32));
Ops.push_back(Chain);
unsigned NewOpc = ARM::STREXD;
if (Subtarget->isThumb() && Subtarget->hasThumb2())
NewOpc = ARM::t2STREXD;
unsigned NewOpc = isThumb ? ARM::t2STREXD : ARM::STREXD;
SDNode *St = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops.data(),
Ops.size());

View File

@ -5807,12 +5807,16 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
// for ldrexd must be different.
BB = loopMBB;
// Load
unsigned GPRPair0 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
unsigned GPRPair1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
AddDefaultPred(BuildMI(BB, dl, TII->get(ldrOpc))
.addReg(ARM::R2, RegState::Define)
.addReg(ARM::R3, RegState::Define).addReg(ptr));
.addReg(GPRPair0, RegState::Define).addReg(ptr));
// Copy r2/r3 into dest. (This copy will normally be coalesced.)
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), destlo).addReg(ARM::R2);
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), desthi).addReg(ARM::R3);
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), destlo)
.addReg(GPRPair0, 0, ARM::gsub_0);
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), desthi)
.addReg(GPRPair0, 0, ARM::gsub_1);
if (IsCmpxchg) {
// Add early exit
@ -5831,24 +5835,56 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
// Copy to physregs for strexd
unsigned setlo = MI->getOperand(5).getReg();
unsigned sethi = MI->getOperand(6).getReg();
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R0).addReg(setlo);
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R1).addReg(sethi);
unsigned undef = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
unsigned r1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
BuildMI(BB, dl, TII->get(TargetOpcode::IMPLICIT_DEF), undef);
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), r1)
.addReg(undef)
.addReg(setlo)
.addImm(ARM::gsub_0);
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), GPRPair1)
.addReg(r1)
.addReg(sethi)
.addImm(ARM::gsub_1);
} else if (Op1) {
// Perform binary operation
AddDefaultPred(BuildMI(BB, dl, TII->get(Op1), ARM::R0)
unsigned tmpRegLo = MRI.createVirtualRegister(TRC);
AddDefaultPred(BuildMI(BB, dl, TII->get(Op1), tmpRegLo)
.addReg(destlo).addReg(vallo))
.addReg(NeedsCarry ? ARM::CPSR : 0, getDefRegState(NeedsCarry));
AddDefaultPred(BuildMI(BB, dl, TII->get(Op2), ARM::R1)
unsigned tmpRegHi = MRI.createVirtualRegister(TRC);
AddDefaultPred(BuildMI(BB, dl, TII->get(Op2), tmpRegHi)
.addReg(desthi).addReg(valhi)).addReg(0);
unsigned UndefPair = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
BuildMI(BB, dl, TII->get(TargetOpcode::IMPLICIT_DEF), UndefPair);
unsigned r1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), r1)
.addReg(UndefPair)
.addReg(tmpRegLo)
.addImm(ARM::gsub_0);
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), GPRPair1)
.addReg(r1)
.addReg(tmpRegHi)
.addImm(ARM::gsub_1);
} else {
// Copy to physregs for strexd
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R0).addReg(vallo);
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R1).addReg(valhi);
unsigned UndefPair = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
unsigned r1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
BuildMI(BB, dl, TII->get(TargetOpcode::IMPLICIT_DEF), UndefPair);
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), r1)
.addReg(UndefPair)
.addReg(vallo)
.addImm(ARM::gsub_0);
BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), GPRPair1)
.addReg(r1)
.addReg(valhi)
.addImm(ARM::gsub_1);
}
// Store
AddDefaultPred(BuildMI(BB, dl, TII->get(strOpc), storesuccess)
.addReg(ARM::R0).addReg(ARM::R1).addReg(ptr));
.addReg(GPRPair1).addReg(ptr));
// Cmp+jump
AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri))
.addReg(storesuccess).addImm(0));

View File

@ -417,6 +417,8 @@ def reglist : Operand<i32> {
let DecoderMethod = "DecodeRegListOperand";
}
def GPRPairOp : RegisterOperand<GPRPair, "printGPRPairOperand">;
def DPRRegListAsmOperand : AsmOperandClass { let Name = "DPRRegList"; }
def dpr_reglist : Operand<i32> {
let EncoderMethod = "getRegisterListOpValue";
@ -4229,8 +4231,8 @@ def LDREXH : AIldrex<0b11, (outs GPR:$Rt), (ins addr_offset_none:$addr),
def LDREX : AIldrex<0b00, (outs GPR:$Rt), (ins addr_offset_none:$addr),
NoItinerary, "ldrex", "\t$Rt, $addr", []>;
let hasExtraDefRegAllocReq = 1 in
def LDREXD: AIldrex<0b01, (outs GPR:$Rt, GPR:$Rt2),(ins addr_offset_none:$addr),
NoItinerary, "ldrexd", "\t$Rt, $Rt2, $addr", []> {
def LDREXD: AIldrex<0b01, (outs GPRPairOp:$Rt),(ins addr_offset_none:$addr),
NoItinerary, "ldrexd", "\t$Rt, $addr", []> {
let DecoderMethod = "DecodeDoubleRegLoad";
}
}
@ -4244,8 +4246,8 @@ def STREX : AIstrex<0b00, (outs GPR:$Rd), (ins GPR:$Rt, addr_offset_none:$addr),
NoItinerary, "strex", "\t$Rd, $Rt, $addr", []>;
let hasExtraSrcRegAllocReq = 1 in
def STREXD : AIstrex<0b01, (outs GPR:$Rd),
(ins GPR:$Rt, GPR:$Rt2, addr_offset_none:$addr),
NoItinerary, "strexd", "\t$Rd, $Rt, $Rt2, $addr", []> {
(ins GPRPairOp:$Rt, addr_offset_none:$addr),
NoItinerary, "strexd", "\t$Rd, $Rt, $addr", []> {
let DecoderMethod = "DecodeDoubleRegStore";
}
}

View File

@ -5187,6 +5187,45 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
}
// Adjust operands of ldrexd/strexd to MCK_GPRPair.
// ldrexd/strexd require even/odd GPR pair. To enforce this constraint,
// a single GPRPair reg operand is used in the .td file to replace the two
// GPRs. However, when parsing from asm, the two GRPs cannot be automatically
// expressed as a GPRPair, so we have to manually merge them.
// FIXME: We would really like to be able to tablegen'erate this.
if (!isThumb() && Operands.size() > 4 &&
(Mnemonic == "ldrexd" || Mnemonic == "strexd")) {
bool isLoad = (Mnemonic == "ldrexd");
unsigned Idx = isLoad ? 2 : 3;
ARMOperand* Op1 = static_cast<ARMOperand*>(Operands[Idx]);
ARMOperand* Op2 = static_cast<ARMOperand*>(Operands[Idx+1]);
const MCRegisterClass& MRC = MRI->getRegClass(ARM::GPRRegClassID);
// Adjust only if Op1 and Op2 are GPRs.
if (Op1->isReg() && Op2->isReg() && MRC.contains(Op1->getReg()) &&
MRC.contains(Op2->getReg())) {
unsigned Reg1 = Op1->getReg();
unsigned Reg2 = Op2->getReg();
unsigned Rt = MRI->getEncodingValue(Reg1);
unsigned Rt2 = MRI->getEncodingValue(Reg2);
// Rt2 must be Rt + 1 and Rt must be even.
if (Rt + 1 != Rt2 || (Rt & 1)) {
Error(Op2->getStartLoc(), isLoad ?
"destination operands must be sequential" :
"source operands must be sequential");
return true;
}
unsigned NewReg = MRI->getMatchingSuperReg(Reg1, ARM::gsub_0,
&(MRI->getRegClass(ARM::GPRPairRegClassID)));
Operands.erase(Operands.begin() + Idx, Operands.begin() + Idx + 2);
Operands.insert(Operands.begin() + Idx, ARMOperand::CreateReg(
NewReg, Op1->getStartLoc(), Op2->getEndLoc()));
delete Op1;
delete Op2;
}
}
return false;
}
@ -5274,8 +5313,7 @@ validateInstruction(MCInst &Inst,
switch (Inst.getOpcode()) {
case ARM::LDRD:
case ARM::LDRD_PRE:
case ARM::LDRD_POST:
case ARM::LDREXD: {
case ARM::LDRD_POST: {
// Rt2 must be Rt + 1.
unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
@ -5294,8 +5332,7 @@ validateInstruction(MCInst &Inst,
return false;
}
case ARM::STRD_PRE:
case ARM::STRD_POST:
case ARM::STREXD: {
case ARM::STRD_POST: {
// Rt2 must be Rt + 1.
unsigned Rt = MRI->getEncodingValue(Inst.getOperand(1).getReg());
unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(2).getReg());
@ -7483,6 +7520,7 @@ MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
bool MatchingInlineAsm) {
MCInst Inst;
unsigned MatchResult;
MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
MatchingInlineAsm);
switch (MatchResult) {

View File

@ -252,6 +252,35 @@ void ARMInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
return;
}
// Combine 2 GPRs from disassember into a GPRPair to match with instr def.
// ldrexd/strexd require even/odd GPR pair. To enforce this constraint,
// a single GPRPair reg operand is used in the .td file to replace the two
// GPRs. However, when decoding them, the two GRPs cannot be automatically
// expressed as a GPRPair, so we have to manually merge them.
// FIXME: We would really like to be able to tablegen'erate this.
if (Opcode == ARM::LDREXD || Opcode == ARM::STREXD) {
const MCRegisterClass& MRC = MRI.getRegClass(ARM::GPRRegClassID);
bool isStore = Opcode == ARM::STREXD;
unsigned Reg = MI->getOperand(isStore ? 1 : 0).getReg();
if (MRC.contains(Reg)) {
MCInst NewMI;
MCOperand NewReg;
NewMI.setOpcode(Opcode);
if (isStore)
NewMI.addOperand(MI->getOperand(0));
NewReg = MCOperand::CreateReg(MRI.getMatchingSuperReg(Reg, ARM::gsub_0,
&MRI.getRegClass(ARM::GPRPairRegClassID)));
NewMI.addOperand(NewReg);
// Copy the rest operands into NewMI.
for(unsigned i= isStore ? 3 : 2; i < MI->getNumOperands(); ++i)
NewMI.addOperand(MI->getOperand(i));
printInstruction(&NewMI, O);
return;
}
}
printInstruction(MI, O);
printAnnotation(O, Annot);
}
@ -691,6 +720,15 @@ void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum,
O << "}";
}
void ARMInstPrinter::printGPRPairOperand(const MCInst *MI, unsigned OpNum,
raw_ostream &O) {
unsigned Reg = MI->getOperand(OpNum).getReg();
printRegName(O, MRI.getSubReg(Reg, ARM::gsub_0));
O << ", ";
printRegName(O, MRI.getSubReg(Reg, ARM::gsub_1));
}
void ARMInstPrinter::printSetendOperand(const MCInst *MI, unsigned OpNum,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNum);

View File

@ -124,6 +124,7 @@ public:
void printNEONModImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printImmPlusOneOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printRotImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printGPRPairOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printPCLabel(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printThumbLdrLabelOperand(const MCInst *MI, unsigned OpNum,

View File

@ -1,12 +1,12 @@
; RUN: llc < %s -mtriple=armv7-apple-ios | FileCheck %s
define i64 @test1(i64* %ptr, i64 %val) {
; CHECK: test1
; CHECK: test1:
; CHECK: dmb ish
; CHECK: ldrexd r2, r3
; CHECK: adds r0, r2
; CHECK: adc r1, r3
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
; CHECK: adds [[REG3:(r[0-9]?[02468])]], [[REG1]]
; CHECK: adc [[REG4:(r[0-9]?[13579])]], [[REG2]]
; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
; CHECK: cmp
; CHECK: bne
; CHECK: dmb ish
@ -15,12 +15,12 @@ define i64 @test1(i64* %ptr, i64 %val) {
}
define i64 @test2(i64* %ptr, i64 %val) {
; CHECK: test2
; CHECK: test2:
; CHECK: dmb ish
; CHECK: ldrexd r2, r3
; CHECK: subs r0, r2
; CHECK: sbc r1, r3
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
; CHECK: subs [[REG3:(r[0-9]?[02468])]], [[REG1]]
; CHECK: sbc [[REG4:(r[0-9]?[13579])]], [[REG2]]
; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
; CHECK: cmp
; CHECK: bne
; CHECK: dmb ish
@ -29,12 +29,12 @@ define i64 @test2(i64* %ptr, i64 %val) {
}
define i64 @test3(i64* %ptr, i64 %val) {
; CHECK: test3
; CHECK: test3:
; CHECK: dmb ish
; CHECK: ldrexd r2, r3
; CHECK: and r0, r2
; CHECK: and r1, r3
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
; CHECK: and [[REG3:(r[0-9]?[02468])]], [[REG1]]
; CHECK: and [[REG4:(r[0-9]?[13579])]], [[REG2]]
; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
; CHECK: cmp
; CHECK: bne
; CHECK: dmb ish
@ -43,12 +43,12 @@ define i64 @test3(i64* %ptr, i64 %val) {
}
define i64 @test4(i64* %ptr, i64 %val) {
; CHECK: test4
; CHECK: test4:
; CHECK: dmb ish
; CHECK: ldrexd r2, r3
; CHECK: orr r0, r2
; CHECK: orr r1, r3
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
; CHECK: orr [[REG3:(r[0-9]?[02468])]], [[REG1]]
; CHECK: orr [[REG4:(r[0-9]?[13579])]], [[REG2]]
; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
; CHECK: cmp
; CHECK: bne
; CHECK: dmb ish
@ -57,12 +57,12 @@ define i64 @test4(i64* %ptr, i64 %val) {
}
define i64 @test5(i64* %ptr, i64 %val) {
; CHECK: test5
; CHECK: test5:
; CHECK: dmb ish
; CHECK: ldrexd r2, r3
; CHECK: eor r0, r2
; CHECK: eor r1, r3
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
; CHECK: eor [[REG3:(r[0-9]?[02468])]], [[REG1]]
; CHECK: eor [[REG4:(r[0-9]?[13579])]], [[REG2]]
; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
; CHECK: cmp
; CHECK: bne
; CHECK: dmb ish
@ -71,10 +71,10 @@ define i64 @test5(i64* %ptr, i64 %val) {
}
define i64 @test6(i64* %ptr, i64 %val) {
; CHECK: test6
; CHECK: test6:
; CHECK: dmb ish
; CHECK: ldrexd r2, r3
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
; CHECK: cmp
; CHECK: bne
; CHECK: dmb ish
@ -83,13 +83,13 @@ define i64 @test6(i64* %ptr, i64 %val) {
}
define i64 @test7(i64* %ptr, i64 %val1, i64 %val2) {
; CHECK: test7
; CHECK: test7:
; CHECK: dmb ish
; CHECK: ldrexd r2, r3
; CHECK: cmp r2
; CHECK: cmpeq r3
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
; CHECK: cmp [[REG1]]
; CHECK: cmpeq [[REG2]]
; CHECK: bne
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
; CHECK: cmp
; CHECK: bne
; CHECK: dmb ish
@ -100,12 +100,12 @@ define i64 @test7(i64* %ptr, i64 %val1, i64 %val2) {
; Compiles down to cmpxchg
; FIXME: Should compile to a single ldrexd
define i64 @test8(i64* %ptr) {
; CHECK: test8
; CHECK: ldrexd r2, r3
; CHECK: cmp r2
; CHECK: cmpeq r3
; CHECK: test8:
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
; CHECK: cmp [[REG1]]
; CHECK: cmpeq [[REG2]]
; CHECK: bne
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
; CHECK: cmp
; CHECK: bne
; CHECK: dmb ish
@ -116,10 +116,10 @@ define i64 @test8(i64* %ptr) {
; Compiles down to atomicrmw xchg; there really isn't any more efficient
; way to write it.
define void @test9(i64* %ptr, i64 %val) {
; CHECK: test9
; CHECK: test9:
; CHECK: dmb ish
; CHECK: ldrexd r2, r3
; CHECK: strexd {{[a-z0-9]+}}, r0, r1
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
; CHECK: cmp
; CHECK: bne
; CHECK: dmb ish

View File

@ -581,6 +581,7 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
REG("cc_out");
REG("s_cc_out");
REG("tGPR");
REG("GPRPairOp");
REG("DPR");
REG("DPR_VFP2");
REG("DPR_8");