|
| 1 | +//===--- OwnershipLiveness.h ---------------------------------*- C++ -*----===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See https://swift.org/LICENSE.txt for license information |
| 9 | +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | +/// |
| 13 | +/// Terminology: |
| 14 | +/// |
| 15 | +/// Linear lifetime: All paths through the value's definition to the |
| 16 | +/// function exit pass through exactly one lifetime-ending operation. |
| 17 | +/// |
| 18 | +/// Complete OSSA: All owned values and borrow introducers have linear lifetime. |
| 19 | +/// |
| 20 | +/// |
| 21 | +/// Linear SSA liveness: |
| 22 | +/// |
| 23 | +/// - Liveness for a single "defining" owned value or borrow introducing value |
| 24 | +/// assuming the value's lifetime is already linear. |
| 25 | +/// |
| 26 | +/// - The definition dominates all use points (phis do not extend the lifetime) |
| 27 | +/// |
| 28 | +/// - Only lifetime-ending operations generate liveness |
| 29 | +/// |
| 30 | +/// - Oblivious to pointer escapes within the lifetime |
| 31 | +/// |
| 32 | +/// |
| 33 | +/// Interior SSA liveness: |
| 34 | +/// |
| 35 | +/// - Liveness for a single "defining" value with any ownership. |
| 36 | +/// |
| 37 | +/// - The definition dominates all use points (phis do not extend the lifetime) |
| 38 | +/// |
| 39 | +/// - Does not assume the current lifetime is linear. Transitively follows |
| 40 | +/// guaranteed forwarding and address uses within the current scope. |
| 41 | +/// |
| 42 | +/// - Liveness cannot extend beyond lifetime-ending operations |
| 43 | +/// (a.k.a. affine lifetimes). |
| 44 | +/// |
| 45 | +/// - Assumes inner scopes *are* linear, including borrow and address scopes |
| 46 | +/// (e.g. begin_borrow, load_borrow, begin_apply, store_borrow, begin_access) |
| 47 | +/// A callback may be used to complete inner scopes before updating liveness. |
| 48 | +/// Rarely returns AddressUseKind::PointerEscape, because inner scopes hide |
| 49 | +/// pointer escapes. |
| 50 | +/// |
| 51 | +/// - Insulates outer scopes from inner scope details. Maintains the |
| 52 | +/// invariant that inlining cannot pessimize optimization. |
| 53 | +/// |
| 54 | +/// - Interior SSA liveness is used to complete (linearize) an OSSA lifetime |
| 55 | +/// |
| 56 | +/// |
| 57 | +/// Transitive SSA liveness |
| 58 | +/// |
| 59 | +/// - Liveness for a single "defining" value with any ownership. |
| 60 | +/// |
| 61 | +/// - The definition dominates all use points (phis do not extend the lifetime) |
| 62 | +/// |
| 63 | +/// - Does not assume that any lifetimes are linear. Transitively follows uses |
| 64 | +/// within inner scopes, recursively through nested scopes, including |
| 65 | +/// forwarding operations and address uses. |
| 66 | +/// |
| 67 | +/// - Much more likely to return AddressUseKind::PointerEscape |
| 68 | +/// |
| 69 | +/// - This is no longer needed with complete OSSA lifetimes |
| 70 | +/// |
| 71 | +/// |
| 72 | +/// Extended liveness |
| 73 | +/// |
| 74 | +/// - Liveness of a single "defining" value extended beyond its lifetime-ending |
| 75 | +/// operations. |
| 76 | +/// |
| 77 | +/// - May refer to copy-extension, reborrow-extension, or extension over |
| 78 | +/// barriers such as access markers. |
| 79 | +/// |
| 80 | +/// - For reborrow-extension, the definition no longer dominates the use |
| 81 | +/// points. MultiDefPrunedLiveness must be used. Each extended reborrow is |
| 82 | +/// added as a new definition. |
| 83 | +/// |
| 84 | +/// |
| 85 | +/// Extended linear liveness |
| 86 | +/// |
| 87 | +/// - Only considers lifetime-ending operations. Assumes the definition already |
| 88 | +/// has a linear lifetime and all copy-extended or reborrow-extended lifetimes |
| 89 | +/// are also linear. |
| 90 | +/// |
| 91 | +/// |
| 92 | +/// Extended interior liveness |
| 93 | +/// |
| 94 | +/// - Like interior SSA liveness, does not assume the current lifetime is |
| 95 | +/// linear. Transitively follows guaranteed forwarding and address uses within |
| 96 | +/// the current scope. Assumes inner scopes *are* linear. |
| 97 | +/// |
| 98 | +/// - Interior copy-extension is used to canonicalize an OSSA lifetime |
| 99 | +/// |
| 100 | +/// - Interior reborrow-extension is used to check borrow scopes relative to |
| 101 | +/// their inner uses and outer lifetime. |
| 102 | +/// |
| 103 | +//===----------------------------------------------------------------------===// |
| 104 | +/// |
| 105 | +/// Completing an OSSA lifetime may require phi creation whenever a reborrow is |
| 106 | +/// not dominated by the OSSA definition. The new phi's lifetime will then be |
| 107 | +/// extended over any of its inner adjacent phis. |
| 108 | +/// |
| 109 | +//===----------------------------------------------------------------------===// |
| 110 | + |
| 111 | +#ifndef SWIFT_SIL_OWNERSHIPLIVENESS_H |
| 112 | +#define SWIFT_SIL_OWNERSHIPLIVENESS_H |
| 113 | + |
| 114 | +#include "swift/Basic/Debug.h" |
| 115 | +#include "swift/Basic/LLVM.h" |
| 116 | +#include "swift/SIL/PrunedLiveness.h" |
| 117 | +#include "swift/SIL/OwnershipUseVisitor.h" |
| 118 | +#include "swift/SIL/SILArgument.h" |
| 119 | +#include "swift/SIL/SILBasicBlock.h" |
| 120 | +#include "swift/SIL/SILInstruction.h" |
| 121 | +#include "swift/SIL/SILValue.h" |
| 122 | +#include "llvm/ADT/SmallVector.h" |
| 123 | + |
| 124 | +namespace swift { |
| 125 | + |
| 126 | +/// Analyze SSA liveness of values that introduce an OSSA live range: |
| 127 | +/// |
| 128 | +/// 1. Owned non-phi values |
| 129 | +/// 2. Owned phi values |
| 130 | +/// 3. Borrow scope introducers: begin_borrow/load_borrow |
| 131 | +/// 4. Reborrows: guaranteed phis transitively defined by at least one borrow |
| 132 | +/// scope introducer. |
| 133 | +/// |
| 134 | +/// Used for OSSA lifetime completion. |
| 135 | +class OSSALiveness { |
| 136 | +protected: |
| 137 | + SILValue ownershipDef; |
| 138 | + |
| 139 | + // MARK: Results. |
| 140 | + |
| 141 | + SmallVector<SILBasicBlock *, 8> discoveredBlocks; |
| 142 | + SSAPrunedLiveness liveness; |
| 143 | + |
| 144 | + OSSALiveness(const OSSALiveness &) = delete; |
| 145 | + OSSALiveness &operator=(const OSSALiveness &) = delete; |
| 146 | + |
| 147 | +public: |
| 148 | + OSSALiveness(SILValue def): ownershipDef(def), liveness(&discoveredBlocks) {} |
| 149 | + |
| 150 | + const SSAPrunedLiveness &getLiveness() const { return liveness; } |
| 151 | + |
| 152 | + ArrayRef<SILBasicBlock *> getDiscoveredBlocks() const { |
| 153 | + return discoveredBlocks; |
| 154 | + } |
| 155 | + |
| 156 | + void print(llvm::raw_ostream &OS) const; |
| 157 | + void dump() const; |
| 158 | +}; |
| 159 | + |
| 160 | +// Internal implementation |
| 161 | +struct LinearLivenessVisitor; |
| 162 | + |
| 163 | +/// Compute ownershipDef's lifetime based on it's lifetime-ending uses, assuming |
| 164 | +/// it is already complete/linear. ownershipDef must be either an owned value or |
| 165 | +/// a local borrow scope introduced (begin_borrow, load_borrow, or |
| 166 | +/// store_borrow). |
| 167 | +/// |
| 168 | +/// This is the simplest OSSA liveness analysis, but is not appropriate for |
| 169 | +/// fixing OSSA lifetimes after transformation and cannot tell you whether |
| 170 | +/// pointer escapes occur. |
| 171 | +class LinearLiveness : public OSSALiveness { |
| 172 | + friend LinearLivenessVisitor; |
| 173 | + |
| 174 | +public: |
| 175 | + LinearLiveness(SILValue def); |
| 176 | + |
| 177 | + void compute(); |
| 178 | +}; |
| 179 | + |
| 180 | +// Internal implementation |
| 181 | +struct InteriorLivenessVisitor; |
| 182 | + |
| 183 | +/// Compute ownershipDef's lifetime based on all its uses (except those |
| 184 | +/// already enclosed by inner scopes). Returns AddressUseKind::PointerEscape |
| 185 | +/// if a pointer to ownershipDef escapes (and is not already enclosed by an |
| 186 | +/// inner scope). |
| 187 | +class InteriorLiveness : public OSSALiveness { |
| 188 | + friend InteriorLivenessVisitor; |
| 189 | + |
| 190 | + // Handle inner scopes. Called for inner reborrows, inner adjacent reborrows, |
| 191 | + // and address scopes. |
| 192 | + // |
| 193 | + // This may add uses to the inner scope, but it may not modify a use-list |
| 194 | + // in any outer scopes. |
| 195 | + using InnerScopeHandlerRef = llvm::function_ref<void(SILValue)>; |
| 196 | + |
| 197 | +public: |
| 198 | + // Summarize address uses |
| 199 | + AddressUseKind addressUseKind = AddressUseKind::Unknown; |
| 200 | + |
| 201 | + // Record any guaranteed phi uses that are not already enclosed by an outer |
| 202 | + // adjacent phi. |
| 203 | + SmallVector<SILValue, 8> unenclosedPhis; |
| 204 | + |
| 205 | +public: |
| 206 | + InteriorLiveness(SILValue def): OSSALiveness(def) {} |
| 207 | + |
| 208 | + void compute(const DominanceInfo *domInfo, |
| 209 | + InnerScopeHandlerRef handleInnerScope = InnerScopeHandlerRef()); |
| 210 | + |
| 211 | + AddressUseKind getAddressUseKind() const { return addressUseKind; } |
| 212 | + |
| 213 | + ArrayRef<SILValue> getUnenclosedPhis() const { return unenclosedPhis; } |
| 214 | + |
| 215 | + void print(llvm::raw_ostream &OS) const; |
| 216 | + void dump() const; |
| 217 | +}; |
| 218 | + |
| 219 | +// Internal implementation |
| 220 | +struct ExtendedLivenessVisitor; |
| 221 | + |
| 222 | +/// Analyze liveness of values that introduce an OSSA live range. This computes |
| 223 | +/// the phi-extended live range for these four categories of live range |
| 224 | +/// introducing values: |
| 225 | +/// |
| 226 | +/// 1. Owned non-phi values |
| 227 | +/// 2. Owned phi values |
| 228 | +/// 3. Borrow scope introducers: begin_borrow/load_borrow |
| 229 | +/// 4. Reborrows: guaranteed phis that end their incoming borrow scopes and |
| 230 | +/// begin a new borrow scope |
| 231 | +class ExtendedLiveness { |
| 232 | + friend ExtendedLivenessVisitor; |
| 233 | + |
| 234 | + SILValue ownershipDef; |
| 235 | + |
| 236 | + // MARK: Results. |
| 237 | + |
| 238 | + // Because of reborrows, the ssa def may not dominate all |
| 239 | + // uses. Consider the reborrows to be separate defs. |
| 240 | + SmallVector<SILBasicBlock *, 8> discoveredBlocks; |
| 241 | + MultiDefPrunedLiveness liveness; |
| 242 | + |
| 243 | + ExtendedLiveness(const ExtendedLiveness &) = delete; |
| 244 | + ExtendedLiveness &operator=(const ExtendedLiveness &) = delete; |
| 245 | + |
| 246 | +public: |
| 247 | + ExtendedLiveness(SILValue def); |
| 248 | + |
| 249 | + void compute(); |
| 250 | + |
| 251 | + /// The array of defs. The first element is ownershipDef. The remaining |
| 252 | + /// elements are outer reborrows discovered during computation. |
| 253 | + /// |
| 254 | + /// TODO: These are always SILValues. Convert the iterator. |
| 255 | + NodeSetVector::iterator defBegin() const { return liveness.defBegin(); } |
| 256 | + NodeSetVector::iterator defEnd() const { return liveness.defBegin(); } |
| 257 | + |
| 258 | + const MultiDefPrunedLiveness &getLiveness() const { return liveness; } |
| 259 | + |
| 260 | + void print(llvm::raw_ostream &OS) const; |
| 261 | + void dump() const; |
| 262 | +}; |
| 263 | + |
| 264 | +} // namespace swift |
| 265 | + |
| 266 | +#endif |
0 commit comments