Skip to content

Commit 1025eed

Browse files
committed
IRGen: make the autolink work better in COFF environments
This was obscured due to local workarounds. Because the reference is cross-module, and the symbol itself will be rebased, it cannot serve as a constant initializer (the value is not known until runtime). However, using a function pointer is permissible. The linker will materialize a thunk for the function itself and cause the module to be force linked. This also works on ELF and MachO as well. The overhead associated with this is pretty minimal as the function itself has an empty body, and flags will differentiate between a function and data symbol. The slight penalty in size (on the order of 2-4 bytes) allows for the same pattern to be used across all the targets.
1 parent 43435af commit 1025eed

File tree

3 files changed

+46
-23
lines changed

3 files changed

+46
-23
lines changed

lib/IRGen/IRGenModule.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "clang/Lex/HeaderSearch.h"
3636
#include "clang/Lex/HeaderSearchOptions.h"
3737
#include "clang/Frontend/CodeGenOptions.h"
38+
#include "llvm/IR/IRBuilder.h"
3839
#include "llvm/IR/Constants.h"
3940
#include "llvm/IR/DataLayout.h"
4041
#include "llvm/IR/DerivedTypes.h"
@@ -851,19 +852,20 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
851852
if (linkLib.shouldForceLoad()) {
852853
llvm::SmallString<64> buf;
853854
encodeForceLoadSymbolName(buf, linkLib.getName());
854-
auto symbolAddr = Module.getOrInsertGlobal(buf.str(), Int1Ty);
855+
auto ForceImportThunk =
856+
Module.getOrInsertFunction(buf, llvm::FunctionType::get(VoidTy, false));
855857
if (useDllStorage())
856-
cast<llvm::GlobalVariable>(symbolAddr)
858+
cast<llvm::GlobalValue>(ForceImportThunk)
857859
->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
858860

859861
buf += "_$";
860862
appendEncodedName(buf, IRGen.Opts.ModuleName);
861863

862864
if (!Module.getGlobalVariable(buf.str())) {
863-
auto ref = new llvm::GlobalVariable(Module, symbolAddr->getType(),
865+
auto ref = new llvm::GlobalVariable(Module, ForceImportThunk->getType(),
864866
/*isConstant=*/true,
865867
llvm::GlobalValue::WeakAnyLinkage,
866-
symbolAddr, buf.str());
868+
ForceImportThunk, buf.str());
867869
ref->setVisibility(llvm::GlobalValue::HiddenVisibility);
868870
auto casted = llvm::ConstantExpr::getBitCast(ref, Int8PtrTy);
869871
LLVMUsed.push_back(casted);
@@ -953,13 +955,17 @@ void IRGenModule::emitAutolinkInfo() {
953955
if (!IRGen.Opts.ForceLoadSymbolName.empty()) {
954956
llvm::SmallString<64> buf;
955957
encodeForceLoadSymbolName(buf, IRGen.Opts.ForceLoadSymbolName);
956-
auto symbol =
957-
new llvm::GlobalVariable(Module, Int1Ty, /*isConstant=*/false,
958-
llvm::GlobalValue::CommonLinkage,
959-
llvm::Constant::getNullValue(Int1Ty),
960-
buf.str());
958+
auto ForceImportThunk =
959+
llvm::Function::Create(llvm::FunctionType::get(VoidTy, false),
960+
llvm::GlobalValue::WeakODRLinkage, buf,
961+
&Module);
961962
if (useDllStorage())
962-
symbol->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
963+
ForceImportThunk
964+
->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
965+
966+
auto BB = llvm::BasicBlock::Create(getLLVMContext(), "", ForceImportThunk);
967+
llvm::IRBuilder<> IRB(BB);
968+
IRB.CreateRetVoid();
963969
}
964970
}
965971

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %swift -target i686--windows-msvc -parse-as-library -parse-stdlib -module-name autolink -module-link-name autolink -autolink-force-load -emit-ir -o - %s | %FileCheck %s
4-
// RUN: %swift -target i686--windows-itanium -parse-as-library -parse-stdlib -module-name autolink -module-link-name autolink -autolink-force-load -S -o - %s | %FileCheck %s -check-prefix CHECK-ASM-GNU
5-
// RUN: %swift -target i686--windows-msvc -parse-as-library -parse-stdlib -module-name autolink -module-link-name autolink -autolink-force-load -S -o - %s | %FileCheck %s -check-prefix CHECK-ASM-MSC
3+
// RUN: %swift -target i686--windows-msvc -parse-stdlib -autolink-force-load -module-name swiftMSVCRT -module-link-name swiftMSVCRT -emit-module -o %t/swiftMSVCRT.swiftmodule %S/../Inputs/empty.swift
4+
5+
// RUN: %swift -target i686--windows-msvc -parse-as-library -parse-stdlib -autolink-force-load -module-name autolink -module-link-name autolink -emit-ir -o - %s | %FileCheck %s
6+
// RUN: %swift -target i686--windows-msvc -parse-as-library -parse-stdlib -autolink-force-load -module-name autolink -module-link-name autolink -S -o - %s | %FileCheck %s -check-prefix CHECK-ASM-MSC
7+
8+
// RUN: %swift -target i686--windows-itanium -parse-stdlib -autolink-force-load -module-name swiftMSVCRT -module-link-name swiftMSVCRT -emit-module -o %t/swiftMSVCRT.swiftmodule %S/../Inputs/empty.swift
9+
10+
// RUN: %swift -target i686--windows-itanium -parse-as-library -parse-stdlib -autolink-force-load -module-name autolink -module-link-name autolink -emit-ir -o - %s | %FileCheck %s
11+
// RUN: %swift -target i686--windows-itanium -parse-as-library -parse-stdlib -autolink-force-load -module-name autolink -module-link-name autolink -S -o - %s | %FileCheck %s -check-prefix CHECK-ASM-GNU
12+
13+
// REQUIRES: OS=windows-msvc
14+
15+
import swiftMSVCRT
16+
17+
// CHECK: @"_swift_FORCE_LOAD_$_swiftMSVCRT_$_autolink" = weak hidden constant void ()* @"_swift_FORCE_LOAD_$_swiftMSVCRT"
18+
// CHECK: weak_odr dllexport void @"_swift_FORCE_LOAD_$_autolink"()
19+
20+
// CHECK-ASM-GNU: .ascii " -export:__swift_FORCE_LOAD_$_autolink"
21+
// CHECK-ASM-MSC: .ascii " /EXPORT:__swift_FORCE_LOAD_$_autolink"
622

7-
// CHECK: @"_swift_FORCE_LOAD_$_autolink" = common dllexport global i1 false
8-
// CHECK-ASM-GNU: .ascii " -export:__swift_FORCE_LOAD_$_autolink,data"
9-
// CHECK-ASM-MSC: .ascii " /EXPORT:__swift_FORCE_LOAD_$_autolink,DATA"
1023

test/Serialization/autolinking.swift

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,16 @@ import someModule
3838
// FRAMEWORK-DAG: !{{[0-9]+}} = !{!"-framework", !"someModule"}
3939

4040
// NO-FORCE-LOAD-NOT: FORCE_LOAD
41-
// FORCE-LOAD: @"_swift_FORCE_LOAD_$_module" = common global i1 false
42-
// FORCE-LOAD-HEX: @"_swift_FORCE_LOAD_$306d6f64756c65" = common global i1 false
43-
44-
// FORCE-LOAD-CLIENT: @"_swift_FORCE_LOAD_$_module" = external global i1
45-
// FORCE-LOAD-CLIENT: @"_swift_FORCE_LOAD_$_module_$_autolinking" = weak hidden constant i1* @"_swift_FORCE_LOAD_$_module"
46-
41+
// FORCE-LOAD: define weak_odr void @"_swift_FORCE_LOAD_$_module"() {
42+
// FORCE-LOAD: ret void
43+
// FORCE-LOAD: }
44+
// FORCE-LOAD-HEX: define weak_odr void @"_swift_FORCE_LOAD_$306d6f64756c65"() {
45+
// FORCE-LOAD-HEX: ret void
46+
// FORCE-LOAD-HEX: }
47+
48+
// FORCE-LOAD-CLIENT: @"_swift_FORCE_LOAD_$_module_$_autolinking" = weak hidden constant void ()* @"_swift_FORCE_LOAD_$_module"
4749
// FORCE-LOAD-CLIENT: @llvm.used = appending global [{{[0-9]+}} x i8*] [
48-
// FORCE-LOAD-CLIENT: i8* bitcast (i1** @"_swift_FORCE_LOAD_$_module_$_autolinking" to i8*)
50+
// FORCE-LOAD-CLIENT: i8* bitcast (void ()** @"_swift_FORCE_LOAD_$_module_$_autolinking" to i8*)
4951
// FORCE-LOAD-CLIENT: ], section "llvm.metadata"
52+
// FORCE-LOAD-CLIENT: declare void @"_swift_FORCE_LOAD_$_module"()
53+

0 commit comments

Comments
 (0)