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

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

Powered by Google App Engine
This is Rietveld 408576698