Skip to content

Commit f6b2294

Browse files
committed
Undo Force Load + Incremental Ban on Darwin Platforms
Gather 'round to hear tell of the saga of autolinking in incremental mode. In the beginning, there was Swift code, and there was Objective-C code. To make one import bind two languages, a twinned Swift module named the same as an Objective-C module could be imported as an overlay. But all was not well, for an overlay could be created which had no Swift content, yet required Swift symbols. And there was much wailing and gnashing of teeth as loaders everywhere disregarded loading these content-less Swift libraries. So, a solution was found - a magical symbol _swift_FORCE_LOAD_$_<MODULE> that forced the loaders to heed the dependency on a Swift library regardless of its content. It was a constant with common linkage, and it was good. But, along came COFF which needed to support autolinking but had no support for such matters. It did, however, have support for COMDAT sections into which we placed the symbol. Immediately, a darkness fell across the land as the windows linker loudly proclaimed it had discovered a contradiction: "_swift_FORCE_LOAD_$_<MODULE> cannot be a constant!", it said, gratingly, "for this value requires rebasing." Undeterred, we switched to a function instead, and the windows linker happily added a level of indirection to its symbol resolution procedure and all was right with the world. But this definition was not all right. In order to support multiple translation units emitting it, and to prevent the linker from dead stripping it, Weak ODR linkage was used. Weak ODR linkage has the nasty side effect of pessimizing load times since the dynamic linker must assume that loading a later library could produce a more definitive definition for the symbol. A compromise was drawn up: To keep load times low, external linkage was used. To keep the linker from complaining about multiple strong definitions for the same symbol, the first translation unit in the module was nominated to recieve the magic symbol. But one final problem remained: Incremental builds allow for files to be added or removed during the build procedure. The placement of the symbol was therefore dependent entirely upon the order of files passed at the command line. This was no good, so a decree was set forth that using -autolink-force-load and -incremental together was a criminal offense. So we must compromise once more: Return to a symbol with common linkage, but only on Mach-O targets. Preserve the existing COMDAT-friendly approach everywhere else. This concludes our tale. rdar://77803299
1 parent 99c837b commit f6b2294

File tree

18 files changed

+125
-89
lines changed

18 files changed

+125
-89
lines changed

