X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=test%2FCodeGen%2FWinEH%2Fwineh-cloning.ll;h=748c07df17300c097657dc37ac9d1b10e684c664;hp=58bf71e62b63a457dd0f9d61c1a6be6a41dd17c9;hb=12b6cd2e546a2fa001fdcb8bca0027e4dae45514;hpb=805b66a27cdf79dc620a0899e96c8781e0b4208d diff --git a/test/CodeGen/WinEH/wineh-cloning.ll b/test/CodeGen/WinEH/wineh-cloning.ll index 58bf71e62b6..748c07df173 100644 --- a/test/CodeGen/WinEH/wineh-cloning.ll +++ b/test/CodeGen/WinEH/wineh-cloning.ll @@ -1,46 +1,47 @@ -; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s +; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s declare i32 @__CxxFrameHandler3(...) +declare i32 @__C_specific_handler(...) +declare void @ProcessCLRException(...) declare void @f() -declare i32 @g() -declare void @h(i32) -declare i1 @b() +declare void @llvm.foo(i32) nounwind +declare void @llvm.bar() nounwind +declare i32 @llvm.qux() nounwind +declare i1 @llvm.baz() nounwind define void @test1() personality i32 (...)* @__CxxFrameHandler3 { entry: ; %x def colors: {entry} subset of use colors; must spill - %x = call i32 @g() + %x = call i32 @llvm.qux() invoke void @f() - to label %noreturn unwind label %catch + to label %noreturn unwind label %catch.switch +catch.switch: + %cs = catchswitch within none [label %catch] unwind to caller catch: - catchpad [] - to label %noreturn unwind label %endcatch + %cp = catchpad within %cs [] + br label %noreturn noreturn: ; %x use colors: {entry, cleanup} - call void @h(i32 %x) + call void @llvm.foo(i32 %x) unreachable -endcatch: - catchendpad unwind to caller } ; Need two copies of the call to @h, one under entry and one under catch. ; Currently we generate a load for each, though we shouldn't need one ; for the use in entry's copy. ; CHECK-LABEL: define void @test1( ; CHECK: entry: -; CHECK: store i32 %x, i32* [[Slot:%[^ ]+]] +; CHECK: %x = call i32 @llvm.qux() ; CHECK: invoke void @f() ; CHECK: to label %[[EntryCopy:[^ ]+]] unwind label %catch +; CHECK: catch.switch: +; CHECK: %cs = catchswitch within none [label %catch] unwind to caller ; CHECK: catch: -; CHECK: catchpad [] -; CHECK-NEXT: to label %[[CatchCopy:[^ ]+]] unwind -; CHECK: [[CatchCopy]]: -; CHECK: [[LoadX2:%[^ ]+]] = load i32, i32* [[Slot]] -; CHECK: call void @h(i32 [[LoadX2]] +; CHECK: catchpad within %cs [] +; CHECK-NEXT: call void @llvm.foo(i32 %x) ; CHECK: [[EntryCopy]]: -; CHECK: [[LoadX1:%[^ ]+]] = load i32, i32* [[Slot]] -; CHECK: call void @h(i32 [[LoadX1]] +; CHECK: call void @llvm.foo(i32 %x) define void @test2() personality i32 (...)* @__CxxFrameHandler3 { @@ -48,10 +49,10 @@ entry: invoke void @f() to label %exit unwind label %cleanup cleanup: - cleanuppad [] + cleanuppad within none [] br label %exit exit: - call void @f() + call void @llvm.bar() ret void } ; Need two copies of %exit's call to @f -- the subsequent ret is only @@ -62,30 +63,31 @@ exit: ; CHECK: invoke void @f() ; CHECK: to label %[[exit:[^ ]+]] unwind label %cleanup ; CHECK: cleanup: -; CHECK: cleanuppad [] -; CHECK: call void @f() +; CHECK: cleanuppad within none [] +; CHECK: call void @llvm.bar() ; CHECK-NEXT: unreachable ; CHECK: [[exit]]: -; CHECK: call void @f() +; CHECK: call void @llvm.bar() ; CHECK-NEXT: ret void define void @test3() personality i32 (...)* @__CxxFrameHandler3 { entry: invoke void @f() - to label %invoke.cont unwind label %catch + to label %invoke.cont unwind label %catch.switch invoke.cont: invoke void @f() to label %exit unwind label %cleanup +catch.switch: + %cs = catchswitch within none [label %catch] unwind to caller catch: - catchpad [] to label %shared unwind label %endcatch -endcatch: - catchendpad unwind to caller + catchpad within %cs [] + br label %shared cleanup: - cleanuppad [] + cleanuppad within none [] br label %shared shared: - call void @f() + call void @llvm.bar() br label %exit exit: ret void @@ -97,14 +99,12 @@ exit: ; CHECK: invoke void @f() ; CHECK: to label %[[exit:[^ ]+]] unwind ; CHECK: catch: -; CHECK: catchpad [] -; CHECK-NEXT: to label %[[shared:[^ ]+]] unwind -; CHECK: cleanup: -; CHECK: cleanuppad [] -; CHECK: call void @f() +; CHECK: catchpad within %cs [] +; CHECK-NEXT: call void @llvm.bar() ; CHECK-NEXT: unreachable -; CHECK: [[shared]]: -; CHECK: call void @f() +; CHECK: cleanup: +; CHECK: cleanuppad within none [] +; CHECK: call void @llvm.bar() ; CHECK-NEXT: unreachable ; CHECK: [[exit]]: ; CHECK: ret void @@ -113,33 +113,33 @@ exit: define void @test4() personality i32 (...)* @__CxxFrameHandler3 { entry: invoke void @f() - to label %shared unwind label %catch + to label %shared unwind label %catch.switch +catch.switch: + %cs = catchswitch within none [label %catch] unwind to caller catch: - catchpad [] - to label %shared unwind label %endcatch -endcatch: - catchendpad unwind to caller + catchpad within %cs [] + br label %shared shared: - %x = call i32 @g() - %i = call i32 @g() + %x = call i32 @llvm.qux() + %i = call i32 @llvm.qux() %zero.trip = icmp eq i32 %i, 0 br i1 %zero.trip, label %exit, label %loop loop: %i.loop = phi i32 [ %i, %shared ], [ %i.dec, %loop.tail ] - %b = call i1 @b() + %b = call i1 @llvm.baz() br i1 %b, label %left, label %right left: - %y = call i32 @g() + %y = call i32 @llvm.qux() br label %loop.tail right: - call void @h(i32 %x) + call void @llvm.foo(i32 %x) br label %loop.tail loop.tail: %i.dec = sub i32 %i.loop, 1 %done = icmp eq i32 %i.dec, 0 br i1 %done, label %exit, label %loop exit: - call void @h(i32 %x) + call void @llvm.foo(i32 %x) unreachable } ; Make sure we can clone regions that have internal control @@ -147,38 +147,37 @@ exit: ; from %shared to %exit. ; CHECK-LABEL: define void @test4( ; CHECK: entry: -; CHECK: to label %[[shared_E:[^ ]+]] unwind label %catch +; CHECK: to label %[[shared_E:[^ ]+]] unwind label %catch.switch ; CHECK: catch: -; CHECK: to label %[[shared_C:[^ ]+]] unwind label %endcatch -; CHECK: [[shared_C]]: -; CHECK: [[x_C:%[^ ]+]] = call i32 @g() -; CHECK: [[i_C:%[^ ]+]] = call i32 @g() +; CHECK: catchpad within %cs [] +; CHECK: [[x_C:%[^ ]+]] = call i32 @llvm.qux() +; CHECK: [[i_C:%[^ ]+]] = call i32 @llvm.qux() ; CHECK: [[zt_C:%[^ ]+]] = icmp eq i32 [[i_C]], 0 ; CHECK: br i1 [[zt_C]], label %[[exit_C:[^ ]+]], label %[[loop_C:[^ ]+]] ; CHECK: [[shared_E]]: -; CHECK: [[x_E:%[^ ]+]] = call i32 @g() -; CHECK: [[i_E:%[^ ]+]] = call i32 @g() +; CHECK: [[x_E:%[^ ]+]] = call i32 @llvm.qux() +; CHECK: [[i_E:%[^ ]+]] = call i32 @llvm.qux() ; CHECK: [[zt_E:%[^ ]+]] = icmp eq i32 [[i_E]], 0 ; CHECK: br i1 [[zt_E]], label %[[exit_E:[^ ]+]], label %[[loop_E:[^ ]+]] ; CHECK: [[loop_C]]: -; CHECK: [[iloop_C:%[^ ]+]] = phi i32 [ [[i_C]], %[[shared_C]] ], [ [[idec_C:%[^ ]+]], %[[looptail_C:[^ ]+]] ] -; CHECK: [[b_C:%[^ ]+]] = call i1 @b() +; CHECK: [[iloop_C:%[^ ]+]] = phi i32 [ [[i_C]], %catch ], [ [[idec_C:%[^ ]+]], %[[looptail_C:[^ ]+]] ] +; CHECK: [[b_C:%[^ ]+]] = call i1 @llvm.baz() ; CHECK: br i1 [[b_C]], label %[[left_C:[^ ]+]], label %[[right_C:[^ ]+]] ; CHECK: [[loop_E]]: ; CHECK: [[iloop_E:%[^ ]+]] = phi i32 [ [[i_E]], %[[shared_E]] ], [ [[idec_E:%[^ ]+]], %[[looptail_E:[^ ]+]] ] -; CHECK: [[b_E:%[^ ]+]] = call i1 @b() +; CHECK: [[b_E:%[^ ]+]] = call i1 @llvm.baz() ; CHECK: br i1 [[b_E]], label %[[left_E:[^ ]+]], label %[[right_E:[^ ]+]] ; CHECK: [[left_C]]: -; CHECK: [[y_C:%[^ ]+]] = call i32 @g() +; CHECK: [[y_C:%[^ ]+]] = call i32 @llvm.qux() ; CHECK: br label %[[looptail_C]] ; CHECK: [[left_E]]: -; CHECK: [[y_E:%[^ ]+]] = call i32 @g() +; CHECK: [[y_E:%[^ ]+]] = call i32 @llvm.qux() ; CHECK: br label %[[looptail_E]] ; CHECK: [[right_C]]: -; CHECK: call void @h(i32 [[x_C]]) +; CHECK: call void @llvm.foo(i32 [[x_C]]) ; CHECK: br label %[[looptail_C]] ; CHECK: [[right_E]]: -; CHECK: call void @h(i32 [[x_E]]) +; CHECK: call void @llvm.foo(i32 [[x_E]]) ; CHECK: br label %[[looptail_E]] ; CHECK: [[looptail_C]]: ; CHECK: [[idec_C]] = sub i32 [[iloop_C]], 1 @@ -189,34 +188,32 @@ exit: ; CHECK: [[done_E:%[^ ]+]] = icmp eq i32 [[idec_E]], 0 ; CHECK: br i1 [[done_E]], label %[[exit_E]], label %[[loop_E]] ; CHECK: [[exit_C]]: -; CHECK: call void @h(i32 [[x_C]]) +; CHECK: call void @llvm.foo(i32 [[x_C]]) ; CHECK: unreachable ; CHECK: [[exit_E]]: -; CHECK: call void @h(i32 [[x_E]]) +; CHECK: call void @llvm.foo(i32 [[x_E]]) ; CHECK: unreachable -define void @test5() personality i32 (...)* @__CxxFrameHandler3 { +define void @test5() personality i32 (...)* @__C_specific_handler { entry: invoke void @f() to label %exit unwind label %outer outer: - %o = cleanuppad [] - %x = call i32 @g() - invoke void @f() - to label %outer.ret unwind label %inner + %o = cleanuppad within none [] + %x = call i32 @llvm.qux() + invoke void @f() [ "funclet"(token %o) ] + to label %outer.ret unwind label %catch.switch +catch.switch: + %cs = catchswitch within %o [label %inner] unwind to caller inner: - %i = catchpad [] - to label %inner.catch unwind label %inner.endcatch -inner.catch: - catchret %i to label %outer.post-inner -inner.endcatch: - catchendpad unwind to caller + %i = catchpad within %cs [] + catchret from %i to label %outer.post-inner outer.post-inner: - call void @h(i32 %x) + call void @llvm.foo(i32 %x) br label %outer.ret outer.ret: - cleanupret %o unwind to caller + cleanupret from %o unwind to caller exit: ret void } @@ -225,288 +222,32 @@ exit: ; and so don't need to be spilled. ; CHECK-LABEL: define void @test5( ; CHECK: outer: -; CHECK: %x = call i32 @g() +; CHECK: %x = call i32 @llvm.qux() ; CHECK-NEXT: invoke void @f() -; CHECK-NEXT: to label %outer.ret unwind label %inner +; CHECK-NEXT: to label %outer.ret unwind label %catch.switch ; CHECK: inner: -; CHECK: to label %inner.catch unwind label %inner.endcatch -; CHECK: inner.catch: -; CHECK-NEXT: catchret %i to label %outer.post-inner +; CHECK-NEXT: %i = catchpad within %cs [] +; CHECK-NEXT: catchret from %i to label %outer.post-inner ; CHECK: outer.post-inner: -; CHECK-NEXT: call void @h(i32 %x) +; CHECK-NEXT: call void @llvm.foo(i32 %x) ; CHECK-NEXT: br label %outer.ret -define void @test6() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %exit unwind label %right -left: - cleanuppad [] - br label %shared -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - %x = call i32 @g() - invoke void @f() - to label %shared.cont unwind label %inner -shared.cont: - unreachable -inner: - %i = cleanuppad [] - call void @h(i32 %x) - cleanupret %i unwind label %right.end -exit: - ret void -} -; %inner is a cleanup which appears both as a child of -; %left and as a child of %right. Since statically we -; need each funclet to have a single parent, we need to -; clone the entire %inner funclet so we can have one -; copy under each parent. The cleanupret in %inner -; unwinds to the catchendpad for %right, so the copy -; of %inner under %right should include it; the copy -; of %inner under %left should instead have an -; `unreachable` inserted there, but the copy under -; %left still needs to be created because it's possible -; the dynamic path enters %left, then enters %inner, -; then calls @h, and that the call to @h doesn't return. -; CHECK-LABEL: define void @test6( -; CHECK: left: -; CHECK: to label %[[SHARED_CONT_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: to label %right.catch unwind label %right.end -; CHECK: right.catch: -; CHECK: %x = call i32 @g() -; CHECK: store i32 %x, i32* %x.wineh.spillslot -; CHECK: to label %shared.cont unwind label %[[INNER_RIGHT:.+]] -; CHECK: right.end: -; CHECK: catchendpad unwind to caller -; CHECK: shared.cont: -; CHECK: unreachable -; CHECK: [[SHARED_CONT_LEFT]]: -; CHECK: unreachable -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_R:\%.+]] = cleanuppad [] -; CHECK: [[X_RELOAD_R:\%.+]] = load i32, i32* %x.wineh.spillslot -; CHECK: call void @h(i32 [[X_RELOAD_R]]) -; CHECK: cleanupret [[I_R]] unwind label %right.end -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_L:\%.+]] = cleanuppad [] -; CHECK: [[X_RELOAD_L:\%.+]] = load i32, i32* %x.wineh.spillslot -; CHECK: call void @h(i32 [[X_RELOAD_L]]) -; CHECK: unreachable - - -define void @test7() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %unreachable unwind label %right -left: - cleanuppad [] - invoke void @f() to label %unreachable unwind label %inner -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - invoke void @f() to label %unreachable unwind label %inner -right.end: - catchendpad unwind to caller -inner: - %i = cleanuppad [] - %x = call i32 @g() - call void @h(i32 %x) - cleanupret %i unwind label %right.end -unreachable: - unreachable -} -; Another case of a two-parent child (like @test6), this time -; with the join at the entry itself instead of following a -; non-pad join. -; CHECK-LABEL: define void @test7( -; CHECK: invoke.cont: -; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right -; CHECK: left: -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: to label %right.catch unwind label %right.end -; CHECK: right.catch: -; CHECK: to label %unreachable unwind label %[[INNER_RIGHT:.+]] -; CHECK: right.end: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_RIGHT]]: -; CHECK: [[I_R:\%.+]] = cleanuppad [] -; CHECK: [[X_R:\%.+]] = call i32 @g() -; CHECK: call void @h(i32 [[X_R]]) -; CHECK: cleanupret [[I_R]] unwind label %right.end -; CHECK: [[INNER_LEFT]]: -; CHECK: [[I_L:\%.+]] = cleanuppad [] -; CHECK: [[X_L:\%.+]] = call i32 @g() -; CHECK: call void @h(i32 [[X_L]]) -; CHECK: unreachable -; CHECK: unreachable: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_LEFT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_ENTRY]]: -; CHECK: unreachable - - -define void @test8() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %unreachable unwind label %right -left: - cleanuppad [] - br label %shared -right: - catchpad [] - to label %right.catch unwind label %right.end -right.catch: - br label %shared -right.end: - catchendpad unwind to caller -shared: - invoke void @f() - to label %unreachable unwind label %inner -inner: - cleanuppad [] - invoke void @f() - to label %unreachable unwind label %inner.child -inner.child: - cleanuppad [] - %x = call i32 @g() - call void @h(i32 %x) - unreachable -unreachable: - unreachable -} -; %inner is a two-parent child which itself has a child; need -; to make two copies of both the %inner and %inner.child. -; CHECK-LABEL: define void @test8( -; CHECK: invoke.cont: -; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %right -; CHECK: left: -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[INNER_LEFT:.+]] -; CHECK: right: -; CHECK: to label %right.catch unwind label %right.end -; CHECK: right.catch: -; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[INNER_RIGHT:.+]] -; CHECK: right.end: -; CHECK: catchendpad unwind to caller -; CHECK: [[INNER_RIGHT]]: -; CHECK: to label %[[UNREACHABLE_INNER_RIGHT:.+]] unwind label %[[INNER_CHILD_RIGHT:.+]] -; CHECK: [[INNER_LEFT]]: -; CHECK: to label %[[UNREACHABLE_INNER_LEFT:.+]] unwind label %[[INNER_CHILD_LEFT:.+]] -; CHECK: [[INNER_CHILD_RIGHT]]: -; CHECK: [[TMP:\%.+]] = cleanuppad [] -; CHECK: [[X:\%.+]] = call i32 @g() -; CHECK: call void @h(i32 [[X]]) -; CHECK: unreachable -; CHECK: [[INNER_CHILD_LEFT]]: -; CHECK: [[TMP:\%.+]] = cleanuppad [] -; CHECK: [[X:\%.+]] = call i32 @g() -; CHECK: call void @h(i32 [[X]]) -; CHECK: unreachable -; CHECK: [[UNREACHABLE_INNER_RIGHT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_INNER_LEFT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_RIGHT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_LEFT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_ENTRY]]: -; CHECK: unreachable - - -define void @test9() personality i32 (...)* @__CxxFrameHandler3 { -entry: - invoke void @f() - to label %invoke.cont unwind label %left -invoke.cont: - invoke void @f() - to label %unreachable unwind label %right -left: - cleanuppad [] - call void @h(i32 1) - invoke void @f() - to label %unreachable unwind label %right -right: - cleanuppad [] - call void @h(i32 2) - invoke void @f() - to label %unreachable unwind label %left -unreachable: - unreachable -} -; This is an irreducible loop with two funclets that enter each other; -; need to make two copies of each funclet (one a child of root, the -; other a child of the opposite funclet), but also make sure not to -; clone self-descendants (if we tried to do that we'd need to make an -; infinite number of them). Presumably if optimizations ever generated -; such a thing it would mean that one of the two cleanups was originally -; the parent of the other, but that we'd somehow lost track in the CFG -; of which was which along the way; generating each possibility lets -; whichever case was correct execute correctly. -; CHECK-LABEL: define void @test9( -; CHECK: entry: -; CHECK: to label %invoke.cont unwind label %[[LEFT:.+]] -; CHECK: invoke.cont: -; CHECK: to label %[[UNREACHABLE_ENTRY:.+]] unwind label %[[RIGHT:.+]] -; CHECK: [[LEFT_FROM_RIGHT:.+]]: -; CHECK: call void @h(i32 1) -; CHECK: call void @f() -; CHECK: unreachable -; CHECK: [[LEFT]]: -; CHECK: call void @h(i32 1) -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_LEFT:.+]] unwind label %[[RIGHT_FROM_LEFT:.+]] -; CHECK: [[RIGHT]]: -; CHECK: call void @h(i32 2) -; CHECK: invoke void @f() -; CHECK: to label %[[UNREACHABLE_RIGHT:.+]] unwind label %[[LEFT_FROM_RIGHT]] -; CHECK: [[RIGHT_FROM_LEFT]]: -; CHECK: call void @h(i32 2) -; CHECK: call void @f() -; CHECK: unreachable -; CHECK: [[UNREACHABLE_RIGHT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_LEFT]]: -; CHECK: unreachable -; CHECK: [[UNREACHABLE_ENTRY]]: -; CHECK: unreachable - - define void @test10() personality i32 (...)* @__CxxFrameHandler3 { entry: invoke void @f() to label %unreachable unwind label %inner inner: - %cleanup = cleanuppad [] + %cleanup = cleanuppad within none [] ; make sure we don't overlook this cleanupret and try to process ; successor %outer as a child of inner. - cleanupret %cleanup unwind label %outer + cleanupret from %cleanup unwind label %outer outer: - %catch = catchpad [] to label %catch.body unwind label %endpad + %cs = catchswitch within none [label %catch.body] unwind to caller + catch.body: - catchret %catch to label %exit -endpad: - catchendpad unwind to caller + %catch = catchpad within %cs [] + catchret from %catch to label %exit exit: ret void unreachable: @@ -517,47 +258,41 @@ unreachable: ; CHECK-NEXT: invoke ; CHECK-NEXT: to label %unreachable unwind label %inner ; CHECK: inner: -; CHECK-NEXT: %cleanup = cleanuppad -; CHECK-NEXT: cleanupret %cleanup unwind label %outer +; CHECK-NEXT: %cleanup = cleanuppad within none [] +; CHECK-NEXT: cleanupret from %cleanup unwind label %outer ; CHECK: outer: -; CHECK-NEXT: %catch = catchpad [] -; CHECK-NEXT: to label %catch.body unwind label %endpad +; CHECK-NEXT: %cs = catchswitch within none [label %catch.body] unwind to caller ; CHECK: catch.body: -; CHECK-NEXT: catchret %catch to label %exit -; CHECK: endpad: -; CHECK-NEXT: catchendpad unwind to caller +; CHECK-NEXT: %catch = catchpad within %cs [] +; CHECK-NEXT: catchret from %catch to label %exit ; CHECK: exit: ; CHECK-NEXT: ret void -define void @test11() personality i32 (...)* @__CxxFrameHandler3 { +define void @test11() personality i32 (...)* @__C_specific_handler { entry: invoke void @f() to label %exit unwind label %cleanup.outer cleanup.outer: - %outer = cleanuppad [] - invoke void @f() + %outer = cleanuppad within none [] + invoke void @f() [ "funclet"(token %outer) ] to label %outer.cont unwind label %cleanup.inner outer.cont: br label %merge cleanup.inner: - %inner = cleanuppad [] + %inner = cleanuppad within %outer [] br label %merge merge: - invoke void @f() - to label %unreachable unwind label %merge.end -unreachable: + call void @llvm.bar() unreachable -merge.end: - cleanupendpad %outer unwind to caller exit: ret void } ; merge.end will get cloned for outer and inner, but is implausible -; from inner, so the invoke @f() in inner's copy of merge should be +; from inner, so the call @f() in inner's copy of merge should be ; rewritten to call @f() ; CHECK-LABEL: define void @test11() -; CHECK: %inner = cleanuppad [] -; CHECK-NEXT: call void @f() +; CHECK: %inner = cleanuppad within %outer [] +; CHECK-NEXT: call void @llvm.bar() ; CHECK-NEXT: unreachable define void @test12() personality i32 (...)* @__CxxFrameHandler3 !dbg !5 { @@ -568,15 +303,15 @@ cont: invoke void @f() to label %exit unwind label %right left: - cleanuppad [] + cleanuppad within none [] br label %join right: - cleanuppad [] + cleanuppad within none [] br label %join join: ; This call will get cloned; make sure we can handle cloning ; instructions with debug metadata attached. - call void @f(), !dbg !9 + call void @llvm.bar(), !dbg !9 unreachable exit: ret void @@ -589,67 +324,53 @@ entry: ret void unreachable: - cleanuppad [] + cleanuppad within none [] unreachable } -define void @test14() personality i32 (...)* @__CxxFrameHandler3 { +define void @test14() personality void (...)* @ProcessCLRException { entry: invoke void @f() - to label %exit unwind label %catch1.pad -catch1.pad: - %catch1 = catchpad [i32 1] - to label %catch1.body unwind label %catch2.pad -catch1.body: - invoke void @h(i32 1) - to label %catch1.body2 unwind label %catch.end -catch1.body2: - invoke void @f() - to label %catch1.ret unwind label %cleanup1.pad -cleanup1.pad: - %cleanup1 = cleanuppad [] - call void @f() - cleanupret %cleanup1 unwind label %catch.end -catch1.ret: - catchret %catch1 to label %exit -catch2.pad: - %catch2 = catchpad [i32 2] - to label %catch2.body unwind label %catch.end -catch2.body: - invoke void @h(i32 2) - to label %catch2.body2 unwind label %catch.end -catch2.body2: + to label %cont unwind label %cleanup +cont: invoke void @f() - to label %catch2.ret unwind label %cleanup2.pad -cleanup2.pad: - %cleanup2 = cleanuppad [] - call void @f() - cleanupret %cleanup2 unwind label %catch.end -catch2.ret: - catchret %catch2 to label %exit -catch.end: - catchendpad unwind to caller + to label %exit unwind label %switch.outer +cleanup: + %cleanpad = cleanuppad within none [] + invoke void @f() [ "funclet" (token %cleanpad) ] + to label %cleanret unwind label %switch.inner +switch.inner: + %cs.inner = catchswitch within %cleanpad [label %pad.inner] unwind to caller +pad.inner: + %cp.inner = catchpad within %cs.inner [i32 1] + catchret from %cp.inner to label %join +cleanret: + cleanupret from %cleanpad unwind to caller +switch.outer: + %cs.outer = catchswitch within none [label %pad.outer] unwind to caller +pad.outer: + %cp.outer = catchpad within %cs.outer [i32 2] + catchret from %cp.outer to label %join +join: + %phi = phi i32 [ 1, %pad.inner ], [ 2, %pad.outer ] + call void @llvm.foo(i32 %phi) + unreachable exit: ret void } -; Make sure we don't clone the catchendpad even though the -; cleanupendpads targeting it would naively imply that it -; should get their respective parent colors (catch1 and catch2), -; as well as its properly getting the root function color. The -; references from the invokes ensure that if we did make clones -; for each catch, they'd be reachable, as those invokes would get -; rewritten +; Both catchrets target %join, but the catchret from %cp.inner +; returns to %cleanpad and the catchret from %cp.outer returns to the +; main function, so %join needs to get cloned and one of the cleanuprets +; needs to be updated to target the clone ; CHECK-LABEL: define void @test14() -; CHECK-NOT: catchendpad -; CHECK: invoke void @h(i32 1) -; CHECK-NEXT: unwind label %catch.end -; CHECK-NOT: catchendpad -; CHECK: invoke void @h(i32 2) -; CHECK-NEXT: unwind label %catch.end -; CHECK-NOT: catchendpad -; CHECK: catch.end: -; CHECK-NEXT: catchendpad -; CHECK-NOT: catchendpad +; CHECK: catchret from %cp.inner to label %[[Clone1:.+]] +; CHECK: catchret from %cp.outer to label %[[Clone2:.+]] +; CHECK: [[Clone1]]: +; CHECK-NEXT: call void @llvm.foo(i32 1) +; CHECK-NEXT: unreachable +; CHECK: [[Clone2]]: +; CHECK-NEXT: call void @llvm.foo(i32 2) +; CHECK-NEXT: unreachable ;; Debug info (from test12)