[llvm-branch-commits] [llvm] 5c9647b - release/22.x: [WebAssembly] Fix EHPadStack calculation in fixCallUnwindMismatches (#194184)
Douglas Yung via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Apr 30 20:59:11 PDT 2026
Author: Heejin Ahn
Date: 2026-05-01T03:58:54Z
New Revision: 5c9647b8e680a277281192a5a12b14e9155c7e57
URL: https://github.com/llvm/llvm-project/commit/5c9647b8e680a277281192a5a12b14e9155c7e57
DIFF: https://github.com/llvm/llvm-project/commit/5c9647b8e680a277281192a5a12b14e9155c7e57.diff
LOG: release/22.x: [WebAssembly] Fix EHPadStack calculation in fixCallUnwindMismatches (#194184)
Backport d8c1f8734f43fd6edaf0cbdd8e1a1b0451a4dbb0
Requested by: @aheejin
Added:
Modified:
llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll
llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
llvm/test/CodeGen/WebAssembly/exception.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 44d54cadf289c..6ebd1d1982415 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -1503,7 +1503,7 @@ void WebAssemblyCFGStackify::addNestedTryTable(MachineInstr *RangeBegin,
// Add a 'end_try_table' instruction in the EndTryTable BB created above.
MachineInstr *EndTryTable = BuildMI(EndTryTableBB, RangeEnd->getDebugLoc(),
TII.get(WebAssembly::END_TRY_TABLE));
- registerTryScope(TryTable, EndTryTable, nullptr);
+ registerTryScope(TryTable, EndTryTable, TrampolineBB);
}
// In the standard (exnref) EH, we fix unwind mismatches by adding a new
@@ -1838,8 +1838,51 @@ bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) {
EHPadStack.pop_back();
else if (MI.getOpcode() == WebAssembly::DELEGATE)
EHPadStack.push_back(MI.getOperand(0).getMBB());
- else if (WebAssembly::isCatch(MI.getOpcode()))
+ else if (WebAssembly::WasmUseLegacyEH &&
+ WebAssembly::isCatch(MI.getOpcode()))
EHPadStack.push_back(MI.getParent());
+ else if (MI.getOpcode() == WebAssembly::END_TRY_TABLE)
+ // In case of the legacy EH, 'catch' instruction is always an EH pad for
+ // the 'try' body that precedes it. But in the standard EH, because
+ // fixCatchUnwindMismatches runs before this, a new try_table's
+ // trampoline BB will be separated from try_table ~ end_try_table body:
+ //
+ // bb0:
+ // try_table (catch_all_ref %far_away_trampoline)
+ // ...
+ // end_try_table
+ // ...
+ // far_away_trampoline:
+ // catch_all_ref
+ // throw_ref
+ //
+ // And there can be multiple try_tables that target a single trampoline:
+ //
+ // bb0:
+ // try_table (catch_all_ref %far_away_trampolinle_bb)
+ // ...
+ // end_try_table
+ // ...
+ // bb1:
+ // try_table (catch_all_ref %far_away_trampolinle_bb)
+ // ...
+ // end_try_table
+ // ...
+ // far_away_trampoline:
+ // catch_all_ref
+ // throw_ref
+ //
+ // So we can't call WebAssembly::isCatch to add its parent EH pad to
+ // EHPadStack. Now we add to EHPadStack at end_try_table marker, by
+ // getting its matching try_table's destination. This works when the
+ // destination EH pad is either a normal EH pad or a trampoline created
+ // in fixCatchUnwindMismatches.
+ //
+ // Note that we don't need to distinguish this case in
+ // fixCatchUnwindMismatches because it runs before
+ // fixCallUnwindMismatches and there is no new try_tables and
+ // trampolines when it runs.
+ EHPadStack.push_back(TryToEHPad[EndToBegin[&MI]]);
// In this loop we only gather calls that have an EH pad to unwind. So
// there will be at most 1 such call (= invoke) in a BB, so after we've
@@ -1946,8 +1989,12 @@ bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) {
EHPadStack.pop_back();
else if (MI.getOpcode() == WebAssembly::DELEGATE)
EHPadStack.push_back(MI.getOperand(0).getMBB());
- else if (WebAssembly::isCatch(MI.getOpcode()))
+ else if (WebAssembly::WasmUseLegacyEH &&
+ WebAssembly::isCatch(MI.getOpcode()))
EHPadStack.push_back(MI.getParent());
+ else if (!WebAssembly::WasmUseLegacyEH &&
+ MI.getOpcode() == WebAssembly::END_TRY_TABLE)
+ EHPadStack.push_back(TryToEHPad[EndToBegin[&MI]]);
}
if (RangeEnd)
diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll
index 3a18a4351b76e..95a078a940303 100644
--- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll
+++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll
@@ -1822,6 +1822,61 @@ unreachable:
unreachable
}
+; A regression test for the case where fixCatchUnwindMismatches generates a
+; single trampoline BB targeted by multiple try_tables. This should not crash.
+define i32 @shared_trampoline(ptr %arg, i1 %arg1) personality ptr @__gxx_wasm_personality_v0 {
+bb:
+ br i1 %arg1, label %bb2, label %bb10
+
+bb2: ; preds = %bb
+ invoke void @f1(ptr null, ptr null)
+ to label %bb3 unwind label %bb8
+
+bb3: ; preds = %bb2
+ %i = invoke ptr @f2(ptr null, ptr null)
+ to label %bb4 unwind label %bb6
+
+bb4: ; preds = %bb3
+ %i5 = invoke ptr @f3(ptr null, ptr null)
+ to label %common.ret unwind label %bb8
+
+common.ret: ; preds = %bb21, %bb18, %bb13, %bb6, %bb4
+ %common.ret.op = phi i32 [ 0, %bb18 ], [ 0, %bb6 ], [ 0, %bb13 ], [ 0, %bb21 ], [ 0, %bb4 ]
+ ret i32 %common.ret.op
+
+bb6: ; preds = %bb3
+ %i7 = cleanuppad within none []
+ br label %common.ret
+
+bb8: ; preds = %bb4, %bb2
+ %i9 = cleanuppad within none []
+ cleanupret from %i9 unwind to caller
+
+bb10: ; preds = %bb
+ invoke void @f4(ptr null)
+ to label %bb21 unwind label %bb11
+
+bb11: ; preds = %bb10
+ %i12 = catchswitch within none [label %bb13] unwind to caller
+
+bb13: ; preds = %bb11
+ %i14 = catchpad within %i12 [ptr null]
+ %i15 = tail call ptr @llvm.wasm.get.exception(token %i14)
+ br label %common.ret
+
+bb16: ; preds = %bb21
+ %i17 = catchswitch within none [label %bb18] unwind to caller
+
+bb18: ; preds = %bb16
+ %i19 = catchpad within %i17 [ptr null]
+ %i20 = tail call ptr @llvm.wasm.get.exception(token %i19)
+ br label %common.ret
+
+bb21: ; preds = %bb10
+ %i22 = invoke i32 @f5(ptr null)
+ to label %common.ret unwind label %bb16
+}
+
declare void @resume_unwind(i32) #1
declare void @do_catch(ptr, i32) #0
declare void @start_cleanup()
@@ -1829,8 +1884,8 @@ declare void @end_cleanup()
declare void @panic_in_cleanup() #2
; Check if the unwind destination mismatch stats are correct
-; NOSORT: 25 wasm-cfg-stackify - Number of call unwind mismatches found
-; NOSORT: 7 wasm-cfg-stackify - Number of catch unwind mismatches found
+; NOSORT: 26 wasm-cfg-stackify - Number of call unwind mismatches found
+; NOSORT: 8 wasm-cfg-stackify - Number of catch unwind mismatches found
declare void @foo()
declare void @bar()
@@ -1838,6 +1893,11 @@ declare i32 @baz()
declare i32 @qux(i32)
declare void @quux(i32)
declare void @fun(i32)
+declare void @f1(ptr, ptr)
+declare ptr @f2(ptr, ptr)
+declare ptr @f3(ptr, ptr)
+declare void @f4(ptr)
+declare i32 @f5(ptr)
; Function Attrs: nounwind
declare void @nothrow(i32) #0
; Function Attrs: nounwind
diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
index 93937fd96d887..b4fc6e4dec8b1 100644
--- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
+++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
@@ -1506,9 +1506,64 @@ unreachable: ; preds = %rethrow, %entry
unreachable
}
+; A regression test for the case where fixCatchUnwindMismatches generates a
+; single trampoline BB targeted by multiple try_tables. This should not crash.
+define i32 @shared_trampoline(ptr %arg, i1 %arg1) personality ptr @__gxx_wasm_personality_v0 {
+bb:
+ br i1 %arg1, label %bb2, label %bb10
+
+bb2: ; preds = %bb
+ invoke void @f1(ptr null, ptr null)
+ to label %bb3 unwind label %bb8
+
+bb3: ; preds = %bb2
+ %i = invoke ptr @f2(ptr null, ptr null)
+ to label %bb4 unwind label %bb6
+
+bb4: ; preds = %bb3
+ %i5 = invoke ptr @f3(ptr null, ptr null)
+ to label %common.ret unwind label %bb8
+
+common.ret: ; preds = %bb21, %bb18, %bb13, %bb6, %bb4
+ %common.ret.op = phi i32 [ 0, %bb18 ], [ 0, %bb6 ], [ 0, %bb13 ], [ 0, %bb21 ], [ 0, %bb4 ]
+ ret i32 %common.ret.op
+
+bb6: ; preds = %bb3
+ %i7 = cleanuppad within none []
+ br label %common.ret
+
+bb8: ; preds = %bb4, %bb2
+ %i9 = cleanuppad within none []
+ cleanupret from %i9 unwind to caller
+
+bb10: ; preds = %bb
+ invoke void @f4(ptr null)
+ to label %bb21 unwind label %bb11
+
+bb11: ; preds = %bb10
+ %i12 = catchswitch within none [label %bb13] unwind to caller
+
+bb13: ; preds = %bb11
+ %i14 = catchpad within %i12 [ptr null]
+ %i15 = tail call ptr @llvm.wasm.get.exception(token %i14)
+ br label %common.ret
+
+bb16: ; preds = %bb21
+ %i17 = catchswitch within none [label %bb18] unwind to caller
+
+bb18: ; preds = %bb16
+ %i19 = catchpad within %i17 [ptr null]
+ %i20 = tail call ptr @llvm.wasm.get.exception(token %i19)
+ br label %common.ret
+
+bb21: ; preds = %bb10
+ %i22 = invoke i32 @f5(ptr null)
+ to label %common.ret unwind label %bb16
+}
+
; Check if the unwind destination mismatch stats are correct
; NOSORT: 24 wasm-cfg-stackify - Number of call unwind mismatches found
-; NOSORT: 4 wasm-cfg-stackify - Number of catch unwind mismatches found
+; NOSORT: 5 wasm-cfg-stackify - Number of catch unwind mismatches found
declare void @foo()
declare void @bar()
@@ -1516,6 +1571,11 @@ declare i32 @baz()
declare i32 @qux(i32)
declare void @quux(i32)
declare void @fun(i32)
+declare void @f1(ptr, ptr)
+declare ptr @f2(ptr, ptr)
+declare ptr @f3(ptr, ptr)
+declare void @f4(ptr)
+declare i32 @f5(ptr)
; Function Attrs: nounwind
declare void @nothrow(i32) #0
; Function Attrs: nounwind
diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll
index 19c3d1b158951..11e5be83d11cd 100644
--- a/llvm/test/CodeGen/WebAssembly/exception.ll
+++ b/llvm/test/CodeGen/WebAssembly/exception.ll
@@ -469,9 +469,9 @@ unreachable: ; preds = %rethrow
; }
;
; ~Temp() generates cleanupret, which is lowered to a 'throw_ref' later. That
-; throw_ref's argument should correctly target the top-level cleanuppad
-; (catch_all_ref). This is a regression test for the bug where we did not
-; compute throw_ref's argument correctly.
+; throw_ref's argument should correctly rethrow the exception caught by the
+; top-level cleanuppad (catch_all_ref). This is a regression test for the bug
+; where we did not compute throw_ref's argument correctly.
; CHECK-LABEL: inlined_cleanupret:
; CHECK: block exnref
@@ -486,41 +486,34 @@ unreachable: ; preds = %rethrow
; CHECK: block
; catch_all 0 dispatches to %terminate.i (the 'call _ZSt9terminatev' instruction).
; CHECK: try_table (catch_all 0)
-; CHECK: block exnref
-; CHECK: block
-; CHECK: block i32
-; CHECK: try_table (catch __cpp_exception 0)
-; CHECK: call __cxa_throw
-; CHECK: end_try_table
-; CHECK: end_block
-;
-; invoke __cxa_end_catch... unwind label %terminate.i
-; should unwind to %terminate.i. catch_all_ref 1 points to the
-; try_table (catch_all 0) which in turn dispatches to %terminate.i
-; CHECK: try_table (catch_all_ref 1)
-; CHECK: call __cxa_end_catch
+; CHECK: block
+; CHECK: block i32
+; CHECK: try_table (catch __cpp_exception 0)
+; CHECK: call __cxa_throw
; CHECK: end_try_table
-; CHECK: block i32
-; CHECK: try_table (catch_all_ref 6)
-; CHECK: try_table (catch __cpp_exception 1)
-; Note that the throw_ref below targets the top-level catch_all_ref (local 2)
-; CHECK: local.get 2
-; CHECK: throw_ref
-; CHECK: end_try_table
-; CHECK: end_try_table
-; CHECK: end_block
+; CHECK: end_block
+; CHECK: call __cxa_end_catch
+; CHECK: block i32
; CHECK: try_table (catch_all_ref 5)
-; CHECK: call __cxa_end_catch
+; CHECK: try_table (catch __cpp_exception 1)
+; Note that the throw_ref below rethrows the exception caught by the top-level
+; catch_all_ref (local 2)
+; CHECK: local.get 2
+; CHECK: throw_ref
+; CHECK: end_try_table
; CHECK: end_try_table
-; CHECK: return
; CHECK: end_block
-; CHECK: throw_ref
-; CHECK: end_try_table
-; CHECK: end_block
-; CHECK: call _ZSt9terminatev
+; CHECK: try_table (catch_all_ref 4)
+; CHECK: call __cxa_end_catch
+; CHECK: end_try_table
+; CHECK: return
+; CHECK: end_block
+; CHECK: end_try_table
; CHECK: end_block
+; CHECK: call _ZSt9terminatev
; CHECK: end_block
-; CHECK: throw_ref
+; CHECK: end_block
+; CHECK: throw_ref
define void @inlined_cleanupret() personality ptr @__gxx_wasm_personality_v0 {
entry:
%exception = tail call ptr @__cxa_allocate_exception(i32 4)
More information about the llvm-branch-commits
mailing list