2 ; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling | FileCheck %s
3 ; RUN: llc < %s -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling
4 ; RUN: llc < %s -O0 -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -verify-machineinstrs -exception-model=wasm -mattr=+exception-handling | FileCheck %s --check-prefix=NOOPT
5 ; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling -wasm-disable-ehpad-sort -stats 2>&1 | FileCheck %s --check-prefix=NOSORT
6 ; RUN: llc < %s -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling -wasm-disable-ehpad-sort | FileCheck %s --check-prefix=NOSORT-LOCALS
8 target triple = "wasm32-unknown-unknown"
10 @_ZTIi = external constant i8*
11 @_ZTId = external constant i8*
13 %class.Object = type { i8 }
14 %class.MyClass = type { i32 }
16 ; Simple test case with two catch clauses
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]]:
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 i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
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 [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)]
55 %2 = call i8* @llvm.wasm.get.exception(token %1)
56 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
57 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
58 %matches = icmp eq i32 %3, %4
59 br i1 %matches, label %catch2, label %catch.fallthrough
61 catch2: ; preds = %catch.start
62 %5 = call i8* @__cxa_begin_catch(i8* %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(i8* bitcast (i8** @_ZTId to i8*))
68 %matches1 = icmp eq i32 %3, %6
69 br i1 %matches1, label %catch, label %rethrow
71 catch: ; preds = %catch.fallthrough
72 %7 = call i8* @__cxa_begin_catch(i8* %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) ]
80 try.cont: ; preds = %catch, %catch2, %entry
84 ; Nested try-catches within a catch
103 ; CHECK: br_if 0, {{.*}} # 0: down to label[[L0:[0-9+]]]
104 ; CHECK: call $drop=, __cxa_begin_catch, $0
108 ; CHECK: br 3 # 3: down to label[[L1:[0-9+]]]
112 ; CHECK: br_if 0, {{.*}} # 0: down to label[[L2:[0-9+]]]
113 ; CHECK: call $drop=, __cxa_begin_catch
116 ; CHECK: br 2 # 2: down to label[[L3:[0-9+]]]
118 ; CHECK: call __cxa_end_catch
119 ; CHECK: rethrow 0 # down to catch[[L4:[0-9+]]]
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]]
127 ; CHECK: catch_all # catch[[L4]]:
128 ; CHECK: call __cxa_end_catch
129 ; CHECK: rethrow 0 # to caller
131 ; CHECK: end_block # label[[L0]]:
132 ; CHECK: rethrow 1 # to caller
133 ; CHECK: end_block # label[[L1]]:
134 ; CHECK: call __cxa_end_catch
136 define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
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 [i8* bitcast (i8** @_ZTIi to i8*)]
146 %2 = call i8* @llvm.wasm.get.exception(token %1)
147 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
148 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
149 %matches = icmp eq i32 %3, %4
150 br i1 %matches, label %catch, label %rethrow
152 catch: ; preds = %catch.start
153 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
154 %6 = bitcast i8* %5 to i32*
155 %7 = load i32, i32* %6, align 4
156 invoke void @foo() [ "funclet"(token %1) ]
157 to label %try.cont unwind label %catch.dispatch2
159 catch.dispatch2: ; preds = %catch
160 %8 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup9
162 catch.start3: ; preds = %catch.dispatch2
163 %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)]
164 %10 = call i8* @llvm.wasm.get.exception(token %9)
165 %11 = call i32 @llvm.wasm.get.ehselector(token %9)
166 %12 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
167 %matches4 = icmp eq i32 %11, %12
168 br i1 %matches4, label %catch6, label %rethrow5
170 catch6: ; preds = %catch.start3
171 %13 = call i8* @__cxa_begin_catch(i8* %10) [ "funclet"(token %9) ]
172 %14 = bitcast i8* %13 to i32*
173 %15 = load i32, i32* %14, align 4
174 invoke void @foo() [ "funclet"(token %9) ]
175 to label %invoke.cont8 unwind label %ehcleanup
177 invoke.cont8: ; preds = %catch6
178 call void @__cxa_end_catch() [ "funclet"(token %9) ]
179 catchret from %9 to label %try.cont
181 rethrow5: ; preds = %catch.start3
182 invoke void @llvm.wasm.rethrow() [ "funclet"(token %9) ]
183 to label %unreachable unwind label %ehcleanup9
185 try.cont: ; preds = %invoke.cont8, %catch
186 call void @__cxa_end_catch() [ "funclet"(token %1) ]
187 catchret from %1 to label %try.cont11
189 rethrow: ; preds = %catch.start
190 call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
193 try.cont11: ; preds = %try.cont, %entry
196 ehcleanup: ; preds = %catch6
197 %16 = cleanuppad within %9 []
198 call void @__cxa_end_catch() [ "funclet"(token %16) ]
199 cleanupret from %16 unwind label %ehcleanup9
201 ehcleanup9: ; preds = %ehcleanup, %rethrow5, %catch.dispatch2
202 %17 = cleanuppad within %1 []
203 call void @__cxa_end_catch() [ "funclet"(token %17) ]
204 cleanupret from %17 unwind to caller
206 unreachable: ; preds = %rethrow5
210 ; Nested loop within a catch clause
215 ; for (int i = 0; i < 50; i++)
224 ; CHECK: call $drop=, __cxa_begin_catch
225 ; CHECK: loop # label[[L0:[0-9]+]]:
228 ; CHECK: br_if 0, {{.*}} # 0: down to label[[L1:[0-9]+]]
231 ; CHECK: br 2 # 2: down to label[[L2:[0-9]+]]
234 ; CHECK: call __cxa_end_catch
236 ; CHECK: call _ZSt9terminatev
239 ; CHECK: rethrow 0 # to caller
241 ; CHECK: end_block # label[[L1]]:
242 ; CHECK: call __cxa_end_catch
243 ; CHECK: br 2 # 2: down to label[[L3:[0-9]+]]
244 ; CHECK: end_block # label[[L2]]:
245 ; CHECK: br 0 # 0: up to label[[L0]]
247 ; CHECK: end_try # label[[L3]]:
248 define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
251 to label %try.cont unwind label %catch.dispatch
253 catch.dispatch: ; preds = %entry
254 %0 = catchswitch within none [label %catch.start] unwind to caller
256 catch.start: ; preds = %catch.dispatch
257 %1 = catchpad within %0 [i8* null]
258 %2 = call i8* @llvm.wasm.get.exception(token %1)
259 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
260 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
263 for.cond: ; preds = %for.inc, %catch.start
264 %i.0 = phi i32 [ 0, %catch.start ], [ %inc, %for.inc ]
265 %cmp = icmp slt i32 %i.0, 50
266 br i1 %cmp, label %for.body, label %for.end
268 for.body: ; preds = %for.cond
269 invoke void @foo() [ "funclet"(token %1) ]
270 to label %for.inc unwind label %ehcleanup
272 for.inc: ; preds = %for.body
273 %inc = add nsw i32 %i.0, 1
276 for.end: ; preds = %for.cond
277 call void @__cxa_end_catch() [ "funclet"(token %1) ]
278 catchret from %1 to label %try.cont
280 try.cont: ; preds = %for.end, %entry
283 ehcleanup: ; preds = %for.body
284 %5 = cleanuppad within %1 []
285 invoke void @__cxa_end_catch() [ "funclet"(token %5) ]
286 to label %invoke.cont2 unwind label %terminate
288 invoke.cont2: ; preds = %ehcleanup
289 cleanupret from %5 unwind to caller
291 terminate: ; preds = %ehcleanup
292 %6 = cleanuppad within %5 []
293 call void @_ZSt9terminatev() [ "funclet"(token %6) ]
297 ; Tests if block and try markers are correctly placed. Even if two predecessors
298 ; of the EH pad are bb2 and bb3 and their nearest common dominator is bb1, the
299 ; TRY marker should be placed at bb0 because there's a branch from bb0 to bb2,
300 ; and scopes cannot be interleaved.
312 ; NOOPT: catch {{.*}}
314 define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
316 br i1 undef, label %bb1, label %bb2
319 br i1 undef, label %bb3, label %bb4
326 to label %try.cont unwind label %catch.dispatch
330 to label %try.cont unwind label %catch.dispatch
332 catch.dispatch: ; preds = %bb4, %bb3
333 %0 = catchswitch within none [label %catch.start] unwind to caller
335 catch.start: ; preds = %catch.dispatch
336 %1 = catchpad within %0 [i8* null]
337 %2 = call i8* @llvm.wasm.get.exception(token %1)
338 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
339 catchret from %1 to label %try.cont
341 try.cont: ; preds = %catch.start, %bb4, %bb3, %bb2
345 ; Tests if try/end_try markers are placed correctly wrt loop/end_loop markers,
346 ; when try and loop markers are in the same BB and end_try and end_loop are in
354 define void @test4(i32* %p) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
356 store volatile i32 0, i32* %p
359 loop: ; preds = %try.cont, %entry
360 store volatile i32 1, i32* %p
362 to label %try.cont unwind label %catch.dispatch
364 catch.dispatch: ; preds = %loop
365 %0 = catchswitch within none [label %catch.start] unwind to caller
367 catch.start: ; preds = %catch.dispatch
368 %1 = catchpad within %0 [i8* null]
369 %2 = call i8* @llvm.wasm.get.exception(token %1)
370 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
371 catchret from %1 to label %try.cont
373 try.cont: ; preds = %catch.start, %loop
377 ; Some of test cases below are hand-tweaked by deleting some library calls to
378 ; simplify tests and changing the order of basic blocks to cause unwind
379 ; destination mismatches. And we use -wasm-disable-ehpad-sort to create maximum
380 ; number of mismatches in several tests below.
382 ; - Call unwind mismatch
383 ; 'call bar''s original unwind destination was 'C0', but after control flow
384 ; linearization, its unwind destination incorrectly becomes 'C1'. We fix this by
385 ; wrapping the call with a nested try-delegate that targets 'C0'.
386 ; - Catch unwind mismatch
387 ; If 'call foo' throws a foreign exception, it will not be caught by C1, and
388 ; should be rethrown to the caller. But after control flow linearization, it
389 ; will instead unwind to C0, an incorrect next EH pad. We wrap the whole
390 ; try-catch with try-delegate that rethrows an exception to the caller to fix
393 ; NOSORT-LABEL: test5
395 ; --- try-delegate starts (catch unwind mismatch)
399 ; --- try-delegate starts (call unwind mismatch)
402 ; NOSORT: delegate 2 # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
403 ; --- try-delegate ends (call unwind mismatch)
404 ; NOSORT: catch {{.*}} # catch[[C1:[0-9]+]]:
406 ; NOSORT: delegate 1 # label/catch{{[0-9]+}}: to caller
407 ; --- try-delegate ends (catch unwind mismatch)
408 ; NOSORT: catch {{.*}} # catch[[C0]]:
412 define void @test5() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
415 to label %bb1 unwind label %catch.dispatch0
419 to label %try.cont unwind label %catch.dispatch1
421 catch.dispatch0: ; preds = %bb0
422 %0 = catchswitch within none [label %catch.start0] unwind to caller
424 catch.start0: ; preds = %catch.dispatch0
425 %1 = catchpad within %0 [i8* null]
426 %2 = call i8* @llvm.wasm.get.exception(token %1)
427 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
428 catchret from %1 to label %try.cont
430 catch.dispatch1: ; preds = %bb1
431 %4 = catchswitch within none [label %catch.start1] unwind to caller
433 catch.start1: ; preds = %catch.dispatch1
434 %5 = catchpad within %4 [i8* null]
435 %6 = call i8* @llvm.wasm.get.exception(token %5)
436 %7 = call i32 @llvm.wasm.get.ehselector(token %5)
437 catchret from %5 to label %try.cont
439 try.cont: ; preds = %catch.start1, %catch.start0, %bb1
443 ; 'call bar' and 'call baz''s original unwind destination was the caller, but
444 ; after control flow linearization, their unwind destination incorrectly becomes
445 ; 'C0'. We fix this by wrapping the calls with a nested try-delegate that
446 ; rethrows exceptions to the caller.
448 ; And the return value of 'baz' should NOT be stackified because the BB is split
449 ; during fixing unwind mismatches.
451 ; NOSORT-LABEL: test6
454 ; --- try-delegate starts (call unwind mismatch)
457 ; NOSORT: call $[[RET:[0-9]+]]=, baz
458 ; NOSORT-NOT: call $push{{.*}}=, baz
459 ; NOSORT: delegate 1 # label/catch{{[0-9]+}}: to caller
460 ; --- try-delegate ends (call unwind mismatch)
461 ; NOSORT: call nothrow, $[[RET]]
463 ; NOSORT: catch {{.*}} # catch[[C0:[0-9]+]]:
467 define void @test6() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
470 to label %bb1 unwind label %catch.dispatch0
474 %call = call i32 @baz()
475 call void @nothrow(i32 %call) #0
478 catch.dispatch0: ; preds = %bb0
479 %0 = catchswitch within none [label %catch.start0] unwind to caller
481 catch.start0: ; preds = %catch.dispatch0
482 %1 = catchpad within %0 [i8* null]
483 %2 = call i8* @llvm.wasm.get.exception(token %1)
484 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
485 catchret from %1 to label %try.cont
487 try.cont: ; preds = %catch.start0
491 ; The same as test5, but we have one more call 'call @foo' in bb1 which unwinds
492 ; to the caller. IN this case bb1 has two call unwind mismatches: 'call @foo'
493 ; unwinds to the caller and 'call @bar' unwinds to catch C0.
495 ; NOSORT-LABEL: test7
497 ; --- try-delegate starts (catch unwind mismatch)
501 ; --- try-delegate starts (call unwind mismatch)
504 ; NOSORT: delegate 3 # label/catch{{[0-9]+}}: to caller
505 ; --- try-delegate ends (call unwind mismatch)
506 ; --- try-delegate starts (call unwind mismatch)
509 ; NOSORT: delegate 2 # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
510 ; --- try-delegate ends (call unwind mismatch)
511 ; NOSORT: catch {{.*}} # catch[[C1:[0-9]+]]:
513 ; NOSORT: delegate 1 # label/catch{{[0-9]+}}: to caller
514 ; --- try-delegate ends (catch unwind mismatch)
515 ; NOSORT: catch {{.*}} # catch[[C0]]:
519 define void @test7() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
522 to label %bb1 unwind label %catch.dispatch0
527 to label %try.cont unwind label %catch.dispatch1
529 catch.dispatch0: ; preds = %bb0
530 %0 = catchswitch within none [label %catch.start0] unwind to caller
532 catch.start0: ; preds = %catch.dispatch0
533 %1 = catchpad within %0 [i8* null]
534 %2 = call i8* @llvm.wasm.get.exception(token %1)
535 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
536 catchret from %1 to label %try.cont
538 catch.dispatch1: ; preds = %bb1
539 %4 = catchswitch within none [label %catch.start1] unwind to caller
541 catch.start1: ; preds = %catch.dispatch1
542 %5 = catchpad within %4 [i8* null]
543 %6 = call i8* @llvm.wasm.get.exception(token %5)
544 %7 = call i32 @llvm.wasm.get.ehselector(token %5)
545 catchret from %5 to label %try.cont
547 try.cont: ; preds = %catch.start1, %catch.start0, %bb1
551 ; Similar situation as @test6. Here 'call @qux''s original unwind destination
552 ; was the caller, but after control flow linearization, their unwind destination
553 ; incorrectly becomes 'C0' within the function. We fix this by wrapping the call
554 ; with a nested try-delegate that rethrows the exception to the caller.
556 ; Because 'call @qux' pops an argument pushed by 'i32.const 5' from stack, the
557 ; nested 'try' should be placed before `i32.const 5', not between 'i32.const 5'
560 ; NOSORT-LABEL: test8
563 ; --- try-delegate starts (call unwind mismatch)
565 ; NOSORT: i32.const $push{{[0-9]+}}=, 5
566 ; NOSORT: call ${{[0-9]+}}=, qux
567 ; NOSORT: delegate 1 # label/catch{{[0-9]+}}: to caller
568 ; --- try-delegate ends (call unwind mismatch)
570 ; NOSORT: catch {{.*}} # catch[[C0:[0-9]+]]:
574 define i32 @test8() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
577 to label %bb1 unwind label %catch.dispatch0
580 %0 = call i32 @qux(i32 5)
583 catch.dispatch0: ; preds = %bb0
584 %1 = catchswitch within none [label %catch.start0] unwind to caller
586 catch.start0: ; preds = %catch.dispatch0
587 %2 = catchpad within %1 [i8* null]
588 %3 = call i8* @llvm.wasm.get.exception(token %2)
589 %j = call i32 @llvm.wasm.get.ehselector(token %2)
590 catchret from %2 to label %try.cont
592 try.cont: ; preds = %catch.start0
596 ; Tests the case when TEE stackifies a register in RegStackify but it gets
597 ; unstackified in fixCallUnwindMismatches in CFGStackify.
599 ; NOSORT-LOCALS-LABEL: test9
600 define void @test9(i32 %x) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
603 to label %bb1 unwind label %catch.dispatch0
607 ; This %addr is used in multiple places, so tee is introduced in RegStackify,
608 ; which stackifies the use of %addr in store instruction. A tee has two dest
609 ; registers, the first of which is stackified and the second is not.
610 ; But when we introduce a nested try-delegate in fixCallUnwindMismatches in
611 ; CFGStackify, it is possible that we end up unstackifying the first dest
612 ; register. In that case, we convert that tee into a copy.
613 %addr = inttoptr i32 %t to i32*
614 %load = load i32, i32* %addr
615 %call = call i32 @baz()
616 %add = add i32 %load, %call
617 store i32 %add, i32* %addr
619 ; NOSORT-LOCALS: i32.add
620 ; NOSORT-LOCALS-NOT: local.tee
621 ; NOSORT-LOCALS-NEXT: local.set
623 catch.dispatch0: ; preds = %bb0
624 %0 = catchswitch within none [label %catch.start0] unwind to caller
626 catch.start0: ; preds = %catch.dispatch0
627 %1 = catchpad within %0 [i8* null]
628 %2 = call i8* @llvm.wasm.get.exception(token %1)
629 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
630 catchret from %1 to label %try.cont
632 try.cont: ; preds = %catch.start0
636 ; We have two call unwind unwind mismatches:
637 ; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the
638 ; CFG, when it is supposed to unwind to another EH pad.
639 ; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the
640 ; CFG, when it is supposed to unwind to the caller.
641 ; We also have a catch unwind mismatch: If an exception is not caught by the
642 ; first catch because it is a non-C++ exception, it shouldn't unwind to the next
643 ; catch, but it should unwind to the caller.
645 ; NOSORT-LABEL: test10
647 ; --- try-delegate starts (catch unwind mismatch)
651 ; --- try-delegate starts (call unwind mismatch)
654 ; NOSORT: delegate 2 # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]
655 ; --- try-delegate ends (call unwind mismatch)
657 ; NOSORT: call {{.*}} __cxa_begin_catch
658 ; --- try-delegate starts (call unwind mismatch)
660 ; NOSORT: call __cxa_end_catch
661 ; NOSORT: delegate 3 # label/catch{{[0-9]+}}: to caller
662 ; --- try-delegate ends (call unwind mismatch)
664 ; NOSORT: delegate 1 # label/catch{{[0-9]+}}: to caller
665 ; --- try-delegate ends (catch unwind mismatch)
666 ; NOSORT: catch {{.*}} # catch[[C0]]:
667 ; NOSORT: call {{.*}} __cxa_begin_catch
668 ; NOSORT: call __cxa_end_catch
672 define void @test10() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
675 to label %bb1 unwind label %catch.dispatch0
679 to label %try.cont unwind label %catch.dispatch1
681 catch.dispatch0: ; preds = %bb0
682 %0 = catchswitch within none [label %catch.start0] unwind to caller
684 catch.start0: ; preds = %catch.dispatch0
685 %1 = catchpad within %0 [i8* null]
686 %2 = call i8* @llvm.wasm.get.exception(token %1)
687 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
688 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
689 call void @__cxa_end_catch() [ "funclet"(token %1) ]
690 catchret from %1 to label %try.cont
692 catch.dispatch1: ; preds = %bb1
693 %5 = catchswitch within none [label %catch.start1] unwind to caller
695 catch.start1: ; preds = %catch.dispatch1
696 %6 = catchpad within %5 [i8* null]
697 %7 = call i8* @llvm.wasm.get.exception(token %6)
698 %8 = call i32 @llvm.wasm.get.ehselector(token %6)
699 %9 = call i8* @__cxa_begin_catch(i8* %7) [ "funclet"(token %6) ]
700 call void @__cxa_end_catch() [ "funclet"(token %6) ]
701 catchret from %6 to label %try.cont
703 try.cont: ; preds = %catch.start1, %catch.start0, %bb1
707 ; In CFGSort, EH pads should be sorted as soon as it is available and
708 ; 'Preferred' queue and should NOT be entered into 'Ready' queue unless we are
709 ; in the middle of sorting another region that does not contain the EH pad. In
710 ; this example, 'catch.start' should be sorted right after 'if.then' is sorted
711 ; (before 'cont' is sorted) and there should not be any unwind destination
712 ; mismatches in CFGStackify.
714 ; NOOPT-LABEL: test11
723 define void @test11(i32 %arg) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
725 %tobool = icmp ne i32 %arg, 0
726 br i1 %tobool, label %if.then, label %if.end
728 catch.dispatch: ; preds = %if.then
729 %0 = catchswitch within none [label %catch.start] unwind to caller
731 catch.start: ; preds = %catch.dispatch
732 %1 = catchpad within %0 [i8* null]
733 %2 = call i8* @llvm.wasm.get.exception(token %1)
734 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
735 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
736 call void @__cxa_end_catch() [ "funclet"(token %1) ]
737 catchret from %1 to label %if.end
739 if.then: ; preds = %entry
741 to label %cont unwind label %catch.dispatch
743 cont: ; preds = %if.then
747 if.end: ; preds = %cont, %catch.start, %entry
751 ; Intrinsics like memcpy, memmove, and memset don't throw and are lowered into
752 ; calls to external symbols (not global addresses) in instruction selection,
753 ; which will be eventually lowered to library function calls.
754 ; Because this test runs with -wasm-disable-ehpad-sort, these library calls in
755 ; invoke.cont BB fall within try~end_try, but they shouldn't cause crashes or
756 ; unwinding destination mismatches in CFGStackify.
758 ; NOSORT-LABEL: test12
761 ; NOSORT: call {{.*}} memcpy
762 ; NOSORT: call {{.*}} memmove
763 ; NOSORT: call {{.*}} memset
768 define void @test12(i8* %a, i8* %b) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
770 %o = alloca %class.Object, align 1
772 to label %invoke.cont unwind label %ehcleanup
774 invoke.cont: ; preds = %entry
775 call void @llvm.memcpy.p0i8.p0i8.i32(i8* %a, i8* %b, i32 100, i1 false)
776 call void @llvm.memmove.p0i8.p0i8.i32(i8* %a, i8* %b, i32 100, i1 false)
777 call void @llvm.memset.p0i8.i32(i8* %a, i8 0, i32 100, i1 false)
778 %call = call %class.Object* @_ZN6ObjectD2Ev(%class.Object* %o)
781 ehcleanup: ; preds = %entry
782 %0 = cleanuppad within none []
783 %call2 = call %class.Object* @_ZN6ObjectD2Ev(%class.Object* %o) [ "funclet"(token %0) ]
784 cleanupret from %0 unwind to caller
787 ; Tests if 'try' marker is placed correctly. In this test, 'try' should be
788 ; placed before the call to 'nothrow_i32' and not between the call to
789 ; 'nothrow_i32' and 'fun', because the return value of 'nothrow_i32' is
790 ; stackified and pushed onto the stack to be consumed by the call to 'fun'.
792 ; CHECK-LABEL: test13
794 ; CHECK: call $push{{.*}}=, nothrow_i32
795 ; CHECK: call fun, $pop{{.*}}
796 define void @test13() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
798 %call = call i32 @nothrow_i32()
799 invoke void @fun(i32 %call)
800 to label %invoke.cont unwind label %terminate
802 invoke.cont: ; preds = %entry
805 terminate: ; preds = %entry
806 %0 = cleanuppad within none []
807 call void @_ZSt9terminatev() [ "funclet"(token %0) ]
811 ; This crashed on debug mode (= when NDEBUG is not defined) when the logic for
812 ; computing the innermost region was not correct, in which a loop region
813 ; contains an exception region. This should pass CFGSort without crashing.
814 define void @test14() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
816 %e = alloca %class.MyClass, align 4
819 for.cond: ; preds = %for.inc, %entry
820 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
821 %cmp = icmp slt i32 %i.0, 9
822 br i1 %cmp, label %for.body, label %for.end
824 for.body: ; preds = %for.cond
825 invoke void @quux(i32 %i.0)
826 to label %for.inc unwind label %catch.dispatch
828 catch.dispatch: ; preds = %for.body
829 %0 = catchswitch within none [label %catch.start] unwind to caller
831 catch.start: ; preds = %catch.dispatch
832 %1 = catchpad within %0 [i8* bitcast ({ i8*, i8* }* @_ZTI7MyClass to i8*)]
833 %2 = call i8* @llvm.wasm.get.exception(token %1)
834 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
835 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast ({ i8*, i8* }* @_ZTI7MyClass to i8*))
836 %matches = icmp eq i32 %3, %4
837 br i1 %matches, label %catch, label %rethrow
839 catch: ; preds = %catch.start
840 %5 = call i8* @__cxa_get_exception_ptr(i8* %2) [ "funclet"(token %1) ]
841 %6 = bitcast i8* %5 to %class.MyClass*
842 %call = call %class.MyClass* @_ZN7MyClassC2ERKS_(%class.MyClass* %e, %class.MyClass* dereferenceable(4) %6) [ "funclet"(token %1) ]
843 %7 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
844 %x = getelementptr inbounds %class.MyClass, %class.MyClass* %e, i32 0, i32 0
845 %8 = load i32, i32* %x, align 4
846 invoke void @quux(i32 %8) [ "funclet"(token %1) ]
847 to label %invoke.cont2 unwind label %ehcleanup
849 invoke.cont2: ; preds = %catch
850 %call3 = call %class.MyClass* @_ZN7MyClassD2Ev(%class.MyClass* %e) [ "funclet"(token %1) ]
851 call void @__cxa_end_catch() [ "funclet"(token %1) ]
852 catchret from %1 to label %for.inc
854 rethrow: ; preds = %catch.start
855 call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
858 for.inc: ; preds = %invoke.cont2, %for.body
859 %inc = add nsw i32 %i.0, 1
862 ehcleanup: ; preds = %catch
863 %9 = cleanuppad within %1 []
864 %call4 = call %class.MyClass* @_ZN7MyClassD2Ev(%class.MyClass* %e) [ "funclet"(token %9) ]
865 invoke void @__cxa_end_catch() [ "funclet"(token %9) ]
866 to label %invoke.cont6 unwind label %terminate7
868 invoke.cont6: ; preds = %ehcleanup
869 cleanupret from %9 unwind to caller
871 for.end: ; preds = %for.cond
874 terminate7: ; preds = %ehcleanup
875 %10 = cleanuppad within %9 []
876 call void @_ZSt9terminatev() [ "funclet"(token %10) ]
880 ; Tests if CFGStackify's removeUnnecessaryInstrs() removes unnecessary branches
881 ; correctly. The code is in the form below, where 'br' is unnecessary because
882 ; after running the 'try' body the control flow will fall through to bb2 anyway.
887 ; br bb2 <- Not necessary
891 ; bb2: <- Continuation BB
893 ; CHECK-LABEL: test15
894 define void @test15(i32 %n) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
897 to label %for.body unwind label %catch.dispatch
899 for.body: ; preds = %for.end, %entry
900 %i = phi i32 [ %inc, %for.end ], [ 0, %entry ]
902 to label %for.end unwind label %catch.dispatch
904 ; Before going to CFGStackify, this BB will have a conditional branch followed
905 ; by an unconditional branch. CFGStackify should remove only the unconditional
907 for.end: ; preds = %for.body
908 %inc = add nuw nsw i32 %i, 1
909 %exitcond = icmp eq i32 %inc, %n
910 br i1 %exitcond, label %try.cont, label %for.body
916 catch.dispatch: ; preds = %for.body, %entry
917 %0 = catchswitch within none [label %catch.start] unwind to caller
919 catch.start: ; preds = %catch.dispatch
920 %1 = catchpad within %0 [i8* null]
921 %2 = call i8* @llvm.wasm.get.exception(token %1)
922 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
923 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
924 call void @__cxa_end_catch() [ "funclet"(token %1) ]
925 catchret from %1 to label %try.cont
927 try.cont: ; preds = %catch.start, %for.end
943 ; This tests whether the 'br' can be removed in code in the form as follows.
944 ; Here 'br' is inside an inner try, whose 'end' is in another EH pad. In this
945 ; case, after running an inner try body, the control flow should fall through to
946 ; bb3, so the 'br' in the code is unnecessary.
952 ; br bb3 <- Not necessary
959 ; bb3: <- Continuation BB
962 ; CHECK-LABEL: test16
963 define void @test16() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
967 to label %invoke.cont unwind label %catch.dispatch3
971 invoke.cont: ; preds = %entry
973 to label %try.cont8 unwind label %catch.dispatch
975 catch.dispatch: ; preds = %invoke.cont
976 %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch3
979 catch.start: ; preds = %catch.dispatch
980 %1 = catchpad within %0 [i8* null]
981 %2 = call i8* @llvm.wasm.get.exception(token %1)
982 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
983 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
984 invoke void @__cxa_end_catch() [ "funclet"(token %1) ]
985 to label %invoke.cont2 unwind label %catch.dispatch3
987 catch.dispatch3: ; preds = %catch.start, %catch.dispatch, %entry
988 %5 = catchswitch within none [label %catch.start4] unwind to caller
990 catch.start4: ; preds = %catch.dispatch3
991 %6 = catchpad within %5 [i8* null]
992 %7 = call i8* @llvm.wasm.get.exception(token %6)
993 %8 = call i32 @llvm.wasm.get.ehselector(token %6)
994 %9 = call i8* @__cxa_begin_catch(i8* %7) [ "funclet"(token %6) ]
995 call void @__cxa_end_catch() [ "funclet"(token %6) ]
996 catchret from %6 to label %try.cont8
998 try.cont8: ; preds = %invoke.cont2, %catch.start4, %invoke.cont
1001 invoke.cont2: ; preds = %catch.start
1002 catchret from %1 to label %try.cont8
1005 ; Here an exception is semantically contained in a loop. 'ehcleanup' BB belongs
1006 ; to the exception, but does not belong to the loop (because it does not have a
1007 ; path back to the loop header), and is placed after the loop latch block
1008 ; 'invoke.cont' intentionally. This tests if 'end_loop' marker is placed
1009 ; correctly not right after 'invoke.cont' part but after 'ehcleanup' part,
1010 ; NOSORT-LABEL: test17
1015 define void @test17(i32 %n) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1017 br label %while.cond
1019 while.cond: ; preds = %invoke.cont, %entry
1020 %n.addr.0 = phi i32 [ %n, %entry ], [ %dec, %invoke.cont ]
1021 %tobool = icmp ne i32 %n.addr.0, 0
1022 br i1 %tobool, label %while.body, label %while.end
1024 while.body: ; preds = %while.cond
1025 %dec = add nsw i32 %n.addr.0, -1
1027 to label %while.end unwind label %catch.dispatch
1029 catch.dispatch: ; preds = %while.body
1030 %0 = catchswitch within none [label %catch.start] unwind to caller
1032 catch.start: ; preds = %catch.dispatch
1033 %1 = catchpad within %0 [i8* null]
1034 %2 = call i8* @llvm.wasm.get.exception(token %1)
1035 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1036 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
1037 invoke void @__cxa_end_catch() [ "funclet"(token %1) ]
1038 to label %invoke.cont unwind label %ehcleanup
1040 invoke.cont: ; preds = %catch.start
1041 catchret from %1 to label %while.cond
1043 ehcleanup: ; preds = %catch.start
1044 %5 = cleanuppad within %1 []
1045 call void @_ZSt9terminatev() [ "funclet"(token %5) ]
1048 while.end: ; preds = %while.body, %while.cond
1052 ; When the function return type is non-void and 'end' instructions are at the
1053 ; very end of a function, CFGStackify's fixEndsAtEndOfFunction function fixes
1054 ; the corresponding block/loop/try's type to match the function's return type.
1055 ; But when a `try`'s type is fixed, we should also check `end` instructions
1056 ; before its corresponding `catch_all`, because both `try` and `catch_all` body
1057 ; should satisfy the return type requirements.
1059 ; NOSORT-LABEL: test18
1065 ; NOSORT-NEXT: end_function
1066 define i32 @test18(i32 %n) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1068 %t = alloca %class.Object, align 1
1071 for.cond: ; preds = %for.inc, %entry
1072 %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
1073 %cmp = icmp slt i32 %i.0, %n
1076 for.body: ; preds = %for.cond
1077 %div = sdiv i32 %n, 2
1078 %cmp1 = icmp eq i32 %i.0, %div
1079 br i1 %cmp1, label %if.then, label %for.inc
1081 if.then: ; preds = %for.body
1082 %call = invoke i32 @baz()
1083 to label %invoke.cont unwind label %ehcleanup
1085 invoke.cont: ; preds = %if.then
1086 %call2 = call %class.Object* @_ZN6ObjectD2Ev(%class.Object* %t)
1089 for.inc: ; preds = %for.body
1090 %inc = add nsw i32 %i.0, 1
1093 ehcleanup: ; preds = %if.then
1094 %0 = cleanuppad within none []
1095 %call3 = call %class.Object* @_ZN6ObjectD2Ev(%class.Object* %t) [ "funclet"(token %0) ]
1096 cleanupret from %0 unwind to caller
1099 ; This crashed when updating EHPadStack within fixCallUniwindMismatch had a bug.
1100 ; This should not crash and try-delegate has to be created around 'call @baz',
1101 ; because the initial TRY placement for 'call @quux' was done before 'call @baz'
1102 ; because 'call @baz''s return value is stackified.
1104 ; CHECK-LABEL: test19
1107 ; CHECK: call $[[RET:[0-9]+]]=, baz
1109 ; CHECK: call quux, $[[RET]]
1112 define void @test19() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1114 %call = call i32 @baz()
1115 invoke void @quux(i32 %call)
1116 to label %invoke.cont unwind label %ehcleanup
1118 ehcleanup: ; preds = %entry
1119 %0 = cleanuppad within none []
1120 cleanupret from %0 unwind to caller
1122 invoke.cont: ; preds = %entry
1126 ; This tests if invalidated branch destinations after fixing catch unwind
1127 ; mismatches are correctly remapped. For example, we have this code and suppose
1128 ; we need to wrap this try-catch-end in this code with a try-delegate to fix a
1129 ; catch unwind mismatch:
1150 ; After adding a try-delegate, the 'br's destination BB, where (a) points,
1151 ; becomes invalid because it incorrectly branches into an inner scope. The
1152 ; destination should change to the BB where (b) points.
1154 ; NOSORT-LABEL: test20
1157 define void @test20(i1 %arg) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1159 br i1 %arg, label %bb0, label %dest
1161 bb0: ; preds = %entry
1163 to label %bb1 unwind label %catch.dispatch0
1167 to label %try.cont unwind label %catch.dispatch1
1169 catch.dispatch0: ; preds = %bb0
1170 %0 = catchswitch within none [label %catch.start0] unwind to caller
1172 catch.start0: ; preds = %catch.dispatch0
1173 %1 = catchpad within %0 [i8* null]
1174 %2 = call i8* @llvm.wasm.get.exception(token %1)
1175 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1176 catchret from %1 to label %try.cont
1178 dest: ; preds = %entry
1181 catch.dispatch1: ; preds = %bb1
1182 %4 = catchswitch within none [label %catch.start1] unwind to caller
1184 catch.start1: ; preds = %catch.dispatch1
1185 %5 = catchpad within %4 [i8* null]
1186 %6 = call i8* @llvm.wasm.get.exception(token %5)
1187 %7 = call i32 @llvm.wasm.get.ehselector(token %5)
1188 catchret from %5 to label %try.cont
1190 try.cont: ; preds = %catch.start1, %catch.start0, %bb1
1194 ; The similar case with test20, but multiple consecutive delegates are
1218 ; <- (b) The br destination should be remapped to here
1220 ; The test was reduced by bugpoint and should not crash in CFGStackify.
1221 define void @test21() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1223 br i1 undef, label %if.then, label %if.end12
1225 if.then: ; preds = %entry
1226 invoke void @__cxa_throw(i8* null, i8* null, i8* null) #1
1227 to label %unreachable unwind label %catch.dispatch
1229 catch.dispatch: ; preds = %if.then
1230 %0 = catchswitch within none [label %catch.start] unwind to caller
1232 catch.start: ; preds = %catch.dispatch
1233 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
1234 %2 = call i8* @llvm.wasm.get.exception(token %1)
1235 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1236 catchret from %1 to label %catchret.dest
1238 catchret.dest: ; preds = %catch.start
1240 to label %invoke.cont unwind label %catch.dispatch4
1242 invoke.cont: ; preds = %catchret.dest
1243 invoke void @__cxa_throw(i8* null, i8* null, i8* null) #1
1244 to label %unreachable unwind label %catch.dispatch4
1246 catch.dispatch4: ; preds = %invoke.cont, %catchret.dest
1247 %4 = catchswitch within none [label %catch.start5] unwind to caller
1249 catch.start5: ; preds = %catch.dispatch4
1250 %5 = catchpad within %4 [i8* bitcast (i8** @_ZTIi to i8*)]
1251 %6 = call i8* @llvm.wasm.get.exception(token %5)
1252 %7 = call i32 @llvm.wasm.get.ehselector(token %5)
1255 if.end12: ; preds = %entry
1257 to label %invoke.cont14 unwind label %catch.dispatch16
1259 catch.dispatch16: ; preds = %if.end12
1260 %8 = catchswitch within none [label %catch.start17] unwind label %ehcleanup
1262 catch.start17: ; preds = %catch.dispatch16
1263 %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)]
1264 %10 = call i8* @llvm.wasm.get.exception(token %9)
1265 %11 = call i32 @llvm.wasm.get.ehselector(token %9)
1266 br i1 undef, label %catch20, label %rethrow19
1268 catch20: ; preds = %catch.start17
1269 catchret from %9 to label %catchret.dest22
1271 catchret.dest22: ; preds = %catch20
1272 br label %try.cont23
1274 rethrow19: ; preds = %catch.start17
1275 invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %9) ]
1276 to label %unreachable unwind label %ehcleanup
1278 try.cont23: ; preds = %invoke.cont14, %catchret.dest22
1280 to label %invoke.cont24 unwind label %ehcleanup
1282 invoke.cont24: ; preds = %try.cont23
1285 invoke.cont14: ; preds = %if.end12
1286 br label %try.cont23
1288 ehcleanup: ; preds = %try.cont23, %rethrow19, %catch.dispatch16
1289 %12 = cleanuppad within none []
1290 cleanupret from %12 unwind to caller
1292 unreachable: ; preds = %rethrow19, %invoke.cont, %if.then
1296 ; Regression test for WasmEHFuncInfo's reverse mapping bug. 'UnwindDestToSrc'
1297 ; should return a vector and not a single BB, which was incorrect.
1298 ; This was reduced by bugpoint and should not crash in CFGStackify.
1299 define void @test22() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1302 to label %invoke.cont unwind label %catch.dispatch
1304 catch.dispatch: ; preds = %entry
1305 %0 = catchswitch within none [label %catch.start] unwind label %ehcleanup22
1307 catch.start: ; preds = %catch.dispatch
1308 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
1309 %2 = call i8* @llvm.wasm.get.exception(token %1)
1310 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1311 invoke void @__cxa_throw(i8* null, i8* null, i8* null) #1 [ "funclet"(token %1) ]
1312 to label %unreachable unwind label %catch.dispatch2
1314 catch.dispatch2: ; preds = %catch.start
1315 %4 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup
1317 catch.start3: ; preds = %catch.dispatch2
1318 %5 = catchpad within %4 [i8* bitcast (i8** @_ZTIi to i8*)]
1319 %6 = call i8* @llvm.wasm.get.exception(token %5)
1320 %7 = call i32 @llvm.wasm.get.ehselector(token %5)
1321 catchret from %5 to label %try.cont
1323 try.cont: ; preds = %catch.start3
1324 invoke void @foo() [ "funclet"(token %1) ]
1325 to label %invoke.cont8 unwind label %ehcleanup
1327 invoke.cont8: ; preds = %try.cont
1328 invoke void @__cxa_throw(i8* null, i8* null, i8* null) #1 [ "funclet"(token %1) ]
1329 to label %unreachable unwind label %catch.dispatch11
1331 catch.dispatch11: ; preds = %invoke.cont8
1332 %8 = catchswitch within %1 [label %catch.start12] unwind label %ehcleanup
1334 catch.start12: ; preds = %catch.dispatch11
1335 %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)]
1336 %10 = call i8* @llvm.wasm.get.exception(token %9)
1337 %11 = call i32 @llvm.wasm.get.ehselector(token %9)
1340 invoke.cont: ; preds = %entry
1343 ehcleanup: ; preds = %catch.dispatch11, %try.cont, %catch.dispatch2
1344 %12 = cleanuppad within %1 []
1345 cleanupret from %12 unwind label %ehcleanup22
1347 ehcleanup22: ; preds = %ehcleanup, %catch.dispatch
1348 %13 = cleanuppad within none []
1349 cleanupret from %13 unwind to caller
1351 unreachable: ; preds = %invoke.cont8, %catch.start
1365 ; Regression test for a WebAssemblyException grouping bug. After catchswitches
1366 ; are removed, EH pad catch.start2 is dominated by catch.start, but because
1367 ; catch.start2 is the unwind destination of catch.start, it should not be
1368 ; included in catch.start's exception. Also, after we take catch.start2's
1369 ; exception out of catch.start's exception, we have to take out try.cont8 out of
1370 ; catch.start's exception, because it has a predecessor in catch.start2.
1371 define void @test23() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1373 %exception = call i8* @__cxa_allocate_exception(i32 4) #0
1374 %0 = bitcast i8* %exception to i32*
1375 store i32 0, i32* %0, align 16
1376 invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) #1
1377 to label %unreachable unwind label %catch.dispatch
1379 catch.dispatch: ; preds = %entry
1380 %1 = catchswitch within none [label %catch.start] unwind label %catch.dispatch1
1382 catch.start: ; preds = %catch.dispatch
1383 %2 = catchpad within %1 [i8* bitcast (i8** @_ZTIi to i8*)]
1384 %3 = call i8* @llvm.wasm.get.exception(token %2)
1385 %4 = call i32 @llvm.wasm.get.ehselector(token %2)
1386 %5 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #0
1387 %matches = icmp eq i32 %4, %5
1388 br i1 %matches, label %catch, label %rethrow
1390 catch: ; preds = %catch.start
1391 %6 = call i8* @__cxa_begin_catch(i8* %3) #0 [ "funclet"(token %2) ]
1392 %7 = bitcast i8* %6 to i32*
1393 %8 = load i32, i32* %7, align 4
1394 call void @__cxa_end_catch() #0 [ "funclet"(token %2) ]
1395 catchret from %2 to label %catchret.dest
1397 catchret.dest: ; preds = %catch
1400 rethrow: ; preds = %catch.start
1401 invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %2) ]
1402 to label %unreachable unwind label %catch.dispatch1
1404 catch.dispatch1: ; preds = %rethrow, %catch.dispatch
1405 %9 = catchswitch within none [label %catch.start2] unwind to caller
1407 catch.start2: ; preds = %catch.dispatch1
1408 %10 = catchpad within %9 [i8* bitcast (i8** @_ZTIi to i8*)]
1409 %11 = call i8* @llvm.wasm.get.exception(token %10)
1410 %12 = call i32 @llvm.wasm.get.ehselector(token %10)
1411 %13 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #0
1412 %matches3 = icmp eq i32 %12, %13
1413 br i1 %matches3, label %catch5, label %rethrow4
1415 catch5: ; preds = %catch.start2
1416 %14 = call i8* @__cxa_begin_catch(i8* %11) #0 [ "funclet"(token %10) ]
1417 %15 = bitcast i8* %14 to i32*
1418 %16 = load i32, i32* %15, align 4
1419 call void @__cxa_end_catch() #0 [ "funclet"(token %10) ]
1420 catchret from %10 to label %catchret.dest7
1422 catchret.dest7: ; preds = %catch5
1425 rethrow4: ; preds = %catch.start2
1426 call void @llvm.wasm.rethrow() #1 [ "funclet"(token %10) ]
1429 try.cont8: ; preds = %try.cont, %catchret.dest7
1432 try.cont: ; preds = %catchret.dest
1435 unreachable: ; preds = %rethrow, %entry
1439 ; Test for WebAssemblyException grouping. This test is hand-modified to generate
1441 ; catch.start dominates catch.start4 and catch.start4 dominates catch.start12,
1442 ; so the after dominator-based grouping, we end up with:
1443 ; catch.start's exception > catch4.start's exception > catch12.start's exception
1444 ; (> here represents subexception relationship)
1446 ; But the unwind destination chain is catch.start -> catch.start4 ->
1447 ; catch.start12. So all these subexception relationship should be deconstructed.
1448 ; We have to make sure to take out catch.start4's exception out of catch.start's
1449 ; exception first, before taking out catch.start12's exception out of
1450 ; catch.start4's exception; otherwise we end up with an incorrect relationship
1451 ; of catch.start's exception > catch.start12's exception.
1452 define void @test24() personality i8* bitcast (i32 (...)*
1453 @__gxx_wasm_personality_v0 to i8*) {
1456 to label %invoke.cont unwind label %catch.dispatch
1458 invoke.cont: ; preds = %entry
1460 to label %invoke.cont1 unwind label %catch.dispatch
1462 invoke.cont1: ; preds = %invoke.cont
1464 to label %try.cont18 unwind label %catch.dispatch
1466 catch.dispatch11: ; preds = %rethrow6, %catch.dispatch3
1467 %0 = catchswitch within none [label %catch.start12] unwind to caller
1469 catch.start12: ; preds = %catch.dispatch11
1470 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
1471 %2 = call i8* @llvm.wasm.get.exception(token %1)
1472 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1473 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #0
1474 %matches13 = icmp eq i32 %3, %4
1475 br i1 %matches13, label %catch15, label %rethrow14
1477 catch15: ; preds = %catch.start12
1478 %5 = call i8* @__cxa_begin_catch(i8* %2) #0 [ "funclet"(token %1) ]
1479 %6 = bitcast i8* %5 to i32*
1480 %7 = load i32, i32* %6, align 4
1481 call void @__cxa_end_catch() #0 [ "funclet"(token %1) ]
1482 catchret from %1 to label %try.cont18
1484 rethrow14: ; preds = %catch.start12
1485 call void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]
1488 catch.dispatch3: ; preds = %rethrow, %catch.dispatch
1489 %8 = catchswitch within none [label %catch.start4] unwind label %catch.dispatch11
1491 catch.start4: ; preds = %catch.dispatch3
1492 %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)]
1493 %10 = call i8* @llvm.wasm.get.exception(token %9)
1494 %11 = call i32 @llvm.wasm.get.ehselector(token %9)
1495 %12 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #0
1496 %matches5 = icmp eq i32 %11, %12
1497 br i1 %matches5, label %catch7, label %rethrow6
1499 catch7: ; preds = %catch.start4
1500 %13 = call i8* @__cxa_begin_catch(i8* %10) #0 [ "funclet"(token %9) ]
1501 %14 = bitcast i8* %13 to i32*
1502 %15 = load i32, i32* %14, align 4
1503 call void @__cxa_end_catch() #0 [ "funclet"(token %9) ]
1504 catchret from %9 to label %try.cont18
1506 rethrow6: ; preds = %catch.start4
1507 invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %9) ]
1508 to label %unreachable unwind label %catch.dispatch11
1510 catch.dispatch: ; preds = %invoke.cont1, %invoke.cont, %entry
1511 %16 = catchswitch within none [label %catch.start] unwind label %catch.dispatch3
1513 catch.start: ; preds = %catch.dispatch
1514 %17 = catchpad within %16 [i8* bitcast (i8** @_ZTIi to i8*)]
1515 %18 = call i8* @llvm.wasm.get.exception(token %17)
1516 %19 = call i32 @llvm.wasm.get.ehselector(token %17)
1517 %20 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #0
1518 %matches = icmp eq i32 %19, %20
1519 br i1 %matches, label %catch, label %rethrow
1521 catch: ; preds = %catch.start
1522 %21 = call i8* @__cxa_begin_catch(i8* %18) #0 [ "funclet"(token %17) ]
1523 %22 = bitcast i8* %21 to i32*
1524 %23 = load i32, i32* %22, align 4
1525 call void @__cxa_end_catch() #0 [ "funclet"(token %17) ]
1526 catchret from %17 to label %try.cont18
1528 rethrow: ; preds = %catch.start
1529 invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %17) ]
1530 to label %unreachable unwind label %catch.dispatch3
1532 try.cont18: ; preds = %catch, %catch7, %catch15, %invoke.cont1
1535 unreachable: ; preds = %rethrow, %rethrow6
1543 ; } catch (int) { // (a)
1545 ; } catch (int) { // (b)
1549 ; } catch (int) { // (c)
1553 ; Regression test for an ExceptionInfo grouping bug. Because the first (inner)
1554 ; try always throws, both EH pads (b) (catch.start2) and (c) (catch.start10) are
1555 ; dominated by EH pad (a) (catch.start), even though they are not semantically
1556 ; contained in (a)'s exception. Because (a)'s unwind destination is (b), (b)'s
1557 ; exception is taken out of (a)'s. But because (c) is reachable from (b), we
1558 ; should make sure to take out (c)'s exception out of (a)'s exception too.
1559 define void @test25() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
1561 %exception = call i8* @__cxa_allocate_exception(i32 4) #1
1562 %0 = bitcast i8* %exception to i32*
1563 store i32 0, i32* %0, align 16
1564 invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) #3
1565 to label %unreachable unwind label %catch.dispatch
1567 catch.dispatch: ; preds = %entry
1568 %1 = catchswitch within none [label %catch.start] unwind label %catch.dispatch1
1570 catch.start: ; preds = %catch.dispatch
1571 %2 = catchpad within %1 [i8* bitcast (i8** @_ZTIi to i8*)]
1572 %3 = call i8* @llvm.wasm.get.exception(token %2)
1573 %4 = call i32 @llvm.wasm.get.ehselector(token %2)
1574 %5 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #1
1575 %matches = icmp eq i32 %4, %5
1576 br i1 %matches, label %catch, label %rethrow
1578 catch: ; preds = %catch.start
1579 %6 = call i8* @__cxa_begin_catch(i8* %3) #1 [ "funclet"(token %2) ]
1580 %7 = bitcast i8* %6 to i32*
1581 %8 = load i32, i32* %7, align 4
1582 call void @__cxa_end_catch() #1 [ "funclet"(token %2) ]
1583 catchret from %2 to label %try.cont8
1585 rethrow: ; preds = %catch.start
1586 invoke void @llvm.wasm.rethrow() #3 [ "funclet"(token %2) ]
1587 to label %unreachable unwind label %catch.dispatch1
1589 catch.dispatch1: ; preds = %rethrow, %catch.dispatch
1590 %9 = catchswitch within none [label %catch.start2] unwind to caller
1592 catch.start2: ; preds = %catch.dispatch1
1593 %10 = catchpad within %9 [i8* bitcast (i8** @_ZTIi to i8*)]
1594 %11 = call i8* @llvm.wasm.get.exception(token %10)
1595 %12 = call i32 @llvm.wasm.get.ehselector(token %10)
1596 %13 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #1
1597 %matches3 = icmp eq i32 %12, %13
1598 br i1 %matches3, label %catch5, label %rethrow4
1600 catch5: ; preds = %catch.start2
1601 %14 = call i8* @__cxa_begin_catch(i8* %11) #1 [ "funclet"(token %10) ]
1602 %15 = bitcast i8* %14 to i32*
1603 %16 = load i32, i32* %15, align 4
1604 call void @__cxa_end_catch() #1 [ "funclet"(token %10) ]
1605 catchret from %10 to label %try.cont8
1607 rethrow4: ; preds = %catch.start2
1608 call void @llvm.wasm.rethrow() #3 [ "funclet"(token %10) ]
1611 try.cont8: ; preds = %catch, %catch5
1613 to label %try.cont16 unwind label %catch.dispatch9
1615 catch.dispatch9: ; preds = %try.cont8
1616 %17 = catchswitch within none [label %catch.start10] unwind to caller
1618 catch.start10: ; preds = %catch.dispatch9
1619 %18 = catchpad within %17 [i8* bitcast (i8** @_ZTIi to i8*)]
1620 %19 = call i8* @llvm.wasm.get.exception(token %18)
1621 %20 = call i32 @llvm.wasm.get.ehselector(token %18)
1622 %21 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #1
1623 %matches11 = icmp eq i32 %20, %21
1624 br i1 %matches11, label %catch13, label %rethrow12
1626 catch13: ; preds = %catch.start10
1627 %22 = call i8* @__cxa_begin_catch(i8* %19) #1 [ "funclet"(token %18) ]
1628 %23 = bitcast i8* %22 to i32*
1629 %24 = load i32, i32* %23, align 4
1630 call void @__cxa_end_catch() #1 [ "funclet"(token %18) ]
1631 catchret from %18 to label %try.cont16
1633 rethrow12: ; preds = %catch.start10
1634 call void @llvm.wasm.rethrow() #3 [ "funclet"(token %18) ]
1637 try.cont16: ; preds = %try.cont8, %catch13
1640 unreachable: ; preds = %rethrow, %entry
1644 ; Check if the unwind destination mismatch stats are correct
1645 ; NOSORT: 23 wasm-cfg-stackify - Number of call unwind mismatches found
1646 ; NOSORT: 4 wasm-cfg-stackify - Number of catch unwind mismatches found
1651 declare i32 @qux(i32)
1652 declare void @quux(i32)
1653 declare void @fun(i32)
1654 ; Function Attrs: nounwind
1655 declare void @nothrow(i32) #0
1656 ; Function Attrs: nounwind
1657 declare i32 @nothrow_i32() #0
1659 ; Function Attrs: nounwind
1660 declare %class.Object* @_ZN6ObjectD2Ev(%class.Object* returned) #0
1661 @_ZTI7MyClass = external constant { i8*, i8* }, align 4
1662 ; Function Attrs: nounwind
1663 declare %class.MyClass* @_ZN7MyClassD2Ev(%class.MyClass* returned) #0
1664 ; Function Attrs: nounwind
1665 declare %class.MyClass* @_ZN7MyClassC2ERKS_(%class.MyClass* returned, %class.MyClass* dereferenceable(4)) #0
1667 declare i32 @__gxx_wasm_personality_v0(...)
1668 ; Function Attrs: nounwind
1669 declare i8* @llvm.wasm.get.exception(token) #0
1670 ; Function Attrs: nounwind
1671 declare i32 @llvm.wasm.get.ehselector(token) #0
1672 declare i8* @__cxa_allocate_exception(i32) #0
1673 declare void @__cxa_throw(i8*, i8*, i8*)
1674 ; Function Attrs: noreturn
1675 declare void @llvm.wasm.rethrow() #1
1676 ; Function Attrs: nounwind
1677 declare i32 @llvm.eh.typeid.for(i8*) #0
1679 declare i8* @__cxa_begin_catch(i8*)
1680 declare void @__cxa_end_catch()
1681 declare i8* @__cxa_get_exception_ptr(i8*)
1682 declare void @_ZSt9terminatev()
1683 ; Function Attrs: nounwind
1684 declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #0
1685 ; Function Attrs: nounwind
1686 declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i1 immarg) #0
1687 ; Function Attrs: nounwind
1688 declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1 immarg) #0
1690 attributes #0 = { nounwind }
1691 attributes #1 = { noreturn }