@@ -559,6 +559,13 @@ struct AddressLoweringState {
559
559
// / @returns nullable value
560
560
SILValue getEarliestStoragePoint (SILValue userValue, bool allowsInit) const ;
561
561
562
+ // / Finds and caches the latest opening instruction of the type of the value
563
+ // / in \p pair.
564
+ // /
565
+ // / @returns nullable instruction
566
+ SILInstruction *
567
+ getLatestOpeningInst (const ValueStorageMap::ValueStoragePair *) const ;
568
+
562
569
// / The latest instruction which opens an archetype involved in the indicated
563
570
// / type.
564
571
// /
@@ -1245,6 +1252,15 @@ void OpaqueStorageAllocation::allocateValue(SILValue value) {
1245
1252
createStackAllocationStorage (value);
1246
1253
}
1247
1254
1255
+ SILInstruction *AddressLoweringState::getLatestOpeningInst (
1256
+ const ValueStorageMap::ValueStoragePair *pair) const {
1257
+ if (!pair->storage .latestOpeningInst .has_value ()) {
1258
+ auto *loi = getLatestOpeningInst (pair->value ->getType ());
1259
+ pair->storage .latestOpeningInst = {loi};
1260
+ }
1261
+ return pair->storage .latestOpeningInst .value ();
1262
+ }
1263
+
1248
1264
// / Enum and existential projections both perform initialization side-effects.
1249
1265
// / Consequently they can only be materialized once on any path.
1250
1266
// /
@@ -1290,6 +1306,9 @@ SILValue AddressLoweringState::getEarliestStoragePoint(SILValue userValue,
1290
1306
// not allowed. The projection will be inserted here.
1291
1307
return SILValue ();
1292
1308
}
1309
+ if (auto *loi = getLatestOpeningInst (pair)) {
1310
+ return cast<SingleValueInstruction>(loi);
1311
+ }
1293
1312
assert (!(storage.isProjection () && storage.storageAddress ));
1294
1313
if (!allowsInit && !storage.isUseProjection ) {
1295
1314
assert (!storage.isDefProjection &&
@@ -1807,6 +1826,7 @@ AddressMaterialization::materializeProjectionIntoUse(Operand *operand,
1807
1826
1808
1827
SILInstruction *AddressMaterialization::getProjectionInsertionPoint (
1809
1828
SILValue userValue, AddressLoweringState &pass) {
1829
+ SILInstruction *obstruction = nullptr ;
1810
1830
SILInstruction *retval = userValue->getDefiningInsertionPoint ();
1811
1831
for (auto *pair : pass.valueStorageMap .getProjections (userValue)) {
1812
1832
auto const &storage = pair->storage ;
@@ -1815,8 +1835,18 @@ SILInstruction *AddressMaterialization::getProjectionInsertionPoint(
1815
1835
retval = storage.storageAddress ->getNextInstruction ();
1816
1836
break ;
1817
1837
}
1838
+ if (!obstruction) {
1839
+ // It's only necessary to consider the obstruction to the earliest
1840
+ // projection because obstructions to any others must dominate it.
1841
+ if (auto *loi = pass.getLatestOpeningInst (pair))
1842
+ obstruction = loi->getNextInstruction ();
1843
+ }
1818
1844
}
1819
1845
assert (retval);
1846
+ if (obstruction) {
1847
+ if (pass.domInfo ->dominates (retval, obstruction))
1848
+ retval = obstruction;
1849
+ }
1820
1850
return retval;
1821
1851
}
1822
1852
0 commit comments