[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