Skip to content

Stabilize and simplify SIL linkage and serialization #41703

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions include/swift/SIL/SILFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ class SILFunction
unsigned Transparent : 1;

/// The function's serialized attribute.
unsigned Serialized : 2;
bool Serialized : 1;

/// Specifies if this function is a thunk or a reabstraction thunk.
///
Expand Down Expand Up @@ -689,10 +689,7 @@ class SILFunction

/// Returns true if this function can be inlined into a fragile function
/// body.
bool hasValidLinkageForFragileInline() const {
return (isSerialized() == IsSerialized ||
isSerialized() == IsSerializable);
}
bool hasValidLinkageForFragileInline() const { return isSerialized(); }

/// Returns true if this function can be referenced from a fragile function
/// body.
Expand Down Expand Up @@ -914,7 +911,11 @@ class SILFunction

/// Get this function's serialized attribute.
IsSerialized_t isSerialized() const { return IsSerialized_t(Serialized); }
void setSerialized(IsSerialized_t isSerialized) { Serialized = isSerialized; }
void setSerialized(IsSerialized_t isSerialized) {
Serialized = isSerialized;
assert(this->isSerialized() == isSerialized &&
"too few bits for Serialized storage");
}

/// Get this function's thunk attribute.
IsThunk_t isThunk() const { return IsThunk_t(Thunk); }
Expand Down
78 changes: 55 additions & 23 deletions include/swift/SIL/SILLinkage.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,51 @@ enum class SILLinkage : uint8_t {
/// This object definition is visible to multiple Swift modules (and
/// thus potentially across linkage-unit boundaries). There are no
/// other object definitions with this name in the program.
///
/// Public functions must be definitions, i.e. must have a body, except the
/// body is emitted by clang.
Public,

/// This is a special linkage used for symbols which are treated
/// as public for the purposes of SIL serialization and optimization,
/// but do not have public entry points in the generated binary.
///
/// This linkage is used for @_alwaysEmitIntoClient functions.
///
/// There is no external variant of this linkage, because from other
/// translation units in the same module, this behaves identically
/// to the HiddenExternal linkage.
///
/// When deserialized, such declarations receive Shared linkage.
///
/// PublicNonABI functions must be definitions.
PublicNonABI,

/// This object definition is visible only to the current Swift
/// module (and thus should not be visible across linkage-unit
/// boundaries). There are no other object definitions with this
/// name in the module.
///
/// Hidden functions must be definitions, i.e. must have a body, except the
/// body is emitted by clang.
Hidden,

/// This object definition is visible only within a single Swift
/// module. There may be other object definitions with this name in
/// the module; those definitions are all guaranteed to be
/// semantically equivalent to this one.
///
/// This linkage is used e.g. for thunks and for specialized functions.
///
/// Public functions must be definitions, i.e. must have a body, except the
/// body is emitted by clang.
Shared,

/// This object definition is visible only within a single Swift
/// file.
///
/// Private functions must be definitions, i.e. must have a body, except the
/// body is emitted by clang.
Private,

/// A Public definition with the same name as this object will be
Expand All @@ -74,17 +92,12 @@ enum class SILLinkage : uint8_t {
PublicExternal,

/// A Public or Hidden definition with the same name as this object
/// will be defined by the current Swift module at runtime. If this
/// object is a definition, it is semantically equivalent to that
/// definition.
/// will be defined by the current Swift module at runtime.
///
/// This linkage is only used for non-whole-module compilations to refer to
/// functions in other files of the same module.
HiddenExternal,

/// This Shared definition was imported from another module. It is not
/// necessary to serialize it since it can be deserialized from the original
/// module. Besides that caveat this should be treated exactly the same as
/// shared.
SharedExternal,

/// The default linkage for a definition.
DefaultForDefinition = Public,

Expand All @@ -97,14 +110,40 @@ enum {
NumSILLinkageBits = 4
};

/// Related to linkage: flag if a function or global variable is serialized,
/// either unconditionally, or if referenced from another serialized function.
/// Related to linkage: flag if a function, global variable, vtable or witness
/// table is serialized.
///
/// Used, e.g. for @inlinable functions.
///
/// This flag serves for two purposes:
/// * Imposes restrictions for optimizations. For example, non-serialized functions
/// cannot be inlined into serialized functions, because that could expose
/// internal types/functions to client modules.
/// * Tells the serializer which functions (and tables) need to be serialized:
/// - all public functions with the IsSerialized flag and
/// - all IsSerialized shared functions which are referenced from such functions.
///
/// After the swiftmodule file is written, the IsSerialized flag is cleared from
/// all functions. This means that optimizations after the serialization point
/// are not limited anymore regarding serialized functions.
enum IsSerialized_t : unsigned char {
// Never serialized.

/// The function is not inlinable and will not be serialized.
IsNotSerialized,
// Serialized if referenced from another serialized function.
IsSerializable,
// Always serialized.

/// The function (or table) will be serialized.
///
/// This flag is only valid for Public, PublicNonABI, PublicExternal,
/// HiddenExternal and Shared functions.
/// Functions with external linkage (PublicExternl, HiddenExternal) will not
/// be serialized, because they are available in a different module (from which
/// they were de-serialized).
///
/// Functions with Shared linkage will only be serialized if they are referenced
/// from another serialized function (or table).
///
/// This flag is removed from all functions after the serialization point in
/// the optimizer pipeline.
IsSerialized
};

Expand All @@ -131,8 +170,6 @@ inline SILLinkage stripExternalFromLinkage(SILLinkage linkage) {
return SILLinkage::Public;
if (linkage == SILLinkage::HiddenExternal)
return SILLinkage::Hidden;
if (linkage == SILLinkage::SharedExternal)
return SILLinkage::Shared;
return linkage;
}

Expand All @@ -146,13 +183,11 @@ inline SILLinkage addExternalToLinkage(SILLinkage linkage) {
// if the function was emitted in another translation unit of the
// same Swift module, so we treat it as hidden here.
return SILLinkage::HiddenExternal;
case SILLinkage::Shared:
return SILLinkage::SharedExternal;
case SILLinkage::Hidden:
return SILLinkage::HiddenExternal;
case SILLinkage::Shared:
case SILLinkage::Private:
case SILLinkage::PublicExternal:
case SILLinkage::SharedExternal:
case SILLinkage::HiddenExternal:
return linkage;
}
Expand Down Expand Up @@ -186,7 +221,6 @@ inline bool hasPublicVisibility(SILLinkage linkage) {
return true;
case SILLinkage::Hidden:
case SILLinkage::Shared:
case SILLinkage::SharedExternal:
case SILLinkage::Private:
case SILLinkage::HiddenExternal:
return false;
Expand All @@ -198,7 +232,6 @@ inline bool hasPublicVisibility(SILLinkage linkage) {
inline bool hasSharedVisibility(SILLinkage linkage) {
switch (linkage) {
case SILLinkage::Shared:
case SILLinkage::SharedExternal:
return true;
case SILLinkage::Public:
case SILLinkage::PublicExternal:
Expand All @@ -222,7 +255,6 @@ inline bool hasPrivateVisibility(SILLinkage linkage) {
case SILLinkage::Hidden:
case SILLinkage::HiddenExternal:
case SILLinkage::Shared:
case SILLinkage::SharedExternal:
return false;
}

Expand Down
52 changes: 31 additions & 21 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ class SILModule {
llvm::DenseMap<const SILBasicBlock *, std::string>;

enum class LinkingMode : uint8_t {
/// Link functions with non-public linkage. Used by the mandatory pipeline.
/// Link functions with shared linkage. Used by the mandatory pipeline.
LinkNormal,

/// Link all functions. Used by the performance pipeine.
Expand Down Expand Up @@ -349,6 +349,8 @@ class SILModule {
/// to ensure that the module is serialized only once.
bool serialized;

bool parsedAsSerializedSIL;

/// Set if we have registered a deserialization notification handler for
/// lowering ownership in non transparent functions.
/// This gets set in NonTransparent OwnershipModelEliminator pass.
Expand Down Expand Up @@ -455,6 +457,12 @@ class SILModule {
void setSerialized() { serialized = true; }
bool isSerialized() const { return serialized; }

void setParsedAsSerializedSIL() {
serialized = true;
parsedAsSerializedSIL = true;
}
bool isParsedAsSerializedSIL() const { return parsedAsSerializedSIL; }

void setBasicBlockName(const SILBasicBlock *block, StringRef name) {
#ifndef NDEBUG
basicBlockNames[block] = name.str();
Expand Down Expand Up @@ -688,9 +696,20 @@ class SILModule {
/// \return null if this module has no such function
SILFunction *lookUpFunction(SILDeclRef fnRef);

/// Attempt to deserialize the SILFunction. Returns true if deserialization
/// succeeded, false otherwise.
bool loadFunction(SILFunction *F);
/// Attempt to deserialize function \p F and all functions which are referenced
/// from \p F (according to the \p LinkMode).
///
/// Returns true if deserialization succeeded, false otherwise.
bool loadFunction(SILFunction *F, LinkingMode LinkMode);

/// Attempt to deserialize a function with \p name and all functions which are
/// referenced from that function (according to the \p LinkMode).
///
/// If \p linkage is provided, the deserialized function is required to have
/// that linkage. Returns null, if this is not the case.
SILFunction *loadFunction(StringRef name,
LinkingMode LinkMode,
Optional<SILLinkage> linkage = None);

/// Update the linkage of the SILFunction with the linkage of the serialized
/// function.
Expand All @@ -699,19 +718,10 @@ class SILModule {
/// AST, e.g. cross-module-optimization can change the SIL linkages.
void updateFunctionLinkage(SILFunction *F);

/// Attempt to link the SILFunction. Returns true if linking succeeded, false
/// otherwise.
///
/// \return false if the linking failed.
bool linkFunction(SILFunction *F,
LinkingMode LinkMode = LinkingMode::LinkNormal);

/// Check if a given function exists in any of the modules with a
/// required linkage, i.e. it can be linked by linkFunction.
/// Attempt to deserialize function \p F and all required referenced functions.
///
/// \return null if this module has no such function. Otherwise
/// the declaration of a function.
SILFunction *findFunction(StringRef Name, SILLinkage Linkage);
/// Returns true if linking succeeded, false otherwise.
bool linkFunction(SILFunction *F, LinkingMode LinkMode);

/// Check if a given function exists in any of the modules.
/// i.e. it can be linked by linkFunction.
Expand All @@ -725,15 +735,15 @@ class SILModule {
/// table.
/// \arg deserializeLazily If we cannot find the witness table should we
/// attempt to lazily deserialize it.
SILWitnessTable *
lookUpWitnessTable(ProtocolConformanceRef C, bool deserializeLazily=true);
SILWitnessTable *
lookUpWitnessTable(const ProtocolConformance *C, bool deserializeLazily=true);
SILWitnessTable *lookUpWitnessTable(const ProtocolConformance *C);

/// Attempt to lookup \p Member in the witness table for \p C.
///
/// Also, deserialize all referenced functions according to the \p linkgingMode.
std::pair<SILFunction *, SILWitnessTable *>
lookUpFunctionInWitnessTable(ProtocolConformanceRef C,
SILDeclRef Requirement);
SILDeclRef Requirement,
SILModule::LinkingMode linkingMode);

/// Look up the SILDefaultWitnessTable representing the default witnesses
/// of a resilient protocol, if any.
Expand Down
1 change: 0 additions & 1 deletion include/swift/SIL/SILVTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ class SILVTable final : public SILAllocated<SILVTable>,

/// Sets the serialized flag.
void setSerialized(IsSerialized_t serialized) {
assert(serialized != IsSerializable);
Serialized = (serialized ? 1 : 0);
}

Expand Down
1 change: 0 additions & 1 deletion include/swift/SIL/SILWitnessTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,

/// Sets the serialized flag.
void setSerialized(IsSerialized_t serialized) {
assert(serialized != IsSerializable);
Serialized = (serialized ? 1 : 0);
}

Expand Down
4 changes: 1 addition & 3 deletions include/swift/Serialization/SerializedSILLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ class SerializedSILLoader {
~SerializedSILLoader();

SILFunction *lookupSILFunction(SILFunction *Callee, bool onlyUpdateLinkage);
SILFunction *
lookupSILFunction(StringRef Name, bool declarationOnly = false,
Optional<SILLinkage> linkage = None);
SILFunction *lookupSILFunction(StringRef Name, Optional<SILLinkage> linkage);
bool hasSILFunction(StringRef Name, Optional<SILLinkage> linkage = None);
SILVTable *lookupVTable(const ClassDecl *C);
SILWitnessTable *lookupWitnessTable(SILWitnessTable *C);
Expand Down
1 change: 0 additions & 1 deletion lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2106,7 +2106,6 @@ getIRLinkage(const UniversalLinkageInfo &info, SILLinkage linkage,
: RESULT(External, Hidden, Default);

case SILLinkage::Shared:
case SILLinkage::SharedExternal:
return isDefinition ? RESULT(LinkOnceODR, Hidden, Default)
: RESULT(External, Hidden, Default);

Expand Down
1 change: 0 additions & 1 deletion lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2080,7 +2080,6 @@ namespace {
return true;

case SILLinkage::Shared:
case SILLinkage::SharedExternal:
case SILLinkage::PublicNonABI:
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1152,7 +1152,7 @@ bool IRGenerator::canEmitWitnessTableLazily(SILWitnessTable *wt) {
}

void IRGenerator::addLazyWitnessTable(const ProtocolConformance *Conf) {
if (auto *wt = SIL.lookUpWitnessTable(Conf, /*deserializeLazily=*/false)) {
if (auto *wt = SIL.lookUpWitnessTable(Conf)) {
// Add it to the queue if it hasn't already been put there.
if (canEmitWitnessTableLazily(wt) &&
LazilyEmittedWitnessTables.insert(wt).second) {
Expand Down
Loading