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