Skip to content

Commit 49f5c76

Browse files
committed
[pred-memopt] Change AvailableValue to be its own struct instead of a typealias to std::pair.
For pred-memopt to work with ownership, we need to insert instructions in two different places: 1. When loading not-available values, we must insert the load at the site of the load we are trying to promote. 2. When propagating an available value, we must destructure and or copy before each one of the stores that provide our value. By changing AvailableValue to be a struct, I am providing a cleaner API, but more importantly the ability to start tracking that information. rdar://31521023
1 parent 798bff7 commit 49f5c76

File tree

1 file changed

+118
-46
lines changed

1 file changed

+118
-46
lines changed

lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp

Lines changed: 118 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -142,27 +142,94 @@ static unsigned computeSubelement(SILValue Pointer,
142142
}
143143
}
144144

145+
//===----------------------------------------------------------------------===//
146+
// Available Value
147+
//===----------------------------------------------------------------------===//
148+
149+
namespace {
150+
151+
struct AvailableValue {
152+
SILValue Value;
153+
unsigned SubElementNumber;
154+
155+
public:
156+
AvailableValue() = default;
157+
158+
AvailableValue(SILValue Value, unsigned SubElementNumber)
159+
: Value(Value), SubElementNumber(SubElementNumber) {}
160+
161+
/// Deleted copy constructor. This is a move only type.
162+
AvailableValue(const AvailableValue &) = delete;
163+
164+
/// Deleted copy operator. This is a move only type.
165+
AvailableValue &operator=(const AvailableValue &) = delete;
166+
167+
/// Move constructor.
168+
AvailableValue(AvailableValue &&Other)
169+
: Value(nullptr), SubElementNumber(~0) {
170+
std::swap(Value, Other.Value);
171+
std::swap(SubElementNumber, Other.SubElementNumber);
172+
}
173+
174+
/// Move operator.
175+
AvailableValue &operator=(AvailableValue &&Other) {
176+
std::swap(Value, Other.Value);
177+
std::swap(SubElementNumber, Other.SubElementNumber);
178+
return *this;
179+
}
180+
181+
operator bool() const { return bool(Value); }
182+
183+
bool operator==(const AvailableValue &Other) const {
184+
return Value == Other.Value && SubElementNumber == Other.SubElementNumber;
185+
}
186+
187+
bool operator!=(const AvailableValue &Other) const {
188+
return !(*this == Other);
189+
}
190+
191+
SILValue getValue() const { return Value; }
192+
SILType getType() const { return Value->getType(); }
193+
unsigned getSubElementNumber() const { return SubElementNumber; }
194+
195+
/// TODO: This needs a better name.
196+
AvailableValue emitStructExtract(SILBuilder &B, SILLocation Loc, VarDecl *D,
197+
unsigned SubEltNumber) const {
198+
SILValue NewValue = B.emitStructExtract(Loc, Value, D);
199+
return {NewValue, SubEltNumber};
200+
}
201+
202+
/// TODO: This needs a better name.
203+
AvailableValue emitTupleExtract(SILBuilder &B, SILLocation Loc,
204+
unsigned EltNo, unsigned SubEltNumber) const {
205+
SILValue NewValue = B.emitTupleExtract(Loc, Value, EltNo);
206+
return {NewValue, SubEltNumber};
207+
}
208+
};
209+
210+
} // end anonymous namespace
211+
145212
//===----------------------------------------------------------------------===//
146213
// Subelement Extraction
147214
//===----------------------------------------------------------------------===//
148215

