Skip to content

Commit b16f340

Browse files
authored
Merge pull request #35684 from eeckstein/fix-find-jpds
SIL: fix problems in findJointPostDominatingSet and some refactoring
2 parents 2c920c9 + f19f9b0 commit b16f340

15 files changed

+305
-286
lines changed

include/swift/SIL/BasicBlockUtils.h

Lines changed: 50 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -88,83 +88,59 @@ class DeadEndBlocks {
8888
bool isComputed() const { return didComputeValue; }
8989

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

100+
/// Compute joint-postdominating set for \p dominatingBlock and \p
101+
/// dominatedBlockSet found by walking up the CFG from the latter to the
102+
/// former.
103+
///
104+
/// We pass back the following information via callbacks so our callers can
105+
/// use whatever container they need to:
106+
///
107+
/// * inputBlocksFoundDuringWalk: Any blocks from the "dominated
108+
/// block set" that was found as a predecessor block during our traversal is
109+
/// passed to this callback. These can occur for two reasons:
110+
///
111+
/// 1. We actually had a block in \p dominatedBlockSet that was reachable
112+
/// from another block in said set. This is a valid usage of the API
113+
/// since it could be that the user does not care about such uses and
114+
/// leave this callback empty.
115+
///
116+
/// 2. We had a block in \p dominatedBlockSet that is in a sub-loop in the
117+
/// loop-nest relative to \p dominatingBlock causing us to go around a
118+
/// backedge and hit the block during our traversal. In this case, we
119+
/// have already during the traversal passed the exiting blocks of the
120+
/// sub-loop as joint postdominace completion set blocks. This is useful
121+
/// if one is using this API for lifetime extension purposes of lifetime
122+
/// ending uses and one needs to insert compensating copy_value at these
123+
/// locations due to the lack of strong control-equivalence in between
124+
/// the block and \p dominatingBlock.
125+
///
126+
///
127+
/// * foundJointPostDomSetCompletionBlocks: The set of blocks not in \p
128+
/// dominatedBlockSet that together with \p dominatedBlockSet
129+
/// jointly-postdominate \p dominatedBlock. This is "completing" the joint
130+
/// post-dominance set.
131+
///
132+
/// * inputBlocksInJointPostDomSet: Any of our input blocks that were never
133+
/// found as a predecessor is passed to this callback. This block is in the
134+
/// final minimal joint-postdominance set and is passed to this
135+
/// callback. This is optional and we will avoid doing work if it is not
136+
/// set.
137+
void findJointPostDominatingSet(
138+
SILBasicBlock *dominatingBlock,
139+
ArrayRef<SILBasicBlock *> dominatedBlockSet,
140+
function_ref<void(SILBasicBlock *)> inputBlocksFoundDuringWalk,
141+
function_ref<void(SILBasicBlock *)> foundJointPostDomSetCompletionBlocks,
142+
function_ref<void(SILBasicBlock *)> inputBlocksInJointPostDomSet = {});
143+
168144
} // namespace swift
169145

