-
Notifications
You must be signed in to change notification settings - Fork 11.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ensure NoTrapAfterNoreturn is false for the wasm backend (#65876)
In the WebAssembly back end, the TrapUnreachable option is currently load-bearing for correctness, inserting wasm `unreachable` instructions where needed to create valid wasm. There is another option, NoTrapAfterNoreturn, that removes some of those traps and causes incorrect wasm to be emitted. This turns off `NoTrapAfterNoreturn` for the Wasm backend and adds new tests.
- Loading branch information
Showing
5 changed files
with
88 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,97 @@ | ||
; RUN: llc < %s -asm-verbose=false -verify-machineinstrs | FileCheck %s | ||
; RUN: llc < %s -asm-verbose=false -fast-isel -fast-isel-abort=1 -verify-machineinstrs | FileCheck %s | ||
; 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. | ||
|
||
; Test that LLVM unreachable instruction and trap intrinsic are lowered to | ||
; wasm unreachable | ||
; 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" | ||
|
||
declare void @llvm.trap() | ||
declare void @llvm.debugtrap() | ||
declare void @abort() | ||
|
||
; CHECK-LABEL: f1: | ||
; CHECK: call abort{{$}} | ||
; CHECK: unreachable | ||
define i32 @f1() { | ||
call void @abort() | ||
unreachable | ||
} | ||
; Test that the LLVM trap and debug trap intrinsics are lowered to wasm | ||
; unreachable. | ||
|
||
; CHECK-LABEL: f2: | ||
; CHECK: unreachable | ||
define void @f2() { | ||
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: # fallthrough-return | ||
; CHECK-NEXT: end_function | ||
call void @llvm.trap() | ||
ret void | ||
} | ||
|
||
; CHECK-LABEL: f3: | ||
; CHECK: unreachable | ||
define void @f3() { | ||
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: 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 ensures wasm unreachable is emitted | ||
; 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 | ||
} |