1*a8e1135bSHeejin Ahn; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck --implicit-check-not=ehgcr -allow-deprecated-dag-overlap %s 2*a8e1135bSHeejin Ahn; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs -O0 3*a8e1135bSHeejin Ahn; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling 4c108c1e9SHeejin Ahn 5c108c1e9SHeejin Ahntarget triple = "wasm32-unknown-unknown" 6c108c1e9SHeejin Ahn 7c108c1e9SHeejin Ahn%struct.Temp = type { i8 } 8c108c1e9SHeejin Ahn 9c108c1e9SHeejin Ahn@_ZTIi = external dso_local constant ptr 10c108c1e9SHeejin Ahn 11c108c1e9SHeejin Ahn; CHECK: .tagtype __cpp_exception i32 12c108c1e9SHeejin Ahn 138b28e2ebSHeejin Ahn; CHECK-LABEL: throw: 14c108c1e9SHeejin Ahn; CHECK: throw __cpp_exception, $0 15c108c1e9SHeejin Ahn; CHECK-NOT: unreachable 168b28e2ebSHeejin Ahndefine void @throw(ptr %p) { 17c108c1e9SHeejin Ahn call void @llvm.wasm.throw(i32 0, ptr %p) 18c108c1e9SHeejin Ahn ret void 19c108c1e9SHeejin Ahn} 20c108c1e9SHeejin Ahn 21c108c1e9SHeejin Ahn; Simple test with a try-catch 22c108c1e9SHeejin Ahn; 23c108c1e9SHeejin Ahn; void foo(); 248b28e2ebSHeejin Ahn; void catch() { 25c108c1e9SHeejin Ahn; try { 26c108c1e9SHeejin Ahn; foo(); 27c108c1e9SHeejin Ahn; } catch (int) { 28c108c1e9SHeejin Ahn; } 29c108c1e9SHeejin Ahn; } 30c108c1e9SHeejin Ahn 318b28e2ebSHeejin Ahn; CHECK-LABEL: catch: 32c108c1e9SHeejin Ahn; CHECK: global.get ${{.+}}=, __stack_pointer 33c108c1e9SHeejin Ahn; CHECK: try 34c108c1e9SHeejin Ahn; CHECK: call foo 35c108c1e9SHeejin Ahn; CHECK: catch $[[EXN:[0-9]+]]=, __cpp_exception 36c108c1e9SHeejin Ahn; CHECK: global.set __stack_pointer 37c108c1e9SHeejin Ahn; CHECK: i32.{{store|const}} {{.*}} __wasm_lpad_context 38c108c1e9SHeejin Ahn; CHECK: call $drop=, _Unwind_CallPersonality, $[[EXN]] 39c108c1e9SHeejin Ahn; CHECK: block 40c108c1e9SHeejin Ahn; CHECK: br_if 0 41c108c1e9SHeejin Ahn; CHECK: call $drop=, __cxa_begin_catch 42c108c1e9SHeejin Ahn; CHECK: call __cxa_end_catch 43c108c1e9SHeejin Ahn; CHECK: br 1 44c108c1e9SHeejin Ahn; CHECK: end_block 45c108c1e9SHeejin Ahn; CHECK: rethrow 0 46c108c1e9SHeejin Ahn; CHECK: end_try 478b28e2ebSHeejin Ahndefine void @catch() personality ptr @__gxx_wasm_personality_v0 { 48c108c1e9SHeejin Ahnentry: 49c108c1e9SHeejin Ahn invoke void @foo() 50c108c1e9SHeejin Ahn to label %try.cont unwind label %catch.dispatch 51c108c1e9SHeejin Ahn 52c108c1e9SHeejin Ahncatch.dispatch: ; preds = %entry 53c108c1e9SHeejin Ahn %0 = catchswitch within none [label %catch.start] unwind to caller 54c108c1e9SHeejin Ahn 55c108c1e9SHeejin Ahncatch.start: ; preds = %catch.dispatch 56c108c1e9SHeejin Ahn %1 = catchpad within %0 [ptr @_ZTIi] 57c108c1e9SHeejin Ahn %2 = call ptr @llvm.wasm.get.exception(token %1) 58c108c1e9SHeejin Ahn %3 = call i32 @llvm.wasm.get.ehselector(token %1) 59c108c1e9SHeejin Ahn %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) 60c108c1e9SHeejin Ahn %matches = icmp eq i32 %3, %4 61c108c1e9SHeejin Ahn br i1 %matches, label %catch, label %rethrow 62c108c1e9SHeejin Ahn 63c108c1e9SHeejin Ahncatch: ; preds = %catch.start 64c108c1e9SHeejin Ahn %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ] 65c108c1e9SHeejin Ahn call void @__cxa_end_catch() [ "funclet"(token %1) ] 66c108c1e9SHeejin Ahn catchret from %1 to label %try.cont 67c108c1e9SHeejin Ahn 68c108c1e9SHeejin Ahnrethrow: ; preds = %catch.start 69c108c1e9SHeejin Ahn call void @llvm.wasm.rethrow() [ "funclet"(token %1) ] 70c108c1e9SHeejin Ahn unreachable 71c108c1e9SHeejin Ahn 72c108c1e9SHeejin Ahntry.cont: ; preds = %catch, %entry 73c108c1e9SHeejin Ahn ret void 74c108c1e9SHeejin Ahn} 75c108c1e9SHeejin Ahn 76c108c1e9SHeejin Ahn; Destructor (cleanup) test 77c108c1e9SHeejin Ahn; 78c108c1e9SHeejin Ahn; void foo(); 79c108c1e9SHeejin Ahn; struct Temp { 80c108c1e9SHeejin Ahn; ~Temp() {} 81c108c1e9SHeejin Ahn; }; 828b28e2ebSHeejin Ahn; void cleanup() { 83c108c1e9SHeejin Ahn; Temp t; 84c108c1e9SHeejin Ahn; foo(); 85c108c1e9SHeejin Ahn; } 86c108c1e9SHeejin Ahn 878b28e2ebSHeejin Ahn; CHECK-LABEL: cleanup: 88c108c1e9SHeejin Ahn; CHECK: try 89c108c1e9SHeejin Ahn; CHECK: call foo 90c108c1e9SHeejin Ahn; CHECK: catch_all 91c108c1e9SHeejin Ahn; CHECK: global.set __stack_pointer 92c108c1e9SHeejin Ahn; CHECK: call $drop=, _ZN4TempD2Ev 93c108c1e9SHeejin Ahn; CHECK: rethrow 0 94c108c1e9SHeejin Ahn; CHECK: end_try 958b28e2ebSHeejin Ahndefine void @cleanup() personality ptr @__gxx_wasm_personality_v0 { 96c108c1e9SHeejin Ahnentry: 97c108c1e9SHeejin Ahn %t = alloca %struct.Temp, align 1 98c108c1e9SHeejin Ahn invoke void @foo() 99c108c1e9SHeejin Ahn to label %invoke.cont unwind label %ehcleanup 100c108c1e9SHeejin Ahn 101c108c1e9SHeejin Ahninvoke.cont: ; preds = %entry 102c108c1e9SHeejin Ahn %call = call ptr @_ZN4TempD2Ev(ptr %t) 103c108c1e9SHeejin Ahn ret void 104c108c1e9SHeejin Ahn 105c108c1e9SHeejin Ahnehcleanup: ; preds = %entry 106c108c1e9SHeejin Ahn %0 = cleanuppad within none [] 107c108c1e9SHeejin Ahn %call1 = call ptr @_ZN4TempD2Ev(ptr %t) [ "funclet"(token %0) ] 108c108c1e9SHeejin Ahn cleanupret from %0 unwind to caller 109c108c1e9SHeejin Ahn} 110c108c1e9SHeejin Ahn 111c108c1e9SHeejin Ahn; Calling a function that may throw within a 'catch (...)' generates a 1126bbf7f06SHeejin Ahn; terminatepad, because __cxa_end_catch() also can throw within 'catch (...)'. 113c108c1e9SHeejin Ahn; 114c108c1e9SHeejin Ahn; void foo(); 1158b28e2ebSHeejin Ahn; void terminatepad() { 116c108c1e9SHeejin Ahn; try { 117c108c1e9SHeejin Ahn; foo(); 118c108c1e9SHeejin Ahn; } catch (...) { 119c108c1e9SHeejin Ahn; foo(); 120c108c1e9SHeejin Ahn; } 121c108c1e9SHeejin Ahn; } 122c108c1e9SHeejin Ahn 1238b28e2ebSHeejin Ahn; CHECK-LABEL: terminatepad 124c108c1e9SHeejin Ahn; CHECK: try 125c108c1e9SHeejin Ahn; CHECK: call foo 126c108c1e9SHeejin Ahn; CHECK: catch 127c108c1e9SHeejin Ahn; CHECK: call $drop=, __cxa_begin_catch 128c108c1e9SHeejin Ahn; CHECK: try 129c108c1e9SHeejin Ahn; CHECK: call foo 130c108c1e9SHeejin Ahn; CHECK: catch_all 131c108c1e9SHeejin Ahn; CHECK: try 132c108c1e9SHeejin Ahn; CHECK: call __cxa_end_catch 133c108c1e9SHeejin Ahn; CHECK: catch_all 134c108c1e9SHeejin Ahn; CHECK: call _ZSt9terminatev 135c108c1e9SHeejin Ahn; CHECK: unreachable 136c108c1e9SHeejin Ahn; CHECK: end_try 137c108c1e9SHeejin Ahn; CHECK: rethrow 138c108c1e9SHeejin Ahn; CHECK: end_try 139c108c1e9SHeejin Ahn; CHECK: call __cxa_end_catch 140c108c1e9SHeejin Ahn; CHECK: end_try 1418b28e2ebSHeejin Ahndefine void @terminatepad() personality ptr @__gxx_wasm_personality_v0 { 142c108c1e9SHeejin Ahnentry: 143c108c1e9SHeejin Ahn invoke void @foo() 144c108c1e9SHeejin Ahn to label %try.cont unwind label %catch.dispatch 145c108c1e9SHeejin Ahn 146c108c1e9SHeejin Ahncatch.dispatch: ; preds = %entry 147c108c1e9SHeejin Ahn %0 = catchswitch within none [label %catch.start] unwind to caller 148c108c1e9SHeejin Ahn 149c108c1e9SHeejin Ahncatch.start: ; preds = %catch.dispatch 150c108c1e9SHeejin Ahn %1 = catchpad within %0 [ptr null] 151c108c1e9SHeejin Ahn %2 = call ptr @llvm.wasm.get.exception(token %1) 152c108c1e9SHeejin Ahn %3 = call i32 @llvm.wasm.get.ehselector(token %1) 153c108c1e9SHeejin Ahn %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ] 154c108c1e9SHeejin Ahn invoke void @foo() [ "funclet"(token %1) ] 155c108c1e9SHeejin Ahn to label %invoke.cont1 unwind label %ehcleanup 156c108c1e9SHeejin Ahn 157c108c1e9SHeejin Ahninvoke.cont1: ; preds = %catch.start 158c108c1e9SHeejin Ahn call void @__cxa_end_catch() [ "funclet"(token %1) ] 159c108c1e9SHeejin Ahn catchret from %1 to label %try.cont 160c108c1e9SHeejin Ahn 161c108c1e9SHeejin Ahntry.cont: ; preds = %invoke.cont1, %entry 162c108c1e9SHeejin Ahn ret void 163c108c1e9SHeejin Ahn 164c108c1e9SHeejin Ahnehcleanup: ; preds = %catch.start 165c108c1e9SHeejin Ahn %5 = cleanuppad within %1 [] 166c108c1e9SHeejin Ahn invoke void @__cxa_end_catch() [ "funclet"(token %5) ] 167c108c1e9SHeejin Ahn to label %invoke.cont2 unwind label %terminate 168c108c1e9SHeejin Ahn 169c108c1e9SHeejin Ahninvoke.cont2: ; preds = %ehcleanup 170c108c1e9SHeejin Ahn cleanupret from %5 unwind to caller 171c108c1e9SHeejin Ahn 172c108c1e9SHeejin Ahnterminate: ; preds = %ehcleanup 173c108c1e9SHeejin Ahn %6 = cleanuppad within %5 [] 174c108c1e9SHeejin Ahn call void @_ZSt9terminatev() [ "funclet"(token %6) ] 175c108c1e9SHeejin Ahn unreachable 176c108c1e9SHeejin Ahn} 177c108c1e9SHeejin Ahn 178c108c1e9SHeejin Ahn; Tests prologues and epilogues are not generated within EH scopes. 179c108c1e9SHeejin Ahn; They should not be treated as funclets; BBs starting with a catch instruction 180c108c1e9SHeejin Ahn; should not have a prologue, and BBs ending with a catchret/cleanupret should 181c108c1e9SHeejin Ahn; not have an epilogue. This is separate from __stack_pointer restoring 182c108c1e9SHeejin Ahn; instructions after a catch instruction. 183c108c1e9SHeejin Ahn; 184c108c1e9SHeejin Ahn; void bar(int) noexcept; 1858b28e2ebSHeejin Ahn; void no_prolog_epilog_in_ehpad() { 186c108c1e9SHeejin Ahn; int stack_var = 0; 187c108c1e9SHeejin Ahn; bar(stack_var); 188c108c1e9SHeejin Ahn; try { 189c108c1e9SHeejin Ahn; foo(); 190c108c1e9SHeejin Ahn; } catch (int) { 191c108c1e9SHeejin Ahn; foo(); 192c108c1e9SHeejin Ahn; } 193c108c1e9SHeejin Ahn; } 194c108c1e9SHeejin Ahn 1958b28e2ebSHeejin Ahn; CHECK-LABEL: no_prolog_epilog_in_ehpad 196c108c1e9SHeejin Ahn; CHECK: try 197c108c1e9SHeejin Ahn; CHECK: call foo 198c108c1e9SHeejin Ahn; CHECK: catch 199c108c1e9SHeejin Ahn; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer 200c108c1e9SHeejin Ahn; CHECK: global.set __stack_pointer 201c108c1e9SHeejin Ahn; CHECK: block 202c108c1e9SHeejin Ahn; CHECK: block 203c108c1e9SHeejin Ahn; CHECK: br_if 0 204c108c1e9SHeejin Ahn; CHECK: call $drop=, __cxa_begin_catch 205c108c1e9SHeejin Ahn; CHECK: try 206c108c1e9SHeejin Ahn; CHECK: call foo 207c108c1e9SHeejin Ahn; CHECK: catch 208c108c1e9SHeejin Ahn; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer 209c108c1e9SHeejin Ahn; CHECK: global.set __stack_pointer 210c108c1e9SHeejin Ahn; CHECK: call __cxa_end_catch 211c108c1e9SHeejin Ahn; CHECK: rethrow 212c108c1e9SHeejin Ahn; CHECK-NOT: global.set __stack_pointer, $pop{{.+}} 213c108c1e9SHeejin Ahn; CHECK: end_try 214c108c1e9SHeejin Ahn; CHECK: end_block 215c108c1e9SHeejin Ahn; CHECK: rethrow 216c108c1e9SHeejin Ahn; CHECK: end_block 217c108c1e9SHeejin Ahn; CHECK-NOT: global.set __stack_pointer, $pop{{.+}} 218c108c1e9SHeejin Ahn; CHECK: call __cxa_end_catch 219c108c1e9SHeejin Ahn; CHECK: end_try 2208b28e2ebSHeejin Ahndefine void @no_prolog_epilog_in_ehpad() personality ptr @__gxx_wasm_personality_v0 { 221c108c1e9SHeejin Ahnentry: 222c108c1e9SHeejin Ahn %stack_var = alloca i32, align 4 223c108c1e9SHeejin Ahn call void @bar(ptr %stack_var) 224c108c1e9SHeejin Ahn invoke void @foo() 225c108c1e9SHeejin Ahn to label %try.cont unwind label %catch.dispatch 226c108c1e9SHeejin Ahn 227c108c1e9SHeejin Ahncatch.dispatch: ; preds = %entry 228c108c1e9SHeejin Ahn %0 = catchswitch within none [label %catch.start] unwind to caller 229c108c1e9SHeejin Ahn 230c108c1e9SHeejin Ahncatch.start: ; preds = %catch.dispatch 231c108c1e9SHeejin Ahn %1 = catchpad within %0 [ptr @_ZTIi] 232c108c1e9SHeejin Ahn %2 = call ptr @llvm.wasm.get.exception(token %1) 233c108c1e9SHeejin Ahn %3 = call i32 @llvm.wasm.get.ehselector(token %1) 234c108c1e9SHeejin Ahn %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi) 235c108c1e9SHeejin Ahn %matches = icmp eq i32 %3, %4 236c108c1e9SHeejin Ahn br i1 %matches, label %catch, label %rethrow 237c108c1e9SHeejin Ahn 238c108c1e9SHeejin Ahncatch: ; preds = %catch.start 239c108c1e9SHeejin Ahn %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ] 240c108c1e9SHeejin Ahn %6 = load float, ptr %5, align 4 241c108c1e9SHeejin Ahn invoke void @foo() [ "funclet"(token %1) ] 242c108c1e9SHeejin Ahn to label %invoke.cont1 unwind label %ehcleanup 243c108c1e9SHeejin Ahn 244c108c1e9SHeejin Ahninvoke.cont1: ; preds = %catch 245c108c1e9SHeejin Ahn call void @__cxa_end_catch() [ "funclet"(token %1) ] 246c108c1e9SHeejin Ahn catchret from %1 to label %try.cont 247c108c1e9SHeejin Ahn 248c108c1e9SHeejin Ahnrethrow: ; preds = %catch.start 249c108c1e9SHeejin Ahn call void @llvm.wasm.rethrow() [ "funclet"(token %1) ] 250c108c1e9SHeejin Ahn unreachable 251c108c1e9SHeejin Ahn 252c108c1e9SHeejin Ahntry.cont: ; preds = %invoke.cont1, %entry 253c108c1e9SHeejin Ahn ret void 254c108c1e9SHeejin Ahn 255c108c1e9SHeejin Ahnehcleanup: ; preds = %catch 256c108c1e9SHeejin Ahn %7 = cleanuppad within %1 [] 257c108c1e9SHeejin Ahn call void @__cxa_end_catch() [ "funclet"(token %7) ] 258c108c1e9SHeejin Ahn cleanupret from %7 unwind to caller 259c108c1e9SHeejin Ahn} 260c108c1e9SHeejin Ahn 261c108c1e9SHeejin Ahn; When a function does not have stack-allocated objects, it does not need to 262c108c1e9SHeejin Ahn; store SP back to __stack_pointer global at the epilog. 263c108c1e9SHeejin Ahn; 264c108c1e9SHeejin Ahn; void foo(); 2658b28e2ebSHeejin Ahn; void no_sp_writeback() { 266c108c1e9SHeejin Ahn; try { 267c108c1e9SHeejin Ahn; foo(); 268c108c1e9SHeejin Ahn; } catch (...) { 269c108c1e9SHeejin Ahn; } 270c108c1e9SHeejin Ahn; } 271c108c1e9SHeejin Ahn 2728b28e2ebSHeejin Ahn; CHECK-LABEL: no_sp_writeback 273c108c1e9SHeejin Ahn; CHECK: try 274c108c1e9SHeejin Ahn; CHECK: call foo 275c108c1e9SHeejin Ahn; CHECK: catch 276c108c1e9SHeejin Ahn; CHECK: call $drop=, __cxa_begin_catch 277c108c1e9SHeejin Ahn; CHECK: call __cxa_end_catch 278c108c1e9SHeejin Ahn; CHECK: end_try 279c108c1e9SHeejin Ahn; CHECK-NOT: global.set __stack_pointer 280c108c1e9SHeejin Ahn; CHECK: return 2818b28e2ebSHeejin Ahndefine void @no_sp_writeback() personality ptr @__gxx_wasm_personality_v0 { 282c108c1e9SHeejin Ahnentry: 283c108c1e9SHeejin Ahn invoke void @foo() 284c108c1e9SHeejin Ahn to label %try.cont unwind label %catch.dispatch 285c108c1e9SHeejin Ahn 286c108c1e9SHeejin Ahncatch.dispatch: ; preds = %entry 287c108c1e9SHeejin Ahn %0 = catchswitch within none [label %catch.start] unwind to caller 288c108c1e9SHeejin Ahn 289c108c1e9SHeejin Ahncatch.start: ; preds = %catch.dispatch 290c108c1e9SHeejin Ahn %1 = catchpad within %0 [ptr null] 291c108c1e9SHeejin Ahn %2 = call ptr @llvm.wasm.get.exception(token %1) 292c108c1e9SHeejin Ahn %3 = call i32 @llvm.wasm.get.ehselector(token %1) 293c108c1e9SHeejin Ahn %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ] 294c108c1e9SHeejin Ahn call void @__cxa_end_catch() [ "funclet"(token %1) ] 295c108c1e9SHeejin Ahn catchret from %1 to label %try.cont 296c108c1e9SHeejin Ahn 297c108c1e9SHeejin Ahntry.cont: ; preds = %catch.start, %entry 298c108c1e9SHeejin Ahn ret void 299c108c1e9SHeejin Ahn} 300c108c1e9SHeejin Ahn 301c108c1e9SHeejin Ahn; When the result of @llvm.wasm.get.exception is not used. This is created to 302c108c1e9SHeejin Ahn; fix a bug in LateEHPrepare and this should not crash. 3038b28e2ebSHeejin Ahndefine void @get_exception_wo_use() personality ptr @__gxx_wasm_personality_v0 { 304c108c1e9SHeejin Ahnentry: 305c108c1e9SHeejin Ahn invoke void @foo() 306c108c1e9SHeejin Ahn to label %try.cont unwind label %catch.dispatch 307c108c1e9SHeejin Ahn 308c108c1e9SHeejin Ahncatch.dispatch: ; preds = %entry 309c108c1e9SHeejin Ahn %0 = catchswitch within none [label %catch.start] unwind to caller 310c108c1e9SHeejin Ahn 311c108c1e9SHeejin Ahncatch.start: ; preds = %catch.dispatch 312c108c1e9SHeejin Ahn %1 = catchpad within %0 [ptr null] 313c108c1e9SHeejin Ahn %2 = call ptr @llvm.wasm.get.exception(token %1) 314c108c1e9SHeejin Ahn %3 = call i32 @llvm.wasm.get.ehselector(token %1) 315c108c1e9SHeejin Ahn catchret from %1 to label %try.cont 316c108c1e9SHeejin Ahn 317c108c1e9SHeejin Ahntry.cont: ; preds = %catch.start, %entry 318c108c1e9SHeejin Ahn ret void 319c108c1e9SHeejin Ahn} 320c108c1e9SHeejin Ahn 321c108c1e9SHeejin Ahn; Tests a case when a cleanup region (cleanuppad ~ clanupret) contains another 322c108c1e9SHeejin Ahn; catchpad 3238b28e2ebSHeejin Ahndefine void @complex_cleanup_region() personality ptr @__gxx_wasm_personality_v0 { 324c108c1e9SHeejin Ahnentry: 325c108c1e9SHeejin Ahn invoke void @foo() 326c108c1e9SHeejin Ahn to label %invoke.cont unwind label %ehcleanup 327c108c1e9SHeejin Ahn 328c108c1e9SHeejin Ahninvoke.cont: ; preds = %entry 329c108c1e9SHeejin Ahn ret void 330c108c1e9SHeejin Ahn 331c108c1e9SHeejin Ahnehcleanup: ; preds = %entry 332c108c1e9SHeejin Ahn %0 = cleanuppad within none [] 333c108c1e9SHeejin Ahn invoke void @foo() [ "funclet"(token %0) ] 334c108c1e9SHeejin Ahn to label %ehcleanupret unwind label %catch.dispatch 335c108c1e9SHeejin Ahn 336c108c1e9SHeejin Ahncatch.dispatch: ; preds = %ehcleanup 337c108c1e9SHeejin Ahn %1 = catchswitch within %0 [label %catch.start] unwind label %ehcleanup.1 338c108c1e9SHeejin Ahn 339c108c1e9SHeejin Ahncatch.start: ; preds = %catch.dispatch 340c108c1e9SHeejin Ahn %2 = catchpad within %1 [ptr null] 341c108c1e9SHeejin Ahn %3 = call ptr @llvm.wasm.get.exception(token %2) 342c108c1e9SHeejin Ahn %4 = call i32 @llvm.wasm.get.ehselector(token %2) 343c108c1e9SHeejin Ahn catchret from %2 to label %ehcleanupret 344c108c1e9SHeejin Ahn 345c108c1e9SHeejin Ahnehcleanup.1: ; preds = %catch.dispatch 346c108c1e9SHeejin Ahn %5 = cleanuppad within %0 [] 347c108c1e9SHeejin Ahn unreachable 348c108c1e9SHeejin Ahn 349c108c1e9SHeejin Ahnehcleanupret: ; preds = %catch.start, %ehcleanup 350c108c1e9SHeejin Ahn cleanupret from %0 unwind to caller 351c108c1e9SHeejin Ahn} 352c108c1e9SHeejin Ahn 3533c8f3b91SHeejin Ahn; Regression test for the bug that 'rethrow' was not treated correctly as a 3543c8f3b91SHeejin Ahn; terminator in isel. 3558b28e2ebSHeejin Ahndefine void @rethrow_terminator() personality ptr @__gxx_wasm_personality_v0 { 3563c8f3b91SHeejin Ahnentry: 3573c8f3b91SHeejin Ahn invoke void @foo() 3583c8f3b91SHeejin Ahn to label %try.cont unwind label %catch.dispatch 3593c8f3b91SHeejin Ahn 3603c8f3b91SHeejin Ahncatch.dispatch: ; preds = %entry 3613c8f3b91SHeejin Ahn %0 = catchswitch within none [label %catch.start] unwind label %ehcleanup 3623c8f3b91SHeejin Ahn 3633c8f3b91SHeejin Ahncatch.start: ; preds = %catch.dispatch 3643c8f3b91SHeejin Ahn %1 = catchpad within %0 [ptr @_ZTIi] 3653c8f3b91SHeejin Ahn %2 = call ptr @llvm.wasm.get.exception(token %1) 3663c8f3b91SHeejin Ahn %3 = call i32 @llvm.wasm.get.ehselector(token %1) 3673c8f3b91SHeejin Ahn %4 = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi) 3683c8f3b91SHeejin Ahn %matches = icmp eq i32 %3, %4 3693c8f3b91SHeejin Ahn br i1 %matches, label %catch, label %rethrow 3703c8f3b91SHeejin Ahn 3713c8f3b91SHeejin Ahncatch: ; preds = %catch.start 3723c8f3b91SHeejin Ahn %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ] 3733c8f3b91SHeejin Ahn %6 = load i32, ptr %5, align 4 3743c8f3b91SHeejin Ahn call void @__cxa_end_catch() [ "funclet"(token %1) ] 3753c8f3b91SHeejin Ahn catchret from %1 to label %try.cont 3763c8f3b91SHeejin Ahn 3773c8f3b91SHeejin Ahnrethrow: ; preds = %catch.start 3783c8f3b91SHeejin Ahn invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ] 3793c8f3b91SHeejin Ahn to label %unreachable unwind label %ehcleanup 3803c8f3b91SHeejin Ahn 3813c8f3b91SHeejin Ahntry.cont: ; preds = %entry, %catch 3823c8f3b91SHeejin Ahn ret void 3833c8f3b91SHeejin Ahn 3843c8f3b91SHeejin Ahnehcleanup: ; preds = %rethrow, %catch.dispatch 3853c8f3b91SHeejin Ahn ; 'rethrow' BB is this BB's predecessor, and its 3863c8f3b91SHeejin Ahn ; 'invoke void @llvm.wasm.rethrow()' is lowered down to a 'RETHROW' in Wasm 3873c8f3b91SHeejin Ahn ; MIR. And this 'phi' creates 'CONST_I32' instruction in the predecessor 3883c8f3b91SHeejin Ahn ; 'rethrow' BB. If 'RETHROW' is not treated correctly as a terminator, it can 3893c8f3b91SHeejin Ahn ; create a BB like 3903c8f3b91SHeejin Ahn ; bb.3.rethrow: 3913c8f3b91SHeejin Ahn ; RETHROW 0 3923c8f3b91SHeejin Ahn ; %0 = CONST_I32 20 3933c8f3b91SHeejin Ahn ; BR ... 3943c8f3b91SHeejin Ahn %tmp = phi i32 [ 10, %catch.dispatch ], [ 20, %rethrow ] 3953c8f3b91SHeejin Ahn %7 = cleanuppad within none [] 3963c8f3b91SHeejin Ahn call void @take_i32(i32 %tmp) [ "funclet"(token %7) ] 3973c8f3b91SHeejin Ahn cleanupret from %7 unwind to caller 3983c8f3b91SHeejin Ahn 3993c8f3b91SHeejin Ahnunreachable: ; preds = %rethrow 4003c8f3b91SHeejin Ahn unreachable 4013c8f3b91SHeejin Ahn} 4023c8f3b91SHeejin Ahn 403492812f6SHeejin Ahn; The bitcode below is generated when the code below is compiled and 404492812f6SHeejin Ahn; Temp::~Temp() is inlined into inlined_cleanupret(): 405492812f6SHeejin Ahn; 406492812f6SHeejin Ahn; void inlined_cleanupret() { 407492812f6SHeejin Ahn; try { 408492812f6SHeejin Ahn; Temp t; 409492812f6SHeejin Ahn; throw 2; 410492812f6SHeejin Ahn; } catch (...) 411492812f6SHeejin Ahn; } 412492812f6SHeejin Ahn; 413492812f6SHeejin Ahn; Temp::~Temp() { 414492812f6SHeejin Ahn; try { 415492812f6SHeejin Ahn; throw 1; 416492812f6SHeejin Ahn; } catch (...) { 417492812f6SHeejin Ahn; } 418492812f6SHeejin Ahn; } 419492812f6SHeejin Ahn; 420492812f6SHeejin Ahn; ~Temp() generates cleanupret, which is lowered to a 'rethrow' later. That 421492812f6SHeejin Ahn; rethrow's immediate argument should correctly target the top-level cleanuppad 422492812f6SHeejin Ahn; (catch_all). This is a regression test for the bug where we did not compute 423492812f6SHeejin Ahn; rethrow's argument correctly. 424492812f6SHeejin Ahn 425492812f6SHeejin Ahn; CHECK-LABEL: inlined_cleanupret: 426492812f6SHeejin Ahn; CHECK: try 427492812f6SHeejin Ahn; CHECK: call __cxa_throw 428492812f6SHeejin Ahn; CHECK: catch_all 429492812f6SHeejin Ahn; CHECK: try 430492812f6SHeejin Ahn; CHECK: try 431492812f6SHeejin Ahn; CHECK: call __cxa_throw 432492812f6SHeejin Ahn; CHECK: catch 433492812f6SHeejin Ahn; CHECK: call __cxa_end_catch 434492812f6SHeejin Ahn; CHECK: try 435492812f6SHeejin Ahn; CHECK: try 436492812f6SHeejin Ahn; Note that this rethrow targets the top-level catch_all 437492812f6SHeejin Ahn; CHECK: rethrow 4 438492812f6SHeejin Ahn; CHECK: catch 439492812f6SHeejin Ahn; CHECK: try 440492812f6SHeejin Ahn; CHECK: call __cxa_end_catch 441492812f6SHeejin Ahn; CHECK: delegate 5 442492812f6SHeejin Ahn; CHECK: return 443492812f6SHeejin Ahn; CHECK: end_try 444492812f6SHeejin Ahn; CHECK: delegate 3 445492812f6SHeejin Ahn; CHECK: end_try 446492812f6SHeejin Ahn; CHECK: catch_all 447492812f6SHeejin Ahn; CHECK: call _ZSt9terminatev 448492812f6SHeejin Ahn; CHECK: end_try 449492812f6SHeejin Ahn; CHECK: end_try 450492812f6SHeejin Ahndefine void @inlined_cleanupret() personality ptr @__gxx_wasm_personality_v0 { 451492812f6SHeejin Ahnentry: 452492812f6SHeejin Ahn %exception = tail call ptr @__cxa_allocate_exception(i32 4) 453492812f6SHeejin Ahn store i32 2, ptr %exception, align 16 454492812f6SHeejin Ahn invoke void @__cxa_throw(ptr nonnull %exception, ptr nonnull @_ZTIi, ptr null) 455492812f6SHeejin Ahn to label %unreachable unwind label %ehcleanup 456492812f6SHeejin Ahn 457492812f6SHeejin Ahnehcleanup: ; preds = %entry 458492812f6SHeejin Ahn %0 = cleanuppad within none [] 459492812f6SHeejin Ahn %exception.i = call ptr @__cxa_allocate_exception(i32 4) [ "funclet"(token %0) ] 460492812f6SHeejin Ahn store i32 1, ptr %exception.i, align 16 461492812f6SHeejin Ahn invoke void @__cxa_throw(ptr nonnull %exception.i, ptr nonnull @_ZTIi, ptr null) [ "funclet"(token %0) ] 462492812f6SHeejin Ahn to label %unreachable unwind label %catch.dispatch.i 463492812f6SHeejin Ahn 464492812f6SHeejin Ahncatch.dispatch.i: ; preds = %ehcleanup 465492812f6SHeejin Ahn %1 = catchswitch within %0 [label %catch.start.i] unwind label %terminate.i 466492812f6SHeejin Ahn 467492812f6SHeejin Ahncatch.start.i: ; preds = %catch.dispatch.i 468492812f6SHeejin Ahn %2 = catchpad within %1 [ptr null] 469492812f6SHeejin Ahn %3 = tail call ptr @llvm.wasm.get.exception(token %2) 470492812f6SHeejin Ahn %4 = tail call i32 @llvm.wasm.get.ehselector(token %2) 471492812f6SHeejin Ahn %5 = call ptr @__cxa_begin_catch(ptr %3) [ "funclet"(token %2) ] 472492812f6SHeejin Ahn invoke void @__cxa_end_catch() [ "funclet"(token %2) ] 473492812f6SHeejin Ahn to label %invoke.cont.i unwind label %terminate.i 474492812f6SHeejin Ahn 475492812f6SHeejin Ahninvoke.cont.i: ; preds = %catch.start.i 476492812f6SHeejin Ahn catchret from %2 to label %_ZN4TempD2Ev.exit 477492812f6SHeejin Ahn 478492812f6SHeejin Ahnterminate.i: ; preds = %catch.start.i, %catch.dispatch.i 479492812f6SHeejin Ahn %6 = cleanuppad within %0 [] 480492812f6SHeejin Ahn call void @_ZSt9terminatev() [ "funclet"(token %6) ] 481492812f6SHeejin Ahn unreachable 482492812f6SHeejin Ahn 483492812f6SHeejin Ahn_ZN4TempD2Ev.exit: ; preds = %invoke.cont.i 484492812f6SHeejin Ahn cleanupret from %0 unwind label %catch.dispatch 485492812f6SHeejin Ahn 486492812f6SHeejin Ahncatch.dispatch: ; preds = %_ZN4TempD2Ev.exit 487492812f6SHeejin Ahn %7 = catchswitch within none [label %catch.start] unwind to caller 488492812f6SHeejin Ahn 489492812f6SHeejin Ahncatch.start: ; preds = %catch.dispatch 490492812f6SHeejin Ahn %8 = catchpad within %7 [ptr null] 491492812f6SHeejin Ahn %9 = tail call ptr @llvm.wasm.get.exception(token %8) 492492812f6SHeejin Ahn %10 = tail call i32 @llvm.wasm.get.ehselector(token %8) 493492812f6SHeejin Ahn %11 = call ptr @__cxa_begin_catch(ptr %9) #8 [ "funclet"(token %8) ] 494492812f6SHeejin Ahn call void @__cxa_end_catch() [ "funclet"(token %8) ] 495492812f6SHeejin Ahn catchret from %8 to label %try.cont 496492812f6SHeejin Ahn 497492812f6SHeejin Ahntry.cont: ; preds = %catch.start 498492812f6SHeejin Ahn ret void 499492812f6SHeejin Ahn 500492812f6SHeejin Ahnunreachable: ; preds = %entry 501492812f6SHeejin Ahn unreachable 502492812f6SHeejin Ahn} 503492812f6SHeejin Ahn 5043c8f3b91SHeejin Ahn 505c108c1e9SHeejin Ahndeclare void @foo() 506c108c1e9SHeejin Ahndeclare void @bar(ptr) 5073c8f3b91SHeejin Ahndeclare void @take_i32(i32) 508c108c1e9SHeejin Ahndeclare i32 @__gxx_wasm_personality_v0(...) 509c108c1e9SHeejin Ahn; Function Attrs: noreturn 510c108c1e9SHeejin Ahndeclare void @llvm.wasm.throw(i32, ptr) #1 511c108c1e9SHeejin Ahn; Function Attrs: nounwind 512c108c1e9SHeejin Ahndeclare ptr @llvm.wasm.get.exception(token) #0 513c108c1e9SHeejin Ahn; Function Attrs: nounwind 514c108c1e9SHeejin Ahndeclare i32 @llvm.wasm.get.ehselector(token) #0 515c108c1e9SHeejin Ahn; Function Attrs: noreturn 516c108c1e9SHeejin Ahndeclare void @llvm.wasm.rethrow() #1 517c108c1e9SHeejin Ahn; Function Attrs: nounwind 518c108c1e9SHeejin Ahndeclare i32 @llvm.eh.typeid.for(ptr) #0 519492812f6SHeejin Ahn; Function Attrs: nounwind 520492812f6SHeejin Ahndeclare ptr @__cxa_allocate_exception(i32) #0 521c108c1e9SHeejin Ahndeclare ptr @__cxa_begin_catch(ptr) 522c108c1e9SHeejin Ahndeclare void @__cxa_end_catch() 523492812f6SHeejin Ahn; Function Attrs: noreturn 524492812f6SHeejin Ahndeclare void @__cxa_throw(ptr, ptr, ptr) #1 525c108c1e9SHeejin Ahndeclare void @_ZSt9terminatev() 526c108c1e9SHeejin Ahndeclare ptr @_ZN4TempD2Ev(ptr returned) 527c108c1e9SHeejin Ahn 528c108c1e9SHeejin Ahnattributes #0 = { nounwind } 529c108c1e9SHeejin Ahnattributes #1 = { noreturn } 530c108c1e9SHeejin Ahn 531c108c1e9SHeejin Ahn; CHECK: __cpp_exception: 532