Skip to content

Commit 57bdd98

Browse files
nikictstellar
authored andcommitted
[ARM] Add target feature to force 32-bit atomics
This adds a +atomic-32 target feature, which instructs LLVM to assume that lock-free 32-bit atomics are available for this target, even if they usually wouldn't be. If only atomic loads/stores are used, then this won't emit libcalls. If atomic CAS is used, then the user is responsible for providing any necessary __sync implementations (e.g. by masking interrupts for single-core privileged use cases). See https://reviews.llvm.org/D120026#3674333 for context on this change. The tl;dr is that the thumbv6m target in Rust has historically made atomic load/store only available, which is incompatible with the change from D120026, which switched these to use libatomic. Differential Revision: https://reviews.llvm.org/D130480 (cherry picked from commit b1b1086)
1 parent e077f4a commit 57bdd98

File tree

3 files changed

+214
-1
lines changed

3 files changed

+214
-1
lines changed

llvm/lib/Target/ARM/ARM.td

+9
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,15 @@ def FeatureAAPCSFrameChainLeaf : SubtargetFeature<"aapcs-frame-chain-leaf",
556556
"for leaf functions",
557557
[FeatureAAPCSFrameChain]>;
558558

559+
// Assume that lock-free 32-bit atomics are available, even if the target
560+
// and operating system combination would not usually provide them. The user
561+
// is responsible for providing any necessary __sync implementations. Code
562+
// built with this feature is not ABI-compatible with code built without this
563+
// feature, if atomic variables are exposed across the ABI boundary.
564+
def FeatureAtomics32 : SubtargetFeature<
565+
"atomics-32", "HasForced32BitAtomics", "true",
566+
"Assume that lock-free 32-bit atomics are available">;
567+
559568
//===----------------------------------------------------------------------===//
560569
// ARM architecture class
561570
//

