12
12
13
13
#include " swift/SIL/OwnershipUtils.h"
14
14
#include " swift/Basic/Defer.h"
15
+ #include " swift/Basic/DAGNodeWorklist.h"
15
16
#include " swift/Basic/SmallPtrSetVector.h"
16
17
#include " swift/SIL/InstructionUtils.h"
17
18
#include " swift/SIL/LinearLifetimeChecker.h"
@@ -160,35 +161,33 @@ bool swift::canOpcodeForwardOwnedValues(Operand *use) {
160
161
// points. Transitively find all nested scope-ending instructions by looking
161
162
// through nested reborrows. Nested reborrows are not use points and \p
162
163
// visitReborrow is not called for them.
163
- bool swift::
164
- findInnerTransitiveGuaranteedUses (SILValue guaranteedValue,
165
- SmallVectorImpl<Operand *> &usePoints) {
164
+ bool swift::findInnerTransitiveGuaranteedUses (
165
+ SILValue guaranteedValue, SmallVectorImpl<Operand *> *usePoints) {
166
166
// Push the value's immediate uses.
167
- unsigned firstOffset = usePoints.size ();
167
+ //
168
+ // TODO: The worklist can be a simple vector without any a membership check if
169
+ // destructures are changed to be represented as reborrows. Currently a
170
+ // destructure forwards multiple results! This means that usePoints could grow
171
+ // exponentially without the membership check. It's fine to do this membership
172
+ // check locally in this function (within a borrow scope) because it isn't
173
+ // needed for the immediate uses, only the transitive uses.
174
+ DAGNodeWorklist<Operand *, 8 > worklist;
168
175
for (Operand *use : guaranteedValue->getUses ()) {
169
176
if (use->getOperandOwnership () != OperandOwnership::NonUse)
170
- usePoints. push_back (use);
177
+ worklist. insert (use);
171
178
}
172
179
173
180
// --- Transitively follow forwarded uses and look for escapes.
174
181
175
- // TODO: Remove this SmallPtrSet if destructures are changed to be represented
176
- // as reborrows. Currently it forwards multiple results! This means that
177
- // usePoints could grow exponentially without a membership check. It's fine to
178
- // do this membership check locally in this function (within a borrow
179
- // scope). It isn't needed for the immediate uses, only the transitive uses.
180
- SmallPtrSet<Operand *, 16 > visitedUses;
181
- auto pushUse = [&](Operand *use) {
182
- if (use->getOperandOwnership () != OperandOwnership::NonUse) {
183
- if (visitedUses.insert (use).second )
184
- usePoints.push_back (use);
182
+ auto recordLeafUse = [&](Operand *use) {
183
+ if (usePoints && use->getOperandOwnership () != OperandOwnership::NonUse) {
184
+ usePoints->push_back (use);
185
185
}
186
186
return true ;
187
187
};
188
188
189
189
// usePoints grows in this loop.
190
- for (unsigned i = firstOffset; i < usePoints.size (); ++i) {
191
- Operand *use = usePoints[i];
190
+ while (Operand *use = worklist.pop ()) {
192
191
switch (use->getOperandOwnership ()) {
193
192
case OperandOwnership::NonUse:
194
193
case OperandOwnership::TrivialUse:
@@ -228,14 +227,17 @@ findInnerTransitiveGuaranteedUses(SILValue guaranteedValue,
228
227
if (transitiveValue.getOwnershipKind () == OwnershipKind::None)
229
228
return true ;
230
229
for (auto *transitiveUse : transitiveValue->getUses ()) {
231
- pushUse (transitiveUse);
230
+ if (transitiveUse->getOperandOwnership ()
231
+ != OperandOwnership::NonUse) {
232
+ worklist.insert (use);
233
+ }
232
234
}
233
235
return true ;
234
236
});
235
237
break ;
236
238
237
239
case OperandOwnership::Borrow:
238
- BorrowingOperand (use).visitExtendedScopeEndingUses (pushUse );
240
+ BorrowingOperand (use).visitExtendedScopeEndingUses (recordLeafUse );
239
241
}
240
242
}
241
243
return true ;
@@ -271,7 +273,7 @@ bool swift::findTransitiveGuaranteedUses(
271
273
}
272
274
return true ;
273
275
}
274
- return findInnerTransitiveGuaranteedUses (guaranteedValue, usePoints);
276
+ return findInnerTransitiveGuaranteedUses (guaranteedValue, & usePoints);
275
277
}
276
278
277
279
// Find all use points of \p guaranteedValue within its borrow scope. If the
@@ -705,23 +707,24 @@ bool BorrowedValue::visitInteriorPointerOperandHelper(
705
707
}
706
708
707
709
bool swift::findTransitiveUsesForAddress (
708
- SILValue projectedAddress, SmallVectorImpl<Operand *> & foundUses,
710
+ SILValue projectedAddress, SmallVectorImpl<Operand *> * foundUses,
709
711
std::function<void (Operand *)> *onError) {
710
712
SmallVector<Operand *, 8 > worklist (projectedAddress->getUses ());
711
713
712
714
bool foundError = false ;
713
715
716
+ auto leafUse = [foundUses](Operand *use) {
717
+ if (foundUses)
718
+ foundUses->push_back (use);
719
+ };
720
+
714
721
while (!worklist.empty ()) {
715
722
auto *op = worklist.pop_back_val ();
716
723
717
724
// Skip type dependent operands.
718
725
if (op->isTypeDependent ())
719
726
continue ;
720
727
721
- // Before we do anything, add this operand to our implicit regular user
722
- // list.
723
- foundUses.push_back (op);
724
-
725
728
// Then update the worklist with new things to find if we recognize this
726
729
// inst and then continue. If we fail, we emit an error at the bottom of the
727
730
// loop that we didn't recognize the user.
@@ -741,6 +744,7 @@ bool swift::findTransitiveUsesForAddress(
741
744
isa<SwitchEnumAddrInst>(user) || isa<CheckedCastAddrBranchInst>(user) ||
742
745
isa<SelectEnumAddrInst>(user) || isa<InjectEnumAddrInst>(user) ||
743
746
isa<IsUniqueInst>(user)) {
747
+ leafUse (op);
744
748
continue ;
745
749
}
746
750
@@ -763,33 +767,39 @@ bool swift::findTransitiveUsesForAddress(
763
767
if (auto *builtin = dyn_cast<BuiltinInst>(user)) {
764
768
if (auto kind = builtin->getBuiltinKind ()) {
765
769
if (*kind == BuiltinValueKind::TSanInoutAccess) {
770
+ leafUse (op);
766
771
continue ;
767
772
}
768
773
}
769
774
}
770
775
771
776
// If we have a load_borrow, add it's end scope to the liveness requirement.
772
777
if (auto *lbi = dyn_cast<LoadBorrowInst>(user)) {
773
- transform (lbi->getEndBorrows (), std::back_inserter (foundUses),
774
- [](EndBorrowInst *ebi) { return &ebi->getAllOperands ()[0 ]; });
778
+ if (foundUses) {
779
+ transform (lbi->getEndBorrows (), std::back_inserter (*foundUses),
780
+ [](EndBorrowInst *ebi) { return &ebi->getAllOperands ()[0 ]; });
781
+ }
775
782
continue ;
776
783
}
777
784
778
785
// TODO: Merge this into the full apply site code below.
779
786
if (auto *beginApply = dyn_cast<BeginApplyInst>(user)) {
780
- // TODO: Just add this to implicit regular user list?
781
- llvm::copy (beginApply->getTokenResult ()->getUses (),
782
- std::back_inserter (foundUses));
787
+ if (foundUses) {
788
+ llvm::copy (beginApply->getTokenResult ()->getUses (),
789
+ std::back_inserter (*foundUses));
790
+ }
783
791
continue ;
784
792
}
785
793
786
794
if (auto fas = FullApplySite::isa (user)) {
795
+ leafUse (op);
787
796
continue ;
788
797
}
789
798
790
799
if (auto *mdi = dyn_cast<MarkDependenceInst>(user)) {
791
800
// If this is the base, just treat it as a liveness use.
792
801
if (op->get () == mdi->getBase ()) {
802
+ leafUse (op);
793
803
continue ;
794
804
}
795
805
0 commit comments