Skip to content

Commit 70e9716

Browse files
committed
[DTU] Refine the interface and logic of applyUpdates
Summary: This patch separates two semantics of `applyUpdates`: 1. User provides an accurate CFG diff and the dominator tree is updated according to the difference of `the number of edge insertions` and `the number of edge deletions` to infer the status of an edge before and after the update. 2. User provides a sequence of hints. Updates mentioned in this sequence might never happened and even duplicated. Logic changes: Previously, removing invalid updates is considered a side-effect of deduplication and is not guaranteed to be reliable. To handle the second semantic, `applyUpdates` does validity checking before deduplication, which can cause updates that have already been applied to be submitted again. Then, different calls to `applyUpdates` might cause unintended consequences, for example, ``` DTU(Lazy) and Edge A->B exists. 1. DTU.applyUpdates({{Delete, A, B}, {Insert, A, B}}) // User expects these 2 updates result in a no-op, but {Insert, A, B} is queued 2. Remove A->B 3. DTU.applyUpdates({{Delete, A, B}}) // DTU cancels this update with {Insert, A, B} mentioned above together (Unintended) ``` But by restricting the precondition that updates of an edge need to be strictly ordered as how CFG changes were made, we can infer the initial status of this edge to resolve this issue. Interface changes: The second semantic of `applyUpdates` is separated to `applyUpdatesPermissive`. These changes enable DTU(Lazy) to use the first semantic if needed, which is quite useful in `transforms/utils`. Reviewers: kuhar, brzycki, dmgreen, grosser Reviewed By: brzycki Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D58170 llvm-svn: 354669
1 parent ab86d3d commit 70e9716

File tree

8 files changed

+207
-129
lines changed

8 files changed

+207
-129
lines changed

llvm/include/llvm/Analysis/DomTreeUpdater.h

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,24 @@ class DomTreeUpdater {
103103
/// Although GenericDomTree provides several update primitives,
104104
/// it is not encouraged to use these APIs directly.
105105

106-
/// Submit updates to all available trees. Under Eager UpdateStrategy with
107-
/// ForceRemoveDuplicates enabled or under Lazy UpdateStrategy, it will
106+
/// Submit updates to all available trees.
107+
/// The Eager Strategy flushes updates immediately while the Lazy Strategy
108+
/// queues the updates.
109+
///
110+
/// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
111+
/// in sync with + all updates before that single update.
112+
///
113+
/// CAUTION!
114+
/// 1. It is required for the state of the LLVM IR to be updated
115+
/// *before* submitting the updates because the internal update routine will
116+
/// analyze the current state of the CFG to determine whether an update
117+
/// is valid.
118+
/// 2. It is illegal to submit any update that has already been submitted,
119+
/// i.e., you are supposed not to insert an existent edge or delete a
120+
/// nonexistent edge.
121+
void applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates);
122+
123+
/// Submit updates to all available trees. It will also
108124
/// 1. discard duplicated updates,
109125
/// 2. remove invalid updates. (Invalid updates means deletion of an edge that
110126
/// still exists or insertion of an edge that does not exist.)
@@ -122,8 +138,10 @@ class DomTreeUpdater {
122138
/// 2. It is illegal to submit any update that has already been submitted,
123139
/// i.e., you are supposed not to insert an existent edge or delete a
124140
/// nonexistent edge.
125-
void applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates,
126-
bool ForceRemoveDuplicates = false);
141+
/// 3. It is only legal to submit updates to an edge in the order CFG changes
142+
/// are made. The order you submit updates on different edges is not
143+
/// restricted.
144+
void applyUpdatesPermissive(ArrayRef<DominatorTree::UpdateType> Updates);
127145

128146
/// Notify DTU that the entry block was replaced.
129147
/// Recalculate all available trees and flush all BasicBlocks
@@ -149,7 +167,7 @@ class DomTreeUpdater {
149167
/// submitted. }
150168
LLVM_ATTRIBUTE_DEPRECATED(void insertEdgeRelaxed(BasicBlock *From,
151169
BasicBlock *To),
152-
"Use applyUpdates() instead.");
170+
"Use applyUpdatesPermissive() instead.");
153171

