Skip to content

Commit 47d7b6f

Browse files
committed
[AddressLowering] Place projections below types.
Projections may involve opened archetypes. They must be dominated by the instructions which open those archetypes. When determining the earliest storage point for a value and the point at which to insert its projections, look for such obstructions in the projection chain. The first one found is the earliest storage point.
1 parent 9d4536a commit 47d7b6f

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,13 @@ struct AddressLoweringState {
565565
/// @returns nullable value
566566
SILValue getEarliestStoragePoint(SILValue userValue, bool allowsInit) const;
567567

568+
/// Finds and caches the latest opening instruction of the type of the value
569+
/// in \p pair.
570+
///
571+
/// @returns nullable instruction
572+
SILInstruction *
573+
getLatestOpeningInst(const ValueStorageMap::ValueStoragePair *) const;
574+
568575
/// The latest instruction which opens an archetype involved in the indicated
569576
/// type.
570577
///
@@ -1256,6 +1263,15 @@ void OpaqueStorageAllocation::allocateValue(SILValue value) {
12561263
createStackAllocationStorage(value);
12571264
}
12581265

1266+
SILInstruction *AddressLoweringState::getLatestOpeningInst(
1267+
const ValueStorageMap::ValueStoragePair *pair) const {
1268+
if (!pair->storage.latestOpeningInst.has_value()) {
1269+
auto *loi = getLatestOpeningInst(pair->value->getType());
1270+
pair->storage.latestOpeningInst = {loi};
1271+
}
1272+
return pair->storage.latestOpeningInst.value();
1273+
}
1274+
12591275
SILValue AddressLoweringState::getEarliestStoragePoint(SILValue userValue,
12601276
bool allowsInit) const {
12611277
for (auto *pair : valueStorageMap.getProjections(userValue)) {
@@ -1265,6 +1281,9 @@ SILValue AddressLoweringState::getEarliestStoragePoint(SILValue userValue,
12651281
// not allowed. The projection will be inserted here.
12661282
return pair->value;
12671283
}
1284+
if (auto *loi = getLatestOpeningInst(pair)) {
1285+
return cast<SingleValueInstruction>(loi);
1286+
}
12681287
assert(!(storage.isProjection() && storage.storageAddress));
12691288
// Reached the bottom of the projection tower. There must be storage.
12701289
if (!storage.isProjection()) {
@@ -1781,6 +1800,7 @@ AddressLoweringState::getProjectionInsertionPoint(SILValue userValue) const {
17811800
if (!valueStorageMap.getStorage(userValue).isProjection()) {
17821801
return userValue->getDefiningInsertionPoint();
17831802
}
1803+
SILInstruction *obstruction = nullptr;
17841804
SILInstruction *retval = nullptr;
17851805
for (auto *pair : valueStorageMap.getProjections(userValue)) {
17861806
auto const &storage = pair->storage;
@@ -1789,8 +1809,18 @@ AddressLoweringState::getProjectionInsertionPoint(SILValue userValue) const {
17891809
retval = storage.storageAddress->getNextInstruction();
17901810
break;
17911811
}
1812+
if (!obstruction) {
1813+
// It's only necessary to consider the obstruction to the earliest
1814+
// projection because obstructions to any others must dominate it.
1815+
if (auto *loi = getLatestOpeningInst(pair))
1816+
obstruction = loi->getNextInstruction();
1817+
}
17921818
}
17931819
assert(retval);
1820+
if (obstruction) {
1821+
if (domInfo->dominates(retval, obstruction))
1822+
retval = obstruction;
1823+
}
17941824
return retval;
17951825
}
17961826

lib/SILOptimizer/Mandatory/AddressLowering.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ struct ValueStorage {
8181
/// after materialization (during instruction rewriting).
8282
SILValue storageAddress;
8383

84+
/// The latest instruction which opens an archetype involved in the value's
85+
/// type. Just a cache of getLatestOpeningInst(value).
86+
mutable Optional<SILInstruction *> latestOpeningInst = llvm::None;
87+
8488
/// When either isDefProjection or isUseProjection is set, this refers to the
8589
/// storage whose "def" this value projects out of or whose operand this
8690
/// storage projects into via its "use.
@@ -152,11 +156,14 @@ struct ValueStorage {
152156
/// Mapped values are expected to be created in a single RPO pass. "erase" is
153157
/// unsupported. Values must be replaced using 'replaceValue()'.
154158
class ValueStorageMap {
159+
public:
155160
struct ValueStoragePair {
156161
SILValue value;
157162
ValueStorage storage;
158163
ValueStoragePair(SILValue v, ValueStorage s) : value(v), storage(s) {}
159164
};
165+
166+
private:
160167
typedef std::vector<ValueStoragePair> ValueVector;
161168
// Hash of values to ValueVector indices.
162169
typedef llvm::DenseMap<SILValue, unsigned> ValueHashMap;

test/SILOptimizer/address_lowering.sil

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,32 @@ bb7:
10401040
return %23 : $()
10411041
}
10421042

1043+
// CHECK-LABEL: sil [ossa] @f163_testOpenedArchetype : {{.*}} {
1044+
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
1045+
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $Optional<Any>
1046+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]]
1047+
// CHECK: [[AN_ERROR:%[^,]+]] = open_existential_box [[BORROW]]
1048+
// CHECK: [[ANY_ADDR:%[^,]+]] = init_enum_data_addr [[ADDR]]
1049+
// CHECK: [[OPENED_ADDR:%[^,]+]] = init_existential_addr [[ANY_ADDR]]
1050+
// CHECK: copy_addr [[AN_ERROR]] to [init] [[OPENED_ADDR]]
1051+
// CHECK: inject_enum_addr [[ADDR]] : $*Optional<Any>, #Optional.some!enumelt
1052+
// CHECK: apply undef<Any>([[ADDR]])
1053+
// CHECK-LABEL: } // end sil function 'f163_testOpenedArchetype'
1054+
sil [ossa] @f163_testOpenedArchetype : $@convention(c) (@owned any Error) -> () {
1055+
block(%instance : @owned $any Error):
1056+
%borrow = begin_borrow [lexical] %instance : $any Error
1057+
%an_error = open_existential_box_value %borrow : $any Error to $@opened("55625EBA-9384-11ED-A0B0-32F16C24A34F", any Error) Self
1058+
%an_owned_error = copy_value %an_error : $@opened("55625EBA-9384-11ED-A0B0-32F16C24A34F", any Error) Self
1059+
%any = init_existential_value %an_owned_error : $@opened("55625EBA-9384-11ED-A0B0-32F16C24A34F", any Error) Self, $@opened("55625EBA-9384-11ED-A0B0-32F16C24A34F", any Error) Self, $Any
1060+
%some_any = enum $Optional<Any>, #Optional.some!enumelt, %any : $Any
1061+
apply undef<Any>(%some_any) : $@convention(thin) <T> (@in Optional<T>) -> ()
1062+
end_borrow %borrow : $any Error
1063+
destroy_value %instance : $any Error
1064+
%retval = tuple ()
1065+
return %retval : $()
1066+
} // end sil function 'main'
1067+
1068+
10431069
// CHECK-LABEL: sil [ossa] @f170_compare : $@convention(thin) <T where T : Comparable> (@in_guaranteed T, @in_guaranteed T) -> @out T {
10441070
// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T):
10451071
// CHECK: [[WT:%.*]] = witness_method $T, #Comparable."<" : <Self where Self : Comparable> (Self.Type) -> (Self, Self) -> Builtin.Int1 : $@convention(witness_method: Comparable) <τ_0_0 where τ_0_0 : Comparable> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0, @thick τ_0_0.Type) -> Builtin.Int1

0 commit comments

Comments
 (0)