Skip to content

Commit

Permalink
[TapirUtils] Allow passes to clone exception-handling blocks of a
Browse files Browse the repository at this point in the history
task.  Allow SerializeDetach and cloneEHBlocks to update LoopInfo.
Fix dominator-tree updating logic in SerializeDetach and
cloneEHBlocks.f
  • Loading branch information
neboat committed Jun 12, 2022
1 parent 4f27072 commit 6cdbbd4
Show file tree
Hide file tree
Showing 3 changed files with 220 additions and 31 deletions.
15 changes: 14 additions & 1 deletion llvm/include/llvm/Transforms/Utils/TapirUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class BasicBlock;
class DominatorTree;
class DomTreeUpdater;
class Loop;
class LoopInfo;
class Spindle;
class Task;
class TaskInfo;
Expand Down Expand Up @@ -96,6 +97,18 @@ bool MoveStaticAllocasInBlock(BasicBlock *Entry, BasicBlock *Block,
/// \p DT is provided, then it will be updated to reflect the CFG changes.
void InlineTaskFrameResumes(Value *TaskFrame, DominatorTree *DT = nullptr);

/// Clone exception-handling blocks EHBlocksToClone, with predecessors
/// EHBlockPreds in a given task. Updates EHBlockPreds to point at the cloned
/// blocks. If the given pointers are non-null, updates blocks in *InlinedLPads
/// and *DetachedRethrows to refer to cloned blocks, and updates DT and LI to
/// reflect CFG updates.
void cloneEHBlocks(Function *F, SmallVectorImpl<BasicBlock *> &EHBlocksToClone,
SmallPtrSetImpl<BasicBlock *> &EHBlockPreds,
const char *Suffix,
SmallPtrSetImpl<LandingPadInst *> *InlinedLPads,
SmallVectorImpl<Instruction *> *DetachedRethrows,
DominatorTree *DT = nullptr, LoopInfo *LI = nullptr);

/// Serialize the detach DI. \p ParentEntry should be the entry block of the
/// task that contains DI. \p Reattaches, \p InlinedLPads, and \p
/// DetachedRethrows identify the reattaches, landing pads, and detached
Expand All @@ -109,7 +122,7 @@ void SerializeDetach(DetachInst *DI, BasicBlock *ParentEntry,
SmallPtrSetImpl<BasicBlock *> *EHBlockPreds,
SmallPtrSetImpl<LandingPadInst *> *InlinedLPads,
SmallVectorImpl<Instruction *> *DetachedRethrows,
DominatorTree *DT = nullptr);
DominatorTree *DT = nullptr, LoopInfo *LI = nullptr);

/// Analyze a task T for serialization. Gets the reattaches, landing pads, and
/// detached rethrows that need special handling during serialization.
Expand Down
123 changes: 93 additions & 30 deletions llvm/lib/Transforms/Utils/TapirUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/UnrollLoop.h"
#include "llvm/Transforms/Utils/ValueMapper.h"

