Skip to content

Commit 9659472

Browse files
committed
[AddressLowering] Sink projections to uses.
Visit the tree of projections in post-order, sinking each to the lowest position in the least common ancestor of all uses.
1 parent 8021c87 commit 9659472

File tree

5 files changed

+175
-67
lines changed

5 files changed

+175
-67
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,12 @@ struct AddressLoweringState {
522522
// Handle moves from a phi's operand storage to the phi storage.
523523
std::unique_ptr<PhiRewriter> phiRewriter;
524524

525+
// Projections created for uses, recorded in order to be sunk.
526+
//
527+
// Not all use projections are recorded in the valueStorageMap. It's not
528+
// legal to reuse use projections for non-canonical users or for phis.
529+
SmallVector<SILValue, 16> useProjections;
530+
525531
AddressLoweringState(SILFunction *function, DominanceInfo *domInfo,
526532
DeadEndBlocks *deBlocks)
527533
: function(function), loweredFnConv(getLoweredFnConv(function)),
@@ -1147,6 +1153,8 @@ class OpaqueStorageAllocation {
11471153
/// jointly postdominate.
11481154
void finalizeOpaqueStorage();
11491155

1156+
void sinkProjections();
1157+
11501158
protected:
11511159
void allocateValue(SILValue value);
11521160
bool findProjectionIntoUseImpl(SILValue value,
@@ -1501,6 +1509,54 @@ AllocStackInst *OpaqueStorageAllocation::createStackAllocation(SILValue value) {
15011509
return alloc;
15021510
}
15031511

1512+
namespace {
1513+
enum class SinkResult {
1514+
NoUsers,
1515+
Unmoved,
1516+
Moved,
1517+
};
1518+
SinkResult sinkToUses(SingleValueInstruction *svi, DominanceInfo *domInfo) {
1519+
// Fast paths for 0 and 1 users.
1520+
1521+
if (svi->use_begin() == svi->use_end()) {
1522+
return SinkResult::NoUsers;
1523+
}
1524+
1525+
if (auto *use = svi->getSingleUse()) {
1526+
auto *user = use->getUser();
1527+
if (user == svi->getNextInstruction())
1528+
return SinkResult::Unmoved;
1529+
svi->moveBefore(user);
1530+
return SinkResult::Moved;
1531+
}
1532+
1533+
// Compute the lca and sink the instruction to before its first user or its
1534+
// end if there are none.
1535+
1536+
SILBasicBlock *lca = domInfo->getLeastCommonAncestorOfUses(svi);
1537+
1538+
// The lca may contain a user. Look for the user to insert before it.
1539+
1540+
InstructionSet userSet(svi->getFunction());
1541+
for (auto user : svi->getUsers()) {
1542+
userSet.insert(user);
1543+
}
1544+
1545+
for (auto &instruction : *lca) {
1546+
if (userSet.contains(&instruction)) {
1547+
if (&instruction == svi->getNextInstruction())
1548+
return SinkResult::Unmoved;
1549+
svi->moveBefore(&instruction);
1550+
return SinkResult::Moved;
1551+
}
1552+
}
1553+
1554+
// No user was found in the lca, move to before the end.
1555+
svi->moveBefore(&lca->back());
1556+
return SinkResult::Moved;
1557+
}
1558+
} // end anonymous namespace
1559+
15041560
void OpaqueStorageAllocation::finalizeOpaqueStorage() {
15051561
SmallVector<SILBasicBlock *, 4> boundary;
15061562
for (auto maybeAlloc : allocs) {
@@ -1531,6 +1587,40 @@ void OpaqueStorageAllocation::finalizeOpaqueStorage() {
15311587
}
15321588
}
15331589

1590+
void OpaqueStorageAllocation::sinkProjections() {
1591+
// First, sink use projections to their uses. It's necessary to do this
1592+
// separately from sinking projections in valueStorageMap because not all use
1593+
// projections are recorded there (those for non-canonical users and those for
1594+
// phis).
1595+
//
1596+
// Done in reverse order because outer projections are materialized first and
1597+
// so appear in `useProjections` before inner projections, and inner
1598+
// projections must be sunk first.
1599+
for (auto projection : llvm::reverse(pass.useProjections)) {
1600+
assert(projection);
1601+
auto *svi = dyn_cast<SingleValueInstruction>(projection);
1602+
assert(svi);
1603+
auto sank = sinkToUses(svi, pass.domInfo);
1604+
if (sank == SinkResult::NoUsers) {
1605+
pass.deleter.forceDelete(svi);
1606+
}
1607+
}
1608+
1609+
// Second, sink all storage from the valueStorageMap.
1610+
for (auto pair : llvm::reverse(pass.valueStorageMap)) {
1611+
auto addr = pair.storage.getMaterializedAddress();
1612+
if (!pair.storage.isProjection())
1613+
continue;
1614+
auto *inst = dyn_cast<SingleValueInstruction>(addr);
1615+
if (!inst)
1616+
continue;
1617+
auto sank = sinkToUses(inst, pass.domInfo);
1618+
if (sank == SinkResult::NoUsers) {
1619+
pass.deleter.forceDelete(inst);
1620+
}
1621+
}
1622+
}
1623+
15341624
//===----------------------------------------------------------------------===//
15351625
// AddressMaterialization
15361626
//
@@ -1590,6 +1680,8 @@ class AddressMaterialization {
15901680
SILValue elementValue, unsigned fieldIdx);
15911681

15921682
SILValue materializeProjectionIntoUse(Operand *operand, bool intoPhiOperand);
1683+
SILValue materializeProjectionIntoUseImpl(Operand *operand,
1684+
bool intoPhiOperand);
15931685

15941686
SILValue materializeComposingUser(SingleValueInstruction *user,
15951687
bool intoPhiOperand) {
@@ -1767,12 +1859,20 @@ SILValue AddressMaterialization::materializeTupleExtract(
17671859
elementValue->getType().getAddressType());
17681860
}
17691861

1862+
SILValue
1863+
AddressMaterialization::materializeProjectionIntoUse(Operand *operand,
1864+
bool intoPhiOperand) {
1865+
auto projection = materializeProjectionIntoUseImpl(operand, intoPhiOperand);
1866+
pass.useProjections.push_back(projection);
1867+
return projection;
1868+
}
1869+
17701870
/// Recursively materialize the address of a subobject that is a member of the
17711871
/// operand's user. The operand's user must be an aggregate struct, tuple, enum,
17721872
/// init_existential_value.
17731873
SILValue
1774-
AddressMaterialization::materializeProjectionIntoUse(Operand *operand,
1775-
bool intoPhiOperand) {
1874+
AddressMaterialization::materializeProjectionIntoUseImpl(Operand *operand,
1875+
bool intoPhiOperand) {
17761876
SILInstruction *user = operand->getUser();
17771877
switch (user->getKind()) {
17781878
default:
@@ -4179,6 +4279,8 @@ void AddressLowering::runOnFunction(SILFunction *function) {
41794279

41804280
allocator.finalizeOpaqueStorage();
41814281

4282+
allocator.sinkProjections();
4283+
41824284
deleteRewrittenInstructions(pass);
41834285

41844286
StackNesting::fixNesting(function);

lib/SILOptimizer/Mandatory/AddressLowering.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,12 @@ class ValueStorageMap {
270270
return hashIter->second;
271271
}
272272

273+
ValueStoragePair &operator[](uint32_t index) { return valueVector[index]; }
274+
275+
ValueStoragePair const &operator[](uint32_t index) const {
276+
return valueVector[index];
277+
}
278+
273279
ValueStorage &getStorage(SILValue value) {
274280
return valueVector[getOrdinal(value)].storage;
275281
}

0 commit comments

Comments
 (0)