1; RUN: llc < %s -asm-verbose=false -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; CHECK-LABEL: test0 12; CHECK: call foo@FUNCTION 13; CHECK: .LBB0_1: 14; CHECK: i32.catch 15; CHECK: i32.call $drop=, _Unwind_CallPersonality@FUNCTION 16; CHECK: i32.call $drop=, __cxa_begin_catch@FUNCTION 17; CHECK: call bar@FUNCTION 18; CHECK: call __cxa_end_catch@FUNCTION 19; CHECK: .LBB0_3: 20; CHECK: i32.call $drop=, __cxa_begin_catch@FUNCTION 21; CHECK: call __cxa_end_catch@FUNCTION 22; CHECK: .LBB0_5: 23; CHECK: call __cxa_rethrow@FUNCTION 24; CHECK: .LBB0_6: 25; CHECK: return 26define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 27entry: 28 invoke void @foo() 29 to label %try.cont unwind label %catch.dispatch 30 31catch.dispatch: ; preds = %entry 32 %0 = catchswitch within none [label %catch.start] unwind to caller 33 34catch.start: ; preds = %catch.dispatch 35 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTId to i8*)] 36 %2 = call i8* @llvm.wasm.get.exception(token %1) 37 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 38 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 39 %matches = icmp eq i32 %3, %4 40 br i1 %matches, label %catch2, label %catch.fallthrough 41 42catch2: ; preds = %catch.start 43 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 44 %6 = bitcast i8* %5 to i32* 45 %7 = load i32, i32* %6, align 4 46 call void @bar() [ "funclet"(token %1) ] 47 call void @__cxa_end_catch() [ "funclet"(token %1) ] 48 catchret from %1 to label %try.cont 49 50catch.fallthrough: ; preds = %catch.start 51 %8 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*)) 52 %matches1 = icmp eq i32 %3, %8 53 br i1 %matches1, label %catch, label %rethrow 54 55catch: ; preds = %catch.fallthrough 56 %9 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 57 %10 = bitcast i8* %9 to double* 58 %11 = load double, double* %10, align 8 59 call void @__cxa_end_catch() [ "funclet"(token %1) ] 60 catchret from %1 to label %try.cont 61 62rethrow: ; preds = %catch.fallthrough 63 call void @__cxa_rethrow() [ "funclet"(token %1) ] 64 unreachable 65 66try.cont: ; preds = %entry, %catch, %catch2 67 ret void 68} 69 70; Nested try-catches within a catch 71 72; CHECK-LABEL: test1 73; CHECK: call foo@FUNCTION 74; CHECK: .LBB1_1: 75; CHECK: i32.catch $0=, 0 76; CHECK: i32.call $drop=, _Unwind_CallPersonality@FUNCTION, $0 77; CHECK: i32.call $drop=, __cxa_begin_catch@FUNCTION, $0 78; CHECK: call foo@FUNCTION 79; CHECK: .LBB1_3: 80; CHECK: i32.catch $0=, 0 81; CHECK: i32.call $drop=, _Unwind_CallPersonality@FUNCTION, $0 82; CHECK: i32.call $drop=, __cxa_begin_catch@FUNCTION, $0 83; CHECK: call foo@FUNCTION 84; CHECK: .LBB1_5: 85; CHECK: catch_all 86; CHECK: call __cxa_end_catch@FUNCTION 87; CHECK: rethrow 88; CHECK: .LBB1_6: 89; CHECK: call __cxa_rethrow@FUNCTION 90; CHECK: rethrow 91; CHECK: .LBB1_7: 92; CHECK: call __cxa_end_catch@FUNCTION 93; CHECK: .LBB1_8: 94; CHECK: catch_all 95; CHECK: call __cxa_end_catch@FUNCTION 96; CHECK: .LBB1_9: 97; CHECK: call __cxa_rethrow@FUNCTION 98; CHECK: rethrow 99; CHECK: .LBB1_10: 100; CHECK: call __cxa_end_catch@FUNCTION 101; CHECK: .LBB1_11: 102; CHECK: return 103define hidden void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 104entry: 105 invoke void @foo() 106 to label %try.cont11 unwind label %catch.dispatch 107 108catch.dispatch: ; preds = %entry 109 %0 = catchswitch within none [label %catch.start] unwind to caller 110 111catch.start: ; preds = %catch.dispatch 112 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)] 113 %2 = call i8* @llvm.wasm.get.exception(token %1) 114 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 115 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 116 %matches = icmp eq i32 %3, %4 117 br i1 %matches, label %catch, label %rethrow 118 119catch: ; preds = %catch.start 120 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 121 %6 = bitcast i8* %5 to i32* 122 %7 = load i32, i32* %6, align 4 123 invoke void @foo() [ "funclet"(token %1) ] 124 to label %try.cont unwind label %catch.dispatch2 125 126catch.dispatch2: ; preds = %catch 127 %8 = catchswitch within %1 [label %catch.start3] unwind label %ehcleanup9 128 129catch.start3: ; preds = %catch.dispatch2 130 %9 = catchpad within %8 [i8* bitcast (i8** @_ZTIi to i8*)] 131 %10 = call i8* @llvm.wasm.get.exception(token %9) 132 %11 = call i32 @llvm.wasm.get.ehselector(token %9) 133 %12 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) 134 %matches4 = icmp eq i32 %11, %12 135 br i1 %matches4, label %catch6, label %rethrow5 136 137catch6: ; preds = %catch.start3 138 %13 = call i8* @__cxa_begin_catch(i8* %10) [ "funclet"(token %9) ] 139 %14 = bitcast i8* %13 to i32* 140 %15 = load i32, i32* %14, align 4 141 invoke void @foo() [ "funclet"(token %9) ] 142 to label %invoke.cont8 unwind label %ehcleanup 143 144invoke.cont8: ; preds = %catch6 145 call void @__cxa_end_catch() [ "funclet"(token %9) ] 146 catchret from %9 to label %try.cont 147 148rethrow5: ; preds = %catch.start3 149 invoke void @__cxa_rethrow() [ "funclet"(token %9) ] 150 to label %unreachable unwind label %ehcleanup9 151 152try.cont: ; preds = %catch, %invoke.cont8 153 call void @__cxa_end_catch() [ "funclet"(token %1) ] 154 catchret from %1 to label %try.cont11 155 156rethrow: ; preds = %catch.start 157 call void @__cxa_rethrow() [ "funclet"(token %1) ] 158 unreachable 159 160try.cont11: ; preds = %entry, %try.cont 161 ret void 162 163ehcleanup: ; preds = %catch6 164 %16 = cleanuppad within %9 [] 165 call void @__cxa_end_catch() [ "funclet"(token %16) ] 166 cleanupret from %16 unwind label %ehcleanup9 167 168ehcleanup9: ; preds = %ehcleanup, %rethrow5, %catch.dispatch2 169 %17 = cleanuppad within %1 [] 170 call void @__cxa_end_catch() [ "funclet"(token %17) ] 171 cleanupret from %17 unwind to caller 172 173unreachable: ; preds = %rethrow5 174 unreachable 175} 176 177; Nested loop within a catch clause 178 179; CHECK-LABEL: test2 180; CHECK: call foo@FUNCTION 181; CHECK: .LBB2_1: 182; CHECK: i32.catch 183; CHECK: i32.call $drop=, __cxa_begin_catch@FUNCTION 184; CHECK: .LBB2_2: 185; CHECK: call foo@FUNCTION 186; CHECK: .LBB2_4: 187; CHECK: catch_all 188; CHECK: call __cxa_end_catch@FUNCTION 189; CHECK: .LBB2_5: 190; CHECK: i32.catch 191; CHECK: call __clang_call_terminate@FUNCTION 192; CHECK: unreachable 193; CHECK: .LBB2_6: 194; CHECK: catch_all 195; CHECK: call _ZSt9terminatev@FUNCTION 196; CHECK: unreachable 197; CHECK: .LBB2_7: 198; CHECK: rethrow 199; CHECK: .LBB2_8: 200; CHECK: call __cxa_end_catch@FUNCTION 201; CHECK: .LBB2_10: 202; CHECK: return 203define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { 204entry: 205 invoke void @foo() 206 to label %try.cont unwind label %catch.dispatch 207 208catch.dispatch: ; preds = %entry 209 %0 = catchswitch within none [label %catch.start] unwind to caller 210 211catch.start: ; preds = %catch.dispatch 212 %1 = catchpad within %0 [i8* null] 213 %2 = call i8* @llvm.wasm.get.exception(token %1) 214 %3 = call i32 @llvm.wasm.get.ehselector(token %1) 215 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ] 216 br label %for.cond 217 218for.cond: ; preds = %for.inc, %catch.start 219 %i.0 = phi i32 [ 0, %catch.start ], [ %inc, %for.inc ] 220 %cmp = icmp slt i32 %i.0, 50 221 br i1 %cmp, label %for.body, label %for.end 222 223for.body: ; preds = %for.cond 224 invoke void @foo() [ "funclet"(token %1) ] 225 to label %for.inc unwind label %ehcleanup 226 227for.inc: ; preds = %for.body 228 %inc = add nsw i32 %i.0, 1 229 br label %for.cond 230 231for.end: ; preds = %for.cond 232 call void @__cxa_end_catch() [ "funclet"(token %1) ] 233 catchret from %1 to label %try.cont 234 235try.cont: ; preds = %for.end, %entry 236 ret void 237 238ehcleanup: ; preds = %for.body 239 %5 = cleanuppad within %1 [] 240 invoke void @__cxa_end_catch() [ "funclet"(token %5) ] 241 to label %invoke.cont2 unwind label %terminate 242 243invoke.cont2: ; preds = %ehcleanup 244 cleanupret from %5 unwind to caller 245 246terminate: ; preds = %ehcleanup 247 %6 = cleanuppad within %5 [] 248 %7 = call i8* @llvm.wasm.get.exception(token %6) 249 call void @__clang_call_terminate(i8* %7) [ "funclet"(token %6) ] 250 unreachable 251} 252 253declare void @foo() 254declare void @bar() 255declare i32 @__gxx_wasm_personality_v0(...) 256declare i8* @llvm.wasm.get.exception(token) 257declare i32 @llvm.wasm.get.ehselector(token) 258declare i32 @llvm.eh.typeid.for(i8*) 259declare i8* @__cxa_begin_catch(i8*) 260declare void @__cxa_end_catch() 261declare void @__cxa_rethrow() 262declare void @__clang_call_terminate(i8*) 263declare void @_ZSt9terminatev() 264