12
12
13
13
#define DEBUG_TYPE " predictable-memopt"
14
14
15
- #include " swift/SILOptimizer/PassManager/Passes.h"
16
15
#include " DIMemoryUseCollector.h"
17
16
#include " swift/SIL/SILBuilder.h"
18
- #include " swift/SILOptimizer/Utils/Local .h"
17
+ #include " swift/SILOptimizer/PassManager/Passes .h"
19
18
#include " swift/SILOptimizer/PassManager/Transforms.h"
19
+ #include " swift/SILOptimizer/Utils/Local.h"
20
+ #include " swift/SILOptimizer/Utils/SILSSAUpdater.h"
20
21
#include " llvm/ADT/SmallBitVector.h"
21
22
#include " llvm/ADT/Statistic.h"
22
23
#include " llvm/Support/Compiler.h"
@@ -91,14 +92,14 @@ static SILValue getAccessPathRoot(SILValue Pointer) {
91
92
// / If this pointer is to within an existential projection, it returns ~0U.
92
93
static unsigned computeSubelement (SILValue Pointer,
93
94
SingleValueInstruction *RootInst) {
94
- unsigned SubEltNumber = 0 ;
95
+ unsigned SubElementNumber = 0 ;
95
96
SILModule &M = RootInst->getModule ();
96
97
97
98
while (1 ) {
98
99
// If we got to the root, we're done.
99
100
if (RootInst == Pointer)
100
- return SubEltNumber ;
101
-
101
+ return SubElementNumber ;
102
+
102
103
if (auto *PBI = dyn_cast<ProjectBoxInst>(Pointer)) {
103
104
Pointer = PBI->getOperand ();
104
105
continue ;
@@ -114,7 +115,7 @@ static unsigned computeSubelement(SILValue Pointer,
114
115
115
116
// Keep track of what subelement is being referenced.
116
117
for (unsigned i = 0 , e = TEAI->getFieldNo (); i != e; ++i) {
117
- SubEltNumber += getNumSubElements (TT.getTupleElementType (i), M);
118
+ SubElementNumber += getNumSubElements (TT.getTupleElementType (i), M);
118
119
}
119
120
Pointer = TEAI->getOperand ();
120
121
continue ;
@@ -127,7 +128,7 @@ static unsigned computeSubelement(SILValue Pointer,
127
128
StructDecl *SD = SEAI->getStructDecl ();
128
129
for (auto *D : SD->getStoredProperties ()) {
129
130
if (D == SEAI->getField ()) break ;
130
- SubEltNumber += getNumSubElements (ST.getFieldType (D, M), M);
131
+ SubElementNumber += getNumSubElements (ST.getFieldType (D, M), M);
131
132
}
132
133
133
134
Pointer = SEAI->getOperand ();
@@ -149,14 +150,26 @@ static unsigned computeSubelement(SILValue Pointer,
149
150
namespace {
150
151
151
152
struct AvailableValue {
153
+ // / If this gets too expensive in terms of copying, we can use an arena and a
154
+ // / FrozenPtrSet like we do in ARC.
155
+ using SetVector = llvm::SmallSetVector<SILInstruction *, 1 >;
156
+
152
157
SILValue Value;
153
158
unsigned SubElementNumber;
159
+ SetVector InsertionPoints;
154
160
155
161
public:
156
162
AvailableValue () = default ;
157
163
158
- AvailableValue (SILValue Value, unsigned SubElementNumber)
159
- : Value(Value), SubElementNumber(SubElementNumber) {}
164
+ // / Main initializer for available values.
165
+ // /
166
+ // / *NOTE* We assume that all available values start with a singular insertion
167
+ // / point and insertion points are added by merging.
168
+ AvailableValue (SILValue Value, unsigned SubElementNumber,
169
+ SILInstruction *InsertPoint)
170
+ : Value(Value), SubElementNumber(SubElementNumber), InsertionPoints() {
171
+ InsertionPoints.insert (InsertPoint);
172
+ }
160
173
161
174
// / Deleted copy constructor. This is a move only type.
162
175
AvailableValue (const AvailableValue &) = delete ;
@@ -166,15 +179,17 @@ struct AvailableValue {
166
179
167
180
// / Move constructor.
168
181
AvailableValue (AvailableValue &&Other)
169
- : Value(nullptr ), SubElementNumber(~0 ) {
182
+ : Value(nullptr ), SubElementNumber(~0 ), InsertionPoints() {
170
183
std::swap (Value, Other.Value );
171
184
std::swap (SubElementNumber, Other.SubElementNumber );
185
+ std::swap (InsertionPoints, Other.InsertionPoints );
172
186
}
173
187
174
188
// / Move operator.
175
189
AvailableValue &operator =(AvailableValue &&Other) {
176
190
std::swap (Value, Other.Value );
177
191
std::swap (SubElementNumber, Other.SubElementNumber );
192
+ std::swap (InsertionPoints, Other.InsertionPoints );
178
193
return *this ;
179
194
}
180
195
@@ -191,24 +206,70 @@ struct AvailableValue {
191
206
SILValue getValue () const { return Value; }
192
207
SILType getType () const { return Value->getType (); }
193
208
unsigned getSubElementNumber () const { return SubElementNumber; }
209
+ ArrayRef<SILInstruction *> getInsertionPoints () const {
210
+ return InsertionPoints.getArrayRef ();
211
+ }
212
+
213
+ void mergeInsertionPoints (const AvailableValue &Other) & {
214
+ assert (Value == Other.Value && SubElementNumber == Other.SubElementNumber );
215
+ InsertionPoints.set_union (Other.InsertionPoints );
216
+ }
217
+
218
+ void addInsertionPoint (SILInstruction *I) & { InsertionPoints.insert (I); }
194
219
195
220
// / TODO: This needs a better name.
196
221
AvailableValue emitStructExtract (SILBuilder &B, SILLocation Loc, VarDecl *D,
197
- unsigned SubEltNumber ) const {
222
+ unsigned SubElementNumber ) const {
198
223
SILValue NewValue = B.emitStructExtract (Loc, Value, D);
199
- return {NewValue, SubEltNumber };
224
+ return {NewValue, SubElementNumber, InsertionPoints };
200
225
}
201
226
202
227
// / TODO: This needs a better name.
203
228
AvailableValue emitTupleExtract (SILBuilder &B, SILLocation Loc,
204
- unsigned EltNo, unsigned SubEltNumber) const {
229
+ unsigned EltNo,
230
+ unsigned SubElementNumber) const {
205
231
SILValue NewValue = B.emitTupleExtract (Loc, Value, EltNo);
206
- return {NewValue, SubEltNumber };
232
+ return {NewValue, SubElementNumber, InsertionPoints };
207
233
}
234
+
235
+ void dump () const __attribute__((used));
236
+ void print (llvm::raw_ostream &os) const ;
237
+
238
+ private:
239
+ // / Private constructor for use by emitStructExtract and emitTupleExtract.
240
+ AvailableValue (SILValue Value, unsigned SubElementNumber,
241
+ const SetVector &InsertPoints)
242
+ : Value(Value), SubElementNumber(SubElementNumber),
243
+ InsertionPoints (InsertPoints) {}
208
244
};
209
245
210
246
} // end anonymous namespace
211
247
248
+ void AvailableValue::dump () const { print (llvm::dbgs ()); }
249
+
250
+ void AvailableValue::print (llvm::raw_ostream &os) const {
251
+ os << " Available Value Dump. Value: " ;
252
+ if (getValue ()) {
253
+ os << getValue ();
254
+ } else {
255
+ os << " NoValue;\n " ;
256
+ }
257
+ os << " SubElementNumber: " << getSubElementNumber () << " \n " ;
258
+ os << " Insertion Points:\n " ;
259
+ for (auto *I : getInsertionPoints ()) {
260
+ os << *I;
261
+ }
262
+ }
263
+
264
+ namespace llvm {
265
+
266
+ llvm::raw_ostream &operator <<(llvm::raw_ostream &os, const AvailableValue &V) {
267
+ V.print (os);
268
+ return os;
269
+ }
270
+
271
+ } // end llvm namespace
272
+
212
273
// ===----------------------------------------------------------------------===//
213
274
// Subelement Extraction
214
275
// ===----------------------------------------------------------------------===//
@@ -301,7 +362,7 @@ class AvailableValueAggregator {
301
362
SILValue aggregateValues (SILType LoadTy, SILValue Address, unsigned FirstElt);
302
363
303
364
void print (llvm::raw_ostream &os) const ;
304
- void dump () const ;
365
+ void dump () const __attribute__((used)) ;
305
366
306
367
private:
307
368
SILValue aggregateFullyAvailableValue (SILType LoadTy, unsigned FirstElt);
@@ -321,8 +382,7 @@ void AvailableValueAggregator::print(llvm::raw_ostream &os) const {
321
382
os << " Available Value List, N = " << AvailableValueList.size ()
322
383
<< " . Elts:\n " ;
323
384
for (auto &V : AvailableValueList) {
324
- os << " Value: " << V.getValue ()
325
- << " SubElementNumber: " << V.getSubElementNumber () << " \n " ;
385
+ os << V;
326
386
}
327
387
}
328
388
@@ -440,14 +500,30 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType LoadTy,
440
500
return B.createLoad (Loc, Address, LoadOwnershipQualifier::Unqualified);
441
501
}
442
502
443
- // If we have an available value, we know that we know that the available
444
- // value is already being consumed by the store. This means that we must
445
- // insert a copy of EltVal after we extract it if we do not have a trivial
446
- // value. We use SILBuilder::emit*Operation to handle both trivial/non-trivial
447
- // cases without needing to introduce control flow here.
503
+ // If we have 1 insertion point, just extract the value and return.
504
+ //
505
+ // This saves us from having to spend compile time in the SSA updater in this
506
+ // case.
507
+ ArrayRef<SILInstruction *> InsertPts = Val.getInsertionPoints ();
508
+ if (InsertPts.size () == 1 ) {
509
+ SavedInsertionPointRAII SavedInsertPt (B, InsertPts[0 ]);
510
+ SILValue EltVal = nonDestructivelyExtractSubElement (Val, B, Loc);
511
+ assert (EltVal->getType () == LoadTy && " Subelement types mismatch" );
512
+ return EltVal;
513
+ }
514
+
515
+ // If we have an available value, then we want to extract the subelement from
516
+ // the borrowed aggregate before each insertion point.
517
+ SILSSAUpdater Updater;
518
+ Updater.Initialize (LoadTy);
519
+ for (auto *I : Val.getInsertionPoints ()) {
520
+ SavedInsertionPointRAII SavedInsertPt (B, I);
521
+ SILValue EltVal = nonDestructivelyExtractSubElement (Val, B, Loc);
522
+ Updater.AddAvailableValue (I->getParent (), EltVal);
523
+ }
448
524
449
- // Then extract the subelement from the borrowed aggregate .
450
- SILValue EltVal = nonDestructivelyExtractSubElement (Val, B, Loc );
525
+ // Finally, grab the value from the SSA updater .
526
+ SILValue EltVal = Updater. GetValueInMiddleOfBlock (B. getInsertionBB () );
451
527
assert (EltVal->getType () == LoadTy && " Subelement types mismatch" );
452
528
return EltVal;
453
529
}
@@ -587,6 +663,7 @@ void AllocOptimize::updateAvailableValues(
587
663
SILInstruction *Inst, llvm::SmallBitVector &RequiredElts,
588
664
SmallVectorImpl<AvailableValue> &Result,
589
665
llvm::SmallBitVector &ConflictingValues) {
666
+
590
667
// Handle store and assign.
591
668
if (auto *SI = dyn_cast<StoreInst>(Inst)) {
592
669
unsigned StartSubElt = computeSubelement (SI->getDest (), TheMemory);
@@ -601,12 +678,19 @@ void AllocOptimize::updateAvailableValues(
601
678
// there already is a result, check it for conflict. If there is no
602
679
// conflict, then we're ok.
603
680
auto &Entry = Result[StartSubElt+i];
604
- if (!Entry)
605
- Entry = {SI->getSrc (), i};
606
- else if (Entry.getValue () != SI->getSrc () ||
607
- Entry.getSubElementNumber () != i)
608
- ConflictingValues[StartSubElt+i] = true ;
609
-
681
+ if (!Entry) {
682
+ Entry = {SI->getSrc (), i, Inst};
683
+ } else {
684
+ // TODO: This is /really/, /really/, conservative. This basically means
685
+ // that if we do not have an identical store, we will not promote.
686
+ if (Entry.getValue () != SI->getSrc () ||
687
+ Entry.getSubElementNumber () != i) {
688
+ ConflictingValues[StartSubElt + i] = true ;
689
+ } else {
690
+ Entry.addInsertionPoint (Inst);
691
+ }
692
+ }
693
+
610
694
// This element is now provided.
611
695
RequiredElts[StartSubElt+i] = false ;
612
696
}
@@ -682,8 +766,8 @@ void AllocOptimize::computeAvailableValues(
682
766
if (!ConflictingValues.none ())
683
767
for (unsigned i = 0 , e = Result.size (); i != e; ++i)
684
768
if (ConflictingValues[i])
685
- Result[i] = { SILValue (), 0U };
686
-
769
+ Result[i] = {};
770
+
687
771
return ;
688
772
}
689
773
0 commit comments