mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-17 08:57:34 +00:00
[WinEH] Clone funclets with multiple parents
Windows EH funclets need to always return to a single parent funclet. However, it is possible for earlier optimizations to combine funclets (probably based on one funclet having an unreachable terminator) in such a way that this condition is violated. These changes add code to the WinEHPrepare pass to detect situations where a funclet has multiple parents and clone such funclets, fixing up the unwind and catch return edges so that each copy of the funclet returns to the correct parent funclet. Differential Revision: http://reviews.llvm.org/D13274?id=39098 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252249 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
11e0c3127e
commit
b508d4bda2
@ -5322,7 +5322,8 @@ bool LLParser::ParseCleanupEndPad(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
if (Lex.getKind() == lltok::kw_caller) {
|
||||
Lex.Lex();
|
||||
} else {
|
||||
return true;
|
||||
return Error(Lex.getLoc(),
|
||||
"'to' must be followed by 'caller' in catchendpad");
|
||||
}
|
||||
} else {
|
||||
if (ParseTypeAndBasicBlock(UnwindBB, PFS)) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -280,7 +280,30 @@ exit:
|
||||
; 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
|
||||
; 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 {
|
||||
@ -312,7 +335,32 @@ unreachable:
|
||||
; with the join at the entry itself instead of following a
|
||||
; non-pad join.
|
||||
; CHECK-LABEL: define void @test7(
|
||||
; TODO: CHECKs
|
||||
; 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 {
|
||||
@ -350,7 +398,40 @@ 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
|
||||
; 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 {
|
||||
@ -383,7 +464,33 @@ unreachable:
|
||||
; of which was which along the way; generating each possibility lets
|
||||
; whichever case was correct execute correctly.
|
||||
; CHECK-LABEL: define void @test9(
|
||||
; TODO: CHECKs
|
||||
; 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:
|
||||
|
@ -86,18 +86,18 @@ catch.inner:
|
||||
; CHECK: store i32 %z
|
||||
; CHECK-NEXT: invoke void @f
|
||||
invoke void @f()
|
||||
to label %catchret.inner unwind label %merge.outer
|
||||
to label %catchret.inner unwind label %catchend.inner
|
||||
|
||||
catchret.inner:
|
||||
catchret %cpinner to label %exit
|
||||
catchend.inner:
|
||||
; CHECK-NOT: = phi
|
||||
%y = phi i32 [ %x, %merge.inner ], [ %z, %catch.inner ]
|
||||
catchendpad unwind label %merge.outer
|
||||
|
||||
merge.outer:
|
||||
; CHECK: merge.outer:
|
||||
; CHECK-NOT: = phi
|
||||
; CHECK: [[CatchPad:%[^ ]+]] = catchpad []
|
||||
%y = phi i32 [ %x, %catchend.inner ], [ %z, %catch.inner ]
|
||||
%cpouter = catchpad [] to label %catch.outer unwind label %catchend.outer
|
||||
|
||||
catchend.outer:
|
||||
|
1557
test/CodeGen/WinEH/wineh-multi-parent-cloning.ll
Normal file
1557
test/CodeGen/WinEH/wineh-multi-parent-cloning.ll
Normal file
File diff suppressed because it is too large
Load Diff
@ -39,12 +39,20 @@ shared.cont:
|
||||
unreachable
|
||||
|
||||
inner:
|
||||
; CHECK: %phi = phi i32 [ %x, %right ], [ 0, %invoke.cont2 ], [ %x.for.left, %left ]
|
||||
%phi = phi i32 [ %x, %shared ], [ 0, %invoke.cont2 ]
|
||||
%i = cleanuppad []
|
||||
call void @h(i32 %phi)
|
||||
unreachable
|
||||
|
||||
; CHECK [[INNER_INVOKE_CONT2:inner.*]]:
|
||||
; CHECK: call void @h(i32 0)
|
||||
|
||||
; CHECK [[INNER_RIGHT:inner.*]]:
|
||||
; CHECK: call void @h(i32 %x)
|
||||
|
||||
; CHECK [[INNER_LEFT:inner.*]]:
|
||||
; CHECK: call void @h(i32 %x.for.left)
|
||||
|
||||
exit:
|
||||
unreachable
|
||||
}
|
||||
@ -76,12 +84,16 @@ shared.cont:
|
||||
unreachable
|
||||
|
||||
inner:
|
||||
; CHECK: %x1 = phi i32 [ %x.for.left, %left ], [ %x, %right ]
|
||||
; CHECK: call void @h(i32 %x1)
|
||||
%i = cleanuppad []
|
||||
call void @h(i32 %x)
|
||||
unreachable
|
||||
|
||||
; CHECK [[INNER_RIGHT:inner.*]]:
|
||||
; CHECK: call void @h(i32 %x)
|
||||
|
||||
; CHECK [[INNER_LEFT:inner.*]]:
|
||||
; CHECK: call void @h(i32 %x.for.left)
|
||||
|
||||
exit:
|
||||
unreachable
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user