1; RUN: opt < %s -winehprepare -demote-catchswitch-only -wasmehprepare -S | FileCheck %s 2 3target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" 4target triple = "wasm32-unknown-unknown" 5 6; CHECK: @__wasm_lpad_context = external global { i32, i8*, i32 } 7 8@_ZTIi = external constant i8* 9%struct.Temp = type { i8 } 10 11; A single 'catch (int)' clause. 12; A wasm.catch() call, wasm.lsda() call, and personality call to generate a 13; selector should all be genereated after the catchpad. 14; 15; void foo(); 16; void test0() { 17; try { 18; foo(); 19; } catch (int) { 20; } 21; } 22define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 23; CHECK-LABEL: @test0() 24entry: 25 invoke void @foo() 26 to label %try.cont unwind label %catch.dispatch 27 28catch.dispatch: ; preds = %entry 29 %0 = catchswitch within none [label %catch.start] unwind to caller 30 31catch.start: ; preds = %catch.dispatch 32 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)] 33 %2 = call i8* @llvm.wasm.get.exception(token %1) 34 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 35 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 36 %matches = icmp eq i32 %3, %4 37 br i1 %matches, label %catch, label %rethrow 38; CHECK: catch.start: 39; CHECK-NEXT: %[[CATCHPAD:.*]] = catchpad 40; CHECK-NEXT: %[[EXN:.*]] = call i8* @llvm.wasm.extract.exception() 41; CHECK-NEXT: call void @llvm.wasm.landingpad.index(token %[[CATCHPAD]], i32 0) 42; CHECK-NEXT: store i32 0, i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 0) 43; CHECK-NEXT: %[[LSDA:.*]] = call i8* @llvm.wasm.lsda() 44; CHECK-NEXT: store i8* %[[LSDA]], i8** getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 1) 45; CHECK-NEXT: call i32 @_Unwind_CallPersonality(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ] 46; CHECK-NEXT: %[[SELECTOR:.*]] = load i32, i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 2) 47; CHECK: icmp eq i32 %[[SELECTOR]] 48 49catch: ; preds = %catch.start 50 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 51 call void @__cxa_end_catch() [ "funclet"(token %1) ] 52 catchret from %1 to label %try.cont 53; CHECK: catch: 54; CHECK-NEXT: call i8* @__cxa_begin_catch(i8* %[[EXN]]) 55 56rethrow: ; preds = %catch.start 57 call void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %1) ] 58 unreachable 59 60try.cont: ; preds = %entry, %catch 61 ret void 62} 63 64; Two try-catches. 65; For the catchpad with a single 'catch (...)', only a wasm.catch() call should 66; be generated after the catchpad; wasm.landingpad.index() and personality call 67; should NOT be generated. For the other catchpad, the argument of 68; wasm.landingpad.index() should be not 1 but 0. 69; 70; void foo(); 71; void test1() { 72; try { 73; foo(); 74; } catch (...) { 75; } 76; try { 77; foo(); 78; } catch (int) { 79; } 80; } 81define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 82; CHECK-LABEL: @test1() 83entry: 84 invoke void @foo() 85 to label %try.cont unwind label %catch.dispatch 86 87catch.dispatch: ; preds = %entry 88 %0 = catchswitch within none [label %catch.start] unwind to caller 89 90catch.start: ; preds = %catch.dispatch 91 %1 = catchpad within %0 [i8* null] 92 %2 = call i8* @llvm.wasm.get.exception(token %1) 93 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 94 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 95 call void @__cxa_end_catch() [ "funclet"(token %1) ] 96 catchret from %1 to label %try.cont 97; CHECK: catch.start: 98; CHECK-NEXT: catchpad within %0 [i8* null] 99; CHECK-NOT: call void @llvm.wasm.landingpad.index 100; CHECK-NOT: store {{.*}} @__wasm_lpad_context 101; CHECK-NOT: call i8* @llvm.wasm.lsda() 102; CHECK-NOT: call i32 @_Unwind_CallPersonality 103; CHECK-NOT: load {{.*}} @__wasm_lpad_context 104 105try.cont: ; preds = %entry, %catch.start 106 invoke void @foo() 107 to label %try.cont7 unwind label %catch.dispatch2 108 109catch.dispatch2: ; preds = %try.cont 110 %5 = catchswitch within none [label %catch.start3] unwind to caller 111 112catch.start3: ; preds = %catch.dispatch2 113 %6 = catchpad within %5 [i8* bitcast (i8** @_ZTIi to i8*)] 114 %7 = call i8* @llvm.wasm.get.exception(token %6) 115 %8 = call i32 @llvm.wasm.get.ehselector(token %6) 116 %9 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 117 %matches = icmp eq i32 %8, %9 118 br i1 %matches, label %catch4, label %rethrow 119; CHECK: catch.start3: 120; CHECK: call void @llvm.wasm.landingpad.index(token %{{.+}}, i32 0) 121 122catch4: ; preds = %catch.start3 123 %10 = call i8* @__cxa_begin_catch(i8* %7) [ "funclet"(token %6) ] 124 call void @__cxa_end_catch() [ "funclet"(token %6) ] 125 catchret from %6 to label %try.cont7 126 127rethrow: ; preds = %catch.start3 128 call void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %6) ] 129 unreachable 130 131try.cont7: ; preds = %try.cont, %catch4 132 ret void 133} 134 135; A nested try-catch within a catch. The outer catch catches 'int'. 136; 137; void foo(); 138; void test2() { 139; try { 140; foo(); 141; } catch (int) { 142; try { 143; foo(); 144; } catch (int) { 145; } 146; } 147; } 148; Within the nested catchpad, wasm.lsda() call should NOT be generated. 149define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 150; CHECK-LABEL: @test2() 151entry: 152 invoke void @foo() 153 to label %try.cont9 unwind label %catch.dispatch 154 155catch.dispatch: ; preds = %entry 156 %0 = catchswitch within none [label %catch.start] unwind to caller 157 158catch.start: ; preds = %catch.dispatch 159 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)] 160 %2 = call i8* @llvm.wasm.get.exception(token %1) 161 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 162 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 163 %matches = icmp eq i32 %3, %4 164 br i1 %matches, label %catch, label %rethrow 165; CHECK: catch.start: 166; CHECK: call i8* @llvm.wasm.lsda() 167 168catch: ; preds = %catch.start 169 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 170 invoke void @foo() [ "funclet"(token %1) ] 171 to label %try.cont unwind label %catch.dispatch2 172 173catch.dispatch2: ; preds = %catch 174 %6 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup 175 176catch.start3: ; preds = %catch.dispatch2 177 %7 = catchpad within %6 [i8* bitcast (i8** @_ZTIi to i8*)] 178 %8 = call i8* @llvm.wasm.get.exception(token %7) 179 %9 = call i32 @llvm.wasm.get.ehselector(token %7) 180 %10 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 181 %matches4 = icmp eq i32 %9, %10 182 br i1 %matches4, label %catch6, label %rethrow5 183; CHECK: catch.start3: 184; CHECK-NOT: call i8* @llvm.wasm.lsda() 185 186catch6: ; preds = %catch.start3 187 %11 = call i8* @__cxa_begin_catch(i8* %8) [ "funclet"(token %7) ] 188 call void @__cxa_end_catch() [ "funclet"(token %7) ] 189 catchret from %7 to label %try.cont 190 191rethrow5: ; preds = %catch.start3 192 invoke void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %7) ] 193 to label %unreachable unwind label %ehcleanup 194 195try.cont: ; preds = %catch, %catch6 196 call void @__cxa_end_catch() [ "funclet"(token %1) ] 197 catchret from %1 to label %try.cont9 198 199rethrow: ; preds = %catch.start 200 call void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %1) ] 201 unreachable 202 203try.cont9: ; preds = %entry, %try.cont 204 ret void 205 206ehcleanup: ; preds = %rethrow5, %catch.dispatch2 207 %12 = cleanuppad within %1 [] 208 call void @__cxa_end_catch() [ "funclet"(token %12) ] 209 cleanupret from %12 unwind to caller 210; CHECK: ehcleanup: 211; CHECK-NEXT: cleanuppad 212; CHECK-NOT: call void @llvm.wasm.landingpad.index 213; CHECK-NOT: store {{.*}} @__wasm_lpad_context 214; CHECK-NOT: call i8* @llvm.wasm.lsda() 215; CHECK-NOT: call i32 @_Unwind_CallPersonality 216; CHECK-NOT: load {{.*}} @__wasm_lpad_context 217 218unreachable: ; preds = %rethrow5 219 unreachable 220} 221 222; A nested try-catch within a catch. The outer catch is (...). 223; 224; void foo(); 225; void test2() { 226; try { 227; foo(); 228; } catch (...) { 229; try { 230; foo(); 231; } catch (int) { 232; } 233; } 234; } 235; Within the innermost catchpad, wasm.lsda() call should be generated, because 236; the outer catch is 'catch (...)', which does not need wasm.lsda() call. 237define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 238; CHECK-LABEL: @test3() 239entry: 240 invoke void @foo() 241 to label %try.cont8 unwind label %catch.dispatch 242 243catch.dispatch: ; preds = %entry 244 %0 = catchswitch within none [label %catch.start] unwind to caller 245 246catch.start: ; preds = %catch.dispatch 247 %1 = catchpad within %0 [i8* null] 248 %2 = call i8* @llvm.wasm.get.exception(token %1) 249 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 250 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 251 invoke void @foo() [ "funclet"(token %1) ] 252 to label %try.cont unwind label %catch.dispatch2 253; CHECK: catch.start: 254; CHECK-NOT: call i8* @llvm.wasm.lsda() 255 256catch.dispatch2: ; preds = %catch.start 257 %5 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup 258 259catch.start3: ; preds = %catch.dispatch2 260 %6 = catchpad within %5 [i8* bitcast (i8** @_ZTIi to i8*)] 261 %7 = call i8* @llvm.wasm.get.exception(token %6) 262 %8 = call i32 @llvm.wasm.get.ehselector(token %6) 263 %9 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 264 %matches = icmp eq i32 %8, %9 265 br i1 %matches, label %catch4, label %rethrow 266; CHECK: catch.start3: 267; CHECK: call i8* @llvm.wasm.lsda() 268 269catch4: ; preds = %catch.start3 270 %10 = call i8* @__cxa_begin_catch(i8* %7) [ "funclet"(token %6) ] 271 %11 = bitcast i8* %10 to i32* 272 %12 = load i32, i32* %11, align 4 273 call void @__cxa_end_catch() [ "funclet"(token %6) ] 274 catchret from %6 to label %try.cont 275 276rethrow: ; preds = %catch.start3 277 invoke void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %6) ] 278 to label %unreachable unwind label %ehcleanup 279 280try.cont: ; preds = %catch.start, %catch4 281 call void @__cxa_end_catch() [ "funclet"(token %1) ] 282 catchret from %1 to label %try.cont8 283 284try.cont8: ; preds = %entry, %try.cont 285 ret void 286 287ehcleanup: ; preds = %rethrow, %catch.dispatch2 288 %13 = cleanuppad within %1 [] 289 invoke void @__cxa_end_catch() [ "funclet"(token %13) ] 290 to label %invoke.cont6 unwind label %terminate 291 292invoke.cont6: ; preds = %ehcleanup 293 cleanupret from %13 unwind to caller 294 295unreachable: ; preds = %rethrow 296 unreachable 297 298terminate: ; preds = %ehcleanup 299 %14 = cleanuppad within %13 [] 300 %15 = call i8* @llvm.wasm.get.exception(token %14) 301 call void @__clang_call_terminate(i8* %15) [ "funclet"(token %14) ] 302 unreachable 303} 304 305; void foo(); 306; void test4() { 307; try { 308; foo(); 309; } catch (int) { 310; try { 311; foo(); 312; } catch (...) { 313; try { 314; foo(); 315; } catch (int) { 316; } 317; } 318; } 319; } 320; wasm.lsda() call should be generated only once in the outermost catchpad. The 321; innermost 'catch (int)' can reuse the wasm.lsda() generated in the outermost 322; catch. 323define void @test4() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 324; CHECK-LABEL: @test4() 325entry: 326 invoke void @foo() 327 to label %try.cont19 unwind label %catch.dispatch 328 329catch.dispatch: ; preds = %entry 330 %0 = catchswitch within none [label %catch.start] unwind to caller 331 332catch.start: ; preds = %catch.dispatch 333 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)] 334 %2 = call i8* @llvm.wasm.get.exception(token %1) 335 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 336 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 337 %matches = icmp eq i32 %3, %4 338 br i1 %matches, label %catch, label %rethrow 339; CHECK: catch.start: 340; CHECK: call i8* @llvm.wasm.lsda() 341 342catch: ; preds = %catch.start 343 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 344 %6 = bitcast i8* %5 to i32* 345 %7 = load i32, i32* %6, align 4 346 invoke void @foo() [ "funclet"(token %1) ] 347 to label %try.cont16 unwind label %catch.dispatch2 348 349catch.dispatch2: ; preds = %catch 350 %8 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup17 351 352catch.start3: ; preds = %catch.dispatch2 353 %9 = catchpad within %8 [i8* null] 354 %10 = call i8* @llvm.wasm.get.exception(token %9) 355 %11 = call i32 @llvm.wasm.get.ehselector(token %9) 356 %12 = call i8* @__cxa_begin_catch(i8* %10) [ "funclet"(token %9) ] 357 invoke void @foo() [ "funclet"(token %9) ] 358 to label %try.cont unwind label %catch.dispatch7 359; CHECK: catch.start3: 360; CHECK-NOT: call i8* @llvm.wasm.lsda() 361 362catch.dispatch7: ; preds = %catch.start3 363 %13 = catchswitch within %9 [label %catch.start8] unwind label %ehcleanup 364 365catch.start8: ; preds = %catch.dispatch7 366 %14 = catchpad within %13 [i8* bitcast (i8** @_ZTIi to i8*)] 367 %15 = call i8* @llvm.wasm.get.exception(token %14) 368 %16 = call i32 @llvm.wasm.get.ehselector(token %14) 369 %17 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 370 %matches9 = icmp eq i32 %16, %17 371 br i1 %matches9, label %catch11, label %rethrow10 372; CHECK: catch.start8: 373; CHECK-NOT: call i8* @llvm.wasm.lsda() 374 375catch11: ; preds = %catch.start8 376 %18 = call i8* @__cxa_begin_catch(i8* %15) [ "funclet"(token %14) ] 377 %19 = bitcast i8* %18 to i32* 378 %20 = load i32, i32* %19, align 4 379 call void @__cxa_end_catch() [ "funclet"(token %14) ] 380 catchret from %14 to label %try.cont 381 382rethrow10: ; preds = %catch.start8 383 invoke void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %14) ] 384 to label %unreachable unwind label %ehcleanup 385 386try.cont: ; preds = %catch.start3, %catch11 387 invoke void @__cxa_end_catch() [ "funclet"(token %9) ] 388 to label %invoke.cont13 unwind label %ehcleanup17 389 390invoke.cont13: ; preds = %try.cont 391 catchret from %9 to label %try.cont16 392 393try.cont16: ; preds = %catch, %invoke.cont13 394 call void @__cxa_end_catch() [ "funclet"(token %1) ] 395 catchret from %1 to label %try.cont19 396 397rethrow: ; preds = %catch.start 398 call void @llvm.wasm.rethrow.in.catch() [ "funclet"(token %1) ] 399 unreachable 400 401try.cont19: ; preds = %entry, %try.cont16 402 ret void 403 404ehcleanup: ; preds = %rethrow10, %catch.dispatch7 405 %21 = cleanuppad within %9 [] 406 invoke void @__cxa_end_catch() [ "funclet"(token %21) ] 407 to label %invoke.cont14 unwind label %terminate 408 409invoke.cont14: ; preds = %ehcleanup 410 cleanupret from %21 unwind label %ehcleanup17 411 412ehcleanup17: ; preds = %invoke.cont14, %try.cont, %catch.dispatch2 413 %22 = cleanuppad within %1 [] 414 call void @__cxa_end_catch() [ "funclet"(token %22) ] 415 cleanupret from %22 unwind to caller 416 417unreachable: ; preds = %rethrow10 418 unreachable 419 420terminate: ; preds = %ehcleanup 421 %23 = cleanuppad within %21 [] 422 %24 = call i8* @llvm.wasm.get.exception(token %23) 423 call void @__clang_call_terminate(i8* %24) [ "funclet"(token %23) ] 424 unreachable 425} 426 427; A cleanuppad with a call to __clang_call_terminate(). 428; 429; void foo(); 430; void test5() { 431; try { 432; foo(); 433; } catch (...) { 434; foo(); 435; } 436; } 437define void @test5() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 438; CHECK-LABEL: @test5 439entry: 440 invoke void @foo() 441 to label %try.cont unwind label %catch.dispatch 442 443catch.dispatch: ; preds = %entry 444 %0 = catchswitch within none [label %catch.start] unwind to caller 445 446catch.start: ; preds = %catch.dispatch 447 %1 = catchpad within %0 [i8* null] 448 %2 = call i8* @llvm.wasm.get.exception(token %1) 449 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 450 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 451 invoke void @foo() [ "funclet"(token %1) ] 452 to label %invoke.cont1 unwind label %ehcleanup 453 454invoke.cont1: ; preds = %catch.start 455 call void @__cxa_end_catch() [ "funclet"(token %1) ] 456 catchret from %1 to label %try.cont 457 458try.cont: ; preds = %entry, %invoke.cont1 459 ret void 460 461ehcleanup: ; preds = %catch.start 462 %5 = cleanuppad within %1 [] 463 invoke void @__cxa_end_catch() [ "funclet"(token %5) ] 464 to label %invoke.cont2 unwind label %terminate 465 466invoke.cont2: ; preds = %ehcleanup 467 cleanupret from %5 unwind to caller 468 469terminate: ; preds = %ehcleanup 470 %6 = cleanuppad within %5 [] 471 %7 = call i8* @llvm.wasm.get.exception(token %6) 472 call void @__clang_call_terminate(i8* %7) [ "funclet"(token %6) ] 473 unreachable 474; CHECK: terminate: 475; CHECK-NEXT: cleanuppad 476; CHECK-NEXT: %[[EXN:.*]] = call i8* @llvm.wasm.extract.exception 477; CHECK-NEXT: call void @__clang_call_terminate(i8* %[[EXN]]) 478} 479 480; PHI demotion test. Only the phi before catchswitch should be demoted; the phi 481; before cleanuppad should NOT. 482; 483; void foo(); 484; int bar(int) noexcept; 485; struct Temp { 486; ~Temp() {} 487; }; 488; 489; void test6() { 490; int num; 491; try { 492; Temp t; 493; num = 1; 494; foo(); 495; num = 2; 496; foo(); 497; } catch (...) { 498; bar(num); 499; } 500; try { 501; foo(); 502; num = 1; 503; foo(); 504; num = 2; 505; } catch (...) { 506; bar(num); 507; } 508; } 509define void @test6() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 510; CHECK-LABEL: @test6 511entry: 512 %t = alloca %struct.Temp, align 1 513 invoke void @foo() 514 to label %invoke.cont unwind label %ehcleanup 515 516invoke.cont: ; preds = %entry 517 invoke void @foo() 518 to label %invoke.cont1 unwind label %ehcleanup 519 520invoke.cont1: ; preds = %invoke.cont 521 %call = call %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* %t) 522 br label %try.cont 523 524ehcleanup: ; preds = %invoke.cont, %entry 525 %num.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ] 526 %0 = cleanuppad within none [] 527 %call2 = call %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* %t) [ "funclet"(token %0) ] 528 cleanupret from %0 unwind label %catch.dispatch 529; CHECK: ehcleanup: 530; CHECK-NEXT: = phi 531 532catch.dispatch: ; preds = %ehcleanup 533 %1 = catchswitch within none [label %catch.start] unwind to caller 534 535catch.start: ; preds = %catch.dispatch 536 %2 = catchpad within %1 [i8* null] 537 %3 = call i8* @llvm.wasm.get.exception(token %2) 538 %4 = call i32 @llvm.wasm.get.ehselector(token %2) 539 %5 = call i8* @__cxa_begin_catch(i8* %3) [ "funclet"(token %2) ] 540 call void @bar(i32 %num.0) [ "funclet"(token %2) ] 541 call void @__cxa_end_catch() [ "funclet"(token %2) ] 542 catchret from %2 to label %try.cont 543 544try.cont: ; preds = %catch.start, %invoke.cont1 545 invoke void @foo() 546 to label %invoke.cont3 unwind label %catch.dispatch5 547 548invoke.cont3: ; preds = %try.cont 549 invoke void @foo() 550 to label %try.cont10 unwind label %catch.dispatch5 551 552catch.dispatch5: ; preds = %invoke.cont3, %try.cont 553 %num.1 = phi i32 [ 2, %invoke.cont3 ], [ 1, %try.cont ] 554 %6 = catchswitch within none [label %catch.start6] unwind to caller 555; CHECK: catch.dispatch5: 556; CHECK-NOT: = phi 557 558catch.start6: ; preds = %catch.dispatch5 559 %7 = catchpad within %6 [i8* null] 560 %8 = call i8* @llvm.wasm.get.exception(token %7) 561 %9 = call i32 @llvm.wasm.get.ehselector(token %7) 562 %10 = call i8* @__cxa_begin_catch(i8* %8) [ "funclet"(token %7) ] 563 call void @bar(i32 %num.1) [ "funclet"(token %7) ] 564 call void @__cxa_end_catch() [ "funclet"(token %7) ] 565 catchret from %7 to label %try.cont10 566 567try.cont10: ; preds = %invoke.cont3, %catch.start6 568 ret void 569} 570 571; Tests if instructions after a call to @llvm.wasm.throw are deleted and the 572; BB's dead children are deleted. 573 574; CHECK-LABEL: @test7 575define i32 @test7(i1 %b, i8* %p) { 576entry: 577 br i1 %b, label %bb.true, label %bb.false 578 579; CHECK: bb.true: 580; CHECK-NEXT: call void @llvm.wasm.throw(i32 0, i8* %p) 581; CHECK-NEXT: unreachable 582bb.true: ; preds = %entry 583 call void @llvm.wasm.throw(i32 0, i8* %p) 584 br label %bb.true.0 585 586; CHECK-NOT: bb.true.0 587bb.true.0: ; preds = %bb.true 588 br label %merge 589 590; CHECK: bb.false 591bb.false: ; preds = %entry 592 br label %merge 593 594; CHECK: merge 595merge: ; preds = %bb.true.0, %bb.false 596 ret i32 0 597} 598 599declare void @foo() 600declare void @bar(i32) 601declare %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* returned) 602declare i32 @__gxx_wasm_personality_v0(...) 603declare i8* @llvm.wasm.get.exception(token) 604declare i32 @llvm.wasm.get.ehselector(token) 605declare i32 @llvm.eh.typeid.for(i8*) 606declare void @llvm.wasm.throw(i32, i8*) 607declare void @llvm.wasm.rethrow.in.catch() 608declare i8* @__cxa_begin_catch(i8*) 609declare void @__cxa_end_catch() 610declare void @__clang_call_terminate(i8*) 611 612; CHECK-DAG: declare void @llvm.wasm.landingpad.index(token, i32 immarg) 613; CHECK-DAG: declare i8* @llvm.wasm.lsda() 614; CHECK-DAG: declare i32 @_Unwind_CallPersonality(i8*) 615