Files
swift-mirror/include/swift/SIL/OSSALifetimeCompletion.h

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