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 @@ -1192,39 +1192,39 @@ for (auto &MBB : reverse(MF)) { bool SeenThrowableInstInBB = false; for (auto &MI : reverse(MBB)) { - if (MI.getOpcode() == WebAssembly::TRY) - EHPadStack.pop_back(); - else if (WebAssembly::isCatch(MI.getOpcode())) - EHPadStack.push_back(MI.getParent()); bool MayThrow = WebAssembly::mayThrow(MI); // If MBB has an EH pad successor and this is the last instruction that // may throw, this instruction unwinds to the EH pad and not to the // caller. - if (MBB.hasEHPadSuccessor() && MayThrow && !SeenThrowableInstInBB) { + if (MBB.hasEHPadSuccessor() && MayThrow && !SeenThrowableInstInBB) SeenThrowableInstInBB = true; - continue; - } // We wrap up the current range when we see a marker even if we haven't // finished a BB. - if (RangeEnd && WebAssembly::isMarker(MI.getOpcode())) { + else if (RangeEnd && WebAssembly::isMarker(MI.getOpcode())) RecordCallerMismatchRange(EHPadStack.back()); - continue; - } // If EHPadStack is empty, that means it correctly unwinds to the caller // if it throws, so we're good. If MI does not throw, we're good too. - if (EHPadStack.empty() || !MayThrow) - continue; + else if (EHPadStack.empty() || !MayThrow) { + } // We found an instruction that unwinds to the caller but currently has an // incorrect unwind destination. Create a new range or increment the // currently existing range. - if (!RangeEnd) - RangeBegin = RangeEnd = &MI; - else - RangeBegin = &MI; + else { + if (!RangeEnd) + RangeBegin = RangeEnd = &MI; + else + RangeBegin = &MI; + } + + // Update EHPadStack. + if (MI.getOpcode() == WebAssembly::TRY) + EHPadStack.pop_back(); + else if (WebAssembly::isCatch(MI.getOpcode())) + EHPadStack.push_back(MI.getParent()); } if (RangeEnd) 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 @@ -1099,8 +1099,35 @@ cleanupret from %0 unwind to caller } +; This crashed when updating EHPadStack within fixCallUniwindMismatch had a bug. +; This should not crash and try-delegate has to be created around 'call @baz', +; because the initial TRY placement for 'call @quux' was done before 'call @baz' +; because 'call @baz''s return value is stackified. + +; CHECK-LABEL: test19 +; CHECK: try +; CHECK: try +; CHECK: call $[[RET:[0-9]+]]=, baz +; CHECK: delegate 1 +; CHECK: call quux, $[[RET]] +; CHECK: catch_all +; CHECK: end_try +define void @test19() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { +entry: + %call = call i32 @baz() + invoke void @quux(i32 %call) + to label %invoke.cont unwind label %ehcleanup + +ehcleanup: ; preds = %entry + %0 = cleanuppad within none [] + cleanupret from %0 unwind to caller + +invoke.cont: ; preds = %entry + unreachable +} + ; Check if the unwind destination mismatch stats are correct -; NOSORT: 18 wasm-cfg-stackify - Number of call unwind mismatches found +; NOSORT: 19 wasm-cfg-stackify - Number of call unwind mismatches found ; NOSORT: 3 wasm-cfg-stackify - Number of catch unwind mismatches found declare void @foo()