149216
/// Given an aggregate value and an access path, non-destructively extract the
150217
/// value indicated by the path.
151-
static SILValue nonDestructivelyExtractSubElement(SILValue Val,
152-
unsigned SubElementNumber,
218+
static SILValue nonDestructivelyExtractSubElement(const AvailableValue &Val,
153219
SILBuilder &B,
154220
SILLocation Loc) {
155-
SILType ValTy = Val->getType();
156-
221+
SILType ValTy = Val.getType();
222+
unsigned SubElementNumber = Val.SubElementNumber;
223+
157224
// Extract tuple elements.
158225
if (auto TT = ValTy.getAs<TupleType>()) {
159226
for (unsigned EltNo : indices(TT.getElementTypes())) {
160227
// Keep track of what subelement is being referenced.
161228
SILType EltTy = ValTy.getTupleElementType(EltNo);
162229
unsigned NumSubElt = getNumSubElements(EltTy, B.getModule());
163230
if (SubElementNumber < NumSubElt) {
164-
Val = B.emitTupleExtract(Loc, Val, EltNo, EltTy);
165-
return nonDestructivelyExtractSubElement(Val, SubElementNumber, B, Loc);
231+
auto NewVal = Val.emitTupleExtract(B, Loc, EltNo, SubElementNumber);
232+
return nonDestructivelyExtractSubElement(NewVal, B, Loc);
166233
}
167234

168235
SubElementNumber -= NumSubElt;
@@ -178,8 +245,8 @@ static SILValue nonDestructivelyExtractSubElement(SILValue Val,
178245
unsigned NumSubElt = getNumSubElements(fieldType, B.getModule());
179246

180247
if (SubElementNumber < NumSubElt) {
181-
Val = B.emitStructExtract(Loc, Val, D);
182-
return nonDestructivelyExtractSubElement(Val, SubElementNumber, B, Loc);
248+
auto NewVal = Val.emitStructExtract(B, Loc, D, SubElementNumber);
249+
return nonDestructivelyExtractSubElement(NewVal, B, Loc);
183250
}
184251

185252
SubElementNumber -= NumSubElt;
@@ -190,24 +257,17 @@ static SILValue nonDestructivelyExtractSubElement(SILValue Val,
190257

191258
// Otherwise, we're down to a scalar.
192259
assert(SubElementNumber == 0 && "Miscalculation indexing subelements");
193-
return Val;
260+
return Val.getValue();
194261
}
195262

196263
//===----------------------------------------------------------------------===//
197264
// Available Value Aggregation
198265
//===----------------------------------------------------------------------===//
199266

200-
namespace {
201-
202-
/// Our available value representation. Will become a struct later.
203-
using AvailableValue = std::pair<SILValue, unsigned>;
204-
205-
} // end anonymous namespace
206-
207267
static bool anyMissing(unsigned StartSubElt, unsigned NumSubElts,
208268
ArrayRef<AvailableValue> &Values) {
209269
while (NumSubElts) {
210-
if (!Values[StartSubElt].first)
270+
if (!Values[StartSubElt])
211271
return true;
212272
++StartSubElt;
213273
--NumSubElts;
@@ -240,6 +300,9 @@ class AvailableValueAggregator {
240300

241301
SILValue aggregateValues(SILType LoadTy, SILValue Address, unsigned FirstElt);
242302

303+
void print(llvm::raw_ostream &os) const;
304+
void dump() const;
305+
243306
private:
244307
SILValue aggregateFullyAvailableValue(SILType LoadTy, unsigned FirstElt);
245308
SILValue aggregateTupleSubElts(TupleType *TT, SILType LoadTy,
@@ -252,6 +315,17 @@ class AvailableValueAggregator {
252315

253316
} // end anonymous namespace
254317

318+
void AvailableValueAggregator::dump() const { print(llvm::dbgs()); }
319+
320+
void AvailableValueAggregator::print(llvm::raw_ostream &os) const {
321+
os << "Available Value List, N = " << AvailableValueList.size()
322+
<< ". Elts:\n";
323+
for (auto &V : AvailableValueList) {
324+
os << "Value: " << V.getValue()
325+
<< "SubElementNumber: " << V.getSubElementNumber() << "\n";
326+
}
327+
}
328+
255329
/// Given a bunch of primitive subelement values, build out the right aggregate
256330
/// type (LoadTy) by emitting tuple and struct instructions as necessary.
257331
SILValue AvailableValueAggregator::aggregateValues(SILType LoadTy,
@@ -287,23 +361,23 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType LoadTy,
287361
return SILValue();
288362
}
289363

290-
SILValue FirstVal = AvailableValueList[FirstElt].first;
291-
// Make sure that the first element is available.
292-
if (!FirstVal || AvailableValueList[FirstElt].second != 0 ||
293-
FirstVal->getType() != LoadTy) {
364+
auto &FirstVal = AvailableValueList[FirstElt];
365+
366+
// Make sure that the first element is available and is the correct type.
367+
if (!FirstVal || FirstVal.getType() != LoadTy)
294368
return SILValue();
295-
}
296369

297370
// If the first element of this value is available, check that any extra
298-
// available values match our first value.
299-
if (llvm::any_of(
300-
range(getNumSubElements(LoadTy, M)), [&](unsigned Index) -> bool {
301-
return AvailableValueList[FirstElt + Index].first != FirstVal ||
302-
AvailableValueList[FirstElt + Index].second != Index;
303-
}))
371+
// available values are from the same place as our first value.
372+
if (llvm::any_of(range(getNumSubElements(LoadTy, M)),
373+
[&](unsigned Index) -> bool {
374+
auto &Val = AvailableValueList[FirstElt + Index];
375+
return Val.getValue() != FirstVal.getValue() ||
376+
Val.getSubElementNumber() != Index;
377+
}))
304378
return SILValue();
305379

306-
return FirstVal;
380+
return FirstVal.getValue();
307381
}
308382

309383
SILValue AvailableValueAggregator::aggregateTupleSubElts(TupleType *TT,
@@ -362,7 +436,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType LoadTy,
362436
auto &Val = AvailableValueList[FirstElt];
363437

364438
// If the value is not available, load the value.
365-
if (!Val.first) {
439+
if (!Val) {
366440
return B.createLoad(Loc, Address, LoadOwnershipQualifier::Unqualified);
367441
}
368442

@@ -371,12 +445,9 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType LoadTy,
371445
// insert a copy of EltVal after we extract it if we do not have a trivial
372446
// value. We use SILBuilder::emit*Operation to handle both trivial/non-trivial
373447
// cases without needing to introduce control flow here.
374-
SILValue Aggregate = Val.first;
375-
unsigned AggregateSubElementNumber = Val.second;
376448

377449
// Then extract the subelement from the borrowed aggregate.
378-
SILValue EltVal = nonDestructivelyExtractSubElement(
379-
Aggregate, AggregateSubElementNumber, B, Loc);
450+
SILValue EltVal = nonDestructivelyExtractSubElement(Val, B, Loc);
380451
assert(EltVal->getType() == LoadTy && "Subelement types mismatch");
381452
return EltVal;
382453
}
@@ -517,11 +588,11 @@ void AllocOptimize::updateAvailableValues(
517588
SmallVectorImpl<AvailableValue> &Result,
518589
llvm::SmallBitVector &ConflictingValues) {
519590
// Handle store and assign.
520-
if (isa<StoreInst>(Inst)) {
521-
unsigned StartSubElt = computeSubelement(Inst->getOperand(1), TheMemory);
591+
if (auto *SI = dyn_cast<StoreInst>(Inst)) {
592+
unsigned StartSubElt = computeSubelement(SI->getDest(), TheMemory);
522593
assert(StartSubElt != ~0U && "Store within enum projection not handled");
523-
SILType ValTy = Inst->getOperand(0)->getType();
524-
594+
SILType ValTy = SI->getSrc()->getType();
595+
525596
for (unsigned i = 0, e = getNumSubElements(ValTy, Module); i != e; ++i) {
526597
// If this element is not required, don't fill it in.
527598
if (!RequiredElts[StartSubElt+i]) continue;
@@ -530,9 +601,10 @@ void AllocOptimize::updateAvailableValues(
530601
// there already is a result, check it for conflict. If there is no
531602
// conflict, then we're ok.
532603
auto &Entry = Result[StartSubElt+i];
533-
if (Entry.first == SILValue())
534-
Entry = { Inst->getOperand(0), i };
535-
else if (Entry.first != Inst->getOperand(0) || Entry.second != i)
604+
if (!Entry)
605+
Entry = {SI->getSrc(), i};
606+
else if (Entry.getValue() != SI->getSrc() ||
607+
Entry.getSubElementNumber() != i)
536608
ConflictingValues[StartSubElt+i] = true;
537609

538610
// This element is now provided.
@@ -760,7 +832,7 @@ bool AllocOptimize::promoteLoad(SILInstruction *Inst) {
760832
// promote this load and there is nothing to do.
761833
bool AnyAvailable = false;
762834
for (unsigned i = FirstElt, e = i+NumLoadSubElements; i != e; ++i)
763-
if (AvailableValues[i].first) {
835+
if (AvailableValues[i].getValue()) {
764836
AnyAvailable = true;
765837
break;
766838
}
@@ -838,11 +910,11 @@ bool AllocOptimize::promoteDestroyAddr(DestroyAddrInst *DAI) {
838910
// trivially succeed. This can happen when there is a load of an empty struct.
839911
if (NumLoadSubElements != 0) {
840912
computeAvailableValues(DAI, RequiredElts, AvailableValues);
841-
913+
842914
// If some value is not available at this load point, then we fail.
843-
for (unsigned i = FirstElt, e = FirstElt+NumLoadSubElements; i != e; ++i)
844-
if (!AvailableValues[i].first)
845-
return false;
915+
if (llvm::any_of(range(FirstElt, FirstElt + NumLoadSubElements),
916+
[&](unsigned i) -> bool { return !AvailableValues[i]; }))
917+
return false;
846918
}
847919

848920
// Aggregate together all of the subelements into something that has the same

0 commit comments

Comments
 (0)