Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |