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.
This commit is contained in:
Saleem Abdulrasool
2018-02-08 11:56:45 -08:00
parent 43435af7ee
commit 1025eed645
3 changed files with 45 additions and 22 deletions

View File

@@ -35,6 +35,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
@@ -851,19 +852,20 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
if (linkLib.shouldForceLoad()) {
llvm::SmallString<64> buf;
encodeForceLoadSymbolName(buf, linkLib.getName());
auto symbolAddr = Module.getOrInsertGlobal(buf.str(), Int1Ty);
auto ForceImportThunk =
Module.getOrInsertFunction(buf, llvm::FunctionType::get(VoidTy, false));
if (useDllStorage())
cast<llvm::GlobalVariable>(symbolAddr)
cast<llvm::GlobalValue>(ForceImportThunk)
->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
buf += "_$";
appendEncodedName(buf, IRGen.Opts.ModuleName);
if (!Module.getGlobalVariable(buf.str())) {
auto ref = new llvm::GlobalVariable(Module, symbolAddr->getType(),
auto ref = new llvm::GlobalVariable(Module, ForceImportThunk->getType(),
/*isConstant=*/true,
llvm::GlobalValue::WeakAnyLinkage,
symbolAddr, buf.str());
ForceImportThunk, buf.str());
ref->setVisibility(llvm::GlobalValue::HiddenVisibility);
auto casted = llvm::ConstantExpr::getBitCast(ref, Int8PtrTy);
LLVMUsed.push_back(casted);
@@ -953,13 +955,17 @@ void IRGenModule::emitAutolinkInfo() {
if (!IRGen.Opts.ForceLoadSymbolName.empty()) {
llvm::SmallString<64> buf;
encodeForceLoadSymbolName(buf, IRGen.Opts.ForceLoadSymbolName);
auto symbol =
new llvm::GlobalVariable(Module, Int1Ty, /*isConstant=*/false,
llvm::GlobalValue::CommonLinkage,
llvm::Constant::getNullValue(Int1Ty),
buf.str());
auto ForceImportThunk =
llvm::Function::Create(llvm::FunctionType::get(VoidTy, false),
llvm::GlobalValue::WeakODRLinkage, buf,
&Module);
if (useDllStorage())
symbol->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
ForceImportThunk
->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
auto BB = llvm::BasicBlock::Create(getLLVMContext(), "", ForceImportThunk);
llvm::IRBuilder<> IRB(BB);
IRB.CreateRetVoid();
}
}

View File

@@ -1,10 +1,23 @@
// RUN: %empty-directory(%t)
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// REQUIRES: OS=windows-msvc
import swiftMSVCRT
// CHECK: @"_swift_FORCE_LOAD_$_swiftMSVCRT_$_autolink" = weak hidden constant void ()* @"_swift_FORCE_LOAD_$_swiftMSVCRT"
// CHECK: weak_odr dllexport void @"_swift_FORCE_LOAD_$_autolink"()
// CHECK-ASM-GNU: .ascii " -export:__swift_FORCE_LOAD_$_autolink"
// CHECK-ASM-MSC: .ascii " /EXPORT:__swift_FORCE_LOAD_$_autolink"
// CHECK: @"_swift_FORCE_LOAD_$_autolink" = common dllexport global i1 false
// CHECK-ASM-GNU: .ascii " -export:__swift_FORCE_LOAD_$_autolink,data"
// CHECK-ASM-MSC: .ascii " /EXPORT:__swift_FORCE_LOAD_$_autolink,DATA"

View File

@@ -38,12 +38,16 @@ import someModule
// FRAMEWORK-DAG: !{{[0-9]+}} = !{!"-framework", !"someModule"}
// NO-FORCE-LOAD-NOT: FORCE_LOAD
// FORCE-LOAD: @"_swift_FORCE_LOAD_$_module" = common global i1 false
// FORCE-LOAD-HEX: @"_swift_FORCE_LOAD_$306d6f64756c65" = common global i1 false
// FORCE-LOAD-CLIENT: @"_swift_FORCE_LOAD_$_module" = external global i1
// FORCE-LOAD-CLIENT: @"_swift_FORCE_LOAD_$_module_$_autolinking" = weak hidden constant i1* @"_swift_FORCE_LOAD_$_module"
// FORCE-LOAD: define weak_odr void @"_swift_FORCE_LOAD_$_module"() {
// FORCE-LOAD: ret void
// FORCE-LOAD: }
// FORCE-LOAD-HEX: define weak_odr void @"_swift_FORCE_LOAD_$306d6f64756c65"() {
// FORCE-LOAD-HEX: ret void
// FORCE-LOAD-HEX: }
// FORCE-LOAD-CLIENT: @"_swift_FORCE_LOAD_$_module_$_autolinking" = weak hidden constant void ()* @"_swift_FORCE_LOAD_$_module"
// FORCE-LOAD-CLIENT: @llvm.used = appending global [{{[0-9]+}} x i8*] [
// FORCE-LOAD-CLIENT: i8* bitcast (i1** @"_swift_FORCE_LOAD_$_module_$_autolinking" to i8*)
// FORCE-LOAD-CLIENT: i8* bitcast (void ()** @"_swift_FORCE_LOAD_$_module_$_autolinking" to i8*)
// FORCE-LOAD-CLIENT: ], section "llvm.metadata"
// FORCE-LOAD-CLIENT: declare void @"_swift_FORCE_LOAD_$_module"()