1111// ===----------------------------------------------------------------------===//
1212
1313#include " swift/SIL/OwnershipUtils.h"
14+ #include " swift/Basic/DAGNodeWorklist.h"
1415#include " swift/Basic/Defer.h"
1516#include " swift/Basic/DAGNodeWorklist.h"
1617#include " swift/Basic/SmallPtrSetVector.h"
@@ -159,8 +160,7 @@ bool swift::canOpcodeForwardOwnedValues(Operand *use) {
159160//
160161// Skip over nested borrow scopes. Their scope-ending instructions are their use
161162// points. Transitively find all nested scope-ending instructions by looking
162- // through nested reborrows. Nested reborrows are not use points and \p
163- // visitReborrow is not called for them.
163+ // through nested reborrows. Nested reborrows are not use points.
164164bool swift::findInnerTransitiveGuaranteedUses (
165165 SILValue guaranteedValue, SmallVectorImpl<Operand *> *usePoints) {
166166
@@ -175,10 +175,10 @@ bool swift::findInnerTransitiveGuaranteedUses(
175175 //
176176 // TODO: The worklist can be a simple vector without any a membership check if
177177 // destructures are changed to be represented as reborrows. Currently a
178- // destructure forwards multiple results! This means that usePoints could grow
179- // exponentially without the membership check. It's fine to do this membership
180- // check locally in this function (within a borrow scope) because it isn't
181- // needed for the immediate uses, only the transitive uses.
178+ // destructure forwards multiple results! This means that the worklist could
179+ // grow exponentially without the membership check. It's fine to do this
180+ // membership check locally in this function (within a borrow scope) because
181+ // it isn't needed for the immediate uses, only the transitive uses.
182182 DAGNodeWorklist<Operand *, 8 > worklist;
183183 for (Operand *use : guaranteedValue->getUses ()) {
184184 if (use->getOperandOwnership () != OperandOwnership::NonUse)
@@ -220,7 +220,8 @@ bool swift::findInnerTransitiveGuaranteedUses(
220220 // If our base guaranteed value does not have any consuming uses (consider
221221 // function arguments), we need to be sure to include interior pointer
222222 // operands since we may not get a use from a end_scope instruction.
223- if (!InteriorPointerOperand(use).findTransitiveUses(usePoints)) {
223+ if (InteriorPointerOperand(use).findTransitiveUses(usePoints)
224+ != AddressUseKind::NonEscaping) {
224225 return false;
225226 }
226227#endif
@@ -252,6 +253,7 @@ bool swift::findInnerTransitiveGuaranteedUses(
252253 leafUse (endUse);
253254 return true ;
254255 });
256+ break ;
255257 }
256258 }
257259 return true ;
@@ -720,17 +722,35 @@ bool BorrowedValue::visitInteriorPointerOperandHelper(
720722 return true ;
721723}
722724
723- bool swift::findTransitiveUsesForAddress (
724- SILValue projectedAddress, SmallVectorImpl<Operand *> *foundUses,
725- std::function<void (Operand *)> *onError) {
725+ AddressUseKind
726+ swift::findTransitiveUsesForAddress (SILValue projectedAddress,
727+ SmallVectorImpl<Operand *> *foundUses,
728+ std::function<void (Operand *)> *onError) {
729+ // If the projectedAddress is dead, it is itself a leaf use. Since we don't
730+ // have an operand for it, simply bail. Dead projectedAddress is unexpected.
731+ //
732+ // TODO: store_borrow is currently an InteriorPointer with no uses, so we end
733+ // up bailing. It should be in a dependence scope instead. It's not clear why
734+ // it produces an address at all.
735+ if (projectedAddress->use_empty ())
736+ return AddressUseKind::PointerEscape;
737+
726738 SmallVector<Operand *, 8 > worklist (projectedAddress->getUses ());
727739
728- bool foundError = false ;
740+ AddressUseKind result = AddressUseKind::NonEscaping ;
729741
730742 auto leafUse = [foundUses](Operand *use) {
731743 if (foundUses)
732744 foundUses->push_back (use);
733745 };
746+ auto transitiveResultUses = [&](Operand *use) {
747+ auto *svi = cast<SingleValueInstruction>(use->getUser ());
748+ if (svi->use_empty ()) {
749+ leafUse (use);
750+ } else {
751+ worklist.append (svi->use_begin (), svi->use_end ());
752+ }
753+ };
734754
735755 while (!worklist.empty ()) {
736756 auto *op = worklist.pop_back_val ();
@@ -744,37 +764,44 @@ bool swift::findTransitiveUsesForAddress(
744764 // loop that we didn't recognize the user.
745765 auto *user = op->getUser ();
746766
767+ // TODO: Partial apply should be NonEscaping, but then we need to consider
768+ // the apply to be a use point.
769+ if (isa<PartialApplyInst>(user) || isa<AddressToPointerInst>(user)) {
770+ result = meet (result, AddressUseKind::PointerEscape);
771+ continue ;
772+ }
747773 // First, eliminate "end point uses" that we just need to check liveness at
748774 // and do not need to check transitive uses of.
749- if (isa<LoadInst>(user) || isa<CopyAddrInst>(user) ||
750- isIncidentalUse (user) || isa<StoreInst>(user) ||
751- isa<PartialApplyInst>(user) || isa<DestroyAddrInst>(user) ||
752- isa<AssignInst>(user) || isa<AddressToPointerInst>(user) ||
753- isa<YieldInst>(user) || isa<LoadUnownedInst>(user) ||
754- isa<StoreUnownedInst>(user) || isa<EndApplyInst>(user) ||
755- isa<LoadWeakInst>(user) || isa<StoreWeakInst>(user) ||
756- isa<AssignByWrapperInst>(user) || isa<BeginUnpairedAccessInst>(user) ||
757- isa<EndUnpairedAccessInst>(user) || isa<WitnessMethodInst>(user) ||
758- isa<SwitchEnumAddrInst>(user) || isa<CheckedCastAddrBranchInst>(user) ||
759- isa<SelectEnumAddrInst>(user) || isa<InjectEnumAddrInst>(user) ||
760- isa<IsUniqueInst>(user)) {
775+ if (isa<LoadInst>(user) || isa<CopyAddrInst>(user) || isIncidentalUse (user)
776+ || isa<StoreInst>(user) || isa<DestroyAddrInst>(user)
777+ || isa<AssignInst>(user) || isa<YieldInst>(user)
778+ || isa<LoadUnownedInst>(user) || isa<StoreUnownedInst>(user)
779+ || isa<EndApplyInst>(user) || isa<LoadWeakInst>(user)
780+ || isa<StoreWeakInst>(user) || isa<AssignByWrapperInst>(user)
781+ || isa<BeginUnpairedAccessInst>(user)
782+ || isa<EndUnpairedAccessInst>(user) || isa<WitnessMethodInst>(user)
783+ || isa<SwitchEnumAddrInst>(user) || isa<CheckedCastAddrBranchInst>(user)
784+ || isa<SelectEnumAddrInst>(user) || isa<InjectEnumAddrInst>(user)
785+ || isa<IsUniqueInst>(user)) {
761786 leafUse (op);
762787 continue ;
763788 }
764789
790+ if (isa<UnconditionalCheckedCastAddrInst>(user)
791+ || isa<MarkFunctionEscapeInst>(user)) {
792+ assert (!user->hasResults ());
793+ continue ;
794+ }
795+
765796 // Then handle users that we need to look at transitive uses of.
766797 if (Projection::isAddressProjection (user) ||
767798 isa<ProjectBlockStorageInst>(user) ||
768799 isa<OpenExistentialAddrInst>(user) ||
769800 isa<InitExistentialAddrInst>(user) || isa<InitEnumDataAddrInst>(user) ||
770801 isa<BeginAccessInst>(user) || isa<TailAddrInst>(user) ||
771802 isa<IndexAddrInst>(user) || isa<StoreBorrowInst>(user) ||
772- isa<UnconditionalCheckedCastAddrInst>(user) ||
773- isa<UncheckedAddrCastInst>(user)
774- || isa<MarkFunctionEscapeInst>(user)) {
775- for (SILValue r : user->getResults ()) {
776- llvm::copy (r->getUses (), std::back_inserter (worklist));
777- }
803+ isa<UncheckedAddrCastInst>(user)) {
804+ transitiveResultUses (op);
778805 continue ;
779806 }
780807
@@ -790,17 +817,26 @@ bool swift::findTransitiveUsesForAddress(
790817 // If we have a load_borrow, add it's end scope to the liveness requirement.
791818 if (auto *lbi = dyn_cast<LoadBorrowInst>(user)) {
792819 if (foundUses) {
793- transform (lbi->getEndBorrows (), std::back_inserter (*foundUses),
794- [](EndBorrowInst *ebi) { return &ebi->getAllOperands ()[0 ]; });
820+ for (Operand *use : lbi->getUses ()) {
821+ if (use->endsLocalBorrowScope ()) {
822+ leafUse (use);
823+ }
824+ }
795825 }
796826 continue ;
797827 }
798828
799829 // TODO: Merge this into the full apply site code below.
800830 if (auto *beginApply = dyn_cast<BeginApplyInst>(user)) {
801831 if (foundUses) {
802- llvm::copy (beginApply->getTokenResult ()->getUses (),
803- std::back_inserter (*foundUses));
832+ // TODO: the empty check should not be needed when dead begin_apply is
833+ // disallowed.
834+ if (beginApply->getTokenResult ()->use_empty ()) {
835+ leafUse (op);
836+ } else {
837+ llvm::copy (beginApply->getTokenResult ()->getUses (),
838+ std::back_inserter (*foundUses));
839+ }
804840 }
805841 continue ;
806842 }
@@ -818,20 +854,17 @@ bool swift::findTransitiveUsesForAddress(
818854 }
819855
820856 // If we are the value use, look through it.
821- llvm::copy (mdi-> getUses (), std::back_inserter (worklist) );
857+ transitiveResultUses (op );
822858 continue ;
823859 }
824860
825861 // We were unable to recognize this user, so return true that we failed.
826862 if (onError) {
827863 (*onError)(op);
828864 }
829- foundError = true ;
865+ result = AddressUseKind::Unknown ;
830866 }
831-
832- // We were able to recognize all of the uses of the address, so return false
833- // that we did not find any errors.
834- return !foundError;
867+ return result;
835868}
836869
837870// ===----------------------------------------------------------------------===//
0 commit comments