Skip to content

SIL: fix problems in findJointPostDominatingSet and some refactoring #35684

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 50 additions & 74 deletions include/swift/SIL/BasicBlockUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,83 +88,59 @@ class DeadEndBlocks {
bool isComputed() const { return didComputeValue; }

const SILFunction *getFunction() const { return f; }
};

/// A struct that contains the intermediate state used in computing
/// joint-dominance sets. Enables a pass to easily reuse the same small data
/// structures with clearing (noting that clearing our internal state does not
/// cause us to shrink meaning that once we malloc, we keep the malloced
/// memory).
struct JointPostDominanceSetComputer {
/// The worklist that drives the algorithm.
SmallVector<SILBasicBlock *, 32> worklist;

/// A subset of our initial blocks that we found as a predecessor of another
/// block along our walk.
SmallVector<SILBasicBlock *, 8> reachableInputBlocks;

/// As we process the worklist, any successors that we see that have not been
/// visited yet are placed in here. At the end of our worklist, any blocks
/// that remain here are "leaking blocks" that together with our initial set
/// would provide a jointly-postdominating set of our dominating value.
SmallVector<SILBasicBlock *, 32> blocksThatLeakIfNeverVisited;

DeadEndBlocks &deadEndBlocks;

JointPostDominanceSetComputer(DeadEndBlocks &deadEndBlocks)
: deadEndBlocks(deadEndBlocks) {}

void clear() {
worklist.clear();
reachableInputBlocks.clear();
blocksThatLeakIfNeverVisited.clear();
}

/// Compute joint-postdominating set for \p dominatingBlock and \p
/// dominatedBlockSet found by walking up the CFG from the latter to the
/// former.
///
/// We pass back the following information via callbacks so our callers can
/// use whatever container they need to:
///
/// * inputBlocksFoundDuringWalk: Any blocks from the "dominated
/// block set" that was found as a predecessor block during our traversal is
/// passed to this callback. These can occur for two reasons:
///
/// 1. We actually had a block in \p dominatedBlockSet that was reachable
/// from another block in said set. This is a valid usage of the API
/// since it could be that the user does not care about such uses and
/// leave this callback empty.
///
/// 2. We had a block in \p dominatedBlockSet that is in a sub-loop in the
/// loop-nest relative to \p dominatingBlock causing us to go around a
/// backedge and hit the block during our traversal. In this case, we
/// have already during the traversal passed the exiting blocks of the
/// sub-loop as joint postdominace completion set blocks. This is useful
/// if one is using this API for lifetime extension purposes of lifetime
/// ending uses and one needs to insert compensating copy_value at these
/// locations due to the lack of strong control-equivalence in between
/// the block and \p dominatingBlock.
///

/// Performs a simple check if \p block (or its single successor) ends in an
/// "unreachable".
///
/// * foundJointPostDomSetCompletionBlocks: The set of blocks not in \p
/// dominatedBlockSet that together with \p dominatedBlockSet
/// jointly-postdominate \p dominatedBlock. This is "completing" the joint
/// post-dominance set.
///
/// * inputBlocksInJointPostDomSet: Any of our input blocks that were never
/// found as a predecessor is passed to this callback. This block is in the
/// final minimal joint-postdominance set and is passed to this
/// callback. This is optional and we will avoid doing work if it is not
/// set.
void findJointPostDominatingSet(
SILBasicBlock *dominatingBlock,
ArrayRef<SILBasicBlock *> dominatedBlockSet,
function_ref<void(SILBasicBlock *)> inputBlocksFoundDuringWalk,
function_ref<void(SILBasicBlock *)> foundJointPostDomSetCompletionBlocks,
function_ref<void(SILBasicBlock *)> inputBlocksInJointPostDomSet = {});
/// This handles the common case of failure-handling blocks, which e.g.
/// contain a call to fatalError().
static bool triviallyEndsInUnreachable(SILBasicBlock *block);
};

/// Compute joint-postdominating set for \p dominatingBlock and \p
/// dominatedBlockSet found by walking up the CFG from the latter to the
/// former.
///
/// We pass back the following information via callbacks so our callers can
/// use whatever container they need to:
///
/// * inputBlocksFoundDuringWalk: Any blocks from the "dominated
/// block set" that was found as a predecessor block during our traversal is
/// passed to this callback. These can occur for two reasons:
///
/// 1. We actually had a block in \p dominatedBlockSet that was reachable
/// from another block in said set. This is a valid usage of the API
/// since it could be that the user does not care about such uses and
/// leave this callback empty.
///
/// 2. We had a block in \p dominatedBlockSet that is in a sub-loop in the
/// loop-nest relative to \p dominatingBlock causing us to go around a
/// backedge and hit the block during our traversal. In this case, we
/// have already during the traversal passed the exiting blocks of the
/// sub-loop as joint postdominace completion set blocks. This is useful
/// if one is using this API for lifetime extension purposes of lifetime
/// ending uses and one needs to insert compensating copy_value at these
/// locations due to the lack of strong control-equivalence in between
/// the block and \p dominatingBlock.
///
///
/// * foundJointPostDomSetCompletionBlocks: The set of blocks not in \p
/// dominatedBlockSet that together with \p dominatedBlockSet
/// jointly-postdominate \p dominatedBlock. This is "completing" the joint
/// post-dominance set.
///
/// * inputBlocksInJointPostDomSet: Any of our input blocks that were never
/// found as a predecessor is passed to this callback. This block is in the
/// final minimal joint-postdominance set and is passed to this
/// callback. This is optional and we will avoid doing work if it is not
/// set.
void findJointPostDominatingSet(
SILBasicBlock *dominatingBlock,
ArrayRef<SILBasicBlock *> dominatedBlockSet,
function_ref<void(SILBasicBlock *)> inputBlocksFoundDuringWalk,
function_ref<void(SILBasicBlock *)> foundJointPostDomSetCompletionBlocks,
function_ref<void(SILBasicBlock *)> inputBlocksInJointPostDomSet = {});

} // namespace swift

