1515
1616#include " swift/Basic/Debug.h"
1717#include " swift/Basic/LLVM.h"
18+ #include " swift/SIL/MemAccessUtils.h"
1819#include " swift/SIL/SILArgument.h"
19- #include " swift/SIL/SILInstruction.h"
2020#include " swift/SIL/SILBasicBlock.h"
21+ #include " swift/SIL/SILInstruction.h"
2122#include " swift/SIL/SILValue.h"
2223#include " llvm/ADT/SmallPtrSet.h"
2324#include " llvm/ADT/SmallVector.h"
@@ -29,6 +30,7 @@ class SILInstruction;
2930class SILModule ;
3031class SILValue ;
3132class DeadEndBlocks ;
33+ class PrunedLiveness ;
3234
3335// / Returns true if v is an address or trivial.
3436bool isValueAddressOrTrivial (SILValue v);
@@ -148,7 +150,7 @@ bool findTransitiveGuaranteedUses(SILValue guaranteedValue,
148150// / 1. If \p guaranteedValue introduces a borrow scope (begin_borrow,
149151// / load_borrow, or phi), then its only use points are the extended scope-ending
150152// / uses, and this function returns true. This is, in fact, equivalent to
151- // / calling BorrowedValue::visitExtendedLocalScopeEndingUses ().
153+ // / calling BorrowedValue::visitExtendedScopeEndingUses ().
152154// /
153155// / 2. If \p guaranteedValue does not introduce a borrow scope (it is not a
154156// / valid BorrowedValue), then its uses are discovered transitively by looking
@@ -172,8 +174,8 @@ class ForwardingOperand {
172174 return use->getOwnershipConstraint ();
173175 }
174176
175- ValueOwnershipKind getOwnershipKind () const ;
176- void setOwnershipKind (ValueOwnershipKind newKind) const ;
177+ ValueOwnershipKind getForwardingOwnershipKind () const ;
178+ void setForwardingOwnershipKind (ValueOwnershipKind newKind) const ;
177179 void replaceOwnershipKind (ValueOwnershipKind oldKind,
178180 ValueOwnershipKind newKind) const ;
179181
@@ -304,13 +306,20 @@ struct BorrowingOperand {
304306 // / visits the end of the introduced borrow scope.
305307 bool visitScopeEndingUses (function_ref<bool (Operand *)> func) const ;
306308
309+ // / Returns true for borrows that create a local borrow scope but have no
310+ // / scope-ending uses (presumably all paths are dead-end blocks). This does
311+ // / not include instantaneous borrows, which don't require explicit scope
312+ // / ending uses.
313+ // /
314+ // / FIXME: Borrow scopes should have scope-ending uses on all paths, even to
315+ // / dead end blocks. When the verifier enforces this, remove this check.
316+ bool hasEmptyRequiredEndingUses () const ;
317+
307318 // / Visit the scope ending operands of the extended scope, after transitively
308319 // / searching through reborrows. These uses might not be dominated by this
309320 // / BorrowingOperand.
310321 // /
311322 // / Returns false and early exits if the visitor \p func returns false.
312- // /
313- // / Note: this does not visit the intermediate reborrows.
314323 bool visitExtendedScopeEndingUses (function_ref<bool (Operand *)> func) const ;
315324
316325 // / Returns true if this borrow scope operand consumes guaranteed
@@ -493,7 +502,7 @@ struct InteriorPointerOperand;
493502// / jointly post-dominate this value (see visitLocalScopeEndingUses()). The
494503// / extended scope, including reborrows has end points that are not dominated by
495504// / this value but still jointly post-dominate (see
496- // / visitExtendedLocalScopeEndingUses ()).
505+ // / visitExtendedScopeEndingUses ()).
497506struct BorrowedValue {
498507 SILValue value;
499508 BorrowedValueKind kind = BorrowedValueKind::Invalid;
@@ -535,20 +544,25 @@ struct BorrowedValue {
535544
536545 bool isLocalScope () const { return kind.isLocalScope (); }
537546
538- // / Returns true if the passed in set of uses is completely within
539- // / the lifetime of this borrow introducer.
547+ // / Add this scopes live blocks into the PrunedLiveness result.
548+ void computeLiveness (PrunedLiveness &liveness) const ;
549+
550+ // / Returns true if \p uses are completely within this borrow introducer's
551+ // / local scope.
540552 // /
541- // / NOTE: Scratch space is used internally to this method to store the end
542- // / borrow scopes if needed.
543- bool areUsesWithinScope (ArrayRef<Operand *> uses,
544- SmallVectorImpl<Operand *> &scratchSpace,
545- DeadEndBlocks &deadEndBlocks) const ;
553+ // / Precondition: \p uses are dominated by the local borrow introducer.
554+ // /
555+ // / This ignores reborrows. The assumption is that, since \p uses are
556+ // / dominated by this local scope, checking the extended borrow scope should
557+ // / not be necessary to determine they are within the scope.
558+ bool areUsesWithinLocalScope (ArrayRef<Operand *> uses,
559+ DeadEndBlocks &deadEndBlocks) const ;
546560
547561 // / Given a local borrow scope introducer, visit all non-forwarding consuming
548562 // / users. This means that this looks through guaranteed block arguments. \p
549563 // / visitor is *not* called on Reborrows, only on final scope ending uses.
550- bool visitExtendedLocalScopeEndingUses (
551- function_ref<bool (Operand *)> visitor) const ;
564+ bool
565+ visitExtendedScopeEndingUses ( function_ref<bool (Operand *)> visitor) const ;
552566
553567 void print (llvm::raw_ostream &os) const ;
554568 SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
@@ -583,6 +597,14 @@ struct BorrowedValue {
583597 func, InteriorPointerOperandVisitorKind::YesNestedYesReborrows);
584598 }
585599
600+ bool hasReborrow () const {
601+ for (auto *op : value->getUses ()) {
602+ if (op->getOperandOwnership () == OperandOwnership::Reborrow)
603+ return true ;
604+ }
605+ return false ;
606+ }
607+
586608 // / Visit all immediate uses of this borrowed value and if any of them are
587609 // / reborrows, place them in BorrowingOperand form into \p
588610 // / foundReborrows. Returns true if we appended any such reborrows to
@@ -591,12 +613,10 @@ struct BorrowedValue {
591613 &foundReborrows) const {
592614 bool foundAnyReborrows = false ;
593615 for (auto *op : value->getUses ()) {
594- if (auto borrowingOperand = BorrowingOperand (op)) {
595- if (borrowingOperand.isReborrow ()) {
596- foundReborrows.push_back (
597- {value->getParentBlock (), op->getOperandNumber ()});
598- foundAnyReborrows = true ;
599- }
616+ if (op->getOperandOwnership () == OperandOwnership::Reborrow) {
617+ foundReborrows.push_back (
618+ {value->getParentBlock (), op->getOperandNumber ()});
619+ foundAnyReborrows = true ;
600620 }
601621 }
602622 return foundAnyReborrows;
@@ -642,6 +662,13 @@ bool getAllBorrowIntroducingValues(SILValue value,
642662// / introducer, then we return a .some(BorrowScopeIntroducingValue).
643663BorrowedValue getSingleBorrowIntroducingValue (SILValue inputValue);
644664
665+ // / The algorithm that is used to determine what the verifier will consider to
666+ // / be transitive uses of the given address. Used to implement \see
667+ // / findTransitiveUses.
668+ bool findTransitiveUsesForAddress (
669+ SILValue address, SmallVectorImpl<Operand *> &foundUses,
670+ std::function<void (Operand *)> *onError = nullptr);
671+
645672class InteriorPointerOperandKind {
646673public:
647674 enum Kind : uint8_t {
@@ -785,7 +812,7 @@ struct InteriorPointerOperand {
785812 }
786813
787814 // / Return the base BorrowedValue of the incoming value's operand.
788- BorrowedValue getSingleBaseValue () const {
815+ BorrowedValue getSingleBorrowedValue () const {
789816 return getSingleBorrowIntroducingValue (operand->get ());
790817 }
791818
@@ -820,14 +847,6 @@ struct InteriorPointerOperand {
820847 onError);
821848 }
822849
823- // / The algorithm that is used to determine what the verifier will consider to
824- // / be transitive uses of the given address. Used to implement \see
825- // / findTransitiveUses.
826- static bool
827- findTransitiveUsesForAddress (SILValue address,
828- SmallVectorImpl<Operand *> &foundUses,
829- std::function<void (Operand *)> *onError = nullptr );
830-
831850 Operand *operator ->() { return operand; }
832851 const Operand *operator ->() const { return operand; }
833852 Operand *operator *() { return operand; }
@@ -840,23 +859,70 @@ struct InteriorPointerOperand {
840859 : operand(op), kind(kind) {}
841860};
842861
843- // / Utility to check if an address may originate from a borrowed value. If so,
862+ // / Utility to check if an address may originate from an OSSA value. If so,
844863// / then uses of the address cannot be replaced without ensuring that they are
845- // / also within the same scope.
864+ // / also within the same owned lifetime or borrow scope.
846865// /
847- // / If mayBeBorrowed is false, then there is no enclosing borrow scope and
848- // / interiorPointerOp is irrelevant.
866+ // / If hasOwnership() is false, then there is no enclosing lifetime or borrow
867+ // / scope and interiorPointerOp is irrelevant.
849868// /
850- // / If mayBeBorrowed is true, then interiorPointerOp refers to the operand that
869+ // / If hasOwnership() is true, then interiorPointerOp refers to the operand that
851870// / converts a non-address value into the address from which the contructor's
852871// / address is derived. If the best-effort to find an InteriorPointerOperand
853872// / fails, then interiorPointerOp remains invalid, and clients must be
854873// / conservative.
855- struct BorrowedAddress {
856- bool mayBeBorrowed = true ;
857- InteriorPointerOperand interiorPointerOp;
874+ // /
875+ // / TODO: Handle implicit borrow scopes once they are legal in SIL. The operand
876+ // / of the base will be owned but mayBeBorrowed will remain true.
877+ struct AddressOwnership {
878+ AccessBase base;
879+
880+ AddressOwnership () = default ;
881+
882+ AddressOwnership (SILValue address) : base(AccessBase::compute(address)) {
883+ assert (address->getType ().isAddress ());
884+ }
885+
886+ AddressOwnership (AccessBase base) : base(base) {}
887+
888+ operator bool () const { return bool (base); }
889+
890+ bool operator ==(const AddressOwnership &other) const {
891+ return base.hasIdenticalAccessInfo (other.base );
892+ }
893+
894+ bool operator !=(const AddressOwnership &other) const {
895+ return !(*this == other);
896+ }
858897
859- BorrowedAddress (SILValue address);
898+ // / Return true if this address may be derived from a value with a local OSSA
899+ // / lifetime or borrow scope.
900+ bool hasLocalOwnershipLifetime () const {
901+ return base.hasLocalOwnershipLifetime ();
902+ }
903+
904+ // / Return the OSSA value from which this address is derived. This may be
905+ // / invalid even if hasOSSALifetime() is true in cases where the
906+ // / InteriorPointerOperand is unrecognized.
907+ SILValue getOwnershipReferenceRoot () const {
908+ if (base.isReference ())
909+ return base.getOwnershipReferenceRoot ();
910+
911+ return SILValue ();
912+ }
913+
914+ // / Transitively compute uses of this base address.
915+ bool findTransitiveUses (SmallVectorImpl<Operand *> &foundUses) {
916+ return findTransitiveUsesForAddress (base.getBaseAddress (), foundUses);
917+ }
918+
919+ // / Return true of all \p uses occur before the end of the address' lifetime
920+ // / or borrow scope.
921+ // /
922+ // / Precondition: all \p uses are dominated by the beginning of the address'
923+ // / lifetime or borrow scope.
924+ bool areUsesWithinLifetime (ArrayRef<Operand *> uses,
925+ DeadEndBlocks &deadEndBlocks) const ;
860926};
861927
862928class OwnedValueIntroducerKind {
0 commit comments