Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(206)

Side by Side Diff: tests_lit/llvm2ice_tests/nacl-atomic-intrinsics.ll

Issue 362463002: Subzero: lower the rest of the atomic operations. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: comment cleanup Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 ; This tests each of the supported NaCl atomic instructions for every 1 ; This tests each of the supported NaCl atomic instructions for every
2 ; size allowed. 2 ; size allowed.
3 3
4 ; RUN: %llvm2ice -O2 --verbose none %s | FileCheck %s 4 ; RUN: %llvm2ice -O2 --verbose none %s | FileCheck %s
5 ; RUN: %llvm2ice -O2 --verbose none %s | FileCheck %s --check-prefix=CHECKO2REM
5 ; RUN: %llvm2ice -Om1 --verbose none %s | FileCheck %s 6 ; RUN: %llvm2ice -Om1 --verbose none %s | FileCheck %s
6 ; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s 7 ; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
7 ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s 8 ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s
8 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \ 9 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \
9 ; RUN: | FileCheck --check-prefix=DUMP %s 10 ; RUN: | FileCheck --check-prefix=DUMP %s
10 11
11 declare i8 @llvm.nacl.atomic.load.i8(i8*, i32) 12 declare i8 @llvm.nacl.atomic.load.i8(i8*, i32)
12 declare i16 @llvm.nacl.atomic.load.i16(i16*, i32) 13 declare i16 @llvm.nacl.atomic.load.i16(i16*, i32)
13 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32) 14 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32)
14 declare i64 @llvm.nacl.atomic.load.i64(i64*, i32) 15 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.i8(i8, i8*, i32)
16 declare void @llvm.nacl.atomic.store.i16(i16, i16*, i32) 17 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.i32(i32, i32*, i32)
18 declare void @llvm.nacl.atomic.store.i64(i64, i64*, i32) 19 declare void @llvm.nacl.atomic.store.i64(i64, i64*, i32)
19 declare i8 @llvm.nacl.atomic.rmw.i8(i32, i8*, i8, i32) 20 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 i16 @llvm.nacl.atomic.rmw.i16(i32, i16*, i16, i32)
21 declare i32 @llvm.nacl.atomic.rmw.i32(i32, i32*, i32, i32) 22 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 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 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 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 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 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(i32)
28 declare void @llvm.nacl.atomic.fence.all() 29 declare void @llvm.nacl.atomic.fence.all()
29 declare i1 @llvm.nacl.atomic.is.lock.free(i32, i8*) 30 declare i1 @llvm.nacl.atomic.is.lock.free(i32, i8*)
30 31
32 ; NOTE: The LLC equivalent for 16-bit atomic operations are expanded
33 ; as 32-bit operations. For Subzero, assume that real 16-bit operations
34 ; will be usable (the validator will be fixed):
35 ; https://code.google.com/p/nativeclient/issues/detail?id=2981
36
31 ;;; Load 37 ;;; Load
32 38
33 ; x86 guarantees load/store to be atomic if naturally aligned. 39 ; x86 guarantees load/store to be atomic if naturally aligned.
34 ; The PNaCl IR requires all atomic accesses to be naturally aligned. 40 ; The PNaCl IR requires all atomic accesses to be naturally aligned.
35 41
36 define i32 @test_atomic_load_8(i32 %iptr) { 42 define i32 @test_atomic_load_8(i32 %iptr) {
37 entry: 43 entry:
38 %ptr = inttoptr i32 %iptr to i8* 44 %ptr = inttoptr i32 %iptr to i8*
39 ; parameter value "6" is for the sequential consistency memory order. 45 ; parameter value "6" is for the sequential consistency memory order.
40 %i = call i8 @llvm.nacl.atomic.load.i8(i8* %ptr, i32 6) 46 %i = call i8 @llvm.nacl.atomic.load.i8(i8* %ptr, i32 6)
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 define i64 @test_atomic_load_64_ignored(i32 %iptr) { 106 define i64 @test_atomic_load_64_ignored(i32 %iptr) {
101 entry: 107 entry:
102 %ptr = inttoptr i32 %iptr to i64* 108 %ptr = inttoptr i32 %iptr to i64*
103 %ignored = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6) 109 %ignored = call i64 @llvm.nacl.atomic.load.i64(i64* %ptr, i32 6)
104 ret i64 0 110 ret i64 0
105 } 111 }
106 ; CHECK-LABEL: test_atomic_load_64_ignored 112 ; CHECK-LABEL: test_atomic_load_64_ignored
107 ; CHECK: movq x{{.*}}, qword 113 ; CHECK: movq x{{.*}}, qword
108 ; CHECK: movq qword {{.*}}, x{{.*}} 114 ; CHECK: movq qword {{.*}}, x{{.*}}
109 115
110
111 ;;; Store 116 ;;; Store
112 117
113 define void @test_atomic_store_8(i32 %iptr, i32 %v) { 118 define void @test_atomic_store_8(i32 %iptr, i32 %v) {
114 entry: 119 entry:
115 %truncv = trunc i32 %v to i8 120 %truncv = trunc i32 %v to i8
116 %ptr = inttoptr i32 %iptr to i8* 121 %ptr = inttoptr i32 %iptr to i8*
117 call void @llvm.nacl.atomic.store.i8(i8 %truncv, i8* %ptr, i32 6) 122 call void @llvm.nacl.atomic.store.i8(i8 %truncv, i8* %ptr, i32 6)
118 ret void 123 ret void
119 } 124 }
120 ; CHECK-LABEL: test_atomic_store_8 125 ; CHECK-LABEL: test_atomic_store_8
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 ; CHECK-LABEL: test_atomic_store_64_const 167 ; CHECK-LABEL: test_atomic_store_64_const
163 ; CHECK: mov {{.*}}, 1942892530 168 ; CHECK: mov {{.*}}, 1942892530
164 ; CHECK: mov {{.*}}, 2874 169 ; CHECK: mov {{.*}}, 2874
165 ; CHECK: movq x{{.*}}, qword 170 ; CHECK: movq x{{.*}}, qword
166 ; CHECK: movq qword {{.*}}, x{{.*}} 171 ; CHECK: movq qword {{.*}}, x{{.*}}
167 ; CHECK: mfence 172 ; CHECK: mfence
168 173
169 174
170 ;;; RMW 175 ;;; RMW
171 176
177 ;; add
178
172 define i32 @test_atomic_rmw_add_8(i32 %iptr, i32 %v) { 179 define i32 @test_atomic_rmw_add_8(i32 %iptr, i32 %v) {
173 entry: 180 entry:
174 %trunc = trunc i32 %v to i8 181 %trunc = trunc i32 %v to i8
175 %ptr = inttoptr i32 %iptr to i8* 182 %ptr = inttoptr i32 %iptr to i8*
176 ; "1" is an atomic add, and "6" is sequential consistency. 183 ; "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) 184 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 1, i8* %ptr, i8 %trunc, i32 6)
178 %a_ext = zext i8 %a to i32 185 %a_ext = zext i8 %a to i32
179 ret i32 %a_ext 186 ret i32 %a_ext
180 } 187 }
181 ; CHECK-LABEL: test_atomic_rmw_add_8 188 ; CHECK-LABEL: test_atomic_rmw_add_8
(...skipping 15 matching lines...) Expand all
197 define i32 @test_atomic_rmw_add_32(i32 %iptr, i32 %v) { 204 define i32 @test_atomic_rmw_add_32(i32 %iptr, i32 %v) {
198 entry: 205 entry:
199 %ptr = inttoptr i32 %iptr to i32* 206 %ptr = inttoptr i32 %iptr to i32*
200 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) 207 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6)
201 ret i32 %a 208 ret i32 %a
202 } 209 }
203 ; CHECK-LABEL: test_atomic_rmw_add_32 210 ; CHECK-LABEL: test_atomic_rmw_add_32
204 ; CHECK: lock xadd dword {{.*}}, [[REG:.*]] 211 ; CHECK: lock xadd dword {{.*}}, [[REG:.*]]
205 ; CHECK: mov {{.*}}, {{.*}}[[REG]] 212 ; CHECK: mov {{.*}}, {{.*}}[[REG]]
206 213
207 ;define i64 @test_atomic_rmw_add_64(i32 %iptr, i64 %v) { 214 define i64 @test_atomic_rmw_add_64(i32 %iptr, i64 %v) {
208 ;entry: 215 entry:
209 ; %ptr = inttoptr i32 %iptr to i64* 216 %ptr = inttoptr i32 %iptr to i64*
210 ; %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6) 217 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6)
211 ; ret i64 %a 218 ret i64 %a
212 ;} 219 }
213 ; CHECKLATER-LABEL: test_atomic_rmw_add_64 220 ; CHECK-LABEL: test_atomic_rmw_add_64
214 ; CHECKLATER: uh need a... cmpxchg8b loop. 221 ; CHECK: mov eax, dword ptr [{{.*}}]
222 ; CHECK: mov edx, dword ptr [{{.*}}+4]
223 ; CHECK: .L[[LABEL:.*]]:
224 ; CHECK: mov ebx, eax
225 ; RHS of add cannot be any of the e[abcd]x regs because they are
226 ; clobbered in the loop, and the RHS needs to be remain live.
227 ; CHECK: add ebx, {{.*e.[^x]}}
228 ; CHECK: mov ecx, edx
229 ; CHECK: adc ecx, {{.*e.[^x]}}
230 ; Ptr cannot be eax, ebx, ecx, or edx (used up for the expected and desired).
231 ; It can be esi, edi, or ebp though, for example (so we need to be careful
232 ; about rejecting eb* and ed*.)
233 ; CHECK: lock cmpxchg8b qword ptr [e{{.[^x]}}]
Jim Stichnoth 2014/07/08 04:50:19 For the cmpxchg8b tests, it would be good to check
jvoung (off chromium) 2014/07/09 17:07:56 Done.
234 ; CHECK: jne .L{{.*}}[[LABEL]]
235
236 ; Test with some more register pressure. When we have an alloca, ebp is
237 ; used to manage the stack frame, so it cannot be used as a register either.
238 declare void @use_ptr(i32 %iptr)
239
240 define i64 @test_atomic_rmw_add_64_alloca(i32 %iptr, i64 %v) {
241 entry:
242 %alloca_ptr = alloca i8, i32 16, align 16
243 %ptr = inttoptr i32 %iptr to i64*
244 %old = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v, i32 6)
245 store i8 0, i8* %alloca_ptr, align 1
246 store i8 1, i8* %alloca_ptr, align 1
247 store i8 2, i8* %alloca_ptr, align 1
248 store i8 3, i8* %alloca_ptr, align 1
249 %__5 = ptrtoint i8* %alloca_ptr to i32
250 call void @use_ptr(i32 %__5)
251 ret i64 %old
252 }
253 ; CHECK-LABEL: test_atomic_rmw_add_64_alloca
254 ; CHECK-DAG: mov edx
255 ; CHECK-DAG: mov eax
256 ; CHECK-DAG: mov ecx
257 ; CHECK-DAG: mov ebx
258 ; Ptr cannot be eax, ebx, ecx, or edx (used up for the expected and desired).
259 ; It also cannot be ebp since we use that for alloca. Also make sure it's
260 ; not esp, since that's the stack pointer and mucking with it will break
261 ; the later use_ptr function call.
262 ; That pretty much leaves esi, or edi as the only viable registers.
263 ; CHECK: lock cmpxchg8b qword ptr [e{{[ds]}}i]
264 ; CHECK: call use_ptr
265
215 266
216 define i32 @test_atomic_rmw_add_32_ignored(i32 %iptr, i32 %v) { 267 define i32 @test_atomic_rmw_add_32_ignored(i32 %iptr, i32 %v) {
217 entry: 268 entry:
218 %ptr = inttoptr i32 %iptr to i32* 269 %ptr = inttoptr i32 %iptr to i32*
219 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6) 270 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 1, i32* %ptr, i32 %v, i32 6)
220 ret i32 %v 271 ret i32 %v
221 } 272 }
273 ; Technically this could use "lock add" instead of "lock xadd", if liveness
274 ; tells us that the destination variable is dead.
222 ; CHECK-LABEL: test_atomic_rmw_add_32_ignored 275 ; CHECK-LABEL: test_atomic_rmw_add_32_ignored
223 ; CHECK: lock xadd dword {{.*}}, [[REG:.*]] 276 ; CHECK: lock xadd dword {{.*}}, [[REG:.*]]
224 277
225 ;define i32 @test_atomic_rmw_sub_32(i32 %iptr, i32 %v) { 278 ; Atomic RMW 64 needs to be expanded into its own loop.
226 ;entry: 279 ; Make sure that works w/ non-trivial function bodies.
227 ; %ptr = inttoptr i32 %iptr to i32* 280 define i64 @test_atomic_rmw_add_64_loop(i32 %iptr, i64 %v) {
228 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6) 281 entry:
229 ; ret i32 %a 282 %x = icmp ult i64 %v, 100
230 ;} 283 br i1 %x, label %err, label %loop
231 ; CHECKLATER-LABEL: test_atomic_rmw_sub_32 284
232 ; CHECKLATER: neg 285 loop:
233 ; CHECKLATER: lock 286 %v_next = phi i64 [ %v, %entry ], [ %next, %loop ]
234 ; CHECKLATER: xadd 287 %ptr = inttoptr i32 %iptr to i64*
235 288 %next = call i64 @llvm.nacl.atomic.rmw.i64(i32 1, i64* %ptr, i64 %v_next, i32 6)
236 ;define i32 @test_atomic_rmw_or_32(i32 %iptr, i32 %v) { 289 %success = icmp eq i64 %next, 100
237 ;entry: 290 br i1 %success, label %done, label %loop
238 ; %ptr = inttoptr i32 %iptr to i32* 291
239 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6) 292 done:
240 ; ret i32 %a 293 ret i64 %next
241 ;} 294
242 ; CHECKLATER-LABEL: test_atomic_rmw_or_32 295 err:
243 ; Need a cmpxchg loop. 296 ret i64 0
244 297 }
245 ;define i32 @test_atomic_rmw_and_32(i32 %iptr, i32 %v) { 298 ; CHECK-LABEL: test_atomic_rmw_add_64_loop
246 ;entry: 299 ; CHECK-LABEL: .Ltest_atomic_rmw_add_64_loop{{.*}}loop
247 ; %ptr = inttoptr i32 %iptr to i32* 300 ; CHECK: mov eax, dword ptr [{{.*}}]
248 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6) 301 ; CHECK: mov edx, dword ptr [{{.*}}+4]
249 ; ret i32 %a 302 ; CHECK: .L[[LABEL:.*]]:
250 ;} 303 ; CHECK: mov ebx, eax
251 ; CHECKLATER-LABEL: test_atomic_rmw_and_32 304 ; CHECK: add ebx, {{.*e.[^x]}}
252 ; Also a cmpxchg loop. 305 ; CHECK: mov ecx, edx
253 306 ; CHECK: adc ecx, {{.*e.[^x]}}
254 ;define i32 @test_atomic_rmw_xor_32(i32 %iptr, i32 %v) { 307 ; CHECK: lock cmpxchg8b qword ptr [e{{.[^x]}}]
255 ;entry: 308 ; CHECK: jne .L{{.*}}[[LABEL]]
256 ; %ptr = inttoptr i32 %iptr to i32* 309 ; CHECK-LABEL: .Ltest_atomic_rmw_add_64_loop{{.*}}done
257 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6) 310
258 ; ret i32 %a 311 ;; sub
259 ;} 312
260 ; CHECKLATER-LABEL: test_atomic_rmw_xor_32 313 define i32 @test_atomic_rmw_sub_8(i32 %iptr, i32 %v) {
261 ; Also a cmpxchg loop. 314 entry:
262 315 %trunc = trunc i32 %v to i8
263 ;define i32 @test_atomic_rmw_xchg_32(i32 %iptr, i32 %v) { 316 %ptr = inttoptr i32 %iptr to i8*
264 ;entry: 317 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 2, i8* %ptr, i8 %trunc, i32 6)
265 ; %ptr = inttoptr i32 %iptr to i32* 318 %a_ext = zext i8 %a to i32
266 ; %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6) 319 ret i32 %a_ext
267 ; ret i32 %a 320 }
268 ;} 321 ; CHECK-LABEL: test_atomic_rmw_sub_8
269 ; CHECKLATER-LABEL: test_atomic_rmw_xchg_32 322 ; CHECK: neg [[REG:.*]]
323 ; CHECK: lock xadd byte {{.*}}, {{.*}}[[REG]]
324 ; CHECK: mov {{.*}}, {{.*}}[[REG]]
325
326 define i32 @test_atomic_rmw_sub_16(i32 %iptr, i32 %v) {
327 entry:
328 %trunc = trunc i32 %v to i16
329 %ptr = inttoptr i32 %iptr to i16*
330 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 2, i16* %ptr, i16 %trunc, i32 6)
331 %a_ext = zext i16 %a to i32
332 ret i32 %a_ext
333 }
334 ; CHECK-LABEL: test_atomic_rmw_sub_16
335 ; CHECK: neg [[REG:.*]]
336 ; CHECK: lock xadd word {{.*}}, {{.*}}[[REG]]
337 ; CHECK: mov {{.*}}, {{.*}}[[REG]]
338
339 define i32 @test_atomic_rmw_sub_32(i32 %iptr, i32 %v) {
340 entry:
341 %ptr = inttoptr i32 %iptr to i32*
342 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6)
343 ret i32 %a
344 }
345 ; CHECK-LABEL: test_atomic_rmw_sub_32
346 ; CHECK: neg [[REG:.*]]
347 ; CHECK: lock xadd dword {{.*}}, {{.*}}[[REG]]
348 ; CHECK: mov {{.*}}, {{.*}}[[REG]]
349
350 define i64 @test_atomic_rmw_sub_64(i32 %iptr, i64 %v) {
351 entry:
352 %ptr = inttoptr i32 %iptr to i64*
353 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 2, i64* %ptr, i64 %v, i32 6)
354 ret i64 %a
355 }
356 ; CHECK-LABEL: test_atomic_rmw_sub_64
357 ; CHECK: mov eax, dword ptr [{{.*}}]
358 ; CHECK: mov edx, dword ptr [{{.*}}+4]
359 ; CHECK: .L[[LABEL:.*]]:
360 ; CHECK: mov ebx, eax
361 ; CHECK: sub ebx, {{.*e.[^x]}}
362 ; CHECK: mov ecx, edx
363 ; CHECK: sbb ecx, {{.*e.[^x]}}
364 ; CHECK: lock cmpxchg8b qword ptr [e{{.[^x]}}]
365 ; CHECK: jne .L{{.*}}[[LABEL]]
366
367
368 define i32 @test_atomic_rmw_sub_32_ignored(i32 %iptr, i32 %v) {
369 entry:
370 %ptr = inttoptr i32 %iptr to i32*
371 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 2, i32* %ptr, i32 %v, i32 6)
372 ret i32 %v
373 }
374 ; Could use "lock sub" instead of "neg; lock xadd"
375 ; CHECK-LABEL: test_atomic_rmw_sub_32_ignored
376 ; CHECK: neg [[REG:.*]]
377 ; CHECK: lock xadd dword {{.*}}, {{.*}}[[REG]]
378
379 ;; or
380
381 define i32 @test_atomic_rmw_or_8(i32 %iptr, i32 %v) {
382 entry:
383 %trunc = trunc i32 %v to i8
384 %ptr = inttoptr i32 %iptr to i8*
385 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 3, i8* %ptr, i8 %trunc, i32 6)
386 %a_ext = zext i8 %a to i32
387 ret i32 %a_ext
388 }
389 ; CHECK-LABEL: test_atomic_rmw_or_8
390 ; CHECK: mov al, byte ptr
391 ; CHECK: .L[[LABEL:.*]]:
392 ; Dest cannot be eax here, because eax is used for the old value. Also want
393 ; to make sure that cmpxchg's source is the same register.
394 ; CHECK: or [[REG:[^a].]]
395 ; CHECK: lock cmpxchg byte ptr [e{{[^a].}}], {{.*}}[[REG]]
396 ; CHECK: jne .L{{.*}}[[LABEL]]
397
398 define i32 @test_atomic_rmw_or_16(i32 %iptr, i32 %v) {
399 entry:
400 %trunc = trunc i32 %v to i16
401 %ptr = inttoptr i32 %iptr to i16*
402 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 3, i16* %ptr, i16 %trunc, i32 6)
403 %a_ext = zext i16 %a to i32
404 ret i32 %a_ext
405 }
406 ; CHECK-LABEL: test_atomic_rmw_or_16
407 ; CHECK: mov ax, word ptr
408 ; CHECK: .L[[LABEL:.*]]:
409 ; CHECK: or [[REG:[^a].]]
410 ; CHECK: lock cmpxchg word ptr [e{{[^a].}}], {{.*}}[[REG]]
411 ; CHECK: jne .L{{.*}}[[LABEL]]
412
413 define i32 @test_atomic_rmw_or_32(i32 %iptr, i32 %v) {
414 entry:
415 %ptr = inttoptr i32 %iptr to i32*
416 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6)
417 ret i32 %a
418 }
419 ; CHECK-LABEL: test_atomic_rmw_or_32
420 ; CHECK: mov eax, dword ptr
421 ; CHECK: .L[[LABEL:.*]]:
422 ; CHECK: or [[REG:e[^a].]]
423 ; CHECK: lock cmpxchg dword ptr [e{{[^a].}}], {{.*}}[[REG]]
424 ; CHECK: jne .L{{.*}}[[LABEL]]
425
426 define i64 @test_atomic_rmw_or_64(i32 %iptr, i64 %v) {
427 entry:
428 %ptr = inttoptr i32 %iptr to i64*
429 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 3, i64* %ptr, i64 %v, i32 6)
430 ret i64 %a
431 }
432 ; CHECK-LABEL: test_atomic_rmw_or_64
433 ; CHECK: mov eax, dword ptr [{{.*}}]
434 ; CHECK: mov edx, dword ptr [{{.*}}+4]
435 ; CHECK: .L[[LABEL:.*]]:
436 ; CHECK: mov ebx, eax
437 ; CHECK: or ebx, {{.*e.[^x]}}
438 ; CHECK: mov ecx, edx
439 ; CHECK: or ecx, {{.*e.[^x]}}
440 ; CHECK: lock cmpxchg8b qword ptr [e{{.[^x]}}]
441 ; CHECK: jne .L{{.*}}[[LABEL]]
442
443 define i32 @test_atomic_rmw_or_32_ignored(i32 %iptr, i32 %v) {
444 entry:
445 %ptr = inttoptr i32 %iptr to i32*
446 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 3, i32* %ptr, i32 %v, i32 6)
447 ret i32 %v
448 }
449 ; CHECK-LABEL: test_atomic_rmw_or_32_ignored
450 ; Could just "lock or", if we inspect the liveness information first.
451 ; Would also need a way to introduce "lock"'edness to binary
452 ; operators without introducing overhead on the more common binary ops.
453 ; CHECK: mov eax, dword ptr
454 ; CHECK: .L[[LABEL:.*]]:
455 ; CHECK: or [[REG:e[^a].]]
456 ; CHECK: lock cmpxchg dword ptr [e{{[^a].}}], {{.*}}[[REG]]
457 ; CHECK: jne .L{{.*}}[[LABEL]]
458
459 ;; and
460
461 define i32 @test_atomic_rmw_and_8(i32 %iptr, i32 %v) {
462 entry:
463 %trunc = trunc i32 %v to i8
464 %ptr = inttoptr i32 %iptr to i8*
465 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 4, i8* %ptr, i8 %trunc, i32 6)
466 %a_ext = zext i8 %a to i32
467 ret i32 %a_ext
468 }
469 ; CHECK-LABEL: test_atomic_rmw_and_8
470 ; CHECK: mov al, byte ptr
471 ; CHECK: .L[[LABEL:.*]]:
472 ; CHECK: and [[REG:[^a].]]
473 ; CHECK: lock cmpxchg byte ptr [e{{[^a].}}], {{.*}}[[REG]]
474 ; CHECK: jne .L{{.*}}[[LABEL]]
475
476 define i32 @test_atomic_rmw_and_16(i32 %iptr, i32 %v) {
477 entry:
478 %trunc = trunc i32 %v to i16
479 %ptr = inttoptr i32 %iptr to i16*
480 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 4, i16* %ptr, i16 %trunc, i32 6)
481 %a_ext = zext i16 %a to i32
482 ret i32 %a_ext
483 }
484 ; CHECK-LABEL: test_atomic_rmw_and_16
485 ; CHECK: mov ax, word ptr
486 ; CHECK: .L[[LABEL:.*]]:
487 ; CHECK: and
488 ; CHECK: lock cmpxchg word ptr [e{{[^a].}}]
489 ; CHECK: jne .L{{.*}}[[LABEL]]
490
491 define i32 @test_atomic_rmw_and_32(i32 %iptr, i32 %v) {
492 entry:
493 %ptr = inttoptr i32 %iptr to i32*
494 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6)
495 ret i32 %a
496 }
497 ; CHECK-LABEL: test_atomic_rmw_and_32
498 ; CHECK: mov eax, dword ptr
499 ; CHECK: .L[[LABEL:.*]]:
500 ; CHECK: and
501 ; CHECK: lock cmpxchg dword ptr [e{{[^a].}}]
502 ; CHECK: jne .L{{.*}}[[LABEL]]
503
504 define i64 @test_atomic_rmw_and_64(i32 %iptr, i64 %v) {
505 entry:
506 %ptr = inttoptr i32 %iptr to i64*
507 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 4, i64* %ptr, i64 %v, i32 6)
508 ret i64 %a
509 }
510 ; CHECK-LABEL: test_atomic_rmw_and_64
511 ; CHECK: mov eax, dword ptr [{{.*}}]
512 ; CHECK: mov edx, dword ptr [{{.*}}+4]
513 ; CHECK: .L[[LABEL:.*]]:
514 ; CHECK: mov ebx, eax
515 ; CHECK: and ebx, {{.*e.[^x]}}
516 ; CHECK: mov ecx, edx
517 ; CHECK: and ecx, {{.*e.[^x]}}
518 ; CHECK: lock cmpxchg8b qword ptr [e{{.[^x]}}]
519 ; CHECK: jne .L{{.*}}[[LABEL]]
520
521 define i32 @test_atomic_rmw_and_32_ignored(i32 %iptr, i32 %v) {
522 entry:
523 %ptr = inttoptr i32 %iptr to i32*
524 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 4, i32* %ptr, i32 %v, i32 6)
525 ret i32 %v
526 }
527 ; CHECK-LABEL: test_atomic_rmw_and_32_ignored
528 ; Could just "lock and"
529 ; CHECK: mov eax, dword ptr
530 ; CHECK: .L[[LABEL:.*]]:
531 ; CHECK: and
532 ; CHECK: lock cmpxchg dword ptr [e{{[^a].}}]
533 ; CHECK: jne .L{{.*}}[[LABEL]]
534
535 ;; xor
536
537 define i32 @test_atomic_rmw_xor_8(i32 %iptr, i32 %v) {
538 entry:
539 %trunc = trunc i32 %v to i8
540 %ptr = inttoptr i32 %iptr to i8*
541 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 5, i8* %ptr, i8 %trunc, i32 6)
542 %a_ext = zext i8 %a to i32
543 ret i32 %a_ext
544 }
545 ; CHECK-LABEL: test_atomic_rmw_xor_8
546 ; CHECK: mov al, byte ptr
547 ; CHECK: .L[[LABEL:.*]]:
548 ; CHECK: xor [[REG:[^a].]]
549 ; CHECK: lock cmpxchg byte ptr [e{{[^a].}}], {{.*}}[[REG]]
550 ; CHECK: jne .L{{.*}}[[LABEL]]
551
552 define i32 @test_atomic_rmw_xor_16(i32 %iptr, i32 %v) {
553 entry:
554 %trunc = trunc i32 %v to i16
555 %ptr = inttoptr i32 %iptr to i16*
556 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 5, i16* %ptr, i16 %trunc, i32 6)
557 %a_ext = zext i16 %a to i32
558 ret i32 %a_ext
559 }
560 ; CHECK-LABEL: test_atomic_rmw_xor_16
561 ; CHECK: mov ax, word ptr
562 ; CHECK: .L[[LABEL:.*]]:
563 ; CHECK: xor
564 ; CHECK: lock cmpxchg word ptr [e{{[^a].}}]
565 ; CHECK: jne .L{{.*}}[[LABEL]]
566
567
568 define i32 @test_atomic_rmw_xor_32(i32 %iptr, i32 %v) {
569 entry:
570 %ptr = inttoptr i32 %iptr to i32*
571 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6)
572 ret i32 %a
573 }
574 ; CHECK-LABEL: test_atomic_rmw_xor_32
575 ; CHECK: mov eax, dword ptr
576 ; CHECK: .L[[LABEL:.*]]:
577 ; CHECK: xor
578 ; CHECK: lock cmpxchg dword ptr [e{{[^a].}}]
579 ; CHECK: jne .L{{.*}}[[LABEL]]
580
581 define i64 @test_atomic_rmw_xor_64(i32 %iptr, i64 %v) {
582 entry:
583 %ptr = inttoptr i32 %iptr to i64*
584 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 5, i64* %ptr, i64 %v, i32 6)
585 ret i64 %a
586 }
587 ; CHECK-LABEL: test_atomic_rmw_xor_64
588 ; CHECK: mov eax, dword ptr [{{.*}}]
589 ; CHECK: mov edx, dword ptr [{{.*}}+4]
590 ; CHECK: .L[[LABEL:.*]]:
591 ; CHECK: mov ebx, eax
592 ; CHECK: or ebx, {{.*e.[^x]}}
593 ; CHECK: mov ecx, edx
594 ; CHECK: or ecx, {{.*e.[^x]}}
595 ; CHECK: lock cmpxchg8b qword ptr [e{{.[^x]}}]
596 ; CHECK: jne .L{{.*}}[[LABEL]]
597
598 define i32 @test_atomic_rmw_xor_32_ignored(i32 %iptr, i32 %v) {
599 entry:
600 %ptr = inttoptr i32 %iptr to i32*
601 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %v, i32 6)
602 ret i32 %v
603 }
604 ; CHECK-LABEL: test_atomic_rmw_xor_32_ignored
605 ; CHECK: mov eax, dword ptr
606 ; CHECK: .L[[LABEL:.*]]:
607 ; CHECK: xor
608 ; CHECK: lock cmpxchg dword ptr [e{{[^a].}}]
609 ; CHECK: jne .L{{.*}}[[LABEL]]
610
611 ;; exchange
612
613 define i32 @test_atomic_rmw_xchg_8(i32 %iptr, i32 %v) {
614 entry:
615 %trunc = trunc i32 %v to i8
616 %ptr = inttoptr i32 %iptr to i8*
617 %a = call i8 @llvm.nacl.atomic.rmw.i8(i32 6, i8* %ptr, i8 %trunc, i32 6)
618 %a_ext = zext i8 %a to i32
619 ret i32 %a_ext
620 }
621 ; CHECK-LABEL: test_atomic_rmw_xchg_8
622 ; CHECK: xchg byte ptr {{.*}}, [[REG:.*]]
623
624 define i32 @test_atomic_rmw_xchg_16(i32 %iptr, i32 %v) {
625 entry:
626 %trunc = trunc i32 %v to i16
627 %ptr = inttoptr i32 %iptr to i16*
628 %a = call i16 @llvm.nacl.atomic.rmw.i16(i32 6, i16* %ptr, i16 %trunc, i32 6)
629 %a_ext = zext i16 %a to i32
630 ret i32 %a_ext
631 }
632 ; CHECK-LABEL: test_atomic_rmw_xchg_16
633 ; CHECK: xchg word ptr {{.*}}, [[REG:.*]]
634
635 define i32 @test_atomic_rmw_xchg_32(i32 %iptr, i32 %v) {
636 entry:
637 %ptr = inttoptr i32 %iptr to i32*
638 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6)
639 ret i32 %a
640 }
641 ; CHECK-LABEL: test_atomic_rmw_xchg_32
642 ; CHECK: xchg dword ptr {{.*}}, [[REG:.*]]
643
644 define i64 @test_atomic_rmw_xchg_64(i32 %iptr, i64 %v) {
645 entry:
646 %ptr = inttoptr i32 %iptr to i64*
647 %a = call i64 @llvm.nacl.atomic.rmw.i64(i32 6, i64* %ptr, i64 %v, i32 6)
648 ret i64 %a
649 }
650 ; CHECK-LABEL: test_atomic_rmw_xchg_64
651 ; CHECK-DAG: mov edx
652 ; CHECK-DAG: mov eax
653 ; CHECK-DAG: mov ecx
654 ; CHECK-DAG: mov ebx
655 ; CHECK: .L[[LABEL:.*]]:
656 ; CHECK: lock cmpxchg8b qword ptr [{{e.[^x]}}]
657 ; CHECK: jne .L{{.*}}[[LABEL]]
658
659 define i32 @test_atomic_rmw_xchg_32_ignored(i32 %iptr, i32 %v) {
660 entry:
661 %ptr = inttoptr i32 %iptr to i32*
662 %ignored = call i32 @llvm.nacl.atomic.rmw.i32(i32 6, i32* %ptr, i32 %v, i32 6)
663 ret i32 %v
664 }
665 ; In this case, ignoring the return value doesn't help. The xchg is
666 ; used to do an atomic store.
667 ; CHECK-LABEL: test_atomic_rmw_xchg_32_ignored
668 ; CHECK: xchg dword ptr {{.*}}, [[REG:.*]]
270 669
271 ;;;; Cmpxchg 670 ;;;; Cmpxchg
272 671
273 ;define i32 @test_atomic_cmpxchg_8(i32 %iptr, i32 %expected, i32 %desired) { 672 define i32 @test_atomic_cmpxchg_8(i32 %iptr, i32 %expected, i32 %desired) {
274 ;entry: 673 entry:
275 ; %ptr = inttoptr i32 %iptr to i8* 674 %trunc_exp = trunc i32 %expected to i8
276 ; %trunc_exp = trunc i32 %expected to i8 675 %trunc_des = trunc i32 %desired to i8
277 ; %trunc_des = trunc i32 %desired to i8 676 %ptr = inttoptr i32 %iptr to i8*
278 ; %old = call i8 @llvm.nacl.atomic.cmpxchg.i8(i8* %ptr, i8 %trunc_exp, 677 %old = call i8 @llvm.nacl.atomic.cmpxchg.i8(i8* %ptr, i8 %trunc_exp,
279 ; i8 %trunc_des, i32 6, i32 6) 678 i8 %trunc_des, i32 6, i32 6)
280 ; %old_ext = zext i8 %old to i32 679 %old_ext = zext i8 %old to i32
281 ; ret i32 %old_ext 680 ret i32 %old_ext
282 ;} 681 }
283 ; CHECKLATER-LABEL: test_atomic_cmpxchg_8 682 ; CHECK-LABEL: test_atomic_cmpxchg_8
284 ; CHECKLATER: lock cmpxchg byte 683 ; CHECK: mov al, {{.*}}
285 684 ; Need to check that eax isn't used as the address register or the desired.
286 ;define i32 @test_atomic_cmpxchg_16(i32 %iptr, i32 %expected, i32 %desired) { 685 ; since it is already used as the *expected* register.
287 ;entry: 686 ; CHECK: lock cmpxchg byte ptr [e{{[^a].}}], {{[^a]}}
288 ; %ptr = inttoptr i32 %iptr to i16* 687
289 ; %trunc_exp = trunc i32 %expected to i16 688 define i32 @test_atomic_cmpxchg_16(i32 %iptr, i32 %expected, i32 %desired) {
290 ; %trunc_des = trunc i32 %desired to i16 689 entry:
291 ; %old = call i16 @llvm.nacl.atomic.cmpxchg.i16(i16* %ptr, i16 %trunc_exp, 690 %trunc_exp = trunc i32 %expected to i16
292 ; i16 %trunc_des, i32 6, i32 6) 691 %trunc_des = trunc i32 %desired to i16
293 ; %old_ext = zext i16 %old to i32 692 %ptr = inttoptr i32 %iptr to i16*
294 ; ret i32 %old_ext 693 %old = call i16 @llvm.nacl.atomic.cmpxchg.i16(i16* %ptr, i16 %trunc_exp,
295 ;} 694 i16 %trunc_des, i32 6, i32 6)
296 ; CHECKLATER-LABEL: test_atomic_cmpxchg_16 695 %old_ext = zext i16 %old to i32
297 ; This one is a bit gross for NaCl right now. 696 ret i32 %old_ext
298 ; https://code.google.com/p/nativeclient/issues/detail?id=2981 697 }
299 ; But we'll assume that NaCl will have it fixed... 698 ; CHECK-LABEL: test_atomic_cmpxchg_16
300 ; CHECKLATER: lock cmpxchg word 699 ; CHECK: mov ax, {{.*}}
301 700 ; CHECK: lock cmpxchg word ptr [e{{[^a].}}], {{[^a]}}
302 ;define i32 @test_atomic_cmpxchg_32(i32 %iptr, i32 %expected, i32 %desired) { 701
303 ;entry: 702 define i32 @test_atomic_cmpxchg_32(i32 %iptr, i32 %expected, i32 %desired) {
304 ; %ptr = inttoptr i32 %iptr to i32* 703 entry:
305 ; %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected, 704 %ptr = inttoptr i32 %iptr to i32*
306 ; i32 %desired, i32 6, i32 6) 705 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected,
307 ; ret i32 %old 706 i32 %desired, i32 6, i32 6)
308 ;} 707 ret i32 %old
309 ; CHECKLATER-LABEL: test_atomic_cmpxchg_32 708 }
310 ; CHECKLATER: mov eax 709 ; CHECK-LABEL: test_atomic_cmpxchg_32
311 ; CHECKLATER: mov ecx 710 ; CHECK: mov eax, {{.*}}
312 ; CHECKLATER: lock cmpxchg dword 711 ; CHECK: lock cmpxchg dword ptr [e{{[^a].}}], e{{[^a]}}
313 712
314 ;define i64 @test_atomic_cmpxchg_64(i32 %iptr, i64 %expected, i64 %desired) { 713 define i64 @test_atomic_cmpxchg_64(i32 %iptr, i64 %expected, i64 %desired) {
315 ;entry: 714 entry:
316 ; %ptr = inttoptr i32 %iptr to i64* 715 %ptr = inttoptr i32 %iptr to i64*
317 ; %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected, 716 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected,
318 ; i64 %desired, i32 6, i32 6) 717 i64 %desired, i32 6, i32 6)
319 ; ret i64 %old 718 ret i64 %old
320 ;} 719 }
321 ; CHECKLATER-LABEL: test_atomic_cmpxchg_64 720 ; CHECK-LABEL: test_atomic_cmpxchg_64
322 ; CHECKLATER: mov eax 721 ; CHECK-DAG: mov edx
323 ; CHECKLATER: mov edx 722 ; CHECK-DAG: mov eax
324 ; CHECKLATER: mov ebx 723 ; CHECK-DAG: mov ecx
325 ; CHECKLATER: mov ecx 724 ; CHECK-DAG: mov ebx
326 ; CHECKLATER: lock cmpxchg8b qword 725 ; CHECK: lock cmpxchg8b qword ptr [e{{.[^x]}}]
327 726 ; edx and eax are already the return registers, so they don't actually
328 ;define i32 @test_atomic_cmpxchg_32_loop(i32 %iptr, 727 ; need to be reshuffled via movs. The next test stores the result
329 ; i32 %expected, i32 %desired) { 728 ; somewhere, so in that case they do need to be mov'ed.
330 ;entry: 729
331 ; br label %loop 730 ; Test a case where %old really does need to be copied out of edx:eax.
332 ; 731 define void @test_atomic_cmpxchg_64_store(i32 %ret_iptr, i32 %iptr, i64 %expecte d, i64 %desired) {
333 ;loop: 732 entry:
334 ; %cmp = phi i32 [ %expected, %entry], [%old, %loop] 733 %ptr = inttoptr i32 %iptr to i64*
335 ; %ptr = inttoptr i32 %iptr to i32* 734 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected,
336 ; %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %cmp, 735 i64 %desired, i32 6, i32 6)
337 ; i32 %desired, i32 6, i32 6) 736 %__6 = inttoptr i32 %ret_iptr to i64*
338 ; %success = icmp eq i32 %cmp, %old 737 store i64 %old, i64* %__6, align 1
339 ; br i1 %success, label %done, label %loop 738 ret void
340 ; 739 }
341 ;done: 740 ; CHECK-LABEL: test_atomic_cmpxchg_64_store
342 ; ret i32 %old 741 ; CHECK-DAG: mov edx
343 ;} 742 ; CHECK-DAG: mov eax
344 ; CHECKLATER-LABEL: test_atomic_cmpxchg_32_loop 743 ; CHECK-DAG: mov ecx
744 ; CHECK-DAG: mov ebx
745 ; CHECK: lock cmpxchg8b qword ptr [e{{.[^x]}}]
746 ; CHECK: mov {{.*}}, edx
747 ; CHECK: mov {{.*}}, eax
748
749 ; Test with some more register pressure. When we have an alloca, ebp is
750 ; used to manage the stack frame, so it cannot be used as a register either.
751 define i64 @test_atomic_cmpxchg_64_alloca(i32 %iptr, i64 %expected, i64 %desired ) {
752 entry:
753 %alloca_ptr = alloca i8, i32 16, align 16
754 %ptr = inttoptr i32 %iptr to i64*
755 %old = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected,
756 i64 %desired, i32 6, i32 6)
757 store i8 0, i8* %alloca_ptr, align 1
758 store i8 1, i8* %alloca_ptr, align 1
759 store i8 2, i8* %alloca_ptr, align 1
760 store i8 3, i8* %alloca_ptr, align 1
761 %__6 = ptrtoint i8* %alloca_ptr to i32
762 call void @use_ptr(i32 %__6)
763 ret i64 %old
764 }
765 ; CHECK-LABEL: test_atomic_cmpxchg_64_alloca
766 ; CHECK-DAG: mov edx
767 ; CHECK-DAG: mov eax
768 ; CHECK-DAG: mov ecx
769 ; CHECK-DAG: mov ebx
770 ; Ptr cannot be eax, ebx, ecx, or edx (used up for the expected and desired).
771 ; It also cannot be ebp since we use that for alloca. Also make sure it's
772 ; not esp, since that's the stack pointer and mucking with it will break
773 ; the later use_ptr function call.
774 ; That pretty much leaves esi, or edi as the only viable registers.
775 ; CHECK: lock cmpxchg8b qword ptr [e{{[ds]}}i]
776 ; CHECK: call use_ptr
777
778 define i32 @test_atomic_cmpxchg_32_ignored(i32 %iptr, i32 %expected, i32 %desire d) {
779 entry:
780 %ptr = inttoptr i32 %iptr to i32*
781 %ignored = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected,
782 i32 %desired, i32 6, i32 6)
783 ret i32 0
784 }
785 ; CHECK-LABEL: test_atomic_cmpxchg_32_ignored
786 ; CHECK: mov eax, {{.*}}
787 ; CHECK: lock cmpxchg dword ptr [e{{[^a].}}]
788
789 define i64 @test_atomic_cmpxchg_64_ignored(i32 %iptr, i64 %expected, i64 %desire d) {
790 entry:
791 %ptr = inttoptr i32 %iptr to i64*
792 %ignored = call i64 @llvm.nacl.atomic.cmpxchg.i64(i64* %ptr, i64 %expected,
793 i64 %desired, i32 6, i32 6)
794 ret i64 0
795 }
796 ; CHECK-LABEL: test_atomic_cmpxchg_64_ignored
797 ; CHECK-DAG: mov edx
798 ; CHECK-DAG: mov eax
799 ; CHECK-DAG: mov ecx
800 ; CHECK-DAG: mov ebx
801 ; CHECK: lock cmpxchg8b qword ptr [e{{.[^x]}}]
802
803 define i32 @test_atomic_cmpxchg_32_loop(i32 %iptr, i32 %expected, i32 %desired) {
804 entry:
805 br label %loop
806
807 loop:
808 %cmp = phi i32 [ %expected, %entry ], [ %old, %loop ]
809 %ptr = inttoptr i32 %iptr to i32*
810 %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %cmp,
811 i32 %desired, i32 6, i32 6)
812 %success = icmp eq i32 %cmp, %old
813 br i1 %success, label %done, label %loop
814
815 done:
816 ret i32 %old
817 }
818 ; CHECK-LABEL: test_atomic_cmpxchg_32_loop
345 819
346 ;;;; Fence and is-lock-free. 820 ;;;; Fence and is-lock-free.
347 821
348 define void @test_atomic_fence() { 822 define void @test_atomic_fence() {
349 entry: 823 entry:
350 call void @llvm.nacl.atomic.fence(i32 6) 824 call void @llvm.nacl.atomic.fence(i32 6)
351 ret void 825 ret void
352 } 826 }
353 ; CHECK-LABEL: test_atomic_fence 827 ; CHECK-LABEL: test_atomic_fence
354 ; CHECK: mfence 828 ; CHECK: mfence
(...skipping 19 matching lines...) Expand all
374 define i32 @test_not_lock_free(i32 %iptr) { 848 define i32 @test_not_lock_free(i32 %iptr) {
375 entry: 849 entry:
376 %ptr = inttoptr i32 %iptr to i8* 850 %ptr = inttoptr i32 %iptr to i8*
377 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 7, i8* %ptr) 851 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 7, i8* %ptr)
378 %r = zext i1 %i to i32 852 %r = zext i1 %i to i32
379 ret i32 %r 853 ret i32 %r
380 } 854 }
381 ; CHECK-LABEL: test_not_lock_free 855 ; CHECK-LABEL: test_not_lock_free
382 ; CHECK: mov {{.*}}, 0 856 ; CHECK: mov {{.*}}, 0
383 857
858 define i32 @test_atomic_is_lock_free_ignored(i32 %iptr) {
859 entry:
860 %ptr = inttoptr i32 %iptr to i8*
861 %ignored = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr)
862 ret i32 0
863 }
864 ; CHECK-LABEL: test_atomic_is_lock_free_ignored
865 ; CHECK: mov {{.*}}, 0
866 ; This can get optimized out, because it's side-effect-free.
867 ; CHECKO2REM-LABEL: test_atomic_is_lock_free_ignored
868 ; CHECKO2REM-NOT: mov {{.*}}, 1
869 ; CHECKO2REM: mov {{.*}}, 0
870
384 ; TODO(jvoung): at some point we can take advantage of the 871 ; TODO(jvoung): at some point we can take advantage of the
385 ; fact that nacl.atomic.is.lock.free will resolve to a constant 872 ; fact that nacl.atomic.is.lock.free will resolve to a constant
386 ; (which adds DCE opportunities). Once we optimize, the test expectations 873 ; (which adds DCE opportunities). Once we optimize, the test expectations
387 ; for this case should change. 874 ; for this case should change.
388 define i32 @test_atomic_is_lock_free_can_dce(i32 %iptr, i32 %x, i32 %y) { 875 define i32 @test_atomic_is_lock_free_can_dce(i32 %iptr, i32 %x, i32 %y) {
389 entry: 876 entry:
390 %ptr = inttoptr i32 %iptr to i8* 877 %ptr = inttoptr i32 %iptr to i8*
391 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr) 878 %i = call i1 @llvm.nacl.atomic.is.lock.free(i32 4, i8* %ptr)
392 %i_ext = zext i1 %i to i32 879 %i_ext = zext i1 %i to i32
393 %cmp = icmp eq i32 %i_ext, 1 880 %cmp = icmp eq i32 %i_ext, 1
394 br i1 %cmp, label %lock_free, label %not_lock_free 881 br i1 %cmp, label %lock_free, label %not_lock_free
395 lock_free: 882 lock_free:
396 ret i32 %i_ext 883 ret i32 %i_ext
397 884
398 not_lock_free: 885 not_lock_free:
399 %z = add i32 %x, %y 886 %z = add i32 %x, %y
400 ret i32 %z 887 ret i32 %z
401 } 888 }
402 ; CHECK-LABEL: test_atomic_is_lock_free_can_dce 889 ; CHECK-LABEL: test_atomic_is_lock_free_can_dce
403 ; CHECK: mov {{.*}}, 1 890 ; CHECK: mov {{.*}}, 1
404 ; CHECK: ret 891 ; CHECK: ret
405 ; CHECK: add 892 ; CHECK: add
406 ; CHECK: ret 893 ; CHECK: ret
407 894
408 ; ERRORS-NOT: ICE translation error 895 ; ERRORS-NOT: ICE translation error
409 ; DUMP-NOT: SZ 896 ; DUMP-NOT: SZ
OLDNEW
« src/IceTargetLoweringX8632.cpp ('K') | « src/IceTargetLoweringX8632.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698