Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure NoTrapAfterNoreturn is false for the wasm backend #65876

Merged
merged 16 commits into from
Oct 5, 2023
Merged
2 changes: 1 addition & 1 deletion llvm/include/llvm/CodeGen/MachineFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ class LLVM_EXTERNAL_VISIBILITY MachineFunction {
// RegInfo - Information about each register in use in the function.
MachineRegisterInfo *RegInfo;

// Used to keep track of target-specific per-machine function information for
// Used to keep track of target-specific per-machine-function information for
// the target implementation.
MachineFunctionInfo *MFInfo;

Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/CodeGen/MachineInstr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1276,7 +1276,7 @@ class MachineInstr
/// eraseFromBundle() to erase individual bundled instructions.
void eraseFromParent();

/// Unlink 'this' form its basic block and delete it.
/// Unlink 'this' from its basic block and delete it.
///
/// If the instruction is part of a bundle, the other instructions in the
/// bundle remain bundled.
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) {

// When there is an unconditional branch right before a catch instruction and
// it branches to the end of end_try marker, we don't need the branch, because
// it there is no exception, the control flow transfers to that point anyway.
// if there is no exception, the control flow transfers to that point anyway.
// bb0:
// try
// ...
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
// LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
// 'unreachable' instructions which is meant for that case.
this->Options.TrapUnreachable = true;
this->Options.NoTrapAfterNoreturn = false;
majaha marked this conversation as resolved.
Show resolved Hide resolved

// WebAssembly treats each function as an independent unit. Force
// -ffunction-sections, effectively, so that we can emit them independently.
Expand Down
102 changes: 82 additions & 20 deletions llvm/test/CodeGen/WebAssembly/unreachable.ll
Original file line number Diff line number Diff line change
@@ -1,33 +1,95 @@
; 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.

majaha marked this conversation as resolved.
Show resolved Hide resolved
; Test that LLVM unreachable instruction and trap intrinsic are lowered to
; wasm unreachable

; The --trap-unreachable and --no-trap-after-noreturn options are ignored, and
; should have no effect.
; RUN: llc < %s -verify-machineinstrs | FileCheck %s
majaha marked this conversation as resolved.
Show resolved Hide resolved
; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs | FileCheck %s
majaha marked this conversation as resolved.
Show resolved Hide resolved
majaha marked this conversation as resolved.
Show resolved Hide resolved
; 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.

declare void @llvm.trap() cold noreturn nounwind
declare void @llvm.debugtrap() nounwind

; CHECK-LABEL: f2:
; CHECK: unreachable
define void @f2() {
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

; The wasm unreachable in this test is necessary for the function to pass wasm
; validation.
define i32 @missing_ret_unreachable() {
majaha marked this conversation as resolved.
Show resolved Hide resolved
; 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
; even after a noreturn call. Using --no-trap-after-noreturn was previously
; known to break this.
define i32 @missing_ret_noreturn_unreachable() {
majaha marked this conversation as resolved.
Show resolved Hide resolved
; 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
}
Loading