Skip to content

Commit 9a20eba

Browse files
committed
[Embedded] Emit weak definitions for imported symbols
When Embedded Swift emits a symbol that was imported from another module, ensure that the symbol is emitted as a weak definition. This way, importing the same module (and using its symbol) into several different modules doesn't cause duplicate-symbol errors at link time. Rather, the linker will merge the different symbol definitions. This makes Embedded Swift libraries work without resorting to `-mergeable-symbols` or `-emit-empty-object-file`.
1 parent c91a482 commit 9a20eba

18 files changed

+446
-20
lines changed

include/swift/IRGen/Linking.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,6 +1850,14 @@ class LinkEntity {
18501850
bool isTypeKind() const { return isTypeKind(getKind()); }
18511851

18521852
bool isAlwaysSharedLinkage() const;
1853+
1854+
/// Whether the link entity's definitions must be considered non-unique.
1855+
///
1856+
/// This applies only in the Embedded Swift linkage model, and is used for
1857+
/// any symbols that have not been explicitly requested to have unique
1858+
/// definitions (e.g., with @_used).
1859+
bool hasNonUniqueDefinition() const;
1860+
18531861
#undef LINKENTITY_GET_FIELD
18541862
#undef LINKENTITY_SET_FIELD
18551863

include/swift/SIL/SILDeclRef.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,14 @@ struct SILDeclRef {
399399
/// True if the function has the @backDeployed attribute.
400400
bool isBackDeployed() const;
401401

402+
/// True if this entity should have a non-unique definition based on the
403+
/// embedded linkage model.
404+
bool hasNonUniqueDefinition() const;
405+
406+
/// True if the declaration should have a non-unique definition based on the
407+
/// embedded linkage model.
408+
static bool declHasNonUniqueDefinition(const ValueDecl *decl);
409+
402410
/// Return the expected linkage for a definition of this declaration.
403411
SILLinkage getDefinitionLinkage() const;
404412

include/swift/SIL/SILFunction.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,10 @@ class SILFunction
659659

660660
bool isNoReturnFunction(TypeExpansionContext context) const;
661661

662+
/// True if this function should have a non-unique definition based on the
663+
/// embedded linkage model.
664+
bool hasNonUniqueDefinition() const;
665+
662666
/// Unsafely rewrite the lowered type of this function.
663667
///
664668
/// This routine does not touch the entry block arguments
@@ -916,6 +920,10 @@ class SILFunction
916920
return swift::isAvailableExternally(getLinkage());
917921
}
918922

923+
/// Helper method that determines whether this SILFunction is a Swift runtime
924+
/// function, such as swift_retain.
925+
bool isSwiftRuntimeFunction() const;
926+
919927
/// Helper method which returns true if the linkage of the SILFunction
920928
/// indicates that the object's definition might be required outside the
921929
/// current SILModule.

include/swift/SIL/SILGlobalVariable.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ class SILGlobalVariable
151151
/// might be referenced from outside the current compilation unit.
152152
bool isPossiblyUsedExternally() const;
153153

154+
/// True if this variable should have a non-unique definition based on the
155+
/// embedded linkage model.
156+
bool hasNonUniqueDefinition() const;
157+
154158
/// Returns true if this global variable should be preserved so it can
155159
/// potentially be inspected by the debugger.
156160
bool shouldBePreservedForDebugger() const;

lib/IRGen/GenDecl.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,9 +1156,17 @@ static bool isLazilyEmittedFunction(SILFunction &f, SILModule &m) {
11561156
f.getLoweredFunctionType()->getSubstGenericSignature()) {
11571157
return true;
11581158
}
1159-
1160-
if (f.isPossiblyUsedExternally())
1159+
1160+
if (f.isPossiblyUsedExternally()) {
1161+
// Under the embedded linkage model, if it has a non-unique definition,
1162+
// treat it lazily.
1163+
if (f.hasNonUniqueDefinition() && !f.isSwiftRuntimeFunction()
1164+
&& !f.markedAsUsed()) {
1165+
return true;
1166+
}
1167+
11611168
return false;
1169+
}
11621170

11631171
if (f.getDynamicallyReplacedFunction())
11641172
return false;
@@ -2244,7 +2252,8 @@ void IRGenerator::emitEntryPointInfo() {
22442252
static IRLinkage
22452253
getIRLinkage(StringRef name, const UniversalLinkageInfo &info,
22462254
SILLinkage linkage, ForDefinition_t isDefinition,
2247-
bool isWeakImported, bool isKnownLocal = false) {
2255+
bool isWeakImported, bool isKnownLocal,
2256+
bool hasNonUniqueDefinition) {
22482257
#define RESULT(LINKAGE, VISIBILITY, DLL_STORAGE) \
22492258
IRLinkage{llvm::GlobalValue::LINKAGE##Linkage, \
22502259
llvm::GlobalValue::VISIBILITY##Visibility, \
@@ -2275,7 +2284,9 @@ getIRLinkage(StringRef name, const UniversalLinkageInfo &info,
22752284
case SILLinkage::Package: {
22762285
auto linkage = llvm::GlobalValue::ExternalLinkage;
22772286

2278-
if (info.MergeableSymbols)
2287+
if (hasNonUniqueDefinition)
2288+
linkage = llvm::GlobalValue::WeakODRLinkage;
2289+
else if (info.MergeableSymbols)
22792290
linkage = llvm::GlobalValue::WeakODRLinkage;
22802291

22812292
return {linkage, PublicDefinitionVisibility,
@@ -2293,6 +2304,8 @@ getIRLinkage(StringRef name, const UniversalLinkageInfo &info,
22932304
: RESULT(External, Hidden, Default);
22942305

22952306
case SILLinkage::Hidden:
2307+
if (hasNonUniqueDefinition)
2308+
return RESULT(WeakODR, Hidden, Default);
22962309
if (info.MergeableSymbols)
22972310
return RESULT(WeakODR, Hidden, Default);
22982311

@@ -2301,7 +2314,7 @@ getIRLinkage(StringRef name, const UniversalLinkageInfo &info,
23012314
case SILLinkage::Private: {
23022315
if (info.forcePublicDecls() && !isDefinition)
23032316
return getIRLinkage(name, info, SILLinkage::PublicExternal, isDefinition,
2304-
isWeakImported, isKnownLocal);
2317+
isWeakImported, isKnownLocal, hasNonUniqueDefinition);
23052318

23062319
auto linkage = info.needLinkerToMergeDuplicateSymbols()
23072320
? llvm::GlobalValue::LinkOnceODRLinkage
@@ -2357,7 +2370,8 @@ void irgen::updateLinkageForDefinition(IRGenModule &IGM,
23572370
auto IRL =
23582371
getIRLinkage(global->hasName() ? global->getName() : StringRef(),
23592372
linkInfo, entity.getLinkage(ForDefinition), ForDefinition,
2360-
weakImported, isKnownLocal);
2373+
weakImported, isKnownLocal,
2374+
entity.hasNonUniqueDefinition());
23612375
ApplyIRLinkage(IRL).to(global);
23622376

23632377
LinkInfo link = LinkInfo::get(IGM, entity, ForDefinition);
@@ -2410,7 +2424,8 @@ LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo,
24102424
bool weakImported = entity.isWeakImported(swiftModule);
24112425
result.IRL = getIRLinkage(result.Name, linkInfo,
24122426
entity.getLinkage(isDefinition), isDefinition,
2413-
weakImported, isKnownLocal);
2427+
weakImported, isKnownLocal,
2428+
entity.hasNonUniqueDefinition());
24142429
result.ForDefinition = isDefinition;
24152430
return result;
24162431
}
@@ -2421,7 +2436,8 @@ LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo, StringRef name,
24212436
LinkInfo result;
24222437
result.Name += name;
24232438
result.IRL = getIRLinkage(name, linkInfo, linkage, isDefinition,
2424-
isWeakImported, linkInfo.Internalize);
2439+
isWeakImported, linkInfo.Internalize,
2440+
/*hasNonUniqueDefinition=*/false);
24252441
result.ForDefinition = isDefinition;
24262442
return result;
24272443
}

lib/IRGen/Linking.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,3 +1734,31 @@ bool LinkEntity::isAlwaysSharedLinkage() const {
17341734
return false;
17351735
}
17361736
}
1737+
1738+
bool LinkEntity::hasNonUniqueDefinition() const {
1739+
if (isDeclKind(getKind())) {
1740+
auto decl = getDecl();
1741+
return SILDeclRef::declHasNonUniqueDefinition(decl);
1742+
}
1743+
1744+
if (hasSILFunction()) {
1745+
return getSILFunction()->hasNonUniqueDefinition();
1746+
}
1747+
1748+
if (getKind() == Kind::SILGlobalVariable ||
1749+
getKind() == Kind::ReadOnlyGlobalObject)
1750+
return getSILGlobalVariable()->hasNonUniqueDefinition();
1751+
1752+
if (getKind() == Kind::TypeMetadata) {
1753+
// For a nominal type, check its declaration.
1754+
CanType type = getType();
1755+
if (auto nominal = type->getAnyNominal()) {
1756+
return SILDeclRef::declHasNonUniqueDefinition(nominal);
1757+
}
1758+
1759+
// All other type metadata is nonuniqued.
1760+
return true;
1761+
}
1762+
1763+
return false;
1764+
}

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,7 @@ static LinkageLimit getLinkageLimit(SILDeclRef constant) {
571571
case Kind::AsyncEntryPoint:
572572
llvm_unreachable("Already handled");
573573
}
574+
574575
return Limit::None;
575576
}
576577

@@ -1089,6 +1090,25 @@ bool SILDeclRef::isBackDeployed() const {
10891090
return false;
10901091
}
10911092

1093+
bool SILDeclRef::hasNonUniqueDefinition() const {
1094+
if (auto decl = getDecl())
1095+
return declHasNonUniqueDefinition(decl);
1096+
1097+
return false;
1098+
}
1099+
1100+
bool SILDeclRef::declHasNonUniqueDefinition(const ValueDecl *decl) {
1101+
// This function only forces the issue in embedded.
1102+
if (!decl->getASTContext().LangOpts.hasFeature(Feature::Embedded))
1103+
return false;
1104+
1105+
// If the declaration is not from the main module, treat its definition as
1106+
// non-unique.
1107+
auto module = decl->getModuleContext();
1108+
auto &ctx = module->getASTContext();
1109+
return module != ctx.MainModule && ctx.MainModule;
1110+
}
1111+
10921112
bool SILDeclRef::isForeignToNativeThunk() const {
10931113
// If this isn't a native entry-point, it's not a foreign-to-native thunk.
10941114
if (isForeign)

lib/SIL/IR/SILFunction.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,24 @@ bool SILFunction::isNoReturnFunction(TypeExpansionContext context) const {
553553
.isNoReturnFunction(getModule(), context);
554554
}
555555

556+
bool SILFunction::hasNonUniqueDefinition() const {
557+
// Non-uniqueness is a property of the Embedded linkage model.
558+
if (!getASTContext().LangOpts.hasFeature(Feature::Embedded))
559+
return false;
560+
561+
// If this is for a declaration, ask it.
562+
if (auto declRef = getDeclRef()) {
563+
return declRef.hasNonUniqueDefinition();
564+
}
565+
566+
// If this function is from a different module than the one we are emitting
567+
// code for, then it must have a non-unique definition.
568+
if (getParentModule() != getModule().getSwiftModule())
569+
return true;
570+
571+
return false;
572+
}
573+
556574
ResilienceExpansion SILFunction::getResilienceExpansion() const {
557575
// If a function definition is in another module, and
558576
// it was serialized due to package serialization opt,
@@ -1016,6 +1034,17 @@ bool SILFunction::hasValidLinkageForFragileRef(SerializedKind_t callerSerialized
10161034
return hasPublicOrPackageVisibility(getLinkage(), /*includePackage*/ true);
10171035
}
10181036

1037+
bool SILFunction::isSwiftRuntimeFunction() const {
1038+
if (!getName().starts_with("swift_") &&
1039+
!getName().starts_with("_swift_"))
1040+
return false;
1041+
1042+
auto module = getParentModule();
1043+
return !module ||
1044+
module->getName().str() == "Swift" ||
1045+
module->getName().str() == "_Concurrency";
1046+
}
1047+
10191048
bool
10201049
SILFunction::isPossiblyUsedExternally() const {
10211050
auto linkage = getLinkage();
@@ -1046,6 +1075,11 @@ SILFunction::isPossiblyUsedExternally() const {
10461075
hasOpaqueResultTypeWithAvailabilityConditions())
10471076
return true;
10481077

1078+
// All Swift runtime functions can be used externally.
1079+
if (getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
1080+
isSwiftRuntimeFunction())
1081+
return true;
1082+
10491083
return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule());
10501084
}
10511085

lib/SIL/IR/SILGlobalVariable.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ bool SILGlobalVariable::isPossiblyUsedExternally() const {
8888
return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule());
8989
}
9090

91+
bool SILGlobalVariable::hasNonUniqueDefinition() const {
92+
auto decl = getDecl();
93+
if (!decl)
94+
return false;
95+
96+
return SILDeclRef::declHasNonUniqueDefinition(decl);
97+
}
98+
9199
bool SILGlobalVariable::shouldBePreservedForDebugger() const {
92100
if (getModule().getOptions().OptMode != OptimizationMode::NoOptimization)
93101
return false;

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,9 @@ void CrossModuleOptimization::serializeInstruction(SILInstruction *inst,
950950
}
951951
serializeFunction(callee, canSerializeFlags);
952952
assert(isSerializedWithRightKind(M, callee) ||
953-
isPackageOrPublic(callee->getLinkage()));
953+
isPackageOrPublic(callee->getLinkage()) ||
954+
M.getSwiftModule()->getASTContext().LangOpts.hasFeature(
955+
Feature::Embedded));
954956
return;
955957
}
956958

@@ -1005,7 +1007,10 @@ void CrossModuleOptimization::keepMethodAlive(SILDeclRef method) {
10051007
void CrossModuleOptimization::makeFunctionUsableFromInline(SILFunction *function) {
10061008
assert(canUseFromInline(function));
10071009
if (!isAvailableExternally(function->getLinkage()) &&
1008-
!isPackageOrPublic(function->getLinkage())) {
1010+
!isPackageOrPublic(function->getLinkage()) &&
1011+
!(function->getLinkage() == SILLinkage::Shared &&
1012+
M.getSwiftModule()->getASTContext().LangOpts.hasFeature(
1013+
Feature::Embedded))) {
10091014
function->setLinkage(SILLinkage::Public);
10101015
}
10111016
}

0 commit comments

Comments
 (0)