Mercurial > hg > CbC > CbC_llvm
diff test/CodeGen/WinEH/wineh-cloning.ll @ 100:7d135dc70f03 LLVM 3.9
LLVM 3.9
author | Miyagi Mitsuki <e135756@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 26 Jan 2016 22:53:40 +0900 |
parents | afa8332a0e37 |
children | 1172e4bd9c6f |
line wrap: on
line diff
--- a/test/CodeGen/WinEH/wineh-cloning.ll Tue Oct 13 17:49:56 2015 +0900 +++ b/test/CodeGen/WinEH/wineh-cloning.ll Tue Jan 26 22:53:40 2016 +0900 @@ -1,57 +1,58 @@ -; 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 { +define void @test2() personality i32 (...)* @__C_specific_handler { 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 @@ ; 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 { +define void @test3() personality i32 (...)* @__C_specific_handler { 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 @@ ; CHECK: invoke void @f() ; CHECK: to label %[[exit:[^ ]+]] unwind ; CHECK: catch: -; CHECK: catchpad [] -; CHECK-NEXT: to label %[[shared:[^ ]+]] unwind +; CHECK: catchpad within %cs [] +; CHECK-NEXT: call void @llvm.bar() +; CHECK-NEXT: unreachable ; CHECK: cleanup: -; CHECK: cleanuppad [] -; CHECK: call void @f() -; CHECK-NEXT: unreachable -; CHECK: [[shared]]: -; CHECK: call void @f() +; CHECK: cleanuppad within none [] +; CHECK: call void @llvm.bar() ; CHECK-NEXT: unreachable ; CHECK: [[exit]]: ; CHECK: ret void @@ -113,33 +113,33 @@ 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 @@ ; 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 @@ ; 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,181 +222,32 @@ ; 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( -; TODO: CHECKs - - -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( -; TODO: CHECKs - - -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( -; TODO: CHECKs - - -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( -; TODO: CHECKs - 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: @@ -410,50 +258,44 @@ ; 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 { +define void @test12() personality i32 (...)* @__CxxFrameHandler3 !dbg !5 { entry: invoke void @f() to label %cont unwind label %left, !dbg !8 @@ -461,15 +303,15 @@ 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 @@ -482,10 +324,56 @@ ret void unreachable: - cleanuppad [] + cleanuppad within none [] unreachable } +define void @test14() personality void (...)* @ProcessCLRException { +entry: + invoke void @f() + to label %cont unwind label %cleanup +cont: + invoke void @f() + 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 +} +; 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: 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) + ; Make sure the DISubprogram doesn't get cloned ; CHECK-LABEL: !llvm.module.flags ; CHECK-NOT: !DISubprogram @@ -499,7 +387,7 @@ !2 = !DIFile(filename: "test.cpp", directory: ".") !3 = !{} !4 = !{!5} -!5 = distinct !DISubprogram(name: "test12", scope: !2, file: !2, type: !6, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, function: void ()* @test12, variables: !3) +!5 = distinct !DISubprogram(name: "test12", scope: !2, file: !2, type: !6, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, variables: !3) !6 = !DISubroutineType(types: !7) !7 = !{null} !8 = !DILocation(line: 1, scope: !5)