@@ -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 &&
@@ -1811,6 +1830,7 @@ AddressMaterialization::materializeProjectionIntoUse(Operand *operand,
1811
1830
1812
1831
SILInstruction *AddressMaterialization::getProjectionInsertionPoint (
1813
1832
SILValue userValue, AddressLoweringState &pass) {
1833
+ SILInstruction *obstruction = nullptr ;
1814
1834
SILInstruction *retval = userValue->getDefiningInsertionPoint ();
1815
1835
for (auto *pair : pass.valueStorageMap .getProjections (userValue)) {
1816
1836
auto const &storage = pair->storage ;
@@ -1819,8 +1839,18 @@ SILInstruction *AddressMaterialization::getProjectionInsertionPoint(
1819
1839
retval = storage.storageAddress ->getNextInstruction ();
1820
1840
break ;
1821
1841
}
1842
+ if (!obstruction) {
1843
+ // It's only necessary to consider the obstruction to the earliest
1844
+ // projection because obstructions to any others must dominate it.
1845
+ if (auto *loi = pass.getLatestOpeningInst (pair))
1846
+ obstruction = loi->getNextInstruction ();
1847
+ }
1822
1848
}
1823
1849
assert (retval);
1850
+ if (obstruction) {
1851
+ if (pass.domInfo ->dominates (retval, obstruction))
1852
+ retval = obstruction;
1853
+ }
1824
1854
return retval;
1825
1855
}
1826
1856
0 commit comments