@@ -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-
411458define void @unwind_mismatches_0 () personality ptr @__gxx_wasm_personality_v0 {
412459bb0:
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-
466512define void @unwind_mismatches_1 () personality ptr @__gxx_wasm_personality_v0 {
467513bb0:
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-
518563define void @unwind_mismatches_2 () personality ptr @__gxx_wasm_personality_v0 {
519564bb0:
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-
574618define i32 @unwind_mismatches_3 () personality ptr @__gxx_wasm_personality_v0 {
575619bb0:
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-
672675define void @unwind_mismatches_4 () personality ptr @__gxx_wasm_personality_v0 {
673676bb0:
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
10131147define void @loop_contains_exception (i32 %n ) personality ptr @__gxx_wasm_personality_v0 {
10141148entry:
@@ -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
16351742declare void @foo ()
16361743declare void @bar ()
0 commit comments