Skip to content

[CanonicalizeOSSALifetime] Extend Onone lifetimes. #61464

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
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
41 changes: 29 additions & 12 deletions include/swift/SILOptimizer/Utils/CanonicalizeOSSALifetime.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ void diagnoseRequiredCopyOfMoveOnly(Operand *use,
///
/// This result remains valid during copy rewriting. The only instructions
/// referenced it contains are consumes that cannot be deleted.
class CanonicalOSSAConsumeInfo {
class CanonicalOSSAConsumeInfo final {
/// Map blocks on the lifetime boundary to the last consuming instruction.
llvm::SmallDenseMap<SILBasicBlock *, SILInstruction *, 4> finalBlockConsumes;

Expand Down Expand Up @@ -159,6 +159,10 @@ class CanonicalOSSAConsumeInfo {
return false;
}

CanonicalOSSAConsumeInfo() {}
CanonicalOSSAConsumeInfo(CanonicalOSSAConsumeInfo const &) = delete;
CanonicalOSSAConsumeInfo &
operator=(CanonicalOSSAConsumeInfo const &) = delete;
SWIFT_ASSERT_ONLY_DECL(void dump() const LLVM_ATTRIBUTE_USED);
};

Expand All @@ -169,7 +173,7 @@ class CanonicalOSSAConsumeInfo {
///
/// TODO: Move all the private per-definition members into an implementation
/// class in the .cpp file.
class CanonicalizeOSSALifetime {
class CanonicalizeOSSALifetime final {
public:
/// Find the original definition of a potentially copied value. \p copiedValue
/// must be an owned value. It is usually a copy but may also be a destroy.
Expand Down Expand Up @@ -205,6 +209,10 @@ class CanonicalizeOSSALifetime {
/// liveness may be pruned during canonicalization.
bool pruneDebugMode;

/// If true, lifetimes will not be shortened except when necessary to avoid
/// copies.
bool maximizeLifetime;

/// If true and we are processing a value of move_only type, emit a diagnostic
/// when-ever we need to insert a copy_value.
std::function<void(Operand *)> moveOnlyCopyValueNotification;
Expand Down Expand Up @@ -240,8 +248,8 @@ class CanonicalizeOSSALifetime {
/// Visited set for general def-use traversal that prevents revisiting values.
GraphNodeWorklist<SILValue, 8> defUseWorklist;

/// Visited set general CFG traversal that prevents revisiting blocks.
GraphNodeWorklist<SILBasicBlock *, 8> blockWorklist;
/// The blocks that were discovered by PrunedLiveness.
SmallVector<SILBasicBlock *, 32> discoveredBlocks;

/// Pruned liveness for the extended live range including copies. For this
/// purpose, only consuming instructions are considered "lifetime
Expand All @@ -251,7 +259,7 @@ class CanonicalizeOSSALifetime {
/// The destroys of the value. These are not uses, but need to be recorded so
/// that we know when the last use in a consuming block is (without having to
/// repeatedly do use-def walks from destroys).
SmallPtrSet<SILInstruction *, 8> destroys;
SmallPtrSetVector<SILInstruction *, 8> destroys;

/// Information about consuming instructions discovered in this canonical OSSA
/// lifetime.
Expand Down Expand Up @@ -289,15 +297,17 @@ class CanonicalizeOSSALifetime {
}

CanonicalizeOSSALifetime(
bool pruneDebugMode, NonLocalAccessBlockAnalysis *accessBlockAnalysis,
DominanceInfo *domTree, InstructionDeleter &deleter,
bool pruneDebugMode, bool maximizeLifetime,
NonLocalAccessBlockAnalysis *accessBlockAnalysis, DominanceInfo *domTree,
InstructionDeleter &deleter,
std::function<void(Operand *)> moveOnlyCopyValueNotification = nullptr,
std::function<void(Operand *)> moveOnlyFinalConsumingUse = nullptr)
: pruneDebugMode(pruneDebugMode),
: pruneDebugMode(pruneDebugMode), maximizeLifetime(maximizeLifetime),
moveOnlyCopyValueNotification(moveOnlyCopyValueNotification),
moveOnlyFinalConsumingUse(moveOnlyFinalConsumingUse),
accessBlockAnalysis(accessBlockAnalysis), domTree(domTree),
deleter(deleter) {}
deleter(deleter),
liveness(maximizeLifetime ? &discoveredBlocks : nullptr) {}

SILValue getCurrentDef() const { return liveness.getDef(); }

Expand All @@ -307,6 +317,7 @@ class CanonicalizeOSSALifetime {
// analysis, freeing its memory.
accessBlocks = nullptr;
consumes.clear();
destroys.clear();

liveness.initializeDef(def);
}
Expand All @@ -315,6 +326,7 @@ class CanonicalizeOSSALifetime {
consumingBlocks.clear();
debugValues.clear();
liveness.clear();
discoveredBlocks.clear();
}

/// Top-Level API: rewrites copies and destroys within \p def's extended
Expand All @@ -333,7 +345,7 @@ class CanonicalizeOSSALifetime {

InstModCallbacks &getCallbacks() { return deleter.getCallbacks(); }

protected:
private:
void recordDebugValue(DebugValueInst *dvi) { debugValues.insert(dvi); }

void recordConsumingUse(Operand *use) {
Expand All @@ -345,9 +357,14 @@ class CanonicalizeOSSALifetime {

void extendLivenessThroughOverlappingAccess();

void findExtendedBoundary(PrunedLivenessBoundary &boundary);
void findOriginalBoundary(PrunedLivenessBoundary &boundary);

void findExtendedBoundary(PrunedLivenessBoundary const &originalBoundary,
PrunedLivenessBoundary &boundary);

void extendUnconsumedLiveness(PrunedLivenessBoundary const &boundary);

void insertDestroysOnBoundary(PrunedLivenessBoundary &boundary);
void insertDestroysOnBoundary(PrunedLivenessBoundary const &boundary);

void rewriteCopies();
};
Expand Down
4 changes: 3 additions & 1 deletion lib/SILOptimizer/Mandatory/MoveOnlyAddressChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,9 @@ struct MoveOnlyChecker {
instToDelete->eraseFromParent();
})),
canonicalizer(
false /*pruneDebugMode*/, accessBlockAnalysis, domTree, deleter,
false /*pruneDebugMode*/,
!fn->shouldOptimize() /*maximizeLifetime*/, accessBlockAnalysis,
domTree, deleter,
[&](Operand *use) { consumingUsesNeedingCopy.push_back(use); },
[&](Operand *use) { finalConsumingUses.push_back(use); }) {}

Expand Down
5 changes: 3 additions & 2 deletions lib/SILOptimizer/Mandatory/MoveOnlyObjectChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,9 @@ bool MoveOnlyChecker::check(NonLocalAccessBlockAnalysis *accessBlockAnalysis,
};

CanonicalizeOSSALifetime canonicalizer(
false /*pruneDebugMode*/, accessBlockAnalysis, domTree, deleter,
foundConsumingUseNeedingCopy, foundConsumingUseNotNeedingCopy);
false /*pruneDebugMode*/, !fn->shouldOptimize() /*maximizeLifetime*/,
accessBlockAnalysis, domTree, deleter, foundConsumingUseNeedingCopy,
foundConsumingUseNotNeedingCopy);
auto moveIntroducers = llvm::makeArrayRef(moveIntroducersToProcess.begin(),
moveIntroducersToProcess.end());
SmallPtrSet<MarkMustCheckInst *, 4> valuesWithDiagnostics;
Expand Down
6 changes: 4 additions & 2 deletions lib/SILOptimizer/SILCombiner/SILCombine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,10 @@ void SILCombiner::canonicalizeOSSALifetimes(SILInstruction *currentInst) {
InstructionDeleter deleter(std::move(canonicalizeCallbacks));

DominanceInfo *domTree = DA->get(&Builder.getFunction());
CanonicalizeOSSALifetime canonicalizer(false /*prune debug*/, NLABA, domTree,
deleter);
CanonicalizeOSSALifetime canonicalizer(
false /*prune debug*/,
!parentTransform->getFunction()->shouldOptimize() /*maximize lifetime*/,
NLABA, domTree, deleter);
CanonicalizeBorrowScope borrowCanonicalizer(deleter);

while (!defsToCanonicalize.empty()) {
Expand Down
9 changes: 5 additions & 4 deletions lib/SILOptimizer/Transforms/CopyPropagation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,9 @@ static bool sinkOwnedForward(SILInstruction *ownedForward,
namespace {

class CopyPropagation : public SILFunctionTransform {
/// True if debug_value instructions should be pruned.
/// If true, debug_value instructions should be pruned.
bool pruneDebug;
/// True if all values should be canonicalized.
/// If true, all values will be canonicalized.
bool canonicalizeAll;
/// If true, then borrow scopes will be canonicalized, allowing copies of
/// guaranteed values to be optimized. Does *not* shrink the borrow scope.
Expand Down Expand Up @@ -437,8 +437,9 @@ void CopyPropagation::run() {

// canonicalizer performs all modifications through deleter's callbacks, so we
// don't need to explicitly check for changes.
CanonicalizeOSSALifetime canonicalizer(pruneDebug, accessBlockAnalysis,
domTree, deleter);
CanonicalizeOSSALifetime canonicalizer(
pruneDebug, /*maximizeLifetime=*/!getFunction()->shouldOptimize(),
accessBlockAnalysis, domTree, deleter);

// NOTE: We assume that the function is in reverse post order so visiting the
// blocks and pushing begin_borrows as we see them and then popping them
Expand Down
Loading