using namespace llvm;
Expand Down Expand Up @@ -288,7 +289,7 @@ bool llvm::MoveStaticAllocasInBlock(
// Leave lifetime markers for the static alloca's, scoping them to the
// from cloned block to cloned exit.
if (!StaticAllocas.empty()) {
IRBuilder<> Builder(&Block->front());
IRBuilder<> Builder(&*Block->getFirstInsertionPt());
for (unsigned ai = 0, ae = StaticAllocas.size(); ai != ae; ++ai) {
AllocaInst *AI = StaticAllocas[ai];
// Don't mark swifterror allocas. They can't have bitcast uses.
Expand Down Expand Up @@ -507,18 +508,15 @@ void LandingPadInliningInfo::forwardTaskResume(InvokeInst *TR) {

// Update the DT
BasicBlock *NormalDest = nullptr, *UnwindDest = nullptr;
SmallVector<DominatorTree::UpdateType, 8> Updates;
if (DT) {
if (TR->getNormalDest()->getSinglePredecessor()) {
if (TR->getNormalDest()->getSinglePredecessor())
NormalDest = TR->getNormalDest();
DT->eraseNode(TR->getNormalDest());
} else
DT->deleteEdge(Src, TR->getNormalDest());
Updates.push_back({DominatorTree::Delete, Src, TR->getNormalDest()});

if (TR->getUnwindDest()->getSinglePredecessor()) {
if (TR->getUnwindDest()->getSinglePredecessor())
UnwindDest = TR->getUnwindDest();
DT->eraseNode(TR->getUnwindDest());
} else
DT->deleteEdge(Src, TR->getUnwindDest());
Updates.push_back({DominatorTree::Delete, Src, TR->getUnwindDest()});
}

// Remove the TR
Expand All @@ -529,6 +527,11 @@ void LandingPadInliningInfo::forwardTaskResume(InvokeInst *TR) {

TR->eraseFromParent();

if (DT) {
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
DTU.applyUpdates(Updates);
}

if (NormalDest) {
for (BasicBlock *Succ : successors(NormalDest))
maybeRemovePredecessor(Succ, NormalDest);
Expand Down Expand Up @@ -565,26 +568,41 @@ static void handleDetachedLandingPads(
DetUnwind.forwardTaskResume(cast<InvokeInst>(DR));
}

static void cloneEHBlocks(Function *F, Value *SyncRegion,
SmallVectorImpl<BasicBlock *> &EHBlocksToClone,
SmallPtrSetImpl<BasicBlock *> &EHBlockPreds,
SmallPtrSetImpl<LandingPadInst *> *InlinedLPads,
SmallVectorImpl<Instruction *> *DetachedRethrows,
DominatorTree *DT = nullptr) {
void llvm::cloneEHBlocks(Function *F,
SmallVectorImpl<BasicBlock *> &EHBlocksToClone,
SmallPtrSetImpl<BasicBlock *> &EHBlockPreds,
const char *Suffix,
SmallPtrSetImpl<LandingPadInst *> *InlinedLPads,
SmallVectorImpl<Instruction *> *DetachedRethrows,
DominatorTree *DT, LoopInfo *LI) {
ValueToValueMapTy VMap;
SmallVector<BasicBlock *, 8> NewBlocks;
SmallPtrSet<BasicBlock *, 8> NewBlocksSet;
SmallPtrSet<LandingPadInst *, 4> NewInlinedLPads;
SmallPtrSet<Instruction *, 4> NewDetachedRethrows;
NewLoopsMap NewLoops;
for (BasicBlock *BB : EHBlocksToClone) {
BasicBlock *New = CloneBasicBlock(BB, VMap, ".sd", F);
BasicBlock *New = CloneBasicBlock(BB, VMap, Suffix, F);
VMap[BB] = New;
if (DT)
DT->addNewBlock(New, DT->getRoot());

// If the cloned block is inside of a loop, update LoopInfo.
if (LI && LI->getLoopFor(BB)) {
Loop *OldLoop = LI->getLoopFor(BB);
Loop *ParentLoop = OldLoop->getParentLoop();
if (ParentLoop && !NewLoops.count(ParentLoop))
NewLoops[ParentLoop] = ParentLoop;
addClonedBlockToLoopInfo(BB, New, LI, NewLoops);
}

NewBlocks.push_back(New);
NewBlocksSet.insert(New);
}

// Remap instructions in the cloned blocks based on VMap.
remapInstructionsInBlocks(NewBlocks, VMap);

SmallPtrSet<BasicBlock *, 8> NewSuccSet;
// For all old successors, remove the predecessors in EHBlockPreds.
for (BasicBlock *EHPred : EHBlockPreds)
Expand All @@ -609,37 +627,62 @@ static void cloneEHBlocks(Function *F, Value *SyncRegion,
}
}

// Update the dominator tree and edges from EHBlockPreds to cloned EHBlocks.
for (BasicBlock *EHBlock : EHBlocksToClone) {
BasicBlock *NewEHBlock = cast<BasicBlock>(VMap[EHBlock]);
BasicBlock *IDomBB = nullptr;
if (DT) {
BasicBlock *IDomBB = DT->getNode(EHBlock)->getIDom()->getBlock();
if (VMap.lookup(IDomBB))
IDomBB = DT->getNode(EHBlock)->getIDom()->getBlock();
if (VMap.count(IDomBB)) {
DT->changeImmediateDominator(cast<BasicBlock>(VMap[EHBlock]),
cast<BasicBlock>(VMap[IDomBB]));
else
DT->changeImmediateDominator(cast<BasicBlock>(VMap[EHBlock]), IDomBB);
} else {
IDomBB = nullptr;
// Get the idom of EHBlock's predecessors.
for (BasicBlock *Pred : predecessors(EHBlock)) {
if (EHBlockPreds.contains(Pred)) {
if (IDomBB)
IDomBB = DT->findNearestCommonDominator(IDomBB, Pred);
else
IDomBB = Pred;
}
}
assert(IDomBB && "Found no predecessors of EHBlock in EHBlockPreds.");
// Use this computed idom (or its clone) as the idom of the cloned
// EHBlock.
if (VMap.count(IDomBB)) {
DT->changeImmediateDominator(cast<BasicBlock>(VMap[EHBlock]),
cast<BasicBlock>(VMap[IDomBB]));
} else {
DT->changeImmediateDominator(cast<BasicBlock>(VMap[EHBlock]),
IDomBB);
}
}
}
// Move the edges from Preds to point to NewBB instead of BB.
}

// Move the edges from Preds to point to NewEHBlock instead of EHBlock.
for (BasicBlock *EHBlock : EHBlocksToClone) {
BasicBlock *NewEHBlock = cast<BasicBlock>(VMap[EHBlock]);
DomTreeNodeBase<BasicBlock> *Node = DT ? DT->getNode(EHBlock) : nullptr;
BasicBlock *EHBlockIDom = Node ? Node->getIDom()->getBlock() : nullptr;
for (BasicBlock *Pred : EHBlockPreds) {
// This is slightly more strict than necessary; the minimum requirement is
// that there be no more than one indirectbr branching to BB. And all
// BlockAddress uses would need to be updated.
assert(!isa<IndirectBrInst>(Pred->getTerminator()) &&
"Cannot split an edge from an IndirectBrInst");
Pred->getTerminator()->replaceUsesOfWith(EHBlock, NewEHBlock);
if (DT && Pred == IDomBB)
if (DT && EHBlockIDom)
DT->deleteEdge(Pred, EHBlock);
}
}

// Remap instructions in the cloned blocks based on VMap.
remapInstructionsInBlocks(NewBlocks, VMap);

// Update all successors of the cloned EH blocks.
for (BasicBlock *BB : EHBlocksToClone) {
for (BasicBlock *Succ : successors(BB)) {
if (NewBlocksSet.count(Succ)) continue;
if (NewBlocksSet.count(Succ) || VMap.count(Succ))
continue;

// Update the PHI's in the successor of the cloned EH block.
for (PHINode &PN : Succ->phis()) {
Value *Val = PN.getIncomingValueForBlock(BB);
Expand All @@ -649,6 +692,24 @@ static void cloneEHBlocks(Function *F, Value *SyncRegion,
}
}

if (DT && LI) {
// If any EHBlocks become unreachable, update LoopInfo to remove the
// relevant loops.
for (BasicBlock *EHBlock : EHBlocksToClone) {
if (!DT->isReachableFromEntry(EHBlock)) {
if (LI->isLoopHeader(EHBlock)) {
// Delete the whole loop.
Loop *L = LI->getLoopFor(EHBlock);
if (Loop *ParentL = L->getParentLoop())
ParentL->removeChildLoop(llvm::find(*ParentL, L));
else
LI->removeLoop(llvm::find(*LI, L));
}
LI->removeBlock(EHBlock);
}
}
}

// Move the new InlinedLPads and DetachedRethrows to the appropriate
// set/vector.
if (InlinedLPads) {
Expand Down Expand Up @@ -758,7 +819,7 @@ void llvm::SerializeDetach(DetachInst *DI, BasicBlock *ParentEntry,
SmallPtrSetImpl<BasicBlock *> *EHBlockPreds,
SmallPtrSetImpl<LandingPadInst *> *InlinedLPads,
SmallVectorImpl<Instruction *> *DetachedRethrows,
DominatorTree *DT) {
DominatorTree *DT, LoopInfo *LI) {
BasicBlock *Spawner = DI->getParent();
BasicBlock *TaskEntry = DI->getDetached();
BasicBlock *Continue = DI->getContinue();
Expand All @@ -773,8 +834,8 @@ void llvm::SerializeDetach(DetachInst *DI, BasicBlock *ParentEntry,
if (EHBlocksToClone) {
assert(EHBlockPreds &&
"Given EH blocks to clone, but not blocks exiting to them.");
cloneEHBlocks(Spawner->getParent(), SyncRegion, *EHBlocksToClone,
*EHBlockPreds, InlinedLPads, DetachedRethrows, DT);
cloneEHBlocks(Spawner->getParent(), *EHBlocksToClone, *EHBlockPreds, ".sd",
InlinedLPads, DetachedRethrows, DT, LI);
}

// Collect the exit points into a single vector.
Expand Down Expand Up @@ -865,12 +926,14 @@ void llvm::AnalyzeTaskForSerialization(
// Skip basic blocks that are placeholder successors
if (isPlaceholderSuccessor(BB))
continue;

EHBlocksToClone.push_back(BB);
if (S->getEntry() == BB)
for (BasicBlock *Pred : predecessors(BB))
if (T->simplyEncloses(Pred))
EHBlockPreds.insert(Pred);
}

if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator())) {
if (!isDetachedRethrow(BB->getTerminator(), SyncRegion)) {
assert(!isDetachedRethrow(BB->getTerminator()) &&
Expand Down
113 changes: 113 additions & 0 deletions llvm/test/Transforms/Tapir/task-simplify-domtree-update.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
; Verify that task-simplify properly handles with unreachable blocks,
; specifically, during its incremental updates to the dominator tree.
;
; RUN: opt < %s -task-simplify -S -o - | FileCheck %s
; RUN: opt < %s -passes='task-simplify' -S -o - | FileCheck %s

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@_ZTIi = external dso_local constant i8*
@.str.16 = external dso_local unnamed_addr constant [9 x i8], align 1

declare dso_local i32 @__gxx_personality_v0(...)

declare dso_local void @_ZN3ObjC2EPKc() unnamed_addr #0 align 2

; Function Attrs: argmemonly nounwind willreturn
declare token @llvm.syncregion.start() #1

; Function Attrs: argmemonly nounwind willreturn
declare token @llvm.taskframe.create() #1

; Function Attrs: argmemonly willreturn
declare void @llvm.taskframe.resume.sl_p0i8i32s(token, { i8*, i32 }) #2

define dso_local void @main() local_unnamed_addr #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
entry:
%syncreg = call token @llvm.syncregion.start()
%syncreg54 = call token @llvm.syncregion.start()
%syncreg157 = call token @llvm.syncregion.start()
invoke void @_ZN3ObjC2EPKc()
to label %invoke.cont unwind label %lpad

; CHECK: entry
; CHECK: invoke void @_ZN3ObjC2EPKc()
; CHECK-NEXT: to label %[[CONT:.+]] unwind label %[[UNWIND:.+]]

; CHECK: [[CONT]]:
; CHECK: unreachable

; CHECK: [[UNWIND]]:
; CHECK: landingpad
; CHECK-NEXT: cleanup
; CHECK-NEXT: catch
; CHECK: unreachable

invoke.cont: ; preds = %entry
%0 = call token @llvm.taskframe.create()
detach within %syncreg, label %det.achd, label %det.cont unwind label %lpad6

det.achd: ; preds = %invoke.cont
unreachable

det.cont: ; preds = %invoke.cont
%1 = call token @llvm.taskframe.create()
unreachable

lpad: ; preds = %entry
%2 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (i8** @_ZTIi to i8*)
%3 = call token @llvm.taskframe.create()
br label %det.achd55

lpad6: ; preds = %invoke.cont
%4 = landingpad { i8*, i32 }
cleanup
invoke void @llvm.taskframe.resume.sl_p0i8i32s(token %0, { i8*, i32 } %4)
to label %unreachable unwind label %lpad13

lpad13: ; preds = %lpad6
%5 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (i8** @_ZTIi to i8*)
unreachable

det.achd55: ; preds = %lpad
unreachable

det.cont68: ; No predecessors!
%6 = call token @llvm.taskframe.create()
detach within %syncreg54, label %det.achd75, label %det.cont88 unwind label %lpad85

det.achd75: ; preds = %det.cont68
unreachable

det.cont88: ; preds = %det.cont68
%7 = call token @llvm.taskframe.create()
unreachable

lpad74: ; preds = %lpad85
%8 = landingpad { i8*, i32 }
cleanup
catch i8* bitcast (i8** @_ZTIi to i8*)
unreachable

lpad85: ; preds = %det.cont68
%9 = landingpad { i8*, i32 }
cleanup
invoke void @llvm.taskframe.resume.sl_p0i8i32s(token %6, { i8*, i32 } %9)
to label %unreachable unwind label %lpad74

unreachable: ; preds = %lpad85, %lpad6
unreachable
}

attributes #0 = { "use-soft-float"="false" }
attributes #1 = { argmemonly nounwind willreturn }
attributes #2 = { argmemonly willreturn }

!llvm.ident = !{!0}

!0 = !{!"clang version 12.0.0 ([email protected]:OpenCilk/opencilk-project.git 31ad596bd7126d79fa36fd82538084e8a8f4d913)"}

0 comments on commit 6cdbbd4

Please sign in to comment.