1; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling | FileCheck %s 2 3target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" 4target triple = "wasm32-unknown-unknown" 5 6@_ZTIi = external constant i8* 7@_ZTId = external constant i8* 8 9; Simple test case with two catch clauses 10; 11; void foo(); 12; void test0() { 13; try { 14; foo(); 15; } catch (int) { 16; } catch (double) { 17; } 18; } 19 20; CHECK-LABEL: test0 21; CHECK: block 22; CHECK: try 23; CHECK: call foo 24; CHECK: br 0 # 0: down to label1 25; CHECK: catch 26; CHECK: block 27; CHECK: br_if 0, {{.*}} # 0: down to label3 28; CHECK: i32.call $drop=, __cxa_begin_catch 29; CHECK: call __cxa_end_catch 30; CHECK: br 1 # 1: down to label1 31; CHECK: end_block # label3: 32; CHECK: block 33; CHECK: br_if 0, {{.*}} # 0: down to label4 34; CHECK: i32.call $drop=, __cxa_begin_catch 35; CHECK: call __cxa_end_catch 36; CHECK: br 1 # 1: down to label1 37; CHECK: end_block # label4: 38; CHECK: call __cxa_rethrow 39; CHECK: end_try # label1: 40; CHECK: end_block 41define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 42entry: 43 invoke void @foo() 44 to label %try.cont unwind label %catch.dispatch 45 46catch.dispatch: ; preds = %entry 47 %0 = catchswitch within none [label %catch.start] unwind to caller 48 49catch.start: ; preds = %catch.dispatch 50 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)] 51 %2 = call i8* @llvm.wasm.get.exception(token %1) 52 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 53 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 54 %matches = icmp eq i32 %3, %4 55 br i1 %matches, label %catch2, label %catch.fallthrough 56 57catch2: ; preds = %catch.start 58 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 59 call void @__cxa_end_catch() [ "funclet"(token %1) ] 60 catchret from %1 to label %try.cont 61 62catch.fallthrough: ; preds = %catch.start 63 %6 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*)) 64 %matches1 = icmp eq i32 %3, %6 65 br i1 %matches1, label %catch, label %rethrow 66 67catch: ; preds = %catch.fallthrough 68 %7 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 69 call void @__cxa_end_catch() [ "funclet"(token %1) ] 70 catchret from %1 to label %try.cont 71 72rethrow: ; preds = %catch.fallthrough 73 call void @__cxa_rethrow() [ "funclet"(token %1) ] 74 unreachable 75 76try.cont: ; preds = %entry, %catch, %catch2 77 ret void 78} 79 80; Nested try-catches within a catch 81; void test1() { 82; try { 83; foo(); 84; } catch (int) { 85; try { 86; foo(); 87; } catch (int) { 88; foo(); 89; } 90; } 91; } 92 93; CHECK-LABEL: test1 94; TODO Fill in CHECK lines once we fix ScopeTops info bug in D58605 95define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 96entry: 97 invoke void @foo() 98 to label %try.cont11 unwind label %catch.dispatch 99 100catch.dispatch: ; preds = %entry 101 %0 = catchswitch within none [label %catch.start] unwind to caller 102 103catch.start: ; preds = %catch.dispatch 104 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)] 105 %2 = call i8* @llvm.wasm.get.exception(token %1) 106 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 107 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 108 %matches = icmp eq i32 %3, %4 109 br i1 %matches, label %catch, label %rethrow 110 111catch: ; preds = %catch.start 112 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 113 %6 = bitcast i8* %5 to i32* 114 %7 = load i32, i32* %6, align 4 115 invoke void @foo() [ "funclet"(token %1) ] 116 to label %try.cont unwind label %catch.dispatch2 117 118catch.dispatch2: ; preds = %catch 119 %8 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup9 120 121catch.start3: ; preds = %catch.dispatch2 122 %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)] 123 %10 = call i8* @llvm.wasm.get.exception(token %9) 124 %11 = call i32 @llvm.wasm.get.ehselector(token %9) 125 %12 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 126 %matches4 = icmp eq i32 %11, %12 127 br i1 %matches4, label %catch6, label %rethrow5 128 129catch6: ; preds = %catch.start3 130 %13 = call i8* @__cxa_begin_catch(i8* %10) [ "funclet"(token %9) ] 131 %14 = bitcast i8* %13 to i32* 132 %15 = load i32, i32* %14, align 4 133 invoke void @foo() [ "funclet"(token %9) ] 134 to label %invoke.cont8 unwind label %ehcleanup 135 136invoke.cont8: ; preds = %catch6 137 call void @__cxa_end_catch() [ "funclet"(token %9) ] 138 catchret from %9 to label %try.cont 139 140rethrow5: ; preds = %catch.start3 141 invoke void @__cxa_rethrow() [ "funclet"(token %9) ] 142 to label %unreachable unwind label %ehcleanup9 143 144try.cont: ; preds = %catch, %invoke.cont8 145 call void @__cxa_end_catch() [ "funclet"(token %1) ] 146 catchret from %1 to label %try.cont11 147 148rethrow: ; preds = %catch.start 149 call void @__cxa_rethrow() [ "funclet"(token %1) ] 150 unreachable 151 152try.cont11: ; preds = %entry, %try.cont 153 ret void 154 155ehcleanup: ; preds = %catch6 156 %16 = cleanuppad within %9 [] 157 call void @__cxa_end_catch() [ "funclet"(token %16) ] 158 cleanupret from %16 unwind label %ehcleanup9 159 160ehcleanup9: ; preds = %ehcleanup, %rethrow5, %catch.dispatch2 161 %17 = cleanuppad within %1 [] 162 call void @__cxa_end_catch() [ "funclet"(token %17) ] 163 cleanupret from %17 unwind to caller 164 165unreachable: ; preds = %rethrow5 166 unreachable 167} 168 169; Nested loop within a catch clause 170; void test2() { 171; try { 172; foo(); 173; } catch (...) { 174; for (int i = 0; i < 50; i++) 175; foo(); 176; } 177; } 178 179; CHECK-LABEL: test2 180; CHECK: block 181; CHECK: try 182; CHECK: call foo 183; CHECK: br 0 # 0: down to label17 184; CHECK: catch 185; CHECK: i32.call $drop=, __cxa_begin_catch 186; CHECK: loop # label19: 187; CHECK: block 188; CHECK: block 189; CHECK: br_if 0, {{.*}} # 0: down to label21 190; CHECK: try 191; CHECK: call foo 192; CHECK: br 2 # 2: down to label20 193; CHECK: catch 194; CHECK: block 195; CHECK: try 196; CHECK: call __cxa_end_catch 197; CHECK: br 0 # 0: down to label24 198; CHECK: catch 199; CHECK: call __clang_call_terminate 200; CHECK: unreachable 201; CHECK: end_try # label24: 202; CHECK: end_block 203; CHECK: rethrow # to caller 204; CHECK: end_try 205; CHECK: end_block # label21: 206; CHECK: call __cxa_end_catch 207; CHECK: br 2 # 2: down to label17 208; CHECK: end_block # label20: 209; CHECK: br 0 # 0: up to label19 210; CHECK: end_loop 211; CHECK: end_try # label17: 212; CHECK: end_block 213define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 214entry: 215 invoke void @foo() 216 to label %try.cont unwind label %catch.dispatch 217 218catch.dispatch: ; preds = %entry 219 %0 = catchswitch within none [label %catch.start] unwind to caller 220 221catch.start: ; preds = %catch.dispatch 222 %1 = catchpad within %0 [i8* null] 223 %2 = call i8* @llvm.wasm.get.exception(token %1) 224 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 225 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 226 br label %for.cond 227 228for.cond: ; preds = %for.inc, %catch.start 229 %i.0 = phi i32 [ 0, %catch.start ], [ %inc, %for.inc ] 230 %cmp = icmp slt i32 %i.0, 50 231 br i1 %cmp, label %for.body, label %for.end 232 233for.body: ; preds = %for.cond 234 invoke void @foo() [ "funclet"(token %1) ] 235 to label %for.inc unwind label %ehcleanup 236 237for.inc: ; preds = %for.body 238 %inc = add nsw i32 %i.0, 1 239 br label %for.cond 240 241for.end: ; preds = %for.cond 242 call void @__cxa_end_catch() [ "funclet"(token %1) ] 243 catchret from %1 to label %try.cont 244 245try.cont: ; preds = %for.end, %entry 246 ret void 247 248ehcleanup: ; preds = %for.body 249 %5 = cleanuppad within %1 [] 250 invoke void @__cxa_end_catch() [ "funclet"(token %5) ] 251 to label %invoke.cont2 unwind label %terminate 252 253invoke.cont2: ; preds = %ehcleanup 254 cleanupret from %5 unwind to caller 255 256terminate: ; preds = %ehcleanup 257 %6 = cleanuppad within %5 [] 258 %7 = call i8* @llvm.wasm.get.exception(token %6) 259 call void @__clang_call_terminate(i8* %7) [ "funclet"(token %6) ] 260 unreachable 261} 262 263declare void @foo() 264declare void @bar() 265declare i32 @__gxx_wasm_personality_v0(...) 266declare i8* @llvm.wasm.get.exception(token) 267declare i32 @llvm.wasm.get.ehselector(token) 268declare i32 @llvm.eh.typeid.for(i8*) 269declare i8* @__cxa_begin_catch(i8*) 270declare void @__cxa_end_catch() 271declare void @__cxa_rethrow() 272declare void @__clang_call_terminate(i8*) 273declare void @_ZSt9terminatev() 274