Skip to content

Commit ad55fd1

Browse files
authored
Merge pull request swiftlang#34949 from gottesmm/pr-1fb3bad22e50b7ec605b680cc78d2c521a35dc27
[basicblock-utils] Add new API: JointPostDominanceSetComputer and its method findJointPostDominatingSet(...).
2 parents 2d299de + a6027fc commit ad55fd1

File tree

2 files changed

+197
-2
lines changed

2 files changed

+197
-2
lines changed

include/swift/SIL/BasicBlockUtils.h

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#ifndef SWIFT_SIL_DEADENDBLOCKS_H
14-
#define SWIFT_SIL_DEADENDBLOCKS_H
13+
#ifndef SWIFT_SIL_BASICBLOCKUTILS_H
14+
#define SWIFT_SIL_BASICBLOCKUTILS_H
1515

1616
#include "swift/SIL/SILValue.h"
1717
#include "llvm/ADT/SetVector.h"
18+
#include "llvm/ADT/SmallPtrSet.h"
1819
#include "llvm/ADT/SmallVector.h"
1920

2021
namespace swift {
@@ -90,6 +91,90 @@ class DeadEndBlocks {
9091
}
9192
};
9293

94+
/// A struct that contains the intermediate state used in computing
95+
/// joint-dominance sets. Enables a pass to easily reuse the same small data
96+
/// structures with clearing (noting that clearing our internal state does not
97+
/// cause us to shrink meaning that once we malloc, we keep the malloced
98+
/// memory).
99+
struct JointPostDominanceSetComputer {
100+
/// The worklist that drives the algorithm.
101+
SmallVector<SILBasicBlock *, 32> worklist;
102+
103+
/// A set that guards our worklist. Any block before it is added to worklist
104+
/// should be checked against visitedBlocks.
105+
SmallPtrSet<SILBasicBlock *, 32> visitedBlocks;
106+
107+
/// The set of blocks where we begin our walk.
108+
SmallPtrSet<SILBasicBlock *, 8> initialBlocks;
109+
110+
/// A subset of our initial blocks that we found as a predecessor of another
111+
/// block along our walk.
112+
SmallVector<SILBasicBlock *, 8> reachableInputBlocks;
113+
114+
/// As we process the worklist, any successors that we see that have not been
115+
/// visited yet are placed in here. At the end of our worklist, any blocks
116+
/// that remain here are "leaking blocks" that together with our initial set
117+
/// would provide a jointly-postdominating set of our dominating value.
118+
SmallSetVector<SILBasicBlock *, 8> blocksThatLeakIfNeverVisited;
119+
120+
DeadEndBlocks &deadEndBlocks;
121+
122+
JointPostDominanceSetComputer(DeadEndBlocks &deadEndBlocks)
123+
: deadEndBlocks(deadEndBlocks) {}
124+
125+
void clear() {
126+
worklist.clear();
127+
visitedBlocks.clear();
128+
initialBlocks.clear();
129+
reachableInputBlocks.clear();
130+
blocksThatLeakIfNeverVisited.clear();
131+
}
132+
133+
/// Compute joint-postdominating set for \p dominatingBlock and \p
134+
/// dominatedBlockSet found by walking up the CFG from the latter to the
135+
/// former.
136+
///
137+
/// We pass back the following information via callbacks so our callers can
138+
/// use whatever container they need to:
139+
///
140+
/// * inputBlocksFoundDuringWalk: Any blocks from the "dominated
141+
/// block set" that was found as a predecessor block during our traversal is
142+
/// passed to this callback. These can occur for two reasons:
143+
///
144+
/// 1. We actually had a block in \p dominatedBlockSet that was reachable
145+
/// from another block in said set. This is a valid usage of the API
146+
/// since it could be that the user does not care about such uses and
147+
/// leave this callback empty.
148+
///
149+
/// 2. We had a block in \p dominatedBlockSet that is in a sub-loop in the
150+
/// loop-nest relative to \p dominatingBlock causing us to go around a
151+
/// backedge and hit the block during our traversal. In this case, we
152+
/// have already during the traversal passed the exiting blocks of the
153+
/// sub-loop as joint postdominace completion set blocks. This is useful
154+
/// if one is using this API for lifetime extension purposes of lifetime
155+
/// ending uses and one needs to insert compensating copy_value at these
156+
/// locations due to the lack of strong control-equivalence in between
157+
/// the block and \p dominatingBlock.
158+
///
159+
///
160+
/// * foundJointPostDomSetCompletionBlocks: The set of blocks not in \p
161+
/// dominatedBlockSet that together with \p dominatedBlockSet
162+
/// jointly-postdominate \p dominatedBlock. This is "completing" the joint
163+
/// post-dominance set.
164+
///
165+
/// * inputBlocksInJointPostDomSet: Any of our input blocks that were never
166+
/// found as a predecessor is passed to this callback. This block is in the
167+
/// final minimal joint-postdominance set and is passed to this
168+
/// callback. This is optional and we will avoid doing work if it is not
169+
/// set.
170+
void findJointPostDominatingSet(
171+
SILBasicBlock *dominatingBlock,
172+
ArrayRef<SILBasicBlock *> dominatedBlockSet,
173+
function_ref<void(SILBasicBlock *)> inputBlocksFoundDuringWalk,
174+
function_ref<void(SILBasicBlock *)> foundJointPostDomSetCompletionBlocks,
175+
function_ref<void(SILBasicBlock *)> inputBlocksInJointPostDomSet = {});
176+
};
177+
93178
} // namespace swift
94179

95180
#endif

