[llvm] [WebAssembly] Add/Reorder legacy EH tests (PR #114363)

Heejin Ahn via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 30 22:50:16 PDT 2024


https://github.com/aheejin created https://github.com/llvm/llvm-project/pull/114363

These tests are added to match the standard EH tests in #114361:
- nested_try
- unwind_mismatches_with_loop These tests are useful to test certain aspects of the new EH but I think they add more coverage to the legaacy tests as well.

And `unstackify_when_fixing_unwind_mismatch` and `unwind_mismatches_5` have not changed; they have been just moved.

This also fixes some comments.

>From a7b88b4b5d38e1b18ff54de0c717768100152e55 Mon Sep 17 00:00:00 2001
From: Heejin Ahn <aheejin at gmail.com>
Date: Thu, 31 Oct 2024 03:18:44 +0000
Subject: [PATCH] [WebAssembly] Add/Reorder legacy EH tests

These tests are added to match the standard EH tests in #114361:
- nested_try
- unwind_mismatches_with_loop
These tests are useful to test certain aspects of the new EH but I think
they add more coverage to the legaacy tests as well.

And `unstackify_when_fixing_unwind_mismatch` and `unwind_mismatches_5`
have not changed; they have been just moved.

This also fixes some comments.
---
 .../WebAssembly/cfg-stackify-eh-legacy.ll     | 277 ++++++++++++------
 1 file changed, 192 insertions(+), 85 deletions(-)

diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll
index cef92f459e4aa3..3a186775f4c0bc 100644
--- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll
+++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll
@@ -205,16 +205,64 @@ unreachable:                                      ; preds = %rethrow5
   unreachable
 }
 
