1; REQUIRES: asserts
2; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling | FileCheck %s
3; RUN: llc < %s -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling
4; RUN: llc < %s -O0 -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -verify-machineinstrs -exception-model=wasm -mattr=+exception-handling | FileCheck %s --check-prefix=NOOPT
5; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling -wasm-disable-ehpad-sort -stats 2>&1 | FileCheck %s --check-prefix=NOSORT
6; RUN: llc < %s -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling -wasm-disable-ehpad-sort | FileCheck %s --check-prefix=NOSORT-LOCALS
7
8target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
9target triple = "wasm32-unknown-unknown"
10
11@_ZTIi = external constant i8*
12@_ZTId = external constant i8*
13
14%class.Object = type { i8 }
15%class.MyClass = type { i32 }
16
17; Simple test case with two catch clauses
18;
19; void foo();
20; void test0() {
21;   try {
22;     foo();
23;   } catch (int) {
24;   } catch (double) {
25;   }
26; }
27
28; CHECK-LABEL: test0
29; CHECK: try
30; CHECK:   call      foo
31; CHECK: catch
32; CHECK:   block
33; CHECK:     br_if     0, {{.*}}                       # 0: down to label[[L0:[0-9]+]]
34; CHECK:     call      $drop=, __cxa_begin_catch
35; CHECK:     call      __cxa_end_catch
36; CHECK:     br        1                               # 1: down to label[[L1:[0-9]+]]
37; CHECK:   end_block                                   # label[[L0]]:
38; CHECK:   block
39; CHECK:     br_if     0, {{.*}}                       # 0: down to label[[L2:[0-9]+]]
40; CHECK:     call      $drop=, __cxa_begin_catch
41; CHECK:     call      __cxa_end_catch
42; CHECK:     br        1                               # 1: down to label[[L1]]
43; CHECK:   end_block                                   # label[[L2]]:
44; CHECK:   rethrow   0                                 # to caller
45; CHECK: end_try                                       # label[[L1]]:
46define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
47entry:
48  invoke void @foo()
49          to label %try.cont unwind label %catch.dispatch
50
51catch.dispatch:                                   ; preds = %entry
52  %0 = catchswitch within none [label %catch.start] unwind to caller
53
54catch.start:                                      ; preds = %catch.dispatch
55  %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)]
56  %2 = call i8* @llvm.wasm.get.exception(token %1)
57  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
58  %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
59  %matches = icmp eq i32 %3, %4
60  br i1 %matches, label %catch2, label %catch.fallthrough
61
62catch2:                                           ; preds = %catch.start
63  %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
64  call void @__cxa_end_catch() [ "funclet"(token %1) ]
65  catchret from %1 to label %try.cont
66
67catch.fallthrough:                                ; preds = %catch.start
68  %6 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*))
69  %matches1 = icmp eq i32 %3, %6
70  br i1 %matches1, label %catch, label %rethrow
71
72catch:                                            ; preds = %catch.fallthrough
73  %7 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
74  call void @__cxa_end_catch() [ "funclet"(token %1) ]
75  catchret from %1 to label %try.cont
76
77rethrow:                                          ; preds = %catch.fallthrough
78  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
79  unreachable
80
81try.cont:                                         ; preds = %catch, %catch2, %entry
82  ret void
83}
84
85; Nested try-catches within a catch
86; void test1() {
87;   try {
88;     foo();
89;   } catch (int) {
90;     try {
91;       foo();
92;     } catch (int) {
93;       foo();
94;     }
95;   }
96; }
97
98; CHECK-LABEL: test1
99; CHECK: try
100; CHECK:   call  foo
101; CHECK: catch
102; CHECK:   block
103; CHECK:     block
104; CHECK:       br_if     0, {{.*}}                     # 0: down to label[[L0:[0-9+]]]
105; CHECK:       call  $drop=, __cxa_begin_catch, $0
106; CHECK:       try
107; CHECK:         try
108; CHECK:           call  foo
109; CHECK:           br        3                         # 3: down to label[[L1:[0-9+]]]
110; CHECK:         catch
111; CHECK:           block
112; CHECK:             block
113; CHECK:               br_if     0, {{.*}}             # 0: down to label[[L2:[0-9+]]]
114; CHECK:               call  $drop=, __cxa_begin_catch
115; CHECK:               try
116; CHECK:                 call  foo
117; CHECK:                 br        2                   # 2: down to label[[L3:[0-9+]]]
118; CHECK:               catch_all
119; CHECK:                 call  __cxa_end_catch
120; CHECK:                 rethrow   0                   # down to catch[[L4:[0-9+]]]
121; CHECK:               end_try
122; CHECK:             end_block                         # label[[L2]]:
123; CHECK:             rethrow   1                       # down to catch[[L4]]
124; CHECK:           end_block                           # label[[L3]]:
125; CHECK:           call  __cxa_end_catch
126; CHECK:           br        3                         # 3: down to label[[L1]]
127; CHECK:         end_try
128; CHECK:       catch_all                               # catch[[L4]]:
129; CHECK:         call  __cxa_end_catch
130; CHECK:         rethrow   0                           # to caller
131; CHECK:       end_try
132; CHECK:     end_block                                 # label[[L0]]:
133; CHECK:     rethrow   1                               # to caller
134; CHECK:   end_block                                   # label[[L1]]:
135; CHECK:   call  __cxa_end_catch
136; CHECK: end_try
137define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
138entry:
139  invoke void @foo()
140          to label %try.cont11 unwind label %catch.dispatch
141
142catch.dispatch:                                   ; preds = %entry
143  %0 = catchswitch within none [label %catch.start] unwind to caller
144
145catch.start:                                      ; preds = %catch.dispatch
146  %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
147  %2 = call i8* @llvm.wasm.get.exception(token %1)
148  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
149  %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
150  %matches = icmp eq i32 %3, %4
151  br i1 %matches, label %catch, label %rethrow
152
153catch:                                            ; preds = %catch.start
154  %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
155  %6 = bitcast i8* %5 to i32*
156  %7 = load i32, i32* %6, align 4
157  invoke void @foo() [ "funclet"(token %1) ]
158          to label %try.cont unwind label %catch.dispatch2
159
160catch.dispatch2:                                  ; preds = %catch
161  %8 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup9
162
163catch.start3:                                     ; preds = %catch.dispatch2
164  %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)]
165  %10 = call i8* @llvm.wasm.get.exception(token %9)
166  %11 = call i32 @llvm.wasm.get.ehselector(token %9)
167  %12 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
168  %matches4 = icmp eq i32 %11, %12
169  br i1 %matches4, label %catch6, label %rethrow5
170
171catch6:                                           ; preds = %catch.start3
172  %13 = call i8* @__cxa_begin_catch(i8* %10) [ "funclet"(token %9) ]
173  %14 = bitcast i8* %13 to i32*
174  %15 = load i32, i32* %14, align 4
175  invoke void @foo() [ "funclet"(token %9) ]
176          to label %invoke.cont8 unwind label %ehcleanup
177
178invoke.cont8:                                     ; preds = %catch6
179  call void @__cxa_end_catch() [ "funclet"(token %9) ]
180  catchret from %9 to label %try.cont
181
182rethrow5:                                         ; preds = %catch.start3
183  invoke void @llvm.wasm.rethrow() [ "funclet"(token %9) ]
184          to label %unreachable unwind label %ehcleanup9
185
186try.cont:                                         ; preds = %invoke.cont8, %catch
187  call void @__cxa_end_catch() [ "funclet"(token %1) ]
188  catchret from %1 to label %try.cont11
189
190rethrow:                                          ; preds = %catch.start
191  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
192  unreachable
193
194try.cont11:                                       ; preds = %try.cont, %entry
195  ret void
196
197ehcleanup:                                        ; preds = %catch6
198  %16 = cleanuppad within %9 []
199  call void @__cxa_end_catch() [ "funclet"(token %16) ]
200  cleanupret from %16 unwind label %ehcleanup9
201
202ehcleanup9:                                       ; preds = %ehcleanup, %rethrow5, %catch.dispatch2
203  %17 = cleanuppad within %1 []
204  call void @__cxa_end_catch() [ "funclet"(token %17) ]
205  cleanupret from %17 unwind to caller
206
207unreachable:                                      ; preds = %rethrow5
208  unreachable
209}
210
211; Nested loop within a catch clause
212; void test2() {
213;   try {
214;     foo();
215;   } catch (...) {
216;     for (int i = 0; i < 50; i++)
217;       foo();
218;   }
219; }
220
221; CHECK-LABEL: test2
222; CHECK: try
223; CHECK:   call      foo
224; CHECK: catch
225; CHECK:   call      $drop=, __cxa_begin_catch
226; CHECK:   loop                                        # label[[L0:[0-9]+]]:
227; CHECK:     block
228; CHECK:       block
229; CHECK:         br_if     0, {{.*}}                   # 0: down to label[[L1:[0-9]+]]
230; CHECK:         try
231; CHECK:           call      foo
232; CHECK:           br        2                         # 2: down to label[[L2:[0-9]+]]
233; CHECK:         catch
234; CHECK:           try
235; CHECK:             call      __cxa_end_catch
236; CHECK:           catch_all
237; CHECK:             call      _ZSt9terminatev
238; CHECK:             unreachable
239; CHECK:           end_try
240; CHECK:           rethrow   0                         # to caller
241; CHECK:         end_try
242; CHECK:       end_block                               # label[[L1]]:
243; CHECK:       call      __cxa_end_catch
244; CHECK:       br        2                             # 2: down to label[[L3:[0-9]+]]
245; CHECK:     end_block                                 # label[[L2]]:
246; CHECK:     br        0                               # 0: up to label[[L0]]
247; CHECK:   end_loop
248; CHECK: end_try                                       # label[[L3]]:
249define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
250entry:
251  invoke void @foo()
252          to label %try.cont unwind label %catch.dispatch
253
254catch.dispatch:                                   ; preds = %entry
255  %0 = catchswitch within none [label %catch.start] unwind to caller
256
257catch.start:                                      ; preds = %catch.dispatch
258  %1 = catchpad within %0 [i8* null]
259  %2 = call i8* @llvm.wasm.get.exception(token %1)
260  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
261  %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
262  br label %for.cond
263
264for.cond:                                         ; preds = %for.inc, %catch.start
265  %i.0 = phi i32 [ 0, %catch.start ], [ %inc, %for.inc ]
266  %cmp = icmp slt i32 %i.0, 50
267  br i1 %cmp, label %for.body, label %for.end
268
269for.body:                                         ; preds = %for.cond
270  invoke void @foo() [ "funclet"(token %1) ]
271          to label %for.inc unwind label %ehcleanup
272
273for.inc:                                          ; preds = %for.body
274  %inc = add nsw i32 %i.0, 1
275  br label %for.cond
276
277for.end:                                          ; preds = %for.cond
278  call void @__cxa_end_catch() [ "funclet"(token %1) ]
279  catchret from %1 to label %try.cont
280
281try.cont:                                         ; preds = %for.end, %entry
282  ret void
283
284ehcleanup:                                        ; preds = %for.body
285  %5 = cleanuppad within %1 []
286  invoke void @__cxa_end_catch() [ "funclet"(token %5) ]
287          to label %invoke.cont2 unwind label %terminate
288
289invoke.cont2:                                     ; preds = %ehcleanup
290  cleanupret from %5 unwind to caller
291
292terminate:                                        ; preds = %ehcleanup
293  %6 = cleanuppad within %5 []
294  call void @_ZSt9terminatev() [ "funclet"(token %6) ]
295  unreachable
296}
297
298; Tests if block and try markers are correctly placed. Even if two predecessors
299; of the EH pad are bb2 and bb3 and their nearest common dominator is bb1, the
300; TRY marker should be placed at bb0 because there's a branch from bb0 to bb2,
301; and scopes cannot be interleaved.
302
303; NOOPT-LABEL: test3
304; NOOPT: try
305; NOOPT:   block
306; NOOPT:     block
307; NOOPT:       block
308; NOOPT:       end_block
309; NOOPT:     end_block
310; NOOPT:     call      foo
311; NOOPT:   end_block
312; NOOPT:   call      bar
313; NOOPT: catch     {{.*}}
314; NOOPT: end_try
315define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
316bb0:
317  br i1 undef, label %bb1, label %bb2
318
319bb1:                                              ; preds = %bb0
320  br i1 undef, label %bb3, label %bb4
321
322bb2:                                              ; preds = %bb0
323  br label %try.cont
324
325bb3:                                              ; preds = %bb1
326  invoke void @foo()
327          to label %try.cont unwind label %catch.dispatch
328
329bb4:                                              ; preds = %bb1
330  invoke void @bar()
331          to label %try.cont unwind label %catch.dispatch
332
333catch.dispatch:                                   ; preds = %bb4, %bb3
334  %0 = catchswitch within none [label %catch.start] unwind to caller
335
336catch.start:                                      ; preds = %catch.dispatch
337  %1 = catchpad within %0 [i8* null]
338  %2 = call i8* @llvm.wasm.get.exception(token %1)
339  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
340  catchret from %1 to label %try.cont
341
342try.cont:                                         ; preds = %catch.start, %bb4, %bb3, %bb2
343  ret void
344}
345
346; Tests if try/end_try markers are placed correctly wrt loop/end_loop markers,
347; when try and loop markers are in the same BB and end_try and end_loop are in
348; another BB.
349; CHECK: loop
350; CHECK:   try
351; CHECK:     call      foo
352; CHECK:   catch
353; CHECK:   end_try
354; CHECK: end_loop
355define void @test4(i32* %p) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
356entry:
357  store volatile i32 0, i32* %p
358  br label %loop
359
360loop:                                             ; preds = %try.cont, %entry
361  store volatile i32 1, i32* %p
362  invoke void @foo()
363          to label %try.cont unwind label %catch.dispatch
364
365catch.dispatch:                                   ; preds = %loop
366  %0 = catchswitch within none [label %catch.start] unwind to caller
367
368catch.start:                                      ; preds = %catch.dispatch
369  %1 = catchpad within %0 [i8* null]
370  %2 = call i8* @llvm.wasm.get.exception(token %1)
371  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
372  catchret from %1 to label %try.cont
373
374try.cont:                                         ; preds = %catch.start, %loop
375  br label %loop
376}
377
378; Some of test cases below are hand-tweaked by deleting some library calls to
379; simplify tests and changing the order of basic blocks to cause unwind
380; destination mismatches. And we use -wasm-disable-ehpad-sort to create maximum
381; number of mismatches in several tests below.
382
383; - Call unwind mismatch
384; 'call bar''s original unwind destination was 'C0', but after control flow
385; linearization, its unwind destination incorrectly becomes 'C1'. We fix this by
386; wrapping the call with a nested try-delegate that targets 'C0'.
387; - Catch unwind mismatch
388; If 'call foo' throws a foreign exception, it will not be caught by C1, and
389; should be rethrown to the caller. But after control flow linearization, it
390; will instead unwind to C0, an incorrect next EH pad. We wrap the whole
391; try-catch with try-delegate that rethrows an exception to the caller to fix
392; this.
393
394; NOSORT-LABEL: test5
395; NOSORT: try
396; --- try-delegate starts (catch unwind mismatch)
397; NOSORT    try
398; NOSORT:     try
399; NOSORT:       call  foo
400; --- try-delegate starts (call unwind mismatch)
401; NOSORT:       try
402; NOSORT:         call  bar
403; NOSORT:       delegate    2     # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
404; --- try-delegate ends (call unwind mismatch)
405; NOSORT:     catch   {{.*}}      # catch[[C1:[0-9]+]]:
406; NOSORT:     end_try
407; NOSORT:   delegate    1         # label/catch{{[0-9]+}}: to caller
408; --- try-delegate ends (catch unwind mismatch)
409; NOSORT: catch   {{.*}}          # catch[[C0]]:
410; NOSORT: end_try
411; NOSORT: return
412
413define void @test5() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
414bb0:
415  invoke void @foo()
416          to label %bb1 unwind label %catch.dispatch0
417
418bb1:                                              ; preds = %bb0
419  invoke void @bar()
420          to label %try.cont unwind label %catch.dispatch1
421
422catch.dispatch0:                                  ; preds = %bb0
423  %0 = catchswitch within none [label %catch.start0] unwind to caller
424
425catch.start0:                                     ; preds = %catch.dispatch0
426  %1 = catchpad within %0 [i8* null]
427  %2 = call i8* @llvm.wasm.get.exception(token %1)
428  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
429  catchret from %1 to label %try.cont
430
431catch.dispatch1:                                  ; preds = %bb1
432  %4 = catchswitch within none [label %catch.start1] unwind to caller
433
434catch.start1:                                     ; preds = %catch.dispatch1
435  %5 = catchpad within %4 [i8* null]
436  %6 = call i8* @llvm.wasm.get.exception(token %5)
437  %7 = call i32 @llvm.wasm.get.ehselector(token %5)
438  catchret from %5 to label %try.cont
439
440try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1
441  ret void
442}
443
444; 'call bar' and 'call baz''s original unwind destination was the caller, but
445; after control flow linearization, their unwind destination incorrectly becomes
446; 'C0'. We fix this by wrapping the calls with a nested try-delegate that
447; rethrows exceptions to the caller.
448
449; And the return value of 'baz' should NOT be stackified because the BB is split
450; during fixing unwind mismatches.
451
452; NOSORT-LABEL: test6
453; NOSORT: try
454; NOSORT:   call  foo
455; --- try-delegate starts (call unwind mismatch)
456; NOSORT:   try
457; NOSORT:     call  bar
458; NOSORT:     call  $[[RET:[0-9]+]]=, baz
459; NOSORT-NOT: call  $push{{.*}}=, baz
460; NOSORT:   delegate    1                     # label/catch{{[0-9]+}}: to caller
461; --- try-delegate ends (call unwind mismatch)
462; NOSORT:   call  nothrow, $[[RET]]
463; NOSORT:   return
464; NOSORT: catch   {{.*}}                      # catch[[C0:[0-9]+]]:
465; NOSORT:   return
466; NOSORT: end_try
467
468define void @test6() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
469bb0:
470  invoke void @foo()
471          to label %bb1 unwind label %catch.dispatch0
472
473bb1:                                              ; preds = %bb0
474  call void @bar()
475  %call = call i32 @baz()
476  call void @nothrow(i32 %call) #0
477  ret void
478
479catch.dispatch0:                                  ; preds = %bb0
480  %0 = catchswitch within none [label %catch.start0] unwind to caller
481
482catch.start0:                                     ; preds = %catch.dispatch0
483  %1 = catchpad within %0 [i8* null]
484  %2 = call i8* @llvm.wasm.get.exception(token %1)
485  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
486  catchret from %1 to label %try.cont
487
488try.cont:                                         ; preds = %catch.start0
489  ret void
490}
491
492; The same as test5, but we have one more call 'call @foo' in bb1 which unwinds
493; to the caller. IN this case bb1 has two call unwind mismatches: 'call @foo'
494; unwinds to the caller and 'call @bar' unwinds to catch C0.
495
496; NOSORT-LABEL: test7
497; NOSORT: try
498; --- try-delegate starts (catch unwind mismatch)
499; NOSORT    try
500; NOSORT:     try
501; NOSORT:       call  foo
502; --- try-delegate starts (call unwind mismatch)
503; NOSORT:       try
504; NOSORT:         call  foo
505; NOSORT:       delegate    3     # label/catch{{[0-9]+}}: to caller
506; --- try-delegate ends (call unwind mismatch)
507; --- try-delegate starts (call unwind mismatch)
508; NOSORT:       try
509; NOSORT:         call  bar
510; NOSORT:       delegate    2     # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
511; --- try-delegate ends (call unwind mismatch)
512; NOSORT:     catch   {{.*}}      # catch[[C1:[0-9]+]]:
513; NOSORT:     end_try
514; NOSORT:   delegate    1         # label/catch{{[0-9]+}}: to caller
515; --- try-delegate ends (catch unwind mismatch)
516; NOSORT: catch   {{.*}}        # catch[[C0]]:
517; NOSORT: end_try
518; NOSORT: return
519
520define void @test7() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
521bb0:
522  invoke void @foo()
523          to label %bb1 unwind label %catch.dispatch0
524
525bb1:                                              ; preds = %bb0
526  call void @foo()
527  invoke void @bar()
528          to label %try.cont unwind label %catch.dispatch1
529
530catch.dispatch0:                                  ; preds = %bb0
531  %0 = catchswitch within none [label %catch.start0] unwind to caller
532
533catch.start0:                                     ; preds = %catch.dispatch0
534  %1 = catchpad within %0 [i8* null]
535  %2 = call i8* @llvm.wasm.get.exception(token %1)
536  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
537  catchret from %1 to label %try.cont
538
539catch.dispatch1:                                  ; preds = %bb1
540  %4 = catchswitch within none [label %catch.start1] unwind to caller
541
542catch.start1:                                     ; preds = %catch.dispatch1
543  %5 = catchpad within %4 [i8* null]
544  %6 = call i8* @llvm.wasm.get.exception(token %5)
545  %7 = call i32 @llvm.wasm.get.ehselector(token %5)
546  catchret from %5 to label %try.cont
547
548try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1
549  ret void
550}
551
552; Similar situation as @test6. Here 'call @qux''s original unwind destination
553; was the caller, but after control flow linearization, their unwind destination
554; incorrectly becomes 'C0' within the function. We fix this by wrapping the call
555; with a nested try-delegate that rethrows the exception to the caller.
556
557; Because 'call @qux' pops an argument pushed by 'i32.const 5' from stack, the
558; nested 'try' should be placed before `i32.const 5', not between 'i32.const 5'
559; and 'call @qux'.
560
561; NOSORT-LABEL: test8
562; NOSORT: try       i32
563; NOSORT:   call  foo
564; --- try-delegate starts (call unwind mismatch)
565; NOSORT:   try
566; NOSORT:     i32.const  $push{{[0-9]+}}=, 5
567; NOSORT:     call  ${{[0-9]+}}=, qux
568; NOSORT:   delegate    1                     # label/catch{{[0-9]+}}: to caller
569; --- try-delegate ends (call unwind mismatch)
570; NOSORT:   return
571; NOSORT: catch   {{.*}}                      # catch[[C0:[0-9]+]]:
572; NOSORT:   return
573; NOSORT: end_try
574
575define i32 @test8() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
576bb0:
577  invoke void @foo()
578          to label %bb1 unwind label %catch.dispatch0
579
580bb1:                                              ; preds = %bb0
581  %0 = call i32 @qux(i32 5)
582  ret i32 %0
583
584catch.dispatch0:                                  ; preds = %bb0
585  %1 = catchswitch within none [label %catch.start0] unwind to caller
586
587catch.start0:                                     ; preds = %catch.dispatch0
588  %2 = catchpad within %1 [i8* null]
589  %3 = call i8* @llvm.wasm.get.exception(token %2)
590  %j = call i32 @llvm.wasm.get.ehselector(token %2)
591  catchret from %2 to label %try.cont
592
593try.cont:                                         ; preds = %catch.start0
594  ret i32 0
595}
596
597; Tests the case when TEE stackifies a register in RegStackify but it gets
598; unstackified in fixCallUnwindMismatches in CFGStackify.
599
600; NOSORT-LOCALS-LABEL: test9
601define void @test9(i32 %x) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
602bb0:
603  invoke void @foo()
604          to label %bb1 unwind label %catch.dispatch0
605
606bb1:                                              ; preds = %bb0
607  %t = add i32 %x, 4
608  ; This %addr is used in multiple places, so tee is introduced in RegStackify,
609  ; which stackifies the use of %addr in store instruction. A tee has two dest
610  ; registers, the first of which is stackified and the second is not.
611  ; But when we introduce a nested try-delegate in fixCallUnwindMismatches in
612  ; CFGStackify, it is possible that we end up unstackifying the first dest
613  ; register. In that case, we convert that tee into a copy.
614  %addr = inttoptr i32 %t to i32*
615  %load = load i32, i32* %addr
616  %call = call i32 @baz()
617  %add = add i32 %load, %call
618  store i32 %add, i32* %addr
619  ret void
620; NOSORT-LOCALS:       i32.add
621; NOSORT-LOCALS-NOT:   local.tee
622; NOSORT-LOCALS-NEXT:  local.set
623
624catch.dispatch0:                                  ; preds = %bb0
625  %0 = catchswitch within none [label %catch.start0] unwind to caller
626
627catch.start0:                                     ; preds = %catch.dispatch0
628  %1 = catchpad within %0 [i8* null]
629  %2 = call i8* @llvm.wasm.get.exception(token %1)
630  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
631  catchret from %1 to label %try.cont
632
633try.cont:                                         ; preds = %catch.start0
634  ret void
635}
636
637; We have two call unwind unwind mismatches:
638; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the
639;   CFG, when it is supposed to unwind to another EH pad.
640; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the
641;   CFG, when it is supposed to unwind to the caller.
642; We also have a catch unwind mismatch: If an exception is not caught by the
643; first catch because it is a non-C++ exception, it shouldn't unwind to the next
644; catch, but it should unwind to the caller.
645
646; NOSORT-LABEL: test10
647; NOSORT: try
648; --- try-delegate starts (catch unwind mismatch)
649; NOSORT:   try
650; NOSORT:     try
651; NOSORT:       call  foo
652; --- try-delegate starts (call unwind mismatch)
653; NOSORT:       try
654; NOSORT:         call  bar
655; NOSORT:       delegate    2            # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
656; --- try-delegate ends (call unwind mismatch)
657; NOSORT:     catch
658; NOSORT:       call  {{.*}} __cxa_begin_catch
659; --- try-delegate starts (call unwind mismatch)
660; NOSORT:       try
661; NOSORT:         call  __cxa_end_catch
662; NOSORT:       delegate    3            # label/catch{{[0-9]+}}: to caller
663; --- try-delegate ends (call unwind mismatch)
664; NOSORT:     end_try
665; NOSORT:   delegate    1                # label/catch{{[0-9]+}}: to caller
666; --- try-delegate ends (catch unwind mismatch)
667; NOSORT: catch  {{.*}}                  # catch[[C0]]:
668; NOSORT:   call  {{.*}} __cxa_begin_catch
669; NOSORT:   call  __cxa_end_catch
670; NOSORT: end_try
671; NOSORT: return
672
673define void @test10() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
674bb0:
675  invoke void @foo()
676          to label %bb1 unwind label %catch.dispatch0
677
678bb1:                                              ; preds = %bb0
679  invoke void @bar()
680          to label %try.cont unwind label %catch.dispatch1
681
682catch.dispatch0:                                  ; preds = %bb0
683  %0 = catchswitch within none [label %catch.start0] unwind to caller
684
685catch.start0:                                     ; preds = %catch.dispatch0
686  %1 = catchpad within %0 [i8* null]
687  %2 = call i8* @llvm.wasm.get.exception(token %1)
688  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
689  %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
690  call void @__cxa_end_catch() [ "funclet"(token %1) ]
691  catchret from %1 to label %try.cont
692
693catch.dispatch1:                                  ; preds = %bb1
694  %5 = catchswitch within none [label %catch.start1] unwind to caller
695
696catch.start1:                                     ; preds = %catch.dispatch1
697  %6 = catchpad within %5 [i8* null]
698  %7 = call i8* @llvm.wasm.get.exception(token %6)
699  %8 = call i32 @llvm.wasm.get.ehselector(token %6)
700  %9 = call i8* @__cxa_begin_catch(i8* %7) [ "funclet"(token %6) ]
701  call void @__cxa_end_catch() [ "funclet"(token %6) ]
702  catchret from %6 to label %try.cont
703
704try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1
705  ret void
706}
707
708; In CFGSort, EH pads should be sorted as soon as it is available and
709; 'Preferred' queue and should NOT be entered into 'Ready' queue unless we are
710; in the middle of sorting another region that does not contain the EH pad. In
711; this example, 'catch.start' should be sorted right after 'if.then' is sorted
712; (before 'cont' is sorted) and there should not be any unwind destination
713; mismatches in CFGStackify.
714
715; NOOPT-LABEL: test11
716; NOOPT: block
717; NOOPT:   try
718; NOOPT:     call      foo
719; NOOPT:   catch
720; NOOPT:   end_try
721; NOOPT:   call      foo
722; NOOPT: end_block
723; NOOPT: return
724define void @test11(i32 %arg) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
725entry:
726  %tobool = icmp ne i32 %arg, 0
727  br i1 %tobool, label %if.then, label %if.end
728
729catch.dispatch:                                   ; preds = %if.then
730  %0 = catchswitch within none [label %catch.start] unwind to caller
731
732catch.start:                                      ; preds = %catch.dispatch
733  %1 = catchpad within %0 [i8* null]
734  %2 = call i8* @llvm.wasm.get.exception(token %1)
735  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
736  %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
737  call void @__cxa_end_catch() [ "funclet"(token %1) ]
738  catchret from %1 to label %if.end
739
740if.then:                                          ; preds = %entry
741  invoke void @foo()
742          to label %cont unwind label %catch.dispatch
743
744cont:                                             ; preds = %if.then
745  call void @foo()
746  br label %if.end
747
748if.end:                                           ; preds = %cont, %catch.start, %entry
749  ret void
750}
751
752; Intrinsics like memcpy, memmove, and memset don't throw and are lowered into
753; calls to external symbols (not global addresses) in instruction selection,
754; which will be eventually lowered to library function calls.
755; Because this test runs with -wasm-disable-ehpad-sort, these library calls in
756; invoke.cont BB fall within try~end_try, but they shouldn't cause crashes or
757; unwinding destination mismatches in CFGStackify.
758
759; NOSORT-LABEL: test12
760; NOSORT: try
761; NOSORT:   call  foo
762; NOSORT:   call {{.*}} memcpy
763; NOSORT:   call {{.*}} memmove
764; NOSORT:   call {{.*}} memset
765; NOSORT:   return
766; NOSORT: catch_all
767; NOSORT:   rethrow 0
768; NOSORT: end_try
769define void @test12(i8* %a, i8* %b) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
770entry:
771  %o = alloca %class.Object, align 1
772  invoke void @foo()
773          to label %invoke.cont unwind label %ehcleanup
774
775invoke.cont:                                      ; preds = %entry
776  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %a, i8* %b, i32 100, i1 false)
777  call void @llvm.memmove.p0i8.p0i8.i32(i8* %a, i8* %b, i32 100, i1 false)
778  call void @llvm.memset.p0i8.i32(i8* %a, i8 0, i32 100, i1 false)
779  %call = call %class.Object* @_ZN6ObjectD2Ev(%class.Object* %o)
780  ret void
781
782ehcleanup:                                        ; preds = %entry
783  %0 = cleanuppad within none []
784  %call2 = call %class.Object* @_ZN6ObjectD2Ev(%class.Object* %o) [ "funclet"(token %0) ]
785  cleanupret from %0 unwind to caller
786}
787
788; Tests if 'try' marker is placed correctly. In this test, 'try' should be
789; placed before the call to 'nothrow_i32' and not between the call to
790; 'nothrow_i32' and 'fun', because the return value of 'nothrow_i32' is
791; stackified and pushed onto the stack to be consumed by the call to 'fun'.
792
793; CHECK-LABEL: test13
794; CHECK: try
795; CHECK: call      $push{{.*}}=, nothrow_i32
796; CHECK: call      fun, $pop{{.*}}
797define void @test13() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
798entry:
799  %call = call i32 @nothrow_i32()
800  invoke void @fun(i32 %call)
801          to label %invoke.cont unwind label %terminate
802
803invoke.cont:                                      ; preds = %entry
804  ret void
805
806terminate:                                        ; preds = %entry
807  %0 = cleanuppad within none []
808  call void @_ZSt9terminatev() [ "funclet"(token %0) ]
809  unreachable
810}
811
812; This crashed on debug mode (= when NDEBUG is not defined) when the logic for
813; computing the innermost region was not correct, in which a loop region
814; contains an exception region. This should pass CFGSort without crashing.
815define void @test14() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
816entry:
817  %e = alloca %class.MyClass, align 4
818  br label %for.cond
819
820for.cond:                                         ; preds = %for.inc, %entry
821  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
822  %cmp = icmp slt i32 %i.0, 9
823  br i1 %cmp, label %for.body, label %for.end
824
825for.body:                                         ; preds = %for.cond
826  invoke void @quux(i32 %i.0)
827          to label %for.inc unwind label %catch.dispatch
828
829catch.dispatch:                                   ; preds = %for.body
830  %0 = catchswitch within none [label %catch.start] unwind to caller
831
832catch.start:                                      ; preds = %catch.dispatch
833  %1 = catchpad within %0 [i8* bitcast ({ i8*, i8* }* @_ZTI7MyClass to i8*)]
834  %2 = call i8* @llvm.wasm.get.exception(token %1)
835  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
836  %4 = call i32 @llvm.eh.typeid.for(i8* bitcast ({ i8*, i8* }* @_ZTI7MyClass to i8*))
837  %matches = icmp eq i32 %3, %4
838  br i1 %matches, label %catch, label %rethrow
839
840catch:                                            ; preds = %catch.start
841  %5 = call i8* @__cxa_get_exception_ptr(i8* %2) [ "funclet"(token %1) ]
842  %6 = bitcast i8* %5 to %class.MyClass*
843  %call = call %class.MyClass* @_ZN7MyClassC2ERKS_(%class.MyClass* %e, %class.MyClass* dereferenceable(4) %6) [ "funclet"(token %1) ]
844  %7 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
845  %x = getelementptr inbounds %class.MyClass, %class.MyClass* %e, i32 0, i32 0
846  %8 = load i32, i32* %x, align 4
847  invoke void @quux(i32 %8) [ "funclet"(token %1) ]
848          to label %invoke.cont2 unwind label %ehcleanup
849
850invoke.cont2:                                     ; preds = %catch
851  %call3 = call %class.MyClass* @_ZN7MyClassD2Ev(%class.MyClass* %e) [ "funclet"(token %1) ]
852  call void @__cxa_end_catch() [ "funclet"(token %1) ]
853  catchret from %1 to label %for.inc
854
855rethrow:                                          ; preds = %catch.start
856  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
857  unreachable
858
859for.inc:                                          ; preds = %invoke.cont2, %for.body
860  %inc = add nsw i32 %i.0, 1
861  br label %for.cond
862
863ehcleanup:                                        ; preds = %catch
864  %9 = cleanuppad within %1 []
865  %call4 = call %class.MyClass* @_ZN7MyClassD2Ev(%class.MyClass* %e) [ "funclet"(token %9) ]
866  invoke void @__cxa_end_catch() [ "funclet"(token %9) ]
867          to label %invoke.cont6 unwind label %terminate7
868
869invoke.cont6:                                     ; preds = %ehcleanup
870  cleanupret from %9 unwind to caller
871
872for.end:                                          ; preds = %for.cond
873  ret void
874
875terminate7:                                       ; preds = %ehcleanup
876  %10 = cleanuppad within %9 []
877  call void @_ZSt9terminatev() [ "funclet"(token %10) ]
878  unreachable
879}
880
881; Tests if CFGStackify's removeUnnecessaryInstrs() removes unnecessary branches
882; correctly. The code is in the form below, where 'br' is unnecessary because
883; after running the 'try' body the control flow will fall through to bb2 anyway.
884
885; bb0:
886;   try
887;     ...
888;     br bb2      <- Not necessary
889; bb1 (ehpad):
890;   catch
891;     ...
892; bb2:            <- Continuation BB
893;   end
894; CHECK-LABEL: test15
895define void @test15(i32 %n) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
896entry:
897  invoke void @foo()
898          to label %for.body unwind label %catch.dispatch
899
900for.body:                                         ; preds = %for.end, %entry
901  %i = phi i32 [ %inc, %for.end ], [ 0, %entry ]
902  invoke void @foo()
903          to label %for.end unwind label %catch.dispatch
904
905; Before going to CFGStackify, this BB will have a conditional branch followed
906; by an unconditional branch. CFGStackify should remove only the unconditional
907; one.
908for.end:                                          ; preds = %for.body
909  %inc = add nuw nsw i32 %i, 1
910  %exitcond = icmp eq i32 %inc, %n
911  br i1 %exitcond, label %try.cont, label %for.body
912; CHECK: br_if
913; CHECK-NOT: br
914; CHECK: end_loop
915; CHECK: catch
916
917catch.dispatch:                                   ; preds = %for.body, %entry
918  %0 = catchswitch within none [label %catch.start] unwind to caller
919
920catch.start:                                      ; preds = %catch.dispatch
921  %1 = catchpad within %0 [i8* null]
922  %2 = call i8* @llvm.wasm.get.exception(token %1)
923  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
924  %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
925  call void @__cxa_end_catch() [ "funclet"(token %1) ]
926  catchret from %1 to label %try.cont
927
928try.cont:                                         ; preds = %catch.start, %for.end
929  ret void
930}
931
932; void foo();
933; void test16() {
934;   try {
935;     foo();
936;     try {
937;       foo();
938;     } catch (...) {
939;     }
940;   } catch (...) {
941;   }
942; }
943;
944; This tests whether the 'br' can be removed in code in the form as follows.
945; Here 'br' is inside an inner try, whose 'end' is in another EH pad. In this
946; case, after running an inner try body, the control flow should fall through to
947; bb3, so the 'br' in the code is unnecessary.
948
949; bb0:
950;   try
951;     try
952;       ...
953;       br bb3      <- Not necessary
954; bb1:
955;     catch
956; bb2:
957;     end_try
958;   catch
959;     ...
960; bb3:            <- Continuation BB
961;   end
962;
963; CHECK-LABEL: test16
964define void @test16() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
965; CHECK: call foo
966entry:
967  invoke void @foo()
968          to label %invoke.cont unwind label %catch.dispatch3
969
970; CHECK: call foo
971; CHECK-NOT: br
972invoke.cont:                                      ; preds = %entry
973  invoke void @foo()
974          to label %try.cont8 unwind label %catch.dispatch
975
976catch.dispatch:                                   ; preds = %invoke.cont
977  %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch3
978
979; CHECK: catch
980catch.start:                                      ; preds = %catch.dispatch
981  %1 = catchpad within %0 [i8* null]
982  %2 = call i8* @llvm.wasm.get.exception(token %1)
983  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
984  %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
985  invoke void @__cxa_end_catch() [ "funclet"(token %1) ]
986          to label %invoke.cont2 unwind label %catch.dispatch3
987
988catch.dispatch3:                                  ; preds = %catch.start, %catch.dispatch, %entry
989  %5 = catchswitch within none [label %catch.start4] unwind to caller
990
991catch.start4:                                     ; preds = %catch.dispatch3
992  %6 = catchpad within %5 [i8* null]
993  %7 = call i8* @llvm.wasm.get.exception(token %6)
994  %8 = call i32 @llvm.wasm.get.ehselector(token %6)
995  %9 = call i8* @__cxa_begin_catch(i8* %7) [ "funclet"(token %6) ]
996  call void @__cxa_end_catch() [ "funclet"(token %6) ]
997  catchret from %6 to label %try.cont8
998
999try.cont8:                                        ; preds = %invoke.cont2, %catch.start4, %invoke.cont
1000  ret void
1001
1002invoke.cont2:                                     ; preds = %catch.start
1003  catchret from %1 to label %try.cont8
1004}
1005
1006; Here an exception is semantically contained in a loop. 'ehcleanup' BB belongs
1007; to the exception, but does not belong to the loop (because it does not have a
1008; path back to the loop header), and is placed after the loop latch block
1009; 'invoke.cont' intentionally. This tests if 'end_loop' marker is placed
1010; correctly not right after 'invoke.cont' part but after 'ehcleanup' part,
1011; NOSORT-LABEL: test17
1012; NOSORT: loop
1013; NOSORT: try
1014; NOSORT: end_try
1015; NOSORT: end_loop
1016define void @test17(i32 %n) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1017entry:
1018  br label %while.cond
1019
1020while.cond:                                       ; preds = %invoke.cont, %entry
1021  %n.addr.0 = phi i32 [ %n, %entry ], [ %dec, %invoke.cont ]
1022  %tobool = icmp ne i32 %n.addr.0, 0
1023  br i1 %tobool, label %while.body, label %while.end
1024
1025while.body:                                       ; preds = %while.cond
1026  %dec = add nsw i32 %n.addr.0, -1
1027  invoke void @foo()
1028          to label %while.end unwind label %catch.dispatch
1029
1030catch.dispatch:                                   ; preds = %while.body
1031  %0 = catchswitch within none [label %catch.start] unwind to caller
1032
1033catch.start:                                      ; preds = %catch.dispatch
1034  %1 = catchpad within %0 [i8* null]
1035  %2 = call i8* @llvm.wasm.get.exception(token %1)
1036  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1037  %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
1038  invoke void @__cxa_end_catch() [ "funclet"(token %1) ]
1039          to label %invoke.cont unwind label %ehcleanup
1040
1041invoke.cont:                                      ; preds = %catch.start
1042  catchret from %1 to label %while.cond
1043
1044ehcleanup:                                        ; preds = %catch.start
1045  %5 = cleanuppad within %1 []
1046  call void @_ZSt9terminatev() [ "funclet"(token %5) ]
1047  unreachable
1048
1049while.end:                                        ; preds = %while.body, %while.cond
1050  ret void
1051}
1052
1053; When the function return type is non-void and 'end' instructions are at the
1054; very end of a function, CFGStackify's fixEndsAtEndOfFunction function fixes
1055; the corresponding block/loop/try's type to match the function's return type.
1056; But when a `try`'s type is fixed, we should also check `end` instructions
1057; before its corresponding `catch_all`, because both `try` and `catch_all` body
1058; should satisfy the return type requirements.
1059
1060; NOSORT-LABEL: test18
1061; NOSORT: try i32
1062; NOSORT: loop i32
1063; NOSORT: end_loop
1064; NOSORT: catch_all
1065; NOSORT: end_try
1066; NOSORT-NEXT: end_function
1067define i32 @test18(i32 %n) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1068entry:
1069  %t = alloca %class.Object, align 1
1070  br label %for.cond
1071
1072for.cond:                                         ; preds = %for.inc, %entry
1073  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
1074  %cmp = icmp slt i32 %i.0, %n
1075  br label %for.body
1076
1077for.body:                                         ; preds = %for.cond
1078  %div = sdiv i32 %n, 2
1079  %cmp1 = icmp eq i32 %i.0, %div
1080  br i1 %cmp1, label %if.then, label %for.inc
1081
1082if.then:                                          ; preds = %for.body
1083  %call = invoke i32 @baz()
1084          to label %invoke.cont unwind label %ehcleanup
1085
1086invoke.cont:                                      ; preds = %if.then
1087  %call2 = call %class.Object* @_ZN6ObjectD2Ev(%class.Object* %t)
1088  ret i32 %call
1089
1090for.inc:                                          ; preds = %for.body
1091  %inc = add nsw i32 %i.0, 1
1092  br label %for.cond
1093
1094ehcleanup:                                        ; preds = %if.then
1095  %0 = cleanuppad within none []
1096  %call3 = call %class.Object* @_ZN6ObjectD2Ev(%class.Object* %t) [ "funclet"(token %0) ]
1097  cleanupret from %0 unwind to caller
1098}
1099
1100; This crashed when updating EHPadStack within fixCallUniwindMismatch had a bug.
1101; This should not crash and try-delegate has to be created around 'call @baz',
1102; because the initial TRY placement for 'call @quux' was done before 'call @baz'
1103; because 'call @baz''s return value is stackified.
1104
1105; CHECK-LABEL: test19
1106; CHECK: try
1107; CHECK:   try
1108; CHECK:     call $[[RET:[0-9]+]]=, baz
1109; CHECK:   delegate  1
1110; CHECK:    call  quux, $[[RET]]
1111; CHECK: catch_all
1112; CHECK: end_try
1113define void @test19() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1114entry:
1115  %call = call i32 @baz()
1116  invoke void @quux(i32 %call)
1117          to label %invoke.cont unwind label %ehcleanup
1118
1119ehcleanup:                                        ; preds = %entry
1120  %0 = cleanuppad within none []
1121  cleanupret from %0 unwind to caller
1122
1123invoke.cont:                                      ; preds = %entry
1124  unreachable
1125}
1126
1127; This tests if invalidated branch destinations after fixing catch unwind
1128; mismatches are correctly remapped. For example, we have this code and suppose
1129; we need to wrap this try-catch-end in this code with a try-delegate to fix a
1130; catch unwind mismatch:
1131  ; - Before:
1132; block
1133;   br (a)
1134;   try
1135;   catch
1136;   end_try
1137; end_block
1138;           <- (a)
1139;
1140; - After
1141; block
1142;   br (a)
1143;   try
1144;     try
1145;     catch
1146;     end_try
1147;           <- (a)
1148;   delegate
1149; end_block
1150;           <- (b)
1151; After adding a try-delegate, the 'br's destination BB, where (a) points,
1152; becomes invalid because it incorrectly branches into an inner scope. The
1153; destination should change to the BB where (b) points.
1154
1155; NOSORT-LABEL: test20
1156; NOSORT: try
1157; NOSORT:   br_if   0
1158define void @test20(i1 %arg) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1159entry:
1160  br i1 %arg, label %bb0, label %dest
1161
1162bb0:                                              ; preds = %entry
1163  invoke void @foo()
1164          to label %bb1 unwind label %catch.dispatch0
1165
1166bb1:                                              ; preds = %bb0
1167  invoke void @bar()
1168          to label %try.cont unwind label %catch.dispatch1
1169
1170catch.dispatch0:                                  ; preds = %bb0
1171  %0 = catchswitch within none [label %catch.start0] unwind to caller
1172
1173catch.start0:                                     ; preds = %catch.dispatch0
1174  %1 = catchpad within %0 [i8* null]
1175  %2 = call i8* @llvm.wasm.get.exception(token %1)
1176  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1177  catchret from %1 to label %try.cont
1178
1179dest:                                             ; preds = %entry
1180  ret void
1181
1182catch.dispatch1:                                  ; preds = %bb1
1183  %4 = catchswitch within none [label %catch.start1] unwind to caller
1184
1185catch.start1:                                     ; preds = %catch.dispatch1
1186  %5 = catchpad within %4 [i8* null]
1187  %6 = call i8* @llvm.wasm.get.exception(token %5)
1188  %7 = call i32 @llvm.wasm.get.ehselector(token %5)
1189  catchret from %5 to label %try.cont
1190
1191try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1
1192  ret void
1193}
1194
1195; The similar case with test20, but multiple consecutive delegates are
1196; generated:
1197; - Before:
1198; block
1199;   br (a)
1200;   try
1201;   catch
1202;   end_try
1203; end_block
1204;           <- (a)
1205;
1206; - After
1207; block
1208;   br (a)
1209;   try
1210;     ...
1211;     try
1212;       try
1213;       catch
1214;       end_try
1215;             <- (a)
1216;     delegate
1217;   delegate
1218; end_block
1219;           <- (b) The br destination should be remapped to here
1220;
1221; The test was reduced by bugpoint and should not crash in CFGStackify.
1222define void @test21() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1223entry:
1224  br i1 undef, label %if.then, label %if.end12
1225
1226if.then:                                          ; preds = %entry
1227  invoke void @__cxa_throw(i8* null, i8* null, i8* null) #1
1228          to label %unreachable unwind label %catch.dispatch
1229
1230catch.dispatch:                                   ; preds = %if.then
1231  %0 = catchswitch within none [label %catch.start] unwind to caller
1232
1233catch.start:                                      ; preds = %catch.dispatch
1234  %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
1235  %2 = call i8* @llvm.wasm.get.exception(token %1)
1236  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1237  catchret from %1 to label %catchret.dest
1238
1239catchret.dest:                                    ; preds = %catch.start
1240  invoke void @foo()
1241          to label %invoke.cont unwind label %catch.dispatch4
1242
1243invoke.cont:                                      ; preds = %catchret.dest
1244  invoke void @__cxa_throw(i8* null, i8* null, i8* null) #1
1245          to label %unreachable unwind label %catch.dispatch4
1246
1247catch.dispatch4:                                  ; preds = %invoke.cont, %catchret.dest
1248  %4 = catchswitch within none [label %catch.start5] unwind to caller
1249
1250catch.start5:                                     ; preds = %catch.dispatch4
1251  %5 = catchpad within %4 [i8* bitcast (i8** @_ZTIi to i8*)]
1252  %6 = call i8* @llvm.wasm.get.exception(token %5)
1253  %7 = call i32 @llvm.wasm.get.ehselector(token %5)
1254  unreachable
1255
1256if.end12:                                         ; preds = %entry
1257  invoke void @foo()
1258          to label %invoke.cont14 unwind label %catch.dispatch16
1259
1260catch.dispatch16:                                 ; preds = %if.end12
1261  %8 = catchswitch within none [label %catch.start17] unwind label %ehcleanup
1262
1263catch.start17:                                    ; preds = %catch.dispatch16
1264  %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)]
1265  %10 = call i8* @llvm.wasm.get.exception(token %9)
1266  %11 = call i32 @llvm.wasm.get.ehselector(token %9)
1267  br i1 undef, label %catch20, label %rethrow19
1268
1269catch20:                                          ; preds = %catch.start17
1270  catchret from %9 to label %catchret.dest22
1271
1272catchret.dest22:                                  ; preds = %catch20
1273  br label %try.cont23
1274
1275rethrow19:                                        ; preds = %catch.start17
1276  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %9) ]
1277          to label %unreachable unwind label %ehcleanup
1278
1279try.cont23:                                       ; preds = %invoke.cont14, %catchret.dest22
1280  invoke void @foo()
1281          to label %invoke.cont24 unwind label %ehcleanup
1282
1283invoke.cont24:                                    ; preds = %try.cont23
1284  ret void
1285
1286invoke.cont14:                                    ; preds = %if.end12
1287  br label %try.cont23
1288
1289ehcleanup:                                        ; preds = %try.cont23, %rethrow19, %catch.dispatch16
1290  %12 = cleanuppad within none []
1291  cleanupret from %12 unwind to caller
1292
1293unreachable:                                      ; preds = %rethrow19, %invoke.cont, %if.then
1294  unreachable
1295}
1296
1297; Regression test for WasmEHFuncInfo's reverse mapping bug. 'UnwindDestToSrc'
1298; should return a vector and not a single BB, which was incorrect.
1299; This was reduced by bugpoint and should not crash in CFGStackify.
1300define void @test22() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1301entry:
1302  invoke void @foo()
1303          to label %invoke.cont unwind label %catch.dispatch
1304
1305catch.dispatch:                                   ; preds = %entry
1306  %0 = catchswitch within none [label %catch.start] unwind label %ehcleanup22
1307
1308catch.start:                                      ; preds = %catch.dispatch
1309  %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
1310  %2 = call i8* @llvm.wasm.get.exception(token %1)
1311  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1312  invoke void @__cxa_throw(i8* null, i8* null, i8* null) #1 [ "funclet"(token %1) ]
1313          to label %unreachable unwind label %catch.dispatch2
1314
1315catch.dispatch2:                                  ; preds = %catch.start
1316  %4 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup
1317
1318catch.start3:                                     ; preds = %catch.dispatch2
1319  %5 = catchpad within %4 [i8* bitcast (i8** @_ZTIi to i8*)]
1320  %6 = call i8* @llvm.wasm.get.exception(token %5)
1321  %7 = call i32 @llvm.wasm.get.ehselector(token %5)
1322  catchret from %5 to label %try.cont
1323
1324try.cont:                                         ; preds = %catch.start3
1325  invoke void @foo() [ "funclet"(token %1) ]
1326          to label %invoke.cont8 unwind label %ehcleanup
1327
1328invoke.cont8:                                     ; preds = %try.cont
1329  invoke void @__cxa_throw(i8* null, i8* null, i8* null) #1 [ "funclet"(token %1) ]
1330          to label %unreachable unwind label %catch.dispatch11
1331
1332catch.dispatch11:                                 ; preds = %invoke.cont8
1333  %8 = catchswitch within %1 [label %catch.start12] unwind label %ehcleanup
1334
1335catch.start12:                                    ; preds = %catch.dispatch11
1336  %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)]
1337  %10 = call i8* @llvm.wasm.get.exception(token %9)
1338  %11 = call i32 @llvm.wasm.get.ehselector(token %9)
1339  unreachable
1340
1341invoke.cont:                                      ; preds = %entry
1342  unreachable
1343
1344ehcleanup:                                        ; preds = %catch.dispatch11, %try.cont, %catch.dispatch2
1345  %12 = cleanuppad within %1 []
1346  cleanupret from %12 unwind label %ehcleanup22
1347
1348ehcleanup22:                                      ; preds = %ehcleanup, %catch.dispatch
1349  %13 = cleanuppad within none []
1350  cleanupret from %13 unwind to caller
1351
1352unreachable:                                      ; preds = %invoke.cont8, %catch.start
1353  unreachable
1354}
1355
1356; void test23() {
1357;   try {
1358;     try {
1359;       throw 0;
1360;     } catch (int) {
1361;     }
1362;   } catch (int) {
1363;   }
1364; }
1365;
1366; Regression test for a WebAssemblyException grouping bug. After catchswitches
1367; are removed, EH pad catch.start2 is dominated by catch.start, but because
1368; catch.start2 is the unwind destination of catch.start, it should not be
1369; included in catch.start's exception. Also, after we take catch.start2's
1370; exception out of catch.start's exception, we have to take out try.cont8 out of
1371; catch.start's exception, because it has a predecessor in catch.start2.
1372define void @test23() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1373entry:
1374  %exception = call i8* @__cxa_allocate_exception(i32 4) #0
1375  %0 = bitcast i8* %exception to i32*
1376  store i32 0, i32* %0, align 16
1377  invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) #1
1378          to label %unreachable unwind label %catch.dispatch
1379
1380catch.dispatch:                                   ; preds = %entry
1381  %1 = catchswitch within none [label %catch.start] unwind label %catch.dispatch1
1382
1383catch.start:                                      ; preds = %catch.dispatch
1384  %2 = catchpad within %1 [i8* bitcast (i8** @_ZTIi to i8*)]
1385  %3 = call i8* @llvm.wasm.get.exception(token %2)
1386  %4 = call i32 @llvm.wasm.get.ehselector(token %2)
1387  %5 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #0
1388  %matches = icmp eq i32 %4, %5
1389  br i1 %matches, label %catch, label %rethrow
1390
1391catch:                                            ; preds = %catch.start
1392  %6 = call i8* @__cxa_begin_catch(i8* %3) #0 [ "funclet"(token %2) ]
1393  %7 = bitcast i8* %6 to i32*
1394  %8 = load i32, i32* %7, align 4
1395  call void @__cxa_end_catch() #0 [ "funclet"(token %2) ]
1396  catchret from %2 to label %catchret.dest
1397
1398catchret.dest:                                    ; preds = %catch
1399  br label %try.cont
1400
1401rethrow:                                          ; preds = %catch.start
1402  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %2) ]
1403          to label %unreachable unwind label %catch.dispatch1
1404
1405catch.dispatch1:                                  ; preds = %rethrow, %catch.dispatch
1406  %9 = catchswitch within none [label %catch.start2] unwind to caller
1407
1408catch.start2:                                     ; preds = %catch.dispatch1
1409  %10 = catchpad within %9 [i8* bitcast (i8** @_ZTIi to i8*)]
1410  %11 = call i8* @llvm.wasm.get.exception(token %10)
1411  %12 = call i32 @llvm.wasm.get.ehselector(token %10)
1412  %13 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #0
1413  %matches3 = icmp eq i32 %12, %13
1414  br i1 %matches3, label %catch5, label %rethrow4
1415
1416catch5:                                           ; preds = %catch.start2
1417  %14 = call i8* @__cxa_begin_catch(i8* %11) #0 [ "funclet"(token %10) ]
1418  %15 = bitcast i8* %14 to i32*
1419  %16 = load i32, i32* %15, align 4
1420  call void @__cxa_end_catch() #0 [ "funclet"(token %10) ]
1421  catchret from %10 to label %catchret.dest7
1422
1423catchret.dest7:                                   ; preds = %catch5
1424  br label %try.cont8
1425
1426rethrow4:                                         ; preds = %catch.start2
1427  call void @llvm.wasm.rethrow() #1 [ "funclet"(token %10) ]
1428  unreachable
1429
1430try.cont8:                                        ; preds = %try.cont, %catchret.dest7
1431  ret void
1432
1433try.cont:                                         ; preds = %catchret.dest
1434  br label %try.cont8
1435
1436unreachable:                                      ; preds = %rethrow, %entry
1437  unreachable
1438}
1439
1440; Test for WebAssemblyException grouping. This test is hand-modified to generate
1441; this structure:
1442; catch.start dominates catch.start4 and catch.start4 dominates catch.start12,
1443; so the after dominator-based grouping, we end up with:
1444; catch.start's exception > catch4.start's exception > catch12.start's exception
1445; (> here represents subexception relationship)
1446;
1447; But the unwind destination chain is catch.start -> catch.start4 ->
1448; catch.start12. So all these subexception relationship should be deconstructed.
1449; We have to make sure to take out catch.start4's exception out of catch.start's
1450; exception first, before taking out catch.start12's exception out of
1451; catch.start4's exception; otherwise we end up with an incorrect relationship
1452; of catch.start's exception > catch.start12's exception.
1453define void @test24() personality i8* bitcast (i32 (...)*
1454@__gxx_wasm_personality_v0 to i8*) {
1455entry:
1456  invoke void @foo()
1457          to label %invoke.cont unwind label %catch.dispatch
1458
1459invoke.cont:                                      ; preds = %entry
1460  invoke void @foo()
1461          to label %invoke.cont1 unwind label %catch.dispatch
1462
1463invoke.cont1:                                     ; preds = %invoke.cont
1464  invoke void @foo()
1465          to label %try.cont18 unwind label %catch.dispatch
1466
1467catch.dispatch11:                                 ; preds = %rethrow6, %catch.dispatch3
1468  %0 = catchswitch within none [label %catch.start12] unwind to caller
1469
1470catch.start12:                                    ; preds = %catch.dispatch11
1471  %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
1472  %2 = call i8* @llvm.wasm.get.exception(token %1)
1473  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1474  %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #0
1475  %matches13 = icmp eq i32 %3, %4
1476  br i1 %matches13, label %catch15, label %rethrow14
1477
1478catch15:                                          ; preds = %catch.start12
1479  %5 = call i8* @__cxa_begin_catch(i8* %2) #0 [ "funclet"(token %1) ]
1480  %6 = bitcast i8* %5 to i32*
1481  %7 = load i32, i32* %6, align 4
1482  call void @__cxa_end_catch() #0 [ "funclet"(token %1) ]
1483  catchret from %1 to label %try.cont18
1484
1485rethrow14:                                        ; preds = %catch.start12
1486  call void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]
1487  unreachable
1488
1489catch.dispatch3:                                  ; preds = %rethrow, %catch.dispatch
1490  %8 = catchswitch within none [label %catch.start4] unwind label %catch.dispatch11
1491
1492catch.start4:                                     ; preds = %catch.dispatch3
1493  %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)]
1494  %10 = call i8* @llvm.wasm.get.exception(token %9)
1495  %11 = call i32 @llvm.wasm.get.ehselector(token %9)
1496  %12 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #0
1497  %matches5 = icmp eq i32 %11, %12
1498  br i1 %matches5, label %catch7, label %rethrow6
1499
1500catch7:                                           ; preds = %catch.start4
1501  %13 = call i8* @__cxa_begin_catch(i8* %10) #0 [ "funclet"(token %9) ]
1502  %14 = bitcast i8* %13 to i32*
1503  %15 = load i32, i32* %14, align 4
1504  call void @__cxa_end_catch() #0 [ "funclet"(token %9) ]
1505  catchret from %9 to label %try.cont18
1506
1507rethrow6:                                         ; preds = %catch.start4
1508  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %9) ]
1509          to label %unreachable unwind label %catch.dispatch11
1510
1511catch.dispatch:                                   ; preds = %invoke.cont1, %invoke.cont, %entry
1512  %16 = catchswitch within none [label %catch.start] unwind label %catch.dispatch3
1513
1514catch.start:                                      ; preds = %catch.dispatch
1515  %17 = catchpad within %16 [i8* bitcast (i8** @_ZTIi to i8*)]
1516  %18 = call i8* @llvm.wasm.get.exception(token %17)
1517  %19 = call i32 @llvm.wasm.get.ehselector(token %17)
1518  %20 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #0
1519  %matches = icmp eq i32 %19, %20
1520  br i1 %matches, label %catch, label %rethrow
1521
1522catch:                                            ; preds = %catch.start
1523  %21 = call i8* @__cxa_begin_catch(i8* %18) #0 [ "funclet"(token %17) ]
1524  %22 = bitcast i8* %21 to i32*
1525  %23 = load i32, i32* %22, align 4
1526  call void @__cxa_end_catch() #0 [ "funclet"(token %17) ]
1527  catchret from %17 to label %try.cont18
1528
1529rethrow:                                          ; preds = %catch.start
1530  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %17) ]
1531          to label %unreachable unwind label %catch.dispatch3
1532
1533try.cont18:                                       ; preds = %catch, %catch7, %catch15, %invoke.cont1
1534  ret void
1535
1536unreachable:                                      ; preds = %rethrow, %rethrow6
1537  unreachable
1538}
1539
1540; void test25() {
1541;   try {
1542;     try {
1543;       throw 0;
1544;     } catch (int) { // (a)
1545;     }
1546;   } catch (int) {   // (b)
1547;   }
1548;   try {
1549;     foo();
1550;   } catch (int) {   // (c)
1551;   }
1552; }
1553;
1554; Regression test for an ExceptionInfo grouping bug. Because the first (inner)
1555; try always throws, both EH pads (b) (catch.start2) and (c) (catch.start10) are
1556; dominated by EH pad (a) (catch.start), even though they are not semantically
1557; contained in (a)'s exception. Because (a)'s unwind destination is (b), (b)'s
1558; exception is taken out of (a)'s. But because (c) is reachable from (b), we
1559; should make sure to take out (c)'s exception out of (a)'s exception too.
1560define void @test25() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1561entry:
1562  %exception = call i8* @__cxa_allocate_exception(i32 4) #1
1563  %0 = bitcast i8* %exception to i32*
1564  store i32 0, i32* %0, align 16
1565  invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) #3
1566          to label %unreachable unwind label %catch.dispatch
1567
1568catch.dispatch:                                   ; preds = %entry
1569  %1 = catchswitch within none [label %catch.start] unwind label %catch.dispatch1
1570
1571catch.start:                                      ; preds = %catch.dispatch
1572  %2 = catchpad within %1 [i8* bitcast (i8** @_ZTIi to i8*)]
1573  %3 = call i8* @llvm.wasm.get.exception(token %2)
1574  %4 = call i32 @llvm.wasm.get.ehselector(token %2)
1575  %5 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #1
1576  %matches = icmp eq i32 %4, %5
1577  br i1 %matches, label %catch, label %rethrow
1578
1579catch:                                            ; preds = %catch.start
1580  %6 = call i8* @__cxa_begin_catch(i8* %3) #1 [ "funclet"(token %2) ]
1581  %7 = bitcast i8* %6 to i32*
1582  %8 = load i32, i32* %7, align 4
1583  call void @__cxa_end_catch() #1 [ "funclet"(token %2) ]
1584  catchret from %2 to label %try.cont8
1585
1586rethrow:                                          ; preds = %catch.start
1587  invoke void @llvm.wasm.rethrow() #3 [ "funclet"(token %2) ]
1588          to label %unreachable unwind label %catch.dispatch1
1589
1590catch.dispatch1:                                  ; preds = %rethrow, %catch.dispatch
1591  %9 = catchswitch within none [label %catch.start2] unwind to caller
1592
1593catch.start2:                                     ; preds = %catch.dispatch1
1594  %10 = catchpad within %9 [i8* bitcast (i8** @_ZTIi to i8*)]
1595  %11 = call i8* @llvm.wasm.get.exception(token %10)
1596  %12 = call i32 @llvm.wasm.get.ehselector(token %10)
1597  %13 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #1
1598  %matches3 = icmp eq i32 %12, %13
1599  br i1 %matches3, label %catch5, label %rethrow4
1600
1601catch5:                                           ; preds = %catch.start2
1602  %14 = call i8* @__cxa_begin_catch(i8* %11) #1 [ "funclet"(token %10) ]
1603  %15 = bitcast i8* %14 to i32*
1604  %16 = load i32, i32* %15, align 4
1605  call void @__cxa_end_catch() #1 [ "funclet"(token %10) ]
1606  catchret from %10 to label %try.cont8
1607
1608rethrow4:                                         ; preds = %catch.start2
1609  call void @llvm.wasm.rethrow() #3 [ "funclet"(token %10) ]
1610  unreachable
1611
1612try.cont8:                                        ; preds = %catch, %catch5
1613  invoke void @foo()
1614          to label %try.cont16 unwind label %catch.dispatch9
1615
1616catch.dispatch9:                                  ; preds = %try.cont8
1617  %17 = catchswitch within none [label %catch.start10] unwind to caller
1618
1619catch.start10:                                    ; preds = %catch.dispatch9
1620  %18 = catchpad within %17 [i8* bitcast (i8** @_ZTIi to i8*)]
1621  %19 = call i8* @llvm.wasm.get.exception(token %18)
1622  %20 = call i32 @llvm.wasm.get.ehselector(token %18)
1623  %21 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #1
1624  %matches11 = icmp eq i32 %20, %21
1625  br i1 %matches11, label %catch13, label %rethrow12
1626
1627catch13:                                          ; preds = %catch.start10
1628  %22 = call i8* @__cxa_begin_catch(i8* %19) #1 [ "funclet"(token %18) ]
1629  %23 = bitcast i8* %22 to i32*
1630  %24 = load i32, i32* %23, align 4
1631  call void @__cxa_end_catch() #1 [ "funclet"(token %18) ]
1632  catchret from %18 to label %try.cont16
1633
1634rethrow12:                                        ; preds = %catch.start10
1635  call void @llvm.wasm.rethrow() #3 [ "funclet"(token %18) ]
1636  unreachable
1637
1638try.cont16:                                       ; preds = %try.cont8, %catch13
1639  ret void
1640
1641unreachable:                                      ; preds = %rethrow, %entry
1642  unreachable
1643}
1644
1645; Check if the unwind destination mismatch stats are correct
1646; NOSORT: 23 wasm-cfg-stackify    - Number of call unwind mismatches found
1647; NOSORT:  4 wasm-cfg-stackify    - Number of catch unwind mismatches found
1648
1649declare void @foo()
1650declare void @bar()
1651declare i32 @baz()
1652declare i32 @qux(i32)
1653declare void @quux(i32)
1654declare void @fun(i32)
1655; Function Attrs: nounwind
1656declare void @nothrow(i32) #0
1657; Function Attrs: nounwind
1658declare i32 @nothrow_i32() #0
1659
1660; Function Attrs: nounwind
1661declare %class.Object* @_ZN6ObjectD2Ev(%class.Object* returned) #0
1662@_ZTI7MyClass = external constant { i8*, i8* }, align 4
1663; Function Attrs: nounwind
1664declare %class.MyClass* @_ZN7MyClassD2Ev(%class.MyClass* returned) #0
1665; Function Attrs: nounwind
1666declare %class.MyClass* @_ZN7MyClassC2ERKS_(%class.MyClass* returned, %class.MyClass* dereferenceable(4)) #0
1667
1668declare i32 @__gxx_wasm_personality_v0(...)
1669; Function Attrs: nounwind
1670declare i8* @llvm.wasm.get.exception(token) #0
1671; Function Attrs: nounwind
1672declare i32 @llvm.wasm.get.ehselector(token) #0
1673declare i8* @__cxa_allocate_exception(i32) #0
1674declare void @__cxa_throw(i8*, i8*, i8*)
1675; Function Attrs: noreturn
1676declare void @llvm.wasm.rethrow() #1
1677; Function Attrs: nounwind
1678declare i32 @llvm.eh.typeid.for(i8*) #0
1679
1680declare i8* @__cxa_begin_catch(i8*)
1681declare void @__cxa_end_catch()
1682declare i8* @__cxa_get_exception_ptr(i8*)
1683declare void @_ZSt9terminatev()
1684; Function Attrs: nounwind
1685declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #0
1686; Function Attrs: nounwind
1687declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i1 immarg) #0
1688; Function Attrs: nounwind
1689declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1 immarg) #0
1690
1691attributes #0 = { nounwind }
1692attributes #1 = { noreturn }
1693