https://github.com/rnk updated https://github.com/llvm/llvm-project/pull/107154
>From cfb2cea5a4d4e0c1712e038692c4c5acee6b1f27 Mon Sep 17 00:00:00 2001 From: Reid Kleckner <r...@google.com> Date: Tue, 3 Sep 2024 21:16:40 +0000 Subject: [PATCH 1/2] [MS] Put dllexported inline global initializers in a comdat Follow-up to c19f4f8069722f6804086d4438a0254104242c46 to handle corner case of exported inline variables. Should fix #56485 --- clang/lib/CodeGen/CGDeclCXX.cpp | 2 +- clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 2f56355cff90ec..c9e0fb0d8afaba 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -586,7 +586,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, PrioritizedCXXGlobalInits.size()); PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn)); } else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) || - getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR || + !isUniqueGVALinkage(getContext().GetGVALinkageForVariable(D)) || D->hasAttr<SelectAnyAttr>()) { // C++ [basic.start.init]p2: // Definitions of explicitly specialized class template static data diff --git a/clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp b/clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp index 60b48abca2f89a..871551240debfd 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp @@ -49,8 +49,6 @@ struct X { static T ioo; static T init(); }; -// template specialized static data don't need in llvm.used, -// the static init routine get call from _GLOBAL__sub_I_ routines. template <> int X<int>::ioo = X<int>::init(); template struct X<int>; class a { @@ -87,5 +85,6 @@ struct S1 int foo(); inline int zoo = foo(); inline static int boo = foo(); +inline __declspec(dllexport) A exported_inline{}; -// CHECK: @llvm.used = appending global [8 x ptr] [ptr @"?x@selectany_init@@3HA", ptr @"?x1@selectany_init@@3HA", ptr @"?x@?$A@H@explicit_template_instantiation@@2HA", ptr @"?ioo@?$X_@H@@2HA", ptr @"?aoo@S1@@2UA@@A", ptr @"?zoo@@3HA", ptr @"?s@?$ExportedTemplate@H@@2US@@A", ptr @"?x@?$A@H@implicit_template_instantiation@@2HA"], section "llvm.metadata" +// CHECK: @llvm.used = appending global [10 x ptr] [ptr @"?x@selectany_init@@3HA", ptr @"?x1@selectany_init@@3HA", ptr @"?x@?$A@H@explicit_template_instantiation@@2HA", ptr @"?ioo@?$X_@H@@2HA", ptr @"?ioo@?$X@H@@2HA", ptr @"?aoo@S1@@2UA@@A", ptr @"?zoo@@3HA", ptr @"?exported_inline@@3UA@@A", ptr @"?s@?$ExportedTemplate@H@@2US@@A", ptr @"?x@?$A@H@implicit_template_instantiation@@2HA"], section "llvm.metadata" >From 3cb368a8c01f99a7b12ece55e5b2145650d4f89d Mon Sep 17 00:00:00 2001 From: Reid Kleckner <r...@google.com> Date: Tue, 3 Sep 2024 23:38:51 +0000 Subject: [PATCH 2/2] Update comment block on why vague linkage global initialization is different --- clang/lib/CodeGen/CGDeclCXX.cpp | 41 ++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index c9e0fb0d8afaba..1ae8a2674df20d 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -588,29 +588,48 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, } else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) || !isUniqueGVALinkage(getContext().GetGVALinkageForVariable(D)) || D->hasAttr<SelectAnyAttr>()) { + // For vague linkage globals, put the initializer into its own global_ctors + // entry with the global as a comdat key. This ensures at most one + // initializer per DSO runs during DSO dynamic initialization. + // + // For ELF platforms, this is an important code size and startup time + // optimization. For dynamic, non-hidden symbols, the weak guard variable + // remains to ensure that other DSOs do not re-initialize the global. + // + // For PE-COFF platforms, there is no guard variable, and COMDAT associativity + // is the only way to ensure vauge linkage globals are initialized exactly + // once. + // + // MachO is the only remaining platform with no comdats that doesn't + // benefit from this optimization. The rest are mainly modeled on ELF + // behavior. + // + // C++ requires that inline global variables are initialized in source + // order, but this requirement does not exist for templated entities. + // llvm.global_ctors does not guarantee initialization order, so in + // general, Clang does not fully conform to the ordering requirement. + // However, in practice, LLVM emits global_ctors in the provided order, and + // users typically don't rely on ordering between inline globals in + // different headers which are then transitively included in varying order. + // Clang's current behavior is a practical tradeoff, since dropping the + // comdat would lead to unacceptable impact on code size and startup time. + // + // FIXME: Find a solution to guarantee source-order initialization of + // inline variables. + // // C++ [basic.start.init]p2: // Definitions of explicitly specialized class template static data // members have ordered initialization. Other class template static data // members (i.e., implicitly or explicitly instantiated specializations) // have unordered initialization. // - // As a consequence, we can put them into their own llvm.global_ctors entry. - // - // If the global is externally visible, put the initializer into a COMDAT - // group with the global being initialized. On most platforms, this is a - // minor startup time optimization. In the MS C++ ABI, there are no guard - // variables, so this COMDAT key is required for correctness. - // - // SelectAny globals will be comdat-folded. Put the initializer into a - // COMDAT group associated with the global, so the initializers get folded - // too. - I = DelayedCXXInitPosition.find(D); // CXXGlobalInits.size() is the lex order number for the next deferred // VarDecl. Use it when the current VarDecl is non-deferred. Although this // lex order number is shared between current VarDecl and some following // VarDecls, their order of insertion into `llvm.global_ctors` is the same // as the lexing order and the following stable sort would preserve such // order. + I = DelayedCXXInitPosition.find(D); unsigned LexOrder = I == DelayedCXXInitPosition.end() ? CXXGlobalInits.size() : I->second; AddGlobalCtor(Fn, 65535, LexOrder, COMDATKey); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits