From c8ad813e9d5164ace9aa2178f912272762824e91 Mon Sep 17 00:00:00 2001 From: Matt Harding Date: Thu, 31 Aug 2023 22:55:50 +0100 Subject: [PATCH] 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 4a75bab6b95ddc..eb7d5b2cfd2a4b 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 6e2d566d9b4863..a573f0d86436e5 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 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 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 2f17746965fde3..38b8f543dffd97 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 bc1be793134969..f1ec71da1ebb64 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