#endif
6 changes: 2 additions & 4 deletions include/swift/SILOptimizer/Utils/InstOptUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -695,15 +695,13 @@ SILBasicBlock::iterator replaceSingleUse(Operand *use, SILValue newValue,
/// and destroy at leaking blocks to adjust ownership and make available for use
/// at \p inBlock.
SILValue
makeCopiedValueAvailable(SILValue value, SILBasicBlock *inBlock,
JointPostDominanceSetComputer *jointPostDomComputer);
makeCopiedValueAvailable(SILValue value, SILBasicBlock *inBlock);

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

/// Given a forwarding instruction, eliminate it if all of its users are debug
/// instructions and ownership uses.
Expand Down
12 changes: 4 additions & 8 deletions include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,7 @@ class LSValue : public LSBase {
///
/// In the case where we have a single value this can be materialized by
/// applying Path to the Base.
SILValue materialize(SILInstruction *Inst,
JointPostDominanceSetComputer *jointPostDomComputer) {
SILValue materialize(SILInstruction *Inst) {
if (CoveringValue)
return SILValue();
auto Val = Base;
Expand All @@ -269,8 +268,7 @@ class LSValue : public LSBase {
}
auto Res = Path.getValue().createExtract(Val, &*InsertPt, true);
if (Val != Base) {
Res = makeCopiedValueAvailable(Res, Inst->getParent(),
jointPostDomComputer);
Res = makeCopiedValueAvailable(Res, Inst->getParent());
Builder.emitEndBorrowOperation(InsertPt->getLoc(), Val);
// Insert a destroy on the Base
SILBuilderWithScope(Inst).emitDestroyValueOperation(Inst->getLoc(), Base);
Expand All @@ -296,11 +294,9 @@ class LSValue : public LSBase {
/// location holds. This may involve extracting and aggregating available
/// values.
static void reduceInner(LSLocation &B, SILModule *M, LSLocationValueMap &Vals,
SILInstruction *InsertPt,
JointPostDominanceSetComputer *jointPostDomComputer);
SILInstruction *InsertPt);
static SILValue reduce(LSLocation &B, SILModule *M, LSLocationValueMap &Vals,
SILInstruction *InsertPt,
JointPostDominanceSetComputer *jointPostDomComputer);
SILInstruction *InsertPt);
};

static inline llvm::hash_code hash_value(const LSValue &V) {
Expand Down
19 changes: 2 additions & 17 deletions include/swift/SILOptimizer/Utils/OwnershipOptUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ struct OwnershipFixupContext {
Optional<InstModCallbacks> inlineCallbacks;
InstModCallbacks &callbacks;
DeadEndBlocks &deBlocks;
JointPostDominanceSetComputer &jointPostDomSetComputer;

SmallVector<Operand *, 8> transitiveBorrowedUses;
SmallVector<std::pair<SILBasicBlock *, unsigned>, 8> recursiveReborrows;
Expand All @@ -64,30 +63,16 @@ struct OwnershipFixupContext {
};
AddressFixupContext extraAddressFixupInfo;

OwnershipFixupContext(InstModCallbacks &callbacks, DeadEndBlocks &deBlocks,
JointPostDominanceSetComputer &jointPostDomSetComputer)
: callbacks(callbacks), deBlocks(deBlocks),
jointPostDomSetComputer(jointPostDomSetComputer) {}
OwnershipFixupContext(InstModCallbacks &callbacks, DeadEndBlocks &deBlocks)
: callbacks(callbacks), deBlocks(deBlocks) {}

void clear() {
jointPostDomSetComputer.clear();
transitiveBorrowedUses.clear();
recursiveReborrows.clear();
extraAddressFixupInfo.allAddressUsesFromOldValue.clear();
extraAddressFixupInfo.intPtrOp = InteriorPointerOperand();
}

/// Gets access to the joint post dominance computer and clears it after \p
/// callback.
template <typename ResultTy>
ResultTy withJointPostDomComputer(
function_ref<ResultTy(JointPostDominanceSetComputer &)> callback) {
// Make sure we clear the joint post dom computer after callback.
SWIFT_DEFER { jointPostDomSetComputer.clear(); };
// Then return callback passing in the computer.
return callback(jointPostDomSetComputer);
}

private:
/// Helper method called to determine if we discovered we needed interior
/// pointer fixups while simplifying.
Expand Down
Loading