Skip to content
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
61 changes: 44 additions & 17 deletions include/swift/SIL/SILLinkage.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ enum class SILLinkage : unsigned char {
/// other object definitions with this name in the program.
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.
///
/// 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,

/// 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
Expand Down Expand Up @@ -83,7 +94,7 @@ enum class SILLinkage : unsigned char {

enum {
/// The number of bits required to store a SILLinkage value.
NumSILLinkageBits = 3
NumSILLinkageBits = 4
};

/// Related to linkage: flag if a function or global variable is serialized,
Expand Down Expand Up @@ -125,15 +136,28 @@ inline SILLinkage stripExternalFromLinkage(SILLinkage linkage) {

/// Add the 'external' attribute to \p linkage.
inline SILLinkage addExternalToLinkage(SILLinkage linkage) {
if (linkage == SILLinkage::Public)
switch (linkage) {
case SILLinkage::Public:
return SILLinkage::PublicExternal;
if (linkage == SILLinkage::Hidden)
case SILLinkage::PublicNonABI:
// An external reference to a public non-ABI function is only valid
// if the function was emitted in another translation unit of the
// same Swift module, so we treat it as hidden here.
return SILLinkage::HiddenExternal;
if (linkage == SILLinkage::Shared)
case SILLinkage::Shared:
return SILLinkage::SharedExternal;
if (linkage == SILLinkage::Private)
case SILLinkage::Hidden:
return SILLinkage::HiddenExternal;
case SILLinkage::Private:
return SILLinkage::PrivateExternal;
return linkage;
case SILLinkage::PublicExternal:
case SILLinkage::SharedExternal:
case SILLinkage::PrivateExternal:
case SILLinkage::HiddenExternal:
return linkage;
}

llvm_unreachable("Unhandled SILLinkage in switch.");
}

/// Return whether the linkage indicates that an object has a
Expand All @@ -147,23 +171,24 @@ inline bool isAvailableExternally(SILLinkage linkage) {
/// If \p is true then we are in whole-module compilation.
inline bool isPossiblyUsedExternally(SILLinkage linkage, bool wholeModule) {
if (wholeModule) {
return linkage <= SILLinkage::Public;
return linkage <= SILLinkage::PublicNonABI;
}
return linkage <= SILLinkage::Hidden;
}

inline bool hasPublicVisibility(SILLinkage linkage) {
switch (linkage) {
case SILLinkage::Public:
case SILLinkage::PublicExternal:
return true;
case SILLinkage::Hidden:
case SILLinkage::Shared:
case SILLinkage::SharedExternal:
case SILLinkage::Private:
case SILLinkage::PrivateExternal:
case SILLinkage::HiddenExternal:
return false;
case SILLinkage::Public:
case SILLinkage::PublicExternal:
case SILLinkage::PublicNonABI:
return true;
case SILLinkage::Hidden:
case SILLinkage::Shared:
case SILLinkage::SharedExternal:
case SILLinkage::Private:
case SILLinkage::PrivateExternal:
case SILLinkage::HiddenExternal:
return false;
}

llvm_unreachable("Unhandled SILLinkage in switch.");
Expand All @@ -176,6 +201,7 @@ inline bool hasSharedVisibility(SILLinkage linkage) {
return true;
case SILLinkage::Public:
case SILLinkage::PublicExternal:
case SILLinkage::PublicNonABI:
case SILLinkage::Hidden:
case SILLinkage::HiddenExternal:
case SILLinkage::Private:
Expand All @@ -193,6 +219,7 @@ inline bool hasPrivateVisibility(SILLinkage linkage) {
return true;
case SILLinkage::Public:
case SILLinkage::PublicExternal:
case SILLinkage::PublicNonABI:
case SILLinkage::Hidden:
case SILLinkage::HiddenExternal:
case SILLinkage::Shared:
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
const uint16_t VERSION_MINOR = 392; // Last change: accessor decls
const uint16_t VERSION_MINOR = 393; // SILLinkage::PublicNonABI

using DeclIDField = BCFixed<31>;

Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1478,6 +1478,7 @@ getIRLinkage(const UniversalLinkageInfo &info, SILLinkage linkage,
: RESULT(External, Hidden, Default);

case SILLinkage::Hidden:
case SILLinkage::PublicNonABI:
return RESULT(External, Hidden, Default);

case SILLinkage::Private: {
Expand Down
1 change: 1 addition & 0 deletions lib/ParseSIL/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ static bool parseSILLinkage(Optional<SILLinkage> &Result, Parser &P) {

// Then use a string switch to try and parse the identifier.
Result = llvm::StringSwitch<Optional<SILLinkage>>(P.Tok.getText())
.Case("non_abi", SILLinkage::PublicNonABI)
.Case("hidden", SILLinkage::Hidden)
.Case("shared", SILLinkage::Shared)
.Case("public_external", SILLinkage::PublicExternal)
Expand Down
17 changes: 11 additions & 6 deletions lib/SIL/SILDeclRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,13 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const {
if (isClangImported())
return SILLinkage::Shared;

// Default argument generators of Public functions have PublicNonABI linkage
// if the function was type-checked in Swift 4 mode.
if (kind == SILDeclRef::Kind::DefaultArgGenerator) {
if (isSerialized())
return maybeAddExternal(SILLinkage::PublicNonABI);
}

bool neverPublic = false;

// ivar initializers and destroyers are completely contained within the class
Expand All @@ -281,15 +288,13 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const {

// Stored property initializers get the linkage of their containing type.
if (isStoredPropertyInitializer()) {
// If the property is public, the initializer needs to be public, because
// it might be referenced from an inlineable initializer.
// If the type is public, the property initializer is referenced from
// inlinable initializers, and has PublicNonABI linkage.
//
// Note that we don't serialize the presence of an initializer, so there's
// no way to reference one from another module except for this case.
//
// This is silly, and we need a proper resilience story here.
if (d->getEffectiveAccess() == AccessLevel::Public)
return maybeAddExternal(SILLinkage::Public);
if (isSerialized())
return maybeAddExternal(SILLinkage::PublicNonABI);

// Otherwise, use the visibility of the type itself, because even if the
// property is private, we might reference the initializer from another
Expand Down
10 changes: 8 additions & 2 deletions lib/SIL/SILModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,21 @@ class SILModule::SerializationCallback : public SerializedSILLoader::Callback {
case SILLinkage::Public:
decl->setLinkage(SILLinkage::PublicExternal);
return;
case SILLinkage::PublicNonABI:
// PublicNonABI functions receive SharedExternal linkage, so that
// they have "link once" semantics when deserialized by multiple
// translation units in the same Swift module.
decl->setLinkage(SILLinkage::SharedExternal);
return;
case SILLinkage::Hidden:
decl->setLinkage(SILLinkage::HiddenExternal);
return;
case SILLinkage::Shared:
decl->setLinkage(SILLinkage::SharedExternal);
return;
case SILLinkage::Private:
decl->setLinkage(SILLinkage::PrivateExternal);
return;
decl->setLinkage(SILLinkage::PrivateExternal);
return;
case SILLinkage::PublicExternal:
case SILLinkage::HiddenExternal:
case SILLinkage::SharedExternal:
Expand Down
1 change: 1 addition & 0 deletions lib/SIL/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2192,6 +2192,7 @@ void SILFunction::dump(const char *FileName) const {
static StringRef getLinkageString(SILLinkage linkage) {
switch (linkage) {
case SILLinkage::Public: return "public ";
case SILLinkage::PublicNonABI: return "non_abi ";
case SILLinkage::Hidden: return "hidden ";
case SILLinkage::Shared: return "shared ";
case SILLinkage::Private: return "private ";
Expand Down
83 changes: 43 additions & 40 deletions lib/SILOptimizer/IPO/GlobalOpt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,16 +225,46 @@ static std::string mangleGetter(VarDecl *varDecl) {
return Mangler.mangleGlobalGetterEntity(varDecl);
}

static SILFunction *getGlobalGetterFunction(SILModule &M,
SILLocation loc,
VarDecl *varDecl) {
auto getterName = mangleGetter(varDecl);

// Check if a getter was generated already.
if (auto *F = M.lookUpFunction(getterName))
return F;

auto Linkage = (varDecl->getEffectiveAccess() >= AccessLevel::Public
? SILLinkage::PublicNonABI
: SILLinkage::Private);
auto Serialized = (varDecl->getEffectiveAccess() >= AccessLevel::Public
? IsSerialized
: IsNotSerialized);

auto refType = M.Types.getLoweredType(varDecl->getInterfaceType());

// Function takes no arguments and returns refType
SILResultInfo Results[] = { SILResultInfo(refType.getSwiftRValueType(),
ResultConvention::Owned) };
SILFunctionType::ExtInfo EInfo;
EInfo = EInfo.withRepresentation(SILFunctionType::Representation::Thin);
auto LoweredType =
SILFunctionType::get(nullptr, EInfo,
SILCoroutineKind::None,
ParameterConvention::Direct_Unowned,
/*params*/ {}, /*yields*/ {}, Results, None,
M.getASTContext());

return M.getOrCreateFunction(
loc, getterName, Linkage, LoweredType,
IsBare, IsNotTransparent, Serialized);
}

/// Generate getter from the initialization code whose
/// result is stored by a given store instruction.
static SILFunction *genGetterFromInit(StoreInst *Store,
SILGlobalVariable *SILG) {
auto *varDecl = SILG->getDecl();
auto getterName = mangleGetter(varDecl);

// Check if a getter was generated already.
if (auto *F = Store->getModule().lookUpFunction(getterName))
return F;

// Find the code that performs the initialization first.
// Recursively walk the SIL value being assigned to the SILG.
Expand All @@ -253,25 +283,15 @@ static SILFunction *genGetterFromInit(StoreInst *Store,
Insns.push_back(ReverseInsns.pop_back_val());
}

// Generate a getter from the global init function without side-effects.
auto refType = varDecl->getInterfaceType()->getCanonicalType();
// Function takes no arguments and returns refType
SILResultInfo Results[] = { SILResultInfo(refType, ResultConvention::Owned) };
SILFunctionType::ExtInfo EInfo;
EInfo = EInfo.withRepresentation(SILFunctionType::Representation::Thin);
auto LoweredType = SILFunctionType::get(nullptr, EInfo,
SILCoroutineKind::None, ParameterConvention::Direct_Owned,
/*params*/ {}, /*yields*/ {}, Results, None,
Store->getModule().getASTContext());
auto *GetterF = Store->getModule().getOrCreateFunction(
Store->getLoc(),
getterName, SILLinkage::Private, LoweredType,
IsBare_t::IsBare, IsTransparent_t::IsNotTransparent,
IsSerialized_t::IsSerialized);
auto *GetterF = getGlobalGetterFunction(Store->getModule(),
Store->getLoc(),
varDecl);

GetterF->setDebugScope(Store->getFunction()->getDebugScope());
if (!Store->getFunction()->hasQualifiedOwnership())
GetterF->setUnqualifiedOwnership();
auto *EntryBB = GetterF->createBasicBlock();

// Copy instructions into GetterF
InstructionsCloner Cloner(*GetterF, Insns, EntryBB);
Cloner.clone();
Expand Down Expand Up @@ -503,26 +523,9 @@ void SILGlobalOpt::placeInitializers(SILFunction *InitF,
static SILFunction *genGetterFromInit(SILFunction *InitF, VarDecl *varDecl) {
// Generate a getter from the global init function without side-effects.

auto getterName = mangleGetter(varDecl);

// Check if a getter was generated already.
if (auto *F = InitF->getModule().lookUpFunction(getterName))
return F;

auto refType = varDecl->getInterfaceType()->getCanonicalType();
// Function takes no arguments and returns refType
SILResultInfo Results[] = { SILResultInfo(refType, ResultConvention::Owned) };
SILFunctionType::ExtInfo EInfo;
EInfo = EInfo.withRepresentation(SILFunctionType::Representation::Thin);
auto LoweredType = SILFunctionType::get(nullptr, EInfo,
SILCoroutineKind::None, ParameterConvention::Direct_Owned,
/*params*/ {}, /*yields*/ {}, Results, None,
InitF->getASTContext());
auto *GetterF = InitF->getModule().getOrCreateFunction(
InitF->getLocation(),
getterName, SILLinkage::Private, LoweredType,
IsBare_t::IsBare, IsTransparent_t::IsNotTransparent,
IsSerialized_t::IsSerialized);
auto *GetterF = getGlobalGetterFunction(InitF->getModule(),
InitF->getLocation(),
varDecl);
if (!InitF->hasQualifiedOwnership())
GetterF->setUnqualifiedOwnership();

Expand Down
4 changes: 4 additions & 0 deletions lib/SILOptimizer/UtilityPasses/InstCount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ STATISTIC(TotalExternalFuncDecls, "Number of external funcs declarations");

// Linkage statistics
STATISTIC(TotalPublicFuncs, "Number of public funcs");
STATISTIC(TotalPublicNonABIFuncs, "Number of public non-ABI funcs");
STATISTIC(TotalHiddenFuncs, "Number of hidden funcs");
STATISTIC(TotalPrivateFuncs, "Number of private funcs");
STATISTIC(TotalSharedFuncs, "Number of shared funcs");
Expand Down Expand Up @@ -117,6 +118,9 @@ class InstCount : public SILFunctionTransform {
case SILLinkage::Public:
++TotalPublicFuncs;
break;
case SILLinkage::PublicNonABI:
++TotalPublicNonABIFuncs;
break;
case SILLinkage::Hidden:
++TotalHiddenFuncs;
break;
Expand Down
10 changes: 9 additions & 1 deletion lib/Serialization/DeserializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ static Optional<SILLinkage>
fromStableSILLinkage(unsigned value) {
switch (value) {
case SIL_LINKAGE_PUBLIC: return SILLinkage::Public;
case SIL_LINKAGE_PUBLIC_NON_ABI: return SILLinkage::PublicNonABI;
case SIL_LINKAGE_HIDDEN: return SILLinkage::Hidden;
case SIL_LINKAGE_SHARED: return SILLinkage::Shared;
case SIL_LINKAGE_PRIVATE: return SILLinkage::Private;
Expand Down Expand Up @@ -469,7 +470,14 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID,
fn->setSerialized(IsSerialized_t(isSerialized));

// Don't override the transparency or linkage of a function with
// an existing declaration.
// an existing declaration, except if we deserialized a
// PublicNonABI function, which has HiddenExternal when
// referenced as a declaration, and SharedExternal when it has
// a deserialized body.
if (fn->getLinkage() == SILLinkage::HiddenExternal &&
linkage == SILLinkage::PublicNonABI) {
fn->setLinkage(SILLinkage::SharedExternal);
}

// Otherwise, create a new function.
} else {
Expand Down
3 changes: 2 additions & 1 deletion lib/Serialization/SILFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ enum SILStringEncoding : uint8_t {

enum SILLinkageEncoding : uint8_t {
SIL_LINKAGE_PUBLIC,
SIL_LINKAGE_PUBLIC_NON_ABI,
SIL_LINKAGE_HIDDEN,
SIL_LINKAGE_SHARED,
SIL_LINKAGE_PRIVATE,
Expand All @@ -45,7 +46,7 @@ enum SILLinkageEncoding : uint8_t {
SIL_LINKAGE_SHARED_EXTERNAL,
SIL_LINKAGE_PRIVATE_EXTERNAL,
};
using SILLinkageField = BCFixed<3>;
using SILLinkageField = BCFixed<4>;

enum SILVTableEntryKindEncoding : uint8_t {
SIL_VTABLE_ENTRY_NORMAL,
Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/SerializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ toStableConstStringEncoding(ConstStringLiteralInst::Encoding encoding) {
static unsigned toStableSILLinkage(SILLinkage linkage) {
switch (linkage) {
case SILLinkage::Public: return SIL_LINKAGE_PUBLIC;
case SILLinkage::PublicNonABI: return SIL_LINKAGE_PUBLIC_NON_ABI;
case SILLinkage::Hidden: return SIL_LINKAGE_HIDDEN;
case SILLinkage::Shared: return SIL_LINKAGE_SHARED;
case SILLinkage::Private: return SIL_LINKAGE_PRIVATE;
Expand Down
Loading