| ; The assertions in this file were autogenerated by |
| ; utils/update_llc_test_checks.py, but were hand-edited to add the |
| ; "end_function" lines to prevent the tests from passing when there are |
| ; superfluous instructions at the end of a function. You can run |
| ; update_llc_test_checks.py again, but please keep the "end_function" lines |
| ; intact when you commit. |
| |
| ; Wasm, to generate valid code, always internally sets `--trap-unreachable` to 1 |
| ; and `--no-trap-after-noreturn` to 0, and these command lines options, if |
| ; explicitly given, are ignored. Various combinations of these options should |
| ; have no effect and should not generate invalid code. |
| ; RUN: llc < %s -verify-machineinstrs | FileCheck %s |
| ; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs | FileCheck %s |
| ; RUN: llc < %s -verify-machineinstrs --trap-unreachable | FileCheck %s |
| ; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs --trap-unreachable | FileCheck %s |
| ; RUN: llc < %s -verify-machineinstrs --trap-unreachable --no-trap-after-noreturn | FileCheck %s |
| ; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs --trap-unreachable --no-trap-after-noreturn | FileCheck %s |
| |
| target triple = "wasm32-unknown-unknown" |
| |
| |
| ; Test that the LLVM trap and debug trap intrinsics are lowered to wasm |
| ; unreachable. |
| |
| declare void @llvm.trap() cold noreturn nounwind |
| declare void @llvm.debugtrap() nounwind |
| |
| define void @trap_ret_void() { |
| ; CHECK-LABEL: trap_ret_void: |
| ; CHECK: .functype trap_ret_void () -> () |
| ; CHECK-NEXT: # %bb.0: |
| ; CHECK-NEXT: unreachable |
| ; CHECK-NEXT: end_function |
| call void @llvm.trap() |
| ret void |
| } |
| |
| define void @debugtrap_ret_void() { |
| ; CHECK-LABEL: debugtrap_ret_void: |
| ; CHECK: .functype debugtrap_ret_void () -> () |
| ; CHECK-NEXT: # %bb.0: |
| ; CHECK-NEXT: unreachable |
| ; CHECK-NEXT: # fallthrough-return |
| ; CHECK-NEXT: end_function |
| call void @llvm.debugtrap() |
| ret void |
| } |
| |
| ; LLVM trap followed by LLVM unreachable could become exactly one wasm |
| ; unreachable, but two are emitted currently. |
| define void @trap_unreacheable() { |
| ; CHECK-LABEL: trap_unreacheable: |
| ; CHECK: .functype trap_unreacheable () -> () |
| ; CHECK-NEXT: # %bb.0: |
| ; CHECK-NEXT: unreachable |
| ; CHECK-NEXT: end_function |
| call void @llvm.trap() |
| unreachable |
| } |
| |
| |
| ; Test that LLVM unreachable instruction is lowered to wasm unreachable when |
| ; necessary to fulfill the wasm operand stack requirements. |
| |
| declare void @ext_func() |
| declare i32 @ext_func_i32() |
| declare void @ext_never_return() noreturn |
| |
| ; LLVM IR's 'unreachable' is translated to Wasm 'unreachable'. |
| define i32 @missing_ret_unreachable() { |
| ; CHECK-LABEL: missing_ret_unreachable: |
| ; CHECK: .functype missing_ret_unreachable () -> (i32) |
| ; CHECK-NEXT: # %bb.0: |
| ; CHECK-NEXT: call ext_func |
| ; CHECK-NEXT: unreachable |
| ; CHECK-NEXT: end_function |
| call void @ext_func() |
| unreachable |
| } |
| |
| ; This is similar to the above test, but the callee has a 'noreturn' attribute. |
| ; There is an optimization that removes an 'unreachable' after a noreturn call, |
| ; but Wasm backend doesn't use it and ignore `--no-trap-after-noreturn`, if |
| ; given, to generate valid code. |
| define i32 @missing_ret_noreturn_unreachable() { |
| ; CHECK-LABEL: missing_ret_noreturn_unreachable: |
| ; CHECK: .functype missing_ret_noreturn_unreachable () -> (i32) |
| ; CHECK-NEXT: # %bb.0: |
| ; CHECK-NEXT: call ext_never_return |
| ; CHECK-NEXT: unreachable |
| ; CHECK-NEXT: end_function |
| call void @ext_never_return() |
| unreachable |
| } |
| |
| define i32 @no_crash_for_other_instruction_after_trap(ptr %p, i32 %b) { |
| ; CHECK-LABEL: no_crash_for_other_instruction_after_trap: |
| ; CHECK: unreachable |
| ; CHECK-NEXT: end_function |
| %a = load i32, ptr %p |
| call void @llvm.trap() |
| ret i32 %a |
| } |