[OpenACC] Create AST nodes for 'data' constructs
[llvm-project.git] / llvm / test / CodeGen / WebAssembly / cfg-stackify-eh-legacy.ll
blobab9023cbac60415449f53f8e165111f0d2b0e01c
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,bulk-memory | 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,bulk-memory
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,-bulk-memory,-bulk-memory-opt | 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,-bulk-memory,-bulk-memory-opt -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,-bulk-memory,-bulk-memory-opt -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 two_catches() {
20 ;   try {
21 ;     foo();
22 ;   } catch (int) {
23 ;   } catch (double) {
24 ;   }
25 ; }
27 ; CHECK-LABEL: two_catches:
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 @two_catches() 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 nested_catch() {
86 ;   try {
87 ;     foo();
88 ;   } catch (int) {
89 ;     try {
90 ;       foo();
91 ;     } catch (int) {
92 ;       foo();
93 ;     }
94 ;   }
95 ; }
97 ; CHECK-LABEL: nested_catch:
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 @nested_catch() 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 try-catches within a try
209 ; void nested_try() {
210 ;   try {
211 ;     try {
212 ;       foo();
213 ;     } catch (...) {
214 ;     }
215 ;   } catch (...) {
216 ;   }
217 ; }
219 ; CHECK-LABEL: nested_try:
220 ; CHECK:   try
221 ; CHECK:     try
222 ; CHECK:       call  foo
223 ; CHECK:     catch
224 ; CHECK:       call  $drop=, __cxa_begin_catch
225 ; CHECK:       call  __cxa_end_catch
226 ; CHECK:     end_try
227 ; CHECK:     catch
228 ; CHECK:     call  $drop=, __cxa_begin_catch
229 ; CHECK:     call  __cxa_end_catch
230 ; CHECK:   end_try
231 define void @nested_try() personality ptr @__gxx_wasm_personality_v0 {
232 entry:
233   invoke void @foo()
234           to label %try.cont7 unwind label %catch.dispatch
236 catch.dispatch:                                   ; preds = %entry
237   %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch2
239 catch.start:                                      ; preds = %catch.dispatch
240   %1 = catchpad within %0 [ptr null]
241   %2 = call ptr @llvm.wasm.get.exception(token %1)
242   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
243   %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
244   invoke void @__cxa_end_catch() [ "funclet"(token %1) ]
245           to label %invoke.cont1 unwind label %catch.dispatch2
247 catch.dispatch2:                                  ; preds = %catch.start, %catch.dispatch
248   %5 = catchswitch within none [label %catch.start3] unwind to caller
250 catch.start3:                                     ; preds = %catch.dispatch2
251   %6 = catchpad within %5 [ptr null]
252   %7 = call ptr @llvm.wasm.get.exception(token %6)
253   %8 = call i32 @llvm.wasm.get.ehselector(token %6)
254   %9 = call ptr @__cxa_begin_catch(ptr %7) [ "funclet"(token %6) ]
255   call void @__cxa_end_catch() [ "funclet"(token %6) ]
256   catchret from %6 to label %try.cont7
258 try.cont7:                                        ; preds = %entry, %invoke.cont1, %catch.start3
259   ret void
261 invoke.cont1:                                     ; preds = %catch.start
262   catchret from %1 to label %try.cont7
266 ; CHECK-LABEL: loop_within_catch:
267 ; CHECK: try
268 ; CHECK:   call      foo
269 ; CHECK: catch
270 ; CHECK:   call      $drop=, __cxa_begin_catch
271 ; CHECK:   loop                                        # label[[L0:[0-9]+]]:
272 ; CHECK:     block
273 ; CHECK:       block
274 ; CHECK:         br_if     0, {{.*}}                   # 0: down to label[[L1:[0-9]+]]
275 ; CHECK:         try
276 ; CHECK:           call      foo
277 ; CHECK:           br        2                         # 2: down to label[[L2:[0-9]+]]
278 ; CHECK:         catch
279 ; CHECK:           try
280 ; CHECK:             call      __cxa_end_catch
281 ; CHECK:           catch_all
282 ; CHECK:             call      _ZSt9terminatev
283 ; CHECK:             unreachable
284 ; CHECK:           end_try
285 ; CHECK:           rethrow   0                         # to caller
286 ; CHECK:         end_try
287 ; CHECK:       end_block                               # label[[L1]]:
288 ; CHECK:       call      __cxa_end_catch
289 ; CHECK:       br        2                             # 2: down to label[[L3:[0-9]+]]
290 ; CHECK:     end_block                                 # label[[L2]]:
291 ; CHECK:     br        0                               # 0: up to label[[L0]]
292 ; CHECK:   end_loop
293 ; CHECK: end_try                                       # label[[L3]]:
294 define void @loop_within_catch() personality ptr @__gxx_wasm_personality_v0 {
295 entry:
296   invoke void @foo()
297           to label %try.cont unwind label %catch.dispatch
299 catch.dispatch:                                   ; preds = %entry
300   %0 = catchswitch within none [label %catch.start] unwind to caller
302 catch.start:                                      ; preds = %catch.dispatch
303   %1 = catchpad within %0 [ptr null]
304   %2 = call ptr @llvm.wasm.get.exception(token %1)
305   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
306   %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
307   br label %for.cond
309 for.cond:                                         ; preds = %for.inc, %catch.start
310   %i.0 = phi i32 [ 0, %catch.start ], [ %inc, %for.inc ]
311   %cmp = icmp slt i32 %i.0, 50
312   br i1 %cmp, label %for.body, label %for.end
314 for.body:                                         ; preds = %for.cond
315   invoke void @foo() [ "funclet"(token %1) ]
316           to label %for.inc unwind label %ehcleanup
318 for.inc:                                          ; preds = %for.body
319   %inc = add nsw i32 %i.0, 1
320   br label %for.cond
322 for.end:                                          ; preds = %for.cond
323   call void @__cxa_end_catch() [ "funclet"(token %1) ]
324   catchret from %1 to label %try.cont
326 try.cont:                                         ; preds = %for.end, %entry
327   ret void
329 ehcleanup:                                        ; preds = %for.body
330   %5 = cleanuppad within %1 []
331   invoke void @__cxa_end_catch() [ "funclet"(token %5) ]
332           to label %invoke.cont2 unwind label %terminate
334 invoke.cont2:                                     ; preds = %ehcleanup
335   cleanupret from %5 unwind to caller
337 terminate:                                        ; preds = %ehcleanup
338   %6 = cleanuppad within %5 []
339   call void @_ZSt9terminatev() [ "funclet"(token %6) ]
340   unreachable
343 ; Tests if block and try markers are correctly placed. Even if two predecessors
344 ; of the EH pad are bb2 and bb3 and their nearest common dominator is bb1, the
345 ; TRY marker should be placed at bb0 because there's a branch from bb0 to bb2,
346 ; and scopes cannot be interleaved.
348 ; NOOPT-LABEL: block_try_markers:
349 ; NOOPT: try
350 ; NOOPT:   block
351 ; NOOPT:     block
352 ; NOOPT:       block
353 ; NOOPT:       end_block
354 ; NOOPT:     end_block
355 ; NOOPT:     call      foo
356 ; NOOPT:   end_block
357 ; NOOPT:   call      bar
358 ; NOOPT: catch     {{.*}}
359 ; NOOPT: end_try
360 define void @block_try_markers() personality ptr @__gxx_wasm_personality_v0 {
361 bb0:
362   br i1 undef, label %bb1, label %bb2
364 bb1:                                              ; preds = %bb0
365   br i1 undef, label %bb3, label %bb4
367 bb2:                                              ; preds = %bb0
368   br label %try.cont
370 bb3:                                              ; preds = %bb1
371   invoke void @foo()
372           to label %try.cont unwind label %catch.dispatch
374 bb4:                                              ; preds = %bb1
375   invoke void @bar()
376           to label %try.cont unwind label %catch.dispatch
378 catch.dispatch:                                   ; preds = %bb4, %bb3
379   %0 = catchswitch within none [label %catch.start] unwind to caller
381 catch.start:                                      ; preds = %catch.dispatch
382   %1 = catchpad within %0 [ptr null]
383   %2 = call ptr @llvm.wasm.get.exception(token %1)
384   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
385   catchret from %1 to label %try.cont
387 try.cont:                                         ; preds = %catch.start, %bb4, %bb3, %bb2
388   ret void
391 ; Tests if try/end_try markers are placed correctly wrt loop/end_loop markers,
392 ; when try and loop markers are in the same BB and end_try and end_loop are in
393 ; another BB.
394 ; CHECK-LABEL: loop_try_markers:
395 ; CHECK: loop
396 ; CHECK:   try
397 ; CHECK:     call      foo
398 ; CHECK:   catch
399 ; CHECK:   end_try
400 ; CHECK: end_loop
401 define void @loop_try_markers(ptr %p) personality ptr @__gxx_wasm_personality_v0 {
402 entry:
403   store volatile i32 0, ptr %p
404   br label %loop
406 loop:                                             ; preds = %try.cont, %entry
407   store volatile i32 1, ptr %p
408   invoke void @foo()
409           to label %try.cont unwind label %catch.dispatch
411 catch.dispatch:                                   ; preds = %loop
412   %0 = catchswitch within none [label %catch.start] unwind to caller
414 catch.start:                                      ; preds = %catch.dispatch
415   %1 = catchpad within %0 [ptr null]
416   %2 = call ptr @llvm.wasm.get.exception(token %1)
417   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
418   catchret from %1 to label %try.cont
420 try.cont:                                         ; preds = %catch.start, %loop
421   br label %loop
424 ; Some of test cases below are hand-tweaked by deleting some library calls to
425 ; simplify tests and changing the order of basic blocks to cause unwind
426 ; destination mismatches. And we use -wasm-disable-ehpad-sort to create maximum
427 ; number of mismatches in several tests below.
429 ; - Call unwind mismatch
430 ; 'call bar''s original unwind destination was 'C0', but after control flow
431 ; linearization, its unwind destination incorrectly becomes 'C1'. We fix this by
432 ; wrapping the call with a nested try-delegate that targets 'C0'.
433 ; - Catch unwind mismatch
434 ; If 'call foo' throws a foreign exception, it will not be caught by C1, and
435 ; should be rethrown to the caller. But after control flow linearization, it
436 ; will instead unwind to C0, an incorrect next EH pad. We wrap the whole
437 ; try-catch with try-delegate that rethrows the exception to the caller to fix
438 ; this.
440 ; NOSORT-LABEL: unwind_mismatches_0:
441 ; NOSORT: try
442 ; --- try-delegate starts (catch unwind mismatch)
443 ; NOSORT    try
444 ; NOSORT:     try
445 ; NOSORT:       call  foo
446 ; --- try-delegate starts (call unwind mismatch)
447 ; NOSORT:       try
448 ; NOSORT:         call  bar
449 ; NOSORT:       delegate    2     # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
450 ; --- try-delegate ends (call unwind mismatch)
451 ; NOSORT:     catch   {{.*}}      # catch[[C1:[0-9]+]]:
452 ; NOSORT:     end_try
453 ; NOSORT:   delegate    1         # label/catch{{[0-9]+}}: to caller
454 ; --- try-delegate ends (catch unwind mismatch)
455 ; NOSORT: catch   {{.*}}          # catch[[C0]]:
456 ; NOSORT: end_try
457 ; NOSORT: return
458 define void @unwind_mismatches_0() personality ptr @__gxx_wasm_personality_v0 {
459 bb0:
460   invoke void @foo()
461           to label %bb1 unwind label %catch.dispatch0
463 bb1:                                              ; preds = %bb0
464   invoke void @bar()
465           to label %try.cont unwind label %catch.dispatch1
467 catch.dispatch0:                                  ; preds = %bb0
468   %0 = catchswitch within none [label %catch.start0] unwind to caller
470 catch.start0:                                     ; preds = %catch.dispatch0
471   %1 = catchpad within %0 [ptr null]
472   %2 = call ptr @llvm.wasm.get.exception(token %1)
473   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
474   catchret from %1 to label %try.cont
476 catch.dispatch1:                                  ; preds = %bb1
477   %4 = catchswitch within none [label %catch.start1] unwind to caller
479 catch.start1:                                     ; preds = %catch.dispatch1
480   %5 = catchpad within %4 [ptr null]
481   %6 = call ptr @llvm.wasm.get.exception(token %5)
482   %7 = call i32 @llvm.wasm.get.ehselector(token %5)
483   catchret from %5 to label %try.cont
485 try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1
486   ret void
489 ; 'call bar' and 'call baz''s original unwind destination was the caller, but
490 ; after control flow linearization, their unwind destination incorrectly becomes
491 ; 'C0'. We fix this by wrapping the calls with a nested try-delegate that
492 ; rethrows the exception to the caller.
494 ; And the return value of 'baz' should NOT be stackified because the BB is split
495 ; during fixing unwind mismatches.
497 ; NOSORT-LABEL: unwind_mismatches_1:
498 ; NOSORT: try
499 ; NOSORT:   call  foo
500 ; --- try-delegate starts (call unwind mismatch)
501 ; NOSORT:   try
502 ; NOSORT:     call  bar
503 ; NOSORT:     call  $[[RET:[0-9]+]]=, baz
504 ; NOSORT-NOT: call  $push{{.*}}=, baz
505 ; NOSORT:   delegate    1                     # label/catch{{[0-9]+}}: to caller
506 ; --- try-delegate ends (call unwind mismatch)
507 ; NOSORT:   call  nothrow, $[[RET]]
508 ; NOSORT:   return
509 ; NOSORT: catch   {{.*}}                      # catch[[C0:[0-9]+]]:
510 ; NOSORT:   return
511 ; NOSORT: end_try
512 define void @unwind_mismatches_1() personality ptr @__gxx_wasm_personality_v0 {
513 bb0:
514   invoke void @foo()
515           to label %bb1 unwind label %catch.dispatch0
517 bb1:                                              ; preds = %bb0
518   call void @bar()
519   %call = call i32 @baz()
520   call void @nothrow(i32 %call) #0
521   ret void
523 catch.dispatch0:                                  ; preds = %bb0
524   %0 = catchswitch within none [label %catch.start0] unwind to caller
526 catch.start0:                                     ; preds = %catch.dispatch0
527   %1 = catchpad within %0 [ptr null]
528   %2 = call ptr @llvm.wasm.get.exception(token %1)
529   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
530   catchret from %1 to label %try.cont
532 try.cont:                                         ; preds = %catch.start0
533   ret void
536 ; The same as unwind_mismatches_0, but we have one more call 'call @foo' in bb1
537 ; which unwinds to the caller. IN this case bb1 has two call unwind mismatches:
538 ; 'call @foo' unwinds to the caller and 'call @bar' unwinds to catch C0.
540 ; NOSORT-LABEL: unwind_mismatches_2:
541 ; NOSORT: try
542 ; --- try-delegate starts (catch unwind mismatch)
543 ; NOSORT    try
544 ; NOSORT:     try
545 ; NOSORT:       call  foo
546 ; --- try-delegate starts (call unwind mismatch)
547 ; NOSORT:       try
548 ; NOSORT:         call  foo
549 ; NOSORT:       delegate    3     # label/catch{{[0-9]+}}: to caller
550 ; --- try-delegate ends (call unwind mismatch)
551 ; --- try-delegate starts (call unwind mismatch)
552 ; NOSORT:       try
553 ; NOSORT:         call  bar
554 ; NOSORT:       delegate    2     # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
555 ; --- try-delegate ends (call unwind mismatch)
556 ; NOSORT:     catch   {{.*}}      # catch[[C1:[0-9]+]]:
557 ; NOSORT:     end_try
558 ; NOSORT:   delegate    1         # label/catch{{[0-9]+}}: to caller
559 ; --- try-delegate ends (catch unwind mismatch)
560 ; NOSORT: catch   {{.*}}        # catch[[C0]]:
561 ; NOSORT: end_try
562 ; NOSORT: return
563 define void @unwind_mismatches_2() personality ptr @__gxx_wasm_personality_v0 {
564 bb0:
565   invoke void @foo()
566           to label %bb1 unwind label %catch.dispatch0
568 bb1:                                              ; preds = %bb0
569   call void @foo()
570   invoke void @bar()
571           to label %try.cont unwind label %catch.dispatch1
573 catch.dispatch0:                                  ; preds = %bb0
574   %0 = catchswitch within none [label %catch.start0] unwind to caller
576 catch.start0:                                     ; preds = %catch.dispatch0
577   %1 = catchpad within %0 [ptr null]
578   %2 = call ptr @llvm.wasm.get.exception(token %1)
579   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
580   catchret from %1 to label %try.cont
582 catch.dispatch1:                                  ; preds = %bb1
583   %4 = catchswitch within none [label %catch.start1] unwind to caller
585 catch.start1:                                     ; preds = %catch.dispatch1
586   %5 = catchpad within %4 [ptr null]
587   %6 = call ptr @llvm.wasm.get.exception(token %5)
588   %7 = call i32 @llvm.wasm.get.ehselector(token %5)
589   catchret from %5 to label %try.cont
591 try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1
592   ret void
595 ; Similar situation as @unwind_mismatches_1. Here 'call @qux''s original unwind
596 ; destination was the caller, but after control flow linearization, their unwind
597 ; destination incorrectly becomes 'C0' within the function. We fix this by
598 ; wrapping the call with a nested try-delegate that rethrows the exception to
599 ; the caller.
601 ; Because 'call @qux' pops an argument pushed by 'i32.const 5' from stack, the
602 ; nested 'try' should be placed before `i32.const 5', not between 'i32.const 5'
603 ; and 'call @qux'.
605 ; NOSORT-LABEL: unwind_mismatches_3:
606 ; NOSORT: try       i32
607 ; NOSORT:   call  foo
608 ; --- try-delegate starts (call unwind mismatch)
609 ; NOSORT:   try
610 ; NOSORT:     i32.const  $push{{[0-9]+}}=, 5
611 ; NOSORT:     call  ${{[0-9]+}}=, qux
612 ; NOSORT:   delegate    1                     # label/catch{{[0-9]+}}: to caller
613 ; --- try-delegate ends (call unwind mismatch)
614 ; NOSORT:   return
615 ; NOSORT: catch   {{.*}}                      # catch[[C0:[0-9]+]]:
616 ; NOSORT:   return
617 ; NOSORT: end_try
618 define i32 @unwind_mismatches_3() personality ptr @__gxx_wasm_personality_v0 {
619 bb0:
620   invoke void @foo()
621           to label %bb1 unwind label %catch.dispatch0
623 bb1:                                              ; preds = %bb0
624   %0 = call i32 @qux(i32 5)
625   ret i32 %0
627 catch.dispatch0:                                  ; preds = %bb0
628   %1 = catchswitch within none [label %catch.start0] unwind to caller
630 catch.start0:                                     ; preds = %catch.dispatch0
631   %2 = catchpad within %1 [ptr null]
632   %3 = call ptr @llvm.wasm.get.exception(token %2)
633   %j = call i32 @llvm.wasm.get.ehselector(token %2)
634   catchret from %2 to label %try.cont
636 try.cont:                                         ; preds = %catch.start0
637   ret i32 0
640 ; We have two call unwind unwind mismatches:
641 ; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the
642 ;   CFG, when it is supposed to unwind to another EH pad.
643 ; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the
644 ;   CFG, when it is supposed to unwind to the caller.
645 ; We also have a catch unwind mismatch: If an exception is not caught by the
646 ; first catch because it is a non-C++ exception, it shouldn't unwind to the next
647 ; catch, but it should unwind to the caller.
649 ; NOSORT-LABEL: unwind_mismatches_4:
650 ; NOSORT: try
651 ; --- try-delegate starts (catch unwind mismatch)
652 ; NOSORT:   try
653 ; NOSORT:     try
654 ; NOSORT:       call  foo
655 ; --- try-delegate starts (call unwind mismatch)
656 ; NOSORT:       try
657 ; NOSORT:         call  bar
658 ; NOSORT:       delegate    2            # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
659 ; --- try-delegate ends (call unwind mismatch)
660 ; NOSORT:     catch
661 ; NOSORT:       call  {{.*}} __cxa_begin_catch
662 ; --- try-delegate starts (call unwind mismatch)
663 ; NOSORT:       try
664 ; NOSORT:         call  __cxa_end_catch
665 ; NOSORT:       delegate    3            # label/catch{{[0-9]+}}: to caller
666 ; --- try-delegate ends (call unwind mismatch)
667 ; NOSORT:     end_try
668 ; NOSORT:   delegate    1                # label/catch{{[0-9]+}}: to caller
669 ; --- try-delegate ends (catch unwind mismatch)
670 ; NOSORT: catch  {{.*}}                  # catch[[C0]]:
671 ; NOSORT:   call  {{.*}} __cxa_begin_catch
672 ; NOSORT:   call  __cxa_end_catch
673 ; NOSORT: end_try
674 ; NOSORT: return
675 define void @unwind_mismatches_4() personality ptr @__gxx_wasm_personality_v0 {
676 bb0:
677   invoke void @foo()
678           to label %bb1 unwind label %catch.dispatch0
680 bb1:                                              ; preds = %bb0
681   invoke void @bar()
682           to label %try.cont unwind label %catch.dispatch1
684 catch.dispatch0:                                  ; preds = %bb0
685   %0 = catchswitch within none [label %catch.start0] unwind to caller
687 catch.start0:                                     ; preds = %catch.dispatch0
688   %1 = catchpad within %0 [ptr null]
689   %2 = call ptr @llvm.wasm.get.exception(token %1)
690   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
691   %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
692   call void @__cxa_end_catch() [ "funclet"(token %1) ]
693   catchret from %1 to label %try.cont
695 catch.dispatch1:                                  ; preds = %bb1
696   %5 = catchswitch within none [label %catch.start1] unwind to caller
698 catch.start1:                                     ; preds = %catch.dispatch1
699   %6 = catchpad within %5 [ptr null]
700   %7 = call ptr @llvm.wasm.get.exception(token %6)
701   %8 = call i32 @llvm.wasm.get.ehselector(token %6)
702   %9 = call ptr @__cxa_begin_catch(ptr %7) [ "funclet"(token %6) ]
703   call void @__cxa_end_catch() [ "funclet"(token %6) ]
704   catchret from %6 to label %try.cont
706 try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1
707   ret void
710 ; This crashed when updating EHPadStack within fixCallUniwindMismatch had a bug.
711 ; This should not crash and try-delegate has to be created around 'call @baz',
712 ; because the initial TRY placement for 'call @quux' was done before 'call @baz'
713 ; because 'call @baz''s return value is stackified.
715 ; CHECK-LABEL: unwind_mismatches_5:
716 ; CHECK: try
717 ; --- try-delegate starts (call unwind mismatch)
718 ; CHECK:   try
719 ; CHECK:     call $[[RET:[0-9]+]]=, baz
720 ; CHECK:   delegate  1
721 ; --- try-delegate ends (call unwind mismatch)
722 ; CHECK:    call  quux, $[[RET]]
723 ; CHECK: catch_all
724 ; CHECK: end_try
725 define void @unwind_mismatches_5() personality ptr @__gxx_wasm_personality_v0 {
726 entry:
727   %call = call i32 @baz()
728   invoke void @quux(i32 %call)
729           to label %invoke.cont unwind label %ehcleanup
731 ehcleanup:                                        ; preds = %entry
732   %0 = cleanuppad within none []
733   cleanupret from %0 unwind to caller
735 invoke.cont:                                      ; preds = %entry
736   unreachable
739 ; The structure is similar to unwind_mismatches_0, where the call to 'bar''s
740 ; original unwind destination is catch.dispatch1 but after placing markers it
741 ; unwinds to catch.dispatch0, which we fix. This additionally has a loop before
742 ; the real unwind destination (catch.dispatch1).
744 ; NOSORT-LABEL: unwind_mismatches_with_loop:
745 ; NOSORT: try
746 ; NOSORT:   try
747 ; NOSORT:     try
748 ; NOSORT:       call  foo
749 ; NOSORT:       try
750 ; NOSORT:         call  bar
751 ; NOSORT:       delegate    3                  # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
752 ; NOSORT:     catch  $drop=, __cpp_exception
753 ; NOSORT:     end_try
754 ; NOSORT:   delegate    2                      # label/catch{{[0-9]+}}: to caller
755 ; NOSORT:   loop
756 ; NOSORT:     call  foo
757 ; NOSORT:   end_loop
758 ; NOSORT: catch  $drop=, __cpp_exception       # catch[[C0]]:
759 ; NOSORT:   return
760 ; NOSORT: end_try
761 define void @unwind_mismatches_with_loop() personality ptr @__gxx_wasm_personality_v0 {
762 bb0:
763   invoke void @foo()
764           to label %bb1 unwind label %catch.dispatch0
766 bb1:                                              ; preds = %bb0
767   invoke void @bar()
768           to label %bb2 unwind label %catch.dispatch1
770 catch.dispatch0:                                  ; preds = %bb0
771   %0 = catchswitch within none [label %catch.start0] unwind to caller
773 catch.start0:                                     ; preds = %catch.dispatch0
774   %1 = catchpad within %0 [ptr null]
775   %2 = call ptr @llvm.wasm.get.exception(token %1)
776   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
777   catchret from %1 to label %bb2
779 bb2:
780   invoke void @foo()
781           to label %bb3 unwind label %catch.dispatch1
783 bb3:                                             ; preds = %bb14
784   br label %bb2
786 catch.dispatch1:                                  ; preds = %bb1
787   %4 = catchswitch within none [label %catch.start1] unwind to caller
789 catch.start1:                                     ; preds = %catch.dispatch1
790   %5 = catchpad within %4 [ptr null]
791   %6 = call ptr @llvm.wasm.get.exception(token %5)
792   %7 = call i32 @llvm.wasm.get.ehselector(token %5)
793   catchret from %5 to label %try.cont
795 try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1
796   ret void
799 ; Tests the case when TEE stackifies a register in RegStackify but it gets
800 ; unstackified in fixCallUnwindMismatches in CFGStackify.
802 ; NOSORT-LOCALS-LABEL: unstackify_when_fixing_unwind_mismatch:
803 define void @unstackify_when_fixing_unwind_mismatch(i32 %x) personality ptr @__gxx_wasm_personality_v0 {
804 bb0:
805   invoke void @foo()
806           to label %bb1 unwind label %catch.dispatch0
808 bb1:                                              ; preds = %bb0
809   %t = add i32 %x, 4
810   ; This %addr is used in multiple places, so tee is introduced in RegStackify,
811   ; which stackifies the use of %addr in store instruction. A tee has two dest
812   ; registers, the first of which is stackified and the second is not.
813   ; But when we introduce a nested try-delegate in fixCallUnwindMismatches in
814   ; CFGStackify, we end up unstackifying the first dest register. In that case,
815   ; we convert that tee into a copy.
816   %addr = inttoptr i32 %t to ptr
817   %load = load i32, ptr %addr
818   %call = call i32 @baz()
819   %add = add i32 %load, %call
820   store i32 %add, ptr %addr
821   ret void
822 ; NOSORT-LOCALS:       i32.add
823 ; NOSORT-LOCALS-NOT:   local.tee
824 ; NOSORT-LOCALS-NEXT:  local.set
826 catch.dispatch0:                                  ; preds = %bb0
827   %0 = catchswitch within none [label %catch.start0] unwind to caller
829 catch.start0:                                     ; preds = %catch.dispatch0
830   %1 = catchpad within %0 [ptr null]
831   %2 = call ptr @llvm.wasm.get.exception(token %1)
832   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
833   catchret from %1 to label %try.cont
835 try.cont:                                         ; preds = %catch.start0
836   ret void
839 ; In CFGSort, EH pads should be sorted as soon as it is available and
840 ; 'Preferred' queue and should NOT be entered into 'Ready' queue unless we are
841 ; in the middle of sorting another region that does not contain the EH pad. In
842 ; this example, 'catch.start' should be sorted right after 'if.then' is sorted
843 ; (before 'cont' is sorted) and there should not be any unwind destination
844 ; mismatches in CFGStackify.
846 ; NOOPT-LABEL: cfg_sort_order:
847 ; NOOPT: block
848 ; NOOPT:   try
849 ; NOOPT:     call      foo
850 ; NOOPT:   catch
851 ; NOOPT:   end_try
852 ; NOOPT:   call      foo
853 ; NOOPT: end_block
854 ; NOOPT: return
855 define void @cfg_sort_order(i32 %arg) personality ptr @__gxx_wasm_personality_v0 {
856 entry:
857   %tobool = icmp ne i32 %arg, 0
858   br i1 %tobool, label %if.then, label %if.end
860 catch.dispatch:                                   ; preds = %if.then
861   %0 = catchswitch within none [label %catch.start] unwind to caller
863 catch.start:                                      ; preds = %catch.dispatch
864   %1 = catchpad within %0 [ptr null]
865   %2 = call ptr @llvm.wasm.get.exception(token %1)
866   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
867   %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
868   call void @__cxa_end_catch() [ "funclet"(token %1) ]
869   catchret from %1 to label %if.end
871 if.then:                                          ; preds = %entry
872   invoke void @foo()
873           to label %cont unwind label %catch.dispatch
875 cont:                                             ; preds = %if.then
876   call void @foo()
877   br label %if.end
879 if.end:                                           ; preds = %cont, %catch.start, %entry
880   ret void
883 ; Intrinsics like memcpy, memmove, and memset don't throw and are lowered into
884 ; calls to external symbols (not global addresses) in instruction selection,
885 ; which will be eventually lowered to library function calls.
886 ; Because this test runs with -wasm-disable-ehpad-sort, these library calls in
887 ; invoke.cont BB fall within try~end_try, but they shouldn't cause crashes or
888 ; unwinding destination mismatches in CFGStackify.
890 ; NOSORT-LABEL: mem_intrinsics:
891 ; NOSORT: try
892 ; NOSORT:   call  foo
893 ; NOSORT:   call {{.*}} memcpy
894 ; NOSORT:   call {{.*}} memmove
895 ; NOSORT:   call {{.*}} memset
896 ; NOSORT:   return
897 ; NOSORT: catch_all
898 ; NOSORT:   rethrow 0
899 ; NOSORT: end_try
900 define void @mem_intrinsics(ptr %a, ptr %b) personality ptr @__gxx_wasm_personality_v0 {
901 entry:
902   %o = alloca %class.Object, align 1
903   invoke void @foo()
904           to label %invoke.cont unwind label %ehcleanup
906 invoke.cont:                                      ; preds = %entry
907   call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %b, i32 100, i1 false)
908   call void @llvm.memmove.p0.p0.i32(ptr %a, ptr %b, i32 100, i1 false)
909   call void @llvm.memset.p0.i32(ptr %a, i8 0, i32 100, i1 false)
910   %call = call ptr @_ZN6ObjectD2Ev(ptr %o)
911   ret void
913 ehcleanup:                                        ; preds = %entry
914   %0 = cleanuppad within none []
915   %call2 = call ptr @_ZN6ObjectD2Ev(ptr %o) [ "funclet"(token %0) ]
916   cleanupret from %0 unwind to caller
919 ; Tests if 'try' marker is placed correctly. In this test, 'try' should be
920 ; placed before the call to 'nothrow_i32' and not between the call to
921 ; 'nothrow_i32' and 'fun', because the return value of 'nothrow_i32' is
922 ; stackified and pushed onto the stack to be consumed by the call to 'fun'.
924 ; CHECK-LABEL: try_marker_with_stackified_input:
925 ; CHECK: try
926 ; CHECK: call      $push{{.*}}=, nothrow_i32
927 ; CHECK: call      fun, $pop{{.*}}
928 define void @try_marker_with_stackified_input() personality ptr @__gxx_wasm_personality_v0 {
929 entry:
930   %call = call i32 @nothrow_i32()
931   invoke void @fun(i32 %call)
932           to label %invoke.cont unwind label %terminate
934 invoke.cont:                                      ; preds = %entry
935   ret void
937 terminate:                                        ; preds = %entry
938   %0 = cleanuppad within none []
939   call void @_ZSt9terminatev() [ "funclet"(token %0) ]
940   unreachable
943 ; This crashed on debug mode (= when NDEBUG is not defined) when the logic for
944 ; computing the innermost region was not correct, in which a loop region
945 ; contains an exception region. This should pass CFGSort without crashing.
946 define void @loop_exception_region() personality ptr @__gxx_wasm_personality_v0 {
947 entry:
948   %e = alloca %class.MyClass, align 4
949   br label %for.cond
951 for.cond:                                         ; preds = %for.inc, %entry
952   %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
953   %cmp = icmp slt i32 %i.0, 9
954   br i1 %cmp, label %for.body, label %for.end
956 for.body:                                         ; preds = %for.cond
957   invoke void @quux(i32 %i.0)
958           to label %for.inc unwind label %catch.dispatch
960 catch.dispatch:                                   ; preds = %for.body
961   %0 = catchswitch within none [label %catch.start] unwind to caller
963 catch.start:                                      ; preds = %catch.dispatch
964   %1 = catchpad within %0 [ptr @_ZTI7MyClass]
965   %2 = call ptr @llvm.wasm.get.exception(token %1)
966   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
967   %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTI7MyClass)
968   %matches = icmp eq i32 %3, %4
969   br i1 %matches, label %catch, label %rethrow
971 catch:                                            ; preds = %catch.start
972   %5 = call ptr @__cxa_get_exception_ptr(ptr %2) [ "funclet"(token %1) ]
973   %call = call ptr @_ZN7MyClassC2ERKS_(ptr %e, ptr dereferenceable(4) %5) [ "funclet"(token %1) ]
974   %6 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
975   %7 = load i32, ptr %e, align 4
976   invoke void @quux(i32 %7) [ "funclet"(token %1) ]
977           to label %invoke.cont2 unwind label %ehcleanup
979 invoke.cont2:                                     ; preds = %catch
980   %call3 = call ptr @_ZN7MyClassD2Ev(ptr %e) [ "funclet"(token %1) ]
981   call void @__cxa_end_catch() [ "funclet"(token %1) ]
982   catchret from %1 to label %for.inc
984 rethrow:                                          ; preds = %catch.start
985   call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
986   unreachable
988 for.inc:                                          ; preds = %invoke.cont2, %for.body
989   %inc = add nsw i32 %i.0, 1
990   br label %for.cond
992 ehcleanup:                                        ; preds = %catch
993   %8 = cleanuppad within %1 []
994   %call4 = call ptr @_ZN7MyClassD2Ev(ptr %e) [ "funclet"(token %8) ]
995   invoke void @__cxa_end_catch() [ "funclet"(token %8) ]
996           to label %invoke.cont6 unwind label %terminate7
998 invoke.cont6:                                     ; preds = %ehcleanup
999   cleanupret from %8 unwind to caller
1001 for.end:                                          ; preds = %for.cond
1002   ret void
1004 terminate7:                                       ; preds = %ehcleanup
1005   %9 = cleanuppad within %8 []
1006   call void @_ZSt9terminatev() [ "funclet"(token %9) ]
1007   unreachable
1010 ; Tests if CFGStackify's removeUnnecessaryInstrs() removes unnecessary branches
1011 ; correctly. The code is in the form below, where 'br' is unnecessary because
1012 ; after running the 'try' body the control flow will fall through to bb2 anyway.
1014 ; bb0:
1015 ;   try
1016 ;     ...
1017 ;     br bb2      <- Not necessary
1018 ; bb1 (ehpad):
1019 ;   catch
1020 ;     ...
1021 ; bb2:            <- Continuation BB
1022 ;   end
1023 ; CHECK-LABEL: remove_unnecessary_instrs:
1024 define void @remove_unnecessary_instrs(i32 %n) personality ptr @__gxx_wasm_personality_v0 {
1025 entry:
1026   invoke void @foo()
1027           to label %for.body unwind label %catch.dispatch
1029 for.body:                                         ; preds = %for.end, %entry
1030   %i = phi i32 [ %inc, %for.end ], [ 0, %entry ]
1031   invoke void @foo()
1032           to label %for.end unwind label %catch.dispatch
1034 ; Before going to CFGStackify, this BB will have a conditional branch followed
1035 ; by an unconditional branch. CFGStackify should remove only the unconditional
1036 ; one.
1037 for.end:                                          ; preds = %for.body
1038   %inc = add nuw nsw i32 %i, 1
1039   %exitcond = icmp eq i32 %inc, %n
1040   br i1 %exitcond, label %try.cont, label %for.body
1041 ; CHECK: br_if
1042 ; CHECK-NOT: br
1043 ; CHECK: end_loop
1044 ; CHECK: catch
1046 catch.dispatch:                                   ; preds = %for.body, %entry
1047   %0 = catchswitch within none [label %catch.start] unwind to caller
1049 catch.start:                                      ; preds = %catch.dispatch
1050   %1 = catchpad within %0 [ptr null]
1051   %2 = call ptr @llvm.wasm.get.exception(token %1)
1052   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1053   %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
1054   call void @__cxa_end_catch() [ "funclet"(token %1) ]
1055   catchret from %1 to label %try.cont
1057 try.cont:                                         ; preds = %catch.start, %for.end
1058   ret void
1061 ; void foo();
1062 ; void remove_unnecessary_br() {
1063 ;   try {
1064 ;     foo();
1065 ;     try {
1066 ;       foo();
1067 ;     } catch (...) {
1068 ;     }
1069 ;   } catch (...) {
1070 ;   }
1071 ; }
1073 ; This tests whether the 'br' can be removed in code in the form as follows.
1074 ; Here 'br' is inside an inner try, whose 'end' is in another EH pad. In this
1075 ; case, after running an inner try body, the control flow should fall through to
1076 ; bb3, so the 'br' in the code is unnecessary.
1078 ; bb0:
1079 ;   try
1080 ;     try
1081 ;       ...
1082 ;       br bb3      <- Not necessary
1083 ; bb1:
1084 ;     catch
1085 ; bb2:
1086 ;     end_try
1087 ;   catch
1088 ;     ...
1089 ; bb3:            <- Continuation BB
1090 ;   end
1092 ; CHECK-LABEL: remove_unnecessary_br:
1093 define void @remove_unnecessary_br() personality ptr @__gxx_wasm_personality_v0 {
1094 ; CHECK: call foo
1095 entry:
1096   invoke void @foo()
1097           to label %invoke.cont unwind label %catch.dispatch3
1099 ; CHECK: call foo
1100 ; CHECK-NOT: br
1101 invoke.cont:                                      ; preds = %entry
1102   invoke void @foo()
1103           to label %try.cont8 unwind label %catch.dispatch
1105 catch.dispatch:                                   ; preds = %invoke.cont
1106   %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch3
1108 ; CHECK: catch
1109 catch.start:                                      ; preds = %catch.dispatch
1110   %1 = catchpad within %0 [ptr null]
1111   %2 = call ptr @llvm.wasm.get.exception(token %1)
1112   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1113   %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
1114   invoke void @__cxa_end_catch() [ "funclet"(token %1) ]
1115           to label %invoke.cont2 unwind label %catch.dispatch3
1117 catch.dispatch3:                                  ; preds = %catch.start, %catch.dispatch, %entry
1118   %5 = catchswitch within none [label %catch.start4] unwind to caller
1120 catch.start4:                                     ; preds = %catch.dispatch3
1121   %6 = catchpad within %5 [ptr null]
1122   %7 = call ptr @llvm.wasm.get.exception(token %6)
1123   %8 = call i32 @llvm.wasm.get.ehselector(token %6)
1124   %9 = call ptr @__cxa_begin_catch(ptr %7) [ "funclet"(token %6) ]
1125   call void @__cxa_end_catch() [ "funclet"(token %6) ]
1126   catchret from %6 to label %try.cont8
1128 try.cont8:                                        ; preds = %invoke.cont2, %catch.start4, %invoke.cont
1129   ret void
1131 invoke.cont2:                                     ; preds = %catch.start
1132   catchret from %1 to label %try.cont8
1135 ; Here an exception is semantically contained in a loop. 'ehcleanup' BB belongs
1136 ; to the exception, but does not belong to the loop (because it does not have a
1137 ; path back to the loop header), and is placed after the loop latch block
1138 ; 'invoke.cont' intentionally. This tests if 'end_loop' marker is placed
1139 ; correctly not right after 'invoke.cont' part but after 'ehcleanup' part.
1140 ; NOSORT-LABEL: loop_contains_exception:
1141 ; NOSORT: loop
1142 ; NOSORT:   try
1143 ; NOSORT:     try
1144 ; NOSORT:     end_try
1145 ; NOSORT:   end_try
1146 ; NOSORT: end_loop
1147 define void @loop_contains_exception(i32 %n) personality ptr @__gxx_wasm_personality_v0 {
1148 entry:
1149   br label %while.cond
1151 while.cond:                                       ; preds = %invoke.cont, %entry
1152   %n.addr.0 = phi i32 [ %n, %entry ], [ %dec, %invoke.cont ]
1153   %tobool = icmp ne i32 %n.addr.0, 0
1154   br i1 %tobool, label %while.body, label %while.end
1156 while.body:                                       ; preds = %while.cond
1157   %dec = add nsw i32 %n.addr.0, -1
1158   invoke void @foo()
1159           to label %while.end unwind label %catch.dispatch
1161 catch.dispatch:                                   ; preds = %while.body
1162   %0 = catchswitch within none [label %catch.start] unwind to caller
1164 catch.start:                                      ; preds = %catch.dispatch
1165   %1 = catchpad within %0 [ptr null]
1166   %2 = call ptr @llvm.wasm.get.exception(token %1)
1167   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1168   %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
1169   invoke void @__cxa_end_catch() [ "funclet"(token %1) ]
1170           to label %invoke.cont unwind label %ehcleanup
1172 invoke.cont:                                      ; preds = %catch.start
1173   catchret from %1 to label %while.cond
1175 ehcleanup:                                        ; preds = %catch.start
1176   %5 = cleanuppad within %1 []
1177   call void @_ZSt9terminatev() [ "funclet"(token %5) ]
1178   unreachable
1180 while.end:                                        ; preds = %while.body, %while.cond
1181   ret void
1184 ; When the function return type is non-void and 'end' instructions are at the
1185 ; very end of a function, CFGStackify's fixEndsAtEndOfFunction function fixes
1186 ; the corresponding block/loop/try's type to match the function's return type.
1187 ; But when a `try`'s type is fixed, we should also check `end` instructions
1188 ; before its corresponding `catch_all`, because both `try` and `catch_all` body
1189 ; should satisfy the return type requirements.
1191 ; NOSORT-LABEL: fix_function_end_return_type_with_try_catch:
1192 ; NOSORT: try i32
1193 ; NOSORT: loop i32
1194 ; NOSORT: end_loop
1195 ; NOSORT: catch_all
1196 ; NOSORT: end_try
1197 ; NOSORT-NEXT: end_function
1198 define i32 @fix_function_end_return_type_with_try_catch(i32 %n) personality ptr @__gxx_wasm_personality_v0 {
1199 entry:
1200   %t = alloca %class.Object, align 1
1201   br label %for.cond
1203 for.cond:                                         ; preds = %for.inc, %entry
1204   %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
1205   %cmp = icmp slt i32 %i.0, %n
1206   br label %for.body
1208 for.body:                                         ; preds = %for.cond
1209   %div = sdiv i32 %n, 2
1210   %cmp1 = icmp eq i32 %i.0, %div
1211   br i1 %cmp1, label %if.then, label %for.inc
1213 if.then:                                          ; preds = %for.body
1214   %call = invoke i32 @baz()
1215           to label %invoke.cont unwind label %ehcleanup
1217 invoke.cont:                                      ; preds = %if.then
1218   %call2 = call ptr @_ZN6ObjectD2Ev(ptr %t)
1219   ret i32 %call
1221 for.inc:                                          ; preds = %for.body
1222   %inc = add nsw i32 %i.0, 1
1223   br label %for.cond
1225 ehcleanup:                                        ; preds = %if.then
1226   %0 = cleanuppad within none []
1227   %call3 = call ptr @_ZN6ObjectD2Ev(ptr %t) [ "funclet"(token %0) ]
1228   cleanupret from %0 unwind to caller
1231 ; This tests if invalidated branch destinations after fixing catch unwind
1232 ; mismatches are correctly remapped. For example, we have this code and suppose
1233 ; we need to wrap this try-catch-end in this code with a try-delegate to fix a
1234 ; catch unwind mismatch:
1235   ; - Before:
1236 ; block
1237 ;   br (a)
1238 ;   try
1239 ;   catch
1240 ;   end_try
1241 ; end_block
1242 ;           <- (a)
1244 ; - After
1245 ; block
1246 ;   br (a)
1247 ;   try
1248 ;     try
1249 ;     catch
1250 ;     end_try
1251 ;           <- (a)
1252 ;   delegate
1253 ; end_block
1254 ;           <- (b)
1255 ; After adding a try-delegate, the 'br's destination BB, where (a) points,
1256 ; becomes invalid because it incorrectly branches into an inner scope. The
1257 ; destination should change to the BB where (b) points.
1259 ; NOSORT-LABEL: branch_remapping_after_fixing_unwind_mismatches_0:
1260 ; NOSORT: try
1261 ; NOSORT:   br_if   0
1262 define void @branch_remapping_after_fixing_unwind_mismatches_0(i1 %arg) personality ptr @__gxx_wasm_personality_v0 {
1263 entry:
1264   br i1 %arg, label %bb0, label %dest
1266 bb0:                                              ; preds = %entry
1267   invoke void @foo()
1268           to label %bb1 unwind label %catch.dispatch0
1270 bb1:                                              ; preds = %bb0
1271   invoke void @bar()
1272           to label %try.cont unwind label %catch.dispatch1
1274 catch.dispatch0:                                  ; preds = %bb0
1275   %0 = catchswitch within none [label %catch.start0] unwind to caller
1277 catch.start0:                                     ; preds = %catch.dispatch0
1278   %1 = catchpad within %0 [ptr null]
1279   %2 = call ptr @llvm.wasm.get.exception(token %1)
1280   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1281   catchret from %1 to label %try.cont
1283 dest:                                             ; preds = %entry
1284   ret void
1286 catch.dispatch1:                                  ; preds = %bb1
1287   %4 = catchswitch within none [label %catch.start1] unwind to caller
1289 catch.start1:                                     ; preds = %catch.dispatch1
1290   %5 = catchpad within %4 [ptr null]
1291   %6 = call ptr @llvm.wasm.get.exception(token %5)
1292   %7 = call i32 @llvm.wasm.get.ehselector(token %5)
1293   catchret from %5 to label %try.cont
1295 try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1
1296   ret void
1299 ; The similar case with branch_remapping_after_fixing_unwind_mismatches_0, but
1300 ; multiple consecutive delegates are generated:
1301 ; - Before:
1302 ; block
1303 ;   br (a)
1304 ;   try
1305 ;   catch
1306 ;   end_try
1307 ; end_block
1308 ;           <- (a)
1310 ; - After
1311 ; block
1312 ;   br (a)
1313 ;   try
1314 ;     ...
1315 ;     try
1316 ;       try
1317 ;       catch
1318 ;       end_try
1319 ;             <- (a)
1320 ;     delegate
1321 ;   delegate
1322 ; end_block
1323 ;           <- (b) The br destination should be remapped to here
1325 ; The test was reduced by bugpoint and should not crash in CFGStackify.
1326 define void @branch_remapping_after_fixing_unwind_mismatches_1() personality ptr @__gxx_wasm_personality_v0 {
1327 entry:
1328   br i1 undef, label %if.then, label %if.end12
1330 if.then:                                          ; preds = %entry
1331   invoke void @__cxa_throw(ptr null, ptr null, ptr null) #1
1332           to label %unreachable unwind label %catch.dispatch
1334 catch.dispatch:                                   ; preds = %if.then
1335   %0 = catchswitch within none [label %catch.start] unwind to caller
1337 catch.start:                                      ; preds = %catch.dispatch
1338   %1 = catchpad within %0 [ptr @_ZTIi]
1339   %2 = call ptr @llvm.wasm.get.exception(token %1)
1340   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1341   catchret from %1 to label %catchret.dest
1343 catchret.dest:                                    ; preds = %catch.start
1344   invoke void @foo()
1345           to label %invoke.cont unwind label %catch.dispatch4
1347 invoke.cont:                                      ; preds = %catchret.dest
1348   invoke void @__cxa_throw(ptr null, ptr null, ptr null) #1
1349           to label %unreachable unwind label %catch.dispatch4
1351 catch.dispatch4:                                  ; preds = %invoke.cont, %catchret.dest
1352   %4 = catchswitch within none [label %catch.start5] unwind to caller
1354 catch.start5:                                     ; preds = %catch.dispatch4
1355   %5 = catchpad within %4 [ptr @_ZTIi]
1356   %6 = call ptr @llvm.wasm.get.exception(token %5)
1357   %7 = call i32 @llvm.wasm.get.ehselector(token %5)
1358   unreachable
1360 if.end12:                                         ; preds = %entry
1361   invoke void @foo()
1362           to label %invoke.cont14 unwind label %catch.dispatch16
1364 catch.dispatch16:                                 ; preds = %if.end12
1365   %8 = catchswitch within none [label %catch.start17] unwind label %ehcleanup
1367 catch.start17:                                    ; preds = %catch.dispatch16
1368   %9 = catchpad within %8 [ptr @_ZTIi]
1369   %10 = call ptr @llvm.wasm.get.exception(token %9)
1370   %11 = call i32 @llvm.wasm.get.ehselector(token %9)
1371   br i1 undef, label %catch20, label %rethrow19
1373 catch20:                                          ; preds = %catch.start17
1374   catchret from %9 to label %catchret.dest22
1376 catchret.dest22:                                  ; preds = %catch20
1377   br label %try.cont23
1379 rethrow19:                                        ; preds = %catch.start17
1380   invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %9) ]
1381           to label %unreachable unwind label %ehcleanup
1383 try.cont23:                                       ; preds = %invoke.cont14, %catchret.dest22
1384   invoke void @foo()
1385           to label %invoke.cont24 unwind label %ehcleanup
1387 invoke.cont24:                                    ; preds = %try.cont23
1388   ret void
1390 invoke.cont14:                                    ; preds = %if.end12
1391   br label %try.cont23
1393 ehcleanup:                                        ; preds = %try.cont23, %rethrow19, %catch.dispatch16
1394   %12 = cleanuppad within none []
1395   cleanupret from %12 unwind to caller
1397 unreachable:                                      ; preds = %rethrow19, %invoke.cont, %if.then
1398   unreachable
1401 ; Regression test for WasmEHFuncInfo's reverse mapping bug. 'UnwindDestToSrc'
1402 ; should return a vector and not a single BB, which was incorrect.
1403 ; This was reduced by bugpoint and should not crash in CFGStackify.
1404 define void @wasm_eh_func_info_regression_test() personality ptr @__gxx_wasm_personality_v0 {
1405 entry:
1406   invoke void @foo()
1407           to label %invoke.cont unwind label %catch.dispatch
1409 catch.dispatch:                                   ; preds = %entry
1410   %0 = catchswitch within none [label %catch.start] unwind label %ehcleanup22
1412 catch.start:                                      ; preds = %catch.dispatch
1413   %1 = catchpad within %0 [ptr @_ZTIi]
1414   %2 = call ptr @llvm.wasm.get.exception(token %1)
1415   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1416   invoke void @__cxa_throw(ptr null, ptr null, ptr null) #1 [ "funclet"(token %1) ]
1417           to label %unreachable unwind label %catch.dispatch2
1419 catch.dispatch2:                                  ; preds = %catch.start
1420   %4 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup
1422 catch.start3:                                     ; preds = %catch.dispatch2
1423   %5 = catchpad within %4 [ptr @_ZTIi]
1424   %6 = call ptr @llvm.wasm.get.exception(token %5)
1425   %7 = call i32 @llvm.wasm.get.ehselector(token %5)
1426   catchret from %5 to label %try.cont
1428 try.cont:                                         ; preds = %catch.start3
1429   invoke void @foo() [ "funclet"(token %1) ]
1430           to label %invoke.cont8 unwind label %ehcleanup
1432 invoke.cont8:                                     ; preds = %try.cont
1433   invoke void @__cxa_throw(ptr null, ptr null, ptr null) #1 [ "funclet"(token %1) ]
1434           to label %unreachable unwind label %catch.dispatch11
1436 catch.dispatch11:                                 ; preds = %invoke.cont8
1437   %8 = catchswitch within %1 [label %catch.start12] unwind label %ehcleanup
1439 catch.start12:                                    ; preds = %catch.dispatch11
1440   %9 = catchpad within %8 [ptr @_ZTIi]
1441   %10 = call ptr @llvm.wasm.get.exception(token %9)
1442   %11 = call i32 @llvm.wasm.get.ehselector(token %9)
1443   unreachable
1445 invoke.cont:                                      ; preds = %entry
1446   unreachable
1448 ehcleanup:                                        ; preds = %catch.dispatch11, %try.cont, %catch.dispatch2
1449   %12 = cleanuppad within %1 []
1450   cleanupret from %12 unwind label %ehcleanup22
1452 ehcleanup22:                                      ; preds = %ehcleanup, %catch.dispatch
1453   %13 = cleanuppad within none []
1454   cleanupret from %13 unwind to caller
1456 unreachable:                                      ; preds = %invoke.cont8, %catch.start
1457   unreachable
1460 ; void exception_grouping_0() {
1461 ;   try {
1462 ;     try {
1463 ;       throw 0;
1464 ;     } catch (int) {
1465 ;     }
1466 ;   } catch (int) {
1467 ;   }
1468 ; }
1470 ; Regression test for a WebAssemblyException grouping bug. After catchswitches
1471 ; are removed, EH pad catch.start2 is dominated by catch.start, but because
1472 ; catch.start2 is the unwind destination of catch.start, it should not be
1473 ; included in catch.start's exception. Also, after we take catch.start2's
1474 ; exception out of catch.start's exception, we have to take out try.cont8 out of
1475 ; catch.start's exception, because it has a predecessor in catch.start2.
1476 define void @exception_grouping_0() personality ptr @__gxx_wasm_personality_v0 {
1477 entry:
1478   %exception = call ptr @__cxa_allocate_exception(i32 4) #0
1479   store i32 0, ptr %exception, align 16
1480   invoke void @__cxa_throw(ptr %exception, ptr @_ZTIi, ptr null) #1
1481           to label %unreachable unwind label %catch.dispatch
1483 catch.dispatch:                                   ; preds = %entry
1484   %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch1
1486 catch.start:                                      ; preds = %catch.dispatch
1487   %1 = catchpad within %0 [ptr @_ZTIi]
1488   %2 = call ptr @llvm.wasm.get.exception(token %1)
1489   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1490   %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #0
1491   %matches = icmp eq i32 %3, %4
1492   br i1 %matches, label %catch, label %rethrow
1494 catch:                                            ; preds = %catch.start
1495   %5 = call ptr @__cxa_begin_catch(ptr %2) #0 [ "funclet"(token %1) ]
1496   %6 = load i32, ptr %5, align 4
1497   call void @__cxa_end_catch() #0 [ "funclet"(token %1) ]
1498   catchret from %1 to label %catchret.dest
1500 catchret.dest:                                    ; preds = %catch
1501   br label %try.cont
1503 rethrow:                                          ; preds = %catch.start
1504   invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]
1505           to label %unreachable unwind label %catch.dispatch1
1507 catch.dispatch1:                                  ; preds = %rethrow, %catch.dispatch
1508   %7 = catchswitch within none [label %catch.start2] unwind to caller
1510 catch.start2:                                     ; preds = %catch.dispatch1
1511   %8 = catchpad within %7 [ptr @_ZTIi]
1512   %9 = call ptr @llvm.wasm.get.exception(token %8)
1513   %10 = call i32 @llvm.wasm.get.ehselector(token %8)
1514   %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #0
1515   %matches3 = icmp eq i32 %10, %11
1516   br i1 %matches3, label %catch5, label %rethrow4
1518 catch5:                                           ; preds = %catch.start2
1519   %12 = call ptr @__cxa_begin_catch(ptr %9) #0 [ "funclet"(token %8) ]
1520   %13 = load i32, ptr %12, align 4
1521   call void @__cxa_end_catch() #0 [ "funclet"(token %8) ]
1522   catchret from %8 to label %catchret.dest7
1524 catchret.dest7:                                   ; preds = %catch5
1525   br label %try.cont8
1527 rethrow4:                                         ; preds = %catch.start2
1528   call void @llvm.wasm.rethrow() #1 [ "funclet"(token %8) ]
1529   unreachable
1531 try.cont8:                                        ; preds = %try.cont, %catchret.dest7
1532   ret void
1534 try.cont:                                         ; preds = %catchret.dest
1535   br label %try.cont8
1537 unreachable:                                      ; preds = %rethrow, %entry
1538   unreachable
1541 ; Test for WebAssemblyException grouping. This test is hand-modified to generate
1542 ; this structure:
1543 ; catch.start dominates catch.start4 and catch.start4 dominates catch.start12,
1544 ; so the after dominator-based grouping, we end up with:
1545 ; catch.start's exception > catch4.start's exception > catch12.start's exception
1546 ; (> here represents subexception relationship)
1548 ; But the unwind destination chain is catch.start -> catch.start4 ->
1549 ; catch.start12. So all these subexception relationship should be deconstructed.
1550 ; We have to make sure to take out catch.start4's exception out of catch.start's
1551 ; exception first, before taking out catch.start12's exception out of
1552 ; catch.start4's exception; otherwise we end up with an incorrect relationship
1553 ; of catch.start's exception > catch.start12's exception.
1554 define void @exception_grouping_1() personality ptr @__gxx_wasm_personality_v0 {
1555 entry:
1556   invoke void @foo()
1557           to label %invoke.cont unwind label %catch.dispatch
1559 invoke.cont:                                      ; preds = %entry
1560   invoke void @foo()
1561           to label %invoke.cont1 unwind label %catch.dispatch
1563 invoke.cont1:                                     ; preds = %invoke.cont
1564   invoke void @foo()
1565           to label %try.cont18 unwind label %catch.dispatch
1567 catch.dispatch11:                                 ; preds = %rethrow6, %catch.dispatch3
1568   %0 = catchswitch within none [label %catch.start12] unwind to caller
1570 catch.start12:                                    ; preds = %catch.dispatch11
1571   %1 = catchpad within %0 [ptr @_ZTIi]
1572   %2 = call ptr @llvm.wasm.get.exception(token %1)
1573   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1574   %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #0
1575   %matches13 = icmp eq i32 %3, %4
1576   br i1 %matches13, label %catch15, label %rethrow14
1578 catch15:                                          ; preds = %catch.start12
1579   %5 = call ptr @__cxa_begin_catch(ptr %2) #0 [ "funclet"(token %1) ]
1580   %6 = load i32, ptr %5, align 4
1581   call void @__cxa_end_catch() #0 [ "funclet"(token %1) ]
1582   catchret from %1 to label %try.cont18
1584 rethrow14:                                        ; preds = %catch.start12
1585   call void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]
1586   unreachable
1588 catch.dispatch3:                                  ; preds = %rethrow, %catch.dispatch
1589   %7 = catchswitch within none [label %catch.start4] unwind label %catch.dispatch11
1591 catch.start4:                                     ; preds = %catch.dispatch3
1592   %8 = catchpad within %7 [ptr @_ZTIi]
1593   %9 = call ptr @llvm.wasm.get.exception(token %8)
1594   %10 = call i32 @llvm.wasm.get.ehselector(token %8)
1595   %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #0
1596   %matches5 = icmp eq i32 %10, %11
1597   br i1 %matches5, label %catch7, label %rethrow6
1599 catch7:                                           ; preds = %catch.start4
1600   %12 = call ptr @__cxa_begin_catch(ptr %9) #0 [ "funclet"(token %8) ]
1601   %13 = load i32, ptr %12, align 4
1602   call void @__cxa_end_catch() #0 [ "funclet"(token %8) ]
1603   catchret from %8 to label %try.cont18
1605 rethrow6:                                         ; preds = %catch.start4
1606   invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %8) ]
1607           to label %unreachable unwind label %catch.dispatch11
1609 catch.dispatch:                                   ; preds = %invoke.cont1, %invoke.cont, %entry
1610   %14 = catchswitch within none [label %catch.start] unwind label %catch.dispatch3
1612 catch.start:                                      ; preds = %catch.dispatch
1613   %15 = catchpad within %14 [ptr @_ZTIi]
1614   %16 = call ptr @llvm.wasm.get.exception(token %15)
1615   %17 = call i32 @llvm.wasm.get.ehselector(token %15)
1616   %18 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #0
1617   %matches = icmp eq i32 %17, %18
1618   br i1 %matches, label %catch, label %rethrow
1620 catch:                                            ; preds = %catch.start
1621   %19 = call ptr @__cxa_begin_catch(ptr %16) #0 [ "funclet"(token %15) ]
1622   %20 = load i32, ptr %19, align 4
1623   call void @__cxa_end_catch() #0 [ "funclet"(token %15) ]
1624   catchret from %15 to label %try.cont18
1626 rethrow:                                          ; preds = %catch.start
1627   invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %15) ]
1628           to label %unreachable unwind label %catch.dispatch3
1630 try.cont18:                                       ; preds = %catch, %catch7, %catch15, %invoke.cont1
1631   ret void
1633 unreachable:                                      ; preds = %rethrow, %rethrow6
1634   unreachable
1637 ; void exception_grouping_2() {
1638 ;   try {
1639 ;     try {
1640 ;       throw 0;
1641 ;     } catch (int) { // (a)
1642 ;     }
1643 ;   } catch (int) {   // (b)
1644 ;   }
1645 ;   try {
1646 ;     foo();
1647 ;   } catch (int) {   // (c)
1648 ;   }
1649 ; }
1651 ; Regression test for an ExceptionInfo grouping bug. Because the first (inner)
1652 ; try always throws, both EH pads (b) (catch.start2) and (c) (catch.start10) are
1653 ; dominated by EH pad (a) (catch.start), even though they are not semantically
1654 ; contained in (a)'s exception. Because (a)'s unwind destination is (b), (b)'s
1655 ; exception is taken out of (a)'s. But because (c) is reachable from (b), we
1656 ; should make sure to take out (c)'s exception out of (a)'s exception too.
1657 define void @exception_grouping_2() personality ptr @__gxx_wasm_personality_v0 {
1658 entry:
1659   %exception = call ptr @__cxa_allocate_exception(i32 4) #1
1660   store i32 0, ptr %exception, align 16
1661   invoke void @__cxa_throw(ptr %exception, ptr @_ZTIi, ptr null) #3
1662           to label %unreachable unwind label %catch.dispatch
1664 catch.dispatch:                                   ; preds = %entry
1665   %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch1
1667 catch.start:                                      ; preds = %catch.dispatch
1668   %1 = catchpad within %0 [ptr @_ZTIi]
1669   %2 = call ptr @llvm.wasm.get.exception(token %1)
1670   %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1671   %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #1
1672   %matches = icmp eq i32 %3, %4
1673   br i1 %matches, label %catch, label %rethrow
1675 catch:                                            ; preds = %catch.start
1676   %5 = call ptr @__cxa_begin_catch(ptr %2) #1 [ "funclet"(token %1) ]
1677   %6 = load i32, ptr %5, align 4
1678   call void @__cxa_end_catch() #1 [ "funclet"(token %1) ]
1679   catchret from %1 to label %try.cont8
1681 rethrow:                                          ; preds = %catch.start
1682   invoke void @llvm.wasm.rethrow() #3 [ "funclet"(token %1) ]
1683           to label %unreachable unwind label %catch.dispatch1
1685 catch.dispatch1:                                  ; preds = %rethrow, %catch.dispatch
1686   %7 = catchswitch within none [label %catch.start2] unwind to caller
1688 catch.start2:                                     ; preds = %catch.dispatch1
1689   %8 = catchpad within %7 [ptr @_ZTIi]
1690   %9 = call ptr @llvm.wasm.get.exception(token %8)
1691   %10 = call i32 @llvm.wasm.get.ehselector(token %8)
1692   %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #1
1693   %matches3 = icmp eq i32 %10, %11
1694   br i1 %matches3, label %catch5, label %rethrow4
1696 catch5:                                           ; preds = %catch.start2
1697   %12 = call ptr @__cxa_begin_catch(ptr %9) #1 [ "funclet"(token %8) ]
1698   %13 = load i32, ptr %12, align 4
1699   call void @__cxa_end_catch() #1 [ "funclet"(token %8) ]
1700   catchret from %8 to label %try.cont8
1702 rethrow4:                                         ; preds = %catch.start2
1703   call void @llvm.wasm.rethrow() #3 [ "funclet"(token %8) ]
1704   unreachable
1706 try.cont8:                                        ; preds = %catch, %catch5
1707   invoke void @foo()
1708           to label %try.cont16 unwind label %catch.dispatch9
1710 catch.dispatch9:                                  ; preds = %try.cont8
1711   %14 = catchswitch within none [label %catch.start10] unwind to caller
1713 catch.start10:                                    ; preds = %catch.dispatch9
1714   %15 = catchpad within %14 [ptr @_ZTIi]
1715   %16 = call ptr @llvm.wasm.get.exception(token %15)
1716   %17 = call i32 @llvm.wasm.get.ehselector(token %15)
1717   %18 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #1
1718   %matches11 = icmp eq i32 %17, %18
1719   br i1 %matches11, label %catch13, label %rethrow12
1721 catch13:                                          ; preds = %catch.start10
1722   %19 = call ptr @__cxa_begin_catch(ptr %16) #1 [ "funclet"(token %15) ]
1723   %20 = load i32, ptr %19, align 4
1724   call void @__cxa_end_catch() #1 [ "funclet"(token %15) ]
1725   catchret from %15 to label %try.cont16
1727 rethrow12:                                        ; preds = %catch.start10
1728   call void @llvm.wasm.rethrow() #3 [ "funclet"(token %15) ]
1729   unreachable
1731 try.cont16:                                       ; preds = %try.cont8, %catch13
1732   ret void
1734 unreachable:                                      ; preds = %rethrow, %entry
1735   unreachable
1738 ; Check if the unwind destination mismatch stats are correct
1739 ; NOSORT: 24 wasm-cfg-stackify    - Number of call unwind mismatches found
1740 ; NOSORT:  5 wasm-cfg-stackify    - Number of catch unwind mismatches found
1742 declare void @foo()
1743 declare void @bar()
1744 declare i32 @baz()
1745 declare i32 @qux(i32)
1746 declare void @quux(i32)
1747 declare void @fun(i32)
1748 ; Function Attrs: nounwind
1749 declare void @nothrow(i32) #0
1750 ; Function Attrs: nounwind
1751 declare i32 @nothrow_i32() #0
1753 ; Function Attrs: nounwind
1754 declare ptr @_ZN6ObjectD2Ev(ptr returned) #0
1755 @_ZTI7MyClass = external constant { ptr, ptr }, align 4
1756 ; Function Attrs: nounwind
1757 declare ptr @_ZN7MyClassD2Ev(ptr returned) #0
1758 ; Function Attrs: nounwind
1759 declare ptr @_ZN7MyClassC2ERKS_(ptr returned, ptr dereferenceable(4)) #0
1761 declare i32 @__gxx_wasm_personality_v0(...)
1762 ; Function Attrs: nounwind
1763 declare ptr @llvm.wasm.get.exception(token) #0
1764 ; Function Attrs: nounwind
1765 declare i32 @llvm.wasm.get.ehselector(token) #0
1766 declare ptr @__cxa_allocate_exception(i32) #0
1767 declare void @__cxa_throw(ptr, ptr, ptr)
1768 ; Function Attrs: noreturn
1769 declare void @llvm.wasm.rethrow() #1
1770 ; Function Attrs: nounwind
1771 declare i32 @llvm.eh.typeid.for(ptr) #0
1773 declare ptr @__cxa_begin_catch(ptr)
1774 declare void @__cxa_end_catch()
1775 declare ptr @__cxa_get_exception_ptr(ptr)
1776 declare void @_ZSt9terminatev()
1777 ; Function Attrs: nounwind
1778 declare void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i32, i1 immarg) #0
1779 ; Function Attrs: nounwind
1780 declare void @llvm.memmove.p0.p0.i32(ptr nocapture, ptr nocapture readonly, i32, i1 immarg) #0
1781 ; Function Attrs: nounwind
1782 declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #0
1784 attributes #0 = { nounwind }
1785 attributes #1 = { noreturn }