https://github.com/schizophrenicmaniac updated https://github.com/llvm/llvm-project/pull/226645
>From 045a77f1533f3a4659c21565015753e3d8631ebc Mon Sep 17 00:00:00 2001 From: Divyansh <[email protected]> Date: Sat, 26 Sep 2026 11:56:14 +0530 Subject: [PATCH 1/2] [clang][CodeGen] Use guarded init for weak static locals without constant init (#226631) --- clang/lib/CodeGen/CGDecl.cpp | 22 ++++-- .../static-local-inline-non-constant-init.cpp | 77 +++++++++++++++++++ 2 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index e1ed66ae71243e..bbf94e8c4ecce1 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -224,10 +224,6 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) { llvm::GlobalValue::LinkageTypes Linkage = CGM.getLLVMLinkageVarDefinition(&D); - // FIXME: We need to force the emission/use of a guard variable for - // some variables even if we can constant-evaluate them because - // we can't guarantee every translation unit will constant-evaluate them. - return EmitStaticVarDecl(D, Linkage); } @@ -360,8 +356,24 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( llvm::GlobalVariable * CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, llvm::GlobalVariable *GV) { + // A static local with vague linkage (e.g. one in an inline function) is + // shared by every translation unit that emits it, but only a constant + // initializer is guaranteed to be emitted as a constant in all of them. If + // we were to fold an initializer that another translation unit can't fold + // (say, because it reads a variable whose initializer is only visible here), + // that translation unit would perform a guarded initialization which could + // store to our copy of the variable (possibly placed in read-only memory) or + // race with our unguarded reads of it. Use a guarded initialization here as + // well, so that every translation unit agrees on how the variable is + // initialized. + bool NeedsGuardedInit = + getLangOpts().CPlusPlus && !getLangOpts().CUDAIsDevice && + GV->isWeakForLinker() && !D.hasConstantInitialization() && + !D.hasFlexibleArrayInit(getContext()); + ConstantEmitter emitter(*this); - llvm::Constant *Init = emitter.tryEmitForInitializer(D); + llvm::Constant *Init = + NeedsGuardedInit ? nullptr : emitter.tryEmitForInitializer(D); // If constant emission failed, then this should be a C++ static // initializer. diff --git a/clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp b/clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp new file mode 100644 index 00000000000000..ec78d2d90e3600 --- /dev/null +++ b/clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -o - %s | FileCheck %s --check-prefix=ITANIUM +// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=c++17 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSVC + +// A static local in an inline function is shared by every translation unit +// that uses the function. If its initializer isn't a constant initializer, +// another translation unit might not be able to fold it (here, one that can't +// see the initializer of kSize) and will initialize the variable dynamically, +// behind a guard variable. So it must not be emitted as a (possibly read-only) +// constant without a guard in this translation unit either. +// See https://github.com/llvm/llvm-project/issues/226631. + +extern const int kSize; + +inline const int &instance() { + static const int meta = kSize; + return meta; +} + +// Constant initializers are still emitted as constants, without a guard. +inline const int &constant() { + static const int c = 42; + return c; +} + +// A static local that isn't shared with other translation units can still be +// folded, even if its initializer isn't a constant initializer. +static const int &internal() { + static const int i = kSize; + return i; +} + +extern const int kSize = 3; + +const int *a() { return &instance(); } +const int *b() { return &constant(); } +const int *c() { return &internal(); } + +// ITANIUM-DAG: @_ZZ8instancevE4meta = linkonce_odr global i32 0, comdat, align 4 +// ITANIUM-DAG: @_ZGVZ8instancevE4meta = linkonce_odr global i64 0, comdat, align 8 +// ITANIUM-DAG: @_ZZ8constantvE1c = linkonce_odr constant i32 42, comdat, align 4 +// ITANIUM-DAG: @_ZZL8internalvE1i = internal constant i32 3, align 4 +// ITANIUM-NOT: @_ZGVZ8constantvE1c +// ITANIUM-NOT: @_ZGVZL8internalvE1i + +// ITANIUM-LABEL: define linkonce_odr {{.*}} ptr @_Z8instancev() +// ITANIUM: load atomic i8, ptr @_ZGVZ8instancevE4meta acquire +// ITANIUM: call i32 @__cxa_guard_acquire(ptr @_ZGVZ8instancevE4meta) +// ITANIUM: store i32 3, ptr @_ZZ8instancevE4meta +// ITANIUM: call void @__cxa_guard_release(ptr @_ZGVZ8instancevE4meta) +// ITANIUM: ret ptr @_ZZ8instancevE4meta + +// ITANIUM-LABEL: define linkonce_odr {{.*}} ptr @_Z8constantv() +// ITANIUM-NEXT: entry: +// ITANIUM-NEXT: ret ptr @_ZZ8constantvE1c + +// ITANIUM-LABEL: define internal {{.*}} ptr @_ZL8internalv() +// ITANIUM-NEXT: entry: +// ITANIUM-NEXT: ret ptr @_ZZL8internalvE1i + +// MSVC-DAG: @"?meta@?1??instance@@YAAEBHXZ@4HB" = linkonce_odr dso_local global i32 0, comdat, align 4 +// MSVC-DAG: @"?$TSS0@?1??instance@@YAAEBHXZ@4HA" = linkonce_odr global i32 0, comdat, align 4 +// MSVC-DAG: @"?c@?1??constant@@YAAEBHXZ@4HB" = linkonce_odr dso_local constant i32 42, comdat, align 4 +// MSVC-DAG: @"?i@?1??internal@@YAAEBHXZ@4HB" = internal constant i32 3, align 4 + +// MSVC-LABEL: define linkonce_odr {{.*}} ptr @"?instance@@YAAEBHXZ"() +// MSVC: call void @_Init_thread_header(ptr @"?$TSS0@?1??instance@@YAAEBHXZ@4HA") +// MSVC: store i32 3, ptr @"?meta@?1??instance@@YAAEBHXZ@4HB" +// MSVC: call void @_Init_thread_footer(ptr @"?$TSS0@?1??instance@@YAAEBHXZ@4HA") +// MSVC: ret ptr @"?meta@?1??instance@@YAAEBHXZ@4HB" + +// MSVC-LABEL: define linkonce_odr {{.*}} ptr @"?constant@@YAAEBHXZ"() +// MSVC-NEXT: entry: +// MSVC-NEXT: ret ptr @"?c@?1??constant@@YAAEBHXZ@4HB" + +// MSVC-LABEL: define internal {{.*}} ptr @"?internal@@YAAEBHXZ"() +// MSVC-NEXT: entry: +// MSVC-NEXT: ret ptr @"?i@?1??internal@@YAAEBHXZ@4HB" >From c9a8d315376307fa60bf58aa1e5d013def5cc49c Mon Sep 17 00:00:00 2001 From: Divyansh <[email protected]> Date: Mon, 28 Sep 2026 00:02:13 +0530 Subject: [PATCH 2/2] [clang][CodeGen] Also use dynamic init for inline variables and templated static data members without constant init --- clang/lib/CodeGen/CGDecl.cpp | 20 +-- clang/lib/CodeGen/CodeGenModule.cpp | 29 +++- clang/lib/CodeGen/CodeGenModule.h | 4 + .../static-local-inline-non-constant-init.cpp | 77 ---------- .../vague-linkage-non-constant-init.cpp | 132 ++++++++++++++++++ 5 files changed, 166 insertions(+), 96 deletions(-) delete mode 100644 clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp create mode 100644 clang/test/CodeGenCXX/vague-linkage-non-constant-init.cpp diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index bbf94e8c4ecce1..7a03893cb715e1 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -356,24 +356,10 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( llvm::GlobalVariable * CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, llvm::GlobalVariable *GV) { - // A static local with vague linkage (e.g. one in an inline function) is - // shared by every translation unit that emits it, but only a constant - // initializer is guaranteed to be emitted as a constant in all of them. If - // we were to fold an initializer that another translation unit can't fold - // (say, because it reads a variable whose initializer is only visible here), - // that translation unit would perform a guarded initialization which could - // store to our copy of the variable (possibly placed in read-only memory) or - // race with our unguarded reads of it. Use a guarded initialization here as - // well, so that every translation unit agrees on how the variable is - // initialized. - bool NeedsGuardedInit = - getLangOpts().CPlusPlus && !getLangOpts().CUDAIsDevice && - GV->isWeakForLinker() && !D.hasConstantInitialization() && - !D.hasFlexibleArrayInit(getContext()); - ConstantEmitter emitter(*this); - llvm::Constant *Init = - NeedsGuardedInit ? nullptr : emitter.tryEmitForInitializer(D); + llvm::Constant *Init = CGM.mustDynamicallyInitialize(D) + ? nullptr + : emitter.tryEmitForInitializer(D); // If constant emission failed, then this should be a C++ static // initializer. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 7274a8588670f4..b4c907afc07140 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -6649,8 +6649,11 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, Init = EmitNullConstant(D->getType()); } else { initializedGlobalDecl = GlobalDecl(D); - emitter.emplace(*this); - llvm::Constant *Initializer = emitter->tryEmitForInitializer(*InitDecl); + llvm::Constant *Initializer = nullptr; + if (!mustDynamicallyInitialize(*D)) { + emitter.emplace(*this); + Initializer = emitter->tryEmitForInitializer(*InitDecl); + } if (!Initializer) { QualType T = InitExpr->getType(); if (D->getType()->isReferenceType()) @@ -7013,6 +7016,28 @@ CodeGenModule::getLLVMLinkageVarDefinition(const VarDecl *VD) { return getLLVMLinkageForDeclarator(VD, Linkage); } +bool CodeGenModule::mustDynamicallyInitialize(const VarDecl &D) { + // A variable with vague linkage (an inline variable, a static data member of + // a class template, a static local of an inline function, ...) is shared by + // every translation unit that emits it, but only a constant initializer is + // guaranteed to be constant-folded in all of them. If we were to fold an + // initializer that another translation unit can't fold (say, because it + // reads a variable whose initializer is only visible here), that translation + // unit would initialize the variable dynamically, and could store to our + // copy of it (possibly placed in read-only memory) or race with our + // unguarded reads of it. Initialize it dynamically here as well, so that + // every translation unit agrees on how the variable is initialized. + if (!getLangOpts().CPlusPlus || getLangOpts().CUDAIsDevice) + return false; + + const VarDecl *InitDecl; + if (!D.getAnyInitializer(InitDecl) || InitDecl->hasConstantInitialization() || + InitDecl->hasFlexibleArrayInit(getContext())) + return false; + + return llvm::GlobalValue::isWeakForLinker(getLLVMLinkageVarDefinition(&D)); +} + /// Replace the uses of a function that was declared with a non-proto type. /// We want to silently drop extra arguments from call sites static void replaceUsesOfNonProtoConstant(llvm::Constant *old, diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 9e3f073c20f4a0..b6eb86b903f1ce 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1583,6 +1583,10 @@ class CodeGenModule : public CodeGenTypeCache { llvm::GlobalValue::LinkageTypes getLLVMLinkageVarDefinition(const VarDecl *VD); + /// Returns true if the initializer of \p D must not be constant-folded, + /// because other translation units might initialize it dynamically. + bool mustDynamicallyInitialize(const VarDecl &D); + /// Emit all the global annotations. void EmitGlobalAnnotations(); diff --git a/clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp b/clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp deleted file mode 100644 index ec78d2d90e3600..00000000000000 --- a/clang/test/CodeGenCXX/static-local-inline-non-constant-init.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -o - %s | FileCheck %s --check-prefix=ITANIUM -// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=c++17 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSVC - -// A static local in an inline function is shared by every translation unit -// that uses the function. If its initializer isn't a constant initializer, -// another translation unit might not be able to fold it (here, one that can't -// see the initializer of kSize) and will initialize the variable dynamically, -// behind a guard variable. So it must not be emitted as a (possibly read-only) -// constant without a guard in this translation unit either. -// See https://github.com/llvm/llvm-project/issues/226631. - -extern const int kSize; - -inline const int &instance() { - static const int meta = kSize; - return meta; -} - -// Constant initializers are still emitted as constants, without a guard. -inline const int &constant() { - static const int c = 42; - return c; -} - -// A static local that isn't shared with other translation units can still be -// folded, even if its initializer isn't a constant initializer. -static const int &internal() { - static const int i = kSize; - return i; -} - -extern const int kSize = 3; - -const int *a() { return &instance(); } -const int *b() { return &constant(); } -const int *c() { return &internal(); } - -// ITANIUM-DAG: @_ZZ8instancevE4meta = linkonce_odr global i32 0, comdat, align 4 -// ITANIUM-DAG: @_ZGVZ8instancevE4meta = linkonce_odr global i64 0, comdat, align 8 -// ITANIUM-DAG: @_ZZ8constantvE1c = linkonce_odr constant i32 42, comdat, align 4 -// ITANIUM-DAG: @_ZZL8internalvE1i = internal constant i32 3, align 4 -// ITANIUM-NOT: @_ZGVZ8constantvE1c -// ITANIUM-NOT: @_ZGVZL8internalvE1i - -// ITANIUM-LABEL: define linkonce_odr {{.*}} ptr @_Z8instancev() -// ITANIUM: load atomic i8, ptr @_ZGVZ8instancevE4meta acquire -// ITANIUM: call i32 @__cxa_guard_acquire(ptr @_ZGVZ8instancevE4meta) -// ITANIUM: store i32 3, ptr @_ZZ8instancevE4meta -// ITANIUM: call void @__cxa_guard_release(ptr @_ZGVZ8instancevE4meta) -// ITANIUM: ret ptr @_ZZ8instancevE4meta - -// ITANIUM-LABEL: define linkonce_odr {{.*}} ptr @_Z8constantv() -// ITANIUM-NEXT: entry: -// ITANIUM-NEXT: ret ptr @_ZZ8constantvE1c - -// ITANIUM-LABEL: define internal {{.*}} ptr @_ZL8internalv() -// ITANIUM-NEXT: entry: -// ITANIUM-NEXT: ret ptr @_ZZL8internalvE1i - -// MSVC-DAG: @"?meta@?1??instance@@YAAEBHXZ@4HB" = linkonce_odr dso_local global i32 0, comdat, align 4 -// MSVC-DAG: @"?$TSS0@?1??instance@@YAAEBHXZ@4HA" = linkonce_odr global i32 0, comdat, align 4 -// MSVC-DAG: @"?c@?1??constant@@YAAEBHXZ@4HB" = linkonce_odr dso_local constant i32 42, comdat, align 4 -// MSVC-DAG: @"?i@?1??internal@@YAAEBHXZ@4HB" = internal constant i32 3, align 4 - -// MSVC-LABEL: define linkonce_odr {{.*}} ptr @"?instance@@YAAEBHXZ"() -// MSVC: call void @_Init_thread_header(ptr @"?$TSS0@?1??instance@@YAAEBHXZ@4HA") -// MSVC: store i32 3, ptr @"?meta@?1??instance@@YAAEBHXZ@4HB" -// MSVC: call void @_Init_thread_footer(ptr @"?$TSS0@?1??instance@@YAAEBHXZ@4HA") -// MSVC: ret ptr @"?meta@?1??instance@@YAAEBHXZ@4HB" - -// MSVC-LABEL: define linkonce_odr {{.*}} ptr @"?constant@@YAAEBHXZ"() -// MSVC-NEXT: entry: -// MSVC-NEXT: ret ptr @"?c@?1??constant@@YAAEBHXZ@4HB" - -// MSVC-LABEL: define internal {{.*}} ptr @"?internal@@YAAEBHXZ"() -// MSVC-NEXT: entry: -// MSVC-NEXT: ret ptr @"?i@?1??internal@@YAAEBHXZ@4HB" diff --git a/clang/test/CodeGenCXX/vague-linkage-non-constant-init.cpp b/clang/test/CodeGenCXX/vague-linkage-non-constant-init.cpp new file mode 100644 index 00000000000000..bee88541b5c94d --- /dev/null +++ b/clang/test/CodeGenCXX/vague-linkage-non-constant-init.cpp @@ -0,0 +1,132 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -emit-llvm -o - %s | FileCheck %s --check-prefix=ITANIUM +// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=c++17 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSVC + +// A variable with vague linkage (a static local of an inline function, an +// inline variable, a static data member of a class template) is shared by +// every translation unit that uses it. If its initializer isn't a constant +// initializer, another translation unit might not be able to fold it (here, one +// that can't see the initializer of kSize) and will initialize the variable +// dynamically. So it must not be emitted as a (possibly read-only) constant +// without a guard in this translation unit either. +// See https://github.com/llvm/llvm-project/issues/226631. + +extern const int kSize; + +inline const int &instance() { + static const int meta = kSize; + return meta; +} + +// Constant initializers are still emitted as constants, without a guard. +inline const int &constant() { + static const int c = 42; + return c; +} + +// A static local that isn't shared with other translation units can still be +// folded, even if its initializer isn't a constant initializer. +static const int &internal() { + static const int i = kSize; + return i; +} + +inline const int iv = kSize; +inline int mv = kSize; +inline const int ic = 42; + +template <class T> struct S { static const int x; }; +template <class T> const int S<T>::x = kSize; + +static const int sv = kSize; + +const int *d() { return &iv; } +int *e() { return &mv; } +const int *f() { return ⁣ } +const int *g() { return &S<int>::x; } +const int *h() { return &sv; } + +extern const int kSize = 3; + +const int *a() { return &instance(); } +const int *b() { return &constant(); } +const int *c() { return &internal(); } + +// ITANIUM-DAG: @_ZZ8instancevE4meta = linkonce_odr global i32 0, comdat, align 4 +// ITANIUM-DAG: @_ZGVZ8instancevE4meta = linkonce_odr global i64 0, comdat, align 8 +// ITANIUM-DAG: @_ZZ8constantvE1c = linkonce_odr constant i32 42, comdat, align 4 +// ITANIUM-DAG: @_ZZL8internalvE1i = internal constant i32 3, align 4 +// ITANIUM-DAG: @iv = linkonce_odr global i32 0, comdat, align 4 +// ITANIUM-DAG: @_ZGV2iv = linkonce_odr global i64 0, comdat($iv), align 8 +// ITANIUM-DAG: @mv = linkonce_odr global i32 0, comdat, align 4 +// ITANIUM-DAG: @_ZGV2mv = linkonce_odr global i64 0, comdat($mv), align 8 +// ITANIUM-DAG: @ic = linkonce_odr constant i32 42, comdat, align 4 +// ITANIUM-DAG: @_ZN1SIiE1xE = linkonce_odr global i32 0, comdat, align 4 +// ITANIUM-DAG: @_ZGVN1SIiE1xE = linkonce_odr global i64 0, comdat($_ZN1SIiE1xE), align 8 +// ITANIUM-DAG: @_ZL2sv = internal constant i32 3, align 4 +// ITANIUM-NOT: @_ZGVZ8constantvE1c +// ITANIUM-NOT: @_ZGVZL8internalvE1i +// ITANIUM-NOT: @_ZGV2ic + +// ITANIUM-LABEL: define linkonce_odr {{.*}} ptr @_Z8instancev() +// ITANIUM: load atomic i8, ptr @_ZGVZ8instancevE4meta acquire +// ITANIUM: call i32 @__cxa_guard_acquire(ptr @_ZGVZ8instancevE4meta) +// ITANIUM: store i32 3, ptr @_ZZ8instancevE4meta +// ITANIUM: call void @__cxa_guard_release(ptr @_ZGVZ8instancevE4meta) +// ITANIUM: ret ptr @_ZZ8instancevE4meta + +// ITANIUM-LABEL: define linkonce_odr {{.*}} ptr @_Z8constantv() +// ITANIUM-NEXT: entry: +// ITANIUM-NEXT: ret ptr @_ZZ8constantvE1c + +// ITANIUM-LABEL: define internal {{.*}} ptr @_ZL8internalv() +// ITANIUM-NEXT: entry: +// ITANIUM-NEXT: ret ptr @_ZZL8internalvE1i + +// ITANIUM-LABEL: define internal void @__cxx_global_var_init() {{.*}} comdat($iv) +// ITANIUM: call i32 @__cxa_guard_acquire(ptr @_ZGV2iv) +// ITANIUM: store i32 3, ptr @iv +// ITANIUM: call void @__cxa_guard_release(ptr @_ZGV2iv) + +// ITANIUM-LABEL: define internal void @__cxx_global_var_init.1() {{.*}} comdat($mv) +// ITANIUM: call i32 @__cxa_guard_acquire(ptr @_ZGV2mv) +// ITANIUM: store i32 3, ptr @mv +// ITANIUM: call void @__cxa_guard_release(ptr @_ZGV2mv) + +// ITANIUM-LABEL: define internal void @__cxx_global_var_init.2() {{.*}} comdat($_ZN1SIiE1xE) +// ITANIUM: load i8, ptr @_ZGVN1SIiE1xE +// ITANIUM: store i8 1, ptr @_ZGVN1SIiE1xE +// ITANIUM: store i32 3, ptr @_ZN1SIiE1xE + +// MSVC-DAG: @"?meta@?1??instance@@YAAEBHXZ@4HB" = linkonce_odr dso_local global i32 0, comdat, align 4 +// MSVC-DAG: @"?$TSS0@?1??instance@@YAAEBHXZ@4HA" = linkonce_odr global i32 0, comdat, align 4 +// MSVC-DAG: @"?c@?1??constant@@YAAEBHXZ@4HB" = linkonce_odr dso_local constant i32 42, comdat, align 4 +// MSVC-DAG: @"?i@?1??internal@@YAAEBHXZ@4HB" = internal constant i32 3, align 4 +// MSVC-DAG: @"?iv@@3HB" = linkonce_odr dso_local global i32 0, comdat, align 4 +// MSVC-DAG: @"?mv@@3HA" = linkonce_odr dso_local global i32 0, comdat, align 4 +// MSVC-DAG: @"?ic@@3HB" = linkonce_odr dso_local constant i32 42, comdat, align 4 +// MSVC-DAG: @"?x@?$S@H@@2HB" = linkonce_odr dso_local global i32 0, comdat, align 4 +// MSVC-DAG: @sv = internal constant i32 3, align 4 +// MSVC-DAG: @llvm.global_ctors = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @"??__Eiv@@YAXXZ", ptr @"?iv@@3HB" }, { i32, ptr, ptr } { i32 65535, ptr @"??__Emv@@YAXXZ", ptr @"?mv@@3HA" }, { i32, ptr, ptr } { i32 65535, ptr @"??__E?x@?$S@H@@2HB@@YAXXZ", ptr @"?x@?$S@H@@2HB" }] + +// MSVC-LABEL: define linkonce_odr {{.*}} ptr @"?instance@@YAAEBHXZ"() +// MSVC: call void @_Init_thread_header(ptr @"?$TSS0@?1??instance@@YAAEBHXZ@4HA") +// MSVC: store i32 3, ptr @"?meta@?1??instance@@YAAEBHXZ@4HB" +// MSVC: call void @_Init_thread_footer(ptr @"?$TSS0@?1??instance@@YAAEBHXZ@4HA") +// MSVC: ret ptr @"?meta@?1??instance@@YAAEBHXZ@4HB" + +// MSVC-LABEL: define linkonce_odr {{.*}} ptr @"?constant@@YAAEBHXZ"() +// MSVC-NEXT: entry: +// MSVC-NEXT: ret ptr @"?c@?1??constant@@YAAEBHXZ@4HB" + +// MSVC-LABEL: define internal {{.*}} ptr @"?internal@@YAAEBHXZ"() +// MSVC-NEXT: entry: +// MSVC-NEXT: ret ptr @"?i@?1??internal@@YAAEBHXZ@4HB" + +// MSVC-LABEL: define linkonce_odr dso_local void @"??__Eiv@@YAXXZ"() +// MSVC: store i32 3, ptr @"?iv@@3HB" + +// MSVC-LABEL: define linkonce_odr dso_local void @"??__Emv@@YAXXZ"() +// MSVC: store i32 3, ptr @"?mv@@3HA" + +// MSVC-LABEL: define linkonce_odr dso_local void @"??__E?x@?$S@H@@2HB@@YAXXZ"() +// MSVC: store i32 3, ptr @"?x@?$S@H@@2HB" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
