Skip to content

Commit d1d3e4b

Browse files
authored
[WebAssembly] Add/Reorder legacy EH tests (#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.
1 parent 21d25d2 commit d1d3e4b

File tree

1 file changed

+192
-85
lines changed

1 file changed

+192
-85
lines changed

llvm/test/CodeGen/WebAssembly/cfg-stackify-eh-legacy.ll

Lines changed: 192 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -205,16 +205,64 @@ unreachable: ; preds = %rethrow5
205205
unreachable
206206
}
207207

208-
; Nested loop within a catch clause
209-
; void loop_within_catch() {
208+
; Nested try-catches within a try
209+
; void nested_try() {
210210
; try {
211-
; foo();
212-
; } catch (...) {
213-
; for (int i = 0; i < 50; i++)
211+
; try {
214212
; foo();
213+
; } catch (...) {
214+
; }
215+
; } catch (...) {
215216
; }
216217
; }
217218

219+
; CHECK-LABEL: nested_try:
220+
; CHECK: try
221+
; CHECK: try
222+
; CHECK: call foo
223+
; CHECK: catch
224+
; CHECK: call $drop=, __cxa_begin_catch
225+
; CHECK: call __cxa_end_catch
226+
; CHECK: end_try
227+
; CHECK: catch
228+
; CHECK: call $drop=, __cxa_begin_catch
229+
; CHECK: call __cxa_end_catch
230+
; CHECK: end_try
231+
define void @nested_try() personality ptr @__gxx_wasm_personality_v0 {
232+
entry:
233+
invoke void @foo()
234+
to label %try.cont7 unwind label %catch.dispatch
235+
236+
catch.dispatch: ; preds = %entry
237+
%0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch2
238+
239+
catch.start: ; preds = %catch.dispatch
240+
%1 = catchpad within %0 [ptr null]
241+
%2 = call ptr @llvm.wasm.get.exception(token %1)
242+
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
243+
%4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
244+
invoke void @__cxa_end_catch() [ "funclet"(token %1) ]
245+
to label %invoke.cont1 unwind label %catch.dispatch2
246+
247+
catch.dispatch2: ; preds = %catch.start, %catch.dispatch
248+
%5 = catchswitch within none [label %catch.start3] unwind to caller
249+
250+
catch.start3: ; preds = %catch.dispatch2
251+
%6 = catchpad within %5 [ptr null]
252+
%7 = call ptr @llvm.wasm.get.exception(token %6)
253+
%8 = call i32 @llvm.wasm.get.ehselector(token %6)
254+
%9 = call ptr @__cxa_begin_catch(ptr %7) [ "funclet"(token %6) ]
255+
call void @__cxa_end_catch() [ "funclet"(token %6) ]
256+
catchret from %6 to label %try.cont7
257+
258+
try.cont7: ; preds = %entry, %invoke.cont1, %catch.start3
259+
ret void
260+
261+
invoke.cont1: ; preds = %catch.start
262+
catchret from %1 to label %try.cont7
263+
}
264+
265+
218266
; CHECK-LABEL: loop_within_catch:
219267
; CHECK: try
220268
; CHECK: call foo
@@ -386,7 +434,7 @@ try.cont: ; preds = %catch.start, %loop
386434
; If 'call foo' throws a foreign exception, it will not be caught by C1, and
387435
; should be rethrown to the caller. But after control flow linearization, it
388436
; will instead unwind to C0, an incorrect next EH pad. We wrap the whole
389-
; try-catch with try-delegate that rethrows an exception to the caller to fix
437+
; try-catch with try-delegate that rethrows the exception to the caller to fix
390438
; this.
391439

392440
; NOSORT-LABEL: unwind_mismatches_0:
@@ -407,7 +455,6 @@ try.cont: ; preds = %catch.start, %loop
407455
; NOSORT: catch {{.*}} # catch[[C0]]:
408456
; NOSORT: end_try
409457
; NOSORT: return
410-
411458
define void @unwind_mismatches_0() personality ptr @__gxx_wasm_personality_v0 {
412459
bb0:
413460
invoke void @foo()
@@ -442,7 +489,7 @@ try.cont: ; preds = %catch.start1, %catc
442489
; 'call bar' and 'call baz''s original unwind destination was the caller, but
443490
; after control flow linearization, their unwind destination incorrectly becomes
444491
; 'C0'. We fix this by wrapping the calls with a nested try-delegate that
445-
; rethrows exceptions to the caller.
492+
; rethrows the exception to the caller.
446493

447494
; And the return value of 'baz' should NOT be stackified because the BB is split
448495
; during fixing unwind mismatches.
@@ -462,7 +509,6 @@ try.cont: ; preds = %catch.start1, %catc
462509
; NOSORT: catch {{.*}} # catch[[C0:[0-9]+]]:
463510
; NOSORT: return
464511
; NOSORT: end_try
465-
466512
define void @unwind_mismatches_1() personality ptr @__gxx_wasm_personality_v0 {
467513
bb0:
468514
invoke void @foo()
@@ -489,7 +535,7 @@ try.cont: ; preds = %catch.start0
489535

490536
; The same as unwind_mismatches_0, but we have one more call 'call @foo' in bb1
491537
; which unwinds to the caller. IN this case bb1 has two call unwind mismatches:
492-
; 'call @foo' unwinds to the caller and 'call @bar' unwinds to catch C0.
538+
; 'call @foo' unwinds to the caller and 'call @bar' unwinds to catch C0.
493539

494540
; NOSORT-LABEL: unwind_mismatches_2:
495541
; NOSORT: try
@@ -514,7 +560,6 @@ try.cont: ; preds = %catch.start0
514560
; NOSORT: catch {{.*}} # catch[[C0]]:
515561
; NOSORT: end_try
516562
; NOSORT: return
517-
518563
define void @unwind_mismatches_2() personality ptr @__gxx_wasm_personality_v0 {
519564
bb0:
520565
invoke void @foo()
@@ -570,7 +615,6 @@ try.cont: ; preds = %catch.start1, %catc
570615
; NOSORT: catch {{.*}} # catch[[C0:[0-9]+]]:
571616
; NOSORT: return
572617
; NOSORT: end_try
573-
574618
define i32 @unwind_mismatches_3() personality ptr @__gxx_wasm_personality_v0 {
575619
bb0:
576620
invoke void @foo()
@@ -593,46 +637,6 @@ try.cont: ; preds = %catch.start0
593637
ret i32 0
594638
}
595639

596-
; Tests the case when TEE stackifies a register in RegStackify but it gets
597-
; unstackified in fixCallUnwindMismatches in CFGStackify.
598-
599-
; NOSORT-LOCALS-LABEL: unstackify_when_fixing_unwind_mismatch:
600-
define void @unstackify_when_fixing_unwind_mismatch(i32 %x) personality ptr @__gxx_wasm_personality_v0 {
601-
bb0:
602-
invoke void @foo()
603-
to label %bb1 unwind label %catch.dispatch0
604-
605-
bb1: ; preds = %bb0
606-
%t = add i32 %x, 4
607-
; This %addr is used in multiple places, so tee is introduced in RegStackify,
608-
; which stackifies the use of %addr in store instruction. A tee has two dest
609-
; registers, the first of which is stackified and the second is not.
610-
; But when we introduce a nested try-delegate in fixCallUnwindMismatches in
611-
; CFGStackify, it is possible that we end up unstackifying the first dest
612-
; register. In that case, we convert that tee into a copy.
613-
%addr = inttoptr i32 %t to ptr
614-
%load = load i32, ptr %addr
615-
%call = call i32 @baz()
616-
%add = add i32 %load, %call
617-
store i32 %add, ptr %addr
618-
ret void
619-
; NOSORT-LOCALS: i32.add
620-
; NOSORT-LOCALS-NOT: local.tee
621-
; NOSORT-LOCALS-NEXT: local.set
622-
623-
catch.dispatch0: ; preds = %bb0
624-
%0 = catchswitch within none [label %catch.start0] unwind to caller
625-
626-
catch.start0: ; preds = %catch.dispatch0
627-
%1 = catchpad within %0 [ptr null]
628-
%2 = call ptr @llvm.wasm.get.exception(token %1)
629-
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
630-
catchret from %1 to label %try.cont
631-
632-
try.cont: ; preds = %catch.start0
633-
ret void
634-
}
635-
636640
; We have two call unwind unwind mismatches:
637641
; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the
638642
; CFG, when it is supposed to unwind to another EH pad.
@@ -668,7 +672,6 @@ try.cont: ; preds = %catch.start0
668672
; NOSORT: call __cxa_end_catch
669673
; NOSORT: end_try
670674
; NOSORT: return
671-
672675
define void @unwind_mismatches_4() personality ptr @__gxx_wasm_personality_v0 {
673676
bb0:
674677
invoke void @foo()
@@ -704,6 +707,135 @@ try.cont: ; preds = %catch.start1, %catc
704707
ret void
705708
}
706709

710+
; This crashed when updating EHPadStack within fixCallUniwindMismatch had a bug.
711+
; This should not crash and try-delegate has to be created around 'call @baz',
712+
; because the initial TRY placement for 'call @quux' was done before 'call @baz'
713+
; because 'call @baz''s return value is stackified.
714+
715+
; CHECK-LABEL: unwind_mismatches_5:
716+
; CHECK: try
717+
; --- try-delegate starts (call unwind mismatch)
718+
; CHECK: try
719+
; CHECK: call $[[RET:[0-9]+]]=, baz
720+
; CHECK: delegate 1
721+
; --- try-delegate ends (call unwind mismatch)
722+
; CHECK: call quux, $[[RET]]
723+
; CHECK: catch_all
724+
; CHECK: end_try
725+
define void @unwind_mismatches_5() personality ptr @__gxx_wasm_personality_v0 {
726+
entry:
727+
%call = call i32 @baz()
728+
invoke void @quux(i32 %call)
729+
to label %invoke.cont unwind label %ehcleanup
730+
731+
ehcleanup: ; preds = %entry
732+
%0 = cleanuppad within none []
733+
cleanupret from %0 unwind to caller
734+
735+
invoke.cont: ; preds = %entry
736+
unreachable
737+
}
738+
739+
; The structure is similar to unwind_mismatches_0, where the call to 'bar''s
740+
; original unwind destination is catch.dispatch1 but after placing markers it
741+
; unwinds to catch.dispatch0, which we fix. This additionally has a loop before
742+
; the real unwind destination (catch.dispatch1).
743+
744+
; NOSORT-LABEL: unwind_mismatches_with_loop:
745+
; NOSORT: try
746+
; NOSORT: try
747+
; NOSORT: try
748+
; NOSORT: call foo
749+
; NOSORT: try
750+
; NOSORT: call bar
751+
; NOSORT: delegate 3 # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
752+
; NOSORT: catch $drop=, __cpp_exception
753+
; NOSORT: end_try
754+
; NOSORT: delegate 2 # label/catch{{[0-9]+}}: to caller
755+
; NOSORT: loop
756+
; NOSORT: call foo
757+
; NOSORT: end_loop
758+
; NOSORT: catch $drop=, __cpp_exception # catch[[C0]]:
759+
; NOSORT: return
760+
; NOSORT: end_try
761+
define void @unwind_mismatches_with_loop() personality ptr @__gxx_wasm_personality_v0 {
762+
bb0:
763+
invoke void @foo()
764+
to label %bb1 unwind label %catch.dispatch0
765+
766+
bb1: ; preds = %bb0
767+
invoke void @bar()
768+
to label %bb2 unwind label %catch.dispatch1
769+
770+
catch.dispatch0: ; preds = %bb0
771+
%0 = catchswitch within none [label %catch.start0] unwind to caller
772+
773+
catch.start0: ; preds = %catch.dispatch0
774+
%1 = catchpad within %0 [ptr null]
775+
%2 = call ptr @llvm.wasm.get.exception(token %1)
776+
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
777+
catchret from %1 to label %bb2
778+
779+
bb2:
780+
invoke void @foo()
781+
to label %bb3 unwind label %catch.dispatch1
782+
783+
bb3: ; preds = %bb14
784+
br label %bb2
785+
786+
catch.dispatch1: ; preds = %bb1
787+
%4 = catchswitch within none [label %catch.start1] unwind to caller
788+
789+
catch.start1: ; preds = %catch.dispatch1
790+
%5 = catchpad within %4 [ptr null]
791+
%6 = call ptr @llvm.wasm.get.exception(token %5)
792+
%7 = call i32 @llvm.wasm.get.ehselector(token %5)
793+
catchret from %5 to label %try.cont
794+
795+
try.cont: ; preds = %catch.start1, %catch.start0, %bb1
796+
ret void
797+
}
798+
799+
; Tests the case when TEE stackifies a register in RegStackify but it gets
800+
; unstackified in fixCallUnwindMismatches in CFGStackify.
801+
802+
; NOSORT-LOCALS-LABEL: unstackify_when_fixing_unwind_mismatch:
803+
define void @unstackify_when_fixing_unwind_mismatch(i32 %x) personality ptr @__gxx_wasm_personality_v0 {
804+
bb0:
805+
invoke void @foo()
806+
to label %bb1 unwind label %catch.dispatch0
807+
808+
bb1: ; preds = %bb0
809+
%t = add i32 %x, 4
810+
; This %addr is used in multiple places, so tee is introduced in RegStackify,
811+
; which stackifies the use of %addr in store instruction. A tee has two dest
812+
; registers, the first of which is stackified and the second is not.
813+
; But when we introduce a nested try-delegate in fixCallUnwindMismatches in
814+
; CFGStackify, we end up unstackifying the first dest register. In that case,
815+
; we convert that tee into a copy.
816+
%addr = inttoptr i32 %t to ptr
817+
%load = load i32, ptr %addr
818+
%call = call i32 @baz()
819+
%add = add i32 %load, %call
820+
store i32 %add, ptr %addr
821+
ret void
822+
; NOSORT-LOCALS: i32.add
823+
; NOSORT-LOCALS-NOT: local.tee
824+
; NOSORT-LOCALS-NEXT: local.set
825+
826+
catch.dispatch0: ; preds = %bb0
827+
%0 = catchswitch within none [label %catch.start0] unwind to caller
828+
829+
catch.start0: ; preds = %catch.dispatch0
830+
%1 = catchpad within %0 [ptr null]
831+
%2 = call ptr @llvm.wasm.get.exception(token %1)
832+
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
833+
catchret from %1 to label %try.cont
834+
835+
try.cont: ; preds = %catch.start0
836+
ret void
837+
}
838+
707839
; In CFGSort, EH pads should be sorted as soon as it is available and
708840
; 'Preferred' queue and should NOT be entered into 'Ready' queue unless we are
709841
; in the middle of sorting another region that does not contain the EH pad. In
@@ -1004,11 +1136,13 @@ invoke.cont2: ; preds = %catch.start
10041136
; to the exception, but does not belong to the loop (because it does not have a
10051137
; path back to the loop header), and is placed after the loop latch block
10061138
; 'invoke.cont' intentionally. This tests if 'end_loop' marker is placed
1007-
; correctly not right after 'invoke.cont' part but after 'ehcleanup' part,
1139+
; correctly not right after 'invoke.cont' part but after 'ehcleanup' part.
10081140
; NOSORT-LABEL: loop_contains_exception:
10091141
; NOSORT: loop
1010-
; NOSORT: try
1011-
; NOSORT: end_try
1142+
; NOSORT: try
1143+
; NOSORT: try
1144+
; NOSORT: end_try
1145+
; NOSORT: end_try
10121146
; NOSORT: end_loop
10131147
define void @loop_contains_exception(i32 %n) personality ptr @__gxx_wasm_personality_v0 {
10141148
entry:
@@ -1094,33 +1228,6 @@ ehcleanup: ; preds = %if.then
10941228
cleanupret from %0 unwind to caller
10951229
}
10961230

1097-
; This crashed when updating EHPadStack within fixCallUniwindMismatch had a bug.
1098-
; This should not crash and try-delegate has to be created around 'call @baz',
1099-
; because the initial TRY placement for 'call @quux' was done before 'call @baz'
1100-
; because 'call @baz''s return value is stackified.
1101-
1102-
; CHECK-LABEL: unwind_mismatches_5:
1103-
; CHECK: try
1104-
; CHECK: try
1105-
; CHECK: call $[[RET:[0-9]+]]=, baz
1106-
; CHECK: delegate 1
1107-
; CHECK: call quux, $[[RET]]
1108-
; CHECK: catch_all
1109-
; CHECK: end_try
1110-
define void @unwind_mismatches_5() personality ptr @__gxx_wasm_personality_v0 {
1111-
entry:
1112-
%call = call i32 @baz()
1113-
invoke void @quux(i32 %call)
1114-
to label %invoke.cont unwind label %ehcleanup
1115-
1116-
ehcleanup: ; preds = %entry
1117-
%0 = cleanuppad within none []
1118-
cleanupret from %0 unwind to caller
1119-
1120-
invoke.cont: ; preds = %entry
1121-
unreachable
1122-
}
1123-
11241231
; This tests if invalidated branch destinations after fixing catch unwind
11251232
; mismatches are correctly remapped. For example, we have this code and suppose
11261233
; 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
16291736
}
16301737

16311738
; Check if the unwind destination mismatch stats are correct
1632-
; NOSORT: 23 wasm-cfg-stackify - Number of call unwind mismatches found
1633-
; NOSORT: 4 wasm-cfg-stackify - Number of catch unwind mismatches found
1739+
; NOSORT: 24 wasm-cfg-stackify - Number of call unwind mismatches found
1740+
; NOSORT: 5 wasm-cfg-stackify - Number of catch unwind mismatches found
16341741

16351742
declare void @foo()
16361743
declare void @bar()

0 commit comments

Comments
 (0)