From: Saleem Abdulrasool Date: Thu, 15 Dec 2016 06:59:05 +0000 (+0000) Subject: CodeGen: fix runtime function dll storage X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e13e0e403d22d8abc1105a3ae841eb64de64526e;p=clang CodeGen: fix runtime function dll storage Properly attribute DLL storage to runtime functions. When generating the runtime function, scan for an existing declaration which may provide an explicit declaration (local storage) or a DLL import or export storage from the user. Honour that if available. Otherwise, if building with a local visibility of the public or standard namespaces (-flto-visibility-public-std), give the symbols local storage (it indicates a /MT[d] link, so static runtime). Otherwise, assume that the link is dynamic, and give the runtime function dllimport storage. This allows for implementations to get the correct storage as long as they are properly declared, the user to override the import storage, and in case no explicit storage is given, use of the import storage. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@289776 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index eb5d481bb7..8d9d0b21bf 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -237,7 +237,8 @@ void CodeGenFunction::registerGlobalDtorWithAtExit(const VarDecl &VD, llvm::FunctionType::get(IntTy, dtorStub->getType(), false); llvm::Constant *atexit = - CGM.CreateRuntimeFunction(atexitTy, "atexit"); + CGM.CreateRuntimeFunction(atexitTy, "atexit", llvm::AttributeSet(), + /*Local=*/true); if (llvm::Function *atexitFn = dyn_cast(atexit)) atexitFn->setDoesNotThrow(); diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index d155df6d4c..7b7880e07a 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -221,10 +221,9 @@ const EHPersonality &EHPersonality::get(CodeGenFunction &CGF) { static llvm::Constant *getPersonalityFn(CodeGenModule &CGM, const EHPersonality &Personality) { - llvm::Constant *Fn = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, true), - Personality.PersonalityFn); - return Fn; + return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, true), + Personality.PersonalityFn, + llvm::AttributeSet(), /*Local=*/true); } static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM, diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 9aa952d82b..932b8a129e 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -1811,7 +1811,8 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM, // If the target runtime doesn't naturally support ARC, emit weak // references to the runtime support library. We don't really // permit this to fail, but we need a particular relocation style. - if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC()) { + if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC() && + !CGM.getTriple().isOSBinFormatCOFF()) { f->setLinkage(llvm::Function::ExternalWeakLinkage); } else if (fnName == "objc_retain" || fnName == "objc_release") { // If we have Native ARC, set nonlazybind attribute for these APIs for diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 78f43bdef9..404cbae1d8 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -2038,18 +2038,70 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD, IsForDefinition); } +static const FunctionDecl * +GetRuntimeFunctionDecl(ASTContext &C, StringRef Name) { + TranslationUnitDecl *TUDecl = C.getTranslationUnitDecl(); + DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl); + + IdentifierInfo &CII = C.Idents.get(Name); + for (const auto &Result : DC->lookup(&CII)) + if (const auto FD = dyn_cast(Result)) + return FD; + + if (!C.getLangOpts().CPlusPlus) + return nullptr; + + // Demangle the premangled name from getTerminateFn() + IdentifierInfo &CXXII = + (Name == "_ZSt9terminatev" || Name == "\01?terminate@@YAXXZ") + ? C.Idents.get("terminate") + : C.Idents.get(Name); + + for (const auto &N : {"__cxxabiv1", "std"}) { + IdentifierInfo &NS = C.Idents.get(N); + for (const auto &Result : DC->lookup(&NS)) { + NamespaceDecl *ND = dyn_cast(Result); + if (auto LSD = dyn_cast(Result)) + for (const auto &Result : LSD->lookup(&NS)) + if ((ND = dyn_cast(Result))) + break; + + if (ND) + for (const auto &Result : ND->lookup(&CXXII)) + if (const auto *FD = dyn_cast(Result)) + return FD; + } + } + + return nullptr; +} + /// CreateRuntimeFunction - Create a new runtime function with the specified /// type and name. llvm::Constant * -CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, - StringRef Name, - llvm::AttributeSet ExtraAttrs) { +CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name, + llvm::AttributeSet ExtraAttrs, + bool Local) { llvm::Constant *C = GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false, - /*DontDefer=*/false, /*IsThunk=*/false, ExtraAttrs); - if (auto *F = dyn_cast(C)) - if (F->empty()) + /*DontDefer=*/false, /*IsThunk=*/false, + ExtraAttrs); + + if (auto *F = dyn_cast(C)) { + if (F->empty()) { F->setCallingConv(getRuntimeCC()); + + if (!Local && getTriple().isOSBinFormatCOFF() && + !getCodeGenOpts().LTOVisibilityPublicStd) { + const FunctionDecl *FD = GetRuntimeFunctionDecl(Context, Name); + if (!FD || FD->hasAttr()) { + F->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + F->setLinkage(llvm::GlobalValue::ExternalLinkage); + } + } + } + } + return C; } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index be45bb8ea4..d4c096ed67 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -876,10 +876,11 @@ public: } /// Create a new runtime function with the specified type and name. - llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty, - StringRef Name, - llvm::AttributeSet ExtraAttrs = - llvm::AttributeSet()); + llvm::Constant * + CreateRuntimeFunction(llvm::FunctionType *Ty, StringRef Name, + llvm::AttributeSet ExtraAttrs = llvm::AttributeSet(), + bool Local = false); + /// Create a new compiler builtin function with the specified type and name. llvm::Constant *CreateBuiltinFunction(llvm::FunctionType *Ty, StringRef Name, diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 963b1403f5..26c486af12 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -3899,7 +3899,8 @@ static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) { llvm::FunctionType *fnTy = llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false); llvm::Constant *fnRef = - CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate"); + CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate", + llvm::AttributeSet(), /*Local=*/true); llvm::Function *fn = dyn_cast(fnRef); if (fn && fn->empty()) { diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index eb40a45c80..1576483770 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -2204,7 +2204,8 @@ static void emitGlobalDtorWithTLRegDtor(CodeGenFunction &CGF, const VarDecl &VD, CGF.IntTy, DtorStub->getType(), /*IsVarArg=*/false); llvm::Constant *TLRegDtor = - CGF.CGM.CreateRuntimeFunction(TLRegDtorTy, "__tlregdtor"); + CGF.CGM.CreateRuntimeFunction(TLRegDtorTy, "__tlregdtor", + llvm::AttributeSet(), /*Local=*/true); if (llvm::Function *TLRegDtorFn = dyn_cast(TLRegDtor)) TLRegDtorFn->setDoesNotThrow(); @@ -2302,7 +2303,8 @@ static llvm::Constant *getInitThreadHeaderFn(CodeGenModule &CGM) { FTy, "_Init_thread_header", llvm::AttributeSet::get(CGM.getLLVMContext(), llvm::AttributeSet::FunctionIndex, - llvm::Attribute::NoUnwind)); + llvm::Attribute::NoUnwind), + /*Local=*/true); } static llvm::Constant *getInitThreadFooterFn(CodeGenModule &CGM) { @@ -2313,7 +2315,8 @@ static llvm::Constant *getInitThreadFooterFn(CodeGenModule &CGM) { FTy, "_Init_thread_footer", llvm::AttributeSet::get(CGM.getLLVMContext(), llvm::AttributeSet::FunctionIndex, - llvm::Attribute::NoUnwind)); + llvm::Attribute::NoUnwind), + /*Local=*/true); } static llvm::Constant *getInitThreadAbortFn(CodeGenModule &CGM) { @@ -2324,7 +2327,8 @@ static llvm::Constant *getInitThreadAbortFn(CodeGenModule &CGM) { FTy, "_Init_thread_abort", llvm::AttributeSet::get(CGM.getLLVMContext(), llvm::AttributeSet::FunctionIndex, - llvm::Attribute::NoUnwind)); + llvm::Attribute::NoUnwind), + /*Local=*/true); } namespace { diff --git a/test/CodeGenCXX/runtime-dllstorage.cpp b/test/CodeGenCXX/runtime-dllstorage.cpp new file mode 100644 index 0000000000..76c002c0e4 --- /dev/null +++ b/test/CodeGenCXX/runtime-dllstorage.cpp @@ -0,0 +1,158 @@ +// RUN: %clang_cc1 -triple i686-windows-msvc -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-MS -check-prefix CHECK-MS-DYNAMIC +// RUN: %clang_cc1 -triple i686-windows-msvc -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -flto-visibility-public-std -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-MS -check-prefix CHECK-MS-STATIC + +// RUN: %clang_cc1 -triple i686-windows-itanium -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-DYNAMIC-IA -check-prefix CHECK-DYNAMIC-NODECL-IA -check-prefix CHECK-DYANMIC-IA-CXA-ATEXIT +// RUN: %clang_cc1 -triple i686-windows-itanium -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -flto-visibility-public-std -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-STATIC-IA -check-prefix CHECK-STATIC-NODECL-IA -check-prefix CHECK-IA-STATIC-CXA-ATEXIT +// RUN: %clang_cc1 -triple i686-windows-itanium -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -DIMPORT_DECLARATIONS -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-DYNAMIC-IA -check-prefix CHECK-DYNAMIC-IMPORT-IA -check-prefix CHECK-DYANMIC-IA-CXA-ATEXIT +// RUN: %clang_cc1 -triple i686-windows-itanium -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -flto-visibility-public-std -DIMPORT_DECLARATIONS -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-STATIC-IA -check-prefix CHECK-STATIC-IMPORT-IA -check-prefix CHECK-IA-STATIC-CXA-ATEXIT +// RUN: %clang_cc1 -triple i686-windows-itanium -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -DEXPORT_DECLARATIONS -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-DYNAMIC-IA -check-prefix CHECK-DYANMIC-IA-CXA-ATEXIT +// RUN: %clang_cc1 -triple i686-windows-itanium -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -flto-visibility-public-std -DEXPORT_DECLARATIONS -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-STATIC-IA -check-prefix CHECK-IA-STATIC-CXA-ATEXIT +// RUN: %clang_cc1 -triple i686-windows-itanium -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -DDECL -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-DYNAMIC-IA -check-prefix CHECK-DYNAMIC-DECL-IA -check-prefix CHECK-DYANMIC-IA-CXA-ATEXIT +// RUN: %clang_cc1 -triple i686-windows-itanium -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -flto-visibility-public-std -DDECL -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-STATIC-IA -check-prefix CHECK-STATIC-DECL-IA -check-prefix CHECK-IA-STATIC-CXA-ATEXIT +// %clang_cc1 -triple i686-windows-itanium -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -fno-use-cxa-atexit -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-DYNAMIC-IA -check-prefix CHECK-DYNAMIC-IA-ATEXIT +// %clang_cc1 -triple i686-windows-itanium -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -fno-use-cxa-atexit -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-STATIC-IA -check-prefix CHECK-STATIC-IA-ATEXIT + +// RUN: %clang_cc1 -triple i686-windows-gnu -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-DYNAMIC-IA +// RUN: %clang_cc1 -triple i686-windows-gnu -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -flto-visibility-public-std -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-STATIC-IA +// RUN: %clang_cc1 -triple i686-windows-cygnus -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-DYNAMIC-IA +// RUN: %clang_cc1 -triple i686-windows-cygnus -std=c++11 -fdeclspec -fms-compatibility -fexceptions -fcxx-exceptions -flto-visibility-public-std -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK-IA -check-prefix CHECK-STATIC-IA + +#if defined(IMPORT_DECLARATIONS) +namespace __cxxabiv1 { +extern "C" { +__declspec(dllimport) void __cxa_guard_acquire(unsigned long long *); +__declspec(dllimport) unsigned char *__cxa_allocate_exception(unsigned long); +} +extern "C" __declspec(dllimport) void __cxa_guard_release(unsigned long long *); +} +namespace std { +__declspec(dllimport) __declspec(noreturn) void terminate(); +} +#elif defined(EXPORT_DECLARATIONS) +namespace __cxxabiv1 { +extern "C" { +__declspec(dllexport) void __cxa_guard_acquire(unsigned long long *); +__declspec(dllexport) unsigned char *__cxa_allocate_exception(unsigned long); +} +extern "C" void __declspec(dllexport) __cxa_guard_release(unsigned long long *); +} +namespace std { +__declspec(dllexport) __declspec(noreturn) void terminate(); +} +#elif defined(DECL) +namespace __cxxabiv1 { +extern "C" unsigned char *__cxa_allocate_exception(unsigned long); +} +namespace std { +__declspec(noreturn) void terminate(); +} +#else +namespace std { +__declspec(noreturn) void terminate(); +} +#endif + +struct s { + s() = default; + s(unsigned char) { throw 0; } + int m() const; +}; + +struct t { + ~t(); + int m() const; +}; + +struct u { + ~u(); +}; + +s o; +thread_local t t; +u v; +__declspec(thread) s q; + +void __declspec(noinline) f() { + throw 0; +} + +void g(); +void __declspec(noinline) h() { + try { + g(); + } catch (const int &) { + return; + } catch (...) { + throw; + } +} + +void i() { + s r(static_cast('\t')); +} + +int j() { + static thread_local struct t v; + static struct t *w = new struct t; + return w->m() ? v.m() : w->m(); +} + +void k() noexcept { + g(); +} + +void l() { + std::terminate(); +} + +// CHECK-MS-DAG: @_Init_thread_epoch = external thread_local global i32 +// CHECK-MS-DAG: declare i32 @__tlregdtor(void ()*) +// CHECK-MS-DAG: declare i32 @atexit(void ()*) +// CHECK-MS-DYNAMIC-DAG: declare dllimport {{.*}} void @_CxxThrowException +// CHECK-MS-STATIC-DAG: declare {{.*}} void @_CxxThrowException +// CHECK-MS-DAG: declare noalias i8* @"\01??2@YAPAXI@Z" +// CHECK-MS-DAG: declare void @_Init_thread_header(i32*) +// CHECK-MS-DAG: declare void @_Init_thread_footer(i32*) + +// CHECK-IA-DAG: declare i32 @__gxx_personality_v0(...) +// CHECK-IA-DAG: define linkonce_odr hidden void @__clang_call_terminate(i8*) + +// CHECK-DYNAMIC-IA-DAG: declare dllimport i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*) +// CHECK-DYNAMIC-IA-DAG: declare dllimport i32 @__cxa_atexit(void (i8*)*, i8*, i8*) +// CHECK-DYNAMIC-IA-DECL-DAG: declare i8* @__cxa_allocate_exception(i32) +// CHECK-DYNAMIC-IA-NODECL-DAG: declare dllimport i8* @__cxa_allocate_exception(i32) +// CHECK-DYNAMIC-IA-IMPORT-DAG: declare dllimport i8* @__cxa_allocate_exception(i32) +// CHECK-DYNAMIC-IA-EXPORT-DAG: declare dllimport i8* @__cxa_allocate_exception(i32) +// CHECK-DYNAMIC-IA-DAG: declare dllimport void @__cxa_throw(i8*, i8*, i8*) +// CHECK-DYNAMIC-DECL-IA-DAG: declare dllimport i32 @__cxa_guard_acquire(i64*) +// CHECK-DYNAMIC-NODECL-IA-DAG: declare dllimport i32 @__cxa_guard_acquire(i64*) +// CHECK-DYNAMIC-IMPORT-IA-DAG: declare dllimport i32 @__cxa_guard_acquire(i64*) +// CHECK-DYNAMIC-EXPORT-IA-DAG: declare dllexport i32 @__cxa_guard_acquire(i64*) +// CHECK-IA-DAG: declare noalias i8* @_Znwj(i32) +// CHECK-DYNAMIC-DECL-IA-DAG: declare dllimport void @__cxa_guard_release(i64*) +// CHECK-DYNAMIC-NODECL-IA-DAG: declare dllimport void @__cxa_guard_release(i64*) +// CHECK-DYNAMIC-IMPORT-IA-DAG: declare dllimport void @__cxa_guard_release(i64*) +// CHECK-DYNAMIC-EXPORT-IA-DAG: declare dllimport void @__cxa_guard_release(i64*) +// CHECK-DYANMIC-IA-DAG: declare dllimport void @_ZSt9terminatev() +// CHECK-DYNAMIC-NODECL-IA-DAG: declare void @_ZSt9terminatev() +// CHECK-DYNAMIC-IMPORT-IA-DAG: declare dllimport void @_ZSt9terminatev() +// CHECK-DYNAMIC-EXPORT-IA-DAG: declare dllexport void @_ZSt9terminatev() + +// CHECK-STATIC-IA-DAG: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*) +// CHECK-STATIC-IA-DAG: declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*) +// CHECK-STATIC-IA-DAG: declare i8* @__cxa_allocate_exception(i32) +// CHECK-STATIC-IA-DAG: declare void @__cxa_throw(i8*, i8*, i8*) +// CHECK-STATIC-DECL-IA-DAG: declare i32 @__cxa_guard_acquire(i64*) +// CHECK-STATIC-NODECL-IA-DAG: declare i32 @__cxa_guard_acquire(i64*) +// CHECK-STATIC-IMPORT-IA-DAG: declare i32 @__cxa_guard_acquire(i64*) +// CHECK-STATIC-EXPORT-IA-DAG: declare i32 @__cxa_guard_acquire(i64*) +// CHECK-IA-DAG: declare noalias i8* @_Znwj(i32) +// CHECK-STATIC-DECL-IA-DAG: declare void @__cxa_guard_release(i64*) +// CHECK-STATIC-NODECL-IA-DAG: declare void @__cxa_guard_release(i64*) +// CHECK-STATIC-IMPORT-IA-DAG: declare void @__cxa_guard_release(i64*) +// CHECK-STATIC-EXPORT-IA-DAG: declare void @__cxa_guard_release(i64*) +// CHECK-STATIC-IA-DAG: declare void @_ZSt9terminatev() +// CHECK-STATIC-NODECL-IA-DAG: declare void @_ZSt9terminatev() +// CHECK-STATIC-IMPORT-IA-DAG: declare void @_ZSt9terminatev() +// CHECK-STATIC-EXPORT-IA-DAG: declare dllexport void @_ZSt9terminatev() +