154172
/// \deprecated { Submit an edge deletion to all available trees. The Eager
155173
/// Strategy flushes this update immediately while the Lazy Strategy queues
@@ -171,7 +189,7 @@ class DomTreeUpdater {
171189
/// submitted. }
172190
LLVM_ATTRIBUTE_DEPRECATED(void deleteEdgeRelaxed(BasicBlock *From,
173191
BasicBlock *To),
174-
"Use applyUpdates() instead.");
192+
"Use applyUpdatesPermissive() instead.");
175193

176194
/// Delete DelBB. DelBB will be removed from its Parent and
177195
/// erased from available trees if it exists and finally get deleted.
@@ -260,11 +278,6 @@ class DomTreeUpdater {
260278
/// Returns true if at least one BasicBlock is deleted.
261279
bool forceFlushDeletedBB();
262280

263-
/// Deduplicate and remove unnecessary updates (no-ops) when using Lazy
264-
/// UpdateStrategy. Returns true if the update is queued for update.
265-
bool applyLazyUpdate(DominatorTree::UpdateKind Kind, BasicBlock *From,
266-
BasicBlock *To);
267-
268281
/// Helper function to apply all pending DomTree updates.
269282
void applyDomTreeUpdates();
270283

llvm/lib/Analysis/DomTreeUpdater.cpp

Lines changed: 64 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "llvm/Analysis/DomTreeUpdater.h"
15+
#include "llvm/ADT/SmallSet.h"
1516
#include "llvm/Analysis/PostDominators.h"
1617
#include "llvm/IR/Dominators.h"
1718
#include "llvm/Support/GenericDomTree.h"
1819
#include <algorithm>
1920
#include <functional>
21+
#include <utility>
2022

2123
namespace llvm {
2224

@@ -53,41 +55,6 @@ bool DomTreeUpdater::isSelfDominance(
5355
return Update.getFrom() == Update.getTo();
5456
}
5557

56-
bool DomTreeUpdater::applyLazyUpdate(DominatorTree::UpdateKind Kind,
57-
BasicBlock *From, BasicBlock *To) {
58-
assert((DT || PDT) &&
59-
"Call applyLazyUpdate() when both DT and PDT are nullptrs.");
60-
assert(Strategy == DomTreeUpdater::UpdateStrategy::Lazy &&
61-
"Call applyLazyUpdate() with Eager strategy error");
62-
// Analyze pending updates to determine if the update is unnecessary.
63-
const DominatorTree::UpdateType Update = {Kind, From, To};
64-
const DominatorTree::UpdateType Invert = {Kind != DominatorTree::Insert
65-
? DominatorTree::Insert
66-
: DominatorTree::Delete,
67-
From, To};
68-
// Only check duplicates in updates that are not applied by both trees.
69-
auto I =
70-
PendUpdates.begin() + std::max(PendDTUpdateIndex, PendPDTUpdateIndex);
71-
const auto E = PendUpdates.end();
72-
73-
assert(I <= E && "Iterator out of range.");
74-
75-
for (; I != E; ++I) {
76-
if (Update == *I)
77-
return false; // Discard duplicate updates.
78-
79-
if (Invert == *I) {
80-
// Update and Invert are both valid (equivalent to a no-op). Remove
81-
// Invert from PendUpdates and discard the Update.
82-
PendUpdates.erase(I);
83-
return false;
84-
}
85-
}
86-
87-
PendUpdates.push_back(Update); // Save the valid update.
88-
return true;
89-
}
90-
9158
void DomTreeUpdater::applyDomTreeUpdates() {
9259
// No pending DomTreeUpdates.
9360
if (Strategy != UpdateStrategy::Lazy || !DT)
@@ -261,31 +228,15 @@ void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
261228
new UnreachableInst(DelBB->getContext(), DelBB);
262229
}
263230

264-
void DomTreeUpdater::applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates,
265-
bool ForceRemoveDuplicates) {
231+
void DomTreeUpdater::applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates) {
266232
if (!DT && !PDT)
267233
return;
268234

269-
if (Strategy == UpdateStrategy::Lazy || ForceRemoveDuplicates) {
270-
SmallVector<DominatorTree::UpdateType, 8> Seen;
235+
if (Strategy == UpdateStrategy::Lazy) {
271236
for (const auto U : Updates)
272-
// For Lazy UpdateStrategy, avoid duplicates to applyLazyUpdate() to save
273-
// on analysis.
274-
if (llvm::none_of(
275-
Seen,
276-
[U](const DominatorTree::UpdateType S) { return S == U; }) &&
277-
isUpdateValid(U) && !isSelfDominance(U)) {
278-
Seen.push_back(U);
279-
if (Strategy == UpdateStrategy::Lazy)
280-
applyLazyUpdate(U.getKind(), U.getFrom(), U.getTo());
281-
}
282-
if (Strategy == UpdateStrategy::Lazy)
283-
return;
237+
if (!isSelfDominance(U))
238+
PendUpdates.push_back(U);
284239

285-
if (DT)
286-
DT->applyUpdates(Seen);
287-
if (PDT)
288-
PDT->applyUpdates(Seen);
289240
return;
290241
}
291242

@@ -295,6 +246,60 @@ void DomTreeUpdater::applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates,
295246
PDT->applyUpdates(Updates);
296247
}
297248

249+
void DomTreeUpdater::applyUpdatesPermissive(
250+
ArrayRef<DominatorTree::UpdateType> Updates) {
251+
if (!DT && !PDT)
252+
return;
253+
254+
SmallSet<std::pair<BasicBlock *, BasicBlock *>, 8> Seen;
255+
SmallVector<DominatorTree::UpdateType, 8> DeduplicatedUpdates;
256+
for (const auto U : Updates) {
257+
auto Edge = std::make_pair(U.getFrom(), U.getTo());
258+
// Because it is illegal to submit updates that have already been applied
259+
// and updates to an edge need to be strictly ordered,
260+
// it is safe to infer the existence of an edge from the first update
261+
// to this edge.
262+
// If the first update to an edge is "Delete", it means that the edge
263+
// existed before. If the first update to an edge is "Insert", it means
264+
// that the edge didn't exist before.
265+
//
266+
// For example, if the user submits {{Delete, A, B}, {Insert, A, B}},
267+
// because
268+
// 1. it is illegal to submit updates that have already been applied,
269+
// i.e., user cannot delete an nonexistent edge,
270+
// 2. updates to an edge need to be strictly ordered,
271+
// So, initially edge A -> B existed.
272+
// We can then safely ignore future updates to this edge and directly
273+
// inspect the current CFG:
274+
// a. If the edge still exists, because the user cannot insert an existent
275+
// edge, so both {Delete, A, B}, {Insert, A, B} actually happened and
276+
// resulted in a no-op. DTU won't submit any update in this case.
277+
// b. If the edge doesn't exist, we can then infer that {Delete, A, B}
278+
// actually happened but {Insert, A, B} was an invalid update which never
279+
// happened. DTU will submit {Delete, A, B} in this case.
280+
if (!isSelfDominance(U) && Seen.count(Edge) == 0) {
281+
Seen.insert(Edge);
282+
// If the update doesn't appear in the CFG, it means that
283+
// either the change isn't made or relevant operations
284+
// result in a no-op.
285+
if (isUpdateValid(U)) {
286+
if (isLazy())
287+
PendUpdates.push_back(U);
288+
else
289+
DeduplicatedUpdates.push_back(U);
290+
}
291+
}
292+
}
293+
294+
if (Strategy == UpdateStrategy::Lazy)
295+
return;
296+
297+
if (DT)
298+
DT->applyUpdates(DeduplicatedUpdates);
299+
if (PDT)
300+
PDT->applyUpdates(DeduplicatedUpdates);
301+
}
302+
298303
DominatorTree &DomTreeUpdater::getDomTree() {
299304
assert(DT && "Invalid acquisition of a null DomTree");
300305
applyDomTreeUpdates();
@@ -331,7 +336,7 @@ void DomTreeUpdater::insertEdge(BasicBlock *From, BasicBlock *To) {
331336
return;
332337
}
333338

334-
applyLazyUpdate(DominatorTree::Insert, From, To);
339+
PendUpdates.push_back({DominatorTree::Insert, From, To});
335340
}
336341

337342
void DomTreeUpdater::insertEdgeRelaxed(BasicBlock *From, BasicBlock *To) {
@@ -352,7 +357,7 @@ void DomTreeUpdater::insertEdgeRelaxed(BasicBlock *From, BasicBlock *To) {
352357
return;
353358
}
354359

355-
applyLazyUpdate(DominatorTree::Insert, From, To);
360+
PendUpdates.push_back({DominatorTree::Insert, From, To});
356361
}
357362

358363
void DomTreeUpdater::deleteEdge(BasicBlock *From, BasicBlock *To) {
@@ -377,7 +382,7 @@ void DomTreeUpdater::deleteEdge(BasicBlock *From, BasicBlock *To) {
377382
return;
378383
}
379384

380-
applyLazyUpdate(DominatorTree::Delete, From, To);
385+
PendUpdates.push_back({DominatorTree::Delete, From, To});
381386
}
382387

383388
void DomTreeUpdater::deleteEdgeRelaxed(BasicBlock *From, BasicBlock *To) {
@@ -398,7 +403,7 @@ void DomTreeUpdater::deleteEdgeRelaxed(BasicBlock *From, BasicBlock *To) {
398403
return;
399404
}
400405

401-
applyLazyUpdate(DominatorTree::Delete, From, To);
406+
PendUpdates.push_back({DominatorTree::Delete, From, To});
402407
}
403408

404409
void DomTreeUpdater::dropOutOfDateUpdates() {

llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ static void splitCallSite(
366366
assert(Splits.size() == 2 && "Expected exactly 2 splits!");
367367
for (unsigned i = 0; i < Splits.size(); i++) {
368368
Splits[i]->getTerminator()->eraseFromParent();
369-
DTU.applyUpdates({{DominatorTree::Delete, Splits[i], TailBB}});
369+
DTU.applyUpdatesPermissive({{DominatorTree::Delete, Splits[i], TailBB}});
370370
}
371371

372372
// Erase the tail block once done with musttail patching

llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ static bool processSwitch(SwitchInst *SI, LazyValueInfo *LVI,
373373
++NumDeadCases;
374374
Changed = true;
375375
if (--SuccessorsCount[Succ] == 0)
376-
DTU.applyUpdates({{DominatorTree::Delete, BB, Succ}});
376+
DTU.applyUpdatesPermissive({{DominatorTree::Delete, BB, Succ}});
377377
continue;
378378
}
379379
if (State == LazyValueInfo::True) {

llvm/lib/Transforms/Scalar/JumpThreading.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
10911091
<< "' folding undef terminator: " << *BBTerm << '\n');
10921092
BranchInst::Create(BBTerm->getSuccessor(BestSucc), BBTerm);
10931093
BBTerm->eraseFromParent();
1094-
DTU->applyUpdates(Updates);
1094+
DTU->applyUpdatesPermissive(Updates);
10951095
return true;
10961096
}
10971097

@@ -1159,7 +1159,8 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
11591159
ConstantInt::getFalse(CondCmp->getType());
11601160
ReplaceFoldableUses(CondCmp, CI);
11611161
}
1162-
DTU->applyUpdates({{DominatorTree::Delete, BB, ToRemoveSucc}});
1162+
DTU->applyUpdatesPermissive(
1163+
{{DominatorTree::Delete, BB, ToRemoveSucc}});
11631164
return true;
11641165
}
11651166

@@ -1246,7 +1247,7 @@ bool JumpThreadingPass::ProcessImpliedCondition(BasicBlock *BB) {
12461247
RemoveSucc->removePredecessor(BB);
12471248
BranchInst::Create(KeepSucc, BI);
12481249
BI->eraseFromParent();
1249-
DTU->applyUpdates({{DominatorTree::Delete, BB, RemoveSucc}});
1250+
DTU->applyUpdatesPermissive({{DominatorTree::Delete, BB, RemoveSucc}});
12501251
return true;
12511252
}
12521253
CurrentBB = CurrentPred;
@@ -1676,7 +1677,7 @@ bool JumpThreadingPass::ProcessThreadableEdges(Value *Cond, BasicBlock *BB,
16761677
Instruction *Term = BB->getTerminator();
16771678
BranchInst::Create(OnlyDest, Term);
16781679
Term->eraseFromParent();
1679-
DTU->applyUpdates(Updates);
1680+
DTU->applyUpdatesPermissive(Updates);
16801681

16811682
// If the condition is now dead due to the removal of the old terminator,
16821683
// erase it.
@@ -2018,9 +2019,9 @@ bool JumpThreadingPass::ThreadEdge(BasicBlock *BB,
20182019
}
20192020

20202021
// Enqueue required DT updates.
2021-
DTU->applyUpdates({{DominatorTree::Insert, NewBB, SuccBB},
2022-
{DominatorTree::Insert, PredBB, NewBB},
2023-
{DominatorTree::Delete, PredBB, BB}});
2022+
DTU->applyUpdatesPermissive({{DominatorTree::Insert, NewBB, SuccBB},
2023+
{DominatorTree::Insert, PredBB, NewBB},
2024+
{DominatorTree::Delete, PredBB, BB}});
20242025

20252026
// If there were values defined in BB that are used outside the block, then we
20262027
// now have to update all uses of the value to use either the original value,
@@ -2114,7 +2115,7 @@ BasicBlock *JumpThreadingPass::SplitBlockPreds(BasicBlock *BB,
21142115
BFI->setBlockFreq(NewBB, NewBBFreq.getFrequency());
21152116
}
21162117

2117-
DTU->applyUpdates(Updates);
2118+
DTU->applyUpdatesPermissive(Updates);
21182119
return NewBBs[0];
21192120
}
21202121

@@ -2387,7 +2388,7 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred(
23872388

23882389
// Remove the unconditional branch at the end of the PredBB block.
23892390
OldPredBranch->eraseFromParent();
2390-
DTU->applyUpdates(Updates);
2391+
DTU->applyUpdatesPermissive(Updates);
23912392

23922393
++NumDupes;
23932394
return true;
@@ -2423,8 +2424,8 @@ void JumpThreadingPass::UnfoldSelectInstr(BasicBlock *Pred, BasicBlock *BB,
24232424

24242425
// The select is now dead.
24252426
SI->eraseFromParent();
2426-
DTU->applyUpdates({{DominatorTree::Insert, NewBB, BB},
2427-
{DominatorTree::Insert, Pred, NewBB}});
2427+
DTU->applyUpdatesPermissive({{DominatorTree::Insert, NewBB, BB},
2428+
{DominatorTree::Insert, Pred, NewBB}});
24282429

24292430
// Update any other PHI nodes in BB.
24302431
for (BasicBlock::iterator BI = BB->begin();
@@ -2601,7 +2602,7 @@ bool JumpThreadingPass::TryToUnfoldSelectInCurrBB(BasicBlock *BB) {
26012602
Updates.push_back({DominatorTree::Delete, BB, Succ});
26022603
Updates.push_back({DominatorTree::Insert, SplitBB, Succ});
26032604
}
2604-
DTU->applyUpdates(Updates);
2605+
DTU->applyUpdatesPermissive(Updates);
26052606
return true;
26062607
}
26072608
return false;

llvm/lib/Transforms/Utils/BasicBlockUtils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ void llvm::DeleteDeadBlocks(ArrayRef <BasicBlock *> BBs, DomTreeUpdater *DTU,
101101
DetatchDeadBlocks(BBs, DTU ? &Updates : nullptr, KeepOneInputPHIs);
102102

103103
if (DTU)
104-
DTU->applyUpdates(Updates, /*ForceRemoveDuplicates*/ true);
104+
DTU->applyUpdatesPermissive(Updates);
105105

106106
for (BasicBlock *BB : BBs)
107107
if (DTU)
@@ -235,7 +235,7 @@ bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DomTreeUpdater *DTU,
235235
isa<UnreachableInst>(BB->getTerminator()) &&
236236
"The successor list of BB isn't empty before "
237237
"applying corresponding DTU updates.");
238-
DTU->applyUpdates(Updates, /*ForceRemoveDuplicates*/ true);
238+
DTU->applyUpdatesPermissive(Updates);
239239
DTU->deleteBB(BB);
240240
}
241241

0 commit comments

Comments
 (0)