xref: /llvm-project/llvm/test/CodeGen/WebAssembly/unreachable.ll (revision 1a462296360f311d4593694aefd30c6b3e969460)
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.
7
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
18
19target triple = "wasm32-unknown-unknown"
20
21
22; Test that the LLVM trap and debug trap intrinsics are lowered to wasm
23; unreachable.
24
25declare void @llvm.trap() cold noreturn nounwind
26declare void @llvm.debugtrap() nounwind
27
28define 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:    end_function
34  call void @llvm.trap()
35  ret void
36}
37
38define void @debugtrap_ret_void() {
39; CHECK-LABEL: debugtrap_ret_void:
40; CHECK:         .functype debugtrap_ret_void () -> ()
41; CHECK-NEXT:  # %bb.0:
42; CHECK-NEXT:    unreachable
43; CHECK-NEXT:    # fallthrough-return
44; CHECK-NEXT:    end_function
45  call void @llvm.debugtrap()
46  ret void
47}
48
49; LLVM trap followed by LLVM unreachable could become exactly one wasm
50; unreachable, but two are emitted currently.
51define void @trap_unreacheable() {
52; CHECK-LABEL: trap_unreacheable:
53; CHECK:         .functype trap_unreacheable () -> ()
54; CHECK-NEXT:  # %bb.0:
55; CHECK-NEXT:    unreachable
56; CHECK-NEXT:    end_function
57  call void @llvm.trap()
58  unreachable
59}
60
61
62; Test that LLVM unreachable instruction is lowered to wasm unreachable when
63; necessary to fulfill the wasm operand stack requirements.
64
65declare void @ext_func()
66declare i32 @ext_func_i32()
67declare void @ext_never_return() noreturn
68
69; LLVM IR's 'unreachable' is translated to Wasm 'unreachable'.
70define i32 @missing_ret_unreachable() {
71; CHECK-LABEL: missing_ret_unreachable:
72; CHECK:         .functype missing_ret_unreachable () -> (i32)
73; CHECK-NEXT:  # %bb.0:
74; CHECK-NEXT:    call ext_func
75; CHECK-NEXT:    unreachable
76; CHECK-NEXT:    end_function
77  call void @ext_func()
78  unreachable
79}
80
81; This is similar to the above test, but the callee has a 'noreturn' attribute.
82; There is an optimization that removes an 'unreachable' after a noreturn call,
83; but Wasm backend doesn't use it and ignore `--no-trap-after-noreturn`, if
84; given, to generate valid code.
85define i32 @missing_ret_noreturn_unreachable() {
86; CHECK-LABEL: missing_ret_noreturn_unreachable:
87; CHECK:         .functype missing_ret_noreturn_unreachable () -> (i32)
88; CHECK-NEXT:  # %bb.0:
89; CHECK-NEXT:    call ext_never_return
90; CHECK-NEXT:    unreachable
91; CHECK-NEXT:    end_function
92  call void @ext_never_return()
93  unreachable
94}
95
96define i32 @no_crash_for_other_instruction_after_trap(ptr %p, i32 %b) {
97; CHECK-LABEL: no_crash_for_other_instruction_after_trap:
98; CHECK:      unreachable
99; CHECK-NEXT: end_function
100  %a = load i32, ptr %p
101  call void @llvm.trap()
102  ret i32 %a
103}
104