brintos

brintos / llvm-project-archived public Read only

0
0
Text · 65.5 KiB · 98de9a2 Raw
1557 lines · plain
1; REQUIRES: asserts2; 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=false -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=false -exception-model=wasm -mattr=+exception-handling,bulk-memory4; RUN: llc < %s -O0 -disable-wasm-fallthrough-return-opt -verify-machineinstrs -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling,-bulk-memory,-bulk-memory-opt | FileCheck %s --check-prefix=NOOPT5; 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=false -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=false -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: block29; CHECK:   block     () -> (i32, exnref)30; CHECK:     try_table    (catch_ref __cpp_exception 0) # 0: down to label[[L0:[0-9]+]]31; CHECK:       call  foo32; CHECK:       br        2                               # 2: down to label[[L1:[0-9]+]]33; CHECK:     end_try_table34; CHECK:   end_block                                     # label[[L0]]:35; CHECK:   local.set  236; CHECK:   local.set  137; CHECK:   local.get  038; CHECK:   call  _Unwind_CallPersonality39; CHECK:   block40; CHECK:     br_if     0                                 # 0: down to label[[L2:[0-9]+]]41; CHECK:     call  __cxa_begin_catch42; CHECK:     call  __cxa_end_catch43; CHECK:     br        1                                 # 1: down to label[[L1]]44; CHECK:   end_block                                     # label[[L2]]:45; CHECK:   block46; CHECK:     br_if     0                                 # 0: down to label[[L3:[0-9]+]]47; CHECK:     call  __cxa_begin_catch48; CHECK:     call  __cxa_end_catch49; CHECK:     br        1                                 # 1: down to label[[L1]]50; CHECK:   end_block                                     # label[[L3]]:51; CHECK:   throw_ref52; CHECK: end_block                                       # label[[L1]]:53define void @two_catches() personality ptr @__gxx_wasm_personality_v0 {54entry:55  invoke void @foo()56          to label %try.cont unwind label %catch.dispatch57 58catch.dispatch:                                   ; preds = %entry59  %0 = catchswitch within none [label %catch.start] unwind to caller60 61catch.start:                                      ; preds = %catch.dispatch62  %1 = catchpad within %0 [ptr @_ZTIi, ptr @_ZTId]63  %2 = call ptr @llvm.wasm.get.exception(token %1)64  %3 = call i32 @llvm.wasm.get.ehselector(token %1)65  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)66  %matches = icmp eq i32 %3, %467  br i1 %matches, label %catch2, label %catch.fallthrough68 69catch2:                                           ; preds = %catch.start70  %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]71  call void @__cxa_end_catch() [ "funclet"(token %1) ]72  catchret from %1 to label %try.cont73 74catch.fallthrough:                                ; preds = %catch.start75  %6 = call i32 @llvm.eh.typeid.for(ptr @_ZTId)76  %matches1 = icmp eq i32 %3, %677  br i1 %matches1, label %catch, label %rethrow78 79catch:                                            ; preds = %catch.fallthrough80  %7 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]81  call void @__cxa_end_catch() [ "funclet"(token %1) ]82  catchret from %1 to label %try.cont83 84rethrow:                                          ; preds = %catch.fallthrough85  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]86  unreachable87 88try.cont:                                         ; preds = %catch, %catch2, %entry89  ret void90}91 92; Nested try-catches within a catch93; void nested_catch() {94;   try {95;     foo();96;   } catch (int) {97;     try {98;       foo();99;     } catch (int) {100;       foo();101;     }102;   }103; }104 105; CHECK-LABEL: nested_catch:106; CHECK: block     exnref107; CHECK:   block108; CHECK:     block     () -> (i32, exnref)109; CHECK:       try_table    (catch_ref __cpp_exception 0)         # 0: down to label[[L0:[0-9]+]]110; CHECK:         call  foo111; CHECK:         br        2                                      # 2: down to label[[L1:[0-9]+]]112; CHECK:       end_try_table113; CHECK:     end_block                                            # label[[L0]]:114; CHECK:     call  _Unwind_CallPersonality115; CHECK:     block116; CHECK:       block117; CHECK:         br_if     0                                      # 0: down to label[[L2:[0-9]+]]118; CHECK:         call  __cxa_begin_catch119; CHECK:         block     exnref120; CHECK:           try_table    (catch_all_ref 0)                 # 0: down to label[[L3:[0-9]+]]121; CHECK:             block     () -> (i32, exnref)122; CHECK:               try_table    (catch_ref __cpp_exception 0) # 0: down to label[[L4:[0-9]+]]123; CHECK:                 call  foo124; CHECK:                 br        5                              # 5: down to label[[L5:[0-9]+]]125; CHECK:               end_try_table126; CHECK:             end_block                                    # label[[L4]]:127; CHECK:             call  _Unwind_CallPersonality128; CHECK:             block129; CHECK:               block130; CHECK:                 br_if     0                              # 0: down to label[[L6:[0-9]+]]131; CHECK:                 call  __cxa_begin_catch132; CHECK:                 block     exnref133; CHECK:                   try_table    (catch_all_ref 0)         # 0: down to label[[L7:[0-9]+]]134; CHECK:                     call  foo135; CHECK:                     br        3                          # 3: down to label[[L8:[0-9]+]]136; CHECK:                   end_try_table137; CHECK:                 end_block                                # label[[L7]]:138; CHECK:                 try_table    (catch_all_ref 7)           # 7: down to label[[L9:[0-9]+]]139; CHECK:                   call  __cxa_end_catch140; CHECK:                 end_try_table141; CHECK:                 throw_ref142; CHECK:               end_block                                  # label[[L6]]:143; CHECK:               throw_ref144; CHECK:             end_block                                    # label[[L8]]:145; CHECK:             try_table    (catch_all_ref 5)               # 5: down to label[[L9]]146; CHECK:               call  __cxa_end_catch147; CHECK:             end_try_table148; CHECK:             br        3                                  # 3: down to label[[L5]]149; CHECK:           end_try_table150; CHECK:         end_block                                        # label[[L3]]:151; CHECK:         call  __cxa_end_catch152; CHECK:         throw_ref153; CHECK:       end_block                                          # label[[L2]]:154; CHECK:       throw_ref155; CHECK:     end_block                                            # label[[L5]]:156; CHECK:     call  __cxa_end_catch157; CHECK:   end_block                                              # label[[L1]]:158; CHECK:   return159; CHECK: end_block                                                # label[[L9]]:160; CHECK: throw_ref161define void @nested_catch() personality ptr @__gxx_wasm_personality_v0 {162entry:163  invoke void @foo()164          to label %try.cont11 unwind label %catch.dispatch165 166catch.dispatch:                                   ; preds = %entry167  %0 = catchswitch within none [label %catch.start] unwind to caller168 169catch.start:                                      ; preds = %catch.dispatch170  %1 = catchpad within %0 [ptr @_ZTIi]171  %2 = call ptr @llvm.wasm.get.exception(token %1)172  %3 = call i32 @llvm.wasm.get.ehselector(token %1)173  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)174  %matches = icmp eq i32 %3, %4175  br i1 %matches, label %catch, label %rethrow176 177catch:                                            ; preds = %catch.start178  %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]179  %6 = load i32, ptr %5, align 4180  invoke void @foo() [ "funclet"(token %1) ]181          to label %try.cont unwind label %catch.dispatch2182 183catch.dispatch2:                                  ; preds = %catch184  %7 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup9185 186catch.start3:                                     ; preds = %catch.dispatch2187  %8 = catchpad within %7 [ptr @_ZTIi]188  %9 = call ptr @llvm.wasm.get.exception(token %8)189  %10 = call i32 @llvm.wasm.get.ehselector(token %8)190  %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)191  %matches4 = icmp eq i32 %10, %11192  br i1 %matches4, label %catch6, label %rethrow5193 194catch6:                                           ; preds = %catch.start3195  %12 = call ptr @__cxa_begin_catch(ptr %9) [ "funclet"(token %8) ]196  %13 = load i32, ptr %12, align 4197  invoke void @foo() [ "funclet"(token %8) ]198          to label %invoke.cont8 unwind label %ehcleanup199 200invoke.cont8:                                     ; preds = %catch6201  call void @__cxa_end_catch() [ "funclet"(token %8) ]202  catchret from %8 to label %try.cont203 204rethrow5:                                         ; preds = %catch.start3205  invoke void @llvm.wasm.rethrow() [ "funclet"(token %8) ]206          to label %unreachable unwind label %ehcleanup9207 208try.cont:                                         ; preds = %invoke.cont8, %catch209  call void @__cxa_end_catch() [ "funclet"(token %1) ]210  catchret from %1 to label %try.cont11211 212rethrow:                                          ; preds = %catch.start213  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]214  unreachable215 216try.cont11:                                       ; preds = %try.cont, %entry217  ret void218 219ehcleanup:                                        ; preds = %catch6220  %14 = cleanuppad within %8 []221  call void @__cxa_end_catch() [ "funclet"(token %14) ]222  cleanupret from %14 unwind label %ehcleanup9223 224ehcleanup9:                                       ; preds = %ehcleanup, %rethrow5, %catch.dispatch2225  %15 = cleanuppad within %1 []226  call void @__cxa_end_catch() [ "funclet"(token %15) ]227  cleanupret from %15 unwind to caller228 229unreachable:                                      ; preds = %rethrow5230  unreachable231}232 233; Nested try-catches within a try234; void nested_try() {235;   try {236;     try {237;       foo();238;     } catch (...) {239;     }240;   } catch (...) {241;   }242; }243 244; CHECK-LABEL: nested_try:245; CHECK: block246; CHECK:   block     i32247; CHECK:     try_table    (catch __cpp_exception 0)   # 0: down to label[[L0:[0-9]+]]248; CHECK:     block     i32249; CHECK:       try_table    (catch __cpp_exception 0) # 0: down to label[[L1:[0-9]+]]250; CHECK:         call  foo251; CHECK:         br        4                          # 4: down to label[[L2:[0-9]+]]252; CHECK:       end_try_table253; CHECK:     end_block                                # label[[L1]]:254; CHECK:     call  __cxa_begin_catch255; CHECK:     call  __cxa_end_catch256; CHECK:     br        2                              # 2: down to label[[L2]]257; CHECK:     end_try_table258; CHECK:   end_block                                  # label[[L0]]:259; CHECK:   call  __cxa_begin_catch260; CHECK:   call  __cxa_end_catch261; CHECK: end_block                                    # label[[L2]]:262define void @nested_try() personality ptr @__gxx_wasm_personality_v0 {263entry:264  invoke void @foo()265          to label %try.cont7 unwind label %catch.dispatch266 267catch.dispatch:                                   ; preds = %entry268  %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch2269 270catch.start:                                      ; preds = %catch.dispatch271  %1 = catchpad within %0 [ptr null]272  %2 = call ptr @llvm.wasm.get.exception(token %1)273  %3 = call i32 @llvm.wasm.get.ehselector(token %1)274  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]275  invoke void @__cxa_end_catch() [ "funclet"(token %1) ]276          to label %invoke.cont1 unwind label %catch.dispatch2277 278catch.dispatch2:                                  ; preds = %catch.start, %catch.dispatch279  %5 = catchswitch within none [label %catch.start3] unwind to caller280 281catch.start3:                                     ; preds = %catch.dispatch2282  %6 = catchpad within %5 [ptr null]283  %7 = call ptr @llvm.wasm.get.exception(token %6)284  %8 = call i32 @llvm.wasm.get.ehselector(token %6)285  %9 = call ptr @__cxa_begin_catch(ptr %7) [ "funclet"(token %6) ]286  call void @__cxa_end_catch() [ "funclet"(token %6) ]287  catchret from %6 to label %try.cont7288 289try.cont7:                                        ; preds = %entry, %invoke.cont1, %catch.start3290  ret void291 292invoke.cont1:                                     ; preds = %catch.start293  catchret from %1 to label %try.cont7294}295 296 297; CHECK-LABEL: loop_within_catch:298; CHECK: block299; CHECK:   block     i32300; CHECK:     try_table    (catch __cpp_exception 0) # 0: down to label[[L0:[0-9]+]]301; CHECK:       call  foo302; CHECK:       br        2                          # 2: down to label[[L1:[0-9]+]]303; CHECK:     end_try_table304; CHECK:   end_block                                # label[[L0]]:305; CHECK:   call  __cxa_begin_catch306; CHECK:   loop                                     # label[[L2:[0-9]+]]:307; CHECK:     block308; CHECK:       block309; CHECK:         br_if     0                        # 0: down to label[[L3:[0-9]+]]310; CHECK:         block     exnref311; CHECK:           try_table    (catch_all_ref 0)   # 0: down to label[[L4:[0-9]+]]312; CHECK:             call  foo313; CHECK:             br        3                    # 3: down to label[[L5:[0-9]+]]314; CHECK:           end_try_table315; CHECK:         end_block                          # label[[L4]]:316; CHECK:         block317; CHECK:           block318; CHECK:             try_table    (catch_all 0)     # 0: down to label[[L6:[0-9]+]]319; CHECK:               call  __cxa_end_catch320; CHECK:               br        2                  # 2: down to label[[L7:[0-9]+]]321; CHECK:             end_try_table322; CHECK:           end_block                        # label[[L6]]:323; CHECK:           call  _ZSt9terminatev324; CHECK:           unreachable325; CHECK:         end_block                          # label[[L7]]:326; CHECK:         throw_ref327; CHECK:       end_block                            # label[[L3]]:328; CHECK:       call  __cxa_end_catch329; CHECK:       br        2                          # 2: down to label[[L1]]330; CHECK:     end_block                              # label[[L5]]:331; CHECK:     br        0                            # 0: up to label[[L2]]332; CHECK:   end_loop333; CHECK: end_block                                  # label[[L1]]:334define void @loop_within_catch() personality ptr @__gxx_wasm_personality_v0 {335entry:336  invoke void @foo()337          to label %try.cont unwind label %catch.dispatch338 339catch.dispatch:                                   ; preds = %entry340  %0 = catchswitch within none [label %catch.start] unwind to caller341 342catch.start:                                      ; preds = %catch.dispatch343  %1 = catchpad within %0 [ptr null]344  %2 = call ptr @llvm.wasm.get.exception(token %1)345  %3 = call i32 @llvm.wasm.get.ehselector(token %1)346  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]347  br label %for.cond348 349for.cond:                                         ; preds = %for.inc, %catch.start350  %i.0 = phi i32 [ 0, %catch.start ], [ %inc, %for.inc ]351  %cmp = icmp slt i32 %i.0, 50352  br i1 %cmp, label %for.body, label %for.end353 354for.body:                                         ; preds = %for.cond355  invoke void @foo() [ "funclet"(token %1) ]356          to label %for.inc unwind label %ehcleanup357 358for.inc:                                          ; preds = %for.body359  %inc = add nsw i32 %i.0, 1360  br label %for.cond361 362for.end:                                          ; preds = %for.cond363  call void @__cxa_end_catch() [ "funclet"(token %1) ]364  catchret from %1 to label %try.cont365 366try.cont:                                         ; preds = %for.end, %entry367  ret void368 369ehcleanup:                                        ; preds = %for.body370  %5 = cleanuppad within %1 []371  invoke void @__cxa_end_catch() [ "funclet"(token %5) ]372          to label %invoke.cont2 unwind label %terminate373 374invoke.cont2:                                     ; preds = %ehcleanup375  cleanupret from %5 unwind to caller376 377terminate:                                        ; preds = %ehcleanup378  %6 = cleanuppad within %5 []379  call void @_ZSt9terminatev() [ "funclet"(token %6) ]380  unreachable381}382 383; Tests if block and try_table markers are correctly placed. Even if two384; predecessors of the EH pad are bb2 and bb3 and their nearest common dominator385; is bb1, the TRY_TABLE marker should be placed at bb0 because there's a branch386; from bb0 to bb2, and scopes cannot be interleaved.387; NOOPT-LABEL: block_try_table_markers:388; NOOPT: block389; NOOPT:   block     i32390; NOOPT:   try_table    (catch __cpp_exception 0)391; NOOPT:     block392; NOOPT:       block393; NOOPT:         block394; NOOPT:         end_block395; NOOPT:       end_block396; NOOPT:       call  foo397; NOOPT:     end_block398; NOOPT:     call  bar399; NOOPT:   end_try_table400; NOOPT:   end_block401; NOOPT: end_block402define void @block_try_table_markers() personality ptr @__gxx_wasm_personality_v0 {403bb0:404  br i1 undef, label %bb1, label %bb2405 406bb1:                                              ; preds = %bb0407  br i1 undef, label %bb3, label %bb4408 409bb2:                                              ; preds = %bb0410  br label %try.cont411 412bb3:                                              ; preds = %bb1413  invoke void @foo()414          to label %try.cont unwind label %catch.dispatch415 416bb4:                                              ; preds = %bb1417  invoke void @bar()418          to label %try.cont unwind label %catch.dispatch419 420catch.dispatch:                                   ; preds = %bb4, %bb3421  %0 = catchswitch within none [label %catch.start] unwind to caller422 423catch.start:                                      ; preds = %catch.dispatch424  %1 = catchpad within %0 [ptr null]425  %2 = call ptr @llvm.wasm.get.exception(token %1)426  %3 = call i32 @llvm.wasm.get.ehselector(token %1)427  catchret from %1 to label %try.cont428 429try.cont:                                         ; preds = %catch.start, %bb4, %bb3, %bb2430  ret void431}432 433; Tests if try_table/end_try_table markers are placed correctly wrt434; loop/end_loop markers, when try_table and loop markers are in the same BB and435; end_try_table and end_loop are in another BB.436; CHECK-LABEL: loop_try_table_markers:437; CHECK: loop438; CHECK:   block     i32439; CHECK:     try_table    (catch __cpp_exception 0)440; CHECK:       call  foo441; CHECK:     end_try_table442; CHECK:   end_block443; CHECK: end_loop444define void @loop_try_table_markers(ptr %p) personality ptr @__gxx_wasm_personality_v0 {445entry:446  store volatile i32 0, ptr %p447  br label %loop448 449loop:                                             ; preds = %try.cont, %entry450  store volatile i32 1, ptr %p451  invoke void @foo()452          to label %try.cont unwind label %catch.dispatch453 454catch.dispatch:                                   ; preds = %loop455  %0 = catchswitch within none [label %catch.start] unwind to caller456 457catch.start:                                      ; preds = %catch.dispatch458  %1 = catchpad within %0 [ptr null]459  %2 = call ptr @llvm.wasm.get.exception(token %1)460  %3 = call i32 @llvm.wasm.get.ehselector(token %1)461  catchret from %1 to label %try.cont462 463try.cont:                                         ; preds = %catch.start, %loop464  br label %loop465}466 467; Some of test cases below are hand-tweaked by deleting some library calls to468; simplify tests and changing the order of basic blocks to cause unwind469; destination mismatches. And we use -wasm-disable-ehpad-sort to create maximum470; number of mismatches in several tests below.471 472; - Call unwind mismatch473; 'call bar''s original unwind destination was 'C0', but after control flow474; linearization, its unwind destination incorrectly becomes 'C1'. We fix this by475; wrapping the call with a nested try_table-end_try_table that targets 'C0'.476; - Catch unwind mismatch477; If 'call foo' throws a foreign exception, it will not be caught by C1, and478; should be rethrown to the caller. But after control flow linearization, it479; will instead unwind to C0, an incorrect next EH pad. We wrap the whole480; try_table-end_try_table with another try_table-end_try_table that jumps to a481; trampoline BB, from which we rethrow the exception to the caller to fix this.482 483; NOSORT-LABEL: unwind_mismatches_0:484; NOSORT: block     exnref485; NOSORT:   block486; NOSORT:     block     i32487; NOSORT:       try_table    (catch __cpp_exception 0)         # 0: down to label[[L0:[0-9]+]]488; NOSORT:         block     exnref489; NOSORT:           block     i32490; --- nested try_table-end_try_table starts (catch unwind mismatch)491; NOSORT:             try_table    (catch_all_ref 5)           # 5: down to label[[L1:[0-9]+]]492; NOSORT:               try_table    (catch __cpp_exception 1) # 1: down to label[[L2:[0-9]+]]493; NOSORT:                 call  foo494; --- nested try_table-end_try_table starts (call unwind mismatch)495; NOSORT:                 try_table    (catch_all_ref 3)       # 3: down to label[[L3:[0-9]+]]496; NOSORT:                   call  bar497; NOSORT:                 end_try_table498; --- nested try_table-end_try_table ends (call unwind mismatch)499; NOSORT:               end_try_table500; NOSORT:             end_try_table501; --- nested try_table-end_try_table ends (catch unwind mismatch)502; NOSORT:           end_block                                  # label[[L2]]:503; NOSORT:         end_block                                    # label[[L3]]:504; NOSORT:         throw_ref505; NOSORT:       end_try_table506; NOSORT:     end_block                                        # label[[L0]]:507; NOSORT:   end_block508; NOSORT:   return509; NOSORT: end_block                                            # label[[L1]]:510; NOSORT: throw_ref511define void @unwind_mismatches_0() personality ptr @__gxx_wasm_personality_v0 {512bb0:513  invoke void @foo()514          to label %bb1 unwind label %catch.dispatch0515 516bb1:                                              ; preds = %bb0517  invoke void @bar()518          to label %try.cont unwind label %catch.dispatch1519 520catch.dispatch0:                                  ; preds = %bb0521  %0 = catchswitch within none [label %catch.start0] unwind to caller522 523catch.start0:                                     ; preds = %catch.dispatch0524  %1 = catchpad within %0 [ptr null]525  %2 = call ptr @llvm.wasm.get.exception(token %1)526  %3 = call i32 @llvm.wasm.get.ehselector(token %1)527  catchret from %1 to label %try.cont528 529catch.dispatch1:                                  ; preds = %bb1530  %4 = catchswitch within none [label %catch.start1] unwind to caller531 532catch.start1:                                     ; preds = %catch.dispatch1533  %5 = catchpad within %4 [ptr null]534  %6 = call ptr @llvm.wasm.get.exception(token %5)535  %7 = call i32 @llvm.wasm.get.ehselector(token %5)536  catchret from %5 to label %try.cont537 538try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1539  ret void540}541 542; 'call bar' and 'call baz''s original unwind destination was the caller, but543; after control flow linearization, their unwind destination incorrectly becomes544; 'C0'. We fix this by wrapping the calls with a nested try_table-end_try_table545; that jumps to a trampoline BB where we rethrow the exception to the caller.546 547; And the return value of 'baz' should NOT be stackified because the BB is split548; during fixing unwind mismatches.549 550; NOSORT-LABEL: unwind_mismatches_1:551; NOSORT: block     exnref552; NOSORT:   block     i32553; NOSORT:     try_table    (catch __cpp_exception 0) # 0: down to label[[L0:[0-9]+]]554; NOSORT:       call  foo555; --- nested try_table-end_try_table starts (call unwind mismatch)556; NOSORT:       try_table    (catch_all_ref 2)       # 2: down to label[[L1:[0-9]+]]557; NOSORT:         call  bar558; NOSORT:         call  baz559; NOSORT:         local.set [[LOCAL:[0-9]+]]560; NOSORT:       end_try_table561; --- nested try_table-end_try_table ends (call unwind mismatch)562; NOSORT:       local.get [[LOCAL]]563; NOSORT:       call  nothrow564; NOSORT:       return565; NOSORT:     end_try_table566; NOSORT:   end_block                                # label[[L0]]:567; NOSORT:   return568; NOSORT: end_block                                  # label[[L1]]:569; NOSORT: throw_ref570define void @unwind_mismatches_1() personality ptr @__gxx_wasm_personality_v0 {571bb0:572  invoke void @foo()573          to label %bb1 unwind label %catch.dispatch0574 575bb1:                                              ; preds = %bb0576  call void @bar()577  %call = call i32 @baz()578  call void @nothrow(i32 %call) #0579  ret void580 581catch.dispatch0:                                  ; preds = %bb0582  %0 = catchswitch within none [label %catch.start0] unwind to caller583 584catch.start0:                                     ; preds = %catch.dispatch0585  %1 = catchpad within %0 [ptr null]586  %2 = call ptr @llvm.wasm.get.exception(token %1)587  %3 = call i32 @llvm.wasm.get.ehselector(token %1)588  catchret from %1 to label %try.cont589 590try.cont:                                         ; preds = %catch.start0591  ret void592}593 594; The same as unwind_mismatches_0, but we have one more call 'call @foo' in bb1595; which unwinds to the caller. IN this case bb1 has two call unwind mismatches:596; 'call @foo' unwinds to the caller and 'call @bar' unwinds to catch C0.597 598; NOSORT-LABEL: unwind_mismatches_2:599; NOSORT: block     exnref600; NOSORT:   block601; NOSORT:     block     i32602; NOSORT:       try_table    (catch __cpp_exception 0)         # 0: down to label[[L0:[0-9]+]]603; NOSORT:         block     exnref604; NOSORT:           block     i32605; --- nested try_table-end_try_table starts (catch unwind mismatch)606; NOSORT:             try_table    (catch_all_ref 5)           # 5: down to label[[L1:[0-9]+]]607; NOSORT:               try_table    (catch __cpp_exception 1) # 1: down to label[[L2:[0-9]+]]608; NOSORT:                 call  foo609; --- nested try_table-end_try_table starts (call unwind mismatch)610; NOSORT:                 try_table    (catch_all_ref 7)       # 7: down to label[[L1]]611; NOSORT:                   call  foo612; NOSORT:                 end_try_table613; --- nested try_table-end_try_table ends (call unwind mismatch)614; --- nested try_table-end_try_table starts (call unwind mismatch)615; NOSORT:                 try_table    (catch_all_ref 3)       # 3: down to label[[L3:[0-9]+]]616; NOSORT:                   call  bar617; NOSORT:                 end_try_table618; --- nested try_table-end_try_table ends (call unwind mismatch)619; NOSORT:               end_try_table620; NOSORT:             end_try_table621; --- nested try_table-end_try_table ends (catch unwind mismatch)622; NOSORT:           end_block                                  # label[[L2]]:623; NOSORT:         end_block                                    # label[[L3]]:624; NOSORT:         throw_ref625; NOSORT:       end_try_table626; NOSORT:     end_block                                        # label[[L0]]:627; NOSORT:   end_block628; NOSORT:   return629; NOSORT: end_block                                            # label[[L1]]:630; NOSORT: throw_ref631define void @unwind_mismatches_2() personality ptr @__gxx_wasm_personality_v0 {632bb0:633  invoke void @foo()634          to label %bb1 unwind label %catch.dispatch0635 636bb1:                                              ; preds = %bb0637  call void @foo()638  invoke void @bar()639          to label %try.cont unwind label %catch.dispatch1640 641catch.dispatch0:                                  ; preds = %bb0642  %0 = catchswitch within none [label %catch.start0] unwind to caller643 644catch.start0:                                     ; preds = %catch.dispatch0645  %1 = catchpad within %0 [ptr null]646  %2 = call ptr @llvm.wasm.get.exception(token %1)647  %3 = call i32 @llvm.wasm.get.ehselector(token %1)648  catchret from %1 to label %try.cont649 650catch.dispatch1:                                  ; preds = %bb1651  %4 = catchswitch within none [label %catch.start1] unwind to caller652 653catch.start1:                                     ; preds = %catch.dispatch1654  %5 = catchpad within %4 [ptr null]655  %6 = call ptr @llvm.wasm.get.exception(token %5)656  %7 = call i32 @llvm.wasm.get.ehselector(token %5)657  catchret from %5 to label %try.cont658 659try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1660  ret void661}662 663; Similar situation as @unwind_mismatches_1. Here 'call @qux''s original unwind664; destination was the caller, but after control flow linearization, their unwind665; destination incorrectly becomes 'C0' within the function. We fix this by666; wrapping the call with a nested try_table-end_try_table that jumps to a667; trampoline BB where rethrow the exception to the caller.668 669; Because 'call @qux' pops an argument pushed by 'i32.const 5' from stack, the670; nested 'try_table' should be placed before `i32.const 5', not between671; 'i32.const 5' and 'call @qux'.672 673; NOSORT-LABEL: unwind_mismatches_3:674; NOSORT: block     exnref675; NOSORT:   block     i32676; NOSORT:     try_table    (catch __cpp_exception 0) # 0: down to label[[L0:[0-9]+]]677; NOSORT:       call  foo678; --- nested try_table-end_try_table starts (call unwind mismatch)679; NOSORT:       try_table    (catch_all_ref 2)      # 2: down to label[[L1:[0-9]+]]680; NOSORT:         i32.const  5681; NOSORT:         call  qux682; NOSORT:       end_try_table683; --- nested try_table-end_try_table ends (call unwind mismatch)684; NOSORT:       return685; NOSORT:     end_try_table686; NOSORT:   end_block                               # label[[L0]]:687; NOSORT:   return688; NOSORT: end_block                               # label[[L1]]:689; NOSORT: throw_ref690define i32 @unwind_mismatches_3() personality ptr @__gxx_wasm_personality_v0 {691bb0:692  invoke void @foo()693          to label %bb1 unwind label %catch.dispatch0694 695bb1:                                              ; preds = %bb0696  %0 = call i32 @qux(i32 5)697  ret i32 %0698 699catch.dispatch0:                                  ; preds = %bb0700  %1 = catchswitch within none [label %catch.start0] unwind to caller701 702catch.start0:                                     ; preds = %catch.dispatch0703  %2 = catchpad within %1 [ptr null]704  %3 = call ptr @llvm.wasm.get.exception(token %2)705  %j = call i32 @llvm.wasm.get.ehselector(token %2)706  catchret from %2 to label %try.cont707 708try.cont:                                         ; preds = %catch.start0709  ret i32 0710}711 712; We have two call unwind unwind mismatches:713; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the714;   CFG, when it is supposed to unwind to another EH pad.715; - A may-throw instruction unwinds to an incorrect EH pad after linearizing the716;   CFG, when it is supposed to unwind to the caller.717; We also have a catch unwind mismatch: If an exception is not caught by the718; first catch because it is a non-C++ exception, it shouldn't unwind to the next719; catch, but it should unwind to the caller.720 721; NOSORT-LABEL: unwind_mismatches_4:722; NOSORT: block     exnref723; NOSORT:   block724; NOSORT:     block     i32725; NOSORT:       try_table    (catch __cpp_exception 0)       # 0: down to label[[L0:[0-9]+]]726; NOSORT:         block     exnref727; NOSORT:           block     i32728; --- nested try_table-end_try_table starts (catch unwind mismatch)729; NOSORT:           try_table    (catch_all_ref 5)           # 5: down to label[[L1:[0-9]+]]730; NOSORT:             try_table    (catch __cpp_exception 1) # 1: down to label[[L2:[0-9]+]]731; NOSORT:               call  foo732; --- nested try_table-end_try_table starts (call unwind mismatch)733; NOSORT:               try_table    (catch_all_ref 3)       # 3: down to label[[L3:[0-9]+]]734; NOSORT:                 call  bar735; NOSORT:               end_try_table736; --- nested try_table-end_try_table ends (call unwind mismatch)737; NOSORT:             end_try_table738; NOSORT:           end_try_table739; --- nested try_table-end_try_table ends (catch unwind mismatch)740; NOSORT:           end_block                                # label[[L2]]:741; NOSORT:           call  __cxa_begin_catch742; --- nested try_table-end_try_table starts (call unwind mismatch)743; NOSORT:           try_table    (catch_all_ref 4)           # 4: down to label[[L1]]744; NOSORT:             call  __cxa_end_catch745; NOSORT:           end_try_table746; --- nested try_table-end_try_table ends (call unwind mismatch)747; NOSORT:         end_block                                  # label[[L3]]:748; NOSORT:         throw_ref749; NOSORT:       end_try_table750; NOSORT:     end_block                                      # label[[L0]]:751; NOSORT:     call  __cxa_begin_catch752; NOSORT:     call  __cxa_end_catch753; NOSORT:   end_block                                        # label74:754; NOSORT:   return755; NOSORT: end_block                                          # label[[L1]]:756; NOSORT: throw_ref757define void @unwind_mismatches_4() personality ptr @__gxx_wasm_personality_v0 {758bb0:759  invoke void @foo()760          to label %bb1 unwind label %catch.dispatch0761 762bb1:                                              ; preds = %bb0763  invoke void @bar()764          to label %try.cont unwind label %catch.dispatch1765 766catch.dispatch0:                                  ; preds = %bb0767  %0 = catchswitch within none [label %catch.start0] unwind to caller768 769catch.start0:                                     ; preds = %catch.dispatch0770  %1 = catchpad within %0 [ptr null]771  %2 = call ptr @llvm.wasm.get.exception(token %1)772  %3 = call i32 @llvm.wasm.get.ehselector(token %1)773  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]774  call void @__cxa_end_catch() [ "funclet"(token %1) ]775  catchret from %1 to label %try.cont776 777catch.dispatch1:                                  ; preds = %bb1778  %5 = catchswitch within none [label %catch.start1] unwind to caller779 780catch.start1:                                     ; preds = %catch.dispatch1781  %6 = catchpad within %5 [ptr null]782  %7 = call ptr @llvm.wasm.get.exception(token %6)783  %8 = call i32 @llvm.wasm.get.ehselector(token %6)784  %9 = call ptr @__cxa_begin_catch(ptr %7) [ "funclet"(token %6) ]785  call void @__cxa_end_catch() [ "funclet"(token %6) ]786  catchret from %6 to label %try.cont787 788try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1789  ret void790}791 792; This crashed when updating EHPadStack within fixCallUniwindMismatch had a bug.793; This should not crash and a nested try_table-end_try_table has to be created794; around 'call @baz', because the initial TRY_TABLE placement for 'call @quux'795; was done before 'call @baz' because 'call @baz''s return value is stackified.796 797; CHECK-LABEL: unwind_mismatches_5:798; CHECK: block     exnref799; CHECK:   block800; CHECK:     block     exnref801; CHECK:       try_table    (catch_all_ref 0)    # 0: down to label[[L0:[0-9]+]]802; --- nested try_table-end_try_table starts (call unwind mismatch)803; CHECK:         try_table    (catch_all_ref 3)  # 3: down to label[[L1:[0-9]+]]804; CHECK:           call  baz805; CHECK:         end_try_table806; --- nested try_table-end_try_table ends (call unwind mismatch)807; CHECK:         call  quux808; CHECK:       end_try_table809; CHECK:     end_block                           # label[[L0]]:810; CHECK:     throw_ref811; CHECK:   end_block812; CHECK:   unreachable813; CHECK: end_block                               # label[[L1]]:814; CHECK: throw_ref815define void @unwind_mismatches_5() personality ptr @__gxx_wasm_personality_v0 {816entry:817  %call = call i32 @baz()818  invoke void @quux(i32 %call)819          to label %invoke.cont unwind label %ehcleanup820 821ehcleanup:                                        ; preds = %entry822  %0 = cleanuppad within none []823  cleanupret from %0 unwind to caller824 825invoke.cont:                                      ; preds = %entry826  unreachable827}828 829; The structure is similar to unwind_mismatches_0, where the call to 'bar''s830; original unwind destination is catch.dispatch1 but after placing markers it831; unwinds to catch.dispatch0, which we fix. This additionally has a loop before832; the real unwind destination (catch.dispatch1). This makes sure the code833; generation works when the unwind destination has an end_loop before834; end_try_table before the mismatch fixing.835 836; NOSORT-LABEL: unwind_mismatches_with_loop:837; NOSORT: block     exnref838; NOSORT:   block     i32839; NOSORT:     try_table    (catch __cpp_exception 0)           # 0: down to label[[L0:[0-9]+]]840; NOSORT:       block     exnref841; NOSORT:         block842; NOSORT:           block     i32843; --- nested try_table-end_try_table starts (catch unwind mismatch)844; NOSORT:             try_table    (catch_all_ref 5)           # 5: down to label[[L1:[0-9]+]]845; NOSORT:               try_table    (catch __cpp_exception 1) # 1: down to label[[L2:[0-9]+]]846; NOSORT:                 call  foo847; --- nested try_table-end_try_table starts (call unwind mismatch)848; NOSORT:                 try_table    (catch_all_ref 4)       # 4: down to label[[L3:[0-9]+]]849; NOSORT:                   call  bar850; NOSORT:                 end_try_table851; --- nested try_table-end_try_table ends (call unwind mismatch)852; NOSORT:               end_try_table853; NOSORT:             end_try_table854; --- nested try_table-end_try_table ends (catch unwind mismatch)855; NOSORT:           end_block                                  # label[[L2]]:856; NOSORT:         end_block857; NOSORT:         loop858; NOSORT:           call  foo859; NOSORT:         end_loop860; NOSORT:         unreachable861; NOSORT:       end_block                                      # label[[L3]]:862; NOSORT:       throw_ref863; NOSORT:     end_try_table864; NOSORT:   end_block                                          # label[[L0]]:865; NOSORT:   return866; NOSORT: end_block                                            # label[[L1]]:867; NOSORT: throw_ref868define void @unwind_mismatches_with_loop() personality ptr @__gxx_wasm_personality_v0 {869bb0:870  invoke void @foo()871          to label %bb1 unwind label %catch.dispatch0872 873bb1:                                              ; preds = %bb0874  invoke void @bar()875          to label %bb2 unwind label %catch.dispatch1876 877catch.dispatch0:                                  ; preds = %bb0878  %0 = catchswitch within none [label %catch.start0] unwind to caller879 880catch.start0:                                     ; preds = %catch.dispatch0881  %1 = catchpad within %0 [ptr null]882  %2 = call ptr @llvm.wasm.get.exception(token %1)883  %3 = call i32 @llvm.wasm.get.ehselector(token %1)884  catchret from %1 to label %bb2885 886bb2:887  invoke void @foo()888          to label %bb3 unwind label %catch.dispatch1889 890bb3:                                             ; preds = %bb14891  br label %bb2892 893catch.dispatch1:                                  ; preds = %bb1894  %4 = catchswitch within none [label %catch.start1] unwind to caller895 896catch.start1:                                     ; preds = %catch.dispatch1897  %5 = catchpad within %4 [ptr null]898  %6 = call ptr @llvm.wasm.get.exception(token %5)899  %7 = call i32 @llvm.wasm.get.ehselector(token %5)900  catchret from %5 to label %try.cont901 902try.cont:                                         ; preds = %catch.start1, %catch.start0, %bb1903  ret void904}905 906; Tests the case when TEE stackifies a register in RegStackify but it gets907; unstackified in fixCallUnwindMismatches in CFGStackify.908 909; NOSORT-LOCALS-LABEL: unstackify_when_fixing_unwind_mismatch:910define void @unstackify_when_fixing_unwind_mismatch(i32 %x) personality ptr @__gxx_wasm_personality_v0 {911bb0:912  invoke void @foo()913          to label %bb1 unwind label %catch.dispatch0914 915bb1:                                              ; preds = %bb0916  %t = add i32 %x, 4917  ; This %addr is used in multiple places, so tee is introduced in RegStackify,918  ; which stackifies the use of %addr in store instruction. A tee has two dest919  ; registers, the first of which is stackified and the second is not.920  ; But when we introduce a nested try_table-end_try_table in921  ; fixCallUnwindMismatches in CFGStackify, we end up unstackifying the first922  ; dest register. In that case, we convert that tee into a copy.923  %addr = inttoptr i32 %t to ptr924  %load = load i32, ptr %addr925  %call = call i32 @baz()926  %add = add i32 %load, %call927  store i32 %add, ptr %addr928  ret void929; NOSORT-LOCALS:       i32.add930; NOSORT-LOCALS-NOT:   local.tee931; NOSORT-LOCALS-NEXT:  local.set932 933catch.dispatch0:                                  ; preds = %bb0934  %0 = catchswitch within none [label %catch.start0] unwind to caller935 936catch.start0:                                     ; preds = %catch.dispatch0937  %1 = catchpad within %0 [ptr null]938  %2 = call ptr @llvm.wasm.get.exception(token %1)939  %3 = call i32 @llvm.wasm.get.ehselector(token %1)940  catchret from %1 to label %try.cont941 942try.cont:                                         ; preds = %catch.start0943  ret void944}945 946; In CFGSort, EH pads should be sorted as soon as it is available and947; 'Preferred' queue and should NOT be entered into 'Ready' queue unless we are948; in the middle of sorting another region that does not contain the EH pad. In949; this example, 'catch.start' should be sorted right after 'if.then' is sorted950; (before 'cont' is sorted) and there should not be any unwind destination951; mismatches in CFGStackify.952 953; NOOPT-LABEL: cfg_sort_order:954; NOOPT: block955; NOOPT:   block956; NOOPT:     block     i32957; NOOPT:       try_table    (catch __cpp_exception 0)958; NOOPT:         call  foo959; NOOPT:       end_try_table960; NOOPT:     end_block961; NOOPT:     call  __cxa_begin_catch962; NOOPT:     call  __cxa_end_catch963; NOOPT:   end_block964; NOOPT:   call  foo965; NOOPT: end_block966; NOOPT: return967define void @cfg_sort_order(i32 %arg) personality ptr @__gxx_wasm_personality_v0 {968entry:969  %tobool = icmp ne i32 %arg, 0970  br i1 %tobool, label %if.then, label %if.end971 972catch.dispatch:                                   ; preds = %if.then973  %0 = catchswitch within none [label %catch.start] unwind to caller974 975catch.start:                                      ; preds = %catch.dispatch976  %1 = catchpad within %0 [ptr null]977  %2 = call ptr @llvm.wasm.get.exception(token %1)978  %3 = call i32 @llvm.wasm.get.ehselector(token %1)979  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]980  call void @__cxa_end_catch() [ "funclet"(token %1) ]981  catchret from %1 to label %if.end982 983if.then:                                          ; preds = %entry984  invoke void @foo()985          to label %cont unwind label %catch.dispatch986 987cont:                                             ; preds = %if.then988  call void @foo()989  br label %if.end990 991if.end:                                           ; preds = %cont, %catch.start, %entry992  ret void993}994 995; Intrinsics like memcpy, memmove, and memset don't throw and are lowered into996; calls to external symbols (not global addresses) in instruction selection,997; which will be eventually lowered to library function calls.998; Because this test runs with -wasm-disable-ehpad-sort, these library calls in999; invoke.cont BB fall within try~end_try, but they shouldn't cause crashes or1000; unwinding destination mismatches in CFGStackify.1001 1002; NOSORT-LABEL: mem_intrinsics:1003; NOSORT: block     exnref1004; NOSORT:   try_table    (catch_all_ref 0)1005; NOSORT:     call  foo1006; NOSORT:     call  memcpy1007; NOSORT:     call  memmove1008; NOSORT:     call  memset1009; NOSORT:     return1010; NOSORT:   end_try_table1011; NOSORT: end_block1012; NOSORT: throw_ref1013define void @mem_intrinsics(ptr %a, ptr %b) personality ptr @__gxx_wasm_personality_v0 {1014entry:1015  %o = alloca %class.Object, align 11016  invoke void @foo()1017          to label %invoke.cont unwind label %ehcleanup1018 1019invoke.cont:                                      ; preds = %entry1020  call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %b, i32 100, i1 false)1021  call void @llvm.memmove.p0.p0.i32(ptr %a, ptr %b, i32 100, i1 false)1022  call void @llvm.memset.p0.i32(ptr %a, i8 0, i32 100, i1 false)1023  %call = call ptr @_ZN6ObjectD2Ev(ptr %o)1024  ret void1025 1026ehcleanup:                                        ; preds = %entry1027  %0 = cleanuppad within none []1028  %call2 = call ptr @_ZN6ObjectD2Ev(ptr %o) [ "funclet"(token %0) ]1029  cleanupret from %0 unwind to caller1030}1031 1032; Tests if 'try_table' marker is placed correctly. In this test, 'try_table'1033; should be placed before the call to 'nothrow_i32' and not between the call to1034; 'nothrow_i32' and 'fun', because the return value of 'nothrow_i32' is1035; stackified and pushed onto the stack to be consumed by the call to 'fun'.1036 1037; CHECK-LABEL: try_table_marker_with_stackified_input:1038; CHECK: try_table    (catch_all 0)1039; CHECK: call  nothrow_i321040; CHECK: call  fun1041define void @try_table_marker_with_stackified_input() personality ptr @__gxx_wasm_personality_v0 {1042entry:1043  %call = call i32 @nothrow_i32()1044  invoke void @fun(i32 %call)1045          to label %invoke.cont unwind label %terminate1046 1047invoke.cont:                                      ; preds = %entry1048  ret void1049 1050terminate:                                        ; preds = %entry1051  %0 = cleanuppad within none []1052  call void @_ZSt9terminatev() [ "funclet"(token %0) ]1053  unreachable1054}1055 1056; This crashed on debug mode (= when NDEBUG is not defined) when the logic for1057; computing the innermost region was not correct, in which a loop region1058; contains an exception region. This should pass CFGSort without crashing.1059define void @loop_exception_region() personality ptr @__gxx_wasm_personality_v0 {1060entry:1061  %e = alloca %class.MyClass, align 41062  br label %for.cond1063 1064for.cond:                                         ; preds = %for.inc, %entry1065  %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]1066  %cmp = icmp slt i32 %i.0, 91067  br i1 %cmp, label %for.body, label %for.end1068 1069for.body:                                         ; preds = %for.cond1070  invoke void @quux(i32 %i.0)1071          to label %for.inc unwind label %catch.dispatch1072 1073catch.dispatch:                                   ; preds = %for.body1074  %0 = catchswitch within none [label %catch.start] unwind to caller1075 1076catch.start:                                      ; preds = %catch.dispatch1077  %1 = catchpad within %0 [ptr @_ZTI7MyClass]1078  %2 = call ptr @llvm.wasm.get.exception(token %1)1079  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1080  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTI7MyClass)1081  %matches = icmp eq i32 %3, %41082  br i1 %matches, label %catch, label %rethrow1083 1084catch:                                            ; preds = %catch.start1085  %5 = call ptr @__cxa_get_exception_ptr(ptr %2) [ "funclet"(token %1) ]1086  %call = call ptr @_ZN7MyClassC2ERKS_(ptr %e, ptr dereferenceable(4) %5) [ "funclet"(token %1) ]1087  %6 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]1088  %7 = load i32, ptr %e, align 41089  invoke void @quux(i32 %7) [ "funclet"(token %1) ]1090          to label %invoke.cont2 unwind label %ehcleanup1091 1092invoke.cont2:                                     ; preds = %catch1093  %call3 = call ptr @_ZN7MyClassD2Ev(ptr %e) [ "funclet"(token %1) ]1094  call void @__cxa_end_catch() [ "funclet"(token %1) ]1095  catchret from %1 to label %for.inc1096 1097rethrow:                                          ; preds = %catch.start1098  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]1099  unreachable1100 1101for.inc:                                          ; preds = %invoke.cont2, %for.body1102  %inc = add nsw i32 %i.0, 11103  br label %for.cond1104 1105ehcleanup:                                        ; preds = %catch1106  %8 = cleanuppad within %1 []1107  %call4 = call ptr @_ZN7MyClassD2Ev(ptr %e) [ "funclet"(token %8) ]1108  invoke void @__cxa_end_catch() [ "funclet"(token %8) ]1109          to label %invoke.cont6 unwind label %terminate71110 1111invoke.cont6:                                     ; preds = %ehcleanup1112  cleanupret from %8 unwind to caller1113 1114for.end:                                          ; preds = %for.cond1115  ret void1116 1117terminate7:                                       ; preds = %ehcleanup1118  %9 = cleanuppad within %8 []1119  call void @_ZSt9terminatev() [ "funclet"(token %9) ]1120  unreachable1121}1122 1123; Here exceptions are semantically contained in a loop. 'ehcleanup' BB belongs1124; to the exception, but does not belong to the loop (because it does not have a1125; path back to the loop header), and is placed after the loop latch block1126; 'invoke.cont' intentionally. This tests if 'end_loop' marker is placed1127; correctly not right after 'invoke.cont' part but after 'ehcleanup' part.1128; NOSORT-LABEL: loop_contains_exception:1129; NOSORT: loop1130; NOSORT:   try_table    (catch __cpp_exception 0)1131; NOSORT:   end_try_table1132; NOSORT:   try_table    (catch_all 0)1133; NOSORT:   end_try_table1134; NOSORT: end_loop1135define void @loop_contains_exception(i32 %n) personality ptr @__gxx_wasm_personality_v0 {1136entry:1137  br label %while.cond1138 1139while.cond:                                       ; preds = %invoke.cont, %entry1140  %n.addr.0 = phi i32 [ %n, %entry ], [ %dec, %invoke.cont ]1141  %tobool = icmp ne i32 %n.addr.0, 01142  br i1 %tobool, label %while.body, label %while.end1143 1144while.body:                                       ; preds = %while.cond1145  %dec = add nsw i32 %n.addr.0, -11146  invoke void @foo()1147          to label %while.end unwind label %catch.dispatch1148 1149catch.dispatch:                                   ; preds = %while.body1150  %0 = catchswitch within none [label %catch.start] unwind to caller1151 1152catch.start:                                      ; preds = %catch.dispatch1153  %1 = catchpad within %0 [ptr null]1154  %2 = call ptr @llvm.wasm.get.exception(token %1)1155  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1156  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]1157  invoke void @__cxa_end_catch() [ "funclet"(token %1) ]1158          to label %invoke.cont unwind label %ehcleanup1159 1160invoke.cont:                                      ; preds = %catch.start1161  catchret from %1 to label %while.cond1162 1163ehcleanup:                                        ; preds = %catch.start1164  %5 = cleanuppad within %1 []1165  call void @_ZSt9terminatev() [ "funclet"(token %5) ]1166  unreachable1167 1168while.end:                                        ; preds = %while.body, %while.cond1169  ret void1170}1171 1172; Regression test for WasmEHFuncInfo's reverse mapping bug. 'UnwindDestToSrc'1173; should return a vector and not a single BB, which was incorrect.1174; This was reduced by bugpoint and should not crash in CFGStackify.1175define void @wasm_eh_func_info_regression_test() personality ptr @__gxx_wasm_personality_v0 {1176entry:1177  invoke void @foo()1178          to label %invoke.cont unwind label %catch.dispatch1179 1180catch.dispatch:                                   ; preds = %entry1181  %0 = catchswitch within none [label %catch.start] unwind label %ehcleanup221182 1183catch.start:                                      ; preds = %catch.dispatch1184  %1 = catchpad within %0 [ptr @_ZTIi]1185  %2 = call ptr @llvm.wasm.get.exception(token %1)1186  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1187  invoke void @__cxa_throw(ptr null, ptr null, ptr null) #1 [ "funclet"(token %1) ]1188          to label %unreachable unwind label %catch.dispatch21189 1190catch.dispatch2:                                  ; preds = %catch.start1191  %4 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup1192 1193catch.start3:                                     ; preds = %catch.dispatch21194  %5 = catchpad within %4 [ptr @_ZTIi]1195  %6 = call ptr @llvm.wasm.get.exception(token %5)1196  %7 = call i32 @llvm.wasm.get.ehselector(token %5)1197  catchret from %5 to label %try.cont1198 1199try.cont:                                         ; preds = %catch.start31200  invoke void @foo() [ "funclet"(token %1) ]1201          to label %invoke.cont8 unwind label %ehcleanup1202 1203invoke.cont8:                                     ; preds = %try.cont1204  invoke void @__cxa_throw(ptr null, ptr null, ptr null) #1 [ "funclet"(token %1) ]1205          to label %unreachable unwind label %catch.dispatch111206 1207catch.dispatch11:                                 ; preds = %invoke.cont81208  %8 = catchswitch within %1 [label %catch.start12] unwind label %ehcleanup1209 1210catch.start12:                                    ; preds = %catch.dispatch111211  %9 = catchpad within %8 [ptr @_ZTIi]1212  %10 = call ptr @llvm.wasm.get.exception(token %9)1213  %11 = call i32 @llvm.wasm.get.ehselector(token %9)1214  unreachable1215 1216invoke.cont:                                      ; preds = %entry1217  unreachable1218 1219ehcleanup:                                        ; preds = %catch.dispatch11, %try.cont, %catch.dispatch21220  %12 = cleanuppad within %1 []1221  cleanupret from %12 unwind label %ehcleanup221222 1223ehcleanup22:                                      ; preds = %ehcleanup, %catch.dispatch1224  %13 = cleanuppad within none []1225  cleanupret from %13 unwind to caller1226 1227unreachable:                                      ; preds = %invoke.cont8, %catch.start1228  unreachable1229}1230 1231; void exception_grouping_0() {1232;   try {1233;     try {1234;       throw 0;1235;     } catch (int) {1236;     }1237;   } catch (int) {1238;   }1239; }1240;1241; Regression test for a WebAssemblyException grouping bug. After catchswitches1242; are removed, EH pad catch.start2 is dominated by catch.start, but because1243; catch.start2 is the unwind destination of catch.start, it should not be1244; included in catch.start's exception. Also, after we take catch.start2's1245; exception out of catch.start's exception, we have to take out try.cont8 out of1246; catch.start's exception, because it has a predecessor in catch.start2.1247define void @exception_grouping_0() personality ptr @__gxx_wasm_personality_v0 {1248entry:1249  %exception = call ptr @__cxa_allocate_exception(i32 4) #01250  store i32 0, ptr %exception, align 161251  invoke void @__cxa_throw(ptr %exception, ptr @_ZTIi, ptr null) #11252          to label %unreachable unwind label %catch.dispatch1253 1254catch.dispatch:                                   ; preds = %entry1255  %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch11256 1257catch.start:                                      ; preds = %catch.dispatch1258  %1 = catchpad within %0 [ptr @_ZTIi]1259  %2 = call ptr @llvm.wasm.get.exception(token %1)1260  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1261  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #01262  %matches = icmp eq i32 %3, %41263  br i1 %matches, label %catch, label %rethrow1264 1265catch:                                            ; preds = %catch.start1266  %5 = call ptr @__cxa_begin_catch(ptr %2) #0 [ "funclet"(token %1) ]1267  %6 = load i32, ptr %5, align 41268  call void @__cxa_end_catch() #0 [ "funclet"(token %1) ]1269  catchret from %1 to label %catchret.dest1270 1271catchret.dest:                                    ; preds = %catch1272  br label %try.cont1273 1274rethrow:                                          ; preds = %catch.start1275  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]1276          to label %unreachable unwind label %catch.dispatch11277 1278catch.dispatch1:                                  ; preds = %rethrow, %catch.dispatch1279  %7 = catchswitch within none [label %catch.start2] unwind to caller1280 1281catch.start2:                                     ; preds = %catch.dispatch11282  %8 = catchpad within %7 [ptr @_ZTIi]1283  %9 = call ptr @llvm.wasm.get.exception(token %8)1284  %10 = call i32 @llvm.wasm.get.ehselector(token %8)1285  %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #01286  %matches3 = icmp eq i32 %10, %111287  br i1 %matches3, label %catch5, label %rethrow41288 1289catch5:                                           ; preds = %catch.start21290  %12 = call ptr @__cxa_begin_catch(ptr %9) #0 [ "funclet"(token %8) ]1291  %13 = load i32, ptr %12, align 41292  call void @__cxa_end_catch() #0 [ "funclet"(token %8) ]1293  catchret from %8 to label %catchret.dest71294 1295catchret.dest7:                                   ; preds = %catch51296  br label %try.cont81297 1298rethrow4:                                         ; preds = %catch.start21299  call void @llvm.wasm.rethrow() #1 [ "funclet"(token %8) ]1300  unreachable1301 1302try.cont8:                                        ; preds = %try.cont, %catchret.dest71303  ret void1304 1305try.cont:                                         ; preds = %catchret.dest1306  br label %try.cont81307 1308unreachable:                                      ; preds = %rethrow, %entry1309  unreachable1310}1311 1312; Test for WebAssemblyException grouping. This test is hand-modified to generate1313; this structure:1314; catch.start dominates catch.start4 and catch.start4 dominates catch.start12,1315; so the after dominator-based grouping, we end up with:1316; catch.start's exception > catch4.start's exception > catch12.start's exception1317; (> here represents subexception relationship)1318;1319; But the unwind destination chain is catch.start -> catch.start4 ->1320; catch.start12. So all these subexception relationship should be deconstructed.1321; We have to make sure to take out catch.start4's exception out of catch.start's1322; exception first, before taking out catch.start12's exception out of1323; catch.start4's exception; otherwise we end up with an incorrect relationship1324; of catch.start's exception > catch.start12's exception.1325define void @exception_grouping_1() personality ptr @__gxx_wasm_personality_v0 {1326entry:1327  invoke void @foo()1328          to label %invoke.cont unwind label %catch.dispatch1329 1330invoke.cont:                                      ; preds = %entry1331  invoke void @foo()1332          to label %invoke.cont1 unwind label %catch.dispatch1333 1334invoke.cont1:                                     ; preds = %invoke.cont1335  invoke void @foo()1336          to label %try.cont18 unwind label %catch.dispatch1337 1338catch.dispatch11:                                 ; preds = %rethrow6, %catch.dispatch31339  %0 = catchswitch within none [label %catch.start12] unwind to caller1340 1341catch.start12:                                    ; preds = %catch.dispatch111342  %1 = catchpad within %0 [ptr @_ZTIi]1343  %2 = call ptr @llvm.wasm.get.exception(token %1)1344  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1345  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #01346  %matches13 = icmp eq i32 %3, %41347  br i1 %matches13, label %catch15, label %rethrow141348 1349catch15:                                          ; preds = %catch.start121350  %5 = call ptr @__cxa_begin_catch(ptr %2) #0 [ "funclet"(token %1) ]1351  %6 = load i32, ptr %5, align 41352  call void @__cxa_end_catch() #0 [ "funclet"(token %1) ]1353  catchret from %1 to label %try.cont181354 1355rethrow14:                                        ; preds = %catch.start121356  call void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]1357  unreachable1358 1359catch.dispatch3:                                  ; preds = %rethrow, %catch.dispatch1360  %7 = catchswitch within none [label %catch.start4] unwind label %catch.dispatch111361 1362catch.start4:                                     ; preds = %catch.dispatch31363  %8 = catchpad within %7 [ptr @_ZTIi]1364  %9 = call ptr @llvm.wasm.get.exception(token %8)1365  %10 = call i32 @llvm.wasm.get.ehselector(token %8)1366  %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #01367  %matches5 = icmp eq i32 %10, %111368  br i1 %matches5, label %catch7, label %rethrow61369 1370catch7:                                           ; preds = %catch.start41371  %12 = call ptr @__cxa_begin_catch(ptr %9) #0 [ "funclet"(token %8) ]1372  %13 = load i32, ptr %12, align 41373  call void @__cxa_end_catch() #0 [ "funclet"(token %8) ]1374  catchret from %8 to label %try.cont181375 1376rethrow6:                                         ; preds = %catch.start41377  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %8) ]1378          to label %unreachable unwind label %catch.dispatch111379 1380catch.dispatch:                                   ; preds = %invoke.cont1, %invoke.cont, %entry1381  %14 = catchswitch within none [label %catch.start] unwind label %catch.dispatch31382 1383catch.start:                                      ; preds = %catch.dispatch1384  %15 = catchpad within %14 [ptr @_ZTIi]1385  %16 = call ptr @llvm.wasm.get.exception(token %15)1386  %17 = call i32 @llvm.wasm.get.ehselector(token %15)1387  %18 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #01388  %matches = icmp eq i32 %17, %181389  br i1 %matches, label %catch, label %rethrow1390 1391catch:                                            ; preds = %catch.start1392  %19 = call ptr @__cxa_begin_catch(ptr %16) #0 [ "funclet"(token %15) ]1393  %20 = load i32, ptr %19, align 41394  call void @__cxa_end_catch() #0 [ "funclet"(token %15) ]1395  catchret from %15 to label %try.cont181396 1397rethrow:                                          ; preds = %catch.start1398  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %15) ]1399          to label %unreachable unwind label %catch.dispatch31400 1401try.cont18:                                       ; preds = %catch, %catch7, %catch15, %invoke.cont11402  ret void1403 1404unreachable:                                      ; preds = %rethrow, %rethrow61405  unreachable1406}1407 1408; void exception_grouping_2() {1409;   try {1410;     try {1411;       throw 0;1412;     } catch (int) { // (a)1413;     }1414;   } catch (int) {   // (b)1415;   }1416;   try {1417;     foo();1418;   } catch (int) {   // (c)1419;   }1420; }1421;1422; Regression test for an ExceptionInfo grouping bug. Because the first (inner)1423; try always throws, both EH pads (b) (catch.start2) and (c) (catch.start10) are1424; dominated by EH pad (a) (catch.start), even though they are not semantically1425; contained in (a)'s exception. Because (a)'s unwind destination is (b), (b)'s1426; exception is taken out of (a)'s. But because (c) is reachable from (b), we1427; should make sure to take out (c)'s exception out of (a)'s exception too.1428define void @exception_grouping_2() personality ptr @__gxx_wasm_personality_v0 {1429entry:1430  %exception = call ptr @__cxa_allocate_exception(i32 4) #11431  store i32 0, ptr %exception, align 161432  invoke void @__cxa_throw(ptr %exception, ptr @_ZTIi, ptr null) #31433          to label %unreachable unwind label %catch.dispatch1434 1435catch.dispatch:                                   ; preds = %entry1436  %0 = catchswitch within none [label %catch.start] unwind label %catch.dispatch11437 1438catch.start:                                      ; preds = %catch.dispatch1439  %1 = catchpad within %0 [ptr @_ZTIi]1440  %2 = call ptr @llvm.wasm.get.exception(token %1)1441  %3 = call i32 @llvm.wasm.get.ehselector(token %1)1442  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #11443  %matches = icmp eq i32 %3, %41444  br i1 %matches, label %catch, label %rethrow1445 1446catch:                                            ; preds = %catch.start1447  %5 = call ptr @__cxa_begin_catch(ptr %2) #1 [ "funclet"(token %1) ]1448  %6 = load i32, ptr %5, align 41449  call void @__cxa_end_catch() #1 [ "funclet"(token %1) ]1450  catchret from %1 to label %try.cont81451 1452rethrow:                                          ; preds = %catch.start1453  invoke void @llvm.wasm.rethrow() #3 [ "funclet"(token %1) ]1454          to label %unreachable unwind label %catch.dispatch11455 1456catch.dispatch1:                                  ; preds = %rethrow, %catch.dispatch1457  %7 = catchswitch within none [label %catch.start2] unwind to caller1458 1459catch.start2:                                     ; preds = %catch.dispatch11460  %8 = catchpad within %7 [ptr @_ZTIi]1461  %9 = call ptr @llvm.wasm.get.exception(token %8)1462  %10 = call i32 @llvm.wasm.get.ehselector(token %8)1463  %11 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #11464  %matches3 = icmp eq i32 %10, %111465  br i1 %matches3, label %catch5, label %rethrow41466 1467catch5:                                           ; preds = %catch.start21468  %12 = call ptr @__cxa_begin_catch(ptr %9) #1 [ "funclet"(token %8) ]1469  %13 = load i32, ptr %12, align 41470  call void @__cxa_end_catch() #1 [ "funclet"(token %8) ]1471  catchret from %8 to label %try.cont81472 1473rethrow4:                                         ; preds = %catch.start21474  call void @llvm.wasm.rethrow() #3 [ "funclet"(token %8) ]1475  unreachable1476 1477try.cont8:                                        ; preds = %catch, %catch51478  invoke void @foo()1479          to label %try.cont16 unwind label %catch.dispatch91480 1481catch.dispatch9:                                  ; preds = %try.cont81482  %14 = catchswitch within none [label %catch.start10] unwind to caller1483 1484catch.start10:                                    ; preds = %catch.dispatch91485  %15 = catchpad within %14 [ptr @_ZTIi]1486  %16 = call ptr @llvm.wasm.get.exception(token %15)1487  %17 = call i32 @llvm.wasm.get.ehselector(token %15)1488  %18 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) #11489  %matches11 = icmp eq i32 %17, %181490  br i1 %matches11, label %catch13, label %rethrow121491 1492catch13:                                          ; preds = %catch.start101493  %19 = call ptr @__cxa_begin_catch(ptr %16) #1 [ "funclet"(token %15) ]1494  %20 = load i32, ptr %19, align 41495  call void @__cxa_end_catch() #1 [ "funclet"(token %15) ]1496  catchret from %15 to label %try.cont161497 1498rethrow12:                                        ; preds = %catch.start101499  call void @llvm.wasm.rethrow() #3 [ "funclet"(token %15) ]1500  unreachable1501 1502try.cont16:                                       ; preds = %try.cont8, %catch131503  ret void1504 1505unreachable:                                      ; preds = %rethrow, %entry1506  unreachable1507}1508 1509; Check if the unwind destination mismatch stats are correct1510; NOSORT: 23 wasm-cfg-stackify    - Number of call unwind mismatches found1511; NOSORT:  4 wasm-cfg-stackify    - Number of catch unwind mismatches found1512 1513declare void @foo()1514declare void @bar()1515declare i32 @baz()1516declare i32 @qux(i32)1517declare void @quux(i32)1518declare void @fun(i32)1519; Function Attrs: nounwind1520declare void @nothrow(i32) #01521; Function Attrs: nounwind1522declare i32 @nothrow_i32() #01523 1524; Function Attrs: nounwind1525declare ptr @_ZN6ObjectD2Ev(ptr returned) #01526@_ZTI7MyClass = external constant { ptr, ptr }, align 41527; Function Attrs: nounwind1528declare ptr @_ZN7MyClassD2Ev(ptr returned) #01529; Function Attrs: nounwind1530declare ptr @_ZN7MyClassC2ERKS_(ptr returned, ptr dereferenceable(4)) #01531 1532declare i32 @__gxx_wasm_personality_v0(...)1533; Function Attrs: nounwind1534declare ptr @llvm.wasm.get.exception(token) #01535; Function Attrs: nounwind1536declare i32 @llvm.wasm.get.ehselector(token) #01537declare ptr @__cxa_allocate_exception(i32) #01538declare void @__cxa_throw(ptr, ptr, ptr)1539; Function Attrs: noreturn1540declare void @llvm.wasm.rethrow() #11541; Function Attrs: nounwind1542declare i32 @llvm.eh.typeid.for(ptr) #01543 1544declare ptr @__cxa_begin_catch(ptr)1545declare void @__cxa_end_catch()1546declare ptr @__cxa_get_exception_ptr(ptr)1547declare void @_ZSt9terminatev()1548; Function Attrs: nounwind1549declare void @llvm.memcpy.p0.p0.i32(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i32, i1 immarg) #01550; Function Attrs: nounwind1551declare void @llvm.memmove.p0.p0.i32(ptr nocapture, ptr nocapture readonly, i32, i1 immarg) #01552; Function Attrs: nounwind1553declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #01554 1555attributes #0 = { nounwind }1556attributes #1 = { noreturn }1557