OLD | NEW |
---|---|
(Empty) | |
1 ; This tests each of the supported NaCl atomic instructions for every | |
2 ; size allowed. | |
3 | |
4 ; RUN: %llvm2ice -O2 --verbose none %s | FileCheck %s | |
5 ; RUN: %llvm2ice -Om1 --verbose none %s | FileCheck %s | |
6 ; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s | |
7 ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s | |
8 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \ | |
9 ; RUN: | FileCheck --check-prefix=DUMP %s | |
10 | |
11 declare i8 @llvm.nacl.atomic.load.i8(i8*, i32) | |
12 declare i16 @llvm.nacl.atomic.load.i16(i16*, i32) | |
13 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32) | |
14 declare i64 @llvm.nacl.atomic.load.i64(i64*, i32) | |
15 declare void @llvm.nacl.atomic.store.i8(i8, i8*, i32) | |
16 declare void @llvm.nacl.atomic.store.i16(i16, i16*, i32) | |
17 declare void @llvm.nacl.atomic.store.i32(i32, i32*, i32) | |
18 declare void @llvm.nacl.atomic.store.i64(i64, i64*, i32) | |
19 declare i8 @llvm.nacl.atomic.rmw.i8(i32, i8*, i8, i32) | |
20 declare i16 @llvm.nacl.atomic.rmw.i16(i32, i16*, i16, i32) | |
21 declare i32 @llvm.nacl.atomic.rmw.i32(i32, i32*, i32, i32) | |
22 declare i64 @llvm.nacl.atomic.rmw.i64(i32, i64*, i64, i32) | |
23 declare i8 @llvm.nacl.atomic.cmpxchg.i8(i8*, i8, i8, i32, i32) | |
24 declare i16 @llvm.nacl.atomic.cmpxchg.i16(i16*, i16, i16, i32, i32) | |
25 declare i32 @llvm.nacl.atomic.cmpxchg.i32(i32*, i32, i32, i32, i32) | |
26 declare i64 @llvm.nacl.atomic.cmpxchg.i64(i64*, i64, i64, i32, i32) | |
27 declare void @llvm.nacl.atomic.fence(i32) | |
28 declare void @llvm.nacl.atomic.fence.all() | |
29 declare i1 @llvm.nacl.atomic.is.lock.free(i32, i8*) | |
30 | |
31 ;;; Load | |
32 | |
33 ; x86 guarantees load/store to be atomic if naturally aligned. | |
34 ; The PNaCl IR requires all atomic accesses to be naturally aligned. | |
35 | |
36 define i32 @test_atomic_load_8(i32 %iptr) { | |
37 entry: | |
38 %ptr = inttoptr i32 %iptr to i8* | |
39 ; parameter value "6" is for the sequential consistency memory order. | |
40 %i = call i8 @llvm.nacl.atomic.load.i8(i8* %ptr, i32 6) | |
41 %r = zext i8 %i to i32 | |
42 ret i32 %r | |
43 } | |
44 ; CHECK-LABEL: test_atomic_load_8 | |
45 ; CHECK: mov {{.*}}, dword | |
46 ; CHECK: mov {{.*}}, byte | |
47 | |
48 define i32 @test_atomic_load_16(i32 %iptr) { | |
49 entry: | |
50 %ptr = inttoptr i32 %iptr to i16* | |
51 %i = call i16 @llvm.nacl.atomic.load.i16(i16* %ptr, i32 6) | |
52 %r = zext i16 %i to i32 | |
53 ret i32 %r | |
54 } | |
55 ; CHECK-LABEL: test_atomic_load_16 | |
56 ; CHECK: mov {{.*}}, dword | |
57 ; CHECK: mov {{.*}}, word | |
58 | |
59 define i32 @test_atomic_load_32(i32 %iptr) { | |
60 entry: | |
61 %ptr = inttoptr i32 %iptr to i32* | |
62 %r = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | |
63 ret i32 %r | |
64 } | |
65 ; CHECK-LABEL: test_atomic_load_32 | |
66 ; CHECK: mov {{.*}}, dword | |
67 ; CHECK: mov {{.*}}, dword | |
68 | |
69 define i64 @test_atomic_load_64(i32 %iptr) { | |
70 entry: | |
71 %ptr = inttoptr i32 %iptr to i64* | |
72 %r = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) | |
73 ret i64 %r | |
74 } | |
75 ; CHECK-LABEL: test_atomic_load_64 | |
76 ; CHECK: movq x{{.*}}, qword | |
77 ; CHECK: movq qword {{.*}}, x{{.*}} | |
78 | |
79 define i32 @test_atomic_load_32_with_arith(i32 %iptr) { | |
80 entry: | |
81 %ptr = inttoptr i32 %iptr to i32* | |
82 %r = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | |
83 %r2 = add i32 %r, 32 | |
84 ret i32 %r2 | |
85 } | |
86 ; CHECK-LABEL: test_atomic_load_32_with_arith | |
87 ; CHECK: mov {{.*}}, dword | |
88 ; The next instruction may be a separate load or folded into an add. | |
89 | |
90 define i32 @test_atomic_load_32_ignored(i32 %iptr) { | |
91 entry: | |
92 %ptr = inttoptr i32 %iptr to i32* | |
93 %ignored = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | |
94 ret i32 0 | |
95 } | |
96 ; CHECK-LABEL: test_atomic_load_32_ignored | |
97 ; CHECK: mov {{.*}}, dword | |
98 ; CHECK: mov {{.*}}, dword | |
99 | |
100 define i64 @test_atomic_load_64_ignored(i32 %iptr) { | |
101 entry: | |
102 %ptr = inttoptr i32 %iptr to i64* | |
103 %ignored = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) | |
104 ret i64 0 | |
105 } | |
106 ; CHECK-LABEL: test_atomic_load_64_ignored | |
107 ; CHECK: movq x{{.*}}, qword | |
108 ; CHECK: movq qword {{.*}}, x{{.*}} | |
109 | |
110 | |
111 ;;; Store | |
112 | |
113 define void @test_atomic_store_8(i32 %iptr, i32 %v) { | |
114 entry: | |
115 %truncv = trunc i32 %v to i8 | |
116 %ptr = inttoptr i32 %iptr to i8* | |
117 call void @llvm.nacl.atomic.store.i8(i8 %truncv, i8* %ptr, i32 6) | |
118 ret void | |
119 } | |
120 ; CHECK-LABEL: test_atomic_store_8 | |
121 ; CHECK: mov byte | |
122 ; CHECK: mfence | |
123 | |
124 define void @test_atomic_store_16(i32 %iptr, i32 %v) { | |
125 entry: | |
126 %truncv = trunc i32 %v to i16 | |
127 %ptr = inttoptr i32 %iptr to i16* | |
128 call void @llvm.nacl.atomic.store.i16(i16 %truncv, i16* %ptr, i32 6) | |
129 ret void | |
130 } | |
131 ; CHECK-LABEL: test_atomic_store_16 | |
132 ; CHECK: mov word | |
133 ; CHECK: mfence | |
134 | |
135 define void @test_atomic_store_32(i32 %iptr, i32 %v) { | |
136 entry: | |
137 %ptr = inttoptr i32 %iptr to i32* | |
138 call void @llvm.nacl.atomic.store.i32(i32 %v, i32* %ptr, i32 6) | |
139 ret void | |
140 } | |
141 ; CHECK-LABEL: test_atomic_store_32 | |
142 ; CHECK: mov dword | |
143 ; CHECK: mfence | |
144 | |
145 define void @test_atomic_store_64(i32 %iptr, i64 %v) { | |
146 entry: | |
147 %ptr = inttoptr i32 %iptr to i64* | |
148 call void @llvm.nacl.atomic.store.i64(i64 %v, i64* %ptr, i32 6) | |
149 ret void | |
150 } | |
151 ; CHECK-LABEL: test_atomic_store_64 | |
152 ; CHECK: movq x{{.*}}, qword | |
153 ; CHECK: movq qword {{.*}}, x{{.*}} | |
154 ; CHECK: mfence | |
155 | |
156 define void @test_atomic_store_64_const(i32 %iptr) { | |
157 entry: | |
158 %ptr = inttoptr i32 %iptr to i64* | |
159 call void @llvm.nacl.atomic.store.i64(i64 12345678901234, i64* %ptr, i32 6) | |
160 ret void | |
161 } | |
162 ; CHECK-LABEL: test_atomic_store_64_const | |
163 ; TODO(jvoung): the 64-bit constant materialization | |
164 ; doesn't seem to be right (not split up). | |
165 ; CHECK: movq x{{.*}}, qword | |
166 ; CHECK: movq qword {{.*}}, x{{.*}} | |
167 ; CHECK: mfence | |
168 | |
169 | |
170 ;;; RMW | |
171 | |
172 define i32 @test_atomic_rmw_add_8(i32 %iptr, i32 %v) { | |
173 entry: | |
174 %trunc = trunc i32 %v to i8 | |
175 %ptr = inttoptr i32 %iptr to i8* | |
176 ; "1" is an atomic add, and "6" is sequential consistency. | |
177 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 1, i8* %ptr, i8 %trunc, i32 6) | |
178 %a_ext = zext i8 %a to i32 | |
179 ret i32 %a_ext | |
180 } | |
181 ; CHECK-LABEL: test_atomic_rmw_add_8 | |
182 ; CHECK: lock xadd byte {{.*}}, [[REG:.*]] | |
183 ; CHECK: mov {{.*}}, {{.*}}[[REG]] | |
184 | |
185 define i32 @test_atomic_rmw_add_16(i32 %iptr, i32 %v) { | |
186 entry: | |
187 %trunc = trunc i32 %v to i16 | |
188 %ptr = inttoptr i32 %iptr to i16* | |
189 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 1, i16* %ptr, i16 %trunc, i32 6) | |
190 %a_ext = zext i16 %a to i32 | |
191 ret i32 %a_ext | |
192 } | |
193 ; CHECK-LABEL: test_atomic_rmw_add_16 | |
194 ; CHECK: lock xadd word {{.*}}, [[REG:.*]] | |
195 ; CHECK: mov {{.*}}, {{.*}}[[REG]] | |
196 | |
197 define i32 @test_atomic_rmw_add_32(i32 %iptr, i32 %v) { | |
198 entry: | |
199 %ptr = inttoptr i32 %iptr to i32* | |
200 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) | |
201 ret i32 %a | |
202 } | |
203 ; CHECK-LABEL: test_atomic_rmw_add_32 | |
204 ; CHECK: lock xadd dword {{.*}}, [[REG:.*]] | |
205 ; CHECK: mov {{.*}}, {{.*}}[[REG]] | |
206 | |
207 ;define i64 @test_atomic_rmw_add_64(i32 %iptr, i64 %v) { | |
208 ;entry: | |
209 ; %ptr = inttoptr i32 %iptr to i64* | |
210 ; %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) | |
211 ; ret i64 %a | |
212 ;} | |
213 ; CHECKLATER-LABEL: test_atomic_rmw_add_64 | |
214 ; CHECKLATER: uh need a... cmpxchg8b loop. | |
215 | |
216 define i32 @test_atomic_rmw_add_32_ignored(i32 %iptr, i32 %v) { | |
217 entry: | |
218 %ptr = inttoptr i32 %iptr to i32* | |
219 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) | |
220 ret i32 %v | |
221 } | |
222 ; CHECK-LABEL: test_atomic_rmw_add_32_ignored | |
223 ; CHECK: lock xadd dword {{.*}}, [[REG:.*]] | |
224 | |
225 ;define i32 @test_atomic_rmw_sub_32(i32 %iptr, i32 %v) { | |
226 ;entry: | |
227 ; %ptr = inttoptr i32 %iptr to i32* | |
228 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) | |
229 ; ret i32 %a | |
230 ;} | |
231 ; CHECKLATER-LABEL: test_atomic_rmw_sub_32 | |
232 ; CHECKLATER: neg | |
233 ; CHECKLATER: lock | |
234 ; CHECKLATER: xadd | |
235 | |
236 ;define i32 @test_atomic_rmw_or_32(i32 %iptr, i32 %v) { | |
237 ;entry: | |
238 ; %ptr = inttoptr i32 %iptr to i32* | |
239 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) | |
240 ; ret i32 %a | |
241 ;} | |
242 ; CHECKLATER-LABEL: test_atomic_rmw_or_32 | |
243 ; Need a cmpxchg loop. | |
244 | |
245 ;define i32 @test_atomic_rmw_and_32(i32 %iptr, i32 %v) { | |
246 ;entry: | |
247 ; %ptr = inttoptr i32 %iptr to i32* | |
248 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) | |
249 ; ret i32 %a | |
250 ;} | |
251 ; CHECKLATER-LABEL: test_atomic_rmw_and_32 | |
252 ; Also a cmpxchg loop. | |
253 | |
254 ;define i32 @test_atomic_rmw_xor_32(i32 %iptr, i32 %v) { | |
255 ;entry: | |
256 ; %ptr = inttoptr i32 %iptr to i32* | |
257 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) | |
258 ; ret i32 %a | |
259 ;} | |
260 ; CHECKLATER-LABEL: test_atomic_rmw_xor_32 | |
261 ; Also a cmpxchg loop. | |
262 | |
263 ;define i32 @test_atomic_rmw_xchg_32(i32 %iptr, i32 %v) { | |
264 ;entry: | |
265 ; %ptr = inttoptr i32 %iptr to i32* | |
266 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) | |
267 ; ret i32 %a | |
268 ;} | |
269 ; CHECKLATER-LABEL: test_atomic_rmw_xchg_32 | |
270 | |
271 ;;;; Cmpxchg | |
272 | |
273 ;define i32 @test_atomic_cmpxchg_8(i32 %iptr, i32 %expected, i32 %desired) { | |
274 ;entry: | |
275 ; %ptr = inttoptr i32 %iptr to i8* | |
276 ; %trunc_exp = trunc i32 %expected to i8 | |
277 ; %trunc_des = trunc i32 %desired to i8 | |
278 ; %old = call i8 @llvm.nacl.atomic.cmpxchg.i8(i8* %ptr, i8 %trunc_exp, | |
279 ; i8 %trunc_des, i32 6, i32 6) | |
280 ; %old_ext = zext i8 %old to i32 | |
281 ; ret i32 %old_ext | |
282 ;} | |
283 ; CHECKLATER-LABEL: test_atomic_cmpxchg_8 | |
284 ; CHECKLATER: lock cmpxchg byte | |
285 | |
286 ;define i32 @test_atomic_cmpxchg_16(i32 %iptr, i32 %expected, i32 %desired) { | |
287 ;entry: | |
288 ; %ptr = inttoptr i32 %iptr to i16* | |
289 ; %trunc_exp = trunc i32 %expected to i16 | |
290 ; %trunc_des = trunc i32 %desired to i16 | |
291 ; %old = call i16 @llvm.nacl.atomic.cmpxchg.i16(i16* %ptr, i16 %trunc_exp, | |
292 ; i16 %trunc_des, i32 6, i32 6) | |
293 ; %old_ext = zext i16 %old to i32 | |
294 ; ret i32 %old_ext | |
295 ;} | |
296 ; CHECKLATER-LABEL: test_atomic_cmpxchg_16 | |
297 ; This one is a bit gross for NaCl right now. | |
298 ; https://code.google.com/p/nativeclient/issues/detail?id=2981 | |
jvoung (off chromium)
2014/06/24 21:16:55
I did notice the 16-bit hack (see this reference).
| |
299 ; But we'll assume that NaCl will have it fixed... | |
300 ; CHECKLATER: lock cmpxchg word | |
301 | |
302 ;define i32 @test_atomic_cmpxchg_32(i32 %iptr, i32 %expected, i32 %desired) { | |
303 ;entry: | |
304 ; %ptr = inttoptr i32 %iptr to i32* | |
305 ; %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, | |
306 ; i32 %desired, i32 6, i32 6) | |
307 ; ret i32 %old | |
308 ;} | |
309 ; CHECKLATER-LABEL: test_atomic_cmpxchg_32 | |
310 ; CHECKLATER: mov eax | |
311 ; CHECKLATER: mov ecx | |
312 ; CHECKLATER: lock cmpxchg dword | |
313 | |
314 ;define i64 @test_atomic_cmpxchg_64(i32 %iptr, i64 %expected, i64 %desired) { | |
315 ;entry: | |
316 ; %ptr = inttoptr i32 %iptr to i64* | |
317 ; %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, | |
318 ; i64 %desired, i32 6, i32 6) | |
319 ; ret i64 %old | |
320 ;} | |
321 ; CHECKLATER-LABEL: test_atomic_cmpxchg_64 | |
322 ; CHECKLATER: mov eax | |
323 ; CHECKLATER: mov edx | |
324 ; CHECKLATER: mov ebx | |
325 ; CHECKLATER: mov ecx | |
326 ; CHECKLATER: lock cmpxchg8b qword | |
327 | |
328 ;define i32 @test_atomic_cmpxchg_32_loop(i32 %iptr, | |
329 ; i32 %expected, i32 %desired) { | |
330 ;entry: | |
331 ; br label %loop | |
332 ; | |
333 ;loop: | |
334 ; %cmp = phi i32 [ %expected, %entry], [%old, %loop] | |
335 ; %ptr = inttoptr i32 %iptr to i32* | |
336 ; %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %cmp, | |
337 ; i32 %desired, i32 6, i32 6) | |
338 ; %success = icmp eq i32 %cmp, %old | |
339 ; br i1 %success, label %done, label %loop | |
340 ; | |
341 ;done: | |
342 ; ret i32 %old | |
343 ;} | |
344 ; CHECKLATER-LABEL: test_atomic_cmpxchg_32_loop | |
345 | |
346 ;;;; Fence and is-lock-free. | |
347 | |
348 define void @test_atomic_fence() { | |
349 entry: | |
350 call void @llvm.nacl.atomic.fence(i32 6) | |
351 ret void | |
352 } | |
353 ; CHECK-LABEL: test_atomic_fence | |
354 ; CHECK: mfence | |
355 | |
356 define void @test_atomic_fence_all() { | |
357 entry: | |
358 call void @llvm.nacl.atomic.fence.all() | |
359 ret void | |
360 } | |
361 ; CHECK-LABEL: test_atomic_fence_all | |
362 ; CHECK: mfence | |
363 | |
364 define i32 @test_atomic_is_lock_free(i32 %iptr) { | |
365 entry: | |
366 %ptr = inttoptr i32 %iptr to i8* | |
367 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 6, i8* %ptr) | |
368 %r = zext i1 %i to i32 | |
369 ret i32 %r | |
370 } | |
371 ; CHECK-LABEL: test_atomic_is_lock_free | |
372 ; CHECK: mov {{.*}}, 1 | |
373 | |
374 ; ERRORS-NOT: ICE translation error | |
375 ; DUMP-NOT: SZ | |
OLD | NEW |