Skip to content

Commit 2a9a243

Browse files
authored
Add clang patches to make globals used for array initialization codegen constant (#445)
Backport llvm/llvm-project@7a85aa9 and llvm/llvm-project@4a2757d
1 parent 78c5e3f commit 2a9a243

File tree

1 file changed

+268
-0
lines changed

1 file changed

+268
-0
lines changed
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
From e9e2434697c3a28f151ce179dd88f0ba73f0f0a0 Mon Sep 17 00:00:00 2001
2+
From: Haonan Yang <[email protected]>
3+
Date: Tue, 30 May 2023 09:37:00 +0800
4+
Subject: [PATCH] Make globals used for array initialization codegen constant
5+
6+
This combines https://reviews.llvm.org/D146211 and https://reviews.llvm.org/D145369
7+
1. Emit const globals with constexpr destructor as constant LLVM values
8+
This follows 2b4fa53 which made Clang not emit destructor calls for such
9+
objects. However, they would still not get emitted as constants since
10+
CodeGenModule::isTypeConstant() returns false if the destructor is
11+
constexpr. This change adds a param to make isTypeConstant() ignore the
12+
dtor, allowing the caller to check it instead.
13+
2. Make globals used for array initialization codegen constant
14+
As pointed out in D133835 these globals will never be written to
15+
(they're only used for trivially copyable types), so they can always be
16+
constant.
17+
---
18+
clang/lib/CodeGen/CGDecl.cpp | 12 ++++++++----
19+
clang/lib/CodeGen/CGDeclCXX.cpp | 4 +++-
20+
clang/lib/CodeGen/CGExpr.cpp | 2 +-
21+
clang/lib/CodeGen/CGExprAgg.cpp | 4 ++--
22+
clang/lib/CodeGen/CGExprConstant.cpp | 12 ++++++------
23+
clang/lib/CodeGen/CodeGenModule.cpp | 16 +++++++++-------
24+
clang/lib/CodeGen/CodeGenModule.h | 2 +-
25+
clang/lib/CodeGen/TargetInfo.cpp | 2 +-
26+
clang/test/CodeGen/init.c | 2 +-
27+
clang/test/CodeGen/label-array-aggregate-init.c | 2 +-
28+
clang/test/CodeGenCXX/const-init-cxx2a.cpp | 4 ++--
29+
11 files changed, 35 insertions(+), 27 deletions(-)
30+
31+
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
32+
index 18d658436086..372f392402cf 100644
33+
--- a/clang/lib/CodeGen/CGDecl.cpp
34+
+++ b/clang/lib/CodeGen/CGDecl.cpp
35+
@@ -379,13 +379,15 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
36+
OldGV->eraseFromParent();
37+
}
38+
39+
- GV->setConstant(CGM.isTypeConstant(D.getType(), true));
40+
+ bool NeedsDtor =
41+
+ D.needsDestruction(getContext()) == QualType::DK_cxx_destructor;
42+
+
43+
+ GV->setConstant(CGM.isTypeConstant(D.getType(), true, !NeedsDtor));
44+
GV->setInitializer(Init);
45+
46+
emitter.finalize(GV);
47+
48+
- if (D.needsDestruction(getContext()) == QualType::DK_cxx_destructor &&
49+
- HaveInsertPoint()) {
50+
+ if (NeedsDtor && HaveInsertPoint()) {
51+
// We have a constant initializer, but a nontrivial destructor. We still
52+
// need to perform a guarded "initialization" in order to register the
53+
// destructor.
54+
@@ -1470,10 +1472,12 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
55+
// emit it as a global instead.
56+
// Exception is if a variable is located in non-constant address space
57+
// in OpenCL.
58+
+ bool NeedsDtor =
59+
+ D.needsDestruction(getContext()) == QualType::DK_cxx_destructor;
60+
if ((!getLangOpts().OpenCL ||
61+
Ty.getAddressSpace() == LangAS::opencl_constant) &&
62+
(CGM.getCodeGenOpts().MergeAllConstants && !NRVO &&
63+
- !isEscapingByRef && CGM.isTypeConstant(Ty, true))) {
64+
+ !isEscapingByRef && CGM.isTypeConstant(Ty, true, !NeedsDtor))) {
65+
EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
66+
67+
// Signal this condition to later callbacks.
68+
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
69+
index 7b880c1354e1..3dfffdbed8eb 100644
70+
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
71+
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
72+
@@ -213,9 +213,11 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
73+
&D, DeclAddr, D.getAttr<OMPThreadPrivateDeclAttr>()->getLocation(),
74+
PerformInit, this);
75+
}
76+
+ bool NeedsDtor =
77+
+ D.needsDestruction(getContext()) == QualType::DK_cxx_destructor;
78+
if (PerformInit)
79+
EmitDeclInit(*this, D, DeclAddr);
80+
- if (CGM.isTypeConstant(D.getType(), true))
81+
+ if (CGM.isTypeConstant(D.getType(), true, !NeedsDtor))
82+
EmitDeclInvariant(*this, D, DeclPtr);
83+
else
84+
EmitDeclDestroy(*this, D, DeclAddr);
85+
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
86+
index 2a9b108c31bc..86ed8b1892ea 100644
87+
--- a/clang/lib/CodeGen/CGExpr.cpp
88+
+++ b/clang/lib/CodeGen/CGExpr.cpp
89+
@@ -390,7 +390,7 @@ static Address createReferenceTemporary(CodeGenFunction &CGF,
90+
QualType Ty = Inner->getType();
91+
if (CGF.CGM.getCodeGenOpts().MergeAllConstants &&
92+
(Ty->isArrayType() || Ty->isRecordType()) &&
93+
- CGF.CGM.isTypeConstant(Ty, true))
94+
+ CGF.CGM.isTypeConstant(Ty, true, false))
95+
if (auto Init = ConstantEmitter(CGF).tryEmitAbstract(Inner, Ty)) {
96+
auto AS = CGF.CGM.GetGlobalConstantAddressSpace();
97+
auto *GV = new llvm::GlobalVariable(
98+
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
99+
index 73b05690537d..4f5b5b4cdef3 100644
100+
--- a/clang/lib/CodeGen/CGExprAgg.cpp
101+
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
102+
@@ -506,8 +506,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
103+
if (llvm::Constant *C = Emitter.tryEmitForInitializer(E, AS, ArrayQTy)) {
104+
auto GV = new llvm::GlobalVariable(
105+
CGM.getModule(), C->getType(),
106+
- CGM.isTypeConstant(ArrayQTy, /* ExcludeCtorDtor= */ true),
107+
- llvm::GlobalValue::PrivateLinkage, C, "constinit",
108+
+ /* isConstant= */ true, llvm::GlobalValue::PrivateLinkage, C,
109+
+ "constinit",
110+
/* InsertBefore= */ nullptr, llvm::GlobalVariable::NotThreadLocal,
111+
CGM.getContext().getTargetAddressSpace(AS));
112+
Emitter.finalize(GV);
113+
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
114+
index ac4b4d1308ab..64129b64e272 100644
115+
--- a/clang/lib/CodeGen/CGExprConstant.cpp
116+
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
117+
@@ -913,12 +913,12 @@ static ConstantAddress tryEmitGlobalCompoundLiteral(CodeGenModule &CGM,
118+
return ConstantAddress::invalid();
119+
}
120+
121+
- auto GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(),
122+
- CGM.isTypeConstant(E->getType(), true),
123+
- llvm::GlobalValue::InternalLinkage,
124+
- C, ".compoundliteral", nullptr,
125+
- llvm::GlobalVariable::NotThreadLocal,
126+
- CGM.getContext().getTargetAddressSpace(addressSpace));
127+
+ auto GV = new llvm::GlobalVariable(
128+
+ CGM.getModule(), C->getType(),
129+
+ CGM.isTypeConstant(E->getType(), true, false),
130+
+ llvm::GlobalValue::InternalLinkage, C, ".compoundliteral", nullptr,
131+
+ llvm::GlobalVariable::NotThreadLocal,
132+
+ CGM.getContext().getTargetAddressSpace(addressSpace));
133+
emitter.finalize(GV);
134+
GV->setAlignment(Align.getAsAlign());
135+
CGM.setAddrOfConstantCompoundLiteral(E, GV);
136+
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
137+
index 2777fc22600d..c88228090c17 100644
138+
--- a/clang/lib/CodeGen/CodeGenModule.cpp
139+
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
140+
@@ -2826,7 +2826,7 @@ bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
141+
// codegen for global variables, because they may be marked as threadprivate.
142+
if (LangOpts.OpenMP && LangOpts.OpenMPUseTLS &&
143+
getContext().getTargetInfo().isTLSSupported() && isa<VarDecl>(Global) &&
144+
- !isTypeConstant(Global->getType(), false) &&
145+
+ !isTypeConstant(Global->getType(), false, false) &&
146+
!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(Global))
147+
return false;
148+
149+
@@ -3988,8 +3988,9 @@ CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name,
150+
///
151+
/// If ExcludeCtor is true, the duration when the object's constructor runs
152+
/// will not be considered. The caller will need to verify that the object is
153+
-/// not written to during its construction.
154+
-bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) {
155+
+/// not written to during its construction. ExcludeDtor works similarly.
156+
+bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor,
157+
+ bool ExcludeDtor) {
158+
if (!Ty.isConstant(Context) && !Ty->isReferenceType())
159+
return false;
160+
161+
@@ -3997,7 +3998,7 @@ bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) {
162+
if (const CXXRecordDecl *Record
163+
= Context.getBaseElementType(Ty)->getAsCXXRecordDecl())
164+
return ExcludeCtor && !Record->hasMutableFields() &&
165+
- Record->hasTrivialDestructor();
166+
+ (Record->hasTrivialDestructor() || ExcludeDtor);
167+
}
168+
169+
return true;
170+
@@ -4108,7 +4109,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
171+
172+
// FIXME: This code is overly simple and should be merged with other global
173+
// handling.
174+
- GV->setConstant(isTypeConstant(D->getType(), false));
175+
+ GV->setConstant(isTypeConstant(D->getType(), false, false));
176+
177+
GV->setAlignment(getContext().getDeclAlign(D).getAsAlign());
178+
179+
@@ -4642,7 +4643,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
180+
181+
// If it is safe to mark the global 'constant', do so now.
182+
GV->setConstant(!NeedsGlobalCtor && !NeedsGlobalDtor &&
183+
- isTypeConstant(D->getType(), true));
184+
+ isTypeConstant(D->getType(), true, true));
185+
186+
// If it is in a read-only section, mark it 'constant'.
187+
if (const SectionAttr *SA = D->getAttr<SectionAttr>()) {
188+
@@ -5703,7 +5704,8 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
189+
emitter.emplace(*this);
190+
InitialValue = emitter->emitForInitializer(*Value, AddrSpace,
191+
MaterializedType);
192+
- Constant = isTypeConstant(MaterializedType, /*ExcludeCtor*/Value);
193+
+ Constant = isTypeConstant(MaterializedType, /*ExcludeCtor*/ Value,
194+
+ /*ExcludeDtor*/ false);
195+
Type = InitialValue->getType();
196+
} else {
197+
// No initializer, the initialization will be provided when we
198+
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
199+
index a8a63c8da57f..28ea927c448d 100644
200+
--- a/clang/lib/CodeGen/CodeGenModule.h
201+
+++ b/clang/lib/CodeGen/CodeGenModule.h
202+
@@ -765,7 +765,7 @@ public:
203+
return getTBAAAccessInfo(AccessType);
204+
}
205+
206+
- bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
207+
+ bool isTypeConstant(QualType QTy, bool ExcludeCtor, bool ExcludeDtor);
208+
209+
bool isPaddedAtomicType(QualType type);
210+
bool isPaddedAtomicType(const AtomicType *type);
211+
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
212+
index d83bc9e529a6..672ca38c6803 100644
213+
--- a/clang/lib/CodeGen/TargetInfo.cpp
214+
+++ b/clang/lib/CodeGen/TargetInfo.cpp
215+
@@ -9440,7 +9440,7 @@ AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
216+
return AddrSpace;
217+
218+
// Only promote to address space 4 if VarDecl has constant initialization.
219+
- if (CGM.isTypeConstant(D->getType(), false) &&
220+
+ if (CGM.isTypeConstant(D->getType(), false, false) &&
221+
D->hasConstantInitialization()) {
222+
if (auto ConstAS = CGM.getTarget().getConstantAddressSpace())
223+
return ConstAS.getValue();
224+
diff --git a/clang/test/CodeGen/init.c b/clang/test/CodeGen/init.c
225+
index a21b5f4c09f5..93859924349b 100644
226+
--- a/clang/test/CodeGen/init.c
227+
+++ b/clang/test/CodeGen/init.c
228+
@@ -10,7 +10,7 @@ unsigned v2[2][3] = {[0 ... 1][0 ... 1] = 2222, 3333};
229+
230+
// CHECK-DAG: [1 x %struct.M] [%struct.M { [2 x %struct.I] [%struct.I { [3 x i32] [i32 4, i32 4, i32 0] }, %struct.I { [3 x i32] [i32 4, i32 4, i32 5] }] }],
231+
// CHECK-DAG: [2 x [3 x i32]] {{[[][[]}}3 x i32] [i32 2222, i32 2222, i32 0], [3 x i32] [i32 2222, i32 2222, i32 3333]],
232+
-// CHECK-DAG: [[INIT14:.*]] = private global [16 x i32] [i32 0, i32 0, i32 0, i32 0, i32 0, i32 17, i32 17, i32 17, i32 17, i32 17, i32 17, i32 17, i32 0, i32 0, i32 0, i32 0], align 4
233+
+// CHECK-DAG: [[INIT14:.*]] = private constant [16 x i32] [i32 0, i32 0, i32 0, i32 0, i32 0, i32 17, i32 17, i32 17, i32 17, i32 17, i32 17, i32 17, i32 0, i32 0, i32 0, i32 0], align 4
234+
235+
void f1() {
236+
// Scalars in braces.
237+
diff --git a/clang/test/CodeGen/label-array-aggregate-init.c b/clang/test/CodeGen/label-array-aggregate-init.c
238+
index 5cefd8d270c0..3175c2a6a292 100644
239+
--- a/clang/test/CodeGen/label-array-aggregate-init.c
240+
+++ b/clang/test/CodeGen/label-array-aggregate-init.c
241+
@@ -1,6 +1,6 @@
242+
// RUN: %clang -cc1 -triple x86_64-windows-msvc -emit-llvm %s -o - | FileCheck %s
243+
244+
-// CHECK: @constinit = private global [3 x i8*] [i8* blockaddress(@main, %L), i8* null, i8* null]
245+
+// CHECK: @constinit = private constant [3 x i8*] [i8* blockaddress(@main, %L), i8* null, i8* null]
246+
247+
void receivePtrs(void **);
248+
249+
diff --git a/clang/test/CodeGenCXX/const-init-cxx2a.cpp b/clang/test/CodeGenCXX/const-init-cxx2a.cpp
250+
index 3eafef094387..3c83a9c94ade 100644
251+
--- a/clang/test/CodeGenCXX/const-init-cxx2a.cpp
252+
+++ b/clang/test/CodeGenCXX/const-init-cxx2a.cpp
253+
@@ -11,10 +11,10 @@ struct B {
254+
constexpr ~B() { n *= 5; }
255+
int n = 123;
256+
};
257+
-// CHECK: @b ={{.*}} global {{.*}} i32 123
258+
+// CHECK: @b ={{.*}} constant {{.*}} i32 123
259+
extern constexpr B b = B();
260+
261+
-// CHECK: @_ZL1c = internal global {{.*}} i32 123
262+
+// CHECK: @_ZL1c = internal constant {{.*}} i32 123
263+
const B c;
264+
int use_c() { return c.n; }
265+
266+
--
267+
2.31.1
268+

0 commit comments

Comments
 (0)