Skip to content

Commit 08db6f6

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 9c706ef commit 08db6f6

File tree

5 files changed

+214
-69
lines changed

5 files changed

+214
-69
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
#include "PhiStorageOptimizer.h"
138138
#include "swift/AST/Decl.h"
139139
#include "swift/Basic/BlotSetVector.h"
140+
#include "swift/Basic/FrozenMultiMap.h"
140141
#include "swift/Basic/Range.h"
141142
#include "swift/SIL/BasicBlockUtils.h"
142143
#include "swift/SIL/DebugUtils.h"
@@ -522,6 +523,9 @@ struct AddressLoweringState {
522523
// Handle moves from a phi's operand storage to the phi storage.
523524
std::unique_ptr<PhiRewriter> phiRewriter;
524525

526+
// Projections created for uses, recorded in order to be sunk.
527+
SmallVector<SILValue, 16> useProjections;
528+
525529
AddressLoweringState(SILFunction *function, DominanceInfo *domInfo,
526530
DeadEndBlocks *deBlocks)
527531
: function(function), loweredFnConv(getLoweredFnConv(function)),
@@ -1147,6 +1151,8 @@ class OpaqueStorageAllocation {
11471151
/// jointly postdominate.
11481152
void finalizeOpaqueStorage();
11491153

1154+
void sinkProjections();
1155+
11501156
protected:
11511157
void allocateValue(SILValue value);
11521158
bool findProjectionIntoUseImpl(SILValue value,
@@ -1501,6 +1507,54 @@ AllocStackInst *OpaqueStorageAllocation::createStackAllocation(SILValue value) {
15011507
return alloc;
15021508
}
15031509

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

1588+
void OpaqueStorageAllocation::sinkProjections() {
1589+
// First, sink use projections to their uses.
1590+
//
1591+
// Done in reverse order because outer projections are materialized first and
1592+
// so appear in `useProjections` before inner projections, and inner
1593+
// projections must be sunk first.
1594+
for (auto projection : llvm::reverse(pass.useProjections)) {
1595+
assert(projection);
1596+
auto *svi = dyn_cast<SingleValueInstruction>(projection);
1597+
assert(svi);
1598+
auto sank = sinkToUses(svi, pass.domInfo);
1599+
if (sank == SinkResult::NoUsers) {
1600+
pass.deleter.forceDelete(svi);
1601+
}
1602+
}
1603+
1604+
// Second, sink all storage from the valueStorageMap.
1605+
//
1606+
// Calculate the (multi-rooted) tree of projections represented by their
1607+
// indices in `valueStorageMap` (a). Then visit the projections in
1608+
// post-order (b), in order to visit all inner projections before visiting
1609+
// outer projections.
1610+
1611+
// (a) Assemble the tree.
1612+
SmallFrozenMultiMap<uint32_t, uint32_t, 32> projections;
1613+
SmallVector<uint32_t, 16> roots;
1614+
uint32_t index = 0;
1615+
for (auto &valueAndStorage : pass.valueStorageMap) {
1616+
auto &storage = valueAndStorage.storage;
1617+
if (storage.isProjection()) {
1618+
projections.insert(storage.projectedStorageID, index);
1619+
} else {
1620+
roots.push_back(index);
1621+
}
1622+
++index;
1623+
}
1624+
projections.setFrozen();
1625+
1626+
auto sinkProjectionAtIndex = [&](uint32_t index) {
1627+
auto pair = pass.valueStorageMap[index];
1628+
auto addr = pair.storage.getMaterializedAddress();
1629+
if (!pair.storage.isProjection())
1630+
return;
1631+
auto *inst = dyn_cast<SingleValueInstruction>(addr);
1632+
if (!inst)
1633+
return;
1634+
auto sank = sinkToUses(inst, pass.domInfo);
1635+
if (sank == SinkResult::NoUsers) {
1636+
pass.deleter.forceDelete(inst);
1637+
}
1638+
};
1639+
1640+
// (b) Visit the projections in post-order.
1641+
for (auto root : roots) {
1642+
SmallVector<std::pair<uint32_t, size_t>, 32> stack;
1643+
stack.push_back({root, 0});
1644+
while (!stack.empty()) {
1645+
while (stack.back().second <
1646+
projections.find(stack.back().first)
1647+
.transform([](auto &i) { return i.size(); })
1648+
.value_or(0)) {
1649+
auto child =
1650+
projections.find(stack.back().first).value()[stack.back().second];
1651+
stack.back().second++;
1652+
stack.push_back({child, 0});
1653+
}
1654+
auto index = stack.back().first;
1655+
sinkProjectionAtIndex(index);
1656+
stack.pop_back();
1657+
}
1658+
}
1659+
}
1660+
15341661
//===----------------------------------------------------------------------===//
15351662
// AddressMaterialization
15361663
//
@@ -1590,6 +1717,8 @@ class AddressMaterialization {
15901717
SILValue elementValue, unsigned fieldIdx);
15911718

15921719
SILValue materializeProjectionIntoUse(Operand *operand, bool intoPhiOperand);
1720+
SILValue materializeProjectionIntoUseImpl(Operand *operand,
1721+
bool intoPhiOperand);
15931722

15941723
SILValue materializeComposingUser(SingleValueInstruction *user,
15951724
bool intoPhiOperand) {
@@ -1771,12 +1900,20 @@ SILValue AddressMaterialization::materializeTupleExtract(
17711900
elementValue->getType().getAddressType());
17721901
}
17731902

1903+
SILValue
1904+
AddressMaterialization::materializeProjectionIntoUse(Operand *operand,
1905+
bool intoPhiOperand) {
1906+
auto projection = materializeProjectionIntoUseImpl(operand, intoPhiOperand);
1907+
pass.useProjections.push_back(projection);
1908+
return projection;
1909+
}
1910+
17741911
/// Recursively materialize the address of a subobject that is a member of the
17751912
/// operand's user. The operand's user must be an aggregate struct, tuple, enum,
17761913
/// init_existential_value.
17771914
SILValue
1778-
AddressMaterialization::materializeProjectionIntoUse(Operand *operand,
1779-
bool intoPhiOperand) {
1915+
AddressMaterialization::materializeProjectionIntoUseImpl(Operand *operand,
1916+
bool intoPhiOperand) {
17801917
SILInstruction *user = operand->getUser();
17811918
switch (user->getKind()) {
17821919
default:
@@ -4183,6 +4320,8 @@ void AddressLowering::runOnFunction(SILFunction *function) {
41834320

41844321
allocator.finalizeOpaqueStorage();
41854322

4323+
allocator.sinkProjections();
4324+
41864325
deleteRewrittenInstructions(pass);
41874326

41884327
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)