Skip to content

[WebAssembly] Fix: fixCallUnwindMismatches after fixCatchUnwindMismatches#187484

Merged
aheejin merged 7 commits intollvm:mainfrom
hoodmane:fix-cfg-stackify
Apr 8, 2026
Merged

[WebAssembly] Fix: fixCallUnwindMismatches after fixCatchUnwindMismatches#187484
aheejin merged 7 commits intollvm:mainfrom
hoodmane:fix-cfg-stackify

Conversation

@hoodmane
Copy link
Copy Markdown
Contributor

@hoodmane hoodmane commented Mar 19, 2026

fixCallUnwindMismatches() adds an extra try block around call sites with incorrect unwind targets. fixCatchUnwindMismatches() handles catch blocks that have incorrect next unwind destinations. Previously we ran fixCallUnwindMismatches() first and then ran fixCatchUnwindMismatches(). The problem is that fixCatchUnwindMismatches() wraps entire try blocks which can change the unwind destination of the calls inside. If the calls had an incorrect unwind target to begin with, they will be wrapped already and so the outer wrapping won't alter their unwind target. However, if they start out with a correct unwind target, they won't get wrapped and then that can be messed up by fixCatchUnwindMismatches().

The fix is to run fixCatchUnwindMismatches() first. fixCallUnwindMismatches() never messes up the result of fixCatchUnwindMismatches() so this is the correct order.

Resolves #187302

cc @aheejin, @dschuff

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 19, 2026

@llvm/pr-subscribers-backend-webassembly

Author: Hood Chatham (hoodmane)

Changes

fixCallUnwindMismatches() adds an extra try block around call sites with
incorrect unwind targets. fixCatchUnwindMismatches() handles catch blocks that have incorrect next unwind destinations. Previously we ran fixCallUnwindMismatches() first and then ran fixCatchUnwindMismatches(). The problem is that fixCatchUnwindMismatches() wraps entire try blocks which can change the unwind destination of the calls inside. If the calls had an incorrect unwind target to begin with, they will be wrapped already and so the outer wrapping can't alter their unwind target. However, if they have a correct unwind target, they won't get wrapped and then that can be messed up by fixCatchUnwindMismatches().

The fix is to run fixCatchUnwindMismatches() first. fixCallUnwindMismatches() never messes up the result of fixCatchUnwindMismatches() so this is the correct order.

Resolves #187302


Full diff: https://github.com/llvm/llvm-project/pull/187484.diff

