Files
swift-mirror/include/swift/SIL/OSSALifetimeCompletion.h
Nate Chandler ad33b5de34 [OSSALifetimeCompletion] Handle available boundary
Not every block in a region which begins with the non-lifetime-ending
boundary of a value and ending with unreachable-terminated blocks has
the value available.  If the unreachable-terminated blocks in this
boundary are not available, it is incorrect to insert destroys of the
value in them: it is an overconsume on some paths.  Previously,
however, destroys were simply being inserted at the unreachable.

Here, this is fixed by finding the boundary of availability within that
region and inserting destroys before the terminators of the blocks on
that boundary.

rdar://116255254
2023-10-05 09:15:58 -07:00

141 lines
5.5 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;
}
static void visitUnreachableLifetimeEnds(
SILValue value, const SSAPrunedLiveness &liveness,
llvm::function_ref<void(SILInstruction *)> visit);
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