[llvm] 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:50 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