@@ -199,22 +199,30 @@ bool isValueAddressOrTrivial(SILValue v);
199199// / These operations forward both owned and guaranteed ownership.
200200bool isOwnershipForwardingValueKind (SILNodeKind kind);
201201
202+ // / Is this an instruction that can forward both owned and guaranteed ownership
203+ // / kinds.
204+ bool isOwnershipForwardingInst (SILInstruction *i);
205+
206+ // / Is this an instruction that can forward guaranteed ownership.
207+ bool isGuaranteedForwardingInst (SILInstruction *i);
208+
202209// / These operations forward guaranteed ownership, but don't necessarily forward
203210// / owned values.
204211bool isGuaranteedForwardingValueKind (SILNodeKind kind);
205212
213+ // / Is this a value that is the result of an operation that forwards owned
214+ // / ownership.
206215bool isGuaranteedForwardingValue (SILValue value);
207216
208- bool isOwnershipForwardingInst (SILInstruction *i);
209-
210- bool isGuaranteedForwardingInst (SILInstruction *i );
217+ // / Is this a node kind that can forward owned ownership, but may not be able to
218+ // / forward guaranteed ownership.
219+ bool isOwnedForwardingValueKind (SILNodeKind kind );
211220
212221struct BorrowScopeOperandKind {
213- using UnderlyingKindTy = std::underlying_type<SILInstructionKind>::type;
214-
215- enum Kind : UnderlyingKindTy {
216- BeginBorrow = UnderlyingKindTy (SILInstructionKind::BeginBorrowInst),
217- BeginApply = UnderlyingKindTy (SILInstructionKind::BeginApplyInst),
222+ enum Kind {
223+ BeginBorrow,
224+ BeginApply,
225+ Branch,
218226 };
219227
220228 Kind value;
@@ -232,6 +240,8 @@ struct BorrowScopeOperandKind {
232240 return BorrowScopeOperandKind (BeginBorrow);
233241 case SILInstructionKind::BeginApplyInst:
234242 return BorrowScopeOperandKind (BeginApply);
243+ case SILInstructionKind::BranchInst:
244+ return BorrowScopeOperandKind (Branch);
235245 }
236246 }
237247
@@ -242,9 +252,15 @@ struct BorrowScopeOperandKind {
242252llvm::raw_ostream &operator <<(llvm::raw_ostream &os,
243253 BorrowScopeOperandKind kind);
244254
255+ struct BorrowScopeIntroducingValue ;
256+
245257// / An operand whose user instruction introduces a new borrow scope for the
246258// / operand's value. The value of the operand must be considered as implicitly
247259// / borrowed until the user's corresponding end scope instruction.
260+ // /
261+ // / NOTE: We do not require that the guaranteed scope be represented by a
262+ // / guaranteed value in the same function: see begin_apply. In such cases, we
263+ // / require instead an end_* instruction to mark the end of the scope's region.
248264struct BorrowScopeOperand {
249265 BorrowScopeOperandKind kind;
250266 Operand *op;
@@ -270,6 +286,66 @@ struct BorrowScopeOperand {
270286
271287 void visitEndScopeInstructions (function_ref<void (Operand *)> func) const ;
272288
289+ // / Returns true if this borrow scope operand consumes guaranteed
290+ // / values and produces a new scope afterwards.
291+ bool consumesGuaranteedValues () const {
292+ switch (kind) {
293+ case BorrowScopeOperandKind::BeginBorrow:
294+ case BorrowScopeOperandKind::BeginApply:
295+ return false ;
296+ case BorrowScopeOperandKind::Branch:
297+ return true ;
298+ }
299+ llvm_unreachable (" Covered switch isn't covered?!" );
300+ }
301+
302+ // / Is this a borrow scope operand that can open new borrow scopes
303+ // / for owned values.
304+ bool canAcceptOwnedValues () const {
305+ switch (kind) {
306+ case BorrowScopeOperandKind::BeginBorrow:
307+ case BorrowScopeOperandKind::BeginApply:
308+ return true ;
309+ case BorrowScopeOperandKind::Branch:
310+ return false ;
311+ }
312+ llvm_unreachable (" Covered switch isn't covered?!" );
313+ }
314+
315+ // / Is the result of this instruction also a borrow introducer?
316+ // /
317+ // / TODO: This needs a better name.
318+ bool areAnyUserResultsBorrowIntroducers () const {
319+ // TODO: Can we derive this by running a borrow introducer check ourselves?
320+ switch (kind) {
321+ case BorrowScopeOperandKind::BeginBorrow:
322+ case BorrowScopeOperandKind::Branch:
323+ return true ;
324+ case BorrowScopeOperandKind::BeginApply:
325+ return false ;
326+ }
327+ llvm_unreachable (" Covered switch isn't covered?!" );
328+ }
329+
330+ // / Visit all of the results of the operand's user instruction that are
331+ // / consuming uses.
332+ void visitUserResultConsumingUses (function_ref<void (Operand *)> visitor);
333+
334+ // / Visit all of the "results" of the user of this operand that are borrow
335+ // / scope introducers for the specific scope that this borrow scope operand
336+ // / summarizes.
337+ void visitBorrowIntroducingUserResults (
338+ function_ref<void (BorrowScopeIntroducingValue)> visitor);
339+
340+ // / Passes to visitor all of the consuming uses of this use's using
341+ // / instruction.
342+ // /
343+ // / This enables one to walk the def-use chain of guaranteed phis for a single
344+ // / guaranteed scope by using a worklist and checking if any of the operands
345+ // / are BorrowScopeOperands.
346+ void visitConsumingUsesOfBorrowIntroducingUserResults (
347+ function_ref<void (Operand *)> visitor);
348+
273349 void print (llvm::raw_ostream &os) const ;
274350 SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
275351
@@ -287,10 +363,11 @@ struct BorrowScopeIntroducingValueKind {
287363 using UnderlyingKindTy = std::underlying_type<ValueKind>::type;
288364
289365 // / Enum we use for exhaustive pattern matching over borrow scope introducers.
290- enum Kind : UnderlyingKindTy {
291- LoadBorrow = UnderlyingKindTy (ValueKind::LoadBorrowInst),
292- BeginBorrow = UnderlyingKindTy (ValueKind::BeginBorrowInst),
293- SILFunctionArgument = UnderlyingKindTy (ValueKind::SILFunctionArgument),
366+ enum Kind {
367+ LoadBorrow,
368+ BeginBorrow,
369+ SILFunctionArgument,
370+ Phi,
294371 };
295372
296373 static Optional<BorrowScopeIntroducingValueKind> get (ValueKind kind) {
@@ -303,6 +380,8 @@ struct BorrowScopeIntroducingValueKind {
303380 return BorrowScopeIntroducingValueKind (BeginBorrow);
304381 case ValueKind::SILFunctionArgument:
305382 return BorrowScopeIntroducingValueKind (SILFunctionArgument);
383+ case ValueKind::SILPhiArgument:
384+ return BorrowScopeIntroducingValueKind (Phi);
306385 }
307386 }
308387
@@ -323,6 +402,7 @@ struct BorrowScopeIntroducingValueKind {
323402 switch (value) {
324403 case BorrowScopeIntroducingValueKind::BeginBorrow:
325404 case BorrowScopeIntroducingValueKind::LoadBorrow:
405+ case BorrowScopeIntroducingValueKind::Phi:
326406 return true ;
327407 case BorrowScopeIntroducingValueKind::SILFunctionArgument:
328408 return false ;
@@ -365,9 +445,28 @@ struct BorrowScopeIntroducingValue {
365445 : kind(BorrowScopeIntroducingValueKind::SILFunctionArgument), value(arg) {
366446 assert (arg->getOwnershipKind () == ValueOwnershipKind::Guaranteed);
367447 }
448+ BorrowScopeIntroducingValue (SILPhiArgument *arg)
449+ : kind(BorrowScopeIntroducingValueKind::Phi), value(arg) {
450+ assert (llvm::all_of (arg->getParent ()->getPredecessorBlocks (),
451+ [](SILBasicBlock *block) {
452+ return isa<BranchInst>(block->getTerminator ());
453+ }) &&
454+ " Phi argument incoming values must come from branch insts!" );
455+ assert (arg->isPhiArgument () && " Can only accept a true phi argument!" );
456+ assert (arg->getOwnershipKind () == ValueOwnershipKind::Guaranteed);
457+ }
368458
369459 BorrowScopeIntroducingValue (SILValue v)
370460 : kind(*BorrowScopeIntroducingValueKind::get (v->getKind ())), value(v) {
461+ // Validate that if we have a phi argument that all our predecessors have
462+ // branches as terminators.
463+ assert (!isa<SILPhiArgument>(v) ||
464+ (llvm::all_of (v->getParentBlock ()->getPredecessorBlocks (),
465+ [](SILBasicBlock *block) {
466+ return isa<BranchInst>(block->getTerminator ());
467+ }) &&
468+ " Phi argument incoming values must come from branch insts!" ));
469+
371470 assert (v.getOwnershipKind () == ValueOwnershipKind::Guaranteed);
372471 }
373472
@@ -376,6 +475,15 @@ struct BorrowScopeIntroducingValue {
376475 auto kind = BorrowScopeIntroducingValueKind::get (value->getKind ());
377476 if (!kind || value.getOwnershipKind () != ValueOwnershipKind::Guaranteed)
378477 return None;
478+ // If kind is phi and we were not passed something with all branch
479+ // predecessors, return None.
480+ if ((*kind) == BorrowScopeIntroducingValueKind::Phi &&
481+ llvm::any_of (value->getParentBlock ()->getPredecessorBlocks (),
482+ [](SILBasicBlock *block) {
483+ return !isa<BranchInst>(block->getTerminator ());
484+ }))
485+ return None;
486+ // Otherwise, create our value directly.
379487 return BorrowScopeIntroducingValue (*kind, value);
380488 }
381489
@@ -414,6 +522,11 @@ struct BorrowScopeIntroducingValue {
414522 SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
415523 DeadEndBlocks &deadEndBlocks) const ;
416524
525+ // / Given a local borrow scope introducer, visit all non-forwarding consuming
526+ // / users. This means that this looks through guaranteed block arguments.
527+ bool visitLocalScopeTransitiveEndingUses (
528+ function_ref<void (Operand *)> visitor) const ;
529+
417530 void print (llvm::raw_ostream &os) const ;
418531 SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
419532
0 commit comments