llvm/lib/Target/ARM/ARMISelLowering.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1370,7 +1370,8 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
13701370
// instructions. (ARMv6 doesn't have dmb, but it has an equivalent
13711371
// encoding; see ARMISD::MEMBARRIER_MCR.)
13721372
setMaxAtomicSizeInBitsSupported(64);
1373-
} else if (Subtarget->isMClass() && Subtarget->hasV8MBaselineOps()) {
1373+
} else if ((Subtarget->isMClass() && Subtarget->hasV8MBaselineOps()) ||
1374+
Subtarget->hasForced32BitAtomics()) {
13741375
// Cortex-M (besides Cortex-M0) have 32-bit atomics.
13751376
setMaxAtomicSizeInBitsSupported(32);
13761377
} else {
+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=thumbv6m-none-eabi < %s | FileCheck %s --check-prefixes=CHECK,NO-ATOMIC32
3+
; RUN: llc -mtriple=thumbv6m-none-eabi -mattr=+atomics-32 < %s | FileCheck %s --check-prefixes=CHECK,ATOMIC32
4+
5+
define i32 @load32(ptr %p) {
6+
; NO-ATOMIC32-LABEL: load32:
7+
; NO-ATOMIC32: @ %bb.0:
8+
; NO-ATOMIC32-NEXT: .save {r7, lr}
9+
; NO-ATOMIC32-NEXT: push {r7, lr}
10+
; NO-ATOMIC32-NEXT: movs r1, #5
11+
; NO-ATOMIC32-NEXT: bl __atomic_load_4
12+
; NO-ATOMIC32-NEXT: pop {r7, pc}
13+
;
14+
; ATOMIC32-LABEL: load32:
15+
; ATOMIC32: @ %bb.0:
16+
; ATOMIC32-NEXT: ldr r0, [r0]
17+
; ATOMIC32-NEXT: dmb sy
18+
; ATOMIC32-NEXT: bx lr
19+
%v = load atomic i32, ptr %p seq_cst, align 4
20+
ret i32 %v
21+
}
22+
23+
define void @store32(ptr %p) {
24+
; NO-ATOMIC32-LABEL: store32:
25+
; NO-ATOMIC32: @ %bb.0:
26+
; NO-ATOMIC32-NEXT: .save {r7, lr}
27+
; NO-ATOMIC32-NEXT: push {r7, lr}
28+
; NO-ATOMIC32-NEXT: movs r1, #0
29+
; NO-ATOMIC32-NEXT: movs r2, #5
30+
; NO-ATOMIC32-NEXT: bl __atomic_store_4
31+
; NO-ATOMIC32-NEXT: pop {r7, pc}
32+
;
33+
; ATOMIC32-LABEL: store32:
34+
; ATOMIC32: @ %bb.0:
35+
; ATOMIC32-NEXT: dmb sy
36+
; ATOMIC32-NEXT: movs r1, #0
37+
; ATOMIC32-NEXT: str r1, [r0]
38+
; ATOMIC32-NEXT: dmb sy
39+
; ATOMIC32-NEXT: bx lr
40+
store atomic i32 0, ptr %p seq_cst, align 4
41+
ret void
42+
}
43+
44+
define i32 @rmw32(ptr %p) {
45+
; NO-ATOMIC32-LABEL: rmw32:
46+
; NO-ATOMIC32: @ %bb.0:
47+
; NO-ATOMIC32-NEXT: .save {r7, lr}
48+
; NO-ATOMIC32-NEXT: push {r7, lr}
49+
; NO-ATOMIC32-NEXT: movs r1, #1
50+
; NO-ATOMIC32-NEXT: movs r2, #5
51+
; NO-ATOMIC32-NEXT: bl __atomic_fetch_add_4
52+
; NO-ATOMIC32-NEXT: pop {r7, pc}
53+
;
54+
; ATOMIC32-LABEL: rmw32:
55+
; ATOMIC32: @ %bb.0:
56+
; ATOMIC32-NEXT: .save {r7, lr}
57+
; ATOMIC32-NEXT: push {r7, lr}
58+
; ATOMIC32-NEXT: dmb sy
59+
; ATOMIC32-NEXT: movs r1, #1
60+
; ATOMIC32-NEXT: bl __sync_fetch_and_add_4
61+
; ATOMIC32-NEXT: dmb sy
62+
; ATOMIC32-NEXT: pop {r7, pc}
63+
%v = atomicrmw add ptr %p, i32 1 seq_cst, align 4
64+
ret i32 %v
65+
}
66+
67+
define i32 @cmpxchg32(ptr %p) {
68+
; NO-ATOMIC32-LABEL: cmpxchg32:
69+
; NO-ATOMIC32: @ %bb.0:
70+
; NO-ATOMIC32-NEXT: .save {r7, lr}
71+
; NO-ATOMIC32-NEXT: push {r7, lr}
72+
; NO-ATOMIC32-NEXT: .pad #8
73+
; NO-ATOMIC32-NEXT: sub sp, #8
74+
; NO-ATOMIC32-NEXT: movs r1, #0
75+
; NO-ATOMIC32-NEXT: str r1, [sp, #4]
76+
; NO-ATOMIC32-NEXT: movs r3, #5
77+
; NO-ATOMIC32-NEXT: str r3, [sp]
78+
; NO-ATOMIC32-NEXT: add r1, sp, #4
79+
; NO-ATOMIC32-NEXT: movs r2, #1
80+
; NO-ATOMIC32-NEXT: bl __atomic_compare_exchange_4
81+
; NO-ATOMIC32-NEXT: ldr r0, [sp, #4]
82+
; NO-ATOMIC32-NEXT: add sp, #8
83+
; NO-ATOMIC32-NEXT: pop {r7, pc}
84+
;
85+
; ATOMIC32-LABEL: cmpxchg32:
86+
; ATOMIC32: @ %bb.0:
87+
; ATOMIC32-NEXT: .save {r7, lr}
88+
; ATOMIC32-NEXT: push {r7, lr}
89+
; ATOMIC32-NEXT: dmb sy
90+
; ATOMIC32-NEXT: movs r1, #0
91+
; ATOMIC32-NEXT: movs r2, #1
92+
; ATOMIC32-NEXT: bl __sync_val_compare_and_swap_4
93+
; ATOMIC32-NEXT: dmb sy
94+
; ATOMIC32-NEXT: pop {r7, pc}
95+
%res = cmpxchg ptr %p, i32 0, i32 1 seq_cst seq_cst
96+
%res.0 = extractvalue { i32, i1 } %res, 0
97+
ret i32 %res.0
98+
}
99+
100+
define i64 @load64(ptr %p) {
101+
; CHECK-LABEL: load64:
102+
; CHECK: @ %bb.0:
103+
; CHECK-NEXT: .save {r7, lr}
104+
; CHECK-NEXT: push {r7, lr}
105+
; CHECK-NEXT: .pad #8
106+
; CHECK-NEXT: sub sp, #8
107+
; CHECK-NEXT: mov r1, r0
108+
; CHECK-NEXT: movs r0, #8
109+
; CHECK-NEXT: mov r2, sp
110+
; CHECK-NEXT: movs r3, #5
111+
; CHECK-NEXT: bl __atomic_load
112+
; CHECK-NEXT: ldr r1, [sp, #4]
113+
; CHECK-NEXT: ldr r0, [sp]
114+
; CHECK-NEXT: add sp, #8
115+
; CHECK-NEXT: pop {r7, pc}
116+
%v = load atomic i64, ptr %p seq_cst, align 4
117+
ret i64 %v
118+
}
119+
120+
define void @store64(ptr %p) {
121+
; CHECK-LABEL: store64:
122+
; CHECK: @ %bb.0:
123+
; CHECK-NEXT: .save {r7, lr}
124+
; CHECK-NEXT: push {r7, lr}
125+
; CHECK-NEXT: .pad #8
126+
; CHECK-NEXT: sub sp, #8
127+
; CHECK-NEXT: mov r1, r0
128+
; CHECK-NEXT: movs r0, #0
129+
; CHECK-NEXT: str r0, [sp, #4]
130+
; CHECK-NEXT: str r0, [sp]
131+
; CHECK-NEXT: movs r0, #8
132+
; CHECK-NEXT: mov r2, sp
133+
; CHECK-NEXT: movs r3, #5
134+
; CHECK-NEXT: bl __atomic_store
135+
; CHECK-NEXT: add sp, #8
136+
; CHECK-NEXT: pop {r7, pc}
137+
store atomic i64 0, ptr %p seq_cst, align 4
138+
ret void
139+
}
140+
141+
define i64 @rmw64(ptr %p) {
142+
; CHECK-LABEL: rmw64:
143+
; CHECK: @ %bb.0:
144+
; CHECK-NEXT: .save {r4, lr}
145+
; CHECK-NEXT: push {r4, lr}
146+
; CHECK-NEXT: .pad #24
147+
; CHECK-NEXT: sub sp, #24
148+
; CHECK-NEXT: mov r4, r0
149+
; CHECK-NEXT: ldr r0, [r0]
150+
; CHECK-NEXT: ldr r1, [r4, #4]
151+
; CHECK-NEXT: .LBB6_1: @ %atomicrmw.start
152+
; CHECK-NEXT: @ =>This Inner Loop Header: Depth=1
153+
; CHECK-NEXT: str r0, [sp, #16]
154+
; CHECK-NEXT: str r1, [sp, #20]
155+
; CHECK-NEXT: movs r2, #0
156+
; CHECK-NEXT: adds r0, r0, #1
157+
; CHECK-NEXT: adcs r2, r1
158+
; CHECK-NEXT: str r2, [sp, #12]
159+
; CHECK-NEXT: str r0, [sp, #8]
160+
; CHECK-NEXT: movs r0, #5
161+
; CHECK-NEXT: str r0, [sp]
162+
; CHECK-NEXT: str r0, [sp, #4]
163+
; CHECK-NEXT: movs r0, #8
164+
; CHECK-NEXT: add r2, sp, #16
165+
; CHECK-NEXT: add r3, sp, #8
166+
; CHECK-NEXT: mov r1, r4
167+
; CHECK-NEXT: bl __atomic_compare_exchange
168+
; CHECK-NEXT: mov r2, r0
169+
; CHECK-NEXT: ldr r1, [sp, #20]
170+
; CHECK-NEXT: ldr r0, [sp, #16]
171+
; CHECK-NEXT: cmp r2, #0
172+
; CHECK-NEXT: beq .LBB6_1
173+
; CHECK-NEXT: @ %bb.2: @ %atomicrmw.end
174+
; CHECK-NEXT: add sp, #24
175+
; CHECK-NEXT: pop {r4, pc}
176+
%v = atomicrmw add ptr %p, i64 1 seq_cst, align 4
177+
ret i64 %v
178+
}
179+
180+
define i64 @cmpxchg64(ptr %p) {
181+
; CHECK-LABEL: cmpxchg64:
182+
; CHECK: @ %bb.0:
183+
; CHECK-NEXT: .save {r7, lr}
184+
; CHECK-NEXT: push {r7, lr}
185+
; CHECK-NEXT: .pad #16
186+
; CHECK-NEXT: sub sp, #16
187+
; CHECK-NEXT: movs r3, #0
188+
; CHECK-NEXT: str r3, [sp, #12]
189+
; CHECK-NEXT: str r3, [sp, #8]
190+
; CHECK-NEXT: movs r1, #5
191+
; CHECK-NEXT: str r1, [sp]
192+
; CHECK-NEXT: str r1, [sp, #4]
193+
; CHECK-NEXT: add r1, sp, #8
194+
; CHECK-NEXT: movs r2, #1
195+
; CHECK-NEXT: bl __atomic_compare_exchange_8
196+
; CHECK-NEXT: ldr r1, [sp, #12]
197+
; CHECK-NEXT: ldr r0, [sp, #8]
198+
; CHECK-NEXT: add sp, #16
199+
; CHECK-NEXT: pop {r7, pc}
200+
%res = cmpxchg ptr %p, i64 0, i64 1 seq_cst seq_cst
201+
%res.0 = extractvalue { i64, i1 } %res, 0
202+
ret i64 %res.0
203+
}

0 commit comments

Comments
 (0)