OLD | NEW |
1 ; This tests the NaCl intrinsics not related to atomic operations. | 1 ; This tests the NaCl intrinsics not related to atomic operations. |
2 | 2 |
3 ; RUN: %llvm2ice -O2 --verbose none %s | FileCheck %s | 3 ; RUN: %llvm2ice -O2 --verbose none %s | FileCheck %s |
| 4 ; RUN: %llvm2ice -Om1 --verbose none %s | FileCheck %s |
| 5 |
| 6 ; Do another run w/ O2 and a different check-prefix (otherwise O2 and Om1 |
| 7 ; share the same "CHECK" prefix). This separate run helps check that |
| 8 ; some code is optimized out. |
4 ; RUN: %llvm2ice -O2 --verbose none %s | FileCheck %s --check-prefix=CHECKO2REM | 9 ; RUN: %llvm2ice -O2 --verbose none %s | FileCheck %s --check-prefix=CHECKO2REM |
5 ; RUN: %llvm2ice -Om1 --verbose none %s | FileCheck %s | 10 |
6 ; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s | 11 ; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s |
7 | |
8 ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s | 12 ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s |
9 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \ | 13 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \ |
10 ; RUN: | FileCheck --check-prefix=DUMP %s | 14 ; RUN: | FileCheck --check-prefix=DUMP %s |
11 | 15 |
12 declare i8* @llvm.nacl.read.tp() | 16 declare i8* @llvm.nacl.read.tp() |
13 declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1) | 17 declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1) |
14 declare void @llvm.memmove.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1) | 18 declare void @llvm.memmove.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1) |
15 declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i32, i1) | 19 declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i32, i1) |
16 declare void @llvm.nacl.longjmp(i8*, i32) | 20 declare void @llvm.nacl.longjmp(i8*, i32) |
17 declare i32 @llvm.nacl.setjmp(i8*) | 21 declare i32 @llvm.nacl.setjmp(i8*) |
18 declare float @llvm.sqrt.f32(float) | 22 declare float @llvm.sqrt.f32(float) |
19 declare double @llvm.sqrt.f64(double) | 23 declare double @llvm.sqrt.f64(double) |
20 declare void @llvm.trap() | 24 declare void @llvm.trap() |
| 25 declare i32 @llvm.ctlz.i32(i32, i1) |
| 26 declare i64 @llvm.ctlz.i64(i64, i1) |
| 27 declare i32 @llvm.cttz.i32(i32, i1) |
| 28 declare i64 @llvm.cttz.i64(i64, i1) |
| 29 declare i32 @llvm.ctpop.i32(i32) |
| 30 declare i64 @llvm.ctpop.i64(i64) |
21 | 31 |
22 define i32 @test_nacl_read_tp() { | 32 define i32 @test_nacl_read_tp() { |
23 entry: | 33 entry: |
24 %ptr = call i8* @llvm.nacl.read.tp() | 34 %ptr = call i8* @llvm.nacl.read.tp() |
25 %__1 = ptrtoint i8* %ptr to i32 | 35 %__1 = ptrtoint i8* %ptr to i32 |
26 ret i32 %__1 | 36 ret i32 %__1 |
27 } | 37 } |
28 ; CHECK-LABEL: test_nacl_read_tp | 38 ; CHECK-LABEL: test_nacl_read_tp |
29 ; CHECK: mov e{{.*}}, dword ptr gs:[0] | 39 ; CHECK: mov e{{.*}}, dword ptr gs:[0] |
30 ; CHECKO2REM-LABEL: test_nacl_read_tp | 40 ; CHECKO2REM-LABEL: test_nacl_read_tp |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 br i1 %r1, label %Zero, label %NonZero | 235 br i1 %r1, label %Zero, label %NonZero |
226 Zero: | 236 Zero: |
227 call void @llvm.trap() | 237 call void @llvm.trap() |
228 unreachable | 238 unreachable |
229 NonZero: | 239 NonZero: |
230 ret i32 1 | 240 ret i32 1 |
231 } | 241 } |
232 ; CHECK-LABEL: test_trap | 242 ; CHECK-LABEL: test_trap |
233 ; CHECK: ud2 | 243 ; CHECK: ud2 |
234 | 244 |
| 245 define i32 @test_ctlz_32(i32 %x) { |
| 246 entry: |
| 247 %r = call i32 @llvm.ctlz.i32(i32 %x, i1 0) |
| 248 ret i32 %r |
| 249 } |
| 250 ; CHECK-LABEL: test_ctlz_32 |
| 251 ; TODO(jvoung): If we detect that LZCNT is supported, then use that |
| 252 ; and avoid the need to do the cmovne and xor stuff to guarantee that |
| 253 ; the result is well-defined w/ input == 0. |
| 254 ; CHECK: bsr [[REG_TMP:e.*]], {{.*}} |
| 255 ; CHECK: mov [[REG_RES:e.*]], 63 |
| 256 ; CHECK: cmovne [[REG_RES]], [[REG_TMP]] |
| 257 ; CHECK: xor [[REG_RES]], 31 |
| 258 |
| 259 define i32 @test_ctlz_32_const() { |
| 260 entry: |
| 261 %r = call i32 @llvm.ctlz.i32(i32 123456, i1 0) |
| 262 ret i32 %r |
| 263 } |
| 264 ; Could potentially constant fold this, but the front-end should have done that. |
| 265 ; CHECK-LABEL: test_ctlz_32_const |
| 266 ; CHECK: bsr |
| 267 |
| 268 define i32 @test_ctlz_32_ignored(i32 %x) { |
| 269 entry: |
| 270 %ignored = call i32 @llvm.ctlz.i32(i32 %x, i1 0) |
| 271 ret i32 1 |
| 272 } |
| 273 ; CHECKO2REM-LABEL: test_ctlz_32_ignored |
| 274 ; CHECKO2REM-NOT: bsr |
| 275 |
| 276 define i64 @test_ctlz_64(i64 %x) { |
| 277 entry: |
| 278 %r = call i64 @llvm.ctlz.i64(i64 %x, i1 0) |
| 279 ret i64 %r |
| 280 } |
| 281 ; CHECKO2REM-LABEL: test_ctlz_64 |
| 282 ; CHECK-LABEL: test_ctlz_64 |
| 283 ; CHECK: bsr [[REG_TMP1:e.*]], {{.*}} |
| 284 ; CHECK: mov [[REG_RES1:e.*]], 63 |
| 285 ; CHECK: cmovne [[REG_RES1]], [[REG_TMP1]] |
| 286 ; CHECK: xor [[REG_RES1]], 31 |
| 287 ; CHECK: add [[REG_RES1]], 32 |
| 288 ; CHECK: bsr [[REG_RES2:e.*]], {{.*}} |
| 289 ; CHECK: xor [[REG_RES2]], 31 |
| 290 ; CHECK: test [[REG_UPPER:.*]], [[REG_UPPER]] |
| 291 ; CHECK: cmove [[REG_RES2]], [[REG_RES1]] |
| 292 ; CHECK: mov {{.*}}, 0 |
| 293 |
| 294 define i32 @test_ctlz_64_const(i64 %x) { |
| 295 entry: |
| 296 %r = call i64 @llvm.ctlz.i64(i64 123456789012, i1 0) |
| 297 %r2 = trunc i64 %r to i32 |
| 298 ret i32 %r2 |
| 299 } |
| 300 ; CHECK-LABEL: test_ctlz_64_const |
| 301 ; CHECK: bsr |
| 302 ; CHECK: bsr |
| 303 |
| 304 define i32 @test_ctlz_64_ignored(i64 %x) { |
| 305 entry: |
| 306 %ignored = call i64 @llvm.ctlz.i64(i64 1234567890, i1 0) |
| 307 ret i32 2 |
| 308 } |
| 309 ; CHECKO2REM-LABEL: test_ctlz_64_ignored |
| 310 ; CHECKO2REM-NOT: bsr |
| 311 |
| 312 define i32 @test_cttz_32(i32 %x) { |
| 313 entry: |
| 314 %r = call i32 @llvm.cttz.i32(i32 %x, i1 0) |
| 315 ret i32 %r |
| 316 } |
| 317 ; CHECK-LABEL: test_cttz_32 |
| 318 ; CHECK: bsf [[REG_IF_NOTZERO:e.*]], {{.*}} |
| 319 ; CHECK: mov [[REG_IF_ZERO:e.*]], 32 |
| 320 ; CHECK: cmovne [[REG_IF_ZERO]], [[REG_IF_NOTZERO]] |
| 321 |
| 322 define i64 @test_cttz_64(i64 %x) { |
| 323 entry: |
| 324 %r = call i64 @llvm.cttz.i64(i64 %x, i1 0) |
| 325 ret i64 %r |
| 326 } |
| 327 ; CHECK-LABEL: test_cttz_64 |
| 328 ; CHECK: bsf [[REG_IF_NOTZERO:e.*]], {{.*}} |
| 329 ; CHECK: mov [[REG_RES1:e.*]], 32 |
| 330 ; CHECK: cmovne [[REG_RES1]], [[REG_IF_NOTZERO]] |
| 331 ; CHECK: add [[REG_RES1]], 32 |
| 332 ; CHECK: bsf [[REG_RES2:e.*]], [[REG_LOWER:.*]] |
| 333 ; CHECK: test [[REG_LOWER]], [[REG_LOWER]] |
| 334 ; CHECK: cmove [[REG_RES2]], [[REG_RES1]] |
| 335 ; CHECK: mov {{.*}}, 0 |
| 336 |
| 337 define i32 @test_popcount_32(i32 %x) { |
| 338 entry: |
| 339 %r = call i32 @llvm.ctpop.i32(i32 %x) |
| 340 ret i32 %r |
| 341 } |
| 342 ; CHECK-LABEL: test_popcount_32 |
| 343 ; CHECK: call __popcountsi2 |
| 344 |
| 345 define i64 @test_popcount_64(i64 %x) { |
| 346 entry: |
| 347 %r = call i64 @llvm.ctpop.i64(i64 %x) |
| 348 ret i64 %r |
| 349 } |
| 350 ; CHECK-LABEL: test_popcount_64 |
| 351 ; CHECK: call __popcountdi2 |
| 352 ; __popcountdi2 only returns a 32-bit result, so clear the upper bits of |
| 353 ; the return value just in case. |
| 354 ; CHECK: mov {{.*}}, 0 |
| 355 |
| 356 define i32 @test_popcount_64_ret_i32(i64 %x) { |
| 357 entry: |
| 358 %r_i64 = call i64 @llvm.ctpop.i64(i64 %x) |
| 359 %r = trunc i64 %r_i64 to i32 |
| 360 ret i32 %r |
| 361 } |
| 362 ; If there is a trunc, then the mov {{.*}}, 0 is dead and gets optimized out. |
| 363 ; CHECKO2REM-LABEL: test_popcount_64_ret_i32 |
| 364 ; CHECKO2REM: call __popcountdi2 |
| 365 ; CHECKO2REM-NOT: mov {{.*}}, 0 |
| 366 |
| 367 |
235 ; ERRORS-NOT: ICE translation error | 368 ; ERRORS-NOT: ICE translation error |
236 ; DUMP-NOT: SZ | 369 ; DUMP-NOT: SZ |
OLD | NEW |