brintos

brintos / llvm-project-archived public Read only

0
0
Text · 69.1 KiB · f0a1d98 Raw
1786 lines · plain
1; REQUIRES: asserts2; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling,bulk-memory | FileCheck %s3; RUN: llc < %s -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling,bulk-memory4; RUN: llc < %s -O0 -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -verify-machineinstrs -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling,-bulk-memory,-bulk-memory-opt | FileCheck %s --check-prefix=NOOPT5; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling,-bulk-memory,-bulk-memory-opt -wasm-disable-ehpad-sort -stats 2>&1 | FileCheck %s --check-prefix=NOSORT6; RUN: llc < %s -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling,-bulk-memory,-bulk-memory-opt -wasm-disable-ehpad-sort | FileCheck %s --check-prefix=NOSORT-LOCALS7 8target triple = "wasm32-unknown-unknown"9 10@_ZTIi = external constant ptr11@_ZTId = external constant ptr12 13%class.Object = type { i8 }14%class.MyClass = type { i32 }15 16; Simple test case with two catch clauses17;18; void foo();19; void two_catches() {20;   try {21;     foo();22;   } catch (int) {23;   } catch (double) {24;   }25; }26 27; CHECK-LABEL: two_catches:28; CHECK: try29; CHECK:   call      foo30; CHECK: catch31; CHECK:   block32; CHECK:     br_if     0, {{.*}}                       # 0: down to label[[L0:[0-9]+]]33; CHECK:     call      $drop=, __cxa_begin_catch34; CHECK:     call      __cxa_end_catch35; CHECK:     br        1                               # 1: down to label[[L1:[0-9]+]]36; CHECK:   end_block                                   # label[[L0]]:37; CHECK:   block38; CHECK:     br_if     0, {{.*}}                       # 0: down to label[[L2:[0-9]+]]39; CHECK:     call      $drop=, __cxa_begin_catch40; CHECK:     call      __cxa_end_catch41; CHECK:     br        1                               # 1: down to label[[L1]]42; CHECK:   end_block                                   # label[[L2]]:43; CHECK:   rethrow   0                                 # to caller44; CHECK: end_try                                       # label[[L1]]:45define void @two_catches() personality ptr @__gxx_wasm_personality_v0 {46entry:47  invoke void @foo()48          to label %try.cont unwind label %catch.dispatch49 50catch.dispatch:                                   ; preds = %entry51  %0 = catchswitch within none [label %catch.start] unwind to caller52 53catch.start:                                      ; preds = %catch.dispatch54  %1 = catchpad within %0 [ptr @_ZTIi, ptr @_ZTId]55  %2 = call ptr @llvm.wasm.get.exception(token %1)56  %3 = call i32 @llvm.wasm.get.ehselector(token %1)57  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)58  %matches = icmp eq i32 %3, %459  br i1 %matches, label %catch2, label %catch.fallthrough60 61catch2:                                           ; preds = %catch.start62  %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]63  call void @__cxa_end_catch() [ "funclet"(token %1) ]64  catchret from %1 to label %try.cont65 66catch.fallthrough:                                ; preds = %catch.start67  %6 = call i32 @llvm.eh.typeid.for(ptr @_ZTId)68  %matches1 = icmp eq i32 %3, %669  br i1 %matches1, label %catch, label %rethrow70 71catch:                                            ; preds = %catch.fallthrough72  %7 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]73  call void @__cxa_end_catch() [ "funclet"(token %1) ]74  catchret from %1 to label %try.cont75 76rethrow:                                          ; preds = %catch.fallthrough77  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]78  unreachable79 80try.cont:                                         ; preds = %catch, %catch2, %entry81  ret void82}83 84; Nested try-catches within a catch85; void nested_catch() {86;   try {87;     foo();88;   } catch (int) {89;     try {90;       foo();91;     } catch (int) {92;       foo();93;     }94;   }95; }96 97; CHECK-LABEL: nested_catch:98; CHECK: try99; CHECK:   call  foo100; CHECK: catch101; CHECK:   block102; CHECK:     block103; CHECK:       br_if     0, {{.*}}                     # 0: down to label[[L0:[0-9+]]]104; CHECK:       call  $drop=, __cxa_begin_catch, $0105; CHECK:       try106; CHECK:         try107; CHECK:           call  foo108; CHECK:           br        3                         # 3: down to label[[L1:[0-9+]]]109; CHECK:         catch110; CHECK:           block111; CHECK:             block112; CHECK:               br_if     0, {{.*}}             # 0: down to label[[L2:[0-9+]]]113; CHECK:               call  $drop=, __cxa_begin_catch114; CHECK:               try115; CHECK:                 call  foo116; CHECK:                 br        2                   # 2: down to label[[L3:[0-9+]]]117; CHECK:               catch_all118; CHECK:                 call  __cxa_end_catch119; CHECK:                 rethrow   0                   # down to catch[[L4:[0-9+]]]120; CHECK:               end_try121; CHECK:             end_block                         # label[[L2]]:122; CHECK:             rethrow   1                       # down to catch[[L4]]123; CHECK:           end_block                           # label[[L3]]:124; CHECK:           call  __cxa_end_catch125; CHECK:           br        3                         # 3: down to label[[L1]]126; CHECK:         end_try127; CHECK:       catch_all                               # catch[[L4]]:128; CHECK:         call  __cxa_end_catch129; CHECK:         rethrow   0                           # to caller130; CHECK:       end_try131; CHECK:     end_block                                 # label[[L0]]:132; CHECK:     rethrow   1                               # to caller133; CHECK:   end_block                                   # label[[L1]]:134; CHECK:   call  __cxa_end_catch135; CHECK: end_try136define void @nested_catch() personality ptr @__gxx_wasm_personality_v0 {137entry:138  invoke void @foo()139          to label %try.cont11 unwind label %catch.dispatch140 141catch.dispatch:                                   ; preds = %entry142  %0 = catchswitch within none [label %catch.start] unwind to caller143 144catch.start:                                      ; preds = %catch.dispatch145  %1 = catchpad within %0 [ptr @_ZTIi]146  %2 = call ptr @llvm.wasm.get.exception(token %1)147  %3 = call i32 @llvm.wasm.get.ehselector(token %1)148  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)149  %matches = icmp eq i32 %3, %4150  br i1 %matches, label %catch, label %rethrow151 152catch:                                            ; preds = %catch.start153  %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]154  %6 = load i32, ptr %5, align 4155  invoke void @foo() [ "funclet"(token %1) ]156          to label %try.cont unwind label %catch.dispatch2157 158catch.dispatch2:                                  ; preds = %catch159  %7 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup9160 161catch.start3:                                     ; preds = %catch.dispatch2162  %8 = catchpad within %7 [ptr @_ZTIi]163  %9 = call ptr @llvm.wasm.get.exception(token %8)164  %10 = call i32 @llvm.wasm.get.ehselector(token %8)165  %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)166  %matches4 = icmp eq i32 %10, %11167  br i1 %matches4, label %catch6, label %rethrow5168 169catch6:                                           ; preds = %catch.start3170  %12 = call ptr @__cxa_begin_catch(ptr %9) [ "funclet"(token %8) ]171  %13 = load i32, ptr %12, align 4172  invoke void @foo() [ "funclet"(token %8) ]173          to label %invoke.cont8 unwind label %ehcleanup174 175invoke.cont8:                                     ; preds = %catch6176  call void @__cxa_end_catch() [ "funclet"(token %8) ]177  catchret from %8 to label %try.cont178 179rethrow5:                                         ; preds = %catch.start3180  invoke void @llvm.wasm.rethrow() [ "funclet"(token %8) ]181          to label %unreachable unwind label %ehcleanup9182 183try.cont:                                         ; preds = %invoke.cont8, %catch184  call void @__cxa_end_catch() [ "funclet"(token %1) ]185  catchret from %1 to label %try.cont11186 187rethrow:                                          ; preds = %catch.start188  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]189  unreachable190 191try.cont11:                                       ; preds = %try.cont, %entry192  ret void193 194ehcleanup:                                        ; preds = %catch6195  %14 = cleanuppad within %8 []196  call void @__cxa_end_catch() [ "funclet"(token %14) ]197  cleanupret from %14 unwind label %ehcleanup9198 199ehcleanup9:                                       ; preds = %ehcleanup, %rethrow5, %catch.dispatch2200  %15 = cleanuppad within %1 []201  call void @__cxa_end_catch() [ "funclet"(token %15) ]202  cleanupret from %15 unwind to caller203 204unreachable:                                      ; preds = %rethrow5205  unreachable206}207 208; Nested try-catches within a try209; void nested_try() {210;   try {211;     try {212;       foo();213;     } catch (...) {214;     }215;   } catch (...) {216;   }217; }218 219; CHECK-LABEL: nested_try:220; CHECK:   try221; CHECK:     try222; CHECK:       call  foo223; CHECK:     catch224; CHECK:       call  $drop=, __cxa_begin_catch225; CHECK:       call  __cxa_end_catch226; CHECK:     end_try227; CHECK:     catch228; CHECK:     call  $drop=, __cxa_begin_catch229; CHECK:     call  __cxa_end_catch230; CHECK:   end_try231define void @nested_try() personality ptr @__gxx_wasm_personality_v0 {232entry:233  invoke void @foo()234          to label %try.cont7 unwind label %catch.dispatch235 236catch.dispatch:                                   ; preds = %entry237  %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch2238 239catch.start:                                      ; preds = %catch.dispatch240  %1 = catchpad within %0 [ptr null]241  %2 = call ptr @llvm.wasm.get.exception(token %1)242  %3 = call i32 @llvm.wasm.get.ehselector(token %1)243  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]244  invoke void @__cxa_end_catch() [ "funclet"(token %1) ]245          to label %invoke.cont1 unwind label %catch.dispatch2246 247catch.dispatch2:                                  ; preds = %catch.start, %catch.dispatch248  %5 = catchswitch within none [label %catch.start3] unwind to caller249 250catch.start3:                                     ; preds = %catch.dispatch2251  %6 = catchpad within %5 [ptr null]252  %7 = call ptr @llvm.wasm.get.exception(token %6)253  %8 = call i32 @llvm.wasm.get.ehselector(token %6)254  %9 = call ptr @__cxa_begin_catch(ptr %7) [ "funclet"(token %6) ]255  call void @__cxa_end_catch() [ "funclet"(token %6) ]256  catchret from %6 to label %try.cont7257 258try.cont7:                                        ; preds = %entry, %invoke.cont1, %catch.start3259  ret void260 261invoke.cont1:                                     ; preds = %catch.start262  catchret from %1 to label %try.cont7263}264 265 266; CHECK-LABEL: loop_within_catch:267; CHECK: try268; CHECK:   call      foo269; CHECK: catch270; CHECK:   call      $drop=, __cxa_begin_catch271; CHECK:   loop                                        # label[[L0:[0-9]+]]:272; CHECK:     block273; CHECK:       block274; CHECK:         br_if     0, {{.*}}                   # 0: down to label[[L1:[0-9]+]]275; CHECK:         try276; CHECK:           call      foo277; CHECK:           br        2                         # 2: down to label[[L2:[0-9]+]]278; CHECK:         catch279; CHECK:           try280; CHECK:             call      __cxa_end_catch281; CHECK:           catch_all282; CHECK:             call      _ZSt9terminatev283; CHECK:             unreachable284; CHECK:           end_try285; CHECK:           rethrow   0                         # to caller286; CHECK:         end_try287; CHECK:       end_block                               # label[[L1]]:288; CHECK:       call      __cxa_end_catch289; CHECK:       br        2                             # 2: down to label[[L3:[0-9]+]]290; CHECK:     end_block                                 # label[[L2]]:291; CHECK:     br        0                               # 0: up to label[[L0]]292; CHECK:   end_loop293; CHECK: end_try                                       # label[[L3]]:294define void @loop_within_catch() personality ptr @__gxx_wasm_personality_v0 {295entry:296  invoke void @foo()297          to label %try.cont unwind label %catch.dispatch298 299catch.dispatch:                                   ; preds = %entry300  %0 = catchswitch within none [label %catch.start] unwind to caller301 302catch.start:                                      ; preds = %catch.dispatch303  %1 = catchpad within %0 [ptr null]304  %2 = call ptr @llvm.wasm.get.exception(token %1)305  %3 = call i32 @llvm.wasm.get.ehselector(token %1)306  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]307  br label %for.cond308 309for.cond:                                         ; preds = %for.inc, %catch.start310  %i.0 = phi i32 [ 0, %catch.start ], [ %inc, %for.inc ]311  %cmp = icmp slt i32 %i.0, 50312  br i1 %cmp, label %for.body, label %for.end313 314for.body:                                         ; preds = %for.cond315  invoke void @foo() [ "funclet"(token %1) ]316          to label %for.inc unwind label %ehcleanup317 318for.inc:                                          ; preds = %for.body319  %inc = add nsw i32 %i.0, 1320  br label %for.cond321 322for.end:                                          ; preds = %for.cond323  call void @__cxa_end_catch() [ "funclet"(token %1) ]324  catchret from %1 to label %try.cont325 326try.cont:                                         ; preds = %for.end, %entry327  ret void328 329ehcleanup:                                        ; preds = %for.body330  %5 = cleanuppad within %1 []331  invoke void @__cxa_end_catch() [ "funclet"(token %5) ]332          to label %invoke.cont2 unwind label %terminate333 334invoke.cont2:                                     ; preds = %ehcleanup335  cleanupret from %5 unwind to caller336 337terminate:                                        ; preds = %ehcleanup338  %6 = cleanuppad within %5 []339  call void @_ZSt9terminatev() [ "funclet"(token %6) ]340  unreachable341}342 343; Tests if block and try markers are correctly placed. Even if two predecessors344; of the EH pad are bb2 and bb3 and their nearest common dominator is bb1, the345; TRY marker should be placed at bb0 because there's a branch from bb0 to bb2,346; and scopes cannot be interleaved.347 348; NOOPT-LABEL: block_try_markers:349; NOOPT: try350; NOOPT:   block351; NOOPT:     block352; NOOPT:       block353; NOOPT:       end_block354; NOOPT:     end_block355; NOOPT:     call      foo356; NOOPT:   end_block357; NOOPT:   call      bar358; NOOPT: catch     {{.*}}359; NOOPT: end_try360define void @block_try_markers() personality ptr @__gxx_wasm_personality_v0 {361bb0:362  br i1 undef, label %bb1, label %bb2363 364bb1:                                              ; preds = %bb0365  br i1 undef, label %bb3, label %bb4366 367bb2:                                              ; preds = %bb0368  br label %try.cont369 370bb3:                                              ; preds = %bb1371  invoke void @foo()372          to label %try.cont unwind label %catch.dispatch373 374bb4:                                              ; preds = %bb1375  invoke void @bar()376          to label %try.cont unwind label %catch.dispatch377 378catch.dispatch:                                   ; preds = %bb4, %bb3379  %0 = catchswitch within none [label %catch.start] unwind to caller380 381catch.start:                                      ; preds = %catch.dispatch382  %1 = catchpad within %0 [ptr null]383  %2 = call ptr @llvm.wasm.get.exception(token %1)384  %3 = call i32 @llvm.wasm.get.ehselector(token %1)385  catchret from %1 to label %try.cont386 387try.cont:                                         ; preds = %catch.start, %bb4, %bb3, %bb2388  ret void389}390 391; Tests if try/end_try markers are placed correctly wrt loop/end_loop markers,392; when try and loop markers are in the same BB and end_try and end_loop are in393; another BB.394; CHECK-LABEL: loop_try_markers:395; CHECK: loop396; CHECK:   try397; CHECK:     call      foo398; CHECK:   catch399; CHECK:   end_try400; CHECK: end_loop401define void @loop_try_markers(ptr %p) personality ptr @__gxx_wasm_personality_v0 {402entry:403  store volatile i32 0, ptr %p404  br label %loop405 406loop:                                             ; preds = %try.cont, %entry407  store volatile i32 1, ptr %p408  invoke void @foo()409          to label %try.cont unwind label %catch.dispatch410 411catch.dispatch:                                   ; preds = %loop412  %0 = catchswitch within none [label %catch.start] unwind to caller413 414catch.start:                                      ; preds = %catch.dispatch415  %1 = catchpad within %0 [ptr null]416  %2 = call ptr @llvm.wasm.get.exception(token %1)417  %3 = call i32 @llvm.wasm.get.ehselector(token %1)418  catchret from %1 to label %try.cont419 420try.cont:                                         ; preds = %catch.start, %loop421  br label %loop422}423 424; Some of test cases below are hand-tweaked by deleting some library calls to425; simplify tests and changing the order of basic blocks to cause unwind426; destination mismatches. And we use -wasm-disable-ehpad-sort to create maximum427; number of mismatches in several tests below.428 429; - Call unwind mismatch430; 'call bar''s original unwind destination was 'C0', but after control flow431; linearization, its unwind destination incorrectly becomes 'C1'. We fix this by432; wrapping the call with a nested try-delegate that targets 'C0'.433; - Catch unwind mismatch434; If 'call foo' throws a foreign exception, it will not be caught by C1, and435; should be rethrown to the caller. But after control flow linearization, it436; will instead unwind to C0, an incorrect next EH pad. We wrap the whole437; try-catch with try-delegate that rethrows the exception to the caller to fix438; this.439 440; NOSORT-LABEL: unwind_mismatches_0:441; NOSORT: try442; --- try-delegate starts (catch unwind mismatch)443; NOSORT    try444; NOSORT:     try445; NOSORT:       call  foo446; --- try-delegate starts (call unwind mismatch)447; NOSORT:       try448; NOSORT:         call  bar449; NOSORT:       delegate    2     # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]450; --- try-delegate ends (call unwind mismatch)451; NOSORT:     catch   {{.*}}      # catch[[C1:[0-9]+]]:452; NOSORT:     end_try453; NOSORT:   delegate    1         # label/catch{{[0-9]+}}: to caller454; --- try-delegate ends (catch unwind mismatch)455; NOSORT: catch   {{.*}}          # catch[[C0]]:456; NOSORT: end_try457; NOSORT: return458define void @unwind_mismatches_0() personality ptr @__gxx_wasm_personality_v0 {459bb0:460  invoke void @foo()461          to label %bb1 unwind label %catch.dispatch0462 463bb1:                                              ; preds = %bb0464  invoke void @bar()465          to label %try.cont unwind label %catch.dispatch1466 467catch.dispatch0:                                  ; preds = %bb0468  %0 = catchswitch within none [label %catch.start0] unwind to caller469 470catch.start0:                                     ; preds = %catch.dispatch0471  %1 = catchpad within %0 [ptr null]472  %2 = call ptr @llvm.wasm.get.exception(token %1)473  %3 = call i32 @llvm.wasm.get.ehselector(token %1)474  catchret from %1 to label %try.cont475 476catch.dispatch1:                                  ; preds = %bb1477  %4 = catchswitch within none [label %catch.start1] unwind to caller478 479catch.start1:                                     ; preds = %catch.dispatch1480  %5 = catchpad within %4 [ptr null]481  %6 = call ptr @llvm.wasm.get.exception(token %5)482  %7 = call i32 @llvm.wasm.get.ehselector(token %5)483  catchret from %5 to label %try.cont484 485try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1486  ret void487}488 489; 'call bar' and 'call baz''s original unwind destination was the caller, but490; after control flow linearization, their unwind destination incorrectly becomes491; 'C0'. We fix this by wrapping the calls with a nested try-delegate that492; rethrows the exception to the caller.493 494; And the return value of 'baz' should NOT be stackified because the BB is split495; during fixing unwind mismatches.496 497; NOSORT-LABEL: unwind_mismatches_1:498; NOSORT: try499; NOSORT:   call  foo500; --- try-delegate starts (call unwind mismatch)501; NOSORT:   try502; NOSORT:     call  bar503; NOSORT:     call  $[[RET:[0-9]+]]=, baz504; NOSORT-NOT: call  $push{{.*}}=, baz505; NOSORT:   delegate    1                     # label/catch{{[0-9]+}}: to caller506; --- try-delegate ends (call unwind mismatch)507; NOSORT:   call  nothrow, $[[RET]]508; NOSORT:   return509; NOSORT: catch   {{.*}}                      # catch[[C0:[0-9]+]]:510; NOSORT:   return511; NOSORT: end_try512define void @unwind_mismatches_1() personality ptr @__gxx_wasm_personality_v0 {513bb0:514  invoke void @foo()515          to label %bb1 unwind label %catch.dispatch0516 517bb1:                                              ; preds = %bb0518  call void @bar()519  %call = call i32 @baz()520  call void @nothrow(i32 %call) #0521  ret void522 523catch.dispatch0:                                  ; preds = %bb0524  %0 = catchswitch within none [label %catch.start0] unwind to caller525 526catch.start0:                                     ; preds = %catch.dispatch0527  %1 = catchpad within %0 [ptr null]528  %2 = call ptr @llvm.wasm.get.exception(token %1)529  %3 = call i32 @llvm.wasm.get.ehselector(token %1)530  catchret from %1 to label %try.cont531 532try.cont:                                         ; preds = %catch.start0533  ret void534}535 536; The same as unwind_mismatches_0, but we have one more call 'call @foo' in bb1537; which unwinds to the caller. IN this case bb1 has two call unwind mismatches:538; 'call @foo' unwinds to the caller and 'call @bar' unwinds to catch C0.539 540; NOSORT-LABEL: unwind_mismatches_2:541; NOSORT: try542; --- try-delegate starts (catch unwind mismatch)543; NOSORT    try544; NOSORT:     try545; NOSORT:       call  foo546; --- try-delegate starts (call unwind mismatch)547; NOSORT:       try548; NOSORT:         call  foo549; NOSORT:       delegate    3     # label/catch{{[0-9]+}}: to caller550; --- try-delegate ends (call unwind mismatch)551; --- try-delegate starts (call unwind mismatch)552; NOSORT:       try553; NOSORT:         call  bar554; NOSORT:       delegate    2     # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]555; --- try-delegate ends (call unwind mismatch)556; NOSORT:     catch   {{.*}}      # catch[[C1:[0-9]+]]:557; NOSORT:     end_try558; NOSORT:   delegate    1         # label/catch{{[0-9]+}}: to caller559; --- try-delegate ends (catch unwind mismatch)560; NOSORT: catch   {{.*}}        # catch[[C0]]:561; NOSORT: end_try562; NOSORT: return563define void @unwind_mismatches_2() personality ptr @__gxx_wasm_personality_v0 {564bb0:565  invoke void @foo()566          to label %bb1 unwind label %catch.dispatch0567 568bb1:                                              ; preds = %bb0569  call void @foo()570  invoke void @bar()571          to label %try.cont unwind label %catch.dispatch1572 573catch.dispatch0:                                  ; preds = %bb0574  %0 = catchswitch within none [label %catch.start0] unwind to caller575 576catch.start0:                                     ; preds = %catch.dispatch0577  %1 = catchpad within %0 [ptr null]578  %2 = call ptr @llvm.wasm.get.exception(token %1)579  %3 = call i32 @llvm.wasm.get.ehselector(token %1)580  catchret from %1 to label %try.cont581 582catch.dispatch1:                                  ; preds = %bb1583  %4 = catchswitch within none [label %catch.start1] unwind to caller584 585catch.start1:                                     ; preds = %catch.dispatch1586  %5 = catchpad within %4 [ptr null]587  %6 = call ptr @llvm.wasm.get.exception(token %5)588  %7 = call i32 @llvm.wasm.get.ehselector(token %5)589  catchret from %5 to label %try.cont590 591try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1592  ret void593}594 595; Similar situation as @unwind_mismatches_1. Here 'call @qux''s original unwind596; destination was the caller, but after control flow linearization, their unwind597; destination incorrectly becomes 'C0' within the function. We fix this by598; wrapping the call with a nested try-delegate that rethrows the exception to599; the caller.600 601; Because 'call @qux' pops an argument pushed by 'i32.const 5' from stack, the602; nested 'try' should be placed before `i32.const 5', not between 'i32.const 5'603; and 'call @qux'.604 605; NOSORT-LABEL: unwind_mismatches_3:606; NOSORT: try       i32607; NOSORT:   call  foo608; --- try-delegate starts (call unwind mismatch)609; NOSORT:   try610; NOSORT:     i32.const  $push{{[0-9]+}}=, 5611; NOSORT:     call  ${{[0-9]+}}=, qux612; NOSORT:   delegate    1                     # label/catch{{[0-9]+}}: to caller613; --- try-delegate ends (call unwind mismatch)614; NOSORT:   return615; NOSORT: catch   {{.*}}                      # catch[[C0:[0-9]+]]:616; NOSORT:   return617; NOSORT: end_try618define i32 @unwind_mismatches_3() personality ptr @__gxx_wasm_personality_v0 {619bb0:620  invoke void @foo()621          to label %bb1 unwind label %catch.dispatch0622 623bb1:                                              ; preds = %bb0624  %0 = call i32 @qux(i32 5)625  ret i32 %0626 627catch.dispatch0:                                  ; preds = %bb0628  %1 = catchswitch within none [label %catch.start0] unwind to caller629 630catch.start0:                                     ; preds = %catch.dispatch0631  %2 = catchpad within %1 [ptr null]632  %3 = call ptr @llvm.wasm.get.exception(token %2)633  %j = call i32 @llvm.wasm.get.ehselector(token %2)634  catchret from %2 to label %try.cont635 636try.cont:                                         ; preds = %catch.start0637  ret i32 0638}639 640; We have two call unwind unwind mismatches:641; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the642;   CFG, when it is supposed to unwind to another EH pad.643; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the644;   CFG, when it is supposed to unwind to the caller.645; We also have a catch unwind mismatch: If an exception is not caught by the646; first catch because it is a non-C++ exception, it shouldn't unwind to the next647; catch, but it should unwind to the caller.648 649; NOSORT-LABEL: unwind_mismatches_4:650; NOSORT: try651; --- try-delegate starts (catch unwind mismatch)652; NOSORT:   try653; NOSORT:     try654; NOSORT:       call  foo655; --- try-delegate starts (call unwind mismatch)656; NOSORT:       try657; NOSORT:         call  bar658; NOSORT:       delegate    2            # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]659; --- try-delegate ends (call unwind mismatch)660; NOSORT:     catch661; NOSORT:       call  {{.*}} __cxa_begin_catch662; --- try-delegate starts (call unwind mismatch)663; NOSORT:       try664; NOSORT:         call  __cxa_end_catch665; NOSORT:       delegate    3            # label/catch{{[0-9]+}}: to caller666; --- try-delegate ends (call unwind mismatch)667; NOSORT:     end_try668; NOSORT:   delegate    1                # label/catch{{[0-9]+}}: to caller669; --- try-delegate ends (catch unwind mismatch)670; NOSORT: catch  {{.*}}                  # catch[[C0]]:671; NOSORT:   call  {{.*}} __cxa_begin_catch672; NOSORT:   call  __cxa_end_catch673; NOSORT: end_try674; NOSORT: return675define void @unwind_mismatches_4() personality ptr @__gxx_wasm_personality_v0 {676bb0:677  invoke void @foo()678          to label %bb1 unwind label %catch.dispatch0679 680bb1:                                              ; preds = %bb0681  invoke void @bar()682          to label %try.cont unwind label %catch.dispatch1683 684catch.dispatch0:                                  ; preds = %bb0685  %0 = catchswitch within none [label %catch.start0] unwind to caller686 687catch.start0:                                     ; preds = %catch.dispatch0688  %1 = catchpad within %0 [ptr null]689  %2 = call ptr @llvm.wasm.get.exception(token %1)690  %3 = call i32 @llvm.wasm.get.ehselector(token %1)691  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]692  call void @__cxa_end_catch() [ "funclet"(token %1) ]693  catchret from %1 to label %try.cont694 695catch.dispatch1:                                  ; preds = %bb1696  %5 = catchswitch within none [label %catch.start1] unwind to caller697 698catch.start1:                                     ; preds = %catch.dispatch1699  %6 = catchpad within %5 [ptr null]700  %7 = call ptr @llvm.wasm.get.exception(token %6)701  %8 = call i32 @llvm.wasm.get.ehselector(token %6)702  %9 = call ptr @__cxa_begin_catch(ptr %7) [ "funclet"(token %6) ]703  call void @__cxa_end_catch() [ "funclet"(token %6) ]704  catchret from %6 to label %try.cont705 706try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1707  ret void708}709 710; This crashed when updating EHPadStack within fixCallUniwindMismatch had a bug.711; This should not crash and try-delegate has to be created around 'call @baz',712; because the initial TRY placement for 'call @quux' was done before 'call @baz'713; because 'call @baz''s return value is stackified.714 715; CHECK-LABEL: unwind_mismatches_5:716; CHECK: try717; --- try-delegate starts (call unwind mismatch)718; CHECK:   try719; CHECK:     call $[[RET:[0-9]+]]=, baz720; CHECK:   delegate  1721; --- try-delegate ends (call unwind mismatch)722; CHECK:    call  quux, $[[RET]]723; CHECK: catch_all724; CHECK: end_try725define void @unwind_mismatches_5() personality ptr @__gxx_wasm_personality_v0 {726entry:727  %call = call i32 @baz()728  invoke void @quux(i32 %call)729          to label %invoke.cont unwind label %ehcleanup730 731ehcleanup:                                        ; preds = %entry732  %0 = cleanuppad within none []733  cleanupret from %0 unwind to caller734 735invoke.cont:                                      ; preds = %entry736  unreachable737}738 739; The structure is similar to unwind_mismatches_0, where the call to 'bar''s740; original unwind destination is catch.dispatch1 but after placing markers it741; unwinds to catch.dispatch0, which we fix. This additionally has a loop before742; the real unwind destination (catch.dispatch1).743 744; NOSORT-LABEL: unwind_mismatches_with_loop:745; NOSORT: try746; NOSORT:   try747; NOSORT:     try748; NOSORT:       call  foo749; NOSORT:       try750; NOSORT:         call  bar751; NOSORT:       delegate    3                  # label/catch{{[0-9]+}}: down to catch[[C0:[0-9]+]]752; NOSORT:     catch  $drop=, __cpp_exception753; NOSORT:     end_try754; NOSORT:   delegate    2                      # label/catch{{[0-9]+}}: to caller755; NOSORT:   loop756; NOSORT:     call  foo757; NOSORT:   end_loop758; NOSORT: catch  $drop=, __cpp_exception       # catch[[C0]]:759; NOSORT:   return760; NOSORT: end_try761define void @unwind_mismatches_with_loop() personality ptr @__gxx_wasm_personality_v0 {762bb0:763  invoke void @foo()764          to label %bb1 unwind label %catch.dispatch0765 766bb1:                                              ; preds = %bb0767  invoke void @bar()768          to label %bb2 unwind label %catch.dispatch1769 770catch.dispatch0:                                  ; preds = %bb0771  %0 = catchswitch within none [label %catch.start0] unwind to caller772 773catch.start0:                                     ; preds = %catch.dispatch0774  %1 = catchpad within %0 [ptr null]775  %2 = call ptr @llvm.wasm.get.exception(token %1)776  %3 = call i32 @llvm.wasm.get.ehselector(token %1)777  catchret from %1 to label %bb2778 779bb2:780  invoke void @foo()781          to label %bb3 unwind label %catch.dispatch1782 783bb3:                                             ; preds = %bb14784  br label %bb2785 786catch.dispatch1:                                  ; preds = %bb1787  %4 = catchswitch within none [label %catch.start1] unwind to caller788 789catch.start1:                                     ; preds = %catch.dispatch1790  %5 = catchpad within %4 [ptr null]791  %6 = call ptr @llvm.wasm.get.exception(token %5)792  %7 = call i32 @llvm.wasm.get.ehselector(token %5)793  catchret from %5 to label %try.cont794 795try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1796  ret void797}798 799; Tests the case when TEE stackifies a register in RegStackify but it gets800; unstackified in fixCallUnwindMismatches in CFGStackify.801 802; NOSORT-LOCALS-LABEL: unstackify_when_fixing_unwind_mismatch:803define void @unstackify_when_fixing_unwind_mismatch(i32 %x) personality ptr @__gxx_wasm_personality_v0 {804bb0:805  invoke void @foo()806          to label %bb1 unwind label %catch.dispatch0807 808bb1:                                              ; preds = %bb0809  %t = add i32 %x, 4810  ; This %addr is used in multiple places, so tee is introduced in RegStackify,811  ; which stackifies the use of %addr in store instruction. A tee has two dest812  ; registers, the first of which is stackified and the second is not.813  ; But when we introduce a nested try-delegate in fixCallUnwindMismatches in814  ; CFGStackify, we end up unstackifying the first dest register. In that case,815  ; we convert that tee into a copy.816  %addr = inttoptr i32 %t to ptr817  %load = load i32, ptr %addr818  %call = call i32 @baz()819  %add = add i32 %load, %call820  store i32 %add, ptr %addr821  ret void822; NOSORT-LOCALS:       i32.add823; NOSORT-LOCALS-NOT:   local.tee824; NOSORT-LOCALS-NEXT:  local.set825 826catch.dispatch0:                                  ; preds = %bb0827  %0 = catchswitch within none [label %catch.start0] unwind to caller828 829catch.start0:                                     ; preds = %catch.dispatch0830  %1 = catchpad within %0 [ptr null]831  %2 = call ptr @llvm.wasm.get.exception(token %1)832  %3 = call i32 @llvm.wasm.get.ehselector(token %1)833  catchret from %1 to label %try.cont834 835try.cont:                                         ; preds = %catch.start0836  ret void837}838 839; In CFGSort, EH pads should be sorted as soon as it is available and840; 'Preferred' queue and should NOT be entered into 'Ready' queue unless we are841; in the middle of sorting another region that does not contain the EH pad. In842; this example, 'catch.start' should be sorted right after 'if.then' is sorted843; (before 'cont' is sorted) and there should not be any unwind destination844; mismatches in CFGStackify.845 846; NOOPT-LABEL: cfg_sort_order:847; NOOPT: block848; NOOPT:   try849; NOOPT:     call      foo850; NOOPT:   catch851; NOOPT:   end_try852; NOOPT:   call      foo853; NOOPT: end_block854; NOOPT: return855define void @cfg_sort_order(i32 %arg) personality ptr @__gxx_wasm_personality_v0 {856entry:857  %tobool = icmp ne i32 %arg, 0858  br i1 %tobool, label %if.then, label %if.end859 860catch.dispatch:                                   ; preds = %if.then861  %0 = catchswitch within none [label %catch.start] unwind to caller862 863catch.start:                                      ; preds = %catch.dispatch864  %1 = catchpad within %0 [ptr null]865  %2 = call ptr @llvm.wasm.get.exception(token %1)866  %3 = call i32 @llvm.wasm.get.ehselector(token %1)867  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]868  call void @__cxa_end_catch() [ "funclet"(token %1) ]869  catchret from %1 to label %if.end870 871if.then:                                          ; preds = %entry872  invoke void @foo()873          to label %cont unwind label %catch.dispatch874 875cont:                                             ; preds = %if.then876  call void @foo()877  br label %if.end878 879if.end:                                           ; preds = %cont, %catch.start, %entry880  ret void881}882 883; Intrinsics like memcpy, memmove, and memset don't throw and are lowered into884; calls to external symbols (not global addresses) in instruction selection,885; which will be eventually lowered to library function calls.886; Because this test runs with -wasm-disable-ehpad-sort, these library calls in887; invoke.cont BB fall within try~end_try, but they shouldn't cause crashes or888; unwinding destination mismatches in CFGStackify.889 890; NOSORT-LABEL: mem_intrinsics:891; NOSORT: try892; NOSORT:   call  foo893; NOSORT:   call {{.*}} memcpy894; NOSORT:   call {{.*}} memmove895; NOSORT:   call {{.*}} memset896; NOSORT:   return897; NOSORT: catch_all898; NOSORT:   rethrow 0899; NOSORT: end_try900define void @mem_intrinsics(ptr %a, ptr %b) personality ptr @__gxx_wasm_personality_v0 {901entry:902  %o = alloca %class.Object, align 1903  invoke void @foo()904          to label %invoke.cont unwind label %ehcleanup905 906invoke.cont:                                      ; preds = %entry907  call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %b, i32 100, i1 false)908  call void @llvm.memmove.p0.p0.i32(ptr %a, ptr %b, i32 100, i1 false)909  call void @llvm.memset.p0.i32(ptr %a, i8 0, i32 100, i1 false)910  %call = call ptr @_ZN6ObjectD2Ev(ptr %o)911  ret void912 913ehcleanup:                                        ; preds = %entry914  %0 = cleanuppad within none []915  %call2 = call ptr @_ZN6ObjectD2Ev(ptr %o) [ "funclet"(token %0) ]916  cleanupret from %0 unwind to caller917}918 919; Tests if 'try' marker is placed correctly. In this test, 'try' should be920; placed before the call to 'nothrow_i32' and not between the call to921; 'nothrow_i32' and 'fun', because the return value of 'nothrow_i32' is922; stackified and pushed onto the stack to be consumed by the call to 'fun'.923 924; CHECK-LABEL: try_marker_with_stackified_input:925; CHECK: try926; CHECK: call      $push{{.*}}=, nothrow_i32927; CHECK: call      fun, $pop{{.*}}928define void @try_marker_with_stackified_input() personality ptr @__gxx_wasm_personality_v0 {929entry:930  %call = call i32 @nothrow_i32()931  invoke void @fun(i32 %call)932          to label %invoke.cont unwind label %terminate933 934invoke.cont:                                      ; preds = %entry935  ret void936 937terminate:                                        ; preds = %entry938  %0 = cleanuppad within none []939  call void @_ZSt9terminatev() [ "funclet"(token %0) ]940  unreachable941}942 943; This crashed on debug mode (= when NDEBUG is not defined) when the logic for944; computing the innermost region was not correct, in which a loop region945; contains an exception region. This should pass CFGSort without crashing.946define void @loop_exception_region() personality ptr @__gxx_wasm_personality_v0 {947entry:948  %e = alloca %class.MyClass, align 4949  br label %for.cond950 951for.cond:                                         ; preds = %for.inc, %entry952  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]953  %cmp = icmp slt i32 %i.0, 9954  br i1 %cmp, label %for.body, label %for.end955 956for.body:                                         ; preds = %for.cond957  invoke void @quux(i32 %i.0)958          to label %for.inc unwind label %catch.dispatch959 960catch.dispatch:                                   ; preds = %for.body961  %0 = catchswitch within none [label %catch.start] unwind to caller962 963catch.start:                                      ; preds = %catch.dispatch964  %1 = catchpad within %0 [ptr @_ZTI7MyClass]965  %2 = call ptr @llvm.wasm.get.exception(token %1)966  %3 = call i32 @llvm.wasm.get.ehselector(token %1)967  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTI7MyClass)968  %matches = icmp eq i32 %3, %4969  br i1 %matches, label %catch, label %rethrow970 971catch:                                            ; preds = %catch.start972  %5 = call ptr @__cxa_get_exception_ptr(ptr %2) [ "funclet"(token %1) ]973  %call = call ptr @_ZN7MyClassC2ERKS_(ptr %e, ptr dereferenceable(4) %5) [ "funclet"(token %1) ]974  %6 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]975  %7 = load i32, ptr %e, align 4976  invoke void @quux(i32 %7) [ "funclet"(token %1) ]977          to label %invoke.cont2 unwind label %ehcleanup978 979invoke.cont2:                                     ; preds = %catch980  %call3 = call ptr @_ZN7MyClassD2Ev(ptr %e) [ "funclet"(token %1) ]981  call void @__cxa_end_catch() [ "funclet"(token %1) ]982  catchret from %1 to label %for.inc983 984rethrow:                                          ; preds = %catch.start985  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]986  unreachable987 988for.inc:                                          ; preds = %invoke.cont2, %for.body989  %inc = add nsw i32 %i.0, 1990  br label %for.cond991 992ehcleanup:                                        ; preds = %catch993  %8 = cleanuppad within %1 []994  %call4 = call ptr @_ZN7MyClassD2Ev(ptr %e) [ "funclet"(token %8) ]995  invoke void @__cxa_end_catch() [ "funclet"(token %8) ]996          to label %invoke.cont6 unwind label %terminate7997 998invoke.cont6:                                     ; preds = %ehcleanup999  cleanupret from %8 unwind to caller1000 1001for.end:                                          ; preds = %for.cond1002  ret void1003 1004terminate7:                                       ; preds = %ehcleanup1005  %9 = cleanuppad within %8 []1006  call void @_ZSt9terminatev() [ "funclet"(token %9) ]1007  unreachable1008}1009 1010; Tests if CFGStackify's removeUnnecessaryInstrs() removes unnecessary branches1011; correctly. The code is in the form below, where 'br' is unnecessary because1012; after running the 'try' body the control flow will fall through to bb2 anyway.1013 1014; bb0:1015;   try1016;     ...1017;     br bb2      <- Not necessary1018; bb1 (ehpad):1019;   catch1020;     ...1021; bb2:            <- Continuation BB1022;   end1023; CHECK-LABEL: remove_unnecessary_instrs:1024define void @remove_unnecessary_instrs(i32 %n) personality ptr @__gxx_wasm_personality_v0 {1025entry:1026  invoke void @foo()1027          to label %for.body unwind label %catch.dispatch1028 1029for.body:                                         ; preds = %for.end, %entry1030  %i = phi i32 [ %inc, %for.end ], [ 0, %entry ]1031  invoke void @foo()1032          to label %for.end unwind label %catch.dispatch1033 1034; Before going to CFGStackify, this BB will have a conditional branch followed1035; by an unconditional branch. CFGStackify should remove only the unconditional1036; one.1037for.end:                                          ; preds = %for.body1038  %inc = add nuw nsw i32 %i, 11039  %exitcond = icmp eq i32 %inc, %n1040  br i1 %exitcond, label %try.cont, label %for.body1041; CHECK: br_if1042; CHECK-NOT: br1043; CHECK: end_loop1044; CHECK: catch1045 1046catch.dispatch:                                   ; preds = %for.body, %entry1047  %0 = catchswitch within none [label %catch.start] unwind to caller1048 1049catch.start:                                      ; preds = %catch.dispatch1050  %1 = catchpad within %0 [ptr null]1051  %2 = call ptr @llvm.wasm.get.exception(token %1)1052  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1053  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]1054  call void @__cxa_end_catch() [ "funclet"(token %1) ]1055  catchret from %1 to label %try.cont1056 1057try.cont:                                         ; preds = %catch.start, %for.end1058  ret void1059}1060 1061; void foo();1062; void remove_unnecessary_br() {1063;   try {1064;     foo();1065;     try {1066;       foo();1067;     } catch (...) {1068;     }1069;   } catch (...) {1070;   }1071; }1072;1073; This tests whether the 'br' can be removed in code in the form as follows.1074; Here 'br' is inside an inner try, whose 'end' is in another EH pad. In this1075; case, after running an inner try body, the control flow should fall through to1076; bb3, so the 'br' in the code is unnecessary.1077 1078; bb0:1079;   try1080;     try1081;       ...1082;       br bb3      <- Not necessary1083; bb1:1084;     catch1085; bb2:1086;     end_try1087;   catch1088;     ...1089; bb3:            <- Continuation BB1090;   end1091;1092; CHECK-LABEL: remove_unnecessary_br:1093define void @remove_unnecessary_br() personality ptr @__gxx_wasm_personality_v0 {1094; CHECK: call foo1095entry:1096  invoke void @foo()1097          to label %invoke.cont unwind label %catch.dispatch31098 1099; CHECK: call foo1100; CHECK-NOT: br1101invoke.cont:                                      ; preds = %entry1102  invoke void @foo()1103          to label %try.cont8 unwind label %catch.dispatch1104 1105catch.dispatch:                                   ; preds = %invoke.cont1106  %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch31107 1108; CHECK: catch1109catch.start:                                      ; preds = %catch.dispatch1110  %1 = catchpad within %0 [ptr null]1111  %2 = call ptr @llvm.wasm.get.exception(token %1)1112  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1113  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]1114  invoke void @__cxa_end_catch() [ "funclet"(token %1) ]1115          to label %invoke.cont2 unwind label %catch.dispatch31116 1117catch.dispatch3:                                  ; preds = %catch.start, %catch.dispatch, %entry1118  %5 = catchswitch within none [label %catch.start4] unwind to caller1119 1120catch.start4:                                     ; preds = %catch.dispatch31121  %6 = catchpad within %5 [ptr null]1122  %7 = call ptr @llvm.wasm.get.exception(token %6)1123  %8 = call i32 @llvm.wasm.get.ehselector(token %6)1124  %9 = call ptr @__cxa_begin_catch(ptr %7) [ "funclet"(token %6) ]1125  call void @__cxa_end_catch() [ "funclet"(token %6) ]1126  catchret from %6 to label %try.cont81127 1128try.cont8:                                        ; preds = %invoke.cont2, %catch.start4, %invoke.cont1129  ret void1130 1131invoke.cont2:                                     ; preds = %catch.start1132  catchret from %1 to label %try.cont81133}1134 1135; Here an exception is semantically contained in a loop. 'ehcleanup' BB belongs1136; to the exception, but does not belong to the loop (because it does not have a1137; path back to the loop header), and is placed after the loop latch block1138; 'invoke.cont' intentionally. This tests if 'end_loop' marker is placed1139; correctly not right after 'invoke.cont' part but after 'ehcleanup' part.1140; NOSORT-LABEL: loop_contains_exception:1141; NOSORT: loop1142; NOSORT:   try1143; NOSORT:     try1144; NOSORT:     end_try1145; NOSORT:   end_try1146; NOSORT: end_loop1147define void @loop_contains_exception(i32 %n) personality ptr @__gxx_wasm_personality_v0 {1148entry:1149  br label %while.cond1150 1151while.cond:                                       ; preds = %invoke.cont, %entry1152  %n.addr.0 = phi i32 [ %n, %entry ], [ %dec, %invoke.cont ]1153  %tobool = icmp ne i32 %n.addr.0, 01154  br i1 %tobool, label %while.body, label %while.end1155 1156while.body:                                       ; preds = %while.cond1157  %dec = add nsw i32 %n.addr.0, -11158  invoke void @foo()1159          to label %while.end unwind label %catch.dispatch1160 1161catch.dispatch:                                   ; preds = %while.body1162  %0 = catchswitch within none [label %catch.start] unwind to caller1163 1164catch.start:                                      ; preds = %catch.dispatch1165  %1 = catchpad within %0 [ptr null]1166  %2 = call ptr @llvm.wasm.get.exception(token %1)1167  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1168  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]1169  invoke void @__cxa_end_catch() [ "funclet"(token %1) ]1170          to label %invoke.cont unwind label %ehcleanup1171 1172invoke.cont:                                      ; preds = %catch.start1173  catchret from %1 to label %while.cond1174 1175ehcleanup:                                        ; preds = %catch.start1176  %5 = cleanuppad within %1 []1177  call void @_ZSt9terminatev() [ "funclet"(token %5) ]1178  unreachable1179 1180while.end:                                        ; preds = %while.body, %while.cond1181  ret void1182}1183 1184; When the function return type is non-void and 'end' instructions are at the1185; very end of a function, CFGStackify's fixEndsAtEndOfFunction function fixes1186; the corresponding block/loop/try's type to match the function's return type.1187; But when a `try`'s type is fixed, we should also check `end` instructions1188; before its corresponding `catch_all`, because both `try` and `catch_all` body1189; should satisfy the return type requirements.1190 1191; NOSORT-LABEL: fix_function_end_return_type_with_try_catch:1192; NOSORT: try i321193; NOSORT: loop i321194; NOSORT: end_loop1195; NOSORT: catch_all1196; NOSORT: end_try1197; NOSORT-NEXT: end_function1198define i32 @fix_function_end_return_type_with_try_catch(i32 %n) personality ptr @__gxx_wasm_personality_v0 {1199entry:1200  %t = alloca %class.Object, align 11201  br label %for.cond1202 1203for.cond:                                         ; preds = %for.inc, %entry1204  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]1205  %cmp = icmp slt i32 %i.0, %n1206  br label %for.body1207 1208for.body:                                         ; preds = %for.cond1209  %div = sdiv i32 %n, 21210  %cmp1 = icmp eq i32 %i.0, %div1211  br i1 %cmp1, label %if.then, label %for.inc1212 1213if.then:                                          ; preds = %for.body1214  %call = invoke i32 @baz()1215          to label %invoke.cont unwind label %ehcleanup1216 1217invoke.cont:                                      ; preds = %if.then1218  %call2 = call ptr @_ZN6ObjectD2Ev(ptr %t)1219  ret i32 %call1220 1221for.inc:                                          ; preds = %for.body1222  %inc = add nsw i32 %i.0, 11223  br label %for.cond1224 1225ehcleanup:                                        ; preds = %if.then1226  %0 = cleanuppad within none []1227  %call3 = call ptr @_ZN6ObjectD2Ev(ptr %t) [ "funclet"(token %0) ]1228  cleanupret from %0 unwind to caller1229}1230 1231; This tests if invalidated branch destinations after fixing catch unwind1232; mismatches are correctly remapped. For example, we have this code and suppose1233; we need to wrap this try-catch-end in this code with a try-delegate to fix a1234; catch unwind mismatch:1235  ; - Before:1236; block1237;   br (a)1238;   try1239;   catch1240;   end_try1241; end_block1242;           <- (a)1243;1244; - After1245; block1246;   br (a)1247;   try1248;     try1249;     catch1250;     end_try1251;           <- (a)1252;   delegate1253; end_block1254;           <- (b)1255; After adding a try-delegate, the 'br's destination BB, where (a) points,1256; becomes invalid because it incorrectly branches into an inner scope. The1257; destination should change to the BB where (b) points.1258 1259; NOSORT-LABEL: branch_remapping_after_fixing_unwind_mismatches_0:1260; NOSORT: try1261; NOSORT:   br_if   01262define void @branch_remapping_after_fixing_unwind_mismatches_0(i1 %arg) personality ptr @__gxx_wasm_personality_v0 {1263entry:1264  br i1 %arg, label %bb0, label %dest1265 1266bb0:                                              ; preds = %entry1267  invoke void @foo()1268          to label %bb1 unwind label %catch.dispatch01269 1270bb1:                                              ; preds = %bb01271  invoke void @bar()1272          to label %try.cont unwind label %catch.dispatch11273 1274catch.dispatch0:                                  ; preds = %bb01275  %0 = catchswitch within none [label %catch.start0] unwind to caller1276 1277catch.start0:                                     ; preds = %catch.dispatch01278  %1 = catchpad within %0 [ptr null]1279  %2 = call ptr @llvm.wasm.get.exception(token %1)1280  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1281  catchret from %1 to label %try.cont1282 1283dest:                                             ; preds = %entry1284  ret void1285 1286catch.dispatch1:                                  ; preds = %bb11287  %4 = catchswitch within none [label %catch.start1] unwind to caller1288 1289catch.start1:                                     ; preds = %catch.dispatch11290  %5 = catchpad within %4 [ptr null]1291  %6 = call ptr @llvm.wasm.get.exception(token %5)1292  %7 = call i32 @llvm.wasm.get.ehselector(token %5)1293  catchret from %5 to label %try.cont1294 1295try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb11296  ret void1297}1298 1299; The similar case with branch_remapping_after_fixing_unwind_mismatches_0, but1300; multiple consecutive delegates are generated:1301; - Before:1302; block1303;   br (a)1304;   try1305;   catch1306;   end_try1307; end_block1308;           <- (a)1309;1310; - After1311; block1312;   br (a)1313;   try1314;     ...1315;     try1316;       try1317;       catch1318;       end_try1319;             <- (a)1320;     delegate1321;   delegate1322; end_block1323;           <- (b) The br destination should be remapped to here1324;1325; The test was reduced by bugpoint and should not crash in CFGStackify.1326define void @branch_remapping_after_fixing_unwind_mismatches_1() personality ptr @__gxx_wasm_personality_v0 {1327entry:1328  br i1 undef, label %if.then, label %if.end121329 1330if.then:                                          ; preds = %entry1331  invoke void @__cxa_throw(ptr null, ptr null, ptr null) #11332          to label %unreachable unwind label %catch.dispatch1333 1334catch.dispatch:                                   ; preds = %if.then1335  %0 = catchswitch within none [label %catch.start] unwind to caller1336 1337catch.start:                                      ; preds = %catch.dispatch1338  %1 = catchpad within %0 [ptr @_ZTIi]1339  %2 = call ptr @llvm.wasm.get.exception(token %1)1340  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1341  catchret from %1 to label %catchret.dest1342 1343catchret.dest:                                    ; preds = %catch.start1344  invoke void @foo()1345          to label %invoke.cont unwind label %catch.dispatch41346 1347invoke.cont:                                      ; preds = %catchret.dest1348  invoke void @__cxa_throw(ptr null, ptr null, ptr null) #11349          to label %unreachable unwind label %catch.dispatch41350 1351catch.dispatch4:                                  ; preds = %invoke.cont, %catchret.dest1352  %4 = catchswitch within none [label %catch.start5] unwind to caller1353 1354catch.start5:                                     ; preds = %catch.dispatch41355  %5 = catchpad within %4 [ptr @_ZTIi]1356  %6 = call ptr @llvm.wasm.get.exception(token %5)1357  %7 = call i32 @llvm.wasm.get.ehselector(token %5)1358  unreachable1359 1360if.end12:                                         ; preds = %entry1361  invoke void @foo()1362          to label %invoke.cont14 unwind label %catch.dispatch161363 1364catch.dispatch16:                                 ; preds = %if.end121365  %8 = catchswitch within none [label %catch.start17] unwind label %ehcleanup1366 1367catch.start17:                                    ; preds = %catch.dispatch161368  %9 = catchpad within %8 [ptr @_ZTIi]1369  %10 = call ptr @llvm.wasm.get.exception(token %9)1370  %11 = call i32 @llvm.wasm.get.ehselector(token %9)1371  br i1 undef, label %catch20, label %rethrow191372 1373catch20:                                          ; preds = %catch.start171374  catchret from %9 to label %catchret.dest221375 1376catchret.dest22:                                  ; preds = %catch201377  br label %try.cont231378 1379rethrow19:                                        ; preds = %catch.start171380  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %9) ]1381          to label %unreachable unwind label %ehcleanup1382 1383try.cont23:                                       ; preds = %invoke.cont14, %catchret.dest221384  invoke void @foo()1385          to label %invoke.cont24 unwind label %ehcleanup1386 1387invoke.cont24:                                    ; preds = %try.cont231388  ret void1389 1390invoke.cont14:                                    ; preds = %if.end121391  br label %try.cont231392 1393ehcleanup:                                        ; preds = %try.cont23, %rethrow19, %catch.dispatch161394  %12 = cleanuppad within none []1395  cleanupret from %12 unwind to caller1396 1397unreachable:                                      ; preds = %rethrow19, %invoke.cont, %if.then1398  unreachable1399}1400 1401; Regression test for WasmEHFuncInfo's reverse mapping bug. 'UnwindDestToSrc'1402; should return a vector and not a single BB, which was incorrect.1403; This was reduced by bugpoint and should not crash in CFGStackify.1404define void @wasm_eh_func_info_regression_test() personality ptr @__gxx_wasm_personality_v0 {1405entry:1406  invoke void @foo()1407          to label %invoke.cont unwind label %catch.dispatch1408 1409catch.dispatch:                                   ; preds = %entry1410  %0 = catchswitch within none [label %catch.start] unwind label %ehcleanup221411 1412catch.start:                                      ; preds = %catch.dispatch1413  %1 = catchpad within %0 [ptr @_ZTIi]1414  %2 = call ptr @llvm.wasm.get.exception(token %1)1415  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1416  invoke void @__cxa_throw(ptr null, ptr null, ptr null) #1 [ "funclet"(token %1) ]1417          to label %unreachable unwind label %catch.dispatch21418 1419catch.dispatch2:                                  ; preds = %catch.start1420  %4 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup1421 1422catch.start3:                                     ; preds = %catch.dispatch21423  %5 = catchpad within %4 [ptr @_ZTIi]1424  %6 = call ptr @llvm.wasm.get.exception(token %5)1425  %7 = call i32 @llvm.wasm.get.ehselector(token %5)1426  catchret from %5 to label %try.cont1427 1428try.cont:                                         ; preds = %catch.start31429  invoke void @foo() [ "funclet"(token %1) ]1430          to label %invoke.cont8 unwind label %ehcleanup1431 1432invoke.cont8:                                     ; preds = %try.cont1433  invoke void @__cxa_throw(ptr null, ptr null, ptr null) #1 [ "funclet"(token %1) ]1434          to label %unreachable unwind label %catch.dispatch111435 1436catch.dispatch11:                                 ; preds = %invoke.cont81437  %8 = catchswitch within %1 [label %catch.start12] unwind label %ehcleanup1438 1439catch.start12:                                    ; preds = %catch.dispatch111440  %9 = catchpad within %8 [ptr @_ZTIi]1441  %10 = call ptr @llvm.wasm.get.exception(token %9)1442  %11 = call i32 @llvm.wasm.get.ehselector(token %9)1443  unreachable1444 1445invoke.cont:                                      ; preds = %entry1446  unreachable1447 1448ehcleanup:                                        ; preds = %catch.dispatch11, %try.cont, %catch.dispatch21449  %12 = cleanuppad within %1 []1450  cleanupret from %12 unwind label %ehcleanup221451 1452ehcleanup22:                                      ; preds = %ehcleanup, %catch.dispatch1453  %13 = cleanuppad within none []1454  cleanupret from %13 unwind to caller1455 1456unreachable:                                      ; preds = %invoke.cont8, %catch.start1457  unreachable1458}1459 1460; void exception_grouping_0() {1461;   try {1462;     try {1463;       throw 0;1464;     } catch (int) {1465;     }1466;   } catch (int) {1467;   }1468; }1469;1470; Regression test for a WebAssemblyException grouping bug. After catchswitches1471; are removed, EH pad catch.start2 is dominated by catch.start, but because1472; catch.start2 is the unwind destination of catch.start, it should not be1473; included in catch.start's exception. Also, after we take catch.start2's1474; exception out of catch.start's exception, we have to take out try.cont8 out of1475; catch.start's exception, because it has a predecessor in catch.start2.1476define void @exception_grouping_0() personality ptr @__gxx_wasm_personality_v0 {1477entry:1478  %exception = call ptr @__cxa_allocate_exception(i32 4) #01479  store i32 0, ptr %exception, align 161480  invoke void @__cxa_throw(ptr %exception, ptr @_ZTIi, ptr null) #11481          to label %unreachable unwind label %catch.dispatch1482 1483catch.dispatch:                                   ; preds = %entry1484  %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch11485 1486catch.start:                                      ; preds = %catch.dispatch1487  %1 = catchpad within %0 [ptr @_ZTIi]1488  %2 = call ptr @llvm.wasm.get.exception(token %1)1489  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1490  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #01491  %matches = icmp eq i32 %3, %41492  br i1 %matches, label %catch, label %rethrow1493 1494catch:                                            ; preds = %catch.start1495  %5 = call ptr @__cxa_begin_catch(ptr %2) #0 [ "funclet"(token %1) ]1496  %6 = load i32, ptr %5, align 41497  call void @__cxa_end_catch() #0 [ "funclet"(token %1) ]1498  catchret from %1 to label %catchret.dest1499 1500catchret.dest:                                    ; preds = %catch1501  br label %try.cont1502 1503rethrow:                                          ; preds = %catch.start1504  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]1505          to label %unreachable unwind label %catch.dispatch11506 1507catch.dispatch1:                                  ; preds = %rethrow, %catch.dispatch1508  %7 = catchswitch within none [label %catch.start2] unwind to caller1509 1510catch.start2:                                     ; preds = %catch.dispatch11511  %8 = catchpad within %7 [ptr @_ZTIi]1512  %9 = call ptr @llvm.wasm.get.exception(token %8)1513  %10 = call i32 @llvm.wasm.get.ehselector(token %8)1514  %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #01515  %matches3 = icmp eq i32 %10, %111516  br i1 %matches3, label %catch5, label %rethrow41517 1518catch5:                                           ; preds = %catch.start21519  %12 = call ptr @__cxa_begin_catch(ptr %9) #0 [ "funclet"(token %8) ]1520  %13 = load i32, ptr %12, align 41521  call void @__cxa_end_catch() #0 [ "funclet"(token %8) ]1522  catchret from %8 to label %catchret.dest71523 1524catchret.dest7:                                   ; preds = %catch51525  br label %try.cont81526 1527rethrow4:                                         ; preds = %catch.start21528  call void @llvm.wasm.rethrow() #1 [ "funclet"(token %8) ]1529  unreachable1530 1531try.cont8:                                        ; preds = %try.cont, %catchret.dest71532  ret void1533 1534try.cont:                                         ; preds = %catchret.dest1535  br label %try.cont81536 1537unreachable:                                      ; preds = %rethrow, %entry1538  unreachable1539}1540 1541; Test for WebAssemblyException grouping. This test is hand-modified to generate1542; this structure:1543; catch.start dominates catch.start4 and catch.start4 dominates catch.start12,1544; so the after dominator-based grouping, we end up with:1545; catch.start's exception > catch4.start's exception > catch12.start's exception1546; (> here represents subexception relationship)1547;1548; But the unwind destination chain is catch.start -> catch.start4 ->1549; catch.start12. So all these subexception relationship should be deconstructed.1550; We have to make sure to take out catch.start4's exception out of catch.start's1551; exception first, before taking out catch.start12's exception out of1552; catch.start4's exception; otherwise we end up with an incorrect relationship1553; of catch.start's exception > catch.start12's exception.1554define void @exception_grouping_1() personality ptr @__gxx_wasm_personality_v0 {1555entry:1556  invoke void @foo()1557          to label %invoke.cont unwind label %catch.dispatch1558 1559invoke.cont:                                      ; preds = %entry1560  invoke void @foo()1561          to label %invoke.cont1 unwind label %catch.dispatch1562 1563invoke.cont1:                                     ; preds = %invoke.cont1564  invoke void @foo()1565          to label %try.cont18 unwind label %catch.dispatch1566 1567catch.dispatch11:                                 ; preds = %rethrow6, %catch.dispatch31568  %0 = catchswitch within none [label %catch.start12] unwind to caller1569 1570catch.start12:                                    ; preds = %catch.dispatch111571  %1 = catchpad within %0 [ptr @_ZTIi]1572  %2 = call ptr @llvm.wasm.get.exception(token %1)1573  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1574  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #01575  %matches13 = icmp eq i32 %3, %41576  br i1 %matches13, label %catch15, label %rethrow141577 1578catch15:                                          ; preds = %catch.start121579  %5 = call ptr @__cxa_begin_catch(ptr %2) #0 [ "funclet"(token %1) ]1580  %6 = load i32, ptr %5, align 41581  call void @__cxa_end_catch() #0 [ "funclet"(token %1) ]1582  catchret from %1 to label %try.cont181583 1584rethrow14:                                        ; preds = %catch.start121585  call void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]1586  unreachable1587 1588catch.dispatch3:                                  ; preds = %rethrow, %catch.dispatch1589  %7 = catchswitch within none [label %catch.start4] unwind label %catch.dispatch111590 1591catch.start4:                                     ; preds = %catch.dispatch31592  %8 = catchpad within %7 [ptr @_ZTIi]1593  %9 = call ptr @llvm.wasm.get.exception(token %8)1594  %10 = call i32 @llvm.wasm.get.ehselector(token %8)1595  %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #01596  %matches5 = icmp eq i32 %10, %111597  br i1 %matches5, label %catch7, label %rethrow61598 1599catch7:                                           ; preds = %catch.start41600  %12 = call ptr @__cxa_begin_catch(ptr %9) #0 [ "funclet"(token %8) ]1601  %13 = load i32, ptr %12, align 41602  call void @__cxa_end_catch() #0 [ "funclet"(token %8) ]1603  catchret from %8 to label %try.cont181604 1605rethrow6:                                         ; preds = %catch.start41606  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %8) ]1607          to label %unreachable unwind label %catch.dispatch111608 1609catch.dispatch:                                   ; preds = %invoke.cont1, %invoke.cont, %entry1610  %14 = catchswitch within none [label %catch.start] unwind label %catch.dispatch31611 1612catch.start:                                      ; preds = %catch.dispatch1613  %15 = catchpad within %14 [ptr @_ZTIi]1614  %16 = call ptr @llvm.wasm.get.exception(token %15)1615  %17 = call i32 @llvm.wasm.get.ehselector(token %15)1616  %18 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #01617  %matches = icmp eq i32 %17, %181618  br i1 %matches, label %catch, label %rethrow1619 1620catch:                                            ; preds = %catch.start1621  %19 = call ptr @__cxa_begin_catch(ptr %16) #0 [ "funclet"(token %15) ]1622  %20 = load i32, ptr %19, align 41623  call void @__cxa_end_catch() #0 [ "funclet"(token %15) ]1624  catchret from %15 to label %try.cont181625 1626rethrow:                                          ; preds = %catch.start1627  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %15) ]1628          to label %unreachable unwind label %catch.dispatch31629 1630try.cont18:                                       ; preds = %catch, %catch7, %catch15, %invoke.cont11631  ret void1632 1633unreachable:                                      ; preds = %rethrow, %rethrow61634  unreachable1635}1636 1637; void exception_grouping_2() {1638;   try {1639;     try {1640;       throw 0;1641;     } catch (int) { // (a)1642;     }1643;   } catch (int) {   // (b)1644;   }1645;   try {1646;     foo();1647;   } catch (int) {   // (c)1648;   }1649; }1650;1651; Regression test for an ExceptionInfo grouping bug. Because the first (inner)1652; try always throws, both EH pads (b) (catch.start2) and (c) (catch.start10) are1653; dominated by EH pad (a) (catch.start), even though they are not semantically1654; contained in (a)'s exception. Because (a)'s unwind destination is (b), (b)'s1655; exception is taken out of (a)'s. But because (c) is reachable from (b), we1656; should make sure to take out (c)'s exception out of (a)'s exception too.1657define void @exception_grouping_2() personality ptr @__gxx_wasm_personality_v0 {1658entry:1659  %exception = call ptr @__cxa_allocate_exception(i32 4) #11660  store i32 0, ptr %exception, align 161661  invoke void @__cxa_throw(ptr %exception, ptr @_ZTIi, ptr null) #31662          to label %unreachable unwind label %catch.dispatch1663 1664catch.dispatch:                                   ; preds = %entry1665  %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch11666 1667catch.start:                                      ; preds = %catch.dispatch1668  %1 = catchpad within %0 [ptr @_ZTIi]1669  %2 = call ptr @llvm.wasm.get.exception(token %1)1670  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1671  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #11672  %matches = icmp eq i32 %3, %41673  br i1 %matches, label %catch, label %rethrow1674 1675catch:                                            ; preds = %catch.start1676  %5 = call ptr @__cxa_begin_catch(ptr %2) #1 [ "funclet"(token %1) ]1677  %6 = load i32, ptr %5, align 41678  call void @__cxa_end_catch() #1 [ "funclet"(token %1) ]1679  catchret from %1 to label %try.cont81680 1681rethrow:                                          ; preds = %catch.start1682  invoke void @llvm.wasm.rethrow() #3 [ "funclet"(token %1) ]1683          to label %unreachable unwind label %catch.dispatch11684 1685catch.dispatch1:                                  ; preds = %rethrow, %catch.dispatch1686  %7 = catchswitch within none [label %catch.start2] unwind to caller1687 1688catch.start2:                                     ; preds = %catch.dispatch11689  %8 = catchpad within %7 [ptr @_ZTIi]1690  %9 = call ptr @llvm.wasm.get.exception(token %8)1691  %10 = call i32 @llvm.wasm.get.ehselector(token %8)1692  %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #11693  %matches3 = icmp eq i32 %10, %111694  br i1 %matches3, label %catch5, label %rethrow41695 1696catch5:                                           ; preds = %catch.start21697  %12 = call ptr @__cxa_begin_catch(ptr %9) #1 [ "funclet"(token %8) ]1698  %13 = load i32, ptr %12, align 41699  call void @__cxa_end_catch() #1 [ "funclet"(token %8) ]1700  catchret from %8 to label %try.cont81701 1702rethrow4:                                         ; preds = %catch.start21703  call void @llvm.wasm.rethrow() #3 [ "funclet"(token %8) ]1704  unreachable1705 1706try.cont8:                                        ; preds = %catch, %catch51707  invoke void @foo()1708          to label %try.cont16 unwind label %catch.dispatch91709 1710catch.dispatch9:                                  ; preds = %try.cont81711  %14 = catchswitch within none [label %catch.start10] unwind to caller1712 1713catch.start10:                                    ; preds = %catch.dispatch91714  %15 = catchpad within %14 [ptr @_ZTIi]1715  %16 = call ptr @llvm.wasm.get.exception(token %15)1716  %17 = call i32 @llvm.wasm.get.ehselector(token %15)1717  %18 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #11718  %matches11 = icmp eq i32 %17, %181719  br i1 %matches11, label %catch13, label %rethrow121720 1721catch13:                                          ; preds = %catch.start101722  %19 = call ptr @__cxa_begin_catch(ptr %16) #1 [ "funclet"(token %15) ]1723  %20 = load i32, ptr %19, align 41724  call void @__cxa_end_catch() #1 [ "funclet"(token %15) ]1725  catchret from %15 to label %try.cont161726 1727rethrow12:                                        ; preds = %catch.start101728  call void @llvm.wasm.rethrow() #3 [ "funclet"(token %15) ]1729  unreachable1730 1731try.cont16:                                       ; preds = %try.cont8, %catch131732  ret void1733 1734unreachable:                                      ; preds = %rethrow, %entry1735  unreachable1736}1737 1738; Check if the unwind destination mismatch stats are correct1739; NOSORT: 24 wasm-cfg-stackify    - Number of call unwind mismatches found1740; NOSORT:  5 wasm-cfg-stackify    - Number of catch unwind mismatches found1741 1742declare void @foo()1743declare void @bar()1744declare i32 @baz()1745declare i32 @qux(i32)1746declare void @quux(i32)1747declare void @fun(i32)1748; Function Attrs: nounwind1749declare void @nothrow(i32) #01750; Function Attrs: nounwind1751declare i32 @nothrow_i32() #01752 1753; Function Attrs: nounwind1754declare ptr @_ZN6ObjectD2Ev(ptr returned) #01755@_ZTI7MyClass = external constant { ptr, ptr }, align 41756; Function Attrs: nounwind1757declare ptr @_ZN7MyClassD2Ev(ptr returned) #01758; Function Attrs: nounwind1759declare ptr @_ZN7MyClassC2ERKS_(ptr returned, ptr dereferenceable(4)) #01760 1761declare i32 @__gxx_wasm_personality_v0(...)1762; Function Attrs: nounwind1763declare ptr @llvm.wasm.get.exception(token) #01764; Function Attrs: nounwind1765declare i32 @llvm.wasm.get.ehselector(token) #01766declare ptr @__cxa_allocate_exception(i32) #01767declare void @__cxa_throw(ptr, ptr, ptr)1768; Function Attrs: noreturn1769declare void @llvm.wasm.rethrow() #11770; Function Attrs: nounwind1771declare i32 @llvm.eh.typeid.for(ptr) #01772 1773declare ptr @__cxa_begin_catch(ptr)1774declare void @__cxa_end_catch()1775declare ptr @__cxa_get_exception_ptr(ptr)1776declare void @_ZSt9terminatev()1777; Function Attrs: nounwind1778declare void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i32, i1 immarg) #01779; Function Attrs: nounwind1780declare void @llvm.memmove.p0.p0.i32(ptr nocapture, ptr nocapture readonly, i32, i1 immarg) #01781; Function Attrs: nounwind1782declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #01783 1784attributes #0 = { nounwind }1785attributes #1 = { noreturn }1786