diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h index 6c2da626ea54b4..8f1651c2958e59 100644 --- a/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/llvm/include/llvm/CodeGen/MachineFunction.h @@ -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; diff --git a/llvm/include/llvm/CodeGen/MachineInstr.h b/llvm/include/llvm/CodeGen/MachineInstr.h index 03fb15f77c65cb..8367f999fcc76d 100644 --- a/llvm/include/llvm/CodeGen/MachineInstr.h +++ b/llvm/include/llvm/CodeGen/MachineInstr.h @@ -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. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp index 131e99c66fa2e5..d8cbddf74545da 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -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 // ... diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 10464e8f52e561..88c727796e0dfd 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -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; // WebAssembly treats each function as an independent unit. Force // -ffunction-sections, effectively, so that we can emit them independently. diff --git a/llvm/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll index ad1c90090ac58b..72f865842bdcaa 100644 --- a/llvm/test/CodeGen/WebAssembly/unreachable.ll +++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll @@ -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 +}