Skip to content

Commit d269358

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 82eda6e commit d269358

File tree

5 files changed

+189
-81
lines changed

5 files changed

+189
-81
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

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

530+
// Projections created for uses, recorded in order to be sunk.
531+
//
532+
// Not all use projections are recorded in the valueStorageMap. It's not
533+
// legal to reuse use projections for non-canonical users or for phis.
534+
SmallVector<SILValue, 16> useProjections;
535+
530536
AddressLoweringState(SILFunction *function, DominanceInfo *domInfo,
531537
DeadEndBlocks *deBlocks)
532538
: function(function), loweredFnConv(getLoweredFnConv(function)),
@@ -1159,6 +1165,8 @@ class OpaqueStorageAllocation {
11591165
/// jointly postdominate.
11601166
void finalizeOpaqueStorage();
11611167

1168+
void sinkProjections();
1169+
11621170
protected:
11631171
void allocateValue(SILValue value);
11641172
bool findProjectionIntoUseImpl(SILValue value,
@@ -1518,6 +1526,54 @@ AllocStackInst *OpaqueStorageAllocation::createStackAllocation(SILValue value) {
15181526
return alloc;
15191527
}
15201528

1529+
namespace {
1530+
enum class SinkResult {
1531+
NoUsers,
1532+
Unmoved,
1533+
Moved,
1534+
};
1535+
SinkResult sinkToUses(SingleValueInstruction *svi, DominanceInfo *domInfo) {
1536+
// Fast paths for 0 and 1 users.
1537+
1538+
if (svi->use_begin() == svi->use_end()) {
1539+
return SinkResult::NoUsers;
1540+
}
1541+
1542+
if (auto *use = svi->getSingleUse()) {
1543+
auto *user = use->getUser();
1544+
if (user == svi->getNextInstruction())
1545+
return SinkResult::Unmoved;
1546+
svi->moveBefore(user);
1547+
return SinkResult::Moved;
1548+
}
1549+
1550+
// Compute the lca and sink the instruction to before its first user or its
1551+
// end if there are none.
1552+
1553+
SILBasicBlock *lca = domInfo->getLeastCommonAncestorOfUses(svi);
1554+
1555+
// The lca may contain a user. Look for the user to insert before it.
1556+
1557+
InstructionSet userSet(svi->getFunction());
1558+
for (auto user : svi->getUsers()) {
1559+
userSet.insert(user);
1560+
}
1561+
1562+
for (auto &instruction : *lca) {
1563+
if (userSet.contains(&instruction)) {
1564+
if (&instruction == svi->getNextInstruction())
1565+
return SinkResult::Unmoved;
1566+
svi->moveBefore(&instruction);
1567+
return SinkResult::Moved;
1568+
}
1569+
}
1570+
1571+
// No user was found in the lca, move to before the end.
1572+
svi->moveBefore(&lca->back());
1573+
return SinkResult::Moved;
1574+
}
1575+
} // end anonymous namespace
1576+
15211577
void OpaqueStorageAllocation::finalizeOpaqueStorage() {
15221578
SmallVector<SILBasicBlock *, 4> boundary;
15231579
for (auto maybeAlloc : allocs) {
@@ -1548,6 +1604,40 @@ void OpaqueStorageAllocation::finalizeOpaqueStorage() {
15481604
}
15491605
}
15501606

1607+
void OpaqueStorageAllocation::sinkProjections() {
1608+
// First, sink use projections to their uses. It's necessary to do this
1609+
// separately from sinking projections in valueStorageMap because not all use
1610+
// projections are recorded there (those for non-canonical users and those for
1611+
// phis).
1612+
//
1613+
// Done in reverse order because outer projections are materialized first and
1614+
// so appear in `useProjections` before inner projections, and inner
1615+
// projections must be sunk first.
1616+
for (auto projection : llvm::reverse(pass.useProjections)) {
1617+
assert(projection);
1618+
auto *svi = dyn_cast<SingleValueInstruction>(projection);
1619+
assert(svi);
1620+
auto sank = sinkToUses(svi, pass.domInfo);
1621+
if (sank == SinkResult::NoUsers) {
1622+
pass.deleter.forceDelete(svi);
1623+
}
1624+
}
1625+
1626+
// Second, sink all storage from the valueStorageMap.
1627+
for (auto pair : llvm::reverse(pass.valueStorageMap)) {
1628+
auto addr = pair.storage.getMaterializedAddress();
1629+
if (!pair.storage.isProjection())
1630+
continue;
1631+
auto *inst = dyn_cast<SingleValueInstruction>(addr);
1632+
if (!inst)
1633+
continue;
1634+
auto sank = sinkToUses(inst, pass.domInfo);
1635+
if (sank == SinkResult::NoUsers) {
1636+
pass.deleter.forceDelete(inst);
1637+
}
1638+
}
1639+
}
1640+
15511641
//===----------------------------------------------------------------------===//
15521642
// AddressMaterialization
15531643
//
@@ -1607,6 +1697,8 @@ class AddressMaterialization {
16071697
SILValue elementValue, unsigned fieldIdx);
16081698

16091699
SILValue materializeProjectionIntoUse(Operand *operand, bool intoPhiOperand);
1700+
SILValue materializeProjectionIntoUseImpl(Operand *operand,
1701+
bool intoPhiOperand);
16101702

16111703
SILValue materializeComposingUser(SingleValueInstruction *user,
16121704
bool intoPhiOperand) {
@@ -1788,12 +1880,20 @@ SILValue AddressMaterialization::materializeTupleExtract(
17881880
elementValue->getType().getAddressType());
17891881
}
17901882

1883+
SILValue
1884+
AddressMaterialization::materializeProjectionIntoUse(Operand *operand,
1885+
bool intoPhiOperand) {
1886+
auto projection = materializeProjectionIntoUseImpl(operand, intoPhiOperand);
1887+
pass.useProjections.push_back(projection);
1888+
return projection;
1889+
}
1890+
17911891
/// Recursively materialize the address of a subobject that is a member of the
17921892
/// operand's user. The operand's user must be an aggregate struct, tuple, enum,
17931893
/// init_existential_value.
17941894
SILValue
1795-
AddressMaterialization::materializeProjectionIntoUse(Operand *operand,
1796-
bool intoPhiOperand) {
1895+
AddressMaterialization::materializeProjectionIntoUseImpl(Operand *operand,
1896+
bool intoPhiOperand) {
17971897
SILInstruction *user = operand->getUser();
17981898
switch (user->getKind()) {
17991899
default:
@@ -4285,6 +4385,8 @@ void AddressLowering::runOnFunction(SILFunction *function) {
42854385

42864386
allocator.finalizeOpaqueStorage();
42874387

4388+
allocator.sinkProjections();
4389+
42884390
deleteRewrittenInstructions(pass);
42894391

42904392
StackNesting::fixNesting(function);

lib/SILOptimizer/Mandatory/AddressLowering.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,12 @@ class ValueStorageMap {
317317
return hashIter->second;
318318
}
319319

320+
ValueStoragePair &operator[](uint32_t index) { return valueVector[index]; }
321+
322+
ValueStoragePair const &operator[](uint32_t index) const {
323+
return valueVector[index];
324+
}
325+
320326
ValueStorage &getStorage(SILValue value) {
321327
return valueVector[getOrdinal(value)].storage;
322328
}

0 commit comments

Comments
 (0)