diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 8ceb4863d6ea..207585784865 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -562,7 +562,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, Priority = 400; if (Priority != -1) - AddGlobalCtor(Fn, Priority, COMDATKey); + AddGlobalCtor(Fn, Priority, ~0U, COMDATKey); else EmitPointerToInitFunc(D, Addr, Fn, ISA); } else if (auto *IPA = D->getAttr()) { @@ -588,8 +588,16 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, // SelectAny globals will be comdat-folded. Put the initializer into a // COMDAT group associated with the global, so the initializers get folded // too. - - AddGlobalCtor(Fn, 65535, COMDATKey); + 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. + unsigned LexOrder = + I == DelayedCXXInitPosition.end() ? CXXGlobalInits.size() : I->second; + AddGlobalCtor(Fn, 65535, LexOrder, COMDATKey); if (COMDATKey && (getTriple().isOSBinFormatELF() || getTarget().getCXXABI().isMicrosoft())) { // When COMDAT is used on ELF or in the MS C++ ABI, the key must be in diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 9b97e890c352..74c14fed6575 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -47,6 +47,7 @@ #include "clang/CodeGen/BackendUtil.h" #include "clang/CodeGen/ConstantInitBuilder.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -560,6 +561,9 @@ void CodeGenModule::Release() { if (PGOStats.hasDiagnostics()) PGOStats.reportDiagnostics(getDiags(), getCodeGenOpts().MainFileName); } + llvm::stable_sort(GlobalCtors, [](const Structor &L, const Structor &R) { + return L.LexOrder < R.LexOrder; + }); EmitCtorList(GlobalCtors, "llvm.global_ctors"); EmitCtorList(GlobalDtors, "llvm.global_dtors"); EmitGlobalAnnotations(); @@ -1579,9 +1583,10 @@ llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) { /// AddGlobalCtor - Add a function to the list that will be called before /// main() runs. void CodeGenModule::AddGlobalCtor(llvm::Function *Ctor, int Priority, + unsigned LexOrder, llvm::Constant *AssociatedData) { // FIXME: Type coercion of void()* types. - GlobalCtors.push_back(Structor(Priority, Ctor, AssociatedData)); + GlobalCtors.push_back(Structor(Priority, LexOrder, Ctor, AssociatedData)); } /// AddGlobalDtor - Add a function to the list that will be called @@ -1595,7 +1600,7 @@ void CodeGenModule::AddGlobalDtor(llvm::Function *Dtor, int Priority, } // FIXME: Type coercion of void()* types. - GlobalDtors.push_back(Structor(Priority, Dtor, nullptr)); + GlobalDtors.push_back(Structor(Priority, ~0U, Dtor, nullptr)); } void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) { diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 14c791f4bce5..f57afdca4942 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -282,12 +282,15 @@ class CodeGenModule : public CodeGenTypeCache { public: struct Structor { - Structor() : Priority(0), Initializer(nullptr), AssociatedData(nullptr) {} - Structor(int Priority, llvm::Constant *Initializer, + Structor() + : Priority(0), LexOrder(~0u), Initializer(nullptr), + AssociatedData(nullptr) {} + Structor(int Priority, unsigned LexOrder, llvm::Constant *Initializer, llvm::Constant *AssociatedData) - : Priority(Priority), Initializer(Initializer), + : Priority(Priority), LexOrder(LexOrder), Initializer(Initializer), AssociatedData(AssociatedData) {} int Priority; + unsigned LexOrder; llvm::Constant *Initializer; llvm::Constant *AssociatedData; }; @@ -1602,6 +1605,7 @@ private: // FIXME: Hardcoding priority here is gross. void AddGlobalCtor(llvm::Function *Ctor, int Priority = 65535, + unsigned LexOrder = ~0U, llvm::Constant *AssociatedData = nullptr); void AddGlobalDtor(llvm::Function *Dtor, int Priority = 65535, bool IsDtorAttrFunc = false); diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 002a5edabe22..2809cbe99c10 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -2687,7 +2687,7 @@ void CodeGenModule::registerGlobalDtorsWithAtExit() { } CGF.FinishFunction(); - AddGlobalCtor(GlobalInitFn, Priority, nullptr); + AddGlobalCtor(GlobalInitFn, Priority); } if (getCXXABI().useSinitAndSterm()) diff --git a/clang/test/CodeGenCXX/static-init-inline-variable.cpp b/clang/test/CodeGenCXX/static-init-inline-variable.cpp new file mode 100644 index 000000000000..873e32544c7e --- /dev/null +++ b/clang/test/CodeGenCXX/static-init-inline-variable.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -std=c++17 -S -emit-llvm -disable-llvm-passes -o - %s -triple x86_64-linux-gnu | FileCheck %s + +struct A { + int x; + A(int x) : x(x) {} + ~A() {} +}; + +namespace DeferredSequence { +inline int a = 1; +inline int b = a + 1; +inline int c = b + 1; +inline int d = c + 1; +int e = d; +} + +namespace MixedSequence { +inline A a(1); +inline int x = a.x + 1; +inline int y = x + 1; +inline A b(y); +inline int z = b.x + 1; +inline int w = z + 1; +inline A c(b.x); +inline A d(c.x); +int t = w; +} + +namespace NonDeferredSequence { +inline A a(1); +inline A b(a.x); +inline A c(b.x); +inline A d(c.x); +} + +// CHECK: @llvm.global_ctors = appending global [16 x { i32, ptr, ptr }] [ +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.12, ptr @_ZN16DeferredSequence1bE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.11, ptr @_ZN16DeferredSequence1cE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.10, ptr @_ZN16DeferredSequence1dE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.1, ptr @_ZN13MixedSequence1aE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.14, ptr @_ZN13MixedSequence1xE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.13, ptr @_ZN13MixedSequence1yE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.2, ptr @_ZN13MixedSequence1bE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.16, ptr @_ZN13MixedSequence1zE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.15, ptr @_ZN13MixedSequence1wE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.3, ptr @_ZN13MixedSequence1cE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.4, ptr @_ZN13MixedSequence1dE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.6, ptr @_ZN19NonDeferredSequence1aE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.7, ptr @_ZN19NonDeferredSequence1bE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.8, ptr @_ZN19NonDeferredSequence1cE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @__cxx_global_var_init.9, ptr @_ZN19NonDeferredSequence1dE }, +// CHECK-SAME: { i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_static_init_inline_variable.cpp, ptr null }