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 <majahard...@gmail.com> Date: Fri, 25 Aug 2023 06:19:14 +0100 Subject: [PATCH 01/13] 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 <majahard...@gmail.com> Date: Mon, 28 Aug 2023 18:47:44 +0100 Subject: [PATCH 02/13] 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 <majahard...@gmail.com> Date: Thu, 31 Aug 2023 22:55:50 +0100 Subject: [PATCH 03/13] 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 <majahard...@gmail.com> Date: Sun, 10 Sep 2023 08:58:50 +0100 Subject: [PATCH 04/13] 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 <majahard...@gmail.com> Date: Tue, 12 Sep 2023 00:38:32 +0100 Subject: [PATCH 05/13] 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 <majahard...@gmail.com> Date: Tue, 12 Sep 2023 00:38:40 +0100 Subject: [PATCH 06/13] 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 <majahard...@gmail.com> Date: Tue, 12 Sep 2023 00:46:59 +0100 Subject: [PATCH 07/13] 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 <majahard...@gmail.com> Date: Sat, 23 Sep 2023 23:49:44 +0100 Subject: [PATCH 08/13] 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 <majahard...@gmail.com> Date: Mon, 2 Oct 2023 01:07:57 +0100 Subject: [PATCH 09/13] Apply formatting and naming changes from code review Co-authored-by: Heejin Ahn <ahee...@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 <majahard...@gmail.com> Date: Mon, 2 Oct 2023 01:47:17 +0100 Subject: [PATCH 10/13] 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 () -> () >From c210e9a5632443d2bef7928a6df2202ee469aab4 Mon Sep 17 00:00:00 2001 From: Matt Harding <majahard...@gmail.com> Date: Mon, 2 Oct 2023 16:27:01 +0100 Subject: [PATCH 11/13] Remove unintended "CHECK-NEXT" line --- llvm/test/CodeGen/WebAssembly/unreachable.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll index d5e02c1dd1154f5..c969486ed9c36df 100644 --- a/llvm/test/CodeGen/WebAssembly/unreachable.ll +++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll @@ -1,6 +1,6 @@ ; 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 +; "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. >From f0b5809f8b5a51251834a5a3eaa2d22406bb9075 Mon Sep 17 00:00:00 2001 From: Matt Harding <majahard...@gmail.com> Date: Wed, 4 Oct 2023 22:30:00 +0100 Subject: [PATCH 12/13] Expand "unreach" -> "unreachable" --- llvm/test/CodeGen/WebAssembly/unreachable.ll | 32 ++++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/llvm/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll index c969486ed9c36df..53e468d56f46cca 100644 --- a/llvm/test/CodeGen/WebAssembly/unreachable.ll +++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll @@ -73,9 +73,9 @@ declare void @ext_never_return() noreturn ; 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) +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 @@ -86,9 +86,9 @@ 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() { -; CHECK-LABEL: missing_ret_noreturn_unreach: -; CHECK: .functype missing_ret_noreturn_unreach () -> (i32) +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 @@ -101,9 +101,9 @@ define i32 @missing_ret_noreturn_unreach() { ; three tests, as the signatures match and reaching llvm unreachable is ; undefined behaviour. But currently, wasm unreachable is emitted for them. -define void @void_sig_match_unreach() { -; CHECK-LABEL: void_sig_match_unreach: -; CHECK: .functype void_sig_match_unreach () -> () +define void @void_sig_match_unreachable() { +; CHECK-LABEL: void_sig_match_unreachable: +; CHECK: .functype void_sig_match_unreachable () -> () ; CHECK-NEXT: # %bb.0: ; CHECK-NEXT: call ext_func ; CHECK-NEXT: unreachable @@ -112,9 +112,9 @@ define void @void_sig_match_unreach() { unreachable } -define i32 @i32_sig_match_unreach() { -; CHECK-LABEL: i32_sig_match_unreach: -; CHECK: .functype i32_sig_match_unreach () -> (i32) +define i32 @i32_sig_match_unreachable() { +; CHECK-LABEL: i32_sig_match_unreachable: +; CHECK: .functype i32_sig_match_unreachable () -> (i32) ; CHECK-NEXT: # %bb.0: ; CHECK-NEXT: call ext_func_i32 ; CHECK-NEXT: drop @@ -124,9 +124,9 @@ define i32 @i32_sig_match_unreach() { unreachable } -define void @void_sig_match_noreturn_unreach() { -; CHECK-LABEL: void_sig_match_noreturn_unreach: -; CHECK: .functype void_sig_match_noreturn_unreach () -> () +define void @void_sig_match_noreturn_unreachable() { +; CHECK-LABEL: void_sig_match_noreturn_unreachable: +; CHECK: .functype void_sig_match_noreturn_unreachable () -> () ; CHECK-NEXT: # %bb.0: ; CHECK-NEXT: call ext_never_return ; CHECK-NEXT: unreachable @@ -138,7 +138,7 @@ define void @void_sig_match_noreturn_unreach() { ; 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(). +; @void_sig_match_noreturn_unreachable(). define void @void_sig_match_noreturn_ret() { ; CHECK-LABEL: void_sig_match_noreturn_ret: ; CHECK: .functype void_sig_match_noreturn_ret () -> () >From b2d9080cf62d9d3ab514fd3bdc9115121603173d Mon Sep 17 00:00:00 2001 From: Matt Harding <majahard...@gmail.com> Date: Wed, 4 Oct 2023 23:49:18 +0100 Subject: [PATCH 13/13] Adresss comments --- llvm/test/CodeGen/WebAssembly/unreachable.ll | 70 ++------------------ 1 file changed, 7 insertions(+), 63 deletions(-) diff --git a/llvm/test/CodeGen/WebAssembly/unreachable.ll b/llvm/test/CodeGen/WebAssembly/unreachable.ll index 53e468d56f46cca..a5424b9e716fdfa 100644 --- a/llvm/test/CodeGen/WebAssembly/unreachable.ll +++ b/llvm/test/CodeGen/WebAssembly/unreachable.ll @@ -6,12 +6,8 @@ ; "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. +; The --trap-unreachable and --no-trap-after-noreturn options are ignored, and +; should have no effect. ; 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 @@ -71,8 +67,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, -; which is necessary for the function to pass wasm validation. +; The wasm unreachable in this test is necessary for the function to pass wasm +; validation. define i32 @missing_ret_unreachable() { ; CHECK-LABEL: missing_ret_unreachable: ; CHECK: .functype missing_ret_unreachable () -> (i32) @@ -85,7 +81,8 @@ define i32 @missing_ret_unreachable() { } ; This is similar to the above test, but ensures wasm unreachable is emitted -; even after a noreturn call. +; even after a noreturn call. Using --no-trap-after-noreturn was previously +; known to break this. define i32 @missing_ret_noreturn_unreachable() { ; CHECK-LABEL: missing_ret_noreturn_unreachable: ; CHECK: .functype missing_ret_noreturn_unreachable () -> (i32) @@ -95,57 +92,4 @@ define i32 @missing_ret_noreturn_unreachable() { ; CHECK-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 currently, wasm unreachable is emitted for them. - -define void @void_sig_match_unreachable() { -; CHECK-LABEL: void_sig_match_unreachable: -; CHECK: .functype void_sig_match_unreachable () -> () -; 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_unreachable() { -; CHECK-LABEL: i32_sig_match_unreachable: -; CHECK: .functype i32_sig_match_unreachable () -> (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_unreachable() { -; CHECK-LABEL: void_sig_match_noreturn_unreachable: -; CHECK: .functype void_sig_match_noreturn_unreachable () -> () -; CHECK-NEXT: # %bb.0: -; CHECK-NEXT: call ext_never_return -; CHECK-NEXT: unreachable -; CHECK-NEXT: end_function - call void @ext_never_return() - 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_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 -} +} \ No newline at end of file _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits