|
14 | 14 | #define SWIFT_SIL_OWNERSHIPUTILS_H
|
15 | 15 |
|
16 | 16 | #include "swift/Basic/LLVM.h"
|
| 17 | +#include "swift/SIL/BranchPropagatedUser.h" |
17 | 18 | #include "swift/SIL/SILArgument.h"
|
18 | 19 | #include "swift/SIL/SILInstruction.h"
|
19 | 20 | #include "swift/SIL/SILValue.h"
|
@@ -164,10 +165,152 @@ bool isOwnershipForwardingInst(SILInstruction *i);
|
164 | 165 |
|
165 | 166 | bool isGuaranteedForwardingInst(SILInstruction *i);
|
166 | 167 |
|
| 168 | +struct BorrowScopeIntroducerKind { |
| 169 | + using UnderlyingKindTy = std::underlying_type<ValueKind>::type; |
| 170 | + |
| 171 | + /// Enum we use for exhaustive pattern matching over borrow scope introducers. |
| 172 | + enum Kind : UnderlyingKindTy { |
| 173 | + LoadBorrow = UnderlyingKindTy(ValueKind::LoadBorrowInst), |
| 174 | + BeginBorrow = UnderlyingKindTy(ValueKind::BeginBorrowInst), |
| 175 | + SILFunctionArgument = UnderlyingKindTy(ValueKind::SILFunctionArgument), |
| 176 | + }; |
| 177 | + |
| 178 | + static Optional<BorrowScopeIntroducerKind> get(ValueKind kind) { |
| 179 | + switch (kind) { |
| 180 | + default: |
| 181 | + return None; |
| 182 | + case ValueKind::LoadBorrowInst: |
| 183 | + return BorrowScopeIntroducerKind(LoadBorrow); |
| 184 | + case ValueKind::BeginBorrowInst: |
| 185 | + return BorrowScopeIntroducerKind(BeginBorrow); |
| 186 | + case ValueKind::SILFunctionArgument: |
| 187 | + return BorrowScopeIntroducerKind(SILFunctionArgument); |
| 188 | + } |
| 189 | + } |
| 190 | + |
| 191 | + Kind value; |
| 192 | + |
| 193 | + BorrowScopeIntroducerKind(Kind newValue) : value(newValue) {} |
| 194 | + BorrowScopeIntroducerKind(const BorrowScopeIntroducerKind &other) |
| 195 | + : value(other.value) {} |
| 196 | + operator Kind() const { return value; } |
| 197 | + |
| 198 | + /// Is this a borrow scope that begins and ends within the same function and |
| 199 | + /// thus is guaranteed to have an "end_scope" instruction. |
| 200 | + /// |
| 201 | + /// In contrast, borrow scopes that are non-local (e.x. from |
| 202 | + /// SILFunctionArguments) rely a construct like a SILFunction as the begin/end |
| 203 | + /// of the scope. |
| 204 | + bool isLocalScope() const { |
| 205 | + switch (value) { |
| 206 | + case BorrowScopeIntroducerKind::BeginBorrow: |
| 207 | + case BorrowScopeIntroducerKind::LoadBorrow: |
| 208 | + return true; |
| 209 | + case BorrowScopeIntroducerKind::SILFunctionArgument: |
| 210 | + return false; |
| 211 | + } |
| 212 | + llvm_unreachable("Covered switch isnt covered?!"); |
| 213 | + } |
| 214 | + |
| 215 | + void print(llvm::raw_ostream &os) const; |
| 216 | + LLVM_ATTRIBUTE_DEPRECATED(void dump() const, "only for use in the debugger"); |
| 217 | +}; |
| 218 | + |
| 219 | +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, |
| 220 | + BorrowScopeIntroducerKind kind); |
| 221 | + |
| 222 | +/// A higher level construct for working with values that represent the |
| 223 | +/// introduction of a new borrow scope. |
| 224 | +/// |
| 225 | +/// DISCUSSION: A "borrow introducer" is a SILValue that represents the |
| 226 | +/// beginning of a borrow scope that the ownership verifier validates. The idea |
| 227 | +/// is this API allows one to work in a generic way with all of the various |
| 228 | +/// introducers. |
| 229 | +/// |
| 230 | +/// Some examples of borrow introducers: guaranteed SILFunctionArgument, |
| 231 | +/// LoadBorrow, BeginBorrow, guaranteed BeginApply results. |
| 232 | +/// |
| 233 | +/// NOTE: It is assumed that if a borrow introducer is a value of a |
| 234 | +/// SILInstruction with multiple results, that the all of the SILInstruction's |
| 235 | +/// guaranteed results are borrow introducers. In practice this means that |
| 236 | +/// borrow introducers can not have guaranteed results that are not creating a |
| 237 | +/// new borrow scope. No such instructions exist today. |
| 238 | +struct BorrowScopeIntroducingValue { |
| 239 | + BorrowScopeIntroducerKind kind; |
| 240 | + SILValue value; |
| 241 | + |
| 242 | + BorrowScopeIntroducingValue(LoadBorrowInst *lbi) |
| 243 | + : kind(BorrowScopeIntroducerKind::LoadBorrow), value(lbi) {} |
| 244 | + BorrowScopeIntroducingValue(BeginBorrowInst *bbi) |
| 245 | + : kind(BorrowScopeIntroducerKind::BeginBorrow), value(bbi) {} |
| 246 | + BorrowScopeIntroducingValue(SILFunctionArgument *arg) |
| 247 | + : kind(BorrowScopeIntroducerKind::SILFunctionArgument), value(arg) { |
| 248 | + assert(arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed); |
| 249 | + } |
| 250 | + |
| 251 | + BorrowScopeIntroducingValue(SILValue v) |
| 252 | + : kind(*BorrowScopeIntroducerKind::get(v->getKind())), value(v) { |
| 253 | + assert(v.getOwnershipKind() == ValueOwnershipKind::Guaranteed); |
| 254 | + } |
| 255 | + |
| 256 | + /// If value is a borrow introducer return it after doing some checks. |
| 257 | + static Optional<BorrowScopeIntroducingValue> get(SILValue value) { |
| 258 | + auto kind = BorrowScopeIntroducerKind::get(value->getKind()); |
| 259 | + if (!kind || value.getOwnershipKind() != ValueOwnershipKind::Guaranteed) |
| 260 | + return None; |
| 261 | + return BorrowScopeIntroducingValue(*kind, value); |
| 262 | + } |
| 263 | + |
| 264 | + /// If this value is introducing a local scope, gather all local end scope |
| 265 | + /// instructions and append them to \p scopeEndingInsts. Asserts if this is |
| 266 | + /// called with a scope that is not local. |
| 267 | + /// |
| 268 | + /// NOTE: To determine if a scope is a local scope, call |
| 269 | + /// BorrowScopeIntoducingValue::isLocalScope(). |
| 270 | + void getLocalScopeEndingInstructions( |
| 271 | + SmallVectorImpl<SILInstruction *> &scopeEndingInsts) const; |
| 272 | + |
| 273 | + /// If this value is introducing a local scope, gather all local end scope |
| 274 | + /// instructions and pass them individually to visitor. Asserts if this is |
| 275 | + /// called with a scope that is not local. |
| 276 | + /// |
| 277 | + /// The intention is that this method can be used instead of |
| 278 | + /// BorrowScopeIntroducingValue::getLocalScopeEndingInstructions() to avoid |
| 279 | + /// introducing an intermediate array when one needs to transform the |
| 280 | + /// instructions before storing them. |
| 281 | + /// |
| 282 | + /// NOTE: To determine if a scope is a local scope, call |
| 283 | + /// BorrowScopeIntoducingValue::isLocalScope(). |
| 284 | + void visitLocalScopeEndingInstructions( |
| 285 | + function_ref<void(SILInstruction *)> visitor) const; |
| 286 | + |
| 287 | + bool isLocalScope() const { return kind.isLocalScope(); } |
| 288 | + |
| 289 | + /// Returns true if the passed in set of instructions is completely within the |
| 290 | + /// lifetime of this borrow introducer. |
| 291 | + /// |
| 292 | + /// NOTE: Scratch space is used internally to this method to store the end |
| 293 | + /// borrow scopes if needed. |
| 294 | + bool areInstructionsWithinScope( |
| 295 | + ArrayRef<BranchPropagatedUser> instructions, |
| 296 | + SmallVectorImpl<BranchPropagatedUser> &scratchSpace, |
| 297 | + SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks, |
| 298 | + DeadEndBlocks &deadEndBlocks) const; |
| 299 | + |
| 300 | +private: |
| 301 | + /// Internal constructor for failable static constructor. Please do not expand |
| 302 | + /// its usage since it assumes the code passed in is well formed. |
| 303 | + BorrowScopeIntroducingValue(BorrowScopeIntroducerKind kind, SILValue value) |
| 304 | + : kind(kind), value(value) {} |
| 305 | +}; |
| 306 | + |
167 | 307 | /// Look up through the def-use chain of \p inputValue, recording any "borrow"
|
168 |
| -/// introducers that we find into \p out. |
169 |
| -bool getUnderlyingBorrowIntroducers(SILValue inputValue, |
170 |
| - SmallVectorImpl<SILValue> &out); |
| 308 | +/// introducing values that we find into \p out. If at any point, we find a |
| 309 | +/// point in the chain we do not understand, we bail and return false. If we are |
| 310 | +/// able to understand all of the def-use graph, we know that we have found all |
| 311 | +/// of the borrow introducing values, we return true. |
| 312 | +bool getUnderlyingBorrowIntroducingValues( |
| 313 | + SILValue inputValue, SmallVectorImpl<BorrowScopeIntroducingValue> &out); |
171 | 314 |
|
172 | 315 | } // namespace swift
|
173 | 316 |
|
|
0 commit comments