Skip to content

Commit c537dd9

Browse files
authored
[MS] Put dllexported inline global initializers in a comdat (#107154)
Follow-up to c19f4f8 to handle corner case of exported inline variables. Should fix #56485
1 parent 7764959 commit c537dd9

File tree

2 files changed

+33
-15
lines changed

2 files changed

+33
-15
lines changed

clang/lib/CodeGen/CGDeclCXX.cpp

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -586,31 +586,50 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
586586
PrioritizedCXXGlobalInits.size());
587587
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
588588
} else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) ||
589-
getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR ||
589+
!isUniqueGVALinkage(getContext().GetGVALinkageForVariable(D)) ||
590590
D->hasAttr<SelectAnyAttr>()) {
591+
// For vague linkage globals, put the initializer into its own global_ctors
592+
// entry with the global as a comdat key. This ensures at most one
593+
// initializer per DSO runs during DSO dynamic initialization.
594+
//
595+
// For ELF platforms, this is an important code size and startup time
596+
// optimization. For dynamic, non-hidden symbols, the weak guard variable
597+
// remains to ensure that other DSOs do not re-initialize the global.
598+
//
599+
// For PE-COFF platforms, there is no guard variable, and COMDAT
600+
// associativity is the only way to ensure vauge linkage globals are
601+
// initialized exactly once.
602+
//
603+
// MachO is the only remaining platform with no comdats that doesn't
604+
// benefit from this optimization. The rest are mainly modeled on ELF
605+
// behavior.
606+
//
607+
// C++ requires that inline global variables are initialized in source
608+
// order, but this requirement does not exist for templated entities.
609+
// llvm.global_ctors does not guarantee initialization order, so in
610+
// general, Clang does not fully conform to the ordering requirement.
611+
// However, in practice, LLVM emits global_ctors in the provided order, and
612+
// users typically don't rely on ordering between inline globals in
613+
// different headers which are then transitively included in varying order.
614+
// Clang's current behavior is a practical tradeoff, since dropping the
615+
// comdat would lead to unacceptable impact on code size and startup time.
616+
//
617+
// FIXME: Find a solution to guarantee source-order initialization of
618+
// inline variables.
619+
//
591620
// C++ [basic.start.init]p2:
592621
// Definitions of explicitly specialized class template static data
593622
// members have ordered initialization. Other class template static data
594623
// members (i.e., implicitly or explicitly instantiated specializations)
595624
// have unordered initialization.
596625
//
597-
// As a consequence, we can put them into their own llvm.global_ctors entry.
598-
//
599-
// If the global is externally visible, put the initializer into a COMDAT
600-
// group with the global being initialized. On most platforms, this is a
601-
// minor startup time optimization. In the MS C++ ABI, there are no guard
602-
// variables, so this COMDAT key is required for correctness.
603-
//
604-
// SelectAny globals will be comdat-folded. Put the initializer into a
605-
// COMDAT group associated with the global, so the initializers get folded
606-
// too.
607-
I = DelayedCXXInitPosition.find(D);
608626
// CXXGlobalInits.size() is the lex order number for the next deferred
609627
// VarDecl. Use it when the current VarDecl is non-deferred. Although this
610628
// lex order number is shared between current VarDecl and some following
611629
// VarDecls, their order of insertion into `llvm.global_ctors` is the same
612630
// as the lexing order and the following stable sort would preserve such
613631
// order.
632+
I = DelayedCXXInitPosition.find(D);
614633
unsigned LexOrder =
615634
I == DelayedCXXInitPosition.end() ? CXXGlobalInits.size() : I->second;
616635
AddGlobalCtor(Fn, 65535, LexOrder, COMDATKey);

clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ struct X {
4949
static T ioo;
5050
static T init();
5151
};
52-
// template specialized static data don't need in llvm.used,
53-
// the static init routine get call from _GLOBAL__sub_I_ routines.
5452
template <> int X<int>::ioo = X<int>::init();
5553
template struct X<int>;
5654
class a {
@@ -87,5 +85,6 @@ struct S1
8785
int foo();
8886
inline int zoo = foo();
8987
inline static int boo = foo();
88+
inline __declspec(dllexport) A exported_inline{};
9089

91-
// 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"
90+
// 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"

0 commit comments

Comments
 (0)