include/swift/AST/DiagnosticsDriver.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,6 @@ ERROR(error_input_changed_during_build,none,
119119
ERROR(error_conflicting_options, none,
120120
"conflicting options '%0' and '%1'",
121121
(StringRef, StringRef))
122-
ERROR(error_option_not_supported, none,
123-
"'%0' is not supported with '%1'",
124-
(StringRef, StringRef))
125122
ERROR(error_requirement_not_met, none,
126123
"'%0' requires '%1'",
127124
(StringRef, StringRef))

include/swift/IRGen/Linking.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,6 +1417,7 @@ struct IRLinkage {
14171417
static const IRLinkage InternalWeakODR;
14181418
static const IRLinkage Internal;
14191419

1420+
static const IRLinkage ExternalCommon;
14201421
static const IRLinkage ExternalImport;
14211422
static const IRLinkage ExternalWeakImport;
14221423
static const IRLinkage ExternalExport;

lib/Driver/Driver.cpp

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -251,27 +251,6 @@ static void validateSearchPathArgs(DiagnosticEngine &diags,
251251
}
252252
}
253253

254-
static void validateAutolinkingArgs(DiagnosticEngine &diags,
255-
const ArgList &args,
256-
const llvm::Triple &T) {
257-
auto *forceLoadArg = args.getLastArg(options::OPT_autolink_force_load);
258-
if (!forceLoadArg)
259-
return;
260-
auto *incrementalArg = args.getLastArg(options::OPT_incremental);
261-
if (!incrementalArg)
262-
return;
263-
264-
if (T.supportsCOMDAT())
265-
return;
266-
267-
// Note: -incremental can itself be overridden by other arguments later
268-
// on, but since -autolink-force-load is a rare and not-really-recommended
269-
// option it's not worth modeling that complexity here (or moving the
270-
// check somewhere else).
271-
diags.diagnose(SourceLoc(), diag::error_option_not_supported,
272-
forceLoadArg->getSpelling(), incrementalArg->getSpelling());
273-
}
274-
275254
/// Perform miscellaneous early validation of arguments.
276255
static void validateArgs(DiagnosticEngine &diags, const ArgList &args,
277256
const llvm::Triple &T) {
@@ -282,7 +261,6 @@ static void validateArgs(DiagnosticEngine &diags, const ArgList &args,
282261
validateDebugInfoArgs(diags, args);
283262
validateCompilationConditionArgs(diags, args);
284263
validateSearchPathArgs(diags, args);
285-
validateAutolinkingArgs(diags, args, T);
286264
validateVerifyIncrementalDependencyArgs(diags, args);
287265
}
288266

lib/FrontendTool/TBD.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ static bool validateSymbols(DiagnosticEngine &diags,
8484
if (auto GV = dyn_cast<llvm::GlobalValue>(value)) {
8585
// Is this a symbol that should be listed?
8686
auto externallyVisible =
87-
GV->hasExternalLinkage() && !GV->hasHiddenVisibility();
87+
(GV->hasExternalLinkage() || GV->hasCommonLinkage())
88+
&& !GV->hasHiddenVisibility();
8889
if (!GV->isDeclaration() && externallyVisible) {
8990
// Is it listed?
9091
if (!symbolSet.erase(name))

lib/IRGen/IRGenModule.cpp

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,18 +1300,6 @@ static bool replaceModuleFlagsEntry(llvm::LLVMContext &Ctx,
13001300
llvm_unreachable("Could not replace old linker options entry?");
13011301
}
13021302

1303-
/// Returns true if the object file generated by \p IGM will be the "first"
1304-
/// object file in the module. This lets us determine where to put a symbol
1305-
/// that must be unique.
1306-
static bool isFirstObjectFileInModule(IRGenModule &IGM) {
1307-
if (IGM.getSILModule().isWholeModule())
1308-
return IGM.IRGen.getPrimaryIGM() == &IGM;
1309-
1310-
auto *file = cast<FileUnit>(IGM.getSILModule().getAssociatedContext());
1311-
auto *containingModule = file->getParentModule();
1312-
return containingModule->getFiles().front() == file;
1313-
}
1314-
13151303
static bool
13161304
doesTargetAutolinkUsingAutolinkExtract(const SwiftTargetInfo &TargetInfo,
13171305
const llvm::Triple &Triple) {
@@ -1486,6 +1474,47 @@ AutolinkKind AutolinkKind::create(const SwiftTargetInfo &TargetInfo,
14861474
return AutolinkKind::LLVMLinkerOptions;
14871475
}
14881476

1477+
static llvm::GlobalObject *createForceImportThunk(IRGenModule &IGM) {
1478+
llvm::SmallString<64> buf;
1479+
encodeForceLoadSymbolName(buf, IGM.IRGen.Opts.ForceLoadSymbolName);
1480+
if (IGM.Triple.isOSBinFormatMachO()) {
1481+
// On Mach-O targets, emit a common force-load symbol that resolves to
1482+
// a global variable so it will be coalesced at static link time into a
1483+
// single external symbol.
1484+
//
1485+
// Looks like C's tentative definitions are good for something after all.
1486+
auto ForceImportThunk =
1487+
new llvm::GlobalVariable(IGM.Module,
1488+
IGM.Int1Ty,
1489+
/*isConstant=*/false,
1490+
llvm::GlobalValue::CommonLinkage,
1491+
llvm::Constant::getNullValue(IGM.Int1Ty),
1492+
buf.str());
1493+
ApplyIRLinkage(IRLinkage::ExternalCommon).to(ForceImportThunk);
1494+
IGM.addUsedGlobal(ForceImportThunk);
1495+
return ForceImportThunk;
1496+
} else {
1497+
// On all other targets, emit an external symbol that resolves to a
1498+
// function definition. On Windows, linkonce_odr is basically a no-op and
1499+
// the COMDAT we set by applying linkage gives us the desired coalescing
1500+
// behavior.
1501+
auto ForceImportThunk =
1502+
llvm::Function::Create(llvm::FunctionType::get(IGM.VoidTy, false),
1503+
llvm::GlobalValue::LinkOnceODRLinkage, buf,
1504+
&IGM.Module);
1505+
ForceImportThunk->setAttributes(IGM.constructInitialAttributes());
1506+
ApplyIRLinkage(IRLinkage::ExternalExport).to(ForceImportThunk);
1507+
if (IGM.Triple.supportsCOMDAT())
1508+
if (auto *GO = cast<llvm::GlobalObject>(ForceImportThunk))
1509+
GO->setComdat(IGM.Module.getOrInsertComdat(ForceImportThunk->getName()));
1510+
1511+
auto BB = llvm::BasicBlock::Create(IGM.getLLVMContext(), "", ForceImportThunk);
1512+
llvm::IRBuilder<> IRB(BB);
1513+
IRB.CreateRetVoid();
1514+
return ForceImportThunk;
1515+
}
1516+
}
1517+
14891518
void IRGenModule::emitAutolinkInfo() {
14901519
auto Autolink =
14911520
AutolinkKind::create(TargetInfo, Triple, IRGen.Opts.LLVMLTOKind);
@@ -1504,23 +1533,8 @@ void IRGenModule::emitAutolinkInfo() {
15041533

15051534
Autolink.writeEntries(Entries, Metadata, *this);
15061535

1507-
if (!IRGen.Opts.ForceLoadSymbolName.empty() &&
1508-
(Triple.supportsCOMDAT() || isFirstObjectFileInModule(*this))) {
1509-
llvm::SmallString<64> buf;
1510-
encodeForceLoadSymbolName(buf, IRGen.Opts.ForceLoadSymbolName);
1511-
auto ForceImportThunk =
1512-
llvm::Function::Create(llvm::FunctionType::get(VoidTy, false),
1513-
llvm::GlobalValue::ExternalLinkage, buf,
1514-
&Module);
1515-
ForceImportThunk->setAttributes(constructInitialAttributes());
1516-
ApplyIRLinkage(IRLinkage::ExternalExport).to(ForceImportThunk);
1517-
if (Triple.supportsCOMDAT())
1518-
if (auto *GO = cast<llvm::GlobalObject>(ForceImportThunk))
1519-
GO->setComdat(Module.getOrInsertComdat(ForceImportThunk->getName()));
1520-
1521-
auto BB = llvm::BasicBlock::Create(getLLVMContext(), "", ForceImportThunk);
1522-
llvm::IRBuilder<> IRB(BB);
1523-
IRB.CreateRetVoid();
1536+
if (!IRGen.Opts.ForceLoadSymbolName.empty()) {
1537+
(void) createForceImportThunk(*this);
15241538
}
15251539
}
15261540

lib/IRGen/Linking.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ const IRLinkage IRLinkage::Internal = {
5050
llvm::GlobalValue::DefaultStorageClass,
5151
};
5252

53+
const IRLinkage IRLinkage::ExternalCommon = {
54+
llvm::GlobalValue::CommonLinkage,
55+
llvm::GlobalValue::DefaultVisibility,
56+
llvm::GlobalValue::DLLExportStorageClass,
57+
};
58+
5359
const IRLinkage IRLinkage::ExternalImport = {
5460
llvm::GlobalValue::ExternalLinkage,
5561
llvm::GlobalValue::DefaultVisibility,

lib/TBDGen/TBDGen.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,9 +1186,6 @@ static bool hasLinkerDirective(Decl *D) {
11861186
}
11871187

11881188
void TBDGenVisitor::visitFile(FileUnit *file) {
1189-
if (file == SwiftModule->getFiles()[0])
1190-
addFirstFileSymbols();
1191-
11921189
SmallVector<Decl *, 16> decls;
11931190
file->getTopLevelDecls(decls);
11941191

@@ -1202,6 +1199,9 @@ void TBDGenVisitor::visitFile(FileUnit *file) {
12021199
}
12031200

12041201
void TBDGenVisitor::visit(const TBDGenDescriptor &desc) {
1202+
// Add any autolinking force_load symbols.
1203+
addFirstFileSymbols();
1204+
12051205
if (auto *singleFile = desc.getSingleFile()) {
12061206
assert(SwiftModule == singleFile->getParentModule() &&
12071207
"mismatched file and module");
@@ -1230,6 +1230,7 @@ void TBDGenVisitor::visit(const TBDGenDescriptor &desc) {
12301230
// Diagnose module name that cannot be found
12311231
ctx.Diags.diagnose(SourceLoc(), diag::unknown_swift_module_name, Name);
12321232
}
1233+
12331234
// Collect symbols in each module.
12341235
llvm::for_each(Modules, [&](ModuleDecl *M) {
12351236
for (auto *file : M->getFiles()) {

test/Driver/autolink-force-load-comdat.swift

Lines changed: 0 additions & 10 deletions
This file was deleted.

test/Driver/autolink-force-load-no-comdat.swift

Lines changed: 0 additions & 8 deletions
This file was deleted.

test/IRGen/autolink-force-link.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,25 @@
33
// RUN: %swift -disable-legacy-type-info -target x86_64-apple-macosx10.9 -parse-stdlib -autolink-force-load -module-name TEST -module-link-name TEST -emit-ir %s %S/../Inputs/empty.swift | %FileCheck -check-prefix=CHECK-WMO %s
44

55
// CHECK-WMO: source_filename = "<swift-imported-modules>"
6-
// CHECK-WMO: define void @"_swift_FORCE_LOAD_$_TEST"()
6+
// CHECK-WMO: @"_swift_FORCE_LOAD_$_TEST"
77
// CHECK-WMO-NOT: source_filename
88

99

1010
// RUN: %swift -disable-legacy-type-info -target x86_64-apple-macosx10.9 -parse-stdlib -autolink-force-load -module-name TEST -module-link-name TEST -emit-ir -num-threads 1 %s %S/../Inputs/empty.swift | %FileCheck -check-prefix=CHECK-WMO-THREADED %s
1111

1212
// CHECK-WMO-THREADED: source_filename = "<swift-imported-modules>"
13-
// CHECK-WMO-THREADED: define void @"_swift_FORCE_LOAD_$_TEST"()
13+
// CHECK-WMO-THREADED: @"_swift_FORCE_LOAD_$_TEST"
1414
// CHECK-WMO-THREADED: source_filename = "<swift-imported-modules>"
15-
// CHECK-WMO-THREADED-NOT: _swift_FORCE_LOAD_$_TEST
16-
// CHECK-WMO-THREADED-NOT: source_filename
17-
15+
// CHECK-WMO-THREADED: @"_swift_FORCE_LOAD_$_TEST"
1816

1917
// RUN: %swift -disable-legacy-type-info -target x86_64-apple-macosx10.9 -parse-stdlib -autolink-force-load -module-name TEST -module-link-name TEST -emit-ir -primary-file %s %S/../Inputs/empty.swift | %FileCheck -check-prefix=CHECK-SINGLE-FILE-FIRST %s
2018
// RUN: %swift -disable-legacy-type-info -target x86_64-apple-macosx10.9 -parse-stdlib -autolink-force-load -module-name TEST -module-link-name TEST -emit-ir %S/../Inputs/empty.swift -primary-file %s | %FileCheck -check-prefix=CHECK-SINGLE-FILE-SECOND %s
2119

2220
// CHECK-SINGLE-FILE-FIRST: source_filename = "<swift-imported-modules>"
23-
// CHECK-SINGLE-FILE-FIRST: define void @"_swift_FORCE_LOAD_$_TEST"()
21+
// CHECK-SINGLE-FILE-FIRST: @"_swift_FORCE_LOAD_$_TEST"
2422
// CHECK-SINGLE-FILE-FIRST-NOT: source_filename
2523

2624
// CHECK-SINGLE-FILE-SECOND: source_filename = "<swift-imported-modules>"
27-
// CHECK-SINGLE-FILE-SECOND-NOT: _swift_FORCE_LOAD_$_TEST
25+
// CHECK-SINGLE-FILE-SECOND: @"_swift_FORCE_LOAD_$_TEST"
2826
// CHECK-SINGLE-FILE-SECOND-NOT: source_filename
2927

0 commit comments

Comments
 (0)