@@ -205,16 +205,64 @@ unreachable: ; preds = %rethrow5
205
205
unreachable
206
206
}
207
207
208
- ; Nested loop within a catch clause
209
- ; void loop_within_catch () {
208
+ ; Nested try-catches within a try
209
+ ; void nested_try () {
210
210
; try {
211
- ; foo();
212
- ; } catch (...) {
213
- ; for (int i = 0; i < 50; i++)
211
+ ; try {
214
212
; foo();
213
+ ; } catch (...) {
214
+ ; }
215
+ ; } catch (...) {
215
216
; }
216
217
; }
217
218
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
+
218
266
; CHECK-LABEL: loop_within_catch:
219
267
; CHECK: try
220
268
; CHECK: call foo
@@ -386,7 +434,7 @@ try.cont: ; preds = %catch.start, %loop
386
434
; If 'call foo' throws a foreign exception, it will not be caught by C1, and
387
435
; should be rethrown to the caller. But after control flow linearization, it
388
436
; 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
390
438
; this.
391
439
392
440
; NOSORT-LABEL: unwind_mismatches_0:
@@ -407,7 +455,6 @@ try.cont: ; preds = %catch.start, %loop
407
455
; NOSORT: catch {{.*}} # catch[[C0]]:
408
456
; NOSORT: end_try
409
457
; NOSORT: return
410
-
411
458
define void @unwind_mismatches_0 () personality ptr @__gxx_wasm_personality_v0 {
412
459
bb0:
413
460
invoke void @foo ()
@@ -442,7 +489,7 @@ try.cont: ; preds = %catch.start1, %catc
442
489
; 'call bar' and 'call baz''s original unwind destination was the caller, but
443
490
; after control flow linearization, their unwind destination incorrectly becomes
444
491
; '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.
446
493
447
494
; And the return value of 'baz' should NOT be stackified because the BB is split
448
495
; during fixing unwind mismatches.
@@ -462,7 +509,6 @@ try.cont: ; preds = %catch.start1, %catc
462
509
; NOSORT: catch {{.*}} # catch[[C0:[0-9]+]]:
463
510
; NOSORT: return
464
511
; NOSORT: end_try
465
-
466
512
define void @unwind_mismatches_1 () personality ptr @__gxx_wasm_personality_v0 {
467
513
bb0:
468
514
invoke void @foo ()
@@ -489,7 +535,7 @@ try.cont: ; preds = %catch.start0
489
535
490
536
; The same as unwind_mismatches_0, but we have one more call 'call @foo' in bb1
491
537
; 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.
493
539
494
540
; NOSORT-LABEL: unwind_mismatches_2:
495
541
; NOSORT: try
@@ -514,7 +560,6 @@ try.cont: ; preds = %catch.start0
514
560
; NOSORT: catch {{.*}} # catch[[C0]]:
515
561
; NOSORT: end_try
516
562
; NOSORT: return
517
-
518
563
define void @unwind_mismatches_2 () personality ptr @__gxx_wasm_personality_v0 {
519
564
bb0:
520
565
invoke void @foo ()
@@ -570,7 +615,6 @@ try.cont: ; preds = %catch.start1, %catc
570
615
; NOSORT: catch {{.*}} # catch[[C0:[0-9]+]]:
571
616
; NOSORT: return
572
617
; NOSORT: end_try
573
-
574
618
define i32 @unwind_mismatches_3 () personality ptr @__gxx_wasm_personality_v0 {
575
619
bb0:
576
620
invoke void @foo ()
@@ -593,46 +637,6 @@ try.cont: ; preds = %catch.start0
593
637
ret i32 0
594
638
}
595
639
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
-
636
640
; We have two call unwind unwind mismatches:
637
641
; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the
638
642
; CFG, when it is supposed to unwind to another EH pad.
@@ -668,7 +672,6 @@ try.cont: ; preds = %catch.start0
668
672
; NOSORT: call __cxa_end_catch
669
673
; NOSORT: end_try
670
674
; NOSORT: return
671
-
672
675
define void @unwind_mismatches_4 () personality ptr @__gxx_wasm_personality_v0 {
673
676
bb0:
674
677
invoke void @foo ()
@@ -704,6 +707,135 @@ try.cont: ; preds = %catch.start1, %catc
704
707
ret void
705
708
}
706
709
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
+
707
839
; In CFGSort, EH pads should be sorted as soon as it is available and
708
840
; 'Preferred' queue and should NOT be entered into 'Ready' queue unless we are
709
841
; in the middle of sorting another region that does not contain the EH pad. In
@@ -1004,11 +1136,13 @@ invoke.cont2: ; preds = %catch.start
1004
1136
; to the exception, but does not belong to the loop (because it does not have a
1005
1137
; path back to the loop header), and is placed after the loop latch block
1006
1138
; '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.
1008
1140
; NOSORT-LABEL: loop_contains_exception:
1009
1141
; NOSORT: loop
1010
- ; NOSORT: try
1011
- ; NOSORT: end_try
1142
+ ; NOSORT: try
1143
+ ; NOSORT: try
1144
+ ; NOSORT: end_try
1145
+ ; NOSORT: end_try
1012
1146
; NOSORT: end_loop
1013
1147
define void @loop_contains_exception (i32 %n ) personality ptr @__gxx_wasm_personality_v0 {
1014
1148
entry:
@@ -1094,33 +1228,6 @@ ehcleanup: ; preds = %if.then
1094
1228
cleanupret from %0 unwind to caller
1095
1229
}
1096
1230
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
-
1124
1231
; This tests if invalidated branch destinations after fixing catch unwind
1125
1232
; mismatches are correctly remapped. For example, we have this code and suppose
1126
1233
; 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
1629
1736
}
1630
1737
1631
1738
; 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
1634
1741
1635
1742
declare void @foo ()
1636
1743
declare void @bar ()
0 commit comments