lib/SIL/Utils/BasicBlockUtils.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/SIL/BasicBlockUtils.h"
14+
#include "swift/Basic/STLExtras.h"
1415
#include "swift/SIL/Dominance.h"
1516
#include "swift/SIL/LoopInfo.h"
1617
#include "swift/SIL/SILArgument.h"
1718
#include "swift/SIL/SILBasicBlock.h"
1819
#include "swift/SIL/SILBuilder.h"
1920
#include "swift/SIL/SILFunction.h"
2021
#include "swift/SIL/TerminatorUtils.h"
22+
#include "llvm/ADT/STLExtras.h"
2123

2224
using namespace swift;
2325

@@ -378,3 +380,111 @@ void DeadEndBlocks::compute() {
378380
ReachableBlocks.insert(Pred);
379381
}
380382
}
383+
384+
//===----------------------------------------------------------------------===//
385+
// Post Dominance Set Completion Utilities
386+
//===----------------------------------------------------------------------===//
387+
388+
void JointPostDominanceSetComputer::findJointPostDominatingSet(
389+
SILBasicBlock *dominatingBlock, ArrayRef<SILBasicBlock *> dominatedBlockSet,
390+
function_ref<void(SILBasicBlock *)> foundInputBlocksNotInJointPostDomSet,
391+
function_ref<void(SILBasicBlock *)> foundJointPostDomSetCompletionBlocks,
392+
function_ref<void(SILBasicBlock *)> foundInputBlocksInJointPostDomSet) {
393+
// If our reachable block set is empty, assert. This is most likely programmer
394+
// error.
395+
assert(dominatedBlockSet.size() != 0);
396+
397+
// If we have a reachable block set with a single block and that block is
398+
// dominatingBlock, then we return success since a block post-doms its self so
399+
// it is already complete.
400+
if (dominatedBlockSet.size() == 1) {
401+
if (dominatingBlock == dominatedBlockSet[0]) {
402+
if (foundInputBlocksInJointPostDomSet)
403+
foundInputBlocksInJointPostDomSet(dominatingBlock);
404+
return;
405+
}
406+
}
407+
408+
// At the top of where we for sure are going to use state... make sure we
409+
// always clean up any resources that we use!
410+
SWIFT_DEFER { clear(); };
411+
412+
// Otherwise, we need to compute our joint post dominating set. We do this by
413+
// performing a backwards walk up the CFG tracking back liveness until we find
414+
// our dominating block. As we walk up, we keep track of any successor blocks
415+
// that we need to visit before the walk completes lest we leak. After we
416+
// finish the walk, these leaking blocks are a valid (albeit not unique)
417+
// completion of the post dom set.
418+
for (auto *block : dominatedBlockSet) {
419+
// Skip dead end blocks.
420+
if (deadEndBlocks.isDeadEnd(block))
421+
continue;
422+
423+
// We require dominatedBlockSet to be a set and thus assert if we hit it to
424+
// flag user error to our caller.
425+
bool succeededInserting = visitedBlocks.insert(block).second;
426+
(void)succeededInserting;
427+
assert(succeededInserting &&
428+
"Repeat Elt: dominatedBlockSet should be a set?!");
429+
initialBlocks.insert(block);
430+
worklist.push_back(block);
431+
}
432+
433+
// Then until we run out of blocks...
434+
while (!worklist.empty()) {
435+
auto *block = worklist.pop_back_val();
436+
437+
// First remove block from blocksThatLeakIfNeverVisited if it is there since
438+
// we know that it isn't leaking since we are visiting it now.
439+
blocksThatLeakIfNeverVisited.remove(block);
440+
441+
// Then if our block is not one of our initial blocks, add the block's
442+
// successors to blocksThatLeakIfNeverVisited.
443+
if (!initialBlocks.count(block)) {
444+
for (auto *succBlock : block->getSuccessorBlocks()) {
445+
if (visitedBlocks.count(succBlock))
446+
continue;
447+
if (deadEndBlocks.isDeadEnd(succBlock))
448+
continue;
449+
blocksThatLeakIfNeverVisited.insert(succBlock);
450+
}
451+
}
452+
453+
// If we are the dominating block, we are done.
454+
if (dominatingBlock == block)
455+
continue;
456+
457+
// Otherwise for each predecessor that we have, first check if it was one of
458+
// our initial blocks (signaling a loop) and then add it to the worklist if
459+
// we haven't visited it already.
460+
for (auto *predBlock : block->getPredecessorBlocks()) {
461+
if (initialBlocks.count(predBlock)) {
462+
reachableInputBlocks.push_back(predBlock);
463+
}
464+
if (visitedBlocks.insert(predBlock).second)
465+
worklist.push_back(predBlock);
466+
}
467+
}
468+
469+
// After our worklist has emptied, any blocks left in
470+
// blocksThatLeakIfNeverVisited are "leaking blocks".
471+
for (auto *leakingBlock : blocksThatLeakIfNeverVisited)
472+
foundJointPostDomSetCompletionBlocks(leakingBlock);
473+
474+
// Then unique our list of reachable input blocks and pass them to our
475+
// callback.
476+
sortUnique(reachableInputBlocks);
477+
for (auto *block : reachableInputBlocks)
478+
foundInputBlocksNotInJointPostDomSet(block);
479+
480+
// Then if were asked to find the subset of our input blocks that are in the
481+
// joint-postdominance set, compute that.
482+
if (!foundInputBlocksInJointPostDomSet)
483+
return;
484+
485+
// Pass back the reachable input blocks that were not reachable from other
486+
// input blocks to.
487+
for (auto *block : dominatedBlockSet)
488+
if (lower_bound(reachableInputBlocks, block) == reachableInputBlocks.end())
489+
foundInputBlocksInJointPostDomSet(block);
490+
}

0 commit comments

Comments
 (0)