1; 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 2; 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 3; 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 | FileCheck %s --check-prefix=NOSORT 4 5target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" 6target triple = "wasm32-unknown-unknown" 7 8@_ZTIi = external constant i8* 9@_ZTId = external constant i8* 10 11; Simple test case with two catch clauses 12; 13; void foo(); 14; void test0() { 15; try { 16; foo(); 17; } catch (int) { 18; } catch (double) { 19; } 20; } 21 22; CHECK-LABEL: test0 23; CHECK: try 24; CHECK: call foo 25; CHECK: catch 26; CHECK: block 27; CHECK: br_if 0, {{.*}} # 0: down to label2 28; CHECK: i32.call $drop=, __cxa_begin_catch 29; CHECK: call __cxa_end_catch 30; CHECK: br 1 # 1: down to label0 31; CHECK: end_block # label2: 32; CHECK: block 33; CHECK: br_if 0, {{.*}} # 0: down to label3 34; CHECK: i32.call $drop=, __cxa_begin_catch 35; CHECK: call __cxa_end_catch 36; CHECK: br 1 # 1: down to label0 37; CHECK: end_block # label3: 38; CHECK: rethrow {{.*}} # to caller 39; CHECK: end_try # label0: 40define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 41entry: 42 invoke void @foo() 43 to label %try.cont unwind label %catch.dispatch 44 45catch.dispatch: ; preds = %entry 46 %0 = catchswitch within none [label %catch.start] unwind to caller 47 48catch.start: ; preds = %catch.dispatch 49 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)] 50 %2 = call i8* @llvm.wasm.get.exception(token %1) 51 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 52 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 53 %matches = icmp eq i32 %3, %4 54 br i1 %matches, label %catch2, label %catch.fallthrough 55 56catch2: ; preds = %catch.start 57 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 58 call void @__cxa_end_catch() [ "funclet"(token %1) ] 59 catchret from %1 to label %try.cont 60 61catch.fallthrough: ; preds = %catch.start 62 %6 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*)) 63 %matches1 = icmp eq i32 %3, %6 64 br i1 %matches1, label %catch, label %rethrow 65 66catch: ; preds = %catch.fallthrough 67 %7 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 68 call void @__cxa_end_catch() [ "funclet"(token %1) ] 69 catchret from %1 to label %try.cont 70 71rethrow: ; preds = %catch.fallthrough 72 call void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %1) ] 73 unreachable 74 75try.cont: ; preds = %catch, %catch2, %entry 76 ret void 77} 78 79; Nested try-catches within a catch 80; void test1() { 81; try { 82; foo(); 83; } catch (int) { 84; try { 85; foo(); 86; } catch (int) { 87; foo(); 88; } 89; } 90; } 91 92; CHECK-LABEL: test1 93; CHECK: try 94; CHECK: call foo 95; CHECK: catch 96; CHECK: block 97; CHECK: block 98; CHECK: br_if 0, {{.*}} # 0: down to label7 99; CHECK: i32.call $drop=, __cxa_begin_catch 100; CHECK: try 101; CHECK: call foo 102; CHECK: br 2 # 2: down to label6 103; CHECK: catch 104; CHECK: try 105; CHECK: block 106; CHECK: br_if 0, {{.*}} # 0: down to label11 107; CHECK: i32.call $drop=, __cxa_begin_catch 108; CHECK: try 109; CHECK: call foo 110; CHECK: br 2 # 2: down to label9 111; CHECK: catch 112; CHECK: call __cxa_end_catch 113; CHECK: rethrow {{.*}} # down to catch3 114; CHECK: end_try 115; CHECK: end_block # label11: 116; CHECK: rethrow {{.*}} # down to catch3 117; CHECK: catch {{.*}} # catch3: 118; CHECK: call __cxa_end_catch 119; CHECK: rethrow {{.*}} # to caller 120; CHECK: end_try # label9: 121; CHECK: call __cxa_end_catch 122; CHECK: br 2 # 2: down to label6 123; CHECK: end_try 124; CHECK: end_block # label7: 125; CHECK: rethrow {{.*}} # to caller 126; CHECK: end_block # label6: 127; CHECK: call __cxa_end_catch 128; CHECK: end_try 129define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 130entry: 131 invoke void @foo() 132 to label %try.cont11 unwind label %catch.dispatch 133 134catch.dispatch: ; preds = %entry 135 %0 = catchswitch within none [label %catch.start] unwind to caller 136 137catch.start: ; preds = %catch.dispatch 138 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)] 139 %2 = call i8* @llvm.wasm.get.exception(token %1) 140 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 141 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 142 %matches = icmp eq i32 %3, %4 143 br i1 %matches, label %catch, label %rethrow 144 145catch: ; preds = %catch.start 146 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 147 %6 = bitcast i8* %5 to i32* 148 %7 = load i32, i32* %6, align 4 149 invoke void @foo() [ "funclet"(token %1) ] 150 to label %try.cont unwind label %catch.dispatch2 151 152catch.dispatch2: ; preds = %catch 153 %8 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup9 154 155catch.start3: ; preds = %catch.dispatch2 156 %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)] 157 %10 = call i8* @llvm.wasm.get.exception(token %9) 158 %11 = call i32 @llvm.wasm.get.ehselector(token %9) 159 %12 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 160 %matches4 = icmp eq i32 %11, %12 161 br i1 %matches4, label %catch6, label %rethrow5 162 163catch6: ; preds = %catch.start3 164 %13 = call i8* @__cxa_begin_catch(i8* %10) [ "funclet"(token %9) ] 165 %14 = bitcast i8* %13 to i32* 166 %15 = load i32, i32* %14, align 4 167 invoke void @foo() [ "funclet"(token %9) ] 168 to label %invoke.cont8 unwind label %ehcleanup 169 170invoke.cont8: ; preds = %catch6 171 call void @__cxa_end_catch() [ "funclet"(token %9) ] 172 catchret from %9 to label %try.cont 173 174rethrow5: ; preds = %catch.start3 175 invoke void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %9) ] 176 to label %unreachable unwind label %ehcleanup9 177 178try.cont: ; preds = %invoke.cont8, %catch 179 call void @__cxa_end_catch() [ "funclet"(token %1) ] 180 catchret from %1 to label %try.cont11 181 182rethrow: ; preds = %catch.start 183 call void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %1) ] 184 unreachable 185 186try.cont11: ; preds = %try.cont, %entry 187 ret void 188 189ehcleanup: ; preds = %catch6 190 %16 = cleanuppad within %9 [] 191 call void @__cxa_end_catch() [ "funclet"(token %16) ] 192 cleanupret from %16 unwind label %ehcleanup9 193 194ehcleanup9: ; preds = %ehcleanup, %rethrow5, %catch.dispatch2 195 %17 = cleanuppad within %1 [] 196 call void @__cxa_end_catch() [ "funclet"(token %17) ] 197 cleanupret from %17 unwind to caller 198 199unreachable: ; preds = %rethrow5 200 unreachable 201} 202 203; Nested loop within a catch clause 204; void test2() { 205; try { 206; foo(); 207; } catch (...) { 208; for (int i = 0; i < 50; i++) 209; foo(); 210; } 211; } 212 213; CHECK-LABEL: test2 214; CHECK: try 215; CHECK: call foo 216; CHECK: catch 217; CHECK: i32.call $drop=, __cxa_begin_catch 218; CHECK: loop # label15: 219; CHECK: block 220; CHECK: block 221; CHECK: br_if 0, {{.*}} # 0: down to label17 222; CHECK: try 223; CHECK: call foo 224; CHECK: br 2 # 2: down to label16 225; CHECK: catch 226; CHECK: try 227; CHECK: call __cxa_end_catch 228; CHECK: catch 229; CHECK: call __clang_call_terminate 230; CHECK: unreachable 231; CHECK: end_try 232; CHECK: rethrow {{.*}} # to caller 233; CHECK: end_try 234; CHECK: end_block # label17: 235; CHECK: call __cxa_end_catch 236; CHECK: br 2 # 2: down to label13 237; CHECK: end_block # label16: 238; CHECK: br 0 # 0: up to label15 239; CHECK: end_loop 240; CHECK: end_try # label13: 241define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 242entry: 243 invoke void @foo() 244 to label %try.cont unwind label %catch.dispatch 245 246catch.dispatch: ; preds = %entry 247 %0 = catchswitch within none [label %catch.start] unwind to caller 248 249catch.start: ; preds = %catch.dispatch 250 %1 = catchpad within %0 [i8* null] 251 %2 = call i8* @llvm.wasm.get.exception(token %1) 252 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 253 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 254 br label %for.cond 255 256for.cond: ; preds = %for.inc, %catch.start 257 %i.0 = phi i32 [ 0, %catch.start ], [ %inc, %for.inc ] 258 %cmp = icmp slt i32 %i.0, 50 259 br i1 %cmp, label %for.body, label %for.end 260 261for.body: ; preds = %for.cond 262 invoke void @foo() [ "funclet"(token %1) ] 263 to label %for.inc unwind label %ehcleanup 264 265for.inc: ; preds = %for.body 266 %inc = add nsw i32 %i.0, 1 267 br label %for.cond 268 269for.end: ; preds = %for.cond 270 call void @__cxa_end_catch() [ "funclet"(token %1) ] 271 catchret from %1 to label %try.cont 272 273try.cont: ; preds = %for.end, %entry 274 ret void 275 276ehcleanup: ; preds = %for.body 277 %5 = cleanuppad within %1 [] 278 invoke void @__cxa_end_catch() [ "funclet"(token %5) ] 279 to label %invoke.cont2 unwind label %terminate 280 281invoke.cont2: ; preds = %ehcleanup 282 cleanupret from %5 unwind to caller 283 284terminate: ; preds = %ehcleanup 285 %6 = cleanuppad within %5 [] 286 %7 = call i8* @llvm.wasm.get.exception(token %6) 287 call void @__clang_call_terminate(i8* %7) [ "funclet"(token %6) ] 288 unreachable 289} 290 291; Tests if block and try markers are correctly placed. Even if two predecessors 292; of the EH pad are bb2 and bb3 and their nearest common dominator is bb1, the 293; TRY marker should be placed at bb0 because there's a branch from bb0 to bb2, 294; and scopes cannot be interleaved. 295 296; NOOPT-LABEL: test3 297; NOOPT: try 298; NOOPT: block 299; NOOPT: block 300; NOOPT: block 301; NOOPT: end_block 302; NOOPT: end_block 303; NOOPT: call foo 304; NOOPT: end_block 305; NOOPT: call bar 306; NOOPT: catch {{.*}} 307; NOOPT: end_try 308define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 309bb0: 310 br i1 undef, label %bb1, label %bb2 311 312bb1: ; preds = %bb0 313 br i1 undef, label %bb3, label %bb4 314 315bb2: ; preds = %bb0 316 br label %try.cont 317 318bb3: ; preds = %bb1 319 invoke void @foo() 320 to label %try.cont unwind label %catch.dispatch 321 322bb4: ; preds = %bb1 323 invoke void @bar() 324 to label %try.cont unwind label %catch.dispatch 325 326catch.dispatch: ; preds = %bb4, %bb3 327 %0 = catchswitch within none [label %catch.start] unwind to caller 328 329catch.start: ; preds = %catch.dispatch 330 %1 = catchpad within %0 [i8* null] 331 %2 = call i8* @llvm.wasm.get.exception(token %1) 332 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 333 catchret from %1 to label %try.cont 334 335try.cont: ; preds = %catch.start, %bb4, %bb3, %bb2 336 ret void 337} 338 339; Tests if try/end_try markers are placed correctly wrt loop/end_loop markers, 340; when try and loop markers are in the same BB and end_try and end_loop are in 341; another BB. 342; CHECK: loop 343; CHECK: try 344; CHECK: call foo 345; CHECK: catch 346; CHECK: end_try 347; CHECK: end_loop 348define void @test4(i32* %p) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 349entry: 350 store volatile i32 0, i32* %p 351 br label %loop 352 353loop: ; preds = %try.cont, %entry 354 store volatile i32 1, i32* %p 355 invoke void @foo() 356 to label %try.cont unwind label %catch.dispatch 357 358catch.dispatch: ; preds = %loop 359 %0 = catchswitch within none [label %catch.start] unwind to caller 360 361catch.start: ; preds = %catch.dispatch 362 %1 = catchpad within %0 [i8* null] 363 %2 = call i8* @llvm.wasm.get.exception(token %1) 364 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 365 catchret from %1 to label %try.cont 366 367try.cont: ; preds = %catch.start, %loop 368 br label %loop 369} 370 371; Some of test cases below are hand-tweaked by deleting some library calls to 372; simplify tests and changing the order of basic blocks to cause unwind 373; destination mismatches. And we use -wasm-disable-ehpad-sort to create maximum 374; number of mismatches in several tests below. 375 376; 'call bar''s original unwind destination was 'catch14', but after control flow 377; linearization, its unwind destination incorrectly becomes 'catch15'. We fix 378; this by wrapping the call with a nested try/catch/end_try and branching to the 379; right destination (label32). 380 381; NOSORT-LABEL: test5 382; NOSORT: block 383; NOSORT: try 384; NOSORT: try 385; NOSORT: call foo 386; --- Nested try/catch/end_try starts 387; NOSORT: try 388; NOSORT: call bar 389; NOSORT: catch $drop= 390; NOSORT: br 2 # 2: down to label32 391; NOSORT: end_try 392; --- Nested try/catch/end_try ends 393; NOSORT: br 2 # 2: down to label31 394; NOSORT: catch $drop= # catch15: 395; NOSORT: br 2 # 2: down to label31 396; NOSORT: end_try 397; NOSORT: catch $drop= # catch14: 398; NOSORT: end_try # label32: 399; NOSORT: end_block # label31: 400; NOSORT: return 401 402define void @test5() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 403bb0: 404 invoke void @foo() 405 to label %bb1 unwind label %catch.dispatch0 406 407bb1: ; preds = %bb0 408 invoke void @bar() 409 to label %try.cont unwind label %catch.dispatch1 410 411catch.dispatch0: ; preds = %bb0 412 %0 = catchswitch within none [label %catch.start0] unwind to caller 413 414catch.start0: ; preds = %catch.dispatch0 415 %1 = catchpad within %0 [i8* null] 416 %2 = call i8* @llvm.wasm.get.exception(token %1) 417 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 418 catchret from %1 to label %try.cont 419 420catch.dispatch1: ; preds = %bb1 421 %4 = catchswitch within none [label %catch.start1] unwind to caller 422 423catch.start1: ; preds = %catch.dispatch1 424 %5 = catchpad within %4 [i8* null] 425 %6 = call i8* @llvm.wasm.get.exception(token %5) 426 %7 = call i32 @llvm.wasm.get.ehselector(token %5) 427 catchret from %5 to label %try.cont 428 429try.cont: ; preds = %catch.start1, %catch.start0, %bb1 430 ret void 431} 432 433; Two 'call bar''s original unwind destination was the caller, but after control 434; flow linearization, their unwind destination incorrectly becomes 'catch17'. We 435; fix this by wrapping the call with a nested try/catch/end_try and branching to 436; the right destination (label4), from which we rethrow the exception to the 437; caller. 438 439; NOSORT-LABEL: test6 440; NOSORT: try 441; NOSORT: call foo 442; --- Nested try/catch/end_try starts 443; NOSORT: try 444; NOSORT: call bar 445; NOSORT: call bar 446; NOSORT: catch $[[REG:[0-9]+]]= 447; NOSORT: br 1 # 1: down to label35 448; NOSORT: end_try 449; --- Nested try/catch/end_try ends 450; NOSORT: return 451; NOSORT: catch $drop= # catch17: 452; NOSORT: return 453; NOSORT: end_try # label35: 454; NOSORT: rethrow $[[REG]] # to caller 455 456define void @test6() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 457bb0: 458 invoke void @foo() 459 to label %bb1 unwind label %catch.dispatch0 460 461bb1: ; preds = %bb0 462 call void @bar() 463 call void @bar() 464 ret void 465 466catch.dispatch0: ; preds = %bb0 467 %0 = catchswitch within none [label %catch.start0] unwind to caller 468 469catch.start0: ; preds = %catch.dispatch0 470 %1 = catchpad within %0 [i8* null] 471 %2 = call i8* @llvm.wasm.get.exception(token %1) 472 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 473 catchret from %1 to label %try.cont 474 475try.cont: ; preds = %catch.start0 476 ret void 477} 478 479; If not for the unwind destination mismatch, the LOOP marker here would have an 480; i32 signature. But because we add a rethrow instruction at the end of the 481; appendix block, now the LOOP marker does not have a signature (= has a void 482; signature). Here the two calls two 'bar' are supposed to throw up to the 483; caller, but incorrectly unwind to 'catch19' after linearizing the CFG. 484 485; NOSORT-LABEL: test7 486; NOSORT: block 487; NOSORT-NOT: loop i32 488; NOSORT: loop # label38: 489; NOSORT: try 490; NOSORT: call foo 491; --- Nested try/catch/end_try starts 492; NOSORT: try 493; NOSORT: call bar 494; NOSORT: call bar 495; NOSORT: catch $[[REG:[0-9]+]]= 496; NOSORT: br 1 # 1: down to label39 497; NOSORT: end_try 498; --- Nested try/catch/end_try ends 499; NOSORT: return {{.*}} 500; NOSORT: catch $drop= # catch19: 501; NOSORT: br 1 # 1: up to label38 502; NOSORT: end_try # label39: 503; NOSORT: end_loop 504; NOSORT: end_block 505; NOSORT: rethrow $[[REG]] # to caller 506 507define i32 @test7(i32* %p) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 508entry: 509 store volatile i32 0, i32* %p 510 br label %loop 511 512loop: ; preds = %try.cont, %entry 513 store volatile i32 1, i32* %p 514 invoke void @foo() 515 to label %bb unwind label %catch.dispatch 516 517bb: ; preds = %loop 518 call void @bar() 519 call void @bar() 520 ret i32 0 521 522catch.dispatch: ; preds = %loop 523 %0 = catchswitch within none [label %catch.start] unwind to caller 524 525catch.start: ; preds = %catch.dispatch 526 %1 = catchpad within %0 [i8* null] 527 %2 = call i8* @llvm.wasm.get.exception(token %1) 528 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 529 catchret from %1 to label %try.cont 530 531try.cont: ; preds = %catch.start 532 br label %loop 533} 534 535; When we have both kinds of EH pad unwind mismatches: 536; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the 537; CFG, when it is supposed to unwind to another EH pad. 538; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the 539; CFG, when it is supposed to unwind to the caller. 540 541; NOSORT-LABEL: test8 542; NOSORT: block 543; NOSORT: block 544; NOSORT: try 545; NOSORT: try 546; NOSORT: call foo 547; --- Nested try/catch/end_try starts 548; NOSORT: try 549; NOSORT: call bar 550; NOSORT: catch $[[REG0:[0-9]+]]= 551; NOSORT: br 2 # 2: down to label43 552; NOSORT: end_try 553; --- Nested try/catch/end_try ends 554; NOSORT: br 2 # 2: down to label42 555; NOSORT: catch {{.*}} 556; NOSORT: block i32 557; NOSORT: br_on_exn 0, {{.*}} # 0: down to label46 558; --- Nested try/catch/end_try starts 559; NOSORT: try 560; NOSORT: rethrow {{.*}} # down to catch24 561; NOSORT: catch $[[REG1:[0-9]+]]= # catch24: 562; NOSORT: br 5 # 5: down to label41 563; NOSORT: end_try 564; --- Nested try/catch/end_try ends 565; NOSORT: end_block # label46: 566; NOSORT: i32.call $drop=, __cxa_begin_catch 567; --- Nested try/catch/end_try starts 568; NOSORT: try 569; NOSORT: call __cxa_end_catch 570; NOSORT: catch $[[REG1]]= 571; NOSORT: br 4 # 4: down to label41 572; NOSORT: end_try 573; --- Nested try/catch/end_try ends 574; NOSORT: br 2 # 2: down to label42 575; NOSORT: end_try 576; NOSORT: catch $[[REG0]]= 577; NOSORT: end_try # label43: 578; NOSORT: i32.call $drop=, __cxa_begin_catch 579; NOSORT: call __cxa_end_catch 580; NOSORT: end_block # label42: 581; NOSORT: return 582; NOSORT: end_block # label41: 583; NOSORT: rethrow $[[REG1]] # to caller 584define void @test8() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 585bb0: 586 invoke void @foo() 587 to label %bb1 unwind label %catch.dispatch0 588 589bb1: ; preds = %bb0 590 invoke void @bar() 591 to label %try.cont unwind label %catch.dispatch1 592 593catch.dispatch0: ; preds = %bb0 594 %0 = catchswitch within none [label %catch.start0] unwind to caller 595 596catch.start0: ; preds = %catch.dispatch0 597 %1 = catchpad within %0 [i8* null] 598 %2 = call i8* @llvm.wasm.get.exception(token %1) 599 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 600 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 601 call void @__cxa_end_catch() [ "funclet"(token %1) ] 602 catchret from %1 to label %try.cont 603 604catch.dispatch1: ; preds = %bb1 605 %5 = catchswitch within none [label %catch.start1] unwind to caller 606 607catch.start1: ; preds = %catch.dispatch1 608 %6 = catchpad within %5 [i8* null] 609 %7 = call i8* @llvm.wasm.get.exception(token %6) 610 %8 = call i32 @llvm.wasm.get.ehselector(token %6) 611 %9 = call i8* @__cxa_begin_catch(i8* %7) [ "funclet"(token %6) ] 612 call void @__cxa_end_catch() [ "funclet"(token %6) ] 613 catchret from %6 to label %try.cont 614 615try.cont: ; preds = %catch.start1, %catch.start0, %bb1 616 ret void 617} 618 619declare void @foo() 620declare void @bar() 621declare i32 @__gxx_wasm_personality_v0(...) 622declare i8* @llvm.wasm.get.exception(token) 623declare i32 @llvm.wasm.get.ehselector(token) 624declare void @llvm.wasm.rethrow.in.catch() 625declare i32 @llvm.eh.typeid.for(i8*) 626declare i8* @__cxa_begin_catch(i8*) 627declare void @__cxa_end_catch() 628declare void @__clang_call_terminate(i8*) 629declare void @_ZSt9terminatev() 630