Skip to content

Commit 3275f56

Browse files
authored
Merge pull request #21614 from eeckstein/resilient-globalopt
GlobalOpt: optimize static properties with resilient types.
2 parents 480b433 + aa5a4e1 commit 3275f56

File tree

10 files changed

+250
-55
lines changed

10 files changed

+250
-55
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ class SILBuilder {
677677
!hasOwnership() && "Unqualified inst in qualified function");
678678
assert((Qualifier == LoadOwnershipQualifier::Unqualified) ||
679679
hasOwnership() && "Qualified inst in unqualified function");
680-
assert(LV->getType().isLoadableOrOpaque(getModule()));
680+
assert(isLoadableOrOpaque(LV->getType()));
681681
return insert(new (getModule())
682682
LoadInst(getSILDebugLocation(Loc), LV, Qualifier));
683683
}
@@ -696,13 +696,13 @@ class SILBuilder {
696696
/// non-address values.
697697
SILValue emitLoadValueOperation(SILLocation Loc, SILValue LV,
698698
LoadOwnershipQualifier Qualifier) {
699-
assert(LV->getType().isLoadableOrOpaque(getModule()));
699+
assert(isLoadableOrOpaque(LV->getType()));
700700
const auto &lowering = getTypeLowering(LV->getType());
701701
return lowering.emitLoad(*this, Loc, LV, Qualifier);
702702
}
703703

704704
LoadBorrowInst *createLoadBorrow(SILLocation Loc, SILValue LV) {
705-
assert(LV->getType().isLoadableOrOpaque(getModule()));
705+
assert(isLoadableOrOpaque(LV->getType()));
706706
return insert(new (getModule())
707707
LoadBorrowInst(getSILDebugLocation(Loc), LV));
708708
}
@@ -1069,7 +1069,7 @@ class SILBuilder {
10691069
}
10701070

10711071
DestroyValueInst *createDestroyValue(SILLocation Loc, SILValue operand) {
1072-
assert(operand->getType().isLoadableOrOpaque(getModule()));
1072+
assert(isLoadableOrOpaque(operand->getType()));
10731073
return insert(new (getModule())
10741074
DestroyValueInst(getSILDebugLocation(Loc), operand));
10751075
}
@@ -1100,7 +1100,7 @@ class SILBuilder {
11001100
RetainValueInst *createRetainValue(SILLocation Loc, SILValue operand,
11011101
Atomicity atomicity) {
11021102
assert(!hasOwnership());
1103-
assert(operand->getType().isLoadableOrOpaque(getModule()));
1103+
assert(isLoadableOrOpaque(operand->getType()));
11041104
return insert(new (getModule()) RetainValueInst(getSILDebugLocation(Loc),
11051105
operand, atomicity));
11061106
}
@@ -1115,7 +1115,7 @@ class SILBuilder {
11151115
ReleaseValueInst *createReleaseValue(SILLocation Loc, SILValue operand,
11161116
Atomicity atomicity) {
11171117
assert(!hasOwnership());
1118-
assert(operand->getType().isLoadableOrOpaque(getModule()));
1118+
assert(isLoadableOrOpaque(operand->getType()));
11191119
return insert(new (getModule()) ReleaseValueInst(getSILDebugLocation(Loc),
11201120
operand, atomicity));
11211121
}
@@ -1132,7 +1132,7 @@ class SILBuilder {
11321132
SILValue operand,
11331133
Atomicity atomicity) {
11341134
assert(hasOwnership());
1135-
assert(operand->getType().isLoadableOrOpaque(getModule()));
1135+
assert(isLoadableOrOpaque(operand->getType()));
11361136
return insert(new (getModule()) UnmanagedRetainValueInst(
11371137
getSILDebugLocation(Loc), operand, atomicity));
11381138
}
@@ -1141,7 +1141,7 @@ class SILBuilder {
11411141
SILValue operand,
11421142
Atomicity atomicity) {
11431143
assert(hasOwnership());
1144-
assert(operand->getType().isLoadableOrOpaque(getModule()));
1144+
assert(isLoadableOrOpaque(operand->getType()));
11451145
return insert(new (getModule()) UnmanagedReleaseValueInst(
11461146
getSILDebugLocation(Loc), operand, atomicity));
11471147
}
@@ -1177,14 +1177,14 @@ class SILBuilder {
11771177

11781178
StructInst *createStruct(SILLocation Loc, SILType Ty,
11791179
ArrayRef<SILValue> Elements) {
1180-
assert(Ty.isLoadableOrOpaque(getModule()));
1180+
assert(isLoadableOrOpaque(Ty));
11811181
return insert(StructInst::create(getSILDebugLocation(Loc), Ty, Elements,
11821182
getModule(), hasOwnership()));
11831183
}
11841184

11851185
TupleInst *createTuple(SILLocation Loc, SILType Ty,
11861186
ArrayRef<SILValue> Elements) {
1187-
assert(Ty.isLoadableOrOpaque(getModule()));
1187+
assert(isLoadableOrOpaque(Ty));
11881188
return insert(TupleInst::create(getSILDebugLocation(Loc), Ty, Elements,
11891189
getModule(), hasOwnership()));
11901190
}
@@ -1193,21 +1193,21 @@ class SILBuilder {
11931193

11941194
EnumInst *createEnum(SILLocation Loc, SILValue Operand,
11951195
EnumElementDecl *Element, SILType Ty) {
1196-
assert(Ty.isLoadableOrOpaque(getModule()));
1196+
assert(isLoadableOrOpaque(Ty));
11971197
return insert(new (getModule()) EnumInst(getSILDebugLocation(Loc),
11981198
Operand, Element, Ty));
11991199
}
12001200

12011201
/// Inject a loadable value into the corresponding optional type.
12021202
EnumInst *createOptionalSome(SILLocation Loc, SILValue operand, SILType ty) {
1203-
assert(ty.isLoadableOrOpaque(getModule()));
1203+
assert(isLoadableOrOpaque(ty));
12041204
auto someDecl = getModule().getASTContext().getOptionalSomeDecl();
12051205
return createEnum(Loc, operand, someDecl, ty);
12061206
}
12071207

12081208
/// Create the nil value of a loadable optional type.
12091209
EnumInst *createOptionalNone(SILLocation Loc, SILType ty) {
1210-
assert(ty.isLoadableOrOpaque(getModule()));
1210+
assert(isLoadableOrOpaque(ty));
12111211
auto noneDecl = getModule().getASTContext().getOptionalNoneDecl();
12121212
return createEnum(Loc, nullptr, noneDecl, ty);
12131213
}
@@ -1224,7 +1224,7 @@ class SILBuilder {
12241224
SILValue Operand,
12251225
EnumElementDecl *Element,
12261226
SILType Ty) {
1227-
assert(Ty.isLoadableOrOpaque(getModule()));
1227+
assert(isLoadableOrOpaque(Ty));
12281228
return insert(new (getModule()) UncheckedEnumDataInst(
12291229
getSILDebugLocation(Loc), Operand, Element, Ty));
12301230
}
@@ -1264,7 +1264,7 @@ class SILBuilder {
12641264
ArrayRef<std::pair<EnumElementDecl *, SILValue>> CaseValues,
12651265
Optional<ArrayRef<ProfileCounter>> CaseCounts = None,
12661266
ProfileCounter DefaultCount = ProfileCounter()) {
1267-
assert(Ty.isLoadableOrOpaque(getModule()));
1267+
assert(isLoadableOrOpaque(Ty));
12681268
return insert(SelectEnumInst::create(
12691269
getSILDebugLocation(Loc), Operand, Ty, DefaultValue, CaseValues,
12701270
getModule(), CaseCounts, DefaultCount, hasOwnership()));
@@ -2125,6 +2125,15 @@ class SILBuilder {
21252125
#endif
21262126
}
21272127

2128+
bool isLoadableOrOpaque(SILType Ty) {
2129+
if (!F) {
2130+
// We are inserting into the static initializer of a SILGlobalVariable.
2131+
// All types used there are loadable by definition.
2132+
return true;
2133+
}
2134+
return Ty.isLoadableOrOpaque(F);
2135+
}
2136+
21282137
void appendOperandTypeName(SILType OpdTy, llvm::SmallString<16> &Name) {
21292138
if (auto BuiltinIntTy =
21302139
dyn_cast<BuiltinIntegerType>(OpdTy.getASTType())) {

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/SILBuilder.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ SILBuilder::createClassifyBridgeObject(SILLocation Loc, SILValue value) {
120120
// Create the appropriate cast instruction based on result type.
121121
SingleValueInstruction *
122122
SILBuilder::createUncheckedBitCast(SILLocation Loc, SILValue Op, SILType Ty) {
123-
assert(Ty.isLoadableOrOpaque(getModule()));
123+
assert(isLoadableOrOpaque(Ty));
124124
if (Ty.isTrivial(getModule()))
125125
return insert(UncheckedTrivialBitCastInst::create(
126126
getSILDebugLocation(Loc), Op, Ty, getFunction(), C.OpenedArchetypes));
@@ -552,7 +552,7 @@ void SILBuilder::emitShallowDestructureAddressOperation(
552552

553553
DebugValueInst *SILBuilder::createDebugValue(SILLocation Loc, SILValue src,
554554
SILDebugVariable Var) {
555-
assert(src->getType().isLoadableOrOpaque(getModule()));
555+
assert(isLoadableOrOpaque(src->getType()));
556556
// Debug location overrides cannot apply to debug value instructions.
557557
DebugLocOverrideRAII LocOverride{*this, None};
558558
return insert(

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/SILVerifier.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,7 +1534,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
15341534
void checkLoadInst(LoadInst *LI) {
15351535
require(LI->getType().isObject(), "Result of load must be an object");
15361536
require(!fnConv.useLoweredAddresses()
1537-
|| LI->getType().isLoadable(LI->getModule()),
1537+
|| LI->getType().isLoadable(LI->getFunction()),
15381538
"Load must have a loadable type");
15391539
require(LI->getOperand()->getType().isAddress(),
15401540
"Load operand must be an address");
@@ -1573,7 +1573,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
15731573
"Inst with qualified ownership in a function that is not qualified");
15741574
require(LBI->getType().isObject(), "Result of load must be an object");
15751575
require(!fnConv.useLoweredAddresses()
1576-
|| LBI->getType().isLoadable(LBI->getModule()),
1576+
|| LBI->getType().isLoadable(LBI->getFunction()),
15771577
"Load must have a loadable type");
15781578
require(LBI->getOperand()->getType().isAddress(),
15791579
"Load operand must be an address");
@@ -1691,7 +1691,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
16911691
require(SI->getSrc()->getType().isObject(),
16921692
"Can't store from an address source");
16931693
require(!fnConv.useLoweredAddresses()
1694-
|| SI->getSrc()->getType().isLoadable(SI->getModule()),
1694+
|| SI->getSrc()->getType().isLoadable(SI->getFunction()),
16951695
"Can't store a non loadable type");
16961696
require(SI->getDest()->getType().isAddress(),
16971697
"Must store to an address dest");

0 commit comments

Comments
 (0)