@@ -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+
11621170protected:
11631171 void allocateValue (SILValue value);
11641172 bool findProjectionIntoUseImpl (SILValue value,
@@ -1524,6 +1532,54 @@ AllocStackInst *OpaqueStorageAllocation::createStackAllocation(SILValue value) {
15241532 return alloc;
15251533}
15261534
1535+ namespace {
1536+ enum class SinkResult {
1537+ NoUsers,
1538+ Unmoved,
1539+ Moved,
1540+ };
1541+ SinkResult sinkToUses (SingleValueInstruction *svi, DominanceInfo *domInfo) {
1542+ // Fast paths for 0 and 1 users.
1543+
1544+ if (svi->use_begin () == svi->use_end ()) {
1545+ return SinkResult::NoUsers;
1546+ }
1547+
1548+ if (auto *use = svi->getSingleUse ()) {
1549+ auto *user = use->getUser ();
1550+ if (user == svi->getNextInstruction ())
1551+ return SinkResult::Unmoved;
1552+ svi->moveBefore (user);
1553+ return SinkResult::Moved;
1554+ }
1555+
1556+ // Compute the lca and sink the instruction to before its first user or its
1557+ // end if there are none.
1558+
1559+ SILBasicBlock *lca = domInfo->getLeastCommonAncestorOfUses (svi);
1560+
1561+ // The lca may contain a user. Look for the user to insert before it.
1562+
1563+ InstructionSet userSet (svi->getFunction ());
1564+ for (auto user : svi->getUsers ()) {
1565+ userSet.insert (user);
1566+ }
1567+
1568+ for (auto &instruction : *lca) {
1569+ if (userSet.contains (&instruction)) {
1570+ if (&instruction == svi->getNextInstruction ())
1571+ return SinkResult::Unmoved;
1572+ svi->moveBefore (&instruction);
1573+ return SinkResult::Moved;
1574+ }
1575+ }
1576+
1577+ // No user was found in the lca, move to before the end.
1578+ svi->moveBefore (&lca->back ());
1579+ return SinkResult::Moved;
1580+ }
1581+ } // end anonymous namespace
1582+
15271583void OpaqueStorageAllocation::finalizeOpaqueStorage () {
15281584 SmallVector<SILBasicBlock *, 4 > boundary;
15291585 for (auto maybeAlloc : allocs) {
@@ -1554,6 +1610,40 @@ void OpaqueStorageAllocation::finalizeOpaqueStorage() {
15541610 }
15551611}
15561612
1613+ void OpaqueStorageAllocation::sinkProjections () {
1614+ // First, sink use projections to their uses. It's necessary to do this
1615+ // separately from sinking projections in valueStorageMap because not all use
1616+ // projections are recorded there (those for non-canonical users and those for
1617+ // phis).
1618+ //
1619+ // Done in reverse order because outer projections are materialized first and
1620+ // so appear in `useProjections` before inner projections, and inner
1621+ // projections must be sunk first.
1622+ for (auto projection : llvm::reverse (pass.useProjections )) {
1623+ assert (projection);
1624+ auto *svi = dyn_cast<SingleValueInstruction>(projection);
1625+ assert (svi);
1626+ auto sank = sinkToUses (svi, pass.domInfo );
1627+ if (sank == SinkResult::NoUsers) {
1628+ pass.deleter .forceDelete (svi);
1629+ }
1630+ }
1631+
1632+ // Second, sink all storage from the valueStorageMap.
1633+ for (auto pair : llvm::reverse (pass.valueStorageMap )) {
1634+ auto addr = pair.storage .getMaterializedAddress ();
1635+ if (!pair.storage .isProjection ())
1636+ continue ;
1637+ auto *inst = dyn_cast<SingleValueInstruction>(addr);
1638+ if (!inst)
1639+ continue ;
1640+ auto sank = sinkToUses (inst, pass.domInfo );
1641+ if (sank == SinkResult::NoUsers) {
1642+ pass.deleter .forceDelete (inst);
1643+ }
1644+ }
1645+ }
1646+
15571647// ===----------------------------------------------------------------------===//
15581648// AddressMaterialization
15591649//
@@ -1613,6 +1703,8 @@ class AddressMaterialization {
16131703 SILValue elementValue, unsigned fieldIdx);
16141704
16151705 SILValue materializeProjectionIntoUse (Operand *operand, bool intoPhiOperand);
1706+ SILValue materializeProjectionIntoUseImpl (Operand *operand,
1707+ bool intoPhiOperand);
16161708
16171709 SILValue materializeComposingUser (SingleValueInstruction *user,
16181710 bool intoPhiOperand) {
@@ -1794,12 +1886,20 @@ SILValue AddressMaterialization::materializeTupleExtract(
17941886 elementValue->getType ().getAddressType ());
17951887}
17961888
1889+ SILValue
1890+ AddressMaterialization::materializeProjectionIntoUse (Operand *operand,
1891+ bool intoPhiOperand) {
1892+ auto projection = materializeProjectionIntoUseImpl (operand, intoPhiOperand);
1893+ pass.useProjections .push_back (projection);
1894+ return projection;
1895+ }
1896+
17971897// / Recursively materialize the address of a subobject that is a member of the
17981898// / operand's user. The operand's user must be an aggregate struct, tuple, enum,
17991899// / init_existential_value.
18001900SILValue
1801- AddressMaterialization::materializeProjectionIntoUse (Operand *operand,
1802- bool intoPhiOperand) {
1901+ AddressMaterialization::materializeProjectionIntoUseImpl (Operand *operand,
1902+ bool intoPhiOperand) {
18031903 SILInstruction *user = operand->getUser ();
18041904 switch (user->getKind ()) {
18051905 default :
@@ -4291,6 +4391,8 @@ void AddressLowering::runOnFunction(SILFunction *function) {
42914391
42924392 allocator.finalizeOpaqueStorage ();
42934393
4394+ allocator.sinkProjections ();
4395+
42944396 deleteRewrittenInstructions (pass);
42954397
42964398 StackNesting::fixNesting (function);
0 commit comments