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 @@ -32,12 +32,16 @@ } bool runOnMachineFunction(MachineFunction &MF) override; + void recordCatchRetBBs(MachineFunction &MF); bool addCatches(MachineFunction &MF); bool replaceFuncletReturns(MachineFunction &MF); bool removeUnnecessaryUnreachables(MachineFunction &MF); bool addExceptionExtraction(MachineFunction &MF); bool restoreStackPointer(MachineFunction &MF); + MachineBasicBlock *getMatchingEHPad(MachineInstr *MI); + SmallSet CatchRetBBs; + public: static char ID; // Pass identification, replacement for typeid WebAssemblyLateEHPrepare() : MachineFunctionPass(ID) {} @@ -58,7 +62,8 @@ // possible search paths should be the same. // Returns nullptr in case it does not find any EH pad in the search, or finds // multiple different EH pads. -static MachineBasicBlock *getMatchingEHPad(MachineInstr *MI) { +MachineBasicBlock * +WebAssemblyLateEHPrepare::getMatchingEHPad(MachineInstr *MI) { MachineFunction *MF = MI->getParent()->getParent(); SmallVector WL; SmallPtrSet Visited; @@ -77,7 +82,9 @@ } if (MBB == &MF->front()) return nullptr; - WL.append(MBB->pred_begin(), MBB->pred_end()); + for (auto *Pred : MBB->predecessors()) + if (!CatchRetBBs.count(Pred)) // We don't go into child scopes + WL.push_back(Pred); } return EHPad; } @@ -111,6 +118,7 @@ bool Changed = false; if (MF.getFunction().hasPersonalityFn()) { + recordCatchRetBBs(MF); Changed |= addCatches(MF); Changed |= replaceFuncletReturns(MF); } @@ -122,6 +130,21 @@ 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. +void WebAssemblyLateEHPrepare::recordCatchRetBBs(MachineFunction &MF) { + CatchRetBBs.clear(); + for (auto &MBB : MF) { + auto Pos = MBB.getFirstTerminator(); + if (Pos == MBB.end()) + continue; + MachineInstr *TI = &*Pos; + if (TI->getOpcode() == WebAssembly::CATCHRET) + CatchRetBBs.insert(&MBB); + } +} + // Add catch instruction to beginning of catchpads and cleanuppads. bool WebAssemblyLateEHPrepare::addCatches(MachineFunction &MF) { bool Changed = false; diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll --- a/llvm/test/CodeGen/WebAssembly/exception.ll +++ b/llvm/test/CodeGen/WebAssembly/exception.ll @@ -74,7 +74,7 @@ call void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %1) ] unreachable -try.cont: ; preds = %entry, %catch +try.cont: ; preds = %catch, %entry ret void } @@ -169,7 +169,7 @@ call void @__cxa_end_catch() [ "funclet"(token %1) ] catchret from %1 to label %try.cont -try.cont: ; preds = %entry, %invoke.cont1 +try.cont: ; preds = %invoke.cont1, %entry ret void ehcleanup: ; preds = %catch.start @@ -262,7 +262,7 @@ call void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %1) ] unreachable -try.cont: ; preds = %entry, %invoke.cont1 +try.cont: ; preds = %invoke.cont1, %entry ret void ehcleanup: ; preds = %catch @@ -303,11 +303,11 @@ %1 = catchpad within %0 [i8* null] %2 = call i8* @llvm.wasm.get.exception(token %1) %3 = call i32 @llvm.wasm.get.ehselector(token %1) - %4 = call i8* @__cxa_begin_catch(i8* %2) #2 [ "funclet"(token %1) ] + %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] call void @__cxa_end_catch() [ "funclet"(token %1) ] catchret from %1 to label %try.cont -try.cont: ; preds = %entry, %catch.start +try.cont: ; preds = %catch.start, %entry ret void } @@ -327,8 +327,40 @@ %3 = call i32 @llvm.wasm.get.ehselector(token %1) catchret from %1 to label %try.cont -try.cont: ; preds = %entry, %catch.start +try.cont: ; preds = %catch.start, %entry + ret void +} + +; Tests a case when a cleanup region (cleanuppad ~ clanupret) contains another +; catchpad +define void @test_complex_cleanup_region() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { +entry: + invoke void @foo() + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry ret void + +ehcleanup: ; preds = %entry + %0 = cleanuppad within none [] + invoke void @foo() [ "funclet"(token %0) ] + to label %ehcleanupret unwind label %catch.dispatch + +catch.dispatch: ; preds = %ehcleanup + %1 = catchswitch within %0 [label %catch.start] unwind label %ehcleanup.1 + +catch.start: ; preds = %catch.dispatch + %2 = catchpad within %1 [i8* null] + %3 = call i8* @llvm.wasm.get.exception(token %2) + %4 = call i32 @llvm.wasm.get.ehselector(token %2) + catchret from %2 to label %ehcleanupret + +ehcleanup.1: ; preds = %catch.dispatch + %5 = cleanuppad within %0 [] + unreachable + +ehcleanupret: ; preds = %catch.start, %ehcleanup + cleanupret from %0 unwind to caller } declare void @foo()