mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
During copy propagation (for which -enable-copy-propagation must still be passed), also try to shrink borrow scopes by hoisting end_borrows using the newly added ShrinkBorrowScope utility. Allow end_borrow instructions to be hoisted over instructions that are not deinit barriers for the value which is borrowed. Deinit barriers include uses of the value, loads of memory, loads of weak references that may be zeroed during deinit, and "synchronization points". rdar://79149830
155 lines
5.9 KiB
C++
155 lines
5.9 KiB
C++
//===--- CanonicalizeBorrowScope.h - Canonicalize OSSA borrows --*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// This utility canonicalizes borrow scopes by rewriting them to restrict them
|
|
/// to only the uses within the scope. To do this, it hoists forwarding
|
|
/// operations out of the scope. This exposes many useless scopes that can be
|
|
/// deleted, which in turn allows canonicalization of the outer owned values
|
|
/// (via CanonicalizeOSSALifetime).
|
|
///
|
|
/// This does not shrink borrow scopes; it does not rewrite end_borrows. For
|
|
/// that, see ShrinkBorrowScope.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SILOPTIMIZER_UTILS_CANONICALIZEBORROWSCOPES_H
|
|
#define SWIFT_SILOPTIMIZER_UTILS_CANONICALIZEBORROWSCOPES_H
|
|
|
|
#include "swift/Basic/GraphNodeWorklist.h"
|
|
#include "swift/Basic/SmallPtrSetVector.h"
|
|
#include "swift/SIL/OwnershipUtils.h"
|
|
#include "swift/SIL/PrunedLiveness.h"
|
|
#include "swift/SIL/SILInstruction.h"
|
|
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
|
|
#include "swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h"
|
|
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/SetVector.h"
|
|
|
|
namespace swift {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// MARK: CanonicalizeBorrowScope
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
class CanonicalizeBorrowScope {
|
|
public:
|
|
/// Return true if \p inst is an instructions that forwards ownership is its
|
|
/// first operand and can be trivially duplicated, sunk to its uses, hoisted
|
|
/// outside a borrow scope and have it's ownership kind flipped from
|
|
/// guaranteed to owned if needed, as long as OSSA invariants are preserved.
|
|
static bool isRewritableOSSAForward(SILInstruction *inst);
|
|
|
|
/// Return the root of a borrowed extended lifetime for \p def or invalid.
|
|
///
|
|
/// \p def may be any guaranteed value.
|
|
static SILValue getCanonicalBorrowedDef(SILValue def);
|
|
|
|
private:
|
|
// The borrow that begins this scope.
|
|
BorrowedValue borrowedValue;
|
|
|
|
/// Pruned liveness for the extended live range including copies. For this
|
|
/// purpose, only consuming instructions are considered "lifetime
|
|
/// ending". end_borrows do not end a liverange that may include owned copies.
|
|
PrunedLiveness liveness;
|
|
|
|
InstructionDeleter &deleter;
|
|
|
|
/// 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;
|
|
|
|
/// Record any copies outside the borrow scope that were updated. This
|
|
/// includes the outer copy that us used by outer uses and copies for any
|
|
/// hoisted forwarding instructions.
|
|
SmallVector<CopyValueInst *, 4> updatedCopies;
|
|
|
|
/// For borrowed defs, track per-block copies of the borrowed value that only
|
|
/// have uses outside the borrow scope and will not be removed by
|
|
/// canonicalization. These copies are effectively distinct OSSA lifetimes
|
|
/// that should be canonicalized separately.
|
|
llvm::SmallDenseMap<SILBasicBlock *, CopyValueInst *, 4> persistentCopies;
|
|
|
|
public:
|
|
CanonicalizeBorrowScope(InstructionDeleter &deleter) : deleter(deleter) {}
|
|
|
|
BorrowedValue getBorrowedValue() const { return borrowedValue; }
|
|
|
|
const PrunedLiveness &getLiveness() const { return liveness; }
|
|
|
|
InstructionDeleter &getDeleter() { return deleter; }
|
|
|
|
InstModCallbacks &getCallbacks() { return deleter.getCallbacks(); }
|
|
|
|
/// Top-level entry point for canonicalizing a SILFunctionArgument. This is a
|
|
/// straightforward canonicalization that can be performed as a stand-alone
|
|
/// utility anywhere.
|
|
bool canonicalizeFunctionArgument(SILFunctionArgument *arg);
|
|
|
|
/// Top-level entry point for canonicalizing any borrow scope.
|
|
///
|
|
/// This creates OSSA compensation code outside the borrow scope. It should
|
|
/// only be called within copy propagation, which knows how to cleanup any new
|
|
/// copies outside the borrow scope, along with hoisted forwarding
|
|
/// instructions, etc.
|
|
bool canonicalizeBorrowScope(BorrowedValue borrow);
|
|
|
|
bool hasPersistentCopies() const { return !persistentCopies.empty(); }
|
|
|
|
bool isPersistentCopy(CopyValueInst *copy) const {
|
|
auto iter = persistentCopies.find(copy->getParent());
|
|
if (iter == persistentCopies.end()) {
|
|
return false;
|
|
}
|
|
return iter->second == copy;
|
|
}
|
|
|
|
// Get all the copies that inserted during canonicalizeBorrowScopes(). These
|
|
// are cleared at the next call to canonicalizeBorrowScopes().
|
|
ArrayRef<CopyValueInst *> getUpdatedCopies() const { return updatedCopies; }
|
|
|
|
using OuterUsers = llvm::SmallPtrSet<SILInstruction *, 8>;
|
|
|
|
SILValue findDefInBorrowScope(SILValue value);
|
|
|
|
template <typename Visitor>
|
|
bool visitBorrowScopeUses(SILValue innerValue, Visitor &visitor);
|
|
|
|
void beginVisitBorrowScopeUses() { defUseWorklist.clear(); }
|
|
|
|
void recordOuterCopy(CopyValueInst *copy) { updatedCopies.push_back(copy); }
|
|
|
|
protected:
|
|
void initBorrow(BorrowedValue borrow) {
|
|
assert(borrow && liveness.empty() && persistentCopies.empty());
|
|
|
|
updatedCopies.clear();
|
|
borrowedValue = borrow;
|
|
liveness.initializeDefBlock(borrowedValue->getParentBlock());
|
|
}
|
|
|
|
bool computeBorrowLiveness();
|
|
|
|
void filterOuterBorrowUseInsts(OuterUsers &outerUseInsts);
|
|
|
|
bool consolidateBorrowScope();
|
|
};
|
|
|
|
bool shrinkBorrowScope(BeginBorrowInst *bbi, InstructionDeleter &deleter);
|
|
|
|
} // namespace swift
|
|
|
|
#endif // SWIFT_SILOPTIMIZER_UTILS_CANONICALIZEBORROWSCOPES_H
|