@@ -47,16 +47,16 @@ namespace {
47
47
48
48
class LiveRange {
49
49
// / A list of destroy_values of the live range.
50
- SmallVector<SILInstruction *, 2 > destroys ;
50
+ SmallVector<Operand *, 2 > destroyingUses ;
51
51
52
52
// / A list of forwarding instructions that forward our destroys ownership, but
53
53
// / that are also able to forward guaranteed ownership.
54
- SmallVector<SILInstruction *, 2 > generalForwardingInsts ;
54
+ SmallVector<Operand *, 2 > generalForwardingUses ;
55
55
56
56
// / Consuming users that we were not able to understand as a forwarding
57
57
// / instruction or a destroy_value. These must be passed a strongly control
58
58
// / equivalent +1 value.
59
- SmallVector<SILInstruction *, 2 > unknownConsumingUsers ;
59
+ SmallVector<Operand *, 2 > unknownConsumingUses ;
60
60
61
61
public:
62
62
LiveRange (SILValue value);
@@ -68,18 +68,40 @@ class LiveRange {
68
68
// /
69
69
// / Semantically this implies that a value is never passed off as +1 to memory
70
70
// / or another function implying it can be used everywhere at +0.
71
- bool hasConsumingUse () const { return unknownConsumingUsers .size (); }
71
+ bool hasConsumingUse () const { return unknownConsumingUses .size (); }
72
72
73
- ArrayRef<SILInstruction *> getDestroys () const { return destroys; }
74
- ArrayRef<SILInstruction *> getNonConsumingForwardingInsts () const {
75
- return generalForwardingInsts;
73
+ ArrayRef<Operand *> getDestroyingUses () const { return destroyingUses; }
74
+
75
+ private:
76
+ struct OperandToUser ;
77
+
78
+ public:
79
+ using DestroyingInstsRange =
80
+ TransformRange<ArrayRef<Operand *>, OperandToUser>;
81
+ DestroyingInstsRange getDestroyingInsts () const ;
82
+
83
+ ArrayRef<Operand *> getNonConsumingForwardingUses () const {
84
+ return generalForwardingUses;
76
85
}
77
86
};
78
87
79
88
} // end anonymous namespace
80
89
90
+ struct LiveRange ::OperandToUser {
91
+ OperandToUser () {}
92
+
93
+ SILInstruction *operator ()(const Operand *use) const {
94
+ auto *nonConstUse = const_cast <Operand *>(use);
95
+ return nonConstUse->getUser ();
96
+ }
97
+ };
98
+
99
+ LiveRange::DestroyingInstsRange LiveRange::getDestroyingInsts () const {
100
+ return DestroyingInstsRange (getDestroyingUses (), OperandToUser ());
101
+ }
102
+
81
103
LiveRange::LiveRange (SILValue value)
82
- : destroys (), generalForwardingInsts (), unknownConsumingUsers () {
104
+ : destroyingUses (), generalForwardingUses (), unknownConsumingUses () {
83
105
assert (value.getOwnershipKind () == ValueOwnershipKind::Owned);
84
106
85
107
// We know that our silvalue produces an @owned value. Look through all of our
@@ -109,8 +131,8 @@ LiveRange::LiveRange(SILValue value)
109
131
110
132
// Ok, we know now that we have a consuming use. See if we have a destroy
111
133
// value, quickly up front. If we do have one, stash it and continue.
112
- if (auto *dvi = dyn_cast <DestroyValueInst>(user)) {
113
- destroys .push_back (dvi );
134
+ if (isa <DestroyValueInst>(user)) {
135
+ destroyingUses .push_back (op );
114
136
continue ;
115
137
}
116
138
@@ -134,13 +156,13 @@ LiveRange::LiveRange(SILValue value)
134
156
return v.getOwnershipKind () ==
135
157
ValueOwnershipKind::Owned;
136
158
})) {
137
- unknownConsumingUsers .push_back (user );
159
+ unknownConsumingUses .push_back (op );
138
160
continue ;
139
161
}
140
162
141
163
// Ok, this is a forwarding instruction whose ownership we can flip from
142
164
// owned -> guaranteed.
143
- generalForwardingInsts .push_back (user );
165
+ generalForwardingUses .push_back (op );
144
166
145
167
// If we have a non-terminator, just visit its users recursively to see if
146
168
// the the users force the live range to be alive.
@@ -303,14 +325,16 @@ bool IsAddressWrittenToDefUseAnalysis::isWrittenToHelper(SILValue initialValue)
303
325
// Convert Forwarding Insts from Owned -> Guaranteed
304
326
// ===----------------------------------------------------------------------===//
305
327
306
- static void convertForwardingInstsFromOwnedToGuaranteed (
307
- ArrayRef<SILInstruction *> guaranteedForwardingInsts ) {
328
+ static void convertForwardingUsesFromOwnedToGuaranteed (
329
+ ArrayRef<Operand *> guaranteedForwardingUses ) {
308
330
// Then change all of our guaranteed forwarding insts to have guaranteed
309
331
// ownership kind instead of what ever they previously had (ignoring trivial
310
332
// results);
311
- while (!guaranteedForwardingInsts.empty ()) {
312
- auto *i = guaranteedForwardingInsts.back ();
313
- guaranteedForwardingInsts = guaranteedForwardingInsts.drop_back ();
333
+ while (!guaranteedForwardingUses.empty ()) {
334
+ auto *use = guaranteedForwardingUses.back ();
335
+ guaranteedForwardingUses = guaranteedForwardingUses.drop_back ();
336
+
337
+ auto *i = use->getUser ();
314
338
315
339
// If this is a term inst, just convert all of its incoming values that are
316
340
// owned to be guaranteed.
@@ -745,7 +769,7 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
745
769
return borrowScope.isLocalScope ();
746
770
});
747
771
748
- auto destroys = lr.getDestroys ();
772
+ auto destroys = lr.getDestroyingUses ();
749
773
if (destroys.empty () && haveAnyLocalScopes) {
750
774
return false ;
751
775
}
@@ -766,23 +790,17 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
766
790
// non-local scopes.
767
791
{
768
792
bool foundNonDeadEnd = false ;
769
- for (auto *dvi : destroys) {
770
- foundNonDeadEnd |= !getDeadEndBlocks ().isDeadEnd (dvi-> getParent ());
793
+ for (auto *d : destroys) {
794
+ foundNonDeadEnd |= !getDeadEndBlocks ().isDeadEnd (d-> getParentBlock ());
771
795
}
772
796
if (!foundNonDeadEnd && haveAnyLocalScopes)
773
797
return false ;
774
- // TODO: In a future commit, when LiveRange converts to work with
775
- // operands, this will not be needed. This is just to simplify
776
- // patches.
777
- SmallVector<Operand *, 8 > destroyOperands;
778
- transform (destroys, std::back_inserter (destroyOperands),
779
- [](SILInstruction *i) { return &i->getAllOperands ()[0 ]; });
780
798
SmallVector<Operand *, 8 > scratchSpace;
781
799
SmallPtrSet<SILBasicBlock *, 4 > visitedBlocks;
782
800
if (llvm::any_of (borrowScopeIntroducers,
783
801
[&](BorrowScopeIntroducingValue borrowScope) {
784
802
return !borrowScope.areUsesWithinScope (
785
- destroyOperands , scratchSpace, visitedBlocks,
803
+ destroys , scratchSpace, visitedBlocks,
786
804
getDeadEndBlocks ());
787
805
})) {
788
806
return false ;
@@ -792,15 +810,15 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
792
810
// Otherwise, we know that our copy_value/destroy_values are all completely
793
811
// within the guaranteed value scope. First delete the destroys/copies.
794
812
while (!destroys.empty ()) {
795
- auto *dvi = destroys.back ();
813
+ auto *d = destroys.back ();
796
814
destroys = destroys.drop_back ();
797
- eraseInstruction (dvi );
815
+ eraseInstruction (d-> getUser () );
798
816
++NumEliminatedInsts;
799
817
}
800
818
801
819
eraseAndRAUWSingleValueInstruction (cvi, cvi->getOperand ());
802
- convertForwardingInstsFromOwnedToGuaranteed (
803
- lr.getNonConsumingForwardingInsts ());
820
+ convertForwardingUsesFromOwnedToGuaranteed (
821
+ lr.getNonConsumingForwardingUses ());
804
822
805
823
++NumEliminatedInsts;
806
824
return true ;
@@ -1153,17 +1171,10 @@ class StorageGuaranteesLoadVisitor
1153
1171
1154
1172
SmallPtrSet<SILBasicBlock *, 4 > visitedBlocks;
1155
1173
LinearLifetimeChecker checker (visitedBlocks, ARCOpt.getDeadEndBlocks ());
1174
+
1156
1175
// Returns true on success. So we invert.
1157
- auto destroys = liveRange.getDestroys ();
1158
- // TODO: Once LiveRange uses operands, eliminate this!
1159
- SmallVector<Operand *, 16 > destroyOperands;
1160
- transform (destroys, std::back_inserter (destroyOperands),
1161
- [](SILInstruction *i) {
1162
- assert (isa<DestroyValueInst>(i));
1163
- return &cast<DestroyValueInst>(i)->getAllOperands ()[0 ];
1164
- });
1165
- bool foundError =
1166
- !checker.validateLifetime (baseObject, endScopeInsts, destroyOperands);
1176
+ bool foundError = !checker.validateLifetime (baseObject, endScopeInsts,
1177
+ liveRange.getDestroyingUses ());
1167
1178
return answer (foundError);
1168
1179
}
1169
1180
@@ -1196,17 +1207,12 @@ class StorageGuaranteesLoadVisitor
1196
1207
1197
1208
// Then make sure that all of our load [copy] uses are within the
1198
1209
// destroy_addr.
1199
- SmallVector<Operand *, 16 > destroyOperands;
1200
- transform (liveRange.getDestroys (), std::back_inserter (destroyOperands),
1201
- [](SILInstruction *i) {
1202
- return &cast<DestroyValueInst>(i)->getAllOperands ()[0 ];
1203
- });
1204
1210
SmallPtrSet<SILBasicBlock *, 4 > visitedBlocks;
1205
1211
LinearLifetimeChecker checker (visitedBlocks, ARCOpt.getDeadEndBlocks ());
1206
1212
// Returns true on success. So we invert.
1207
1213
bool foundError = !checker.validateLifetime (
1208
1214
stack, destroyAddrOperands /* consuming users*/ ,
1209
- destroyOperands /* non consuming users*/ );
1215
+ liveRange. getDestroyingUses () /* non consuming users*/ );
1210
1216
return answer (foundError);
1211
1217
}
1212
1218
@@ -1258,8 +1264,7 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
1258
1264
// to find the post-dominating block set of these destroy value to ensure that
1259
1265
// we do not insert multiple end_borrow.
1260
1266
assert (lifetimeFrontier.empty ());
1261
- auto destroyValues = lr.getDestroys ();
1262
- ValueLifetimeAnalysis analysis (li, destroyValues);
1267
+ ValueLifetimeAnalysis analysis (li, lr.getDestroyingInsts ());
1263
1268
bool foundCriticalEdges = !analysis.computeFrontier (
1264
1269
lifetimeFrontier, ValueLifetimeAnalysis::DontModifyCFG,
1265
1270
&getDeadEndBlocks ());
@@ -1273,10 +1278,11 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
1273
1278
}
1274
1279
1275
1280
// Then delete all of our destroy_value.
1281
+ auto destroyValues = lr.getDestroyingUses ();
1276
1282
while (!destroyValues.empty ()) {
1277
1283
auto *dvi = destroyValues.back ();
1278
1284
destroyValues = destroyValues.drop_back ();
1279
- eraseInstruction (dvi);
1285
+ eraseInstruction (dvi-> getUser () );
1280
1286
++NumEliminatedInsts;
1281
1287
}
1282
1288
@@ -1285,8 +1291,8 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
1285
1291
1286
1292
// And then change the ownership all of our owned forwarding users to be
1287
1293
// guaranteed.
1288
- convertForwardingInstsFromOwnedToGuaranteed (
1289
- lr.getNonConsumingForwardingInsts ());
1294
+ convertForwardingUsesFromOwnedToGuaranteed (
1295
+ lr.getNonConsumingForwardingUses ());
1290
1296
1291
1297
++NumEliminatedInsts;
1292
1298
++NumLoadCopyConvertedToLoadBorrow;
0 commit comments