170146
#endif

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -695,15 +695,13 @@ SILBasicBlock::iterator replaceSingleUse(Operand *use, SILValue newValue,
695695
/// and destroy at leaking blocks to adjust ownership and make available for use
696696
/// at \p inBlock.
697697
SILValue
698-
makeCopiedValueAvailable(SILValue value, SILBasicBlock *inBlock,
699-
JointPostDominanceSetComputer *jointPostDomComputer);
698+
makeCopiedValueAvailable(SILValue value, SILBasicBlock *inBlock);
700699

701700
/// Given a newly created @owned value \p value without any uses, this utility
702701
/// inserts control equivalent copy and destroy at leaking blocks to adjust
703702
/// ownership and make \p value available for use at \p inBlock.
704703
SILValue
705-
makeNewValueAvailable(SILValue value, SILBasicBlock *inBlock,
706-
JointPostDominanceSetComputer *jointPostDomComputer);
704+
makeNewValueAvailable(SILValue value, SILBasicBlock *inBlock);
707705

708706
/// Given a forwarding instruction, eliminate it if all of its users are debug
709707
/// instructions and ownership uses.

include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,7 @@ class LSValue : public LSBase {
255255
///
256256
/// In the case where we have a single value this can be materialized by
257257
/// applying Path to the Base.
258-
SILValue materialize(SILInstruction *Inst,
259-
JointPostDominanceSetComputer *jointPostDomComputer) {
258+
SILValue materialize(SILInstruction *Inst) {
260259
if (CoveringValue)
261260
return SILValue();
262261
auto Val = Base;
@@ -269,8 +268,7 @@ class LSValue : public LSBase {
269268
}
270269
auto Res = Path.getValue().createExtract(Val, &*InsertPt, true);
271270
if (Val != Base) {
272-
Res = makeCopiedValueAvailable(Res, Inst->getParent(),
273-
jointPostDomComputer);
271+
Res = makeCopiedValueAvailable(Res, Inst->getParent());
274272
Builder.emitEndBorrowOperation(InsertPt->getLoc(), Val);
275273
// Insert a destroy on the Base
276274
SILBuilderWithScope(Inst).emitDestroyValueOperation(Inst->getLoc(), Base);
@@ -296,11 +294,9 @@ class LSValue : public LSBase {
296294
/// location holds. This may involve extracting and aggregating available
297295
/// values.
298296
static void reduceInner(LSLocation &B, SILModule *M, LSLocationValueMap &Vals,
299-
SILInstruction *InsertPt,
300-
JointPostDominanceSetComputer *jointPostDomComputer);
297+
SILInstruction *InsertPt);
301298
static SILValue reduce(LSLocation &B, SILModule *M, LSLocationValueMap &Vals,
302-
SILInstruction *InsertPt,
303-
JointPostDominanceSetComputer *jointPostDomComputer);
299+
SILInstruction *InsertPt);
304300
};
305301

306302
static inline llvm::hash_code hash_value(const LSValue &V) {

include/swift/SILOptimizer/Utils/OwnershipOptUtils.h

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ struct OwnershipFixupContext {
3737
Optional<InstModCallbacks> inlineCallbacks;
3838
InstModCallbacks &callbacks;
3939
DeadEndBlocks &deBlocks;
40-
JointPostDominanceSetComputer &jointPostDomSetComputer;
4140

4241
SmallVector<Operand *, 8> transitiveBorrowedUses;
4342
SmallVector<PhiOperand, 8> recursiveReborrows;
@@ -64,30 +63,16 @@ struct OwnershipFixupContext {
6463
};
6564
AddressFixupContext extraAddressFixupInfo;
6665

67-
OwnershipFixupContext(InstModCallbacks &callbacks, DeadEndBlocks &deBlocks,
68-
JointPostDominanceSetComputer &jointPostDomSetComputer)
69-
: callbacks(callbacks), deBlocks(deBlocks),
70-
jointPostDomSetComputer(jointPostDomSetComputer) {}
66+
OwnershipFixupContext(InstModCallbacks &callbacks, DeadEndBlocks &deBlocks)
67+
: callbacks(callbacks), deBlocks(deBlocks) {}
7168

7269
void clear() {
73-
jointPostDomSetComputer.clear();
7470
transitiveBorrowedUses.clear();
7571
recursiveReborrows.clear();
7672
extraAddressFixupInfo.allAddressUsesFromOldValue.clear();
7773
extraAddressFixupInfo.intPtrOp = InteriorPointerOperand();
7874
}
7975

80-
/// Gets access to the joint post dominance computer and clears it after \p
81-
/// callback.
82-
template <typename ResultTy>
83-
ResultTy withJointPostDomComputer(
84-
function_ref<ResultTy(JointPostDominanceSetComputer &)> callback) {
85-
// Make sure we clear the joint post dom computer after callback.
86-
SWIFT_DEFER { jointPostDomSetComputer.clear(); };
87-
// Then return callback passing in the computer.
88-
return callback(jointPostDomSetComputer);
89-
}
90-
9176
private:
9277
/// Helper method called to determine if we discovered we needed interior
9378
/// pointer fixups while simplifying.

0 commit comments

Comments
 (0)