llvm.org GIT mirror llvm / fc4fa22
ARM: add intrinsics for the v8 ldaex/stlex We've already got versions without the barriers, so this just adds IR-level support for generating the new v8 ones. rdar://problem/16227836 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@204813 91177308-0d34-0410-b5e6-96231b3b80d8 Tim Northover 5 years ago
6 changed file(s) with 194 addition(s) and 26 deletion(s). Raw diff Collapse all Expand all
3737
3838 def int_arm_ldrex : Intrinsic<[llvm_i32_ty], [llvm_anyptr_ty]>;
3939 def int_arm_strex : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_anyptr_ty]>;
40
41 def int_arm_ldaex : Intrinsic<[llvm_i32_ty], [llvm_anyptr_ty]>;
42 def int_arm_stlex : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_anyptr_ty]>;
43
4044 def int_arm_clrex : Intrinsic<[]>;
4145
4246 def int_arm_strexd : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty,
4347 llvm_ptr_ty]>;
4448 def int_arm_ldrexd : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [llvm_ptr_ty]>;
49
50 def int_arm_stlexd : Intrinsic<[llvm_i32_ty],
51 [llvm_i32_ty, llvm_i32_ty, llvm_ptr_ty]>;
52 def int_arm_ldaexd : Intrinsic<[llvm_i32_ty, llvm_i32_ty], [llvm_ptr_ty]>;
4553
4654 //===----------------------------------------------------------------------===//
4755 // Data barrier instructions
30213021 default:
30223022 break;
30233023
3024 case Intrinsic::arm_ldaexd:
30243025 case Intrinsic::arm_ldrexd: {
3025 SDValue MemAddr = N->getOperand(2);
30263026 SDLoc dl(N);
30273027 SDValue Chain = N->getOperand(0);
3028
3028 SDValue MemAddr = N->getOperand(2);
30293029 bool isThumb = Subtarget->isThumb() && Subtarget->hasThumb2();
3030 unsigned NewOpc = isThumb ? ARM::t2LDREXD :ARM::LDREXD;
3030
3031 bool IsAcquire = IntNo == Intrinsic::arm_ldaexd;
3032 unsigned NewOpc = isThumb ? (IsAcquire ? ARM::t2LDAEXD : ARM::t2LDREXD)
3033 : (IsAcquire ? ARM::LDAEXD : ARM::LDREXD);
30313034
30323035 // arm_ldrexd returns a i64 value in {i32, i32}
30333036 std::vector ResTys;
30793082 ReplaceUses(SDValue(N, 2), OutChain);
30803083 return NULL;
30813084 }
3082
3085 case Intrinsic::arm_stlexd:
30833086 case Intrinsic::arm_strexd: {
30843087 SDLoc dl(N);
30853088 SDValue Chain = N->getOperand(0);
31053108 Ops.push_back(CurDAG->getRegister(0, MVT::i32));
31063109 Ops.push_back(Chain);
31073110
3108 unsigned NewOpc = isThumb ? ARM::t2STREXD : ARM::STREXD;
3111 bool IsRelease = IntNo == Intrinsic::arm_stlexd;
3112 unsigned NewOpc = isThumb ? (IsRelease ? ARM::t2STLEXD : ARM::t2STREXD)
3113 : (IsRelease ? ARM::STLEXD : ARM::STREXD);
31093114
31103115 SDNode *St = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops);
31113116 // Transfer memoperands.
1114911149 Info.writeMem = true;
1115011150 return true;
1115111151 }
11152 case Intrinsic::arm_ldaex:
1115211153 case Intrinsic::arm_ldrex: {
1115311154 PointerType *PtrTy = cast(I.getArgOperand(0)->getType());
1115411155 Info.opc = ISD::INTRINSIC_W_CHAIN;
1116111162 Info.writeMem = false;
1116211163 return true;
1116311164 }
11165 case Intrinsic::arm_stlex:
1116411166 case Intrinsic::arm_strex: {
1116511167 PointerType *PtrTy = cast(I.getArgOperand(1)->getType());
1116611168 Info.opc = ISD::INTRINSIC_W_CHAIN;
1117311175 Info.writeMem = true;
1117411176 return true;
1117511177 }
11178 case Intrinsic::arm_stlexd:
1117611179 case Intrinsic::arm_strexd: {
1117711180 Info.opc = ISD::INTRINSIC_W_CHAIN;
1117811181 Info.memVT = MVT::i64;
1118411187 Info.writeMem = true;
1118511188 return true;
1118611189 }
11190 case Intrinsic::arm_ldaexd:
1118711191 case Intrinsic::arm_ldrexd: {
1118811192 Info.opc = ISD::INTRINSIC_W_CHAIN;
1118911193 Info.memVT = MVT::i64;
45734573 return cast(N)->getMemoryVT() == MVT::i32;
45744574 }]>;
45754575
4576 def ldaex_1 : PatFrag<(ops node:$ptr), (int_arm_ldaex node:$ptr), [{
4577 return cast(N)->getMemoryVT() == MVT::i8;
4578 }]>;
4579
4580 def ldaex_2 : PatFrag<(ops node:$ptr), (int_arm_ldaex node:$ptr), [{
4581 return cast(N)->getMemoryVT() == MVT::i16;
4582 }]>;
4583
4584 def ldaex_4 : PatFrag<(ops node:$ptr), (int_arm_ldaex node:$ptr), [{
4585 return cast(N)->getMemoryVT() == MVT::i32;
4586 }]>;
4587
4588 def stlex_1 : PatFrag<(ops node:$val, node:$ptr),
4589 (int_arm_stlex node:$val, node:$ptr), [{
4590 return cast(N)->getMemoryVT() == MVT::i8;
4591 }]>;
4592
4593 def stlex_2 : PatFrag<(ops node:$val, node:$ptr),
4594 (int_arm_stlex node:$val, node:$ptr), [{
4595 return cast(N)->getMemoryVT() == MVT::i16;
4596 }]>;
4597
4598 def stlex_4 : PatFrag<(ops node:$val, node:$ptr),
4599 (int_arm_stlex node:$val, node:$ptr), [{
4600 return cast(N)->getMemoryVT() == MVT::i32;
4601 }]>;
4602
45764603 let mayLoad = 1 in {
45774604 def LDREXB : AIldrex<0b10, (outs GPR:$Rt), (ins addr_offset_none:$addr),
45784605 NoItinerary, "ldrexb", "\t$Rt, $addr",
45904617 }
45914618
45924619 def LDAEXB : AIldaex<0b10, (outs GPR:$Rt), (ins addr_offset_none:$addr),
4593 NoItinerary, "ldaexb", "\t$Rt, $addr", []>;
4620 NoItinerary, "ldaexb", "\t$Rt, $addr",
4621 [(set GPR:$Rt, (ldaex_1 addr_offset_none:$addr))]>;
45944622 def LDAEXH : AIldaex<0b11, (outs GPR:$Rt), (ins addr_offset_none:$addr),
4595 NoItinerary, "ldaexh", "\t$Rt, $addr", []>;
4623 NoItinerary, "ldaexh", "\t$Rt, $addr",
4624 [(set GPR:$Rt, (ldaex_2 addr_offset_none:$addr))]>;
45964625 def LDAEX : AIldaex<0b00, (outs GPR:$Rt), (ins addr_offset_none:$addr),
4597 NoItinerary, "ldaex", "\t$Rt, $addr", []>;
4626 NoItinerary, "ldaex", "\t$Rt, $addr",
4627 [(set GPR:$Rt, (ldaex_4 addr_offset_none:$addr))]>;
45984628 let hasExtraDefRegAllocReq = 1 in
45994629 def LDAEXD : AIldaex<0b01, (outs GPRPairOp:$Rt),(ins addr_offset_none:$addr),
46004630 NoItinerary, "ldaexd", "\t$Rt, $addr", []> {
46054635 let mayStore = 1, Constraints = "@earlyclobber $Rd" in {
46064636 def STREXB: AIstrex<0b10, (outs GPR:$Rd), (ins GPR:$Rt, addr_offset_none:$addr),
46074637 NoItinerary, "strexb", "\t$Rd, $Rt, $addr",
4608 [(set GPR:$Rd, (strex_1 GPR:$Rt, addr_offset_none:$addr))]>;
4638 [(set GPR:$Rd, (strex_1 GPR:$Rt,
4639 addr_offset_none:$addr))]>;
46094640 def STREXH: AIstrex<0b11, (outs GPR:$Rd), (ins GPR:$Rt, addr_offset_none:$addr),
46104641 NoItinerary, "strexh", "\t$Rd, $Rt, $addr",
4611 [(set GPR:$Rd, (strex_2 GPR:$Rt, addr_offset_none:$addr))]>;
4642 [(set GPR:$Rd, (strex_2 GPR:$Rt,
4643 addr_offset_none:$addr))]>;
46124644 def STREX : AIstrex<0b00, (outs GPR:$Rd), (ins GPR:$Rt, addr_offset_none:$addr),
46134645 NoItinerary, "strex", "\t$Rd, $Rt, $addr",
4614 [(set GPR:$Rd, (strex_4 GPR:$Rt, addr_offset_none:$addr))]>;
4646 [(set GPR:$Rd, (strex_4 GPR:$Rt,
4647 addr_offset_none:$addr))]>;
46154648 let hasExtraSrcRegAllocReq = 1 in
46164649 def STREXD : AIstrex<0b01, (outs GPR:$Rd),
46174650 (ins GPRPairOp:$Rt, addr_offset_none:$addr),
46204653 }
46214654 def STLEXB: AIstlex<0b10, (outs GPR:$Rd), (ins GPR:$Rt, addr_offset_none:$addr),
46224655 NoItinerary, "stlexb", "\t$Rd, $Rt, $addr",
4623 []>;
4656 [(set GPR:$Rd,
4657 (stlex_1 GPR:$Rt, addr_offset_none:$addr))]>;
46244658 def STLEXH: AIstlex<0b11, (outs GPR:$Rd), (ins GPR:$Rt, addr_offset_none:$addr),
46254659 NoItinerary, "stlexh", "\t$Rd, $Rt, $addr",
4626 []>;
4660 [(set GPR:$Rd,
4661 (stlex_2 GPR:$Rt, addr_offset_none:$addr))]>;
46274662 def STLEX : AIstlex<0b00, (outs GPR:$Rd), (ins GPR:$Rt, addr_offset_none:$addr),
46284663 NoItinerary, "stlex", "\t$Rd, $Rt, $addr",
4629 []>;
4664 [(set GPR:$Rd,
4665 (stlex_4 GPR:$Rt, addr_offset_none:$addr))]>;
46304666 let hasExtraSrcRegAllocReq = 1 in
46314667 def STLEXD : AIstlex<0b01, (outs GPR:$Rd),
46324668 (ins GPRPairOp:$Rt, addr_offset_none:$addr),
46494685 (STREXB GPR:$Rt, addr_offset_none:$addr)>;
46504686 def : ARMPat<(strex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr),
46514687 (STREXH GPR:$Rt, addr_offset_none:$addr)>;
4688
4689 def : ARMPat<(and (ldaex_1 addr_offset_none:$addr), 0xff),
4690 (LDAEXB addr_offset_none:$addr)>;
4691 def : ARMPat<(and (ldaex_2 addr_offset_none:$addr), 0xffff),
4692 (LDAEXH addr_offset_none:$addr)>;
4693 def : ARMPat<(stlex_1 (and GPR:$Rt, 0xff), addr_offset_none:$addr),
4694 (STLEXB GPR:$Rt, addr_offset_none:$addr)>;
4695 def : ARMPat<(stlex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr),
4696 (STLEXH GPR:$Rt, addr_offset_none:$addr)>;
46524697
46534698 class acquiring_load
46544699 : PatFrag<(ops node:$ptr), (base node:$ptr), [{
32833283 def t2LDAEXB : T2I_ldrex<0b1100, (outs rGPR:$Rt), (ins addr_offset_none:$addr),
32843284 AddrModeNone, 4, NoItinerary,
32853285 "ldaexb", "\t$Rt, $addr", "",
3286 []>, Requires<[IsThumb, HasV8]>;
3286 [(set rGPR:$Rt, (ldaex_1 addr_offset_none:$addr))]>,
3287 Requires<[IsThumb, HasV8]>;
32873288 def t2LDAEXH : T2I_ldrex<0b1101, (outs rGPR:$Rt), (ins addr_offset_none:$addr),
32883289 AddrModeNone, 4, NoItinerary,
32893290 "ldaexh", "\t$Rt, $addr", "",
3290 []>, Requires<[IsThumb, HasV8]>;
3291 [(set rGPR:$Rt, (ldaex_2 addr_offset_none:$addr))]>,
3292 Requires<[IsThumb, HasV8]>;
32913293 def t2LDAEX : Thumb2I<(outs rGPR:$Rt), (ins addr_offset_none:$addr),
32923294 AddrModeNone, 4, NoItinerary,
32933295 "ldaex", "\t$Rt, $addr", "",
3294 []>, Requires<[IsThumb, HasV8]> {
3296 [(set rGPR:$Rt, (ldaex_4 addr_offset_none:$addr))]>,
3297 Requires<[IsThumb, HasV8]> {
32953298 bits<4> Rt;
32963299 bits<4> addr;
32973300 let Inst{31-27} = 0b11101;
33193322 (ins rGPR:$Rt, addr_offset_none:$addr),
33203323 AddrModeNone, 4, NoItinerary,
33213324 "strexb", "\t$Rd, $Rt, $addr", "",
3322 [(set rGPR:$Rd, (strex_1 rGPR:$Rt,
3323 addr_offset_none:$addr))]>;
3325 [(set rGPR:$Rd,
3326 (strex_1 rGPR:$Rt, addr_offset_none:$addr))]>;
33243327 def t2STREXH : T2I_strex<0b0101, (outs rGPR:$Rd),
33253328 (ins rGPR:$Rt, addr_offset_none:$addr),
33263329 AddrModeNone, 4, NoItinerary,
33273330 "strexh", "\t$Rd, $Rt, $addr", "",
3328 [(set rGPR:$Rd, (strex_2 rGPR:$Rt,
3329 addr_offset_none:$addr))]>;
3331 [(set rGPR:$Rd,
3332 (strex_2 rGPR:$Rt, addr_offset_none:$addr))]>;
33303333
33313334 def t2STREX : Thumb2I<(outs rGPR:$Rd), (ins rGPR:$Rt,
33323335 t2addrmode_imm0_1020s4:$addr),
33333336 AddrModeNone, 4, NoItinerary,
33343337 "strex", "\t$Rd, $Rt, $addr", "",
3335 [(set rGPR:$Rd, (strex_4 rGPR:$Rt,
3336 t2addrmode_imm0_1020s4:$addr))]> {
3338 [(set rGPR:$Rd,
3339 (strex_4 rGPR:$Rt, t2addrmode_imm0_1020s4:$addr))]> {
33373340 bits<4> Rd;
33383341 bits<4> Rt;
33393342 bits<12> addr;
33573360 (ins rGPR:$Rt, addr_offset_none:$addr),
33583361 AddrModeNone, 4, NoItinerary,
33593362 "stlexb", "\t$Rd, $Rt, $addr", "",
3360 []>, Requires<[IsThumb, HasV8]>;
3363 [(set rGPR:$Rd,
3364 (stlex_1 rGPR:$Rt, addr_offset_none:$addr))]>,
3365 Requires<[IsThumb, HasV8]>;
33613366
33623367 def t2STLEXH : T2I_strex<0b1101, (outs rGPR:$Rd),
33633368 (ins rGPR:$Rt, addr_offset_none:$addr),
33643369 AddrModeNone, 4, NoItinerary,
33653370 "stlexh", "\t$Rd, $Rt, $addr", "",
3366 []>, Requires<[IsThumb, HasV8]>;
3371 [(set rGPR:$Rd,
3372 (stlex_2 rGPR:$Rt, addr_offset_none:$addr))]>,
3373 Requires<[IsThumb, HasV8]>;
33673374
33683375 def t2STLEX : Thumb2I<(outs rGPR:$Rd), (ins rGPR:$Rt,
33693376 addr_offset_none:$addr),
33703377 AddrModeNone, 4, NoItinerary,
33713378 "stlex", "\t$Rd, $Rt, $addr", "",
3372 []>, Requires<[IsThumb, HasV8]> {
3379 [(set rGPR:$Rd,
3380 (stlex_4 rGPR:$Rt, addr_offset_none:$addr))]>,
3381 Requires<[IsThumb, HasV8]> {
33733382 bits<4> Rd;
33743383 bits<4> Rt;
33753384 bits<4> addr;
34103419 (t2STREXB GPR:$Rt, addr_offset_none:$addr)>;
34113420 def : T2Pat<(strex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr),
34123421 (t2STREXH GPR:$Rt, addr_offset_none:$addr)>;
3422
3423 def : T2Pat<(and (ldaex_1 addr_offset_none:$addr), 0xff),
3424 (t2LDAEXB addr_offset_none:$addr)>;
3425 def : T2Pat<(and (ldaex_2 addr_offset_none:$addr), 0xffff),
3426 (t2LDAEXH addr_offset_none:$addr)>;
3427 def : T2Pat<(stlex_1 (and GPR:$Rt, 0xff), addr_offset_none:$addr),
3428 (t2STLEXB GPR:$Rt, addr_offset_none:$addr)>;
3429 def : T2Pat<(stlex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr),
3430 (t2STLEXH GPR:$Rt, addr_offset_none:$addr)>;
34133431
34143432 //===----------------------------------------------------------------------===//
34153433 // SJLJ Exception handling intrinsics
0 ; RUN: llc < %s -mtriple=armv8-apple-darwin | FileCheck %s
1 ; RUN: llc < %s -mtriple=thumbv8-apple-darwin | FileCheck %s
2
3 %0 = type { i32, i32 }
4
5 ; CHECK-LABEL: f0:
6 ; CHECK: ldaexd
7 define i64 @f0(i8* %p) nounwind readonly {
8 entry:
9 %ldaexd = tail call %0 @llvm.arm.ldaexd(i8* %p)
10 %0 = extractvalue %0 %ldaexd, 1
11 %1 = extractvalue %0 %ldaexd, 0
12 %2 = zext i32 %0 to i64
13 %3 = zext i32 %1 to i64
14 %shl = shl nuw i64 %2, 32
15 %4 = or i64 %shl, %3
16 ret i64 %4
17 }
18
19 ; CHECK-LABEL: f1:
20 ; CHECK: stlexd
21 define i32 @f1(i8* %ptr, i64 %val) nounwind {
22 entry:
23 %tmp4 = trunc i64 %val to i32
24 %tmp6 = lshr i64 %val, 32
25 %tmp7 = trunc i64 %tmp6 to i32
26 %stlexd = tail call i32 @llvm.arm.stlexd(i32 %tmp4, i32 %tmp7, i8* %ptr)
27 ret i32 %stlexd
28 }
29
30 declare %0 @llvm.arm.ldaexd(i8*) nounwind readonly
31 declare i32 @llvm.arm.stlexd(i32, i32, i8*) nounwind
32
33 ; CHECK-LABEL: test_load_i8:
34 ; CHECK: ldaexb r0, [r0]
35 ; CHECK-NOT: uxtb
36 define i32 @test_load_i8(i8* %addr) {
37 %val = call i32 @llvm.arm.ldaex.p0i8(i8* %addr)
38 ret i32 %val
39 }
40
41 ; CHECK-LABEL: test_load_i16:
42 ; CHECK: ldaexh r0, [r0]
43 ; CHECK-NOT: uxth
44 define i32 @test_load_i16(i16* %addr) {
45 %val = call i32 @llvm.arm.ldaex.p0i16(i16* %addr)
46 ret i32 %val
47 }
48
49 ; CHECK-LABEL: test_load_i32:
50 ; CHECK: ldaex r0, [r0]
51 define i32 @test_load_i32(i32* %addr) {
52 %val = call i32 @llvm.arm.ldaex.p0i32(i32* %addr)
53 ret i32 %val
54 }
55
56 declare i32 @llvm.arm.ldaex.p0i8(i8*) nounwind readonly
57 declare i32 @llvm.arm.ldaex.p0i16(i16*) nounwind readonly
58 declare i32 @llvm.arm.ldaex.p0i32(i32*) nounwind readonly
59
60 ; CHECK-LABEL: test_store_i8:
61 ; CHECK-NOT: uxtb
62 ; CHECK: stlexb r0, r1, [r2]
63 define i32 @test_store_i8(i32, i8 %val, i8* %addr) {
64 %extval = zext i8 %val to i32
65 %res = call i32 @llvm.arm.stlex.p0i8(i32 %extval, i8* %addr)
66 ret i32 %res
67 }
68
69 ; CHECK-LABEL: test_store_i16:
70 ; CHECK-NOT: uxth
71 ; CHECK: stlexh r0, r1, [r2]
72 define i32 @test_store_i16(i32, i16 %val, i16* %addr) {
73 %extval = zext i16 %val to i32
74 %res = call i32 @llvm.arm.stlex.p0i16(i32 %extval, i16* %addr)
75 ret i32 %res
76 }
77
78 ; CHECK-LABEL: test_store_i32:
79 ; CHECK: stlex r0, r1, [r2]
80 define i32 @test_store_i32(i32, i32 %val, i32* %addr) {
81 %res = call i32 @llvm.arm.stlex.p0i32(i32 %val, i32* %addr)
82 ret i32 %res
83 }
84
85 declare i32 @llvm.arm.stlex.p0i8(i32, i8*) nounwind
86 declare i32 @llvm.arm.stlex.p0i16(i32, i16*) nounwind
87 declare i32 @llvm.arm.stlex.p0i32(i32, i32*) nounwind