@@ -41,16 +41,50 @@ STATISTIC(NumLoadCopyConvertedToLoadBorrow,
41
41
// Utility
42
42
// ===----------------------------------------------------------------------===//
43
43
44
- // / Return true if v only has invalidating uses that are destroy_value. Such an
45
- // / owned value is said to represent a dead "live range".
46
- // /
47
- // / Semantically this implies that a value is never passed off as +1 to memory
48
- // / or another function implying it can be used everywhere at +0.
49
- static bool
50
- isDeadLiveRange (SILValue v, SmallVectorImpl<SILInstruction *> &destroys,
51
- SmallVectorImpl<SILInstruction *> &forwardingInsts) {
52
- assert (v.getOwnershipKind () == ValueOwnershipKind::Owned);
53
- SmallVector<Operand *, 32 > worklist (v->use_begin (), v->use_end ());
44
+ // ===----------------------------------------------------------------------===//
45
+ // Live Range Modeling
46
+ // ===----------------------------------------------------------------------===//
47
+
48
+ namespace {
49
+
50
+ class LiveRange {
51
+ // / A list of destroy_values of the live range.
52
+ SmallVector<SILInstruction *, 16 > destroys;
53
+
54
+ // / A list of forwarding instructions that forward our destroys ownership, but
55
+ // / that are also able to forward guaranteed ownership.
56
+ SmallVector<SILInstruction *, 16 > generalForwardingInsts;
57
+
58
+ // / Consuming users that we were not able to understand as a forwarding
59
+ // / instruction or a destroy_value. These must be passed a strongly control
60
+ // / equivalent +1 value.
61
+ SmallVector<SILInstruction *, 16 > unknownConsumingUsers;
62
+
63
+ public:
64
+ LiveRange (SILValue value);
65
+
66
+ LiveRange (const LiveRange &) = delete ;
67
+ LiveRange &operator =(const LiveRange &) = delete ;
68
+
69
+ // / Return true if v only has invalidating uses that are destroy_value. Such
70
+ // / an owned value is said to represent a dead "live range".
71
+ // /
72
+ // / Semantically this implies that a value is never passed off as +1 to memory
73
+ // / or another function implying it can be used everywhere at +0.
74
+ bool hasConsumingUse () const { return unknownConsumingUsers.size (); }
75
+
76
+ ArrayRef<SILInstruction *> getDestroys () const { return destroys; }
77
+ ArrayRef<SILInstruction *> getNonConsumingForwardingInsts () const {
78
+ return generalForwardingInsts;
79
+ }
80
+ };
81
+
82
+ } // end anonymous namespace
83
+
84
+ LiveRange::LiveRange (SILValue value)
85
+ : destroys(), generalForwardingInsts(), unknownConsumingUsers() {
86
+ SmallVector<Operand *, 32 > worklist (value->getUses ());
87
+
54
88
while (!worklist.empty ()) {
55
89
auto *op = worklist.pop_back_val ();
56
90
@@ -93,13 +127,14 @@ isDeadLiveRange(SILValue v, SmallVectorImpl<SILInstruction *> &destroys,
93
127
return v.getOwnershipKind () ==
94
128
ValueOwnershipKind::Owned;
95
129
})) {
96
- return false ;
130
+ unknownConsumingUsers.push_back (user);
131
+ continue ;
97
132
}
98
133
99
134
// Ok, this is a forwarding instruction whose ownership we can flip from
100
135
// owned -> guaranteed. Visit its users recursively to see if the the
101
136
// users force the live range to be alive.
102
- forwardingInsts .push_back (user);
137
+ generalForwardingInsts .push_back (user);
103
138
for (SILValue v : user->getResults ()) {
104
139
if (v.getOwnershipKind () != ValueOwnershipKind::Owned)
105
140
continue ;
@@ -118,10 +153,6 @@ isDeadLiveRange(SILValue v, SmallVectorImpl<SILInstruction *> &destroys,
118
153
continue ;
119
154
}
120
155
}
121
-
122
- // We visited all of our users and were able to prove that all of them were
123
- // benign. Return true.
124
- return true ;
125
156
}
126
157
127
158
// ===----------------------------------------------------------------------===//
@@ -372,12 +403,13 @@ bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) {
372
403
}
373
404
374
405
static void convertForwardingInstsFromOwnedToGuaranteed (
375
- SmallVectorImpl <SILInstruction *> & guaranteedForwardingInsts) {
406
+ ArrayRef <SILInstruction *> guaranteedForwardingInsts) {
376
407
// Then change all of our guaranteed forwarding insts to have guaranteed
377
408
// ownership kind instead of what ever they previously had (ignoring trivial
378
409
// results);
379
410
while (!guaranteedForwardingInsts.empty ()) {
380
- auto *i = guaranteedForwardingInsts.pop_back_val ();
411
+ auto *i = guaranteedForwardingInsts.back ();
412
+ guaranteedForwardingInsts = guaranteedForwardingInsts.drop_back ();
381
413
assert (i->hasResults ());
382
414
383
415
for (SILValue result : i->getResults ()) {
@@ -461,9 +493,8 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
461
493
// must be some consuming use that we either do not understand is /actually/
462
494
// forwarding or a user that truly represents a necessary consume of the
463
495
// value (e.x. storing into memory).
464
- SmallVector<SILInstruction *, 16 > destroys;
465
- SmallVector<SILInstruction *, 16 > guaranteedForwardingInsts;
466
- if (!isDeadLiveRange (cvi, destroys, guaranteedForwardingInsts))
496
+ LiveRange lr (cvi);
497
+ if (lr.hasConsumingUse ())
467
498
return false ;
468
499
469
500
// Next check if we do not have any destroys of our copy_value and are
@@ -526,6 +557,7 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
526
557
return borrowScope.isLocalScope ();
527
558
});
528
559
560
+ auto destroys = lr.getDestroys ();
529
561
if (destroys.empty () && haveAnyLocalScopes) {
530
562
return false ;
531
563
}
@@ -568,13 +600,15 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
568
600
// Otherwise, we know that our copy_value/destroy_values are all completely
569
601
// within the guaranteed value scope. First delete the destroys/copies.
570
602
while (!destroys.empty ()) {
571
- auto *dvi = destroys.pop_back_val ();
603
+ auto *dvi = destroys.back ();
604
+ destroys = destroys.drop_back ();
572
605
eraseInstruction (dvi);
573
606
++NumEliminatedInsts;
574
607
}
575
608
576
609
eraseAndRAUWSingleValueInstruction (cvi, cvi->getOperand ());
577
- convertForwardingInstsFromOwnedToGuaranteed (guaranteedForwardingInsts);
610
+ convertForwardingInstsFromOwnedToGuaranteed (
611
+ lr.getNonConsumingForwardingInsts ());
578
612
579
613
++NumEliminatedInsts;
580
614
return true ;
@@ -842,14 +876,14 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
842
876
// FIXME: We should consider if it is worth promoting a load [copy]
843
877
// -> load_borrow if we can put a copy_value on a cold path and thus
844
878
// eliminate RR traffic on a hot path.
845
- SmallVector<SILInstruction *, 32 > destroyValues;
846
- SmallVector<SILInstruction *, 16 > guaranteedForwardingInsts;
847
- if (!isDeadLiveRange (li, destroyValues, guaranteedForwardingInsts))
879
+ LiveRange lr (li);
880
+ if (lr.hasConsumingUse ())
848
881
return false ;
849
882
850
883
// Then check if our address is ever written to. If it is, then we cannot use
851
884
// the load_borrow because the stored value may be released during the loaded
852
885
// value's live range.
886
+ auto destroyValues = lr.getDestroys ();
853
887
if (isWrittenTo (li, destroyValues))
854
888
return false ;
855
889
@@ -878,7 +912,8 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
878
912
879
913
// Then delete all of our destroy_value.
880
914
while (!destroyValues.empty ()) {
881
- auto *dvi = destroyValues.pop_back_val ();
915
+ auto *dvi = destroyValues.back ();
916
+ destroyValues = destroyValues.drop_back ();
882
917
eraseInstruction (dvi);
883
918
++NumEliminatedInsts;
884
919
}
@@ -888,7 +923,8 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
888
923
889
924
// And then change the ownership all of our owned forwarding users to be
890
925
// guaranteed.
891
- convertForwardingInstsFromOwnedToGuaranteed (guaranteedForwardingInsts);
926
+ convertForwardingInstsFromOwnedToGuaranteed (
927
+ lr.getNonConsumingForwardingInsts ());
892
928
893
929
++NumEliminatedInsts;
894
930
++NumLoadCopyConvertedToLoadBorrow;
0 commit comments