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