mirror of
https://github.com/RPCS3/llvm.git
synced 2025-04-02 21:31:41 +00:00
[WinEHPrepare] Fix catchret successor phi demotion
Summary: When demoting an SSA value that has a use on a phi and one of the phi's predecessors terminates with catchret, the edge needs to be split and the load inserted in the new block, else we'll still have a cross-funclet SSA value. Add a test for this, and for the similar case where a def to be spilled is on and invoke and a critical edge, which was already implemented but missing a test. Reviewers: majnemer Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D12065 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@245218 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
378e97e50c
commit
08b10aaafe
@ -3289,6 +3289,42 @@ void WinEHPrepare::replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot,
|
||||
// coming in from the same block, which is illegal SSA form.
|
||||
// For this reason, we keep track of and reuse loads we insert.
|
||||
BasicBlock *IncomingBlock = UsingPHI->getIncomingBlock(U);
|
||||
if (auto *CatchRet =
|
||||
dyn_cast<CatchReturnInst>(IncomingBlock->getTerminator())) {
|
||||
// Putting a load above a catchret and use on the phi would still leave
|
||||
// a cross-funclet def/use. We need to split the edge, change the
|
||||
// catchret to target the new block, and put the load there.
|
||||
BasicBlock *PHIBlock = UsingInst->getParent();
|
||||
BasicBlock *NewBlock = SplitEdge(IncomingBlock, PHIBlock);
|
||||
// SplitEdge gives us:
|
||||
// IncomingBlock:
|
||||
// ...
|
||||
// br label %NewBlock
|
||||
// NewBlock:
|
||||
// catchret label %PHIBlock
|
||||
// But we need:
|
||||
// IncomingBlock:
|
||||
// ...
|
||||
// catchret label %NewBlock
|
||||
// NewBlock:
|
||||
// br label %PHIBlock
|
||||
// So move the terminators to each others' blocks and swap their
|
||||
// successors.
|
||||
BranchInst *Goto = cast<BranchInst>(IncomingBlock->getTerminator());
|
||||
Goto->removeFromParent();
|
||||
CatchRet->removeFromParent();
|
||||
IncomingBlock->getInstList().push_back(CatchRet);
|
||||
NewBlock->getInstList().push_back(Goto);
|
||||
Goto->setSuccessor(0, PHIBlock);
|
||||
CatchRet->setSuccessor(NewBlock);
|
||||
// Update the color mapping for the newly split edge.
|
||||
std::set<BasicBlock *> &ColorsForPHIBlock = BlockColors[PHIBlock];
|
||||
BlockColors[NewBlock] = ColorsForPHIBlock;
|
||||
for (BasicBlock *FuncletPad : ColorsForPHIBlock)
|
||||
FuncletBlocks[FuncletPad].insert(NewBlock);
|
||||
// Treat the new block as incoming for load insertion.
|
||||
IncomingBlock = NewBlock;
|
||||
}
|
||||
Value *&Load = Loads[IncomingBlock];
|
||||
// Insert the load into the predecessor block
|
||||
if (!Load)
|
||||
|
@ -294,3 +294,89 @@ catchend:
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test6(
|
||||
define void @test6() personality i32 (...)* @__CxxFrameHandler3 {
|
||||
entry:
|
||||
; Since %x needs to be stored but the edge to loop is critical,
|
||||
; it needs to be split
|
||||
; CHECK: entry:
|
||||
; CHECK: invoke i32 @g
|
||||
; CHECK-NEXT: to label %[[SplitBlock:[^ ]+]] unwind label %to_caller
|
||||
%x = invoke i32 @g()
|
||||
to label %loop unwind label %to_caller
|
||||
; The store should be in the split block
|
||||
; CHECK: [[SplitBlock]]:
|
||||
; CHECK: store i32 %x, i32* [[SpillSlot:%[^ ]+]]
|
||||
; CHECK: br label %loop
|
||||
to_caller:
|
||||
cleanuppad void []
|
||||
cleanupret void unwind to caller
|
||||
loop:
|
||||
invoke void @f()
|
||||
to label %loop unwind label %cleanup
|
||||
cleanup:
|
||||
; CHECK: cleanup:
|
||||
; CHECK: [[Load:%[^ ]+]] = load i32, i32* [[SpillSlot]]
|
||||
; CHECK: call void @h(i32 [[Load]])
|
||||
cleanuppad void []
|
||||
call void @h(i32 %x)
|
||||
cleanupret void unwind to caller
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @test7(
|
||||
define void @test7() personality i32 (...)* @__CxxFrameHandler3 {
|
||||
entry:
|
||||
; %x is an EH pad phi, so gets stored in pred here
|
||||
; CHECK: entry:
|
||||
; CHECK: store i32 1, i32* [[SlotX:%[^ ]+]]
|
||||
; CHECK: invoke void @f()
|
||||
invoke void @f()
|
||||
to label %invoke.cont unwind label %catchpad
|
||||
invoke.cont:
|
||||
; %x is an EH pad phi, so gets stored in pred here
|
||||
; CHECK: invoke.cont:
|
||||
; CHECK: store i32 2, i32* [[SlotX]]
|
||||
; CHECK: invoke void @f()
|
||||
invoke void @f()
|
||||
to label %exit unwind label %catchpad
|
||||
catchpad:
|
||||
; %x phi should be eliminated
|
||||
; CHECK: catchpad:
|
||||
; CHECK-NEXT: catchpad void
|
||||
%x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ]
|
||||
catchpad void [] to label %catch unwind label %catchend
|
||||
catch:
|
||||
%b = call i1 @i()
|
||||
br i1 %b, label %left, label %right
|
||||
left:
|
||||
; Edge from %left to %join needs to be split so that
|
||||
; the load of %x can be inserted *after* the catchret
|
||||
; CHECK: left:
|
||||
; CHECK-NEXT: catchret void to label %[[SplitLeft:[^ ]+]]
|
||||
catchret void to label %join
|
||||
; CHECK: [[SplitLeft]]:
|
||||
; CHECK: [[LoadX:%[^ ]+]] = load i32, i32* [[SlotX]]
|
||||
; CHECK: br label %join
|
||||
right:
|
||||
; Edge from %right to %join needs to be split so that
|
||||
; the load of %y can be inserted *after* the catchret
|
||||
; CHECK: right:
|
||||
; CHECK: store i32 %y, i32* [[SlotY:%[^ ]+]]
|
||||
; CHECK: catchret void to label %[[SplitRight:[^ ]+]]
|
||||
%y = call i32 @g()
|
||||
catchret void to label %join
|
||||
; CHECK: [[SplitRight]]:
|
||||
; CHECK: [[LoadY:%[^ ]+]] = load i32, i32* [[SlotY]]
|
||||
; CHECK: br label %join
|
||||
catchend:
|
||||
catchendpad unwind to caller
|
||||
join:
|
||||
; CHECK: join:
|
||||
; CHECK: %phi = phi i32 [ [[LoadX]], %[[SplitLeft]] ], [ [[LoadY]], %[[SplitRight]] ]
|
||||
%phi = phi i32 [ %x, %left ], [ %y, %right ]
|
||||
call void @h(i32 %phi)
|
||||
br label %exit
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user