llvm.org GIT mirror llvm / e56764b
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@168207 91177308-0d34-0410-b5e6-96231b3b80d8 Weiming Zhao 8 years ago
8 changed file(s) with 227 addition(s) and 103 deletion(s). Raw diff Collapse all Expand all
265265 std::vector &OutOps);
266266
267267 // Form pairs of consecutive S, D, or Q registers.
268 SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);
268269 SDNode *PairSRegs(EVT VT, SDValue V0, SDValue V1);
269270 SDNode *PairDRegs(EVT VT, SDValue V0, SDValue V1);
270271 SDNode *PairQRegs(EVT VT, SDValue V0, SDValue V1);
14411442 }
14421443
14431444 return NULL;
1445 }
1446
1447 /// \brief Form a GPRPair pseudo register from a pair of GPR regs.
1448 SDNode *ARMDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
1449 DebugLoc dl = V0.getNode()->getDebugLoc();
1450 SDValue RegClass =
1451 CurDAG->getTargetConstant(ARM::GPRPairRegClassID, MVT::i32);
1452 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::gsub_0, MVT::i32);
1453 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::gsub_1, MVT::i32);
1454 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
1455 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 5);
14441456 }
14451457
14461458 /// PairSRegs - Form a D register from a pair of S registers.
30083020 DebugLoc dl = N->getDebugLoc();
30093021 SDValue Chain = N->getOperand(0);
30103022
3011 unsigned NewOpc = ARM::LDREXD;
3012 if (Subtarget->isThumb() && Subtarget->hasThumb2())
3013 NewOpc = ARM::t2LDREXD;
3023 bool isThumb = Subtarget->isThumb() && Subtarget->hasThumb2();
3024 unsigned NewOpc = isThumb ? ARM::t2LDREXD :ARM::LDREXD;
30143025
30153026 // arm_ldrexd returns a i64 value in {i32, i32}
30163027 std::vector ResTys;
3017 ResTys.push_back(MVT::i32);
3018 ResTys.push_back(MVT::i32);
3028 if (isThumb) {
3029 ResTys.push_back(MVT::i32);
3030 ResTys.push_back(MVT::i32);
3031 } else
3032 ResTys.push_back(MVT::Untyped);
30193033 ResTys.push_back(MVT::Other);
30203034
3021 // place arguments in the right order
3035 // Place arguments in the right order.
30223036 SmallVector Ops;
30233037 Ops.push_back(MemAddr);
30243038 Ops.push_back(getAL(CurDAG));
30313045 MemOp[0] = cast(N)->getMemOperand();
30323046 cast(Ld)->setMemRefs(MemOp, MemOp + 1);
30333047
3034 // Until there's support for specifing explicit register constraints
3035 // like the use of even/odd register pair, hardcode ldrexd to always
3036 // use the pair [R0, R1] to hold the load result.
3037 Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, ARM::R0,
3038 SDValue(Ld, 0), SDValue(0,0));
3039 Chain = CurDAG->getCopyToReg(Chain, dl, ARM::R1,
3040 SDValue(Ld, 1), Chain.getValue(1));
3041
30423048 // Remap uses.
3043 SDValue Glue = Chain.getValue(1);
3049 SDValue Glue = isThumb ? SDValue(Ld, 2) : SDValue(Ld, 1);
30443050 if (!SDValue(N, 0).use_empty()) {
3045 SDValue Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
3046 ARM::R0, MVT::i32, Glue);
3047 Glue = Result.getValue(2);
3051 SDValue Result;
3052 if (isThumb)
3053 Result = SDValue(Ld, 0);
3054 else {
3055 SDValue SubRegIdx = CurDAG->getTargetConstant(ARM::gsub_0, MVT::i32);
3056 SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
3057 dl, MVT::i32, MVT::Glue, SDValue(Ld, 0), SubRegIdx, Glue);
3058 Result = SDValue(ResNode,0);
3059 Glue = Result.getValue(1);
3060 }
30483061 ReplaceUses(SDValue(N, 0), Result);
30493062 }
30503063 if (!SDValue(N, 1).use_empty()) {
3051 SDValue Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
3052 ARM::R1, MVT::i32, Glue);
3053 Glue = Result.getValue(2);
3064 SDValue Result;
3065 if (isThumb)
3066 Result = SDValue(Ld, 1);
3067 else {
3068 SDValue SubRegIdx = CurDAG->getTargetConstant(ARM::gsub_1, MVT::i32);
3069 SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
3070 dl, MVT::i32, MVT::Glue, SDValue(Ld, 0), SubRegIdx, Glue);
3071 Result = SDValue(ResNode,0);
3072 Glue = Result.getValue(1);
3073 }
30543074 ReplaceUses(SDValue(N, 1), Result);
30553075 }
3056
3057 ReplaceUses(SDValue(N, 2), SDValue(Ld, 2));
3076 ReplaceUses(SDValue(N, 2), Glue);
30583077 return NULL;
30593078 }
30603079
30653084 SDValue Val1 = N->getOperand(3);
30663085 SDValue MemAddr = N->getOperand(4);
30673086
3068 // Until there's support for specifing explicit register constraints
3069 // like the use of even/odd register pair, hardcode strexd to always
3070 // use the pair [R2, R3] to hold the i64 (i32, i32) value to be stored.
3071 Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, ARM::R2, Val0,
3072 SDValue(0, 0));
3073 Chain = CurDAG->getCopyToReg(Chain, dl, ARM::R3, Val1, Chain.getValue(1));
3074
3075 SDValue Glue = Chain.getValue(1);
3076 Val0 = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
3077 ARM::R2, MVT::i32, Glue);
3078 Glue = Val0.getValue(1);
3079 Val1 = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
3080 ARM::R3, MVT::i32, Glue);
3081
30823087 // Store exclusive double return a i32 value which is the return status
30833088 // of the issued store.
30843089 std::vector ResTys;
30853090 ResTys.push_back(MVT::i32);
30863091 ResTys.push_back(MVT::Other);
30873092
3088 // place arguments in the right order
3093 bool isThumb = Subtarget->isThumb() && Subtarget->hasThumb2();
3094 // Place arguments in the right order.
30893095 SmallVector Ops;
3090 Ops.push_back(Val0);
3091 Ops.push_back(Val1);
3096 if (isThumb) {
3097 Ops.push_back(Val0);
3098 Ops.push_back(Val1);
3099 } else
3100 // arm_strexd uses GPRPair.
3101 Ops.push_back(SDValue(createGPRPairNode(MVT::Untyped, Val0, Val1), 0));
30923102 Ops.push_back(MemAddr);
30933103 Ops.push_back(getAL(CurDAG));
30943104 Ops.push_back(CurDAG->getRegister(0, MVT::i32));
30953105 Ops.push_back(Chain);
30963106
3097 unsigned NewOpc = ARM::STREXD;
3098 if (Subtarget->isThumb() && Subtarget->hasThumb2())
3099 NewOpc = ARM::t2STREXD;
3107 unsigned NewOpc = isThumb ? ARM::t2STREXD : ARM::STREXD;
31003108
31013109 SDNode *St = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops.data(),
31023110 Ops.size());
58065806 // for ldrexd must be different.
58075807 BB = loopMBB;
58085808 // Load
5809 unsigned GPRPair0 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
5810 unsigned GPRPair1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
5811
58095812 AddDefaultPred(BuildMI(BB, dl, TII->get(ldrOpc))
5810 .addReg(ARM::R2, RegState::Define)
5811 .addReg(ARM::R3, RegState::Define).addReg(ptr));
5813 .addReg(GPRPair0, RegState::Define).addReg(ptr));
58125814 // Copy r2/r3 into dest. (This copy will normally be coalesced.)
5813 BuildMI(BB, dl, TII->get(TargetOpcode::COPY), destlo).addReg(ARM::R2);
5814 BuildMI(BB, dl, TII->get(TargetOpcode::COPY), desthi).addReg(ARM::R3);
5815 BuildMI(BB, dl, TII->get(TargetOpcode::COPY), destlo)
5816 .addReg(GPRPair0, 0, ARM::gsub_0);
5817 BuildMI(BB, dl, TII->get(TargetOpcode::COPY), desthi)
5818 .addReg(GPRPair0, 0, ARM::gsub_1);
58155819
58165820 if (IsCmpxchg) {
58175821 // Add early exit
58305834 // Copy to physregs for strexd
58315835 unsigned setlo = MI->getOperand(5).getReg();
58325836 unsigned sethi = MI->getOperand(6).getReg();
5833 BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R0).addReg(setlo);
5834 BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R1).addReg(sethi);
5837 unsigned undef = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
5838 unsigned r1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
5839 BuildMI(BB, dl, TII->get(TargetOpcode::IMPLICIT_DEF), undef);
5840 BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), r1)
5841 .addReg(undef)
5842 .addReg(setlo)
5843 .addImm(ARM::gsub_0);
5844 BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), GPRPair1)
5845 .addReg(r1)
5846 .addReg(sethi)
5847 .addImm(ARM::gsub_1);
58355848 } else if (Op1) {
58365849 // Perform binary operation
5837 AddDefaultPred(BuildMI(BB, dl, TII->get(Op1), ARM::R0)
5850 unsigned tmpRegLo = MRI.createVirtualRegister(TRC);
5851 AddDefaultPred(BuildMI(BB, dl, TII->get(Op1), tmpRegLo)
58385852 .addReg(destlo).addReg(vallo))
58395853 .addReg(NeedsCarry ? ARM::CPSR : 0, getDefRegState(NeedsCarry));
5840 AddDefaultPred(BuildMI(BB, dl, TII->get(Op2), ARM::R1)
5854 unsigned tmpRegHi = MRI.createVirtualRegister(TRC);
5855 AddDefaultPred(BuildMI(BB, dl, TII->get(Op2), tmpRegHi)
58415856 .addReg(desthi).addReg(valhi)).addReg(0);
5857
5858 unsigned UndefPair = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
5859 BuildMI(BB, dl, TII->get(TargetOpcode::IMPLICIT_DEF), UndefPair);
5860 unsigned r1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
5861 BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), r1)
5862 .addReg(UndefPair)
5863 .addReg(tmpRegLo)
5864 .addImm(ARM::gsub_0);
5865 BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), GPRPair1)
5866 .addReg(r1)
5867 .addReg(tmpRegHi)
5868 .addImm(ARM::gsub_1);
58425869 } else {
58435870 // Copy to physregs for strexd
5844 BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R0).addReg(vallo);
5845 BuildMI(BB, dl, TII->get(TargetOpcode::COPY), ARM::R1).addReg(valhi);
5871 unsigned UndefPair = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
5872 unsigned r1 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
5873 BuildMI(BB, dl, TII->get(TargetOpcode::IMPLICIT_DEF), UndefPair);
5874 BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), r1)
5875 .addReg(UndefPair)
5876 .addReg(vallo)
5877 .addImm(ARM::gsub_0);
5878 BuildMI(BB, dl, TII->get(TargetOpcode::INSERT_SUBREG), GPRPair1)
5879 .addReg(r1)
5880 .addReg(valhi)
5881 .addImm(ARM::gsub_1);
58465882 }
58475883
58485884 // Store
58495885 AddDefaultPred(BuildMI(BB, dl, TII->get(strOpc), storesuccess)
5850 .addReg(ARM::R0).addReg(ARM::R1).addReg(ptr));
5886 .addReg(GPRPair1).addReg(ptr));
58515887 // Cmp+jump
58525888 AddDefaultPred(BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri))
58535889 .addReg(storesuccess).addImm(0));
415415 let PrintMethod = "printRegisterList";
416416 let DecoderMethod = "DecodeRegListOperand";
417417 }
418
419 def GPRPairOp : RegisterOperand;
418420
419421 def DPRRegListAsmOperand : AsmOperandClass { let Name = "DPRRegList"; }
420422 def dpr_reglist : Operand {
42284230 def LDREX : AIldrex<0b00, (outs GPR:$Rt), (ins addr_offset_none:$addr),
42294231 NoItinerary, "ldrex", "\t$Rt, $addr", []>;
42304232 let hasExtraDefRegAllocReq = 1 in
4231 def LDREXD: AIldrex<0b01, (outs GPR:$Rt, GPR:$Rt2),(ins addr_offset_none:$addr),
4232 NoItinerary, "ldrexd", "\t$Rt, $Rt2, $addr", []> {
4233 def LDREXD: AIldrex<0b01, (outs GPRPairOp:$Rt),(ins addr_offset_none:$addr),
4234 NoItinerary, "ldrexd", "\t$Rt, $addr", []> {
42334235 let DecoderMethod = "DecodeDoubleRegLoad";
42344236 }
42354237 }
42434245 NoItinerary, "strex", "\t$Rd, $Rt, $addr", []>;
42444246 let hasExtraSrcRegAllocReq = 1 in
42454247 def STREXD : AIstrex<0b01, (outs GPR:$Rd),
4246 (ins GPR:$Rt, GPR:$Rt2, addr_offset_none:$addr),
4247 NoItinerary, "strexd", "\t$Rd, $Rt, $Rt2, $addr", []> {
4248 (ins GPRPairOp:$Rt, addr_offset_none:$addr),
4249 NoItinerary, "strexd", "\t$Rd, $Rt, $addr", []> {
42484250 let DecoderMethod = "DecodeDoubleRegStore";
42494251 }
42504252 }
51865186 }
51875187 }
51885188
5189 // Adjust operands of ldrexd/strexd to MCK_GPRPair.
5190 // ldrexd/strexd require even/odd GPR pair. To enforce this constraint,
5191 // a single GPRPair reg operand is used in the .td file to replace the two
5192 // GPRs. However, when parsing from asm, the two GRPs cannot be automatically
5193 // expressed as a GPRPair, so we have to manually merge them.
5194 // FIXME: We would really like to be able to tablegen'erate this.
5195 if (!isThumb() && Operands.size() > 4 &&
5196 (Mnemonic == "ldrexd" || Mnemonic == "strexd")) {
5197 bool isLoad = (Mnemonic == "ldrexd");
5198 unsigned Idx = isLoad ? 2 : 3;
5199 ARMOperand* Op1 = static_cast(Operands[Idx]);
5200 ARMOperand* Op2 = static_cast(Operands[Idx+1]);
5201
5202 const MCRegisterClass& MRC = MRI->getRegClass(ARM::GPRRegClassID);
5203 // Adjust only if Op1 and Op2 are GPRs.
5204 if (Op1->isReg() && Op2->isReg() && MRC.contains(Op1->getReg()) &&
5205 MRC.contains(Op2->getReg())) {
5206 unsigned Reg1 = Op1->getReg();
5207 unsigned Reg2 = Op2->getReg();
5208 unsigned Rt = MRI->getEncodingValue(Reg1);
5209 unsigned Rt2 = MRI->getEncodingValue(Reg2);
5210
5211 // Rt2 must be Rt + 1 and Rt must be even.
5212 if (Rt + 1 != Rt2 || (Rt & 1)) {
5213 Error(Op2->getStartLoc(), isLoad ?
5214 "destination operands must be sequential" :
5215 "source operands must be sequential");
5216 return true;
5217 }
5218 unsigned NewReg = MRI->getMatchingSuperReg(Reg1, ARM::gsub_0,
5219 &(MRI->getRegClass(ARM::GPRPairRegClassID)));
5220 Operands.erase(Operands.begin() + Idx, Operands.begin() + Idx + 2);
5221 Operands.insert(Operands.begin() + Idx, ARMOperand::CreateReg(
5222 NewReg, Op1->getStartLoc(), Op2->getEndLoc()));
5223 delete Op1;
5224 delete Op2;
5225 }
5226 }
5227
51895228 return false;
51905229 }
51915230
52735312 switch (Inst.getOpcode()) {
52745313 case ARM::LDRD:
52755314 case ARM::LDRD_PRE:
5276 case ARM::LDRD_POST:
5277 case ARM::LDREXD: {
5315 case ARM::LDRD_POST: {
52785316 // Rt2 must be Rt + 1.
52795317 unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
52805318 unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
52935331 return false;
52945332 }
52955333 case ARM::STRD_PRE:
5296 case ARM::STRD_POST:
5297 case ARM::STREXD: {
5334 case ARM::STRD_POST: {
52985335 // Rt2 must be Rt + 1.
52995336 unsigned Rt = MRI->getEncodingValue(Inst.getOperand(1).getReg());
53005337 unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(2).getReg());
74827519 bool MatchingInlineAsm) {
74837520 MCInst Inst;
74847521 unsigned MatchResult;
7522
74857523 MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
74867524 MatchingInlineAsm);
74877525 switch (MatchResult) {
249249 printPredicateOperand(MI, 2, O);
250250 printAnnotation(O, Annot);
251251 return;
252 }
253
254 // Combine 2 GPRs from disassember into a GPRPair to match with instr def.
255 // ldrexd/strexd require even/odd GPR pair. To enforce this constraint,
256 // a single GPRPair reg operand is used in the .td file to replace the two
257 // GPRs. However, when decoding them, the two GRPs cannot be automatically
258 // expressed as a GPRPair, so we have to manually merge them.
259 // FIXME: We would really like to be able to tablegen'erate this.
260 if (Opcode == ARM::LDREXD || Opcode == ARM::STREXD) {
261 const MCRegisterClass& MRC = MRI.getRegClass(ARM::GPRRegClassID);
262 bool isStore = Opcode == ARM::STREXD;
263 unsigned Reg = MI->getOperand(isStore ? 1 : 0).getReg();
264 if (MRC.contains(Reg)) {
265 MCInst NewMI;
266 MCOperand NewReg;
267 NewMI.setOpcode(Opcode);
268
269 if (isStore)
270 NewMI.addOperand(MI->getOperand(0));
271 NewReg = MCOperand::CreateReg(MRI.getMatchingSuperReg(Reg, ARM::gsub_0,
272 &MRI.getRegClass(ARM::GPRPairRegClassID)));
273 NewMI.addOperand(NewReg);
274
275 // Copy the rest operands into NewMI.
276 for(unsigned i= isStore ? 3 : 2; i < MI->getNumOperands(); ++i)
277 NewMI.addOperand(MI->getOperand(i));
278 printInstruction(&NewMI, O);
279 return;
280 }
252281 }
253282
254283 printInstruction(MI, O);
689718 }
690719 O << "}";
691720 }
721
722 void ARMInstPrinter::printGPRPairOperand(const MCInst *MI, unsigned OpNum,
723 raw_ostream &O) {
724 unsigned Reg = MI->getOperand(OpNum).getReg();
725 printRegName(O, MRI.getSubReg(Reg, ARM::gsub_0));
726 O << ", ";
727 printRegName(O, MRI.getSubReg(Reg, ARM::gsub_1));
728 }
729
692730
693731 void ARMInstPrinter::printSetendOperand(const MCInst *MI, unsigned OpNum,
694732 raw_ostream &O) {
123123 void printNEONModImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
124124 void printImmPlusOneOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
125125 void printRotImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
126 void printGPRPairOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
126127
127128 void printPCLabel(const MCInst *MI, unsigned OpNum, raw_ostream &O);
128129 void printThumbLdrLabelOperand(const MCInst *MI, unsigned OpNum,
0 ; RUN: llc < %s -mtriple=armv7-apple-ios | FileCheck %s
11
22 define i64 @test1(i64* %ptr, i64 %val) {
3 ; CHECK: test1
3 ; CHECK: test1:
44 ; CHECK: dmb ish
5 ; CHECK: ldrexd r2, r3
6 ; CHECK: adds r0, r2
7 ; CHECK: adc r1, r3
8 ; CHECK: strexd {{[a-z0-9]+}}, r0, r1
5 ; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
6 ; CHECK: adds [[REG3:(r[0-9]?[02468])]], [[REG1]]
7 ; CHECK: adc [[REG4:(r[0-9]?[13579])]], [[REG2]]
8 ; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
99 ; CHECK: cmp
1010 ; CHECK: bne
1111 ; CHECK: dmb ish
1414 }
1515
1616 define i64 @test2(i64* %ptr, i64 %val) {
17 ; CHECK: test2
17 ; CHECK: test2:
1818 ; CHECK: dmb ish
19 ; CHECK: ldrexd r2, r3
20 ; CHECK: subs r0, r2
21 ; CHECK: sbc r1, r3
22 ; CHECK: strexd {{[a-z0-9]+}}, r0, r1
19 ; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
20 ; CHECK: subs [[REG3:(r[0-9]?[02468])]], [[REG1]]
21 ; CHECK: sbc [[REG4:(r[0-9]?[13579])]], [[REG2]]
22 ; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
2323 ; CHECK: cmp
2424 ; CHECK: bne
2525 ; CHECK: dmb ish
2828 }
2929
3030 define i64 @test3(i64* %ptr, i64 %val) {
31 ; CHECK: test3
31 ; CHECK: test3:
3232 ; CHECK: dmb ish
33 ; CHECK: ldrexd r2, r3
34 ; CHECK: and r0, r2
35 ; CHECK: and r1, r3
36 ; CHECK: strexd {{[a-z0-9]+}}, r0, r1
33 ; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
34 ; CHECK: and [[REG3:(r[0-9]?[02468])]], [[REG1]]
35 ; CHECK: and [[REG4:(r[0-9]?[13579])]], [[REG2]]
36 ; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
3737 ; CHECK: cmp
3838 ; CHECK: bne
3939 ; CHECK: dmb ish
4242 }
4343
4444 define i64 @test4(i64* %ptr, i64 %val) {
45 ; CHECK: test4
45 ; CHECK: test4:
4646 ; CHECK: dmb ish
47 ; CHECK: ldrexd r2, r3
48 ; CHECK: orr r0, r2
49 ; CHECK: orr r1, r3
50 ; CHECK: strexd {{[a-z0-9]+}}, r0, r1
47 ; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
48 ; CHECK: orr [[REG3:(r[0-9]?[02468])]], [[REG1]]
49 ; CHECK: orr [[REG4:(r[0-9]?[13579])]], [[REG2]]
50 ; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
5151 ; CHECK: cmp
5252 ; CHECK: bne
5353 ; CHECK: dmb ish
5656 }
5757
5858 define i64 @test5(i64* %ptr, i64 %val) {
59 ; CHECK: test5
59 ; CHECK: test5:
6060 ; CHECK: dmb ish
61 ; CHECK: ldrexd r2, r3
62 ; CHECK: eor r0, r2
63 ; CHECK: eor r1, r3
64 ; CHECK: strexd {{[a-z0-9]+}}, r0, r1
61 ; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
62 ; CHECK: eor [[REG3:(r[0-9]?[02468])]], [[REG1]]
63 ; CHECK: eor [[REG4:(r[0-9]?[13579])]], [[REG2]]
64 ; CHECK: strexd {{[a-z0-9]+}}, [[REG3]], [[REG4]]
6565 ; CHECK: cmp
6666 ; CHECK: bne
6767 ; CHECK: dmb ish
7070 }
7171
7272 define i64 @test6(i64* %ptr, i64 %val) {
73 ; CHECK: test6
73 ; CHECK: test6:
7474 ; CHECK: dmb ish
75 ; CHECK: ldrexd r2, r3
76 ; CHECK: strexd {{[a-z0-9]+}}, r0, r1
75 ; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
76 ; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
7777 ; CHECK: cmp
7878 ; CHECK: bne
7979 ; CHECK: dmb ish
8282 }
8383
8484 define i64 @test7(i64* %ptr, i64 %val1, i64 %val2) {
85 ; CHECK: test7
85 ; CHECK: test7:
8686 ; CHECK: dmb ish
87 ; CHECK: ldrexd r2, r3
88 ; CHECK: cmp r2
89 ; CHECK: cmpeq r3
87 ; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
88 ; CHECK: cmp [[REG1]]
89 ; CHECK: cmpeq [[REG2]]
9090 ; CHECK: bne
91 ; CHECK: strexd {{[a-z0-9]+}}, r0, r1
91 ; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
9292 ; CHECK: cmp
9393 ; CHECK: bne
9494 ; CHECK: dmb ish
9999 ; Compiles down to cmpxchg
100100 ; FIXME: Should compile to a single ldrexd
101101 define i64 @test8(i64* %ptr) {
102 ; CHECK: test8
103 ; CHECK: ldrexd r2, r3
104 ; CHECK: cmp r2
105 ; CHECK: cmpeq r3
102 ; CHECK: test8:
103 ; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
104 ; CHECK: cmp [[REG1]]
105 ; CHECK: cmpeq [[REG2]]
106106 ; CHECK: bne
107 ; CHECK: strexd {{[a-z0-9]+}}, r0, r1
107 ; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
108108 ; CHECK: cmp
109109 ; CHECK: bne
110110 ; CHECK: dmb ish
115115 ; Compiles down to atomicrmw xchg; there really isn't any more efficient
116116 ; way to write it.
117117 define void @test9(i64* %ptr, i64 %val) {
118 ; CHECK: test9
118 ; CHECK: test9:
119119 ; CHECK: dmb ish
120 ; CHECK: ldrexd r2, r3
121 ; CHECK: strexd {{[a-z0-9]+}}, r0, r1
120 ; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
121 ; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
122122 ; CHECK: cmp
123123 ; CHECK: bne
124124 ; CHECK: dmb ish
580580 REG("cc_out");
581581 REG("s_cc_out");
582582 REG("tGPR");
583 REG("GPRPairOp");
583584 REG("DPR");
584585 REG("DPR_VFP2");
585586 REG("DPR_8");