mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
137 lines
5.3 KiB
C++
137 lines
5.3 KiB
C++
//===--- OwnershipLifetimeCompletion.h ------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2023 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// OSSA lifetime completion adds lifetime ending instructions to make
|
|
/// linear lifetimes complete.
|
|
///
|
|
/// Completion is bottom-up recursive over nested borrow scopes. Additionally,
|
|
/// this may be extended to support dependent owned lifetimes in the future to
|
|
/// handle owned non-escaping values.
|
|
///
|
|
/// Lexical lifetimes can only be incomplete as a result of dead-end blocks. In
|
|
/// this case, their lifetime ends immediately before the dead-end block.
|
|
///
|
|
/// Nonlexical lifetimes can be incomplete for any reason. Their lifetime ends
|
|
/// at the liveness boundary.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SILOPTIMIZER_UTILS_OSSSALIFETIMECOMPLETION_H
|
|
#define SWIFT_SILOPTIMIZER_UTILS_OSSSALIFETIMECOMPLETION_H
|
|
|
|
#include "swift/SIL/NodeDatastructures.h"
|
|
#include "swift/SIL/OwnershipLiveness.h"
|
|
#include "swift/SIL/SILFunction.h"
|
|
|
|
namespace swift {
|
|
|
|
enum class LifetimeCompletion { NoLifetime, AlreadyComplete, WasCompleted };
|
|
|
|
class OSSALifetimeCompletion {
|
|
// If domInfo is nullptr, then InteriorLiveness never assumes dominance. As a
|
|
// result it may report extra unenclosedPhis. In that case, any attempt to
|
|
// create a new phi would result in an immediately redundant phi.
|
|
const DominanceInfo *domInfo = nullptr;
|
|
|
|
// Cache intructions already handled by the recursive algorithm to avoid
|
|
// recomputing their lifetimes.
|
|
ValueSet completedValues;
|
|
|
|
public:
|
|
OSSALifetimeCompletion(SILFunction *function, const DominanceInfo *domInfo)
|
|
: domInfo(domInfo), completedValues(function) {}
|
|
|
|
/// Insert a lifetime-ending instruction on every path to complete the OSSA
|
|
/// lifetime of \p value. Lifetime completion is only relevant for owned
|
|
/// values or borrow introducers.
|
|
/// For lexical values lifetime is completed at unreachable instructions.
|
|
/// For non-lexical values lifetime is completed at the lifetime boundary.
|
|
/// When \p forceBoundaryCompletion is true, the client is able to guarantee
|
|
/// that lifetime completion of lexical values at the lifetime boundary is
|
|
/// sufficient.
|
|
/// Currently \p forceBoundaryCompletion is used by mem2reg and temprvalueopt
|
|
/// to complete lexical enum values on trivial paths.
|
|
/// Returns true if any new instructions were created to complete the
|
|
/// lifetime.
|
|
///
|
|
/// TODO: We also need to complete scoped addresses (e.g. store_borrow)!
|
|
LifetimeCompletion
|
|
completeOSSALifetime(SILValue value, bool forceBoundaryCompletion = false) {
|
|
if (value->getOwnershipKind() == OwnershipKind::None)
|
|
return LifetimeCompletion::NoLifetime;
|
|
|
|
if (value->getOwnershipKind() != OwnershipKind::Owned) {
|
|
BorrowedValue borrowedValue(value);
|
|
if (!borrowedValue)
|
|
return LifetimeCompletion::NoLifetime;
|
|
|
|
if (!borrowedValue.isLocalScope())
|
|
return LifetimeCompletion::AlreadyComplete;
|
|
}
|
|
if (!completedValues.insert(value))
|
|
return LifetimeCompletion::AlreadyComplete;
|
|
|
|
return analyzeAndUpdateLifetime(value, forceBoundaryCompletion)
|
|
? LifetimeCompletion::WasCompleted
|
|
: LifetimeCompletion::AlreadyComplete;
|
|
}
|
|
|
|
protected:
|
|
bool analyzeAndUpdateLifetime(SILValue value, bool forceBoundaryCompletion);
|
|
};
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// UnreachableLifetimeCompletion
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Fixup OSSA before deleting an unreachable code path.
|
|
///
|
|
/// Only needed when a code path reaches a no-return function, making the
|
|
/// path now partially unreachable. Conditional branch folding requires no fixup
|
|
/// because it causes the entire path to become unreachable.
|
|
class UnreachableLifetimeCompletion {
|
|
SILFunction *function;
|
|
|
|
// If domInfo is nullptr, lifetime completion may attempt to recreate
|
|
// redundant phis, which should be immediately discarded.
|
|
const DominanceInfo *domInfo = nullptr;
|
|
|
|
BasicBlockSetVector unreachableBlocks;
|
|
InstructionSet unreachableInsts; // not including those in unreachableBlocks
|
|
ValueSetVector incompleteValues;
|
|
bool updatingLifetimes = false;
|
|
|
|
public:
|
|
UnreachableLifetimeCompletion(SILFunction *function, DominanceInfo *domInfo)
|
|
: function(function), unreachableBlocks(function),
|
|
unreachableInsts(function), incompleteValues(function) {}
|
|
|
|
/// Record information about this unreachable instruction and return true if
|
|
/// ends any simple OSSA lifetimes.
|
|
///
|
|
/// Note: this must be called in forward order so that lifetime completion
|
|
/// runs from the inside out.
|
|
void visitUnreachableInst(SILInstruction *instruction);
|
|
|
|
void visitUnreachableBlock(SILBasicBlock *block) {
|
|
unreachableBlocks.insert(block);
|
|
}
|
|
|
|
/// Complete the lifetime of any value defined outside of the unreachable
|
|
/// region that was previously destroyed in the unreachable region.
|
|
bool completeLifetimes();
|
|
};
|
|
|
|
} // namespace swift
|
|
|
|
#endif
|