|
1 |
| -; RUN: llc < %s -asm-verbose=false -verify-machineinstrs | FileCheck %s |
2 |
| -; RUN: llc < %s -asm-verbose=false -fast-isel -fast-isel-abort=1 -verify-machineinstrs | FileCheck %s |
| 1 | +; The assertions in this file were autogenerated by |
| 2 | +; utils/update_llc_test_checks.py, but were hand-edited to add the |
| 3 | +; "end_function" lines to prevent the tests from passing when there are |
| 4 | +; superfluous instructions at the end of a function. You can run |
| 5 | +; update_llc_test_checks.py again, but please keep the "end_function" lines |
| 6 | +; intact when you commit. |
3 | 7 |
|
4 |
| -; Test that LLVM unreachable instruction and trap intrinsic are lowered to |
5 |
| -; wasm unreachable |
| 8 | +; Wasm, to generate valid code, always internally sets `--trap-unreachable` to 1 |
| 9 | +; and `--no-trap-after-noreturn` to 0, and these command lines options, if |
| 10 | +; explicitly given, are ignored. Various combinations of these options should |
| 11 | +; have no effect and should not generate invalid code. |
| 12 | +; RUN: llc < %s -verify-machineinstrs | FileCheck %s |
| 13 | +; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs | FileCheck %s |
| 14 | +; RUN: llc < %s -verify-machineinstrs --trap-unreachable | FileCheck %s |
| 15 | +; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs --trap-unreachable | FileCheck %s |
| 16 | +; RUN: llc < %s -verify-machineinstrs --trap-unreachable --no-trap-after-noreturn | FileCheck %s |
| 17 | +; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs --trap-unreachable --no-trap-after-noreturn | FileCheck %s |
6 | 18 |
|
7 | 19 | target triple = "wasm32-unknown-unknown"
|
8 | 20 |
|
9 |
| -declare void @llvm.trap() |
10 |
| -declare void @llvm.debugtrap() |
11 |
| -declare void @abort() |
12 | 21 |
|
13 |
| -; CHECK-LABEL: f1: |
14 |
| -; CHECK: call abort{{$}} |
15 |
| -; CHECK: unreachable |
16 |
| -define i32 @f1() { |
17 |
| - call void @abort() |
18 |
| - unreachable |
19 |
| -} |
| 22 | +; Test that the LLVM trap and debug trap intrinsics are lowered to wasm |
| 23 | +; unreachable. |
20 | 24 |
|
21 |
| -; CHECK-LABEL: f2: |
22 |
| -; CHECK: unreachable |
23 |
| -define void @f2() { |
| 25 | +declare void @llvm.trap() cold noreturn nounwind |
| 26 | +declare void @llvm.debugtrap() nounwind |
| 27 | + |
| 28 | +define void @trap_ret_void() { |
| 29 | +; CHECK-LABEL: trap_ret_void: |
| 30 | +; CHECK: .functype trap_ret_void () -> () |
| 31 | +; CHECK-NEXT: # %bb.0: |
| 32 | +; CHECK-NEXT: unreachable |
| 33 | +; CHECK-NEXT: # fallthrough-return |
| 34 | +; CHECK-NEXT: end_function |
24 | 35 | call void @llvm.trap()
|
25 | 36 | ret void
|
26 | 37 | }
|
27 | 38 |
|
28 |
| -; CHECK-LABEL: f3: |
29 |
| -; CHECK: unreachable |
30 |
| -define void @f3() { |
| 39 | +define void @debugtrap_ret_void() { |
| 40 | +; CHECK-LABEL: debugtrap_ret_void: |
| 41 | +; CHECK: .functype debugtrap_ret_void () -> () |
| 42 | +; CHECK-NEXT: # %bb.0: |
| 43 | +; CHECK-NEXT: unreachable |
| 44 | +; CHECK-NEXT: # fallthrough-return |
| 45 | +; CHECK-NEXT: end_function |
31 | 46 | call void @llvm.debugtrap()
|
32 | 47 | ret void
|
33 | 48 | }
|
| 49 | + |
| 50 | +; LLVM trap followed by LLVM unreachable could become exactly one wasm |
| 51 | +; unreachable, but two are emitted currently. |
| 52 | +define void @trap_unreacheable() { |
| 53 | +; CHECK-LABEL: trap_unreacheable: |
| 54 | +; CHECK: .functype trap_unreacheable () -> () |
| 55 | +; CHECK-NEXT: # %bb.0: |
| 56 | +; CHECK-NEXT: unreachable |
| 57 | +; CHECK-NEXT: unreachable |
| 58 | +; CHECK-NEXT: end_function |
| 59 | + call void @llvm.trap() |
| 60 | + unreachable |
| 61 | +} |
| 62 | + |
| 63 | + |
| 64 | +; Test that LLVM unreachable instruction is lowered to wasm unreachable when |
| 65 | +; necessary to fulfill the wasm operand stack requirements. |
| 66 | + |
| 67 | +declare void @ext_func() |
| 68 | +declare i32 @ext_func_i32() |
| 69 | +declare void @ext_never_return() noreturn |
| 70 | + |
| 71 | +; LLVM IR's 'unreachable' is translated to Wasm 'unreachable'. |
| 72 | +define i32 @missing_ret_unreachable() { |
| 73 | +; CHECK-LABEL: missing_ret_unreachable: |
| 74 | +; CHECK: .functype missing_ret_unreachable () -> (i32) |
| 75 | +; CHECK-NEXT: # %bb.0: |
| 76 | +; CHECK-NEXT: call ext_func |
| 77 | +; CHECK-NEXT: unreachable |
| 78 | +; CHECK-NEXT: end_function |
| 79 | + call void @ext_func() |
| 80 | + unreachable |
| 81 | +} |
| 82 | + |
| 83 | +; This is similar to the above test, but ensures wasm unreachable is emitted |
| 84 | +; This is similar to the above test, but the callee has a 'noreturn' attribute. |
| 85 | +; There is an optimization that removes an 'unreachable' after a noreturn call, |
| 86 | +; but Wasm backend doesn't use it and ignore `--no-trap-after-noreturn`, if |
| 87 | +; given, to generate valid code. |
| 88 | +define i32 @missing_ret_noreturn_unreachable() { |
| 89 | +; CHECK-LABEL: missing_ret_noreturn_unreachable: |
| 90 | +; CHECK: .functype missing_ret_noreturn_unreachable () -> (i32) |
| 91 | +; CHECK-NEXT: # %bb.0: |
| 92 | +; CHECK-NEXT: call ext_never_return |
| 93 | +; CHECK-NEXT: unreachable |
| 94 | +; CHECK-NEXT: end_function |
| 95 | + call void @ext_never_return() |
| 96 | + unreachable |
| 97 | +} |
0 commit comments