Skip to content

Commit 9c706ef

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 8b5b012 commit 9c706ef

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
@@ -559,6 +559,13 @@ struct AddressLoweringState {
559559
/// @returns nullable value
560560
SILValue getEarliestStoragePoint(SILValue userValue, bool allowsInit) const;
561561

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+
562569
/// The latest instruction which opens an archetype involved in the indicated
563570
/// type.
564571
///
@@ -1245,6 +1252,15 @@ void OpaqueStorageAllocation::allocateValue(SILValue value) {
12451252
createStackAllocationStorage(value);
12461253
}
12471254

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+
12481264
/// Enum and existential projections both perform initialization side-effects.
12491265
/// Consequently they can only be materialized once on any path.
12501266
///
@@ -1290,6 +1306,9 @@ SILValue AddressLoweringState::getEarliestStoragePoint(SILValue userValue,
12901306
// not allowed. The projection will be inserted here.
12911307
return SILValue();
12921308
}
1309+
if (auto *loi = getLatestOpeningInst(pair)) {
1310+
return cast<SingleValueInstruction>(loi);
1311+
}
12931312
assert(!(storage.isProjection() && storage.storageAddress));
12941313
if (!allowsInit && !storage.isUseProjection) {
12951314
assert(!storage.isDefProjection &&
@@ -1811,6 +1830,7 @@ AddressMaterialization::materializeProjectionIntoUse(Operand *operand,
18111830

18121831
SILInstruction *AddressMaterialization::getProjectionInsertionPoint(
18131832
SILValue userValue, AddressLoweringState &pass) {
1833+
SILInstruction *obstruction = nullptr;
18141834
SILInstruction *retval = userValue->getDefiningInsertionPoint();
18151835
for (auto *pair : pass.valueStorageMap.getProjections(userValue)) {
18161836
auto const &storage = pair->storage;
@@ -1819,8 +1839,18 @@ SILInstruction *AddressMaterialization::getProjectionInsertionPoint(
18191839
retval = storage.storageAddress->getNextInstruction();
18201840
break;
18211841
}
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+
}
18221848
}
18231849
assert(retval);
1850+
if (obstruction) {
1851+
if (pass.domInfo->dominates(retval, obstruction))
1852+
retval = obstruction;
1853+
}
18241854
return retval;
18251855
}
18261856

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 llvm::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.
@@ -158,6 +162,7 @@ struct ValueStorage {
158162
/// Mapped values are expected to be created in a single RPO pass. "erase" is
159163
/// unsupported. Values must be replaced using 'replaceValue()'.
160164
class ValueStorageMap {
165+
public:
161166
struct ValueStoragePair {
162167
SILValue value;
163168
ValueStorage storage;
@@ -166,6 +171,8 @@ class ValueStorageMap {
166171
void dump() const;
167172
#endif
168173
};
174+
175+
private:
169176
typedef std::vector<ValueStoragePair> ValueVector;
170177
// Hash of values to ValueVector indices.
171178
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)