3 Files Affected:

  • (modified) llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp (+22-5)
  • (modified) llvm/test/CodeGen/WebAssembly/exception-legacy.ll (+101-6)
  • (modified) llvm/test/CodeGen/WebAssembly/exception.ll (+29-20)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 7fd2fb692549e..4e6f70af070b2 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -1836,6 +1836,8 @@ bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) {
     for (auto &MI : reverse(MBB)) {
       if (WebAssembly::isTry(MI.getOpcode()))
         EHPadStack.pop_back();
+      else if (MI.getOpcode() == WebAssembly::DELEGATE)
+        EHPadStack.push_back(MI.getOperand(0).getMBB());
       else if (WebAssembly::isCatch(MI.getOpcode()))
         EHPadStack.push_back(MI.getParent());
 
@@ -1847,6 +1849,8 @@ bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) {
           !WebAssembly::mayThrow(MI))
         continue;
       SeenThrowableInstInBB = true;
+      LLVM_DEBUG(dbgs() << "- fixCallUnwindMismatches considering: " << MI
+                        << "  in MBB = " << MBB.getName() << "\n");
 
       // If the EH pad on the stack top is where this instruction should unwind
       // next, we're good.
@@ -1923,8 +1927,11 @@ bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) {
         RecordCallerMismatchRange(EHPadStack.back());
 
       // 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.
-      else if (EHPadStack.empty() || !MayThrow) {
+      // if it throws, so we're good. A delegate targeting the caller (i.e.,
+      // FakeCallerBB on the stack) also correctly unwinds to the caller. If MI
+      // does not throw, we're good too.
+      else if (EHPadStack.empty() ||
+               EHPadStack.back() == FakeCallerBB || !MayThrow) {
       }
 
       // We found an instruction that unwinds to the caller but currently has an
@@ -1940,8 +1947,15 @@ bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) {
       // Update EHPadStack.
       if (WebAssembly::isTry(MI.getOpcode()))
         EHPadStack.pop_back();
-      else if (WebAssembly::isCatch(MI.getOpcode()))
-        EHPadStack.push_back(MI.getParent());
+      else if (MI.getOpcode() == WebAssembly::DELEGATE)
+        EHPadStack.push_back(MI.getOperand(0).getMBB());
+      else if (WebAssembly::isCatch(MI.getOpcode())) {
+        if (MBB.isEHPad()) {
+          EHPadStack.push_back(&MBB);
+        } else {
+          EHPadStack.push_back(&MBB);
+        }
+      }
     }
 
     if (RangeEnd)
@@ -2474,8 +2488,11 @@ void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {
     // Add an 'unreachable' after 'end_try_table's.
     addUnreachableAfterTryTables(MF, TII);
     // Fix mismatches in unwind destinations induced by linearizing the code.
-    fixCallUnwindMismatches(MF);
+    // Run fixCatchUnwindMismatches() first so that fixCallUnwindMismatches()
+    // will see and correct any new call/rethrow unwind mismatches introduced by
+    // fixCatchUnwindMismatches().
     fixCatchUnwindMismatches(MF);
+    fixCallUnwindMismatches(MF);
     // addUnreachableAfterTryTables and fixUnwindMismatches create new BBs, so
     // we need to recalculate ScopeTops.
     recalculateScopeTops(MF);
diff --git a/llvm/test/CodeGen/WebAssembly/exception-legacy.ll b/llvm/test/CodeGen/WebAssembly/exception-legacy.ll
index b96a664166f42..5537ca0e8f1ca 100644
--- a/llvm/test/CodeGen/WebAssembly/exception-legacy.ll
+++ b/llvm/test/CodeGen/WebAssembly/exception-legacy.ll
@@ -429,16 +429,16 @@ unreachable:                                      ; preds = %rethrow
 ; CHECK:   try
 ; CHECK:     try
 ; CHECK:       call  __cxa_throw
-; CHECK:       catch
+; CHECK:     catch   {{.*}} __cpp_exception
+; CHECK:       call  $drop=, __cxa_begin_catch
 ; CHECK:       call  __cxa_end_catch
 ; CHECK:       try
 ; CHECK:         try
-; Note that this rethrow targets the top-level catch_all
+; Rethrows the original exception caught by the outermost catch_all
 ; CHECK:           rethrow   4
-; CHECK:         catch
-; CHECK:           try
-; CHECK:             call  __cxa_end_catch
-; CHECK:           delegate    5
+; CHECK:         catch   {{.*}} __cpp_exception
+; CHECK:           call  $drop=, __cxa_begin_catch
+; CHECK:           call  __cxa_end_catch
 ; CHECK:           return
 ; CHECK:         end_try
 ; CHECK:       delegate    3
@@ -569,6 +569,101 @@ declare void @__cxa_throw(ptr, ptr, ptr) #1
 declare void @_ZSt9terminatev()
 declare ptr @_ZN4TempD2Ev(ptr returned)
 
+; Regression test for issue #187302: fixCallUnwindMismatches() was run first and
+; found that the rethrow had the correct unwind target so did not wrap it in a
+; try/delegate. Then fixCatchUnwindMismatches() added a try/delegate for
+;
+; invoke void @do_catch unwind label %terminate_catchswitch
+;
+; because otherwise it was going to unwind to outer_catchswitch rather than
+; terminate_catchswitch. But this made the rethrow incorrectly transfer control
+; to terminate_catchswitch rather than outer_catchswitch.
+; Fixed by running fixCatchUnwindMismatches() before fixCallUnwindMismatches().
+;
+; This pattern occurs in Rust's catch_unwind inside a destructor.
+
+; CHECK-LABEL: catch_unwind_in_cleanup:
+; CHECK:        catch_all
+; CHECK:          try
+; CHECK:            try
+; CHECK:              call  resume_unwind
+; CHECK:            catch   {{.*}} __cpp_exception
+; CHECK:              call  do_catch
+; end_cleanup and rethrow are inside the inner catch's scope, but each gets
+; its own try-delegate to route exceptions to the correct destination rather
+; than going through the catch-mismatch delegate to the terminate handler.
+; CHECK:              try
+; CHECK:                call  end_cleanup
+; CHECK:              delegate    7
+;                                (caller)
+; CHECK:              try
+; CHECK:                rethrow   7
+;                                (Rethrow exception caught by outermost catch_all)
+; CHECK:              delegate    2
+;                                (outer_catchswitch)
+; CHECK:            end_try
+; CHECK:          delegate    3
+;                            (terminate)
+; CHECK:          catch   {{.*}} __cpp_exception
+; CHECK:            call  do_catch
+; CHECK:            return
+define void @catch_unwind_in_cleanup() personality ptr @__gxx_wasm_personality_v0 {
+start:
+  invoke void @resume_unwind(i32 1)
+          to label %unreachable unwind label %outer_cleanuppad
+
+outer_cleanuppad:
+  %outer_pad = cleanuppad within none []
+  call void @start_cleanup() [ "funclet"(token %outer_pad) ]
+  invoke void @resume_unwind(i32 2) [ "funclet"(token %outer_pad) ]
+          to label %unreachable unwind label %inner_catchswitch
+
+inner_catchswitch:
+  %inner_cs = catchswitch within %outer_pad [label %inner_catchpad] unwind label %terminate_catchswitch
+
+inner_catchpad:
+  %inner_cp = catchpad within %inner_cs [ptr null]
+  %exn = call ptr @llvm.wasm.get.exception(token %inner_cp)
+  %sel = call i32 @llvm.wasm.get.ehselector(token %inner_cp)
+  invoke void @do_catch(ptr %exn, i32 2) [ "funclet"(token %inner_cp) ]
+          to label %inner_catchret unwind label %terminate_catchswitch
+
+terminate_catchswitch:
+  %term_cs = catchswitch within %outer_pad [label %terminate_catchpad] unwind label %outer_catchswitch
+
+terminate_catchpad:
+  %term_pad = catchpad within %term_cs [ptr null]
+  call void @panic_in_cleanup() [ "funclet"(token %term_pad) ]
+  unreachable
+
+inner_catchret:
+  catchret from %inner_cp to label %outer_cleanupret
+
+outer_cleanupret:
+  call void @end_cleanup() [ "funclet"(token %outer_pad) ]
+  cleanupret from %outer_pad unwind label %outer_catchswitch
+
+outer_catchswitch:
+  %outer_cs = catchswitch within none [label %outer_catchpad] unwind to caller
+outer_catchpad:
+  %outer_cp = catchpad within %outer_cs [ptr null]
+  %exn2 = call ptr @llvm.wasm.get.exception(token %outer_cp)
+  %sel2 = call i32 @llvm.wasm.get.ehselector(token %outer_cp)
+  call void @do_catch(ptr %exn2, i32 1) [ "funclet"(token %outer_cp) ]
+  catchret from %outer_cp to label %done
+
+done:
+  ret void
+unreachable:
+  unreachable
+}
+
+declare void @resume_unwind(i32) #1
+declare void @do_catch(ptr, i32) #0
+declare void @start_cleanup()
+declare void @end_cleanup()
+declare void @panic_in_cleanup() #2
+
 attributes #0 = { nounwind }
 attributes #1 = { noreturn }
 attributes #2 = { noreturn nounwind }
diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll
index 873386b3dcc6d..5cdabfca4cc29 100644
--- a/llvm/test/CodeGen/WebAssembly/exception.ll
+++ b/llvm/test/CodeGen/WebAssembly/exception.ll
@@ -484,34 +484,43 @@ unreachable:                                      ; preds = %rethrow
 ; try_table (catch_all_ref 0)'s caught exception is stored in local 2
 ; CHECK:     local.set  2
 ; CHECK:     block
+; catch_all 0 dispatches to %terminate.i
 ; CHECK:       try_table    (catch_all 0)
-; CHECK:         block
-; CHECK:           block     i32
-; CHECK:             try_table    (catch __cpp_exception 0)
-; CHECK:               call  __cxa_throw
+; 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:             end_try_table
-; CHECK:           end_block
-; CHECK:           call  __cxa_end_catch
-; CHECK:           block     i32
-; CHECK:             try_table    (catch_all_ref 5)
-; CHECK:               try_table    (catch __cpp_exception 1)
+; 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:                   local.get  2
+; CHECK:                   throw_ref
+; CHECK:                 end_try_table
 ; CHECK:               end_try_table
+; CHECK:             end_block
+; CHECK:             try_table    (catch_all_ref 5)
+; CHECK:               call  __cxa_end_catch
 ; CHECK:             end_try_table
+; CHECK:             return
 ; CHECK:           end_block
-; 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:           throw_ref
+; CHECK:         end_try_table
+; CHECK:       end_block
+; CHECK:       call  _ZSt9terminatev
 ; CHECK:     end_block
-; CHECK:     call  _ZSt9terminatev
 ; CHECK:   end_block
-; CHECK: end_block
-; CHECK: throw_ref
+; CHECK:   throw_ref
 define void @inlined_cleanupret() personality ptr @__gxx_wasm_personality_v0 {
 entry:
   %exception = tail call ptr @__cxa_allocate_exception(i32 4)

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 19, 2026

✅ With the latest revision this PR passed the C/C++ code formatter.

@hoodmane hoodmane force-pushed the fix-cfg-stackify branch 3 times, most recently from d3057b9 to 3091d3a Compare March 19, 2026 12:00
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 19, 2026

🪟 Windows x64 Test Results

  • 133095 tests passed
  • 3065 tests skipped

✅ The build succeeded and all tests passed.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 19, 2026

🐧 Linux x64 Test Results

  • 193122 tests passed
  • 4999 tests skipped

✅ The build succeeded and all tests passed.

…indMismatches()`

 `fixCallUnwindMismatches()` adds an extra try block around call sites with
incorrect unwind targets. `fixCatchUnwindMismatches()` handles catch blocks
that have incorrect next unwind destinations. Previously we ran
`fixCallUnwindMismatches()` first and then ran `fixCatchUnwindMismatches()`. The
problem is that `fixCatchUnwindMismatches()` wraps entire try blocks which can
change the unwind destination of the calls inside. If the calls had an incorrect
unwind target to begin with, they will be wrapped already and so the outer
wrapping can't alter their unwind target. However, if they have a correct unwind
target, they won't get wrapped and then that can be messed up by
`fixCatchUnwindMismatches()`.

The fix is to run `fixCatchUnwindMismatches()` first.
`fixCallUnwindMismatches()` never messes up the result of
`fixCatchUnwindMismatches()` so this is the correct order.

Resolves llvm#187302
Comment thread llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp Outdated
Comment thread llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
Comment thread llvm/test/CodeGen/WebAssembly/exception-legacy.ll Outdated
Comment thread llvm/test/CodeGen/WebAssembly/exception-legacy.ll Outdated
Comment thread llvm/test/CodeGen/WebAssembly/exception-legacy.ll Outdated
@aheejin
Copy link
Copy Markdown
Member

aheejin commented Mar 30, 2026

Are you planning to land this? I think we should backport this to the current release.

@hoodmane
Copy link
Copy Markdown
Contributor Author

hoodmane commented Apr 3, 2026

Okay @aheejin I think I addressed your comments assuming I understood them correctly.

Copy link
Copy Markdown
Member

@aheejin aheejin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Comment thread llvm/test/CodeGen/WebAssembly/exception.ll Outdated
@hoodmane
Copy link
Copy Markdown
Contributor Author

hoodmane commented Apr 6, 2026

Thanks for the review @aheejin! Would appreciate it if you could merge this and backport for me.

@aheejin aheejin merged commit f89b9a0 into llvm:main Apr 8, 2026
10 checks passed
@llvm-ci
Copy link
Copy Markdown

llvm-ci commented Apr 8, 2026

LLVM Buildbot has detected a new failure on builder openmp-s390x-linux running on systemz-1 while building llvm at step 6 "test-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/88/builds/22203

Here is the relevant piece of the build log for the reference
Step 6 (test-openmp) failure: test (failure)
******************** TEST 'libomp :: tasking/issue-94260-2.c' FAILED ********************
Exit Code: -11

Command Output (stdout):
--
# RUN: at line 1
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang -fopenmp   -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test -L /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src  -fno-omit-frame-pointer -mbackchain -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c -o /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp -lm -latomic && /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# executed command: /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang -fopenmp -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test -L /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -fno-omit-frame-pointer -mbackchain -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c -o /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp -lm -latomic
# executed command: /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# note: command had no output on stdout or stderr
# error: command failed with exit status: -11

--

********************


@hoodmane hoodmane deleted the fix-cfg-stackify branch April 8, 2026 10:58
@aheejin
Copy link
Copy Markdown
Member

aheejin commented Apr 8, 2026

/cherry-pick f89b9a0

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Apr 8, 2026

/pull-request #190996

@hoodmane
Copy link
Copy Markdown
Contributor Author

hoodmane commented Apr 8, 2026

Thanks again @aheejin!

c-rhodes pushed a commit to llvmbot/llvm-project that referenced this pull request Apr 10, 2026
…ches (llvm#187484)

`fixCallUnwindMismatches()` adds an extra try block around call sites
with incorrect unwind targets. `fixCatchUnwindMismatches()` handles
catch blocks that have incorrect next unwind destinations. Previously we
ran `fixCallUnwindMismatches()` first and then ran
`fixCatchUnwindMismatches()`. The problem is that
`fixCatchUnwindMismatches()` wraps entire try blocks which can change
the unwind destination of the calls inside. If the calls had an
incorrect unwind target to begin with, they will be wrapped already and
so the outer wrapping won't alter their unwind target. However, if they
start out with a correct unwind target, they won't get wrapped and then
that can be messed up by `fixCatchUnwindMismatches()`.

The fix is to run `fixCatchUnwindMismatches()` first.
`fixCallUnwindMismatches()` never messes up the result of
`fixCatchUnwindMismatches()` so this is the correct order.

Resolves llvm#187302

(cherry picked from commit f89b9a0)
YonahGoldberg pushed a commit to YonahGoldberg/llvm-project that referenced this pull request Apr 21, 2026
…ches (llvm#187484)

`fixCallUnwindMismatches()` adds an extra try block around call sites
with incorrect unwind targets. `fixCatchUnwindMismatches()` handles
catch blocks that have incorrect next unwind destinations. Previously we
ran `fixCallUnwindMismatches()` first and then ran
`fixCatchUnwindMismatches()`. The problem is that
`fixCatchUnwindMismatches()` wraps entire try blocks which can change
the unwind destination of the calls inside. If the calls had an
incorrect unwind target to begin with, they will be wrapped already and
so the outer wrapping won't alter their unwind target. However, if they
start out with a correct unwind target, they won't get wrapped and then
that can be messed up by `fixCatchUnwindMismatches()`.

The fix is to run `fixCatchUnwindMismatches()` first.
`fixCallUnwindMismatches()` never messes up the result of
`fixCatchUnwindMismatches()` so this is the correct order.

Resolves llvm#187302
aheejin added a commit that referenced this pull request Apr 28, 2026
This code was written under the assumption that
`fixCallUnwindMismatches` runs before `fixCatchUnwindMismatches`, but
since #187484 it's not true anymore.
aheejin added a commit that referenced this pull request Apr 28, 2026
…194184)

After #187484, `fixCallUnwindMismatches` now runs after
`fixCatchUnwindMismatches`. But `fixCallUnwindMismatches` was not
handling newly generated `try_table`s and trampoline BBs in
`fixCatchUnwindMismatches` correctly. See the comments for details.

This is mean to replace #192968 and adds its test case to
`cfg-stackify-eh.ll` and `cfg-stackify-eh-legacy.ll`. (The bug only
happens in the standard (exnref) EH so `cfg-stackify-eh.ll`, but I added
the same test to `cfg-stackify-eh-legacy.ll` as well for more coverage.)

`exception.ll`'s `inlined_cleanupret`'s results have changed because we
were generating unnecessary `try_table`s, thinking there were call
unwind mismatches when there weren't. (This wouldn't have resulted in
incorrect execution; it just added more unnecessary instructions.) This
also fixes some comments for `inlined_cleanupret`, because "throw_ref
targets the top level cleanuppad" is confusing. (This comment was
probably copy-pasted from "delegate targets ...".)

Closes #192968.
kirthana14m pushed a commit to ROCm/llvm-project that referenced this pull request Apr 30, 2026
…94188)

This code was written under the assumption that
`fixCallUnwindMismatches` runs before `fixCatchUnwindMismatches`, but
since llvm#187484 it's not true anymore.
kirthana14m pushed a commit to ROCm/llvm-project that referenced this pull request Apr 30, 2026
…lvm#194184)

After llvm#187484, `fixCallUnwindMismatches` now runs after
`fixCatchUnwindMismatches`. But `fixCallUnwindMismatches` was not
handling newly generated `try_table`s and trampoline BBs in
`fixCatchUnwindMismatches` correctly. See the comments for details.

This is mean to replace llvm#192968 and adds its test case to
`cfg-stackify-eh.ll` and `cfg-stackify-eh-legacy.ll`. (The bug only
happens in the standard (exnref) EH so `cfg-stackify-eh.ll`, but I added
the same test to `cfg-stackify-eh-legacy.ll` as well for more coverage.)

`exception.ll`'s `inlined_cleanupret`'s results have changed because we
were generating unnecessary `try_table`s, thinking there were call
unwind mismatches when there weren't. (This wouldn't have resulted in
incorrect execution; it just added more unnecessary instructions.) This
also fixes some comments for `inlined_cleanupret`, because "throw_ref
targets the top level cleanuppad" is confusing. (This comment was
probably copy-pasted from "delegate targets ...".)

Closes llvm#192968.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Development

Successfully merging this pull request may close these issues.

[WebAssembly] eh regression from llvm 20 to 21 with nested catchpads

4 participants