Skip to content

Commit 5ccc4cd

Browse files
committed
SIL function can be serialized with different kinds: [serialized] or
[serialized_for_package] if Package CMO is enabled. The latter kind allows a function to be serialized even if it contains loadable types, if Package CMO is enabled. Renamed IsSerialized_t as SerializedKind_t. The tri-state serialization kind requires validating inlinability depending on the serialization kinds of callee vs caller; e.g. if the callee is [serialized_for_package], the caller must be _not_ [serialized]. Renamed `hasValidLinkageForFragileInline` as `canBeInlinedIntoCaller` that takes in its caller's SerializedKind as an argument. Another argument `assumeFragileCaller` is also added to ensure that the calle sites of this function know the caller is serialized unless it's called for SIL inlining optimization passes. The [serialized_for_package] attribute is allowed for SIL function, global var, v-table, and witness-table. Resolves rdar://128406520
1 parent 0f332e1 commit 5ccc4cd

File tree

71 files changed

+1182
-682
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1182
-682
lines changed

include/swift/SIL/GenericSpecializationMangler.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class SpecializationMangler : public Mangle::ASTMangler {
3737
/// The specialization pass.
3838
SpecializationPass Pass;
3939

40-
IsSerialized_t Serialized;
40+
swift::SerializedKind_t Serialized;
4141

4242
/// The original function which is specialized.
4343
SILFunction *Function;
@@ -50,12 +50,12 @@ class SpecializationMangler : public Mangle::ASTMangler {
5050
PossibleEffects RemovedEffects;
5151

5252
protected:
53-
SpecializationMangler(SpecializationPass P, IsSerialized_t Serialized,
53+
SpecializationMangler(SpecializationPass P, swift::SerializedKind_t Serialized,
5454
SILFunction *F)
5555
: Pass(P), Serialized(Serialized), Function(F),
5656
ArgOpBuffer(ArgOpStorage) {}
5757

58-
SpecializationMangler(SpecializationPass P, IsSerialized_t Serialized,
58+
SpecializationMangler(SpecializationPass P, swift::SerializedKind_t Serialized,
5959
std::string functionName)
6060
: Pass(P), Serialized(Serialized), Function(nullptr),
6161
FunctionName(functionName), ArgOpBuffer(ArgOpStorage) {}
@@ -88,7 +88,7 @@ class GenericSpecializationMangler : public SpecializationMangler {
8888
SubstitutionMap subs);
8989

9090
public:
91-
GenericSpecializationMangler(SILFunction *F, IsSerialized_t Serialized)
91+
GenericSpecializationMangler(SILFunction *F, swift::SerializedKind_t Serialized)
9292
: SpecializationMangler(SpecializationPass::GenericSpecializer,
9393
Serialized, F) {}
9494

include/swift/SIL/SILDeclRef.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ namespace swift {
4646
class EffectsAttr;
4747
class FileUnit;
4848
class SILFunctionType;
49-
enum IsSerialized_t : unsigned char;
49+
enum SerializedKind_t : uint8_t;
5050
enum class SubclassScope : unsigned char;
5151
class SILModule;
5252
class SILLocation;
@@ -384,7 +384,11 @@ struct SILDeclRef {
384384
/// True if the function should be treated as transparent.
385385
bool isTransparent() const;
386386
/// True if the function should have its body serialized.
387-
IsSerialized_t isSerialized() const;
387+
bool isSerialized() const;
388+
/// True if this function is neither [serialized] or [serialized_for_package].
389+
bool isNotSerialized() const;
390+
/// Returns IsNotSerialized, IsSerializedForPackage, or IsSerialized.
391+
SerializedKind_t getSerializedKind() const;
388392
/// True if the function has noinline attribute.
389393
bool isNoinline() const;
390394
/// True if the function has __always inline attribute.

include/swift/SIL/SILFunction.h

+52-31
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,7 @@ class SILFunction
364364
unsigned Transparent : 1;
365365

366366
/// The function's serialized attribute.
367-
bool Serialized : 1;
368-
369-
/// [serialized_for_package] attribute if package serialization
370-
/// is enabled.
371-
bool SerializedForPackage : 1;
367+
unsigned SerializedKind : 2;
372368

373369
/// Specifies if this function is a thunk or a reabstraction thunk.
374370
///
@@ -508,7 +504,7 @@ class SILFunction
508504
SILFunction(SILModule &module, SILLinkage linkage, StringRef mangledName,
509505
CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
510506
IsBare_t isBareSILFunction, IsTransparent_t isTrans,
511-
IsSerialized_t isSerialized, ProfileCounter entryCount,
507+
SerializedKind_t serializedKind, ProfileCounter entryCount,
512508
IsThunk_t isThunk, SubclassScope classSubclassScope,
513509
Inline_t inlineStrategy, EffectsKind E,
514510
const SILDebugScope *debugScope,
@@ -521,7 +517,7 @@ class SILFunction
521517
create(SILModule &M, SILLinkage linkage, StringRef name,
522518
CanSILFunctionType loweredType, GenericEnvironment *genericEnv,
523519
std::optional<SILLocation> loc, IsBare_t isBareSILFunction,
524-
IsTransparent_t isTrans, IsSerialized_t isSerialized,
520+
IsTransparent_t isTrans, SerializedKind_t serializedKind,
525521
ProfileCounter entryCount, IsDynamicallyReplaceable_t isDynamic,
526522
IsDistributed_t isDistributed,
527523
IsRuntimeAccessible_t isRuntimeAccessible,
@@ -534,7 +530,7 @@ class SILFunction
534530

535531
void init(SILLinkage Linkage, StringRef Name, CanSILFunctionType LoweredType,
536532
GenericEnvironment *genericEnv, IsBare_t isBareSILFunction,
537-
IsTransparent_t isTrans, IsSerialized_t isSerialized,
533+
IsTransparent_t isTrans, SerializedKind_t serializedKind,
538534
ProfileCounter entryCount, IsThunk_t isThunk,
539535
SubclassScope classSubclassScope, Inline_t inlineStrategy,
540536
EffectsKind E, const SILDebugScope *DebugScope,
@@ -877,13 +873,42 @@ class SILFunction
877873
/// Set the function's linkage attribute.
878874
void setLinkage(SILLinkage linkage) { Linkage = unsigned(linkage); }
879875

880-
/// Returns true if this function can be inlined into a fragile function
881-
/// body.
882-
bool hasValidLinkageForFragileInline() const { return isSerialized(); }
876+
/// Checks if this (callee) function body can be inlined into the caller
877+
/// by comparing their SerializedKind_t values.
878+
///
879+
/// If the \p assumeFragileCaller is true, the caller must be serialized,
880+
/// in which case the callee needs to be serialized also to be inlined.
881+
/// If both callee and caller are `not_serialized`, the callee can be inlined
882+
/// into the caller during SIL inlining passes even if it (and the caller)
883+
/// might contain private symbols. If this callee is `serialized_for_pkg`,
884+
/// it can only be referenced by a serialized caller but not inlined into
885+
/// it.
886+
///
887+
/// ```
888+
/// canInlineInto: Caller
889+
/// | not_serialized | serialized_for_pkg | serialized
890+
/// not_serialized | ok | no | no
891+
/// Callee serialized_for_pkg | ok | ok | no
892+
/// serialized | ok | ok | ok
893+
///
894+
/// ```
895+
///
896+
/// \p callerSerializedKind The caller's SerializedKind.
897+
/// \p assumeFragileCaller True if the call site of this function already
898+
/// knows that the caller is serialized.
899+
bool canBeInlinedIntoCaller(
900+
std::optional<SerializedKind_t> callerSerializedKind = std::nullopt,
901+
bool assumeFragileCaller = true) const;
883902

884903
/// Returns true if this function can be referenced from a fragile function
885904
/// body.
886-
bool hasValidLinkageForFragileRef() const;
905+
/// \p callerSerializedKind The caller's SerializedKind. Used to be passed to
906+
/// \c canBeInlinedIntoCaller.
907+
/// \p assumeFragileCaller Default to true since this function must be called
908+
// if the caller is [serialized].
909+
bool hasValidLinkageForFragileRef(
910+
std::optional<SerializedKind_t> callerSerializedKind = std::nullopt,
911+
bool assumeFragileCaller = true) const;
887912

888913
/// Get's the effective linkage which is used to derive the llvm linkage.
889914
/// Usually this is the same as getLinkage(), except in one case: if this
@@ -1137,28 +1162,24 @@ class SILFunction
11371162
assert(!Transparent || !IsDynamicReplaceable);
11381163
}
11391164

1140-
/// Get this function's serialized attribute.
1141-
IsSerialized_t isSerialized() const { return IsSerialized_t(Serialized); }
1142-
void setSerialized(IsSerialized_t isSerialized) {
1143-
Serialized = isSerialized;
1144-
assert(this->isSerialized() == isSerialized &&
1145-
"too few bits for Serialized storage");
1165+
bool isSerialized() const {
1166+
return SerializedKind_t(SerializedKind) == IsSerialized;
1167+
}
1168+
bool isSerializedForPackage() const {
1169+
return SerializedKind_t(SerializedKind) == IsSerializedForPackage;
1170+
}
1171+
bool isNotSerialized() const {
1172+
return SerializedKind_t(SerializedKind) == IsNotSerialized;
11461173
}
11471174

1148-
/// A [serialized_for_package] attribute is used to indicate that a function
1149-
/// is [serialized] because of package-cmo optimization.
1150-
/// Package-cmo allows serializing a function containing a loadable type in
1151-
/// a resiliently built module, which is normally illegal. During SIL deserialization,
1152-
/// this attribute can be used to check whether a loaded function that was serialized
1153-
/// can be allowed to have loadable types. This attribute is also used to determine
1154-
/// if a callee can be inlined into a caller that's serialized without package-cmo, for
1155-
/// example, by explicitly annotating the caller decl with `@inlinable`.
1156-
IsSerializedForPackage_t isSerializedForPackage() const {
1157-
return IsSerializedForPackage_t(SerializedForPackage);
1175+
/// Get this function's serialized attribute.
1176+
SerializedKind_t getSerializedKind() const {
1177+
return SerializedKind_t(SerializedKind);
11581178
}
1159-
void
1160-
setSerializedForPackage(IsSerializedForPackage_t isSerializedForPackage) {
1161-
SerializedForPackage = isSerializedForPackage;
1179+
void setSerializedKind(SerializedKind_t serializedKind) {
1180+
SerializedKind = serializedKind;
1181+
assert(this->getSerializedKind() == serializedKind &&
1182+
"too few bits for Serialized storage");
11621183
}
11631184

11641185
/// Get this function's thunk attribute.

include/swift/SIL/SILFunctionBuilder.h

+9-14
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,19 @@ class SILFunctionBuilder {
6060

6161
/// Return the declaration of a utility function that can, but needn't, be
6262
/// shared between different parts of a program.
63-
SILFunction *getOrCreateSharedFunction(SILLocation loc, StringRef name,
64-
CanSILFunctionType type,
65-
IsBare_t isBareSILFunction,
66-
IsTransparent_t isTransparent,
67-
IsSerialized_t isSerialized,
68-
ProfileCounter entryCount,
69-
IsThunk_t isThunk,
70-
IsDynamicallyReplaceable_t isDynamic,
71-
IsDistributed_t isDistributed,
72-
IsRuntimeAccessible_t isRuntimeAccessible);
63+
SILFunction *getOrCreateSharedFunction(
64+
SILLocation loc, StringRef name, CanSILFunctionType type,
65+
IsBare_t isBareSILFunction, IsTransparent_t isTransparent,
66+
SerializedKind_t serializedKind, ProfileCounter entryCount,
67+
IsThunk_t isThunk, IsDynamicallyReplaceable_t isDynamic,
68+
IsDistributed_t isDistributed, IsRuntimeAccessible_t isRuntimeAccessible);
7369

7470
/// Return the declaration of a function, or create it if it doesn't exist.
7571
SILFunction *getOrCreateFunction(
7672
SILLocation loc, StringRef name, SILLinkage linkage,
7773
CanSILFunctionType type, IsBare_t isBareSILFunction,
78-
IsTransparent_t isTransparent, IsSerialized_t isSerialized,
79-
IsDynamicallyReplaceable_t isDynamic,
80-
IsDistributed_t isDistributed,
74+
IsTransparent_t isTransparent, SerializedKind_t serializedKind,
75+
IsDynamicallyReplaceable_t isDynamic, IsDistributed_t isDistributed,
8176
IsRuntimeAccessible_t isRuntimeAccessible,
8277
ProfileCounter entryCount = ProfileCounter(),
8378
IsThunk_t isThunk = IsNotThunk,
@@ -104,7 +99,7 @@ class SILFunctionBuilder {
10499
SILLinkage linkage, StringRef name, CanSILFunctionType loweredType,
105100
GenericEnvironment *genericEnv, std::optional<SILLocation> loc,
106101
IsBare_t isBareSILFunction, IsTransparent_t isTrans,
107-
IsSerialized_t isSerialized, IsDynamicallyReplaceable_t isDynamic,
102+
SerializedKind_t serializedKind, IsDynamicallyReplaceable_t isDynamic,
108103
IsDistributed_t isDistributed, IsRuntimeAccessible_t isRuntimeAccessible,
109104
ProfileCounter entryCount = ProfileCounter(),
110105
IsThunk_t isThunk = IsNotThunk,

include/swift/SIL/SILGlobalVariable.h

+14-6
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class SILGlobalVariable
6969
/// The global variable's serialized attribute.
7070
/// Serialized means that the variable can be "inlined" into another module.
7171
/// Currently this flag is set for all global variables in the stdlib.
72-
unsigned Serialized : 1;
72+
unsigned Serialized : 2;
7373

7474
/// Whether this is a 'let' property, which can only be initialized
7575
/// once (either in its declaration, or once later), making it immutable.
@@ -97,7 +97,7 @@ class SILGlobalVariable
9797
SILBasicBlock StaticInitializerBlock;
9898

9999
SILGlobalVariable(SILModule &M, SILLinkage linkage,
100-
IsSerialized_t IsSerialized, StringRef mangledName,
100+
SerializedKind_t serializedKind, StringRef mangledName,
101101
SILType loweredType, std::optional<SILLocation> loc,
102102
VarDecl *decl);
103103

@@ -107,7 +107,7 @@ class SILGlobalVariable
107107
}
108108

109109
static SILGlobalVariable *
110-
create(SILModule &Module, SILLinkage Linkage, IsSerialized_t IsSerialized,
110+
create(SILModule &Module, SILLinkage Linkage, SerializedKind_t serializedKind,
111111
StringRef MangledName, SILType LoweredType,
112112
std::optional<SILLocation> Loc = std::nullopt,
113113
VarDecl *Decl = nullptr);
@@ -151,10 +151,18 @@ class SILGlobalVariable
151151
/// potentially be inspected by the debugger.
152152
bool shouldBePreservedForDebugger() const;
153153

154+
/// Check if this global variable is [serialized]. This does not check
155+
/// if it's [serialized_for_package].
156+
bool isSerialized() const;
157+
/// Check if this global variable is [serialized_for_package].
158+
bool isSerializedForPackage() const;
159+
/// Checks whether this global var is neither [serialized] nor
160+
/// [serialized_for_package].
161+
bool isNotSerialized() const;
154162
/// Get this global variable's serialized attribute.
155-
IsSerialized_t isSerialized() const;
156-
void setSerialized(IsSerialized_t isSerialized);
157-
163+
SerializedKind_t getSerializedKind() const;
164+
void setSerializedKind(SerializedKind_t isSerialized);
165+
158166
/// Is this an immutable 'let' property?
159167
bool isLet() const { return IsLet; }
160168
void setLet(bool isLet) { IsLet = isLet; }

include/swift/SIL/SILLinkage.h

+19-9
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ enum {
141141
/// After the swiftmodule file is written, the IsSerialized flag is cleared from
142142
/// all functions. This means that optimizations after the serialization point
143143
/// are not limited anymore regarding serialized functions.
144-
enum IsSerialized_t : unsigned char {
144+
enum SerializedKind_t : uint8_t {
145145

146146
/// The function is not inlinable and will not be serialized.
147147
IsNotSerialized,
@@ -151,19 +151,29 @@ enum IsSerialized_t : unsigned char {
151151
/// This flag is only valid for Public, PublicNonABI, PublicExternal,
152152
/// HiddenExternal and Shared functions.
153153
/// Functions with external linkage (PublicExternal, HiddenExternal) will not
154-
/// be serialized, because they are available in a different module (from which
155-
/// they were de-serialized).
154+
/// be serialized, because they are available in a different module (from
155+
/// which they were de-serialized).
156156
///
157-
/// Functions with Shared linkage will only be serialized if they are referenced
158-
/// from another serialized function (or table).
157+
/// Functions with Shared linkage will only be serialized if they are
158+
/// referenced from another serialized function (or table).
159159
///
160160
/// This flag is removed from all functions after the serialization point in
161161
/// the optimizer pipeline.
162-
IsSerialized
163-
};
162+
IsSerialized,
164163

165-
enum IsSerializedForPackage_t : unsigned char {
166-
IsNotSerializedForPackage,
164+
/// This flag is valid for all linkages applicable to IsSerialized as well as
165+
/// Package, PackageNonABI, and PackageExternal, if package-wide
166+
/// serialization is enabled with Package-CMO optimization.
167+
///
168+
/// The [serialized_for_package] attribute is used to indicate that a function
169+
/// is serialized because of Package CMO, which allows loadable types in a
170+
/// serialized function in a resiliently built module, which is otherwise illegal.
171+
/// It's also used to determine during SIL deserialization whether loadable
172+
/// types in a serialized function can be allowed in the client module that
173+
/// imports the module built with Package CMO. If the client contains a [serialized]
174+
/// function due to `@inlinable`, funtions with [serialized_for_package] from
175+
/// the imported module are not allowed being inlined into the client function,
176+
/// which is the correct behavior.
167177
IsSerializedForPackage
168178
};
169179

include/swift/SIL/SILMoveOnlyDeinit.h

+12-9
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
namespace swift {
3131

32-
enum IsSerialized_t : unsigned char;
32+
enum SerializedKind_t : uint8_t;
3333
class SILFunction;
3434
class SILModule;
3535

@@ -45,18 +45,18 @@ class SILMoveOnlyDeinit final : public SILAllocated<SILMoveOnlyDeinit> {
4545
/// Whether or not this deinit table is serialized. If a deinit is not
4646
/// serialized, then other modules can not consume directly a move only type
4747
/// since the deinit can not be called directly.
48-
bool serialized : 1;
48+
unsigned serialized : 2;
4949

5050
SILMoveOnlyDeinit()
51-
: nominalDecl(nullptr), funcImpl(nullptr), serialized(false) {}
51+
: nominalDecl(nullptr), funcImpl(nullptr), serialized(unsigned(IsNotSerialized)) {}
5252

5353
SILMoveOnlyDeinit(NominalTypeDecl *nominaldecl, SILFunction *implementation,
54-
bool serialized);
54+
unsigned serialized);
5555
~SILMoveOnlyDeinit();
5656

5757
public:
5858
static SILMoveOnlyDeinit *create(SILModule &mod, NominalTypeDecl *nominalDecl,
59-
IsSerialized_t serialized,
59+
SerializedKind_t serialized,
6060
SILFunction *funcImpl);
6161

6262
NominalTypeDecl *getNominalDecl() const { return nominalDecl; }
@@ -66,11 +66,14 @@ class SILMoveOnlyDeinit final : public SILAllocated<SILMoveOnlyDeinit> {
6666
return funcImpl;
6767
}
6868

69-
IsSerialized_t isSerialized() const {
70-
return serialized ? IsSerialized : IsNotSerialized;
69+
bool isNotSerialized() const {
70+
return SerializedKind_t(serialized) == IsNotSerialized;
7171
}
72-
void setSerialized(IsSerialized_t inputSerialized) {
73-
serialized = inputSerialized ? 1 : 0;
72+
SerializedKind_t getSerializedKind() const {
73+
return SerializedKind_t(serialized);
74+
}
75+
void setSerializedKind(SerializedKind_t inputSerialized) {
76+
serialized = unsigned(inputSerialized);
7477
}
7578

7679
void print(llvm::raw_ostream &os, bool verbose) const;

0 commit comments

Comments
 (0)