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 ;;; Store | |
91 | |
92 define void @test_atomic_store_8(i32 %iptr, i32 %v) { | |
93 entry: | |
94 %truncv = trunc i32 %v to i8 | |
95 %ptr = inttoptr i32 %iptr to i8* | |
96 call void @llvm.nacl.atomic.store.i8(i8 %truncv, i8* %ptr, i32 6) | |
97 ret void | |
98 } | |
99 ; CHECK-LABEL: test_atomic_store_8 | |
100 ; CHECK: mov byte | |
101 ; CHECK: mfence | |
102 | |
103 define void @test_atomic_store_16(i32 %iptr, i32 %v) { | |
104 entry: | |
105 %truncv = trunc i32 %v to i16 | |
106 %ptr = inttoptr i32 %iptr to i16* | |
107 call void @llvm.nacl.atomic.store.i16(i16 %truncv, i16* %ptr, i32 6) | |
108 ret void | |
109 } | |
110 ; CHECK-LABEL: test_atomic_store_16 | |
111 ; CHECK: mov word | |
112 ; CHECK: mfence | |
113 | |
114 define void @test_atomic_store_32(i32 %iptr, i32 %v) { | |
115 entry: | |
116 %ptr = inttoptr i32 %iptr to i32* | |
117 call void @llvm.nacl.atomic.store.i32(i32 %v, i32* %ptr, i32 6) | |
118 ret void | |
119 } | |
120 ; CHECK-LABEL: test_atomic_store_32 | |
121 ; CHECK: mov dword | |
122 ; CHECK: mfence | |
123 | |
124 define void @test_atomic_store_64(i32 %iptr, i64 %v) { | |
125 entry: | |
126 %ptr = inttoptr i32 %iptr to i64* | |
127 call void @llvm.nacl.atomic.store.i64(i64 %v, i64* %ptr, i32 6) | |
128 ret void | |
129 } | |
130 ; CHECK-LABEL: test_atomic_store_64 | |
131 ; CHECK: movq x{{.*}}, qword | |
132 ; CHECK: movq qword {{.*}}, x{{.*}} | |
133 ; CHECK: mfence | |
134 | |
135 define void @test_atomic_store_64_const(i32 %iptr) { | |
136 entry: | |
137 %ptr = inttoptr i32 %iptr to i64* | |
138 call void @llvm.nacl.atomic.store.i64(i64 12345678901234, i64* %ptr, i32 6) | |
139 ret void | |
140 } | |
141 ; CHECK-LABEL: test_atomic_store_64_const | |
142 ; TODO(jvoung): the 64-bit constant materialization | |
jvoung (off chromium)
2014/06/20 23:21:07
Started looking into this: looks like this is beca
| |
143 ; doesn't seem to be right (not split up). | |
144 ; CHECK: movq x{{.*}}, qword | |
145 ; CHECK: movq qword {{.*}}, x{{.*}} | |
146 ; CHECK: mfence | |
147 | |
148 | |
149 ;;; RMW | |
150 | |
151 define i32 @test_atomic_rmw_add_8(i32 %iptr, i32 %v) { | |
152 entry: | |
153 %trunc = trunc i32 %v to i8 | |
154 %ptr = inttoptr i32 %iptr to i8* | |
155 ; "1" is an atomic add, and "6" is sequential consistency. | |
156 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 1, i8* %ptr, i8 %trunc, i32 6) | |
157 %a_ext = zext i8 %a to i32 | |
158 ret i32 %a_ext | |
159 } | |
160 ; CHECK-LABEL: test_atomic_rmw_add_8 | |
161 ; CHECK: lock xadd byte {{.*}}, [[REG:.*]] | |
162 ; CHECK: mov {{.*}}, {{.*}}[[REG]] | |
163 | |
164 define i32 @test_atomic_rmw_add_16(i32 %iptr, i32 %v) { | |
165 entry: | |
166 %trunc = trunc i32 %v to i16 | |
167 %ptr = inttoptr i32 %iptr to i16* | |
168 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 1, i16* %ptr, i16 %trunc, i32 6) | |
169 %a_ext = zext i16 %a to i32 | |
170 ret i32 %a_ext | |
171 } | |
172 ; CHECK-LABEL: test_atomic_rmw_add_16 | |
173 ; CHECK: lock xadd word {{.*}}, [[REG:.*]] | |
174 ; CHECK: mov {{.*}}, {{.*}}[[REG]] | |
175 | |
176 define i32 @test_atomic_rmw_add_32(i32 %iptr, i32 %v) { | |
177 entry: | |
178 %ptr = inttoptr i32 %iptr to i32* | |
179 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) | |
180 ret i32 %a | |
181 } | |
182 ; CHECK-LABEL: test_atomic_rmw_add_32 | |
183 ; CHECK: lock xadd dword {{.*}}, [[REG:.*]] | |
184 ; CHECK: mov {{.*}}, {{.*}}[[REG]] | |
185 | |
186 ;define i64 @test_atomic_rmw_add_64(i32 %iptr, i64 %v) { | |
187 ;entry: | |
188 ; %ptr = inttoptr i32 %iptr to i64* | |
189 ; %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) | |
190 ; ret i64 %a | |
191 ;} | |
192 ; CHECKLATER-LABEL: test_atomic_rmw_add_64 | |
193 ; CHECKLATER: uh need a... cmpxchg8b loop. | |
194 | |
195 ;define i32 @test_atomic_rmw_sub_32(i32 %iptr, i32 %v) { | |
196 ;entry: | |
197 ; %ptr = inttoptr i32 %iptr to i32* | |
198 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) | |
199 ; ret i32 %a | |
200 ;} | |
201 ; CHECKLATER-LABEL: test_atomic_rmw_sub_32 | |
202 ; CHECKLATER: neg | |
203 ; CHECKLATER: lock | |
204 ; CHECKLATER: xadd | |
205 | |
206 ;define i32 @test_atomic_rmw_or_32(i32 %iptr, i32 %v) { | |
207 ;entry: | |
208 ; %ptr = inttoptr i32 %iptr to i32* | |
209 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) | |
210 ; ret i32 %a | |
211 ;} | |
212 ; CHECKLATER-LABEL: test_atomic_rmw_or_32 | |
213 ; Need a cmpxchg loop. | |
214 | |
215 ;define i32 @test_atomic_rmw_and_32(i32 %iptr, i32 %v) { | |
216 ;entry: | |
217 ; %ptr = inttoptr i32 %iptr to i32* | |
218 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) | |
219 ; ret i32 %a | |
220 ;} | |
221 ; CHECKLATER-LABEL: test_atomic_rmw_and_32 | |
222 ; Also a cmpxchg loop. | |
223 | |
224 ;define i32 @test_atomic_rmw_xor_32(i32 %iptr, i32 %v) { | |
225 ;entry: | |
226 ; %ptr = inttoptr i32 %iptr to i32* | |
227 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) | |
228 ; ret i32 %a | |
229 ;} | |
230 ; CHECKLATER-LABEL: test_atomic_rmw_xor_32 | |
231 ; Also a cmpxchg loop. | |
232 | |
233 ;define i32 @test_atomic_rmw_xchg_32(i32 %iptr, i32 %v) { | |
234 ;entry: | |
235 ; %ptr = inttoptr i32 %iptr to i32* | |
236 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) | |
237 ; ret i32 %a | |
238 ;} | |
239 ; CHECKLATER-LABEL: test_atomic_rmw_xchg_32 | |
240 | |
241 ;;;; Cmpxchg | |
242 | |
243 ;define i32 @test_atomic_cmpxchg_8(i32 %iptr, i32 %expected, i32 %desired) { | |
244 ;entry: | |
245 ; %ptr = inttoptr i32 %iptr to i8* | |
246 ; %trunc_exp = trunc i32 %expected to i8 | |
247 ; %trunc_des = trunc i32 %desired to i8 | |
248 ; %old = call i8 @llvm.nacl.atomic.cmpxchg.i8(i8* %ptr, i8 %trunc_exp, | |
249 ; i8 %trunc_des, i32 6, i32 6) | |
250 ; %old_ext = zext i8 %old to i32 | |
251 ; ret i32 %old_ext | |
252 ;} | |
253 ; CHECKLATER-LABEL: test_atomic_cmpxchg_8 | |
254 ; CHECKLATER: lock cmpxchg byte | |
255 | |
256 ;define i32 @test_atomic_cmpxchg_16(i32 %iptr, i32 %expected, i32 %desired) { | |
257 ;entry: | |
258 ; %ptr = inttoptr i32 %iptr to i16* | |
259 ; %trunc_exp = trunc i32 %expected to i16 | |
260 ; %trunc_des = trunc i32 %desired to i16 | |
261 ; %old = call i16 @llvm.nacl.atomic.cmpxchg.i16(i16* %ptr, i16 %trunc_exp, | |
262 ; i16 %trunc_des, i32 6, i32 6) | |
263 ; %old_ext = zext i16 %old to i32 | |
264 ; ret i32 %old_ext | |
265 ;} | |
266 ; CHECKLATER-LABEL: test_atomic_cmpxchg_16 | |
267 ; This one is a bit gross for NaCl right now. | |
268 ; https://code.google.com/p/nativeclient/issues/detail?id=2981 | |
269 ; But we'll assume that NaCl will have it fixed... | |
270 ; CHECKLATER: lock cmpxchg word | |
271 | |
272 ;define i32 @test_atomic_cmpxchg_32(i32 %iptr, i32 %expected, i32 %desired) { | |
273 ;entry: | |
274 ; %ptr = inttoptr i32 %iptr to i32* | |
275 ; %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, | |
276 ; i32 %desired, i32 6, i32 6) | |
277 ; ret i32 %old | |
278 ;} | |
279 ; CHECKLATER-LABEL: test_atomic_cmpxchg_32 | |
280 ; CHECKLATER: mov eax | |
281 ; CHECKLATER: mov ecx | |
282 ; CHECKLATER: lock cmpxchg dword | |
283 | |
284 ;define i64 @test_atomic_cmpxchg_64(i32 %iptr, i64 %expected, i64 %desired) { | |
285 ;entry: | |
286 ; %ptr = inttoptr i32 %iptr to i64* | |
287 ; %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, | |
288 ; i64 %desired, i32 6, i32 6) | |
289 ; ret i64 %old | |
290 ;} | |
291 ; CHECKLATER-LABEL: test_atomic_cmpxchg_64 | |
292 ; CHECKLATER: mov eax | |
293 ; CHECKLATER: mov edx | |
294 ; CHECKLATER: mov ebx | |
295 ; CHECKLATER: mov ecx | |
296 ; CHECKLATER: lock cmpxchg8b qword | |
297 | |
298 ;define i32 @test_atomic_cmpxchg_32_loop(i32 %iptr, | |
299 ; i32 %expected, i32 %desired) { | |
300 ;entry: | |
301 ; br label %loop | |
302 ; | |
303 ;loop: | |
304 ; %cmp = phi i32 [ %expected, %entry], [%old, %loop] | |
305 ; %ptr = inttoptr i32 %iptr to i32* | |
306 ; %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %cmp, | |
307 ; i32 %desired, i32 6, i32 6) | |
308 ; %success = icmp eq i32 %cmp, %old | |
309 ; br i1 %success, label %done, label %loop | |
310 ; | |
311 ;done: | |
312 ; ret i32 %old | |
313 ;} | |
314 ; CHECKLATER-LABEL: test_atomic_cmpxchg_32_loop | |
315 | |
316 ;;;; Fence and is-lock-free. | |
317 | |
318 define void @test_atomic_fence() { | |
319 entry: | |
320 call void @llvm.nacl.atomic.fence(i32 6) | |
321 ret void | |
322 } | |
323 ; CHECK-LABEL: test_atomic_fence | |
324 ; CHECK: mfence | |
325 | |
326 define void @test_atomic_fence_all() { | |
327 entry: | |
328 call void @llvm.nacl.atomic.fence.all() | |
329 ret void | |
330 } | |
331 ; CHECK-LABEL: test_atomic_fence_all | |
332 ; CHECK: mfence | |
333 | |
334 define i32 @test_atomic_is_lock_free(i32 %iptr) { | |
335 entry: | |
336 %ptr = inttoptr i32 %iptr to i8* | |
337 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 6, i8* %ptr) | |
338 %r = zext i1 %i to i32 | |
339 ret i32 %r | |
340 } | |
341 ; CHECK-LABEL: test_atomic_is_lock_free | |
342 ; CHECK: mov {{.*}}, 1 | |
343 | |
344 ; ERRORS-NOT: ICE translation error | |
345 ; DUMP-NOT: SZ | |
OLD | NEW |