Skip to content

Commit b0f10a1

Browse files
authored
[C++20] [Modules] Don't generate the defintition for non-const available external variables (#93530)
Close #93497 The root cause of the problem is, we mark the variable from other modules as constnant in LLVM incorrectly. This patch fixes this problem by not emitting the defintition for non-const available external variables. Since the non const available externally variable is not helpful to the optimization.
1 parent 3613b26 commit b0f10a1

File tree

3 files changed

+122
-4
lines changed

3 files changed

+122
-4
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5341,6 +5341,18 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
53415341
!IsDefinitionAvailableExternally &&
53425342
D->needsDestruction(getContext()) == QualType::DK_cxx_destructor;
53435343

5344+
// It is helpless to emit the definition for an available_externally variable
5345+
// which can't be marked as const.
5346+
// We don't need to check if it needs global ctor or dtor. See the above
5347+
// comment for ideas.
5348+
if (IsDefinitionAvailableExternally &&
5349+
(!D->hasConstantInitialization() ||
5350+
// TODO: Update this when we have interface to check constexpr
5351+
// destructor.
5352+
D->needsDestruction(getContext()) ||
5353+
!D->getType().isConstantStorage(getContext(), true, true)))
5354+
return;
5355+
53445356
const VarDecl *InitDecl;
53455357
const Expr *InitExpr = D->getAnyInitializer(InitDecl);
53465358

clang/test/CodeGenCXX/partitions.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ export int use() {
4040
}
4141

4242
// FIXME: The definition of the variables shouldn't be exported too.
43-
// CHECK: @_ZW3mod1a = available_externally global
44-
// CHECK: @_ZW3mod1b = available_externally global
43+
// CHECK: @_ZW3mod1a = external global
44+
// CHECK: @_ZW3mod1b = external global
4545
// CHECK: declare{{.*}} i32 @_ZW3mod3foov
4646
// CHECK: declare{{.*}} i32 @_ZW3mod3barv
4747

48-
// CHECK-OPT: @_ZW3mod1a = available_externally global
49-
// CHECK-OPT: @_ZW3mod1b = available_externally global
48+
// CHECK-OPT: @_ZW3mod1a = external global
49+
// CHECK-OPT: @_ZW3mod1b = external global
5050
// CHECK-OPT: declare{{.*}} i32 @_ZW3mod3foov
5151
// CHECK-OPT: declare{{.*}} i32 @_ZW3mod3barv

clang/test/Modules/pr93497.cppm

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
5+
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %t/mod.cppm \
6+
// RUN: -emit-module-interface -o %t/mod.pcm
7+
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %t/use.cpp \
8+
// RUN: -fmodule-file=mod=%t/mod.pcm -emit-llvm \
9+
// RUN: -o - | opt -S --passes=simplifycfg | FileCheck %t/use.cpp
10+
11+
//--- mod.cppm
12+
export module mod;
13+
14+
export struct Thing {
15+
static const Thing One;
16+
explicit Thing(int raw) :raw(raw) { }
17+
int raw;
18+
};
19+
20+
const Thing Thing::One = Thing(1);
21+
22+
export struct C {
23+
int value;
24+
};
25+
export const C ConstantValue = {1};
26+
27+
export const C *ConstantPtr = &ConstantValue;
28+
29+
C NonConstantValue = {1};
30+
export const C &ConstantRef = NonConstantValue;
31+
32+
export struct NonConstexprDtor {
33+
constexpr NonConstexprDtor(int raw) : raw(raw) {}
34+
~NonConstexprDtor();
35+
36+
int raw;
37+
};
38+
39+
export const NonConstexprDtor NonConstexprDtorValue = {1};
40+
41+
//--- use.cpp
42+
import mod;
43+
44+
int consume(int);
45+
int consumeC(C);
46+
47+
extern "C" __attribute__((noinline)) inline int unneeded() {
48+
return consume(43);
49+
}
50+
51+
extern "C" __attribute__((noinline)) inline int needed() {
52+
return consume(43);
53+
}
54+
55+
int use() {
56+
Thing t1 = Thing::One;
57+
return consume(t1.raw);
58+
}
59+
60+
int use2() {
61+
if (ConstantValue.value)
62+
return consumeC(ConstantValue);
63+
return unneeded();
64+
}
65+
66+
int use3() {
67+
auto Ptr = ConstantPtr;
68+
if (Ptr->value)
69+
return consumeC(*Ptr);
70+
return needed();
71+
}
72+
73+
int use4() {
74+
auto Ref = ConstantRef;
75+
if (Ref.value)
76+
return consumeC(Ref);
77+
return needed();
78+
}
79+
80+
int use5() {
81+
NonConstexprDtor V = NonConstexprDtorValue;
82+
if (V.raw)
83+
return consume(V.raw);
84+
return needed();
85+
}
86+
87+
// CHECK: @_ZNW3mod5Thing3OneE = external
88+
// CHECK: @_ZW3mod13ConstantValue ={{.*}}available_externally{{.*}} constant
89+
// CHECK: @_ZW3mod11ConstantPtr = external
90+
// CHECK: @_ZW3mod16NonConstantValue = external
91+
// CHECK: @_ZW3mod21NonConstexprDtorValue = external
92+
93+
// Check that the middle end can optimize the program by the constant information.
94+
// CHECK-NOT: @unneeded(
95+
96+
// Check that the use of ConstantPtr won't get optimized incorrectly.
97+
// CHECK-LABEL: @_Z4use3v(
98+
// CHECK: @needed(
99+
100+
// Check that the use of ConstantRef won't get optimized incorrectly.
101+
// CHECK-LABEL: @_Z4use4v(
102+
// CHECK: @needed(
103+
104+
// Check that the use of NonConstexprDtorValue won't get optimized incorrectly.
105+
// CHECK-LABEL: @_Z4use5v(
106+
// CHECK: @needed(

0 commit comments

Comments
 (0)