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: try 22; CHECK: call foo 23; CHECK: catch 24; CHECK: block 25; CHECK: br_if 0, {{.*}} # 0: down to label2 26; CHECK: i32.call $drop=, __cxa_begin_catch 27; CHECK: call __cxa_end_catch 28; CHECK: br 1 # 1: down to label0 29; CHECK: end_block # label2: 30; CHECK: block 31; CHECK: br_if 0, {{.*}} # 0: down to label3 32; CHECK: i32.call $drop=, __cxa_begin_catch 33; CHECK: call __cxa_end_catch 34; CHECK: br 1 # 1: down to label0 35; CHECK: end_block # label3: 36; CHECK: call __cxa_rethrow 37; CHECK: end_try # label0: 38define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 39entry: 40 invoke void @foo() 41 to label %try.cont unwind label %catch.dispatch 42 43catch.dispatch: ; preds = %entry 44 %0 = catchswitch within none [label %catch.start] unwind to caller 45 46catch.start: ; preds = %catch.dispatch 47 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)] 48 %2 = call i8* @llvm.wasm.get.exception(token %1) 49 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 50 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 51 %matches = icmp eq i32 %3, %4 52 br i1 %matches, label %catch2, label %catch.fallthrough 53 54catch2: ; preds = %catch.start 55 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 56 call void @__cxa_end_catch() [ "funclet"(token %1) ] 57 catchret from %1 to label %try.cont 58 59catch.fallthrough: ; preds = %catch.start 60 %6 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*)) 61 %matches1 = icmp eq i32 %3, %6 62 br i1 %matches1, label %catch, label %rethrow 63 64catch: ; preds = %catch.fallthrough 65 %7 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 66 call void @__cxa_end_catch() [ "funclet"(token %1) ] 67 catchret from %1 to label %try.cont 68 69rethrow: ; preds = %catch.fallthrough 70 call void @__cxa_rethrow() [ "funclet"(token %1) ] 71 unreachable 72 73try.cont: ; preds = %entry, %catch, %catch2 74 ret void 75} 76 77; Nested try-catches within a catch 78; void test1() { 79; try { 80; foo(); 81; } catch (int) { 82; try { 83; foo(); 84; } catch (int) { 85; foo(); 86; } 87; } 88; } 89 90; CHECK-LABEL: test1 91; CHECK: try 92; CHECK: call foo 93; CHECK: catch 94; CHECK: block 95; CHECK: block 96; CHECK: br_if 0, {{.*}} # 0: down to label7 97; CHECK: i32.call $drop=, __cxa_begin_catch 98; CHECK: try 99; CHECK: call foo 100; CHECK: br 2 # 2: down to label6 101; CHECK: catch 102; CHECK: try 103; CHECK: block 104; CHECK: br_if 0, {{.*}} # 0: down to label11 105; CHECK: i32.call $drop=, __cxa_begin_catch 106; CHECK: try 107; CHECK: call foo 108; CHECK: br 2 # 2: down to label9 109; CHECK: catch 110; CHECK: call __cxa_end_catch 111; CHECK: rethrow # down to catch3 112; CHECK: end_try 113; CHECK: end_block # label11: 114; CHECK: call __cxa_rethrow 115; CHECK: unreachable 116; CHECK: catch {{.*}} # catch3: 117; CHECK: call __cxa_end_catch 118; CHECK: rethrow # to caller 119; CHECK: end_try # label9: 120; CHECK: call __cxa_end_catch 121; CHECK: br 2 # 2: down to label6 122; CHECK: end_try 123; CHECK: end_block # label7: 124; CHECK: call __cxa_rethrow 125; CHECK: unreachable 126; CHECK: end_block # label6: 127; CHECK: call __cxa_end_catch 128; CHECK: end_try 129define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 130entry: 131 invoke void @foo() 132 to label %try.cont11 unwind label %catch.dispatch 133 134catch.dispatch: ; preds = %entry 135 %0 = catchswitch within none [label %catch.start] unwind to caller 136 137catch.start: ; preds = %catch.dispatch 138 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)] 139 %2 = call i8* @llvm.wasm.get.exception(token %1) 140 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 141 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 142 %matches = icmp eq i32 %3, %4 143 br i1 %matches, label %catch, label %rethrow 144 145catch: ; preds = %catch.start 146 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 147 %6 = bitcast i8* %5 to i32* 148 %7 = load i32, i32* %6, align 4 149 invoke void @foo() [ "funclet"(token %1) ] 150 to label %try.cont unwind label %catch.dispatch2 151 152catch.dispatch2: ; preds = %catch 153 %8 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup9 154 155catch.start3: ; preds = %catch.dispatch2 156 %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)] 157 %10 = call i8* @llvm.wasm.get.exception(token %9) 158 %11 = call i32 @llvm.wasm.get.ehselector(token %9) 159 %12 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 160 %matches4 = icmp eq i32 %11, %12 161 br i1 %matches4, label %catch6, label %rethrow5 162 163catch6: ; preds = %catch.start3 164 %13 = call i8* @__cxa_begin_catch(i8* %10) [ "funclet"(token %9) ] 165 %14 = bitcast i8* %13 to i32* 166 %15 = load i32, i32* %14, align 4 167 invoke void @foo() [ "funclet"(token %9) ] 168 to label %invoke.cont8 unwind label %ehcleanup 169 170invoke.cont8: ; preds = %catch6 171 call void @__cxa_end_catch() [ "funclet"(token %9) ] 172 catchret from %9 to label %try.cont 173 174rethrow5: ; preds = %catch.start3 175 invoke void @__cxa_rethrow() [ "funclet"(token %9) ] 176 to label %unreachable unwind label %ehcleanup9 177 178try.cont: ; preds = %catch, %invoke.cont8 179 call void @__cxa_end_catch() [ "funclet"(token %1) ] 180 catchret from %1 to label %try.cont11 181 182rethrow: ; preds = %catch.start 183 call void @__cxa_rethrow() [ "funclet"(token %1) ] 184 unreachable 185 186try.cont11: ; preds = %entry, %try.cont 187 ret void 188 189ehcleanup: ; preds = %catch6 190 %16 = cleanuppad within %9 [] 191 call void @__cxa_end_catch() [ "funclet"(token %16) ] 192 cleanupret from %16 unwind label %ehcleanup9 193 194ehcleanup9: ; preds = %ehcleanup, %rethrow5, %catch.dispatch2 195 %17 = cleanuppad within %1 [] 196 call void @__cxa_end_catch() [ "funclet"(token %17) ] 197 cleanupret from %17 unwind to caller 198 199unreachable: ; preds = %rethrow5 200 unreachable 201} 202 203; Nested loop within a catch clause 204; void test2() { 205; try { 206; foo(); 207; } catch (...) { 208; for (int i = 0; i < 50; i++) 209; foo(); 210; } 211; } 212 213; CHECK-LABEL: test2 214; CHECK: try 215; CHECK: call foo 216; CHECK: catch 217; CHECK: i32.call $drop=, __cxa_begin_catch 218; CHECK: loop # label15: 219; CHECK: block 220; CHECK: block 221; CHECK: br_if 0, {{.*}} # 0: down to label17 222; CHECK: try 223; CHECK: call foo 224; CHECK: br 2 # 2: down to label16 225; CHECK: catch 226; CHECK: try 227; CHECK: call __cxa_end_catch 228; CHECK: catch 229; CHECK: call __clang_call_terminate 230; CHECK: unreachable 231; CHECK: end_try 232; CHECK: rethrow # to caller 233; CHECK: end_try 234; CHECK: end_block # label17: 235; CHECK: call __cxa_end_catch 236; CHECK: br 2 # 2: down to label13 237; CHECK: end_block # label16: 238; CHECK: br 0 # 0: up to label15 239; CHECK: end_loop 240; CHECK: end_try # label13: 241define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 242entry: 243 invoke void @foo() 244 to label %try.cont unwind label %catch.dispatch 245 246catch.dispatch: ; preds = %entry 247 %0 = catchswitch within none [label %catch.start] unwind to caller 248 249catch.start: ; preds = %catch.dispatch 250 %1 = catchpad within %0 [i8* null] 251 %2 = call i8* @llvm.wasm.get.exception(token %1) 252 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 253 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 254 br label %for.cond 255 256for.cond: ; preds = %for.inc, %catch.start 257 %i.0 = phi i32 [ 0, %catch.start ], [ %inc, %for.inc ] 258 %cmp = icmp slt i32 %i.0, 50 259 br i1 %cmp, label %for.body, label %for.end 260 261for.body: ; preds = %for.cond 262 invoke void @foo() [ "funclet"(token %1) ] 263 to label %for.inc unwind label %ehcleanup 264 265for.inc: ; preds = %for.body 266 %inc = add nsw i32 %i.0, 1 267 br label %for.cond 268 269for.end: ; preds = %for.cond 270 call void @__cxa_end_catch() [ "funclet"(token %1) ] 271 catchret from %1 to label %try.cont 272 273try.cont: ; preds = %for.end, %entry 274 ret void 275 276ehcleanup: ; preds = %for.body 277 %5 = cleanuppad within %1 [] 278 invoke void @__cxa_end_catch() [ "funclet"(token %5) ] 279 to label %invoke.cont2 unwind label %terminate 280 281invoke.cont2: ; preds = %ehcleanup 282 cleanupret from %5 unwind to caller 283 284terminate: ; preds = %ehcleanup 285 %6 = cleanuppad within %5 [] 286 %7 = call i8* @llvm.wasm.get.exception(token %6) 287 call void @__clang_call_terminate(i8* %7) [ "funclet"(token %6) ] 288 unreachable 289} 290 291declare void @foo() 292declare void @bar() 293declare i32 @__gxx_wasm_personality_v0(...) 294declare i8* @llvm.wasm.get.exception(token) 295declare i32 @llvm.wasm.get.ehselector(token) 296declare i32 @llvm.eh.typeid.for(i8*) 297declare i8* @__cxa_begin_catch(i8*) 298declare void @__cxa_end_catch() 299declare void @__cxa_rethrow() 300declare void @__clang_call_terminate(i8*) 301declare void @_ZSt9terminatev() 302