Skip to content

Commit 41e2e29

Browse files
committed
SIL: Store type lowerings for multiple resilience expansions
This lets the SIL optimizer reason about types (e.g. if a type is loadable) in specific functions. For example, a type might be loadable in a resilient function, but not in an inlinable function.
1 parent 95e0c66 commit 41e2e29

File tree

5 files changed

+126
-28
lines changed

5 files changed

+126
-28
lines changed

include/swift/SIL/SILModule.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,10 @@ class SILModule {
316316
mutable Lowering::TypeConverter Types;
317317

318318
/// Look up the TypeLowering for a SILType.
319-
const Lowering::TypeLowering &getTypeLowering(SILType t) {
320-
return Types.getTypeLowering(t);
319+
const Lowering::TypeLowering &
320+
getTypeLowering(SILType t, ResilienceExpansion expansion =
321+
ResilienceExpansion::Minimal) {
322+
return Types.getTypeLowering(t, expansion);
321323
}
322324

323325
/// Invalidate cached entries in SIL Loader.

include/swift/SIL/SILType.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,14 +257,35 @@ class SILType {
257257
bool isLoadable(SILModule &M) const {
258258
return !isAddressOnly(M);
259259
}
260+
261+
/// Like isLoadable(SILModule), but specific to a function.
262+
///
263+
/// This takes the resilience expansion of the function into account. If the
264+
/// type is not loadable in general (because it's resilient), it still might
265+
/// be loadable inside a resilient function in the module.
266+
/// In other words: isLoadable(SILModule) is the conservative default, whereas
267+
/// isLoadable(SILFunction) might give a more optimistic result.
268+
bool isLoadable(SILFunction *inFunction) const {
269+
return !isAddressOnly(inFunction);
270+
}
271+
260272
/// True if either:
261273
/// 1) The type, or the referenced type of an address type, is loadable.
262274
/// 2) The SIL Module conventions uses lowered addresses
263275
bool isLoadableOrOpaque(SILModule &M) const;
276+
277+
/// Like isLoadableOrOpaque(SILModule), but takes the resilience expansion of
278+
/// \p inFunction into account (see isLoadable(SILFunction)).
279+
bool isLoadableOrOpaque(SILFunction *inFunction) const;
280+
264281
/// True if the type, or the referenced type of an address type, is
265282
/// address-only. This is the opposite of isLoadable.
266283
bool isAddressOnly(SILModule &M) const;
267284

285+
/// Like isAddressOnly(SILModule), but takes the resilience expansion of
286+
/// \p inFunction into account (see isLoadable(SILFunction)).
287+
bool isAddressOnly(SILFunction *inFunction) const;
288+
268289
/// True if the type, or the referenced type of an address type, is trivial.
269290
bool isTrivial(SILModule &M) const;
270291

include/swift/SIL/TypeLowering.h

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ enum IsReferenceCounted_t : bool {
148148
IsReferenceCounted = true
149149
};
150150

151+
/// Is this type address only because it's resilient?
152+
enum IsResilient_t : bool {
153+
IsNotResilient = false,
154+
IsResilient = true
155+
};
156+
151157
/// Extended type information used by SIL.
152158
class TypeLowering {
153159
public:
@@ -157,6 +163,7 @@ class TypeLowering {
157163
NonTrivialFlag = 1 << 0,
158164
NonFixedABIFlag = 1 << 1,
159165
AddressOnlyFlag = 1 << 2,
166+
ResilientFlag = 1 << 3,
160167
};
161168

162169
uint8_t Flags;
@@ -167,17 +174,23 @@ class TypeLowering {
167174

168175
constexpr RecursiveProperties(IsTrivial_t isTrivial,
169176
IsFixedABI_t isFixedABI,
170-
IsAddressOnly_t isAddressOnly)
177+
IsAddressOnly_t isAddressOnly,
178+
IsResilient_t isResilient = IsNotResilient)
171179
: Flags((isTrivial ? 0U : NonTrivialFlag) |
172180
(isAddressOnly ? AddressOnlyFlag : 0U) |
173-
(isFixedABI ? 0U : NonFixedABIFlag)) {}
181+
(isFixedABI ? 0U : NonFixedABIFlag) |
182+
(isResilient ? ResilientFlag : 0U)) {}
174183

175184
static constexpr RecursiveProperties forReference() {
176-
return {IsNotTrivial, IsFixedABI, IsNotAddressOnly};
185+
return {IsNotTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient };
177186
}
178187

179188
static constexpr RecursiveProperties forOpaque() {
180-
return {IsNotTrivial, IsNotFixedABI, IsAddressOnly};
189+
return {IsNotTrivial, IsNotFixedABI, IsAddressOnly, IsNotResilient};
190+
}
191+
192+
static constexpr RecursiveProperties forResilient() {
193+
return {IsNotTrivial, IsNotFixedABI, IsAddressOnly, IsResilient};
181194
}
182195

183196
void addSubobject(RecursiveProperties other) {
@@ -193,6 +206,9 @@ class TypeLowering {
193206
IsAddressOnly_t isAddressOnly() const {
194207
return IsAddressOnly_t((Flags & AddressOnlyFlag) != 0);
195208
}
209+
IsResilient_t isResilient() const {
210+
return IsResilient_t((Flags & ResilientFlag) != 0);
211+
}
196212

197213
void setNonTrivial() { Flags |= NonTrivialFlag; }
198214
void setNonFixedABI() { Flags |= NonFixedABIFlag; }
@@ -206,7 +222,16 @@ class TypeLowering {
206222
RecursiveProperties Properties;
207223
unsigned ReferenceCounted : 1;
208224

209-
protected:
225+
public:
226+
/// The resilience expansion for this type lowering.
227+
/// If the type is not resilient at all, this is always Minimal.
228+
ResilienceExpansion forExpansion = ResilienceExpansion::Minimal;
229+
230+
/// A single linked list of lowerings for different resilience expansions.
231+
/// The first lowering is always for ResilientExpansion::Minimal.
232+
mutable const TypeLowering *nextExpansion = nullptr;
233+
234+
protected:
210235
TypeLowering(SILType type, RecursiveProperties properties,
211236
IsReferenceCounted_t isRefCounted)
212237
: LoweredType(type), Properties(properties),
@@ -277,6 +302,10 @@ class TypeLowering {
277302
return LoweredType.isAddress();
278303
}
279304

305+
bool isResilient() const {
306+
return Properties.isResilient();
307+
}
308+
280309
/// Return the semantic type.
281310
///
282311
/// The semantic type is what a type pretends to be during
@@ -670,7 +699,8 @@ class TypeConverter {
670699
Optional<CanType> BridgedType##Ty;
671700
#include "swift/SIL/BridgedTypes.def"
672701

673-
const TypeLowering &getTypeLoweringForLoweredType(TypeKey key);
702+
const TypeLowering &
703+
getTypeLoweringForLoweredType(TypeKey key, ResilienceExpansion forExpansion);
674704
const TypeLowering &getTypeLoweringForUncachedLoweredType(TypeKey key);
675705

676706
public:
@@ -746,7 +776,9 @@ class TypeConverter {
746776
/// Returns the SIL TypeLowering for an already lowered SILType. If the
747777
/// SILType is an address, returns the TypeLowering for the pointed-to
748778
/// type.
749-
const TypeLowering &getTypeLowering(SILType t);
779+
const TypeLowering &
780+
getTypeLowering(SILType t, ResilienceExpansion forExpansion =
781+
ResilienceExpansion::Minimal);
750782

751783
// Returns the lowered SIL type for a Swift type.
752784
SILType getLoweredType(Type t) {

lib/SIL/SILType.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,24 @@ bool SILType::isLoadableOrOpaque(SILModule &M) const {
175175
return isLoadable(M) || !SILModuleConventions(M).useLoweredAddresses();
176176
}
177177

178+
bool SILType::isLoadableOrOpaque(SILFunction *inFunction) const {
179+
SILModule &M = inFunction->getModule();
180+
return isLoadable(inFunction) ||
181+
!SILModuleConventions(M).useLoweredAddresses();
182+
}
183+
178184
/// True if the type, or the referenced type of an address type, is
179185
/// address-only. For example, it could be a resilient struct or something of
180186
/// unknown size.
181187
bool SILType::isAddressOnly(SILModule &M) const {
182188
return M.getTypeLowering(*this).isAddressOnly();
183189
}
184190

191+
bool SILType::isAddressOnly(SILFunction *inFunction) const {
192+
return inFunction->getModule().getTypeLowering(*this,
193+
inFunction->getResilienceExpansion()).isAddressOnly();
194+
}
195+
185196
SILType SILType::substGenericArgs(SILModule &M,
186197
SubstitutionMap SubMap) const {
187198
auto fnTy = castTo<SILFunctionType>();

lib/SIL/TypeLowering.cpp

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,7 +1139,7 @@ namespace {
11391139
/// Build the appropriate TypeLowering subclass for the given type,
11401140
/// which is assumed to already have been lowered.
11411141
class LowerType
1142-
: public TypeClassifierBase<LowerType, const TypeLowering *>
1142+
: public TypeClassifierBase<LowerType, TypeLowering *>
11431143
{
11441144
TypeConverter &TC;
11451145
IsDependent_t Dependent;
@@ -1149,18 +1149,18 @@ namespace {
11491149
: TypeClassifierBase(TC.M, Sig, Expansion),
11501150
TC(TC), Dependent(Dependent) {}
11511151

1152-
const TypeLowering *
1152+
TypeLowering *
11531153
handleTrivial(CanType type) {
11541154
auto silType = SILType::getPrimitiveObjectType(type);
11551155
return new (TC, Dependent) TrivialTypeLowering(silType);
11561156
}
11571157

1158-
const TypeLowering *handleReference(CanType type) {
1158+
TypeLowering *handleReference(CanType type) {
11591159
auto silType = SILType::getPrimitiveObjectType(type);
11601160
return new (TC, Dependent) ReferenceTypeLowering(silType);
11611161
}
11621162

1163-
const TypeLowering *handleAddressOnly(CanType type,
1163+
TypeLowering *handleAddressOnly(CanType type,
11641164
RecursiveProperties properties) {
11651165
if (SILModuleConventions(M).useLoweredAddresses()) {
11661166
auto silType = SILType::getPrimitiveAddressType(type);
@@ -1171,20 +1171,20 @@ namespace {
11711171
}
11721172

11731173
#define SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
1174-
const TypeLowering * \
1174+
TypeLowering * \
11751175
visitLoadable##Name##StorageType(Can##Name##StorageType type) { \
11761176
return new (TC, Dependent) Loadable##Name##TypeLowering( \
11771177
SILType::getPrimitiveObjectType(type)); \
11781178
}
11791179
#include "swift/AST/ReferenceStorage.def"
11801180

1181-
const TypeLowering *
1181+
TypeLowering *
11821182
visitBuiltinUnsafeValueBufferType(CanBuiltinUnsafeValueBufferType type) {
11831183
auto silType = SILType::getPrimitiveAddressType(type);
11841184
return new (TC, Dependent) UnsafeValueBufferTypeLowering(silType);
11851185
}
11861186

1187-
const TypeLowering *visitTupleType(CanTupleType tupleType) {
1187+
TypeLowering *visitTupleType(CanTupleType tupleType) {
11881188
RecursiveProperties properties;
11891189
for (auto eltType : tupleType.getElementTypes()) {
11901190
auto &lowering = TC.getTypeLowering(eltType);
@@ -1195,13 +1195,13 @@ namespace {
11951195
properties);
11961196
}
11971197

1198-
const TypeLowering *visitAnyStructType(CanType structType, StructDecl *D) {
1198+
TypeLowering *visitAnyStructType(CanType structType, StructDecl *D) {
11991199

12001200
// For now, if the type does not have a fixed layout in all resilience
12011201
// domains, we will treat it as address-only in SIL.
12021202
if (D->isResilient(M.getSwiftModule(), Expansion))
12031203
return handleAddressOnly(structType,
1204-
RecursiveProperties::forOpaque());
1204+
RecursiveProperties::forResilient());
12051205

12061206
// Classify the type according to its stored properties.
12071207
RecursiveProperties properties;
@@ -1216,11 +1216,11 @@ namespace {
12161216
properties);
12171217
}
12181218

1219-
const TypeLowering *visitAnyEnumType(CanType enumType, EnumDecl *D) {
1219+
TypeLowering *visitAnyEnumType(CanType enumType, EnumDecl *D) {
12201220
// For now, if the type does not have a fixed layout in all resilience
12211221
// domains, we will treat it as address-only in SIL.
12221222
if (D->isResilient(M.getSwiftModule(), Expansion))
1223-
return handleAddressOnly(enumType, RecursiveProperties::forOpaque());
1223+
return handleAddressOnly(enumType, RecursiveProperties::forResilient());
12241224

12251225
// If the whole enum is indirect, we lower it as if all payload
12261226
// cases were indirect. This means a fixed-layout indirect enum
@@ -1257,7 +1257,7 @@ namespace {
12571257
}
12581258

12591259
template <class LoadableLoweringClass>
1260-
const TypeLowering *handleAggregateByProperties(CanType type,
1260+
TypeLowering *handleAggregateByProperties(CanType type,
12611261
RecursiveProperties props) {
12621262
if (props.isAddressOnly()) {
12631263
return handleAddressOnly(type, props);
@@ -1451,7 +1451,8 @@ TypeConverter::getTypeLowering(AbstractionPattern origType,
14511451
AbstractionPattern(getCurGenericContext(), loweredSubstType);
14521452
auto loweredKey = getTypeKey(origTypeForCaching, loweredSubstType);
14531453

1454-
auto &lowering = getTypeLoweringForLoweredType(loweredKey);
1454+
auto &lowering = getTypeLoweringForLoweredType(loweredKey,
1455+
ResilienceExpansion::Minimal);
14551456
insert(key, &lowering);
14561457
return lowering;
14571458
}
@@ -1565,27 +1566,58 @@ CanType TypeConverter::getLoweredRValueType(AbstractionPattern origType,
15651566
return substType;
15661567
}
15671568

1568-
const TypeLowering &TypeConverter::getTypeLowering(SILType type) {
1569+
const TypeLowering &
1570+
TypeConverter::getTypeLowering(SILType type, ResilienceExpansion forExpansion) {
15691571
auto loweredType = type.getASTType();
15701572
auto key = getTypeKey(AbstractionPattern(getCurGenericContext(), loweredType),
15711573
loweredType);
15721574

1573-
return getTypeLoweringForLoweredType(key);
1575+
return getTypeLoweringForLoweredType(key, forExpansion);
15741576
}
15751577

15761578
const TypeLowering &
1577-
TypeConverter::getTypeLoweringForLoweredType(TypeKey key) {
1579+
TypeConverter::getTypeLoweringForLoweredType(TypeKey key,
1580+
ResilienceExpansion forExpansion) {
15781581
auto type = key.SubstType;
15791582
assert(type->isLegalSILType() && "type is not lowered!");
15801583
(void)type;
15811584

15821585
// Re-using uncurry level 0 is reasonable because our uncurrying
15831586
// transforms are idempotent at this level. This means we don't
15841587
// need a ton of redundant entries in the map.
1585-
if (auto existing = find(key))
1586-
return *existing;
1588+
const TypeLowering *lowering = find(key);
1589+
if (!lowering) {
1590+
lowering = &getTypeLoweringForUncachedLoweredType(key);
1591+
}
1592+
assert(lowering->forExpansion == ResilienceExpansion::Minimal &&
1593+
"the first lowering in the list must be for minimal expansion");
15871594

1588-
return getTypeLoweringForUncachedLoweredType(key);
1595+
if (key.isDependent() || !lowering->isResilient()) {
1596+
// Don't try to refine the lowering for other resilience expansions if
1597+
// we don't expect to get a different lowering anyway.
1598+
return *lowering;
1599+
}
1600+
1601+
// Search for a matching lowering in the linked list of lowerings.
1602+
while (true) {
1603+
if (lowering->forExpansion == forExpansion)
1604+
return *lowering;
1605+
if (lowering->nextExpansion) {
1606+
// Continue searching.
1607+
lowering = lowering->nextExpansion;
1608+
continue;
1609+
}
1610+
1611+
// Create a new lowering for the resilience expansion.
1612+
TypeLowering *theInfo = LowerType(*this,
1613+
CanGenericSignature(),
1614+
forExpansion,
1615+
key.isDependent()).visit(key.SubstType);
1616+
1617+
lowering->nextExpansion = theInfo;
1618+
theInfo->forExpansion = forExpansion;
1619+
return *theInfo;
1620+
}
15891621
}
15901622

15911623
/// Do type-lowering for a lowered type which is not already in the cache,

0 commit comments

Comments
 (0)