[lld] Ensure NoTrapAfterNoreturn is false for the wasm backend (PR #65876)
Matt Harding via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 1 17:47:47 PDT 2023
https://github.com/majaha updated https://github.com/llvm/llvm-project/pull/65876
>From 7c43c803764bf9e0256d4e3e9f497d2622bb8f69 Mon Sep 17 00:00:00 2001
From: Matt Harding <majaharding at gmail.com>
Date: Fri, 25 Aug 2023 06:19:14 +0100
Subject: [PATCH 01/10] Add no-trap-after-noreturn flag and wasm tests
Add the command line flag --no-trap-after-noreturn.
Add and improve tests related to WebAssembly's unreachable instruction.
Also fix various typos.
---
llvm/include/llvm/CodeGen/MachineFunction.h | 2 +-
llvm/include/llvm/CodeGen/MachineInstr.h | 2 +-
llvm/lib/CodeGen/LLVMTargetMachine.cpp | 7 +
.../WebAssembly/WebAssemblyCFGStackify.cpp | 2 +-
llvm/test/CodeGen/WebAssembly/unreachable.ll | 178 +++++++++++++++---
5 files changed, 167 insertions(+), 24 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h
index 6c2da626ea54b4d..8f1651c2958e591 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 03fb15f77c65cbb..8367f999fcc76d3 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/CodeGen/LLVMTargetMachine.cpp b/llvm/lib/CodeGen/LLVMTargetMachine.cpp
index d02ec1db1165d41..aadc3709b85bfb7 100644
--- a/llvm/lib/CodeGen/LLVMTargetMachine.cpp
+++ b/llvm/lib/CodeGen/LLVMTargetMachine.cpp
@@ -37,6 +37,11 @@ static cl::opt<bool>
EnableTrapUnreachable("trap-unreachable", cl::Hidden,
cl::desc("Enable generating trap for unreachable"));
+static cl::opt<bool>
+ EnableNoTrapAfterNoreturn("no-trap-after-noreturn", cl::Hidden,
+ cl::desc("Do not emit a trap instruction for 'unreachable' IR instructions "
+ "after noreturn calls, even if --trap-unreachable is set."));
+
void LLVMTargetMachine::initAsmInfo() {
MRI.reset(TheTarget.createMCRegInfo(getTargetTriple().str()));
assert(MRI && "Unable to create reg info");
@@ -95,6 +100,8 @@ LLVMTargetMachine::LLVMTargetMachine(const Target &T,
if (EnableTrapUnreachable)
this->Options.TrapUnreachable = true;
+ if (EnableNoTrapAfterNoreturn)
+ this->Options.NoTrapAfterNoreturn = true;
}
TargetTransformInfo
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 131e99c66fa2e5a..d8cbddf74545da6 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/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll
index ad1c90090ac58bf..1bac30b842e1e05 100644
--- a/llvm/test/CodeGen/WebAssembly/unreachable.ll
+++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll
@@ -1,33 +1,169 @@
-; 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
-
-; Test that LLVM unreachable instruction and trap intrinsic are lowered to
-; wasm unreachable
+; RUN: llc < %s -verify-machineinstrs | FileCheck %s --check-prefixes CHECK,NORMAL
+; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs | FileCheck %s --check-prefixes CHECK,NORMAL
+; RUN: llc < %s -verify-machineinstrs --trap-unreachable | FileCheck %s --check-prefixes CHECK,NORMAL
+; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs --trap-unreachable | FileCheck %s --check-prefixes CHECK,NORMAL
+; RUN: llc < %s -verify-machineinstrs --trap-unreachable --no-trap-after-noreturn | FileCheck %s --check-prefixes CHECK,NTANR
+; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs --trap-unreachable --no-trap-after-noreturn | FileCheck %s --check-prefixes CHECK,FNTANR
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 @dtrap_ret_void() {
+; CHECK-LABEL: dtrap_ret_void:
+; CHECK: .functype dtrap_ret_void () -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: unreachable
+; CHECK-NEXT: # fallthrough-return
+; CHECK-NEXT: end_function
call void @llvm.debugtrap()
ret void
}
+
+; Test that LLVM trap followed by LLVM unreachable becomes exactly one wasm unreachable.
+define void @trap_unreach() {
+; NORMAL-LABEL: trap_unreach:
+; NORMAL: .functype trap_unreach () -> ()
+; NORMAL-NEXT: # %bb.0:
+; NORMAL-NEXT: unreachable
+; NORMAL-NEXT: unreachable
+; NORMAL-NEXT: end_function
+;
+; NTANR-LABEL: trap_unreach:
+; NTANR: .functype trap_unreach () -> ()
+; NTANR-NEXT: # %bb.0:
+; NTANR-NEXT: unreachable
+; NTANR-NEXT: end_function
+;
+; FNTANR-LABEL: trap_unreach:
+; FNTANR: .functype trap_unreach () -> ()
+; FNTANR-NEXT: # %bb.0:
+; FNTANR-NEXT: unreachable
+; FNTANR-NEXT: unreachable
+; FNTANR-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
+
+; This test emits wasm unreachable to fill in for the missing i32 return value.
+define i32 @missing_ret_unreach() {
+; CHECK-LABEL: missing_ret_unreach:
+; CHECK: .functype missing_ret_unreach () -> (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.
+define i32 @missing_ret_noreturn_unreach() {
+; NORMAL-LABEL: missing_ret_noreturn_unreach:
+; NORMAL: .functype missing_ret_noreturn_unreach () -> (i32)
+; NORMAL-NEXT: # %bb.0:
+; NORMAL-NEXT: call ext_never_return
+; NORMAL-NEXT: unreachable
+; NORMAL-NEXT: end_function
+;
+; NTANR-LABEL: missing_ret_noreturn_unreach:
+; NTANR: .functype missing_ret_noreturn_unreach () -> (i32)
+; NTANR-NEXT: # %bb.0:
+; NTANR-NEXT: call ext_never_return
+; NTANR-NEXT: end_function
+;
+; FNTANR-LABEL: missing_ret_noreturn_unreach:
+; FNTANR: .functype missing_ret_noreturn_unreach () -> (i32)
+; FNTANR-NEXT: # %bb.0:
+; FNTANR-NEXT: call ext_never_return
+; FNTANR-NEXT: unreachable
+; FNTANR-NEXT: end_function
+ call void @ext_never_return()
+ unreachable
+}
+
+; We could emit no instructions at all for the llvm unreachables in these next three tests, as the signatures match
+; and reaching llvm unreachable is undefined behaviour. But wasm unreachable is emitted for the time being.
+
+define void @void_sig_match_unreach() {
+; CHECK-LABEL: void_sig_match_unreach:
+; CHECK: .functype void_sig_match_unreach () -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: call ext_func
+; CHECK-NEXT: unreachable
+; CHECK-NEXT: end_function
+ call void @ext_func()
+ unreachable
+}
+
+define i32 @i32_sig_match_unreach() {
+; CHECK-LABEL: i32_sig_match_unreach:
+; CHECK: .functype i32_sig_match_unreach () -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: call ext_func_i32
+; CHECK-NEXT: drop
+; CHECK-NEXT: unreachable
+; CHECK-NEXT: end_function
+ call i32 @ext_func_i32()
+ unreachable
+}
+
+define void @void_sig_match_noreturn_unreach() {
+; NORMAL-LABEL: void_sig_match_noreturn_unreach:
+; NORMAL: .functype void_sig_match_noreturn_unreach () -> ()
+; NORMAL-NEXT: # %bb.0:
+; NORMAL-NEXT: call ext_never_return
+; NORMAL-NEXT: unreachable
+; NORMAL-NEXT: end_function
+;
+; NTANR-LABEL: void_sig_match_noreturn_unreach:
+; NTANR: .functype void_sig_match_noreturn_unreach () -> ()
+; NTANR-NEXT: # %bb.0:
+; NTANR-NEXT: call ext_never_return
+; NTANR-NEXT: end_function
+;
+; FNTANR-LABEL: void_sig_match_noreturn_unreach:
+; FNTANR: .functype void_sig_match_noreturn_unreach () -> ()
+; FNTANR-NEXT: # %bb.0:
+; FNTANR-NEXT: call ext_never_return
+; FNTANR-NEXT: unreachable
+; FNTANR-NEXT: end_function
+ call void @ext_never_return()
+ unreachable
+}
+
+; This function currently doesn't emit unreachable.
+define void @void_sig_match_noreturn_ret() {
+; CHECK-LABEL: void_sig_match_noreturn_ret:
+; CHECK: .functype void_sig_match_noreturn_ret () -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: call ext_never_return
+; CHECK-NEXT: # fallthrough-return
+; CHECK-NEXT: end_function
+ call void @ext_never_return()
+ ret void
+}
>From 7e834694b09e6a7787674879442b5f0d0c92eb22 Mon Sep 17 00:00:00 2001
From: Matt Harding <majaharding at gmail.com>
Date: Mon, 28 Aug 2023 18:47:44 +0100
Subject: [PATCH 02/10] Ensure NoTrapAfterNoreturn is false for wasm
---
.../WebAssembly/WebAssemblyTargetMachine.cpp | 1 +
llvm/test/CodeGen/WebAssembly/unreachable.ll | 87 +++++--------------
2 files changed, 25 insertions(+), 63 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index f8a4b95a95515e4..184910ae68f15e6 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 1bac30b842e1e05..2f17746965fde3f 100644
--- a/llvm/test/CodeGen/WebAssembly/unreachable.ll
+++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll
@@ -1,9 +1,9 @@
-; RUN: llc < %s -verify-machineinstrs | FileCheck %s --check-prefixes CHECK,NORMAL
-; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs | FileCheck %s --check-prefixes CHECK,NORMAL
-; RUN: llc < %s -verify-machineinstrs --trap-unreachable | FileCheck %s --check-prefixes CHECK,NORMAL
-; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs --trap-unreachable | FileCheck %s --check-prefixes CHECK,NORMAL
-; RUN: llc < %s -verify-machineinstrs --trap-unreachable --no-trap-after-noreturn | FileCheck %s --check-prefixes CHECK,NTANR
-; RUN: llc < %s -fast-isel -fast-isel-abort=1 -verify-machineinstrs --trap-unreachable --no-trap-after-noreturn | FileCheck %s --check-prefixes CHECK,FNTANR
+; 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"
@@ -37,25 +37,12 @@ define void @dtrap_ret_void() {
; Test that LLVM trap followed by LLVM unreachable becomes exactly one wasm unreachable.
define void @trap_unreach() {
-; NORMAL-LABEL: trap_unreach:
-; NORMAL: .functype trap_unreach () -> ()
-; NORMAL-NEXT: # %bb.0:
-; NORMAL-NEXT: unreachable
-; NORMAL-NEXT: unreachable
-; NORMAL-NEXT: end_function
-;
-; NTANR-LABEL: trap_unreach:
-; NTANR: .functype trap_unreach () -> ()
-; NTANR-NEXT: # %bb.0:
-; NTANR-NEXT: unreachable
-; NTANR-NEXT: end_function
-;
-; FNTANR-LABEL: trap_unreach:
-; FNTANR: .functype trap_unreach () -> ()
-; FNTANR-NEXT: # %bb.0:
-; FNTANR-NEXT: unreachable
-; FNTANR-NEXT: unreachable
-; FNTANR-NEXT: end_function
+; CHECK-LABEL: trap_unreach:
+; CHECK: .functype trap_unreach () -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: unreachable
+; CHECK-NEXT: unreachable
+; CHECK-NEXT: end_function
call void @llvm.trap()
unreachable
}
@@ -83,25 +70,12 @@ define i32 @missing_ret_unreach() {
; This is similar to the above test, but ensures wasm unreachable is emitted even
; after a noreturn call.
define i32 @missing_ret_noreturn_unreach() {
-; NORMAL-LABEL: missing_ret_noreturn_unreach:
-; NORMAL: .functype missing_ret_noreturn_unreach () -> (i32)
-; NORMAL-NEXT: # %bb.0:
-; NORMAL-NEXT: call ext_never_return
-; NORMAL-NEXT: unreachable
-; NORMAL-NEXT: end_function
-;
-; NTANR-LABEL: missing_ret_noreturn_unreach:
-; NTANR: .functype missing_ret_noreturn_unreach () -> (i32)
-; NTANR-NEXT: # %bb.0:
-; NTANR-NEXT: call ext_never_return
-; NTANR-NEXT: end_function
-;
-; FNTANR-LABEL: missing_ret_noreturn_unreach:
-; FNTANR: .functype missing_ret_noreturn_unreach () -> (i32)
-; FNTANR-NEXT: # %bb.0:
-; FNTANR-NEXT: call ext_never_return
-; FNTANR-NEXT: unreachable
-; FNTANR-NEXT: end_function
+; CHECK-LABEL: missing_ret_noreturn_unreach:
+; CHECK: .functype missing_ret_noreturn_unreach () -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: call ext_never_return
+; CHECK-NEXT: unreachable
+; CHECK-NEXT: end_function
call void @ext_never_return()
unreachable
}
@@ -133,25 +107,12 @@ define i32 @i32_sig_match_unreach() {
}
define void @void_sig_match_noreturn_unreach() {
-; NORMAL-LABEL: void_sig_match_noreturn_unreach:
-; NORMAL: .functype void_sig_match_noreturn_unreach () -> ()
-; NORMAL-NEXT: # %bb.0:
-; NORMAL-NEXT: call ext_never_return
-; NORMAL-NEXT: unreachable
-; NORMAL-NEXT: end_function
-;
-; NTANR-LABEL: void_sig_match_noreturn_unreach:
-; NTANR: .functype void_sig_match_noreturn_unreach () -> ()
-; NTANR-NEXT: # %bb.0:
-; NTANR-NEXT: call ext_never_return
-; NTANR-NEXT: end_function
-;
-; FNTANR-LABEL: void_sig_match_noreturn_unreach:
-; FNTANR: .functype void_sig_match_noreturn_unreach () -> ()
-; FNTANR-NEXT: # %bb.0:
-; FNTANR-NEXT: call ext_never_return
-; FNTANR-NEXT: unreachable
-; FNTANR-NEXT: end_function
+; CHECK-LABEL: void_sig_match_noreturn_unreach:
+; CHECK: .functype void_sig_match_noreturn_unreach () -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: call ext_never_return
+; CHECK-NEXT: unreachable
+; CHECK-NEXT: end_function
call void @ext_never_return()
unreachable
}
>From c8ad813e9d5164ace9aa2178f912272762824e91 Mon Sep 17 00:00:00 2001
From: Matt Harding <majaharding at gmail.com>
Date: Thu, 31 Aug 2023 22:55:50 +0100
Subject: [PATCH 03/10] Add peephole optimisation
---
.../WebAssembly/WebAssemblyDebugFixup.cpp | 11 ++++
.../WebAssembly/WebAssemblyPeephole.cpp | 51 +++++++++++++++++++
llvm/test/CodeGen/WebAssembly/unreachable.ll | 2 -
llvm/test/MC/WebAssembly/global-ctor-dtor.ll | 12 ++---
4 files changed, 68 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp
index 4a75bab6b95ddcd..eb7d5b2cfd2a4b3 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp
@@ -122,9 +122,20 @@ bool WebAssemblyDebugFixup::runOnMachineFunction(MachineFunction &MF) {
// it will be culled later.
}
} else {
+
+ // WebAssembly Peephole optimisation can remove instructions around wasm unreachable.
+ // This is valid for wasm, as unreachable is operand stack polymorphic. But this is not modeled
+ // in llvm at the moment, and so the stack may not seem to pop all that it pushes.
+ // Clear the stack so we don't violate the assert(Stack.empty()) later on.
+ if (MI.getOpcode() == WebAssembly::UNREACHABLE) {
+ Stack.clear();
+ break;
+ }
+
// Track stack depth.
for (MachineOperand &MO : reverse(MI.explicit_uses())) {
if (MO.isReg() && MFI.isVRegStackified(MO.getReg())) {
+ assert(Stack.size() != 0 && "WebAssemblyDebugFixup: Pop: Operand stack empty!");
auto Prev = Stack.back();
Stack.pop_back();
assert(Prev.Reg == MO.getReg() &&
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
index 6e2d566d9b48630..a573f0d86436e58 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
@@ -20,6 +20,7 @@
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include <iterator>
using namespace llvm;
#define DEBUG_TYPE "wasm-peephole"
@@ -109,6 +110,53 @@ static bool maybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB,
return true;
}
+static bool eraseDeadCodeAroundUnreachable(MachineInstr &UnreachbleMI, MachineBasicBlock &MBB) {
+ SmallVector<MachineInstr*, 16> ToDelete;
+
+ // Because wasm unreachable is stack polymorphic and unconditionally ends control,
+ // all instructions after it can be removed until the end of this block.
+ // We remove the common case of double unreachable.
+ auto ForwardsIterator = UnreachbleMI.getIterator();
+ for (ForwardsIterator++; !ForwardsIterator.isEnd(); ForwardsIterator++) {
+ MachineInstr& MI = *ForwardsIterator;
+ if (MI.getOpcode() == WebAssembly::UNREACHABLE) {
+ ToDelete.push_back(&MI);
+ } else {
+ break;
+ }
+ }
+
+ [&]() {
+ // For the same reasons as above, previous instructions that only affect
+ // local function state can be removed (e.g. local.set, drop, various reads).
+ // We remove the common case of "drop unreachable".
+ auto BackwardsIterator = UnreachbleMI.getReverseIterator();
+ for (BackwardsIterator++; !BackwardsIterator.isEnd(); BackwardsIterator++) {
+ MachineInstr& MI = *BackwardsIterator;
+ switch(MI.getOpcode()) {
+ case WebAssembly::DROP_I32:
+ case WebAssembly::DROP_I64:
+ case WebAssembly::DROP_F32:
+ case WebAssembly::DROP_F64:
+ case WebAssembly::DROP_EXTERNREF:
+ case WebAssembly::DROP_FUNCREF:
+ case WebAssembly::DROP_V128:
+ ToDelete.push_back(&MI);
+ continue;
+ default:
+ return;
+ }
+ }
+ }();
+
+ bool Changed = false;
+ for (MachineInstr* MI : ToDelete) {
+ MI->eraseFromParent();
+ Changed = true;
+ }
+ return Changed;
+}
+
bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
LLVM_DEBUG({
dbgs() << "********** Peephole **********\n"
@@ -159,6 +207,9 @@ bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
case WebAssembly::RETURN:
Changed |= maybeRewriteToFallthrough(MI, MBB, MF, MFI, MRI, TII);
break;
+ case WebAssembly::UNREACHABLE:
+ Changed |= eraseDeadCodeAroundUnreachable(MI, MBB);
+ break;
}
return Changed;
diff --git a/llvm/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll
index 2f17746965fde3f..38b8f543dffd972 100644
--- a/llvm/test/CodeGen/WebAssembly/unreachable.ll
+++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll
@@ -41,7 +41,6 @@ define void @trap_unreach() {
; CHECK: .functype trap_unreach () -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: unreachable
-; CHECK-NEXT: unreachable
; CHECK-NEXT: end_function
call void @llvm.trap()
unreachable
@@ -99,7 +98,6 @@ define i32 @i32_sig_match_unreach() {
; CHECK: .functype i32_sig_match_unreach () -> (i32)
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call ext_func_i32
-; CHECK-NEXT: drop
; CHECK-NEXT: unreachable
; CHECK-NEXT: end_function
call i32 @ext_func_i32()
diff --git a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll
index bc1be7931349697..f1ec71da1ebb641 100644
--- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll
+++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll
@@ -80,29 +80,29 @@ declare void @func3()
; CHECK-NEXT: Offset: 0x1D
; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB
; CHECK-NEXT: Index: 6
-; CHECK-NEXT: Offset: 0x2C
+; CHECK-NEXT: Offset: 0x2B
; CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB
; CHECK-NEXT: Index: 5
-; CHECK-NEXT: Offset: 0x37
+; CHECK-NEXT: Offset: 0x36
; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB
; CHECK-NEXT: Index: 3
-; CHECK-NEXT: Offset: 0x3F
+; CHECK-NEXT: Offset: 0x3E
; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB
; CHECK-NEXT: Index: 4
-; CHECK-NEXT: Offset: 0x45
+; CHECK-NEXT: Offset: 0x44
; CHECK-NEXT: Functions:
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 1080808080000B
; CHECK-NEXT: - Index: 6
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 02404181808080004100418080808000108180808000450D0000000B0B
+; CHECK-NEXT: Body: 02404181808080004100418080808000108180808000450D00000B0B
; CHECK-NEXT: - Index: 7
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 1082808080000B
; CHECK-NEXT: - Index: 8
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 02404182808080004100418080808000108180808000450D0000000B0B
+; CHECK-NEXT: Body: 02404182808080004100418080808000108180808000450D00000B0B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 6
>From 219c19482e38d224d03a16b11cb23a47e2d110d3 Mon Sep 17 00:00:00 2001
From: Matt Harding <majaharding at gmail.com>
Date: Sun, 10 Sep 2023 08:58:50 +0100
Subject: [PATCH 04/10] Fix broken lld wasm test
The new peephole optimisation removed an unreachable in this test.
---
lld/test/wasm/init-fini.ll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lld/test/wasm/init-fini.ll b/lld/test/wasm/init-fini.ll
index 14385f042efb7c2..35286bbcccc2f54 100644
--- a/lld/test/wasm/init-fini.ll
+++ b/lld/test/wasm/init-fini.ll
@@ -77,7 +77,7 @@ entry:
; CHECK-NEXT: Body: 10031004100A100F1012100F10141003100C100F10161001100E0B
; CHECK: - Index: 22
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 02404186808080004100418088808000108780808000450D0000000B0B
+; CHECK-NEXT: Body: 02404186808080004100418088808000108780808000450D00000B0B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
>From 91d5986d3421968c9ef99bf9430d0a30dc49ade6 Mon Sep 17 00:00:00 2001
From: Matt Harding <majaharding at gmail.com>
Date: Tue, 12 Sep 2023 00:38:32 +0100
Subject: [PATCH 05/10] Revert "Fix broken lld wasm test"
This reverts commit 219c19482e38d224d03a16b11cb23a47e2d110d3.
---
lld/test/wasm/init-fini.ll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lld/test/wasm/init-fini.ll b/lld/test/wasm/init-fini.ll
index 35286bbcccc2f54..14385f042efb7c2 100644
--- a/lld/test/wasm/init-fini.ll
+++ b/lld/test/wasm/init-fini.ll
@@ -77,7 +77,7 @@ entry:
; CHECK-NEXT: Body: 10031004100A100F1012100F10141003100C100F10161001100E0B
; CHECK: - Index: 22
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 02404186808080004100418088808000108780808000450D00000B0B
+; CHECK-NEXT: Body: 02404186808080004100418088808000108780808000450D0000000B0B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
>From d2b5701024fed92044b94bd545caabdc1e57f3a3 Mon Sep 17 00:00:00 2001
From: Matt Harding <majaharding at gmail.com>
Date: Tue, 12 Sep 2023 00:38:40 +0100
Subject: [PATCH 06/10] Revert "Add peephole optimisation"
This reverts commit c8ad813e9d5164ace9aa2178f912272762824e91.
---
.../WebAssembly/WebAssemblyDebugFixup.cpp | 11 ----
.../WebAssembly/WebAssemblyPeephole.cpp | 51 -------------------
llvm/test/CodeGen/WebAssembly/unreachable.ll | 2 +
llvm/test/MC/WebAssembly/global-ctor-dtor.ll | 12 ++---
4 files changed, 8 insertions(+), 68 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp
index eb7d5b2cfd2a4b3..4a75bab6b95ddcd 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyDebugFixup.cpp
@@ -122,20 +122,9 @@ bool WebAssemblyDebugFixup::runOnMachineFunction(MachineFunction &MF) {
// it will be culled later.
}
} else {
-
- // WebAssembly Peephole optimisation can remove instructions around wasm unreachable.
- // This is valid for wasm, as unreachable is operand stack polymorphic. But this is not modeled
- // in llvm at the moment, and so the stack may not seem to pop all that it pushes.
- // Clear the stack so we don't violate the assert(Stack.empty()) later on.
- if (MI.getOpcode() == WebAssembly::UNREACHABLE) {
- Stack.clear();
- break;
- }
-
// Track stack depth.
for (MachineOperand &MO : reverse(MI.explicit_uses())) {
if (MO.isReg() && MFI.isVRegStackified(MO.getReg())) {
- assert(Stack.size() != 0 && "WebAssemblyDebugFixup: Pop: Operand stack empty!");
auto Prev = Stack.back();
Stack.pop_back();
assert(Prev.Reg == MO.getReg() &&
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
index a573f0d86436e58..6e2d566d9b48630 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
@@ -20,7 +20,6 @@
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include <iterator>
using namespace llvm;
#define DEBUG_TYPE "wasm-peephole"
@@ -110,53 +109,6 @@ static bool maybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB,
return true;
}
-static bool eraseDeadCodeAroundUnreachable(MachineInstr &UnreachbleMI, MachineBasicBlock &MBB) {
- SmallVector<MachineInstr*, 16> ToDelete;
-
- // Because wasm unreachable is stack polymorphic and unconditionally ends control,
- // all instructions after it can be removed until the end of this block.
- // We remove the common case of double unreachable.
- auto ForwardsIterator = UnreachbleMI.getIterator();
- for (ForwardsIterator++; !ForwardsIterator.isEnd(); ForwardsIterator++) {
- MachineInstr& MI = *ForwardsIterator;
- if (MI.getOpcode() == WebAssembly::UNREACHABLE) {
- ToDelete.push_back(&MI);
- } else {
- break;
- }
- }
-
- [&]() {
- // For the same reasons as above, previous instructions that only affect
- // local function state can be removed (e.g. local.set, drop, various reads).
- // We remove the common case of "drop unreachable".
- auto BackwardsIterator = UnreachbleMI.getReverseIterator();
- for (BackwardsIterator++; !BackwardsIterator.isEnd(); BackwardsIterator++) {
- MachineInstr& MI = *BackwardsIterator;
- switch(MI.getOpcode()) {
- case WebAssembly::DROP_I32:
- case WebAssembly::DROP_I64:
- case WebAssembly::DROP_F32:
- case WebAssembly::DROP_F64:
- case WebAssembly::DROP_EXTERNREF:
- case WebAssembly::DROP_FUNCREF:
- case WebAssembly::DROP_V128:
- ToDelete.push_back(&MI);
- continue;
- default:
- return;
- }
- }
- }();
-
- bool Changed = false;
- for (MachineInstr* MI : ToDelete) {
- MI->eraseFromParent();
- Changed = true;
- }
- return Changed;
-}
-
bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
LLVM_DEBUG({
dbgs() << "********** Peephole **********\n"
@@ -207,9 +159,6 @@ bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) {
case WebAssembly::RETURN:
Changed |= maybeRewriteToFallthrough(MI, MBB, MF, MFI, MRI, TII);
break;
- case WebAssembly::UNREACHABLE:
- Changed |= eraseDeadCodeAroundUnreachable(MI, MBB);
- break;
}
return Changed;
diff --git a/llvm/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll
index 38b8f543dffd972..2f17746965fde3f 100644
--- a/llvm/test/CodeGen/WebAssembly/unreachable.ll
+++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll
@@ -41,6 +41,7 @@ define void @trap_unreach() {
; CHECK: .functype trap_unreach () -> ()
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: unreachable
+; CHECK-NEXT: unreachable
; CHECK-NEXT: end_function
call void @llvm.trap()
unreachable
@@ -98,6 +99,7 @@ define i32 @i32_sig_match_unreach() {
; CHECK: .functype i32_sig_match_unreach () -> (i32)
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call ext_func_i32
+; CHECK-NEXT: drop
; CHECK-NEXT: unreachable
; CHECK-NEXT: end_function
call i32 @ext_func_i32()
diff --git a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll
index f1ec71da1ebb641..bc1be7931349697 100644
--- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll
+++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll
@@ -80,29 +80,29 @@ declare void @func3()
; CHECK-NEXT: Offset: 0x1D
; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB
; CHECK-NEXT: Index: 6
-; CHECK-NEXT: Offset: 0x2B
+; CHECK-NEXT: Offset: 0x2C
; CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB
; CHECK-NEXT: Index: 5
-; CHECK-NEXT: Offset: 0x36
+; CHECK-NEXT: Offset: 0x37
; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB
; CHECK-NEXT: Index: 3
-; CHECK-NEXT: Offset: 0x3E
+; CHECK-NEXT: Offset: 0x3F
; CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB
; CHECK-NEXT: Index: 4
-; CHECK-NEXT: Offset: 0x44
+; CHECK-NEXT: Offset: 0x45
; CHECK-NEXT: Functions:
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 1080808080000B
; CHECK-NEXT: - Index: 6
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 02404181808080004100418080808000108180808000450D00000B0B
+; CHECK-NEXT: Body: 02404181808080004100418080808000108180808000450D0000000B0B
; CHECK-NEXT: - Index: 7
; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 1082808080000B
; CHECK-NEXT: - Index: 8
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 02404182808080004100418080808000108180808000450D00000B0B
+; CHECK-NEXT: Body: 02404182808080004100418080808000108180808000450D0000000B0B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
; CHECK-NEXT: - SectionOffset: 6
>From 05d0c17d424f10d702ccc9ce5db94dc5597758f7 Mon Sep 17 00:00:00 2001
From: Matt Harding <majaharding at gmail.com>
Date: Tue, 12 Sep 2023 00:46:59 +0100
Subject: [PATCH 07/10] Run clang-format
---
llvm/lib/CodeGen/LLVMTargetMachine.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/CodeGen/LLVMTargetMachine.cpp b/llvm/lib/CodeGen/LLVMTargetMachine.cpp
index aadc3709b85bfb7..59ff0ec9a38fafb 100644
--- a/llvm/lib/CodeGen/LLVMTargetMachine.cpp
+++ b/llvm/lib/CodeGen/LLVMTargetMachine.cpp
@@ -37,10 +37,10 @@ static cl::opt<bool>
EnableTrapUnreachable("trap-unreachable", cl::Hidden,
cl::desc("Enable generating trap for unreachable"));
-static cl::opt<bool>
- EnableNoTrapAfterNoreturn("no-trap-after-noreturn", cl::Hidden,
- cl::desc("Do not emit a trap instruction for 'unreachable' IR instructions "
- "after noreturn calls, even if --trap-unreachable is set."));
+static cl::opt<bool> EnableNoTrapAfterNoreturn(
+ "no-trap-after-noreturn", cl::Hidden,
+ cl::desc("Do not emit a trap instruction for 'unreachable' IR instructions "
+ "after noreturn calls, even if --trap-unreachable is set."));
void LLVMTargetMachine::initAsmInfo() {
MRI.reset(TheTarget.createMCRegInfo(getTargetTriple().str()));
>From 35f61031e38b76fb1edbbd9d66a0f678e68d4531 Mon Sep 17 00:00:00 2001
From: Matt Harding <majaharding at gmail.com>
Date: Sat, 23 Sep 2023 23:49:44 +0100
Subject: [PATCH 08/10] Fix test comments
---
llvm/test/CodeGen/WebAssembly/unreachable.ll | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/llvm/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll
index 2f17746965fde3f..605aa1b0970a0fd 100644
--- a/llvm/test/CodeGen/WebAssembly/unreachable.ll
+++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll
@@ -8,7 +8,8 @@
target triple = "wasm32-unknown-unknown"
-; Test that the LLVM trap and debug trap intrinsics are lowered to wasm 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
@@ -35,7 +36,8 @@ define void @dtrap_ret_void() {
ret void
}
-; Test that LLVM trap followed by LLVM unreachable becomes exactly one wasm unreachable.
+; LLVM trap followed by LLVM unreachable could become exactly one
+; wasm unreachable, but two are emitted currently.
define void @trap_unreach() {
; CHECK-LABEL: trap_unreach:
; CHECK: .functype trap_unreach () -> ()
@@ -48,8 +50,8 @@ define void @trap_unreach() {
}
-; Test that LLVM unreachable instruction is lowered to wasm unreachable when necessary
-; to fulfill the wasm operand stack requirements.
+; 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()
@@ -67,8 +69,8 @@ define i32 @missing_ret_unreach() {
unreachable
}
-; This is similar to the above test, but ensures wasm unreachable is emitted even
-; after a noreturn call.
+; This is similar to the above test, but ensures wasm unreachable is emitted
+; even after a noreturn call.
define i32 @missing_ret_noreturn_unreach() {
; CHECK-LABEL: missing_ret_noreturn_unreach:
; CHECK: .functype missing_ret_noreturn_unreach () -> (i32)
@@ -80,8 +82,9 @@ define i32 @missing_ret_noreturn_unreach() {
unreachable
}
-; We could emit no instructions at all for the llvm unreachables in these next three tests, as the signatures match
-; and reaching llvm unreachable is undefined behaviour. But wasm unreachable is emitted for the time being.
+; We could emit no instructions at all for the llvm unreachables in these next
+; three tests, as the signatures match and reaching llvm unreachable is
+; undefined behaviour. But wasm unreachable is emitted for the time being.
define void @void_sig_match_unreach() {
; CHECK-LABEL: void_sig_match_unreach:
>From 3cb13e555f26f2a06528f22c4ad7e74d28be2b95 Mon Sep 17 00:00:00 2001
From: Matt Harding <majaharding at gmail.com>
Date: Mon, 2 Oct 2023 01:07:57 +0100
Subject: [PATCH 09/10] Apply formatting and naming changes from code review
Co-authored-by: Heejin Ahn <aheejin at gmail.com>
---
llvm/test/CodeGen/WebAssembly/unreachable.ll | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/llvm/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll
index 605aa1b0970a0fd..a354c7bc493b548 100644
--- a/llvm/test/CodeGen/WebAssembly/unreachable.ll
+++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll
@@ -8,8 +8,8 @@
target triple = "wasm32-unknown-unknown"
-; Test that the LLVM trap and debug trap intrinsics are lowered to
-; wasm 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
@@ -25,9 +25,9 @@ define void @trap_ret_void() {
ret void
}
-define void @dtrap_ret_void() {
-; CHECK-LABEL: dtrap_ret_void:
-; CHECK: .functype dtrap_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
@@ -36,11 +36,11 @@ define void @dtrap_ret_void() {
ret void
}
-; LLVM trap followed by LLVM unreachable could become exactly one
-; wasm unreachable, but two are emitted currently.
-define void @trap_unreach() {
-; CHECK-LABEL: trap_unreach:
-; CHECK: .functype trap_unreach () -> ()
+; 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
>From 039383693bd58dc970810e632102d01fdfa5a507 Mon Sep 17 00:00:00 2001
From: Matt Harding <majaharding at gmail.com>
Date: Mon, 2 Oct 2023 01:47:17 +0100
Subject: [PATCH 10/10] Improve explanation in unreachable.ll test
---
llvm/test/CodeGen/WebAssembly/unreachable.ll | 24 +++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/llvm/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll
index a354c7bc493b548..d5e02c1dd1154f5 100644
--- a/llvm/test/CodeGen/WebAssembly/unreachable.ll
+++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll
@@ -1,3 +1,17 @@
+; The assertions in this file were autogenerated by
+; utils/update_llc_test_checks.py, but were hand-edited to add the
+; "CHECK-NEXT: 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.
+
+
+; --trap-unreachable and --no-trap-after-noreturn are sensitive and bug-prone
+; options for the WebAssembly back-end as, unlike in many other target
+; architechtures, unreachable code being compiled to a trap instruction (i.e.
+; WebAssembly "unreachable" instruction) is often necessary for the code to
+; pass wasm's validation step. We test that various combinations of
+; these options produce the expected output.
; 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
@@ -57,7 +71,8 @@ declare void @ext_func()
declare i32 @ext_func_i32()
declare void @ext_never_return() noreturn
-; This test emits wasm unreachable to fill in for the missing i32 return value.
+; This test emits wasm unreachable to fill in for the missing i32 return value,
+; which is necessary for the function to pass wasm validation.
define i32 @missing_ret_unreach() {
; CHECK-LABEL: missing_ret_unreach:
; CHECK: .functype missing_ret_unreach () -> (i32)
@@ -84,7 +99,7 @@ define i32 @missing_ret_noreturn_unreach() {
; We could emit no instructions at all for the llvm unreachables in these next
; three tests, as the signatures match and reaching llvm unreachable is
-; undefined behaviour. But wasm unreachable is emitted for the time being.
+; undefined behaviour. But currently, wasm unreachable is emitted for them.
define void @void_sig_match_unreach() {
; CHECK-LABEL: void_sig_match_unreach:
@@ -120,7 +135,10 @@ define void @void_sig_match_noreturn_unreach() {
unreachable
}
-; This function currently doesn't emit unreachable.
+; This function currently doesn't emit wasm unreachable, even though the final
+; "ret void" instruction is dead code and could be replaced with an llvm
+; unreachable. Compare and contrast with the above function,
+; @void_sig_match_noreturn_unreach().
define void @void_sig_match_noreturn_ret() {
; CHECK-LABEL: void_sig_match_noreturn_ret:
; CHECK: .functype void_sig_match_noreturn_ret () -> ()
More information about the llvm-commits
mailing list