Skip to content

Commit

Permalink
[WinEH] Update catchrets with cloned successors
Browse files Browse the repository at this point in the history
Summary:
Add a pass to update catchrets when their successors get cloned; the
existing pass doesn't catch these because it walks the funclet whose
blocks are being cloned but the catchret is in a child funclet.

Also update the test for removing incoming PHI values; when the
predecessor is a catchret, the relevant color is the catchret's parentPad,
not its block's color.


Reviewers: andrew.w.kaylor, rnk, majnemer

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D15840

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256689 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
JosephTremoulet committed Jan 2, 2016
1 parent 8e6708e commit d5ab13d
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 4 deletions.
42 changes: 38 additions & 4 deletions lib/CodeGen/WinEHPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,11 @@ void WinEHPrepare::cloneCommonBlocks(Function &F) {
for (auto &Funclets : FuncletBlocks) {
BasicBlock *FuncletPadBB = Funclets.first;
std::vector<BasicBlock *> &BlocksInFunclet = Funclets.second;
Value *FuncletToken;
if (FuncletPadBB == &F.getEntryBlock())
FuncletToken = ConstantTokenNone::get(F.getContext());
else
FuncletToken = FuncletPadBB->getFirstNonPHI();

std::vector<std::pair<BasicBlock *, BasicBlock *>> Orig2Clone;
ValueToValueMapTy VMap;
Expand Down Expand Up @@ -669,15 +674,44 @@ void WinEHPrepare::cloneCommonBlocks(Function &F) {
RemapInstruction(&I, VMap,
RF_IgnoreMissingEntries | RF_NoModuleLevelChanges);

// Catchrets targeting cloned blocks need to be updated separately from
// the loop above because they are not in the current funclet.
SmallVector<CatchReturnInst *, 2> FixupCatchrets;
for (auto &BBMapping : Orig2Clone) {
BasicBlock *OldBlock = BBMapping.first;
BasicBlock *NewBlock = BBMapping.second;

FixupCatchrets.clear();
for (BasicBlock *Pred : predecessors(OldBlock))
if (auto *CatchRet = dyn_cast<CatchReturnInst>(Pred->getTerminator()))
if (CatchRet->getParentPad() == FuncletToken)
FixupCatchrets.push_back(CatchRet);

for (CatchReturnInst *CatchRet : FixupCatchrets)
CatchRet->setSuccessor(NewBlock);
}

auto UpdatePHIOnClonedBlock = [&](PHINode *PN, bool IsForOldBlock) {
unsigned NumPreds = PN->getNumIncomingValues();
for (unsigned PredIdx = 0, PredEnd = NumPreds; PredIdx != PredEnd;
++PredIdx) {
BasicBlock *IncomingBlock = PN->getIncomingBlock(PredIdx);
ColorVector &IncomingColors = BlockColors[IncomingBlock];
bool BlockInFunclet = IncomingColors.size() == 1 &&
IncomingColors.front() == FuncletPadBB;
if (IsForOldBlock != BlockInFunclet)
bool EdgeTargetsFunclet;
if (auto *CRI =
dyn_cast<CatchReturnInst>(IncomingBlock->getTerminator())) {
EdgeTargetsFunclet = (CRI->getParentPad() == FuncletToken);
} else {
ColorVector &IncomingColors = BlockColors[IncomingBlock];
assert(!IncomingColors.empty() && "Block not colored!");
assert((IncomingColors.size() == 1 ||
llvm::all_of(IncomingColors,
[&](BasicBlock *Color) {
return Color != FuncletPadBB;
})) &&
"Cloning should leave this funclet's blocks monochromatic");
EdgeTargetsFunclet = (IncomingColors.front() == FuncletPadBB);
}
if (IsForOldBlock != EdgeTargetsFunclet)
continue;
PN->removeIncomingValue(IncomingBlock, /*DeletePHIIfEmpty=*/false);
// Revisit the next entry.
Expand Down
45 changes: 45 additions & 0 deletions test/CodeGen/WinEH/wineh-cloning.ll
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

declare i32 @__CxxFrameHandler3(...)
declare i32 @__C_specific_handler(...)
declare void @ProcessCLRException(...)

declare void @f()

Expand Down Expand Up @@ -369,6 +370,50 @@ unreachable:
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
Expand Down

0 comments on commit d5ab13d

Please sign in to comment.