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