diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -15,7 +15,7 @@ #include "WebAssembly.h" #include "WebAssemblySubtarget.h" #include "WebAssemblyUtilities.h" -#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/WasmEHFuncInfo.h" #include "llvm/MC/MCAsmInfo.h" @@ -32,6 +32,7 @@ } bool runOnMachineFunction(MachineFunction &MF) override; + bool removeUnreachableEHPads(MachineFunction &MF); void recordCatchRetBBs(MachineFunction &MF); bool hoistCatches(MachineFunction &MF); bool addCatchAlls(MachineFunction &MF); @@ -40,7 +41,7 @@ bool restoreStackPointer(MachineFunction &MF); MachineBasicBlock *getMatchingEHPad(MachineInstr *MI); - SmallSet CatchRetBBs; + SmallPtrSet CatchRetBBs; public: static char ID; // Pass identification, replacement for typeid @@ -94,14 +95,18 @@ template static void eraseDeadBBsAndChildren(const Container &MBBs) { SmallVector WL(MBBs.begin(), MBBs.end()); + SmallPtrSet Deleted; while (!WL.empty()) { MachineBasicBlock *MBB = WL.pop_back_val(); - if (!MBB->pred_empty()) + if (Deleted.count(MBB) || !MBB->pred_empty()) continue; SmallVector Succs(MBB->successors()); WL.append(MBB->succ_begin(), MBB->succ_end()); for (auto *Succ : Succs) MBB->removeSuccessor(Succ); + // To prevent deleting the same BB multiple times, which can happen when + // 'MBBs' contain both a parent and a child + Deleted.insert(MBB); MBB->eraseFromParent(); } } @@ -117,6 +122,7 @@ bool Changed = false; if (MF.getFunction().hasPersonalityFn()) { + Changed |= removeUnreachableEHPads(MF); recordCatchRetBBs(MF); Changed |= hoistCatches(MF); Changed |= addCatchAlls(MF); @@ -128,9 +134,20 @@ return Changed; } -// Record which BB ends with 'CATCHRET' instruction, because this will be -// replaced with BRs later. This set of 'CATCHRET' BBs is necessary in -// 'getMatchingEHPad' function. +// Remove unreachable EH pads and its children. If they remain, CFG +// stackification can be tricky. +bool WebAssemblyLateEHPrepare::removeUnreachableEHPads(MachineFunction &MF) { + SmallVector ToDelete; + for (auto &MBB : MF) + if (MBB.isEHPad() && MBB.pred_empty()) + ToDelete.push_back(&MBB); + eraseDeadBBsAndChildren(ToDelete); + return !ToDelete.empty(); +} + +// Record which BB ends with catchret instruction, because this will be replaced +// with 'br's later. This set of catchret BBs is necessary in 'getMatchingEHPad' +// function. void WebAssemblyLateEHPrepare::recordCatchRetBBs(MachineFunction &MF) { CatchRetBBs.clear(); for (auto &MBB : MF) { @@ -204,6 +221,8 @@ return Changed; } +// Replace pseudo-instructions catchret and cleanupret with br and rethrow +// respectively. bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) { bool Changed = false; const auto &TII = *MF.getSubtarget().getInstrInfo(); @@ -239,6 +258,7 @@ return Changed; } +// Remove unnecessary unreachables after a throw or rethrow. bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables( MachineFunction &MF) { bool Changed = false; diff --git a/llvm/test/CodeGen/WebAssembly/eh-labels.mir b/llvm/test/CodeGen/WebAssembly/exception.mir rename from llvm/test/CodeGen/WebAssembly/eh-labels.mir rename to llvm/test/CodeGen/WebAssembly/exception.mir --- a/llvm/test/CodeGen/WebAssembly/eh-labels.mir +++ b/llvm/test/CodeGen/WebAssembly/exception.mir @@ -1,7 +1,5 @@ # RUN: llc -mtriple=wasm32-unknown-unknown -exception-model=wasm -mattr=+exception-handling -run-pass wasm-late-eh-prepare -run-pass wasm-cfg-stackify %s -o - | FileCheck %s -# This tests 'try' and 'catch' instructions are correctly placed with respect to -# EH_LABEL instructions. --- | target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" @@ -11,10 +9,15 @@ define void @eh_label_test() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { ret void } + define void @unreachable_ehpad_test() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { + ret void + } ... --- -# CHECK-LABEL: eh_label_test +# This tests 'try' and 'catch' instructions are correctly placed with respect to +# EH_LABEL instructions. +# CHECK-LABEL: name: eh_label_test name: eh_label_test liveins: - { reg: '$arguments' } @@ -44,3 +47,27 @@ ; predecessors: %bb.0, %bb.1 RETURN implicit-def dead $arguments ... +--- +# Unreachable EH pads should be removed by LateEHPrepare. +# CHECK-LABEL: name: unreachable_ehpad_test +name: unreachable_ehpad_test +liveins: + - { reg: '$arguments' } +body: | + ; CHECK: bb.0 + bb.0: + successors: %bb.2 + BR %bb.2, implicit-def dead $arguments + + ; This EH pad is unreachable, so it should be removed by LateEHPrepare + ; CHECK-NOT: bb.1 (landing-pad) + bb.1 (landing-pad): + successors: %bb.2 + EH_LABEL + CATCHRET %bb.2, %bb.0, implicit-def dead $arguments + + ; CHECK: bb.2 + bb.2: + ; predecessors: %bb.0, %bb.1 + RETURN implicit-def dead $arguments +...