-; Nested loop within a catch clause
-; void loop_within_catch() {
+; Nested try-catches within a try
+; void nested_try() {
 ;   try {
-;     foo();
-;   } catch (...) {
-;     for (int i = 0; i < 50; i++)
+;     try {
 ;       foo();
+;     } catch (...) {
+;     }
+;   } catch (...) {
 ;   }
 ; }
 
+; CHECK-LABEL: nested_try:
+; CHECK:   try
+; CHECK:     try
+; CHECK:       call  foo
+; CHECK:     catch
+; CHECK:       call  $drop=, __cxa_begin_catch
+; CHECK:       call  __cxa_end_catch
+; CHECK:     end_try
+; CHECK:     catch
+; CHECK:     call  $drop=, __cxa_begin_catch
+; CHECK:     call  __cxa_end_catch
+; CHECK:   end_try
+define void @nested_try() personality ptr @__gxx_wasm_personality_v0 {
+entry:
+  invoke void @foo()
+          to label %try.cont7 unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %entry
+  %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch2
+
+catch.start:                                      ; preds = %catch.dispatch
+  %1 = catchpad within %0 [ptr null]
+  %2 = call ptr @llvm.wasm.get.exception(token %1)
+  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
+  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
+  invoke void @__cxa_end_catch() [ "funclet"(token %1) ]
+          to label %invoke.cont1 unwind label %catch.dispatch2
+
+catch.dispatch2:                                  ; preds = %catch.start, %catch.dispatch
+  %5 = catchswitch within none [label %catch.start3] unwind to caller
+
+catch.start3:                                     ; preds = %catch.dispatch2
+  %6 = catchpad within %5 [ptr null]
+  %7 = call ptr @llvm.wasm.get.exception(token %6)
+  %8 = call i32 @llvm.wasm.get.ehselector(token %6)
+  %9 = call ptr @__cxa_begin_catch(ptr %7) [ "funclet"(token %6) ]
+  call void @__cxa_end_catch() [ "funclet"(token %6) ]
+  catchret from %6 to label %try.cont7
+
+try.cont7:                                        ; preds = %entry, %invoke.cont1, %catch.start3
+  ret void
+
+invoke.cont1:                                     ; preds = %catch.start
+  catchret from %1 to label %try.cont7
+}
+
+
 ; CHECK-LABEL: loop_within_catch:
 ; CHECK: try
 ; CHECK:   call      foo
@@ -386,7 +434,7 @@ try.cont:                                         ; preds = %catch.start, %loop
 ; If 'call foo' throws a foreign exception, it will not be caught by C1, and
 ; should be rethrown to the caller. But after control flow linearization, it
 ; will instead unwind to C0, an incorrect next EH pad. We wrap the whole
-; try-catch with try-delegate that rethrows an exception to the caller to fix
+; try-catch with try-delegate that rethrows the exception to the caller to fix
 ; this.
 
 ; NOSORT-LABEL: unwind_mismatches_0:
@@ -407,7 +455,6 @@ try.cont:                                         ; preds = %catch.start, %loop
 ; NOSORT: catch   {{.*}}          # catch[[C0]]:
 ; NOSORT: end_try
 ; NOSORT: return
-
 define void @unwind_mismatches_0() personality ptr @__gxx_wasm_personality_v0 {
 bb0:
   invoke void @foo()
@@ -442,7 +489,7 @@ try.cont:                                         ; preds = %catch.start1, %catc
 ; 'call bar' and 'call baz''s original unwind destination was the caller, but
 ; after control flow linearization, their unwind destination incorrectly becomes
 ; 'C0'. We fix this by wrapping the calls with a nested try-delegate that
-; rethrows exceptions to the caller.
+; rethrows the exception to the caller.
 
 ; And the return value of 'baz' should NOT be stackified because the BB is split
 ; during fixing unwind mismatches.
@@ -462,7 +509,6 @@ try.cont:                                         ; preds = %catch.start1, %catc
 ; NOSORT: catch   {{.*}}                      # catch[[C0:[0-9]+]]:
 ; NOSORT:   return
 ; NOSORT: end_try
-
 define void @unwind_mismatches_1() personality ptr @__gxx_wasm_personality_v0 {
 bb0:
   invoke void @foo()
@@ -489,7 +535,7 @@ try.cont:                                         ; preds = %catch.start0
 
 ; The same as unwind_mismatches_0, but we have one more call 'call @foo' in bb1
 ; which unwinds to the caller. IN this case bb1 has two call unwind mismatches:
-  ; 'call @foo' unwinds to the caller and 'call @bar' unwinds to catch C0.
+; 'call @foo' unwinds to the caller and 'call @bar' unwinds to catch C0.
 
 ; NOSORT-LABEL: unwind_mismatches_2:
 ; NOSORT: try
@@ -514,7 +560,6 @@ try.cont:                                         ; preds = %catch.start0
 ; NOSORT: catch   {{.*}}        # catch[[C0]]:
 ; NOSORT: end_try
 ; NOSORT: return
-
 define void @unwind_mismatches_2() personality ptr @__gxx_wasm_personality_v0 {
 bb0:
   invoke void @foo()
@@ -570,7 +615,6 @@ try.cont:                                         ; preds = %catch.start1, %catc
 ; NOSORT: catch   {{.*}}                      # catch[[C0:[0-9]+]]:
 ; NOSORT:   return
 ; NOSORT: end_try
-
 define i32 @unwind_mismatches_3() personality ptr @__gxx_wasm_personality_v0 {
 bb0:
   invoke void @foo()
@@ -593,46 +637,6 @@ try.cont:                                         ; preds = %catch.start0
   ret i32 0
 }
 
-; Tests the case when TEE stackifies a register in RegStackify but it gets
-; unstackified in fixCallUnwindMismatches in CFGStackify.
-
-; NOSORT-LOCALS-LABEL: unstackify_when_fixing_unwind_mismatch:
-define void @unstackify_when_fixing_unwind_mismatch(i32 %x) personality ptr @__gxx_wasm_personality_v0 {
-bb0:
-  invoke void @foo()
-          to label %bb1 unwind label %catch.dispatch0
-
-bb1:                                              ; preds = %bb0
-  %t = add i32 %x, 4
-  ; This %addr is used in multiple places, so tee is introduced in RegStackify,
-  ; which stackifies the use of %addr in store instruction. A tee has two dest
-  ; registers, the first of which is stackified and the second is not.
-  ; But when we introduce a nested try-delegate in fixCallUnwindMismatches in
-  ; CFGStackify, it is possible that we end up unstackifying the first dest
-  ; register. In that case, we convert that tee into a copy.
-  %addr = inttoptr i32 %t to ptr
-  %load = load i32, ptr %addr
-  %call = call i32 @baz()
-  %add = add i32 %load, %call
-  store i32 %add, ptr %addr
-  ret void
-; NOSORT-LOCALS:       i32.add
-; NOSORT-LOCALS-NOT:   local.tee
-; NOSORT-LOCALS-NEXT:  local.set
-
-catch.dispatch0:                                  ; preds = %bb0
-  %0 = catchswitch within none [label %catch.start0] unwind to caller
-
-catch.start0:                                     ; preds = %catch.dispatch0
-  %1 = catchpad within %0 [ptr null]
-  %2 = call ptr @llvm.wasm.get.exception(token %1)
-  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
-  catchret from %1 to label %try.cont
-
-try.cont:                                         ; preds = %catch.start0
-  ret void
-}
-
 ; We have two call unwind unwind mismatches:
 ; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the
 ;   CFG, when it is supposed to unwind to another EH pad.
@@ -668,7 +672,6 @@ try.cont:                                         ; preds = %catch.start0
 ; NOSORT:   call  __cxa_end_catch
 ; NOSORT: end_try
 ; NOSORT: return
-
 define void @unwind_mismatches_4() personality ptr @__gxx_wasm_personality_v0 {
 bb0:
   invoke void @foo()
@@ -704,6 +707,135 @@ try.cont:                                         ; preds = %catch.start1, %catc
   ret void
 }
 
+; 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: unwind_mismatches_5:
+; CHECK: try
+; --- try-delegate starts (call unwind mismatch)
+; CHECK:   try
+; CHECK:     call $[[RET:[0-9]+]]=, baz
+; CHECK:   delegate  1
+; --- try-delegate ends (call unwind mismatch)
+; CHECK:    call  quux, $[[RET]]
+; CHECK: catch_all
+; CHECK: end_try
+define void @unwind_mismatches_5() personality ptr @__gxx_wasm_personality_v0 {
+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
+}
+
+; The structure is similar to unwind_mismatches_0, where the call to 'bar''s
+; original unwind destination is catch.dispatch1 but after placing markers it
+; unwinds to catch.dispatch0, which we fix. This additionally has a loop before
+; the real unwind destination (catch.dispatch1).
+
+; NOSORT-LABEL: unwind_mismatches_with_loop:
+; NOSORT: try
+; NOSORT:   try
+; NOSORT:     try
+; NOSORT:       call  foo
+; NOSORT:       try
+; NOSORT:         call  bar
+; NOSORT:       delegate    3                  # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
+; NOSORT:     catch  $drop=, __cpp_exception
+; NOSORT:     end_try
+; NOSORT:   delegate    2                      # label/catch{{[0-9]+}}: to caller
+; NOSORT:   loop
+; NOSORT:     call  foo
+; NOSORT:   end_loop
+; NOSORT: catch  $drop=, __cpp_exception       # catch[[C0]]:
+; NOSORT:   return
+; NOSORT: end_try
+define void @unwind_mismatches_with_loop() personality ptr @__gxx_wasm_personality_v0 {
+bb0:
+  invoke void @foo()
+          to label %bb1 unwind label %catch.dispatch0
+
+bb1:                                              ; preds = %bb0
+  invoke void @bar()
+          to label %bb2 unwind label %catch.dispatch1
+
+catch.dispatch0:                                  ; preds = %bb0
+  %0 = catchswitch within none [label %catch.start0] unwind to caller
+
+catch.start0:                                     ; preds = %catch.dispatch0
+  %1 = catchpad within %0 [ptr null]
+  %2 = call ptr @llvm.wasm.get.exception(token %1)
+  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
+  catchret from %1 to label %bb2
+
+bb2:
+  invoke void @foo()
+          to label %bb3 unwind label %catch.dispatch1
+
+bb3:                                             ; preds = %bb14
+  br label %bb2
+
+catch.dispatch1:                                  ; preds = %bb1
+  %4 = catchswitch within none [label %catch.start1] unwind to caller
+
+catch.start1:                                     ; preds = %catch.dispatch1
+  %5 = catchpad within %4 [ptr null]
+  %6 = call ptr @llvm.wasm.get.exception(token %5)
+  %7 = call i32 @llvm.wasm.get.ehselector(token %5)
+  catchret from %5 to label %try.cont
+
+try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1
+  ret void
+}
+
+; Tests the case when TEE stackifies a register in RegStackify but it gets
+; unstackified in fixCallUnwindMismatches in CFGStackify.
+
+; NOSORT-LOCALS-LABEL: unstackify_when_fixing_unwind_mismatch:
+define void @unstackify_when_fixing_unwind_mismatch(i32 %x) personality ptr @__gxx_wasm_personality_v0 {
+bb0:
+  invoke void @foo()
+          to label %bb1 unwind label %catch.dispatch0
+
+bb1:                                              ; preds = %bb0
+  %t = add i32 %x, 4
+  ; This %addr is used in multiple places, so tee is introduced in RegStackify,
+  ; which stackifies the use of %addr in store instruction. A tee has two dest
+  ; registers, the first of which is stackified and the second is not.
+  ; But when we introduce a nested try-delegate in fixCallUnwindMismatches in
+  ; CFGStackify, we end up unstackifying the first dest register. In that case,
+  ; we convert that tee into a copy.
+  %addr = inttoptr i32 %t to ptr
+  %load = load i32, ptr %addr
+  %call = call i32 @baz()
+  %add = add i32 %load, %call
+  store i32 %add, ptr %addr
+  ret void
+; NOSORT-LOCALS:       i32.add
+; NOSORT-LOCALS-NOT:   local.tee
+; NOSORT-LOCALS-NEXT:  local.set
+
+catch.dispatch0:                                  ; preds = %bb0
+  %0 = catchswitch within none [label %catch.start0] unwind to caller
+
+catch.start0:                                     ; preds = %catch.dispatch0
+  %1 = catchpad within %0 [ptr null]
+  %2 = call ptr @llvm.wasm.get.exception(token %1)
+  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
+  catchret from %1 to label %try.cont
+
+try.cont:                                         ; preds = %catch.start0
+  ret void
+}
+
 ; In CFGSort, EH pads should be sorted as soon as it is available and
 ; 'Preferred' queue and should NOT be entered into 'Ready' queue unless we are
 ; in the middle of sorting another region that does not contain the EH pad. In
@@ -1004,11 +1136,13 @@ invoke.cont2:                                     ; preds = %catch.start
 ; to the exception, but does not belong to the loop (because it does not have a
 ; path back to the loop header), and is placed after the loop latch block
 ; 'invoke.cont' intentionally. This tests if 'end_loop' marker is placed
-; correctly not right after 'invoke.cont' part but after 'ehcleanup' part,
+; correctly not right after 'invoke.cont' part but after 'ehcleanup' part.
 ; NOSORT-LABEL: loop_contains_exception:
 ; NOSORT: loop
-; NOSORT: try
-; NOSORT: end_try
+; NOSORT:   try
+; NOSORT:     try
+; NOSORT:     end_try
+; NOSORT:   end_try
 ; NOSORT: end_loop
 define void @loop_contains_exception(i32 %n) personality ptr @__gxx_wasm_personality_v0 {
 entry:
@@ -1094,33 +1228,6 @@ ehcleanup:                                        ; preds = %if.then
   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: unwind_mismatches_5:
-; 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 @unwind_mismatches_5() personality ptr @__gxx_wasm_personality_v0 {
-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
-}
-
 ; This tests if invalidated branch destinations after fixing catch unwind
 ; mismatches are correctly remapped. For example, we have this code and suppose
 ; we need to wrap this try-catch-end in this code with a try-delegate to fix a
@@ -1629,8 +1736,8 @@ unreachable:                                      ; preds = %rethrow, %entry
 }
 
 ; Check if the unwind destination mismatch stats are correct
-; NOSORT: 23 wasm-cfg-stackify    - Number of call unwind mismatches found
-; NOSORT:  4 wasm-cfg-stackify    - Number of catch unwind mismatches found
+; NOSORT: 24 wasm-cfg-stackify    - Number of call unwind mismatches found
+; NOSORT:  5 wasm-cfg-stackify    - Number of catch unwind mismatches found
 
 declare void @foo()
 declare void @bar()



More information about the llvm-commits mailing list