diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -526,40 +526,50 @@ AfterSet.insert(&MI); } - // Local expression tree should go after the TRY. - for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; - --I) { - if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) - continue; - if (WebAssembly::isChild(*std::prev(I), MFI)) - AfterSet.insert(&*std::prev(I)); - else - break; - } - // If Header unwinds to MBB (= Header contains 'invoke'), the try block should // contain the call within it. So the call should go after the TRY. The // exception is when the header's terminator is a rethrow instruction, in // which case that instruction, not a call instruction before it, is gonna // throw. + MachineInstr *ThrowingCall = nullptr; if (MBB.isPredecessor(Header)) { auto TermPos = Header->getFirstTerminator(); if (TermPos == Header->end() || TermPos->getOpcode() != WebAssembly::RETHROW) { - for (const auto &MI : reverse(*Header)) { + for (auto &MI : reverse(*Header)) { if (MI.isCall()) { AfterSet.insert(&MI); + ThrowingCall = &MI; // Possibly throwing calls are usually wrapped by EH_LABEL // instructions. We don't want to split them and the call. if (MI.getIterator() != Header->begin() && - std::prev(MI.getIterator())->isEHLabel()) + std::prev(MI.getIterator())->isEHLabel()) { AfterSet.insert(&*std::prev(MI.getIterator())); + ThrowingCall = &*std::prev(MI.getIterator()); + } break; } } } } + // Local expression tree should go after the TRY. + // For BLOCK placement, we start the search from the previous instruction of a + // BB's terminator, but in TRY's case, we should start from the previous + // instruction of a call that can throw, or a EH_LABEL that precedes the call, + // because the return values of the call's previous instructions can be + // stackified and consumed by the throwing call. + auto SearchStartPt = ThrowingCall ? MachineBasicBlock::iterator(ThrowingCall) + : Header->getFirstTerminator(); + for (auto I = SearchStartPt, E = Header->begin(); I != E; --I) { + if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) + continue; + if (WebAssembly::isChild(*std::prev(I), MFI)) + AfterSet.insert(&*std::prev(I)); + else + break; + } + // Add the TRY. auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); MachineInstr *Begin = diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll --- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll +++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll @@ -704,14 +704,41 @@ cleanupret from %0 unwind to caller } +; Tests if 'try' marker is placed correctly. In this test, 'try' should be +; placed before the call to 'nothrow_i32' and not between the call to +; 'nothrow_i32' and 'fun', because the return value of 'nothrow_i32' is +; stackified and pushed onto the stack to be consumed by the call to 'fun'. + +; CHECK-LABEL: test11 +; CHECK: try +; CHECK: i32.call $push{{.*}}=, nothrow_i32 +; CHECK: call fun, $pop{{.*}} +define void @test11() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { +entry: + %call = call i32 @nothrow_i32() + invoke void @fun(i32 %call) + to label %invoke.cont unwind label %terminate + +invoke.cont: ; preds = %entry + ret void + +terminate: ; preds = %entry + %0 = cleanuppad within none [] + %1 = tail call i8* @llvm.wasm.get.exception(token %0) + call void @__clang_call_terminate(i8* %1) [ "funclet"(token %0) ] + unreachable +} + ; Check if the unwind destination mismatch stats are correct ; NOSORT-STAT: 11 wasm-cfg-stackify - Number of EH pad unwind mismatches found declare void @foo() declare void @bar() declare i32 @baz() +declare void @fun(i32) ; Function Attrs: nounwind declare void @nothrow(i32) #0 +declare i32 @nothrow_i32() #0 ; Function Attrs: nounwind declare %class.Object* @_ZN6ObjectD2Ev(%class.Object* returned) #0 declare i32 @__gxx_wasm_personality_v0(...)