Skip to content

Commit b574c81

Browse files
authored
[CIR] Defer declarations and tentative definitions (#141700)
This change adds code to defer emitting declarations and tentative definitions until they are referenced or trigger by a call to CompleteTentativeDefinition. This is needed to avoid premature handling of declarations and definitions that might not be referenced in the current translation unit. It also avoids incorrectly adding an initializer to external declarations. This change also updates the way the insertion location for globals is chosen so that all globals will be emitted together at the top of the module. This makes no functional difference, but it is very useful for writing sensible tests. Some tests are modified in this change to reorder global variables so that they can be checked in the order in which they will be emitted.
1 parent 711a177 commit b574c81

File tree

13 files changed

+155
-95
lines changed

13 files changed

+155
-95
lines changed

clang/include/clang/CIR/CIRGenerator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class CIRGenerator : public clang::ASTConsumer {
5454
~CIRGenerator() override;
5555
void Initialize(clang::ASTContext &astContext) override;
5656
bool HandleTopLevelDecl(clang::DeclGroupRef group) override;
57+
void CompleteTentativeDefinition(clang::VarDecl *d) override;
58+
5759
mlir::ModuleOp getModule() const;
5860
mlir::MLIRContext &getMLIRContext() { return *mlirContext; };
5961
const mlir::MLIRContext &getMLIRContext() const { return *mlirContext; };

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ struct MissingFeatures {
201201
static bool writebacks() { return false; }
202202
static bool cleanupsToDeactivate() { return false; }
203203
static bool stackBase() { return false; }
204+
static bool deferredDecls() { return false; }
204205

205206
// Missing types
206207
static bool dataMemberType() { return false; }

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,20 @@ void CIRGenModule::emitGlobal(clang::GlobalDecl gd) {
231231
return;
232232
}
233233
} else {
234-
assert(cast<VarDecl>(global)->isFileVarDecl() &&
235-
"Cannot emit local var decl as global");
234+
const auto *vd = cast<VarDecl>(global);
235+
assert(vd->isFileVarDecl() && "Cannot emit local var decl as global.");
236+
if (vd->isThisDeclarationADefinition() != VarDecl::Definition &&
237+
!astContext.isMSStaticDataMemberInlineDefinition(vd)) {
238+
assert(!cir::MissingFeatures::openMP());
239+
// If this declaration may have caused an inline variable definition to
240+
// change linkage, make sure that it's emitted.
241+
if (astContext.getInlineVariableDefinitionKind(vd) ==
242+
ASTContext::InlineVariableDefinitionKind::Strong)
243+
getAddrOfGlobalVar(vd);
244+
// Otherwise, we can ignore this declaration. The variable will be emitted
245+
// on its first use.
246+
return;
247+
}
236248
}
237249

238250
// TODO(CIR): Defer emitting some global definitions until later
@@ -279,22 +291,23 @@ cir::GlobalOp CIRGenModule::createGlobalOp(CIRGenModule &cgm,
279291
{
280292
mlir::OpBuilder::InsertionGuard guard(builder);
281293

282-
// Some global emissions are triggered while emitting a function, e.g.
283-
// void s() { const char *s = "yolo"; ... }
284-
//
285-
// Be sure to insert global before the current function
286-
CIRGenFunction *curCGF = cgm.curCGF;
287-
if (curCGF)
288-
builder.setInsertionPoint(curCGF->curFn);
289-
290-
g = builder.create<cir::GlobalOp>(loc, name, t);
291-
if (!curCGF) {
292-
if (insertPoint)
293-
cgm.getModule().insert(insertPoint, g);
294+
// If an insertion point is provided, we're replacing an existing global,
295+
// otherwise, create the new global immediately after the last gloabl we
296+
// emitted.
297+
if (insertPoint) {
298+
builder.setInsertionPoint(insertPoint);
299+
} else {
300+
// Group global operations together at the top of the module.
301+
if (cgm.lastGlobalOp)
302+
builder.setInsertionPointAfter(cgm.lastGlobalOp);
294303
else
295-
cgm.getModule().push_back(g);
304+
builder.setInsertionPointToStart(cgm.getModule().getBody());
296305
}
297306

307+
g = builder.create<cir::GlobalOp>(loc, name, t);
308+
if (!insertPoint)
309+
cgm.lastGlobalOp = g;
310+
298311
// Default to private until we can judge based on the initializer,
299312
// since MLIR doesn't allow public declarations.
300313
mlir::SymbolTable::setSymbolVisibility(
@@ -1044,6 +1057,24 @@ StringRef CIRGenModule::getMangledName(GlobalDecl gd) {
10441057
return mangledDeclNames[canonicalGd] = result.first->first();
10451058
}
10461059

1060+
void CIRGenModule::emitTentativeDefinition(const VarDecl *d) {
1061+
assert(!d->getInit() && "Cannot emit definite definitions here!");
1062+
1063+
StringRef mangledName = getMangledName(d);
1064+
mlir::Operation *gv = getGlobalValue(mangledName);
1065+
1066+
// If we already have a definition, not declaration, with the same mangled
1067+
// name, emitting of declaration is not required (and would actually overwrite
1068+
// the emitted definition).
1069+
if (gv && !mlir::cast<cir::GlobalOp>(gv).isDeclaration())
1070+
return;
1071+
1072+
assert(!cir::MissingFeatures::deferredDecls());
1073+
1074+
// The tentative definition is the only definition.
1075+
emitGlobalVarDefinition(d);
1076+
}
1077+
10471078
cir::FuncOp CIRGenModule::getOrCreateCIRFunction(
10481079
StringRef mangledName, mlir::Type funcType, GlobalDecl gd, bool forVTable,
10491080
bool dontDefer, bool isThunk, ForDefinition_t isForDefinition,

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ class CIRGenModule : public CIRGenTypeCache {
111111
/// Handling globals
112112
/// -------
113113

114+
mlir::Operation *lastGlobalOp = nullptr;
115+
114116
mlir::Operation *getGlobalValue(llvm::StringRef ref);
115117

116118
/// If the specified mangled name is not in the module, create and return an
@@ -194,6 +196,8 @@ class CIRGenModule : public CIRGenTypeCache {
194196

195197
llvm::StringRef getMangledName(clang::GlobalDecl gd);
196198

199+
void emitTentativeDefinition(const VarDecl *d);
200+
197201
static void setInitializer(cir::GlobalOp &op, mlir::Attribute value);
198202

199203
cir::FuncOp

clang/lib/CIR/CodeGen/CIRGenerator.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,10 @@ bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef group) {
6262

6363
return true;
6464
}
65+
66+
void CIRGenerator::CompleteTentativeDefinition(VarDecl *d) {
67+
if (diags.hasErrorOccurred())
68+
return;
69+
70+
cgm->emitTentativeDefinition(d);
71+
}

clang/lib/CIR/FrontendAction/CIRGenAction.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ class CIRGenConsumer : public clang::ASTConsumer {
135135
}
136136
}
137137
}
138+
139+
void CompleteTentativeDefinition(VarDecl *D) override {
140+
Gen->CompleteTentativeDefinition(D);
141+
}
138142
};
139143
} // namespace cir
140144

clang/test/CIR/CodeGen/array.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,6 @@ int aa[10][5];
1919

2020
// OGCG: @aa = global [10 x [5 x i32]] zeroinitializer
2121

22-
extern int b[10];
23-
// CIR: cir.global external @b = #cir.zero : !cir.array<!s32i x 10>
24-
25-
// LLVM: @b = dso_local global [10 x i32] zeroinitializer
26-
27-
extern int bb[10][5];
28-
// CIR: cir.global external @bb = #cir.zero : !cir.array<!cir.array<!s32i x 5> x 10>
29-
30-
// LLVM: @bb = dso_local global [10 x [5 x i32]] zeroinitializer
31-
3222
int c[10] = {};
3323
// CIR: cir.global external @c = #cir.zero : !cir.array<!s32i x 10>
3424

@@ -66,6 +56,22 @@ int f[5] = {1, 2};
6656

6757
// OGCG: @f = global [5 x i32] [i32 1, i32 2, i32 0, i32 0, i32 0]
6858

59+
extern int b[10];
60+
// CIR: cir.global external @b : !cir.array<!s32i x 10>
61+
// LLVM: @b = external dso_local global [10 x i32]
62+
// OGCG: @b = external global [10 x i32]
63+
64+
extern int bb[10][5];
65+
// CIR: cir.global external @bb : !cir.array<!cir.array<!s32i x 5> x 10>
66+
// LLVM: @bb = external dso_local global [10 x [5 x i32]]
67+
// OGCG: @bb = external global [10 x [5 x i32]]
68+
69+
// This function is only here to make sure the external globals are emitted.
70+
void reference_externs() {
71+
b;
72+
bb;
73+
}
74+
6975
// OGCG: @[[FUN2_ARR:.*]] = private unnamed_addr constant [2 x i32] [i32 5, i32 0], align 4
7076
// OGCG: @[[FUN3_ARR:.*]] = private unnamed_addr constant [2 x i32] [i32 5, i32 6], align 4
7177
// OGCG: @[[FUN4_ARR:.*]] = private unnamed_addr constant [2 x [1 x i32]] [

clang/test/CIR/CodeGen/basic.c

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,36 @@
55
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
66
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
77

8+
enum A {
9+
A_one,
10+
A_two
11+
};
12+
enum A a;
13+
14+
// CHECK: cir.global external @a = #cir.int<0> : !u32i
15+
16+
enum B : int;
17+
enum B b;
18+
19+
// CHECK: cir.global external @b = #cir.int<0> : !u32i
20+
21+
22+
enum C : int {
23+
C_one,
24+
C_two
25+
};
26+
enum C c;
27+
28+
// CHECK: cir.global external @c = #cir.int<0> : !u32i
29+
830
int f1(int i);
931

1032
int f1(int i) {
1133
i;
1234
return i;
1335
}
1436

15-
// CIR: module
16-
// CIR-NEXT: cir.func @f1(%arg0: !s32i loc({{.*}})) -> !s32i
37+
// CIR: cir.func @f1(%arg0: !s32i loc({{.*}})) -> !s32i
1738
// CIR-NEXT: %[[I_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] {alignment = 4 : i64}
1839
// CIR-NEXT: %[[RV:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64}
1940
// CIR-NEXT: cir.store{{.*}} %arg0, %[[I_PTR]] : !s32i, !cir.ptr<!s32i>
@@ -288,25 +309,3 @@ size_type max_size(void) {
288309
// CHECK: %6 = cir.load{{.*}} %0 : !cir.ptr<!u64i>, !u64i
289310
// CHECK: cir.return %6 : !u64i
290311
// CHECK: }
291-
292-
enum A {
293-
A_one,
294-
A_two
295-
};
296-
enum A a;
297-
298-
// CHECK: cir.global external @a = #cir.int<0> : !u32i
299-
300-
enum B : int;
301-
enum B b;
302-
303-
// CHECK: cir.global external @b = #cir.int<0> : !u32i
304-
305-
306-
enum C : int {
307-
C_one,
308-
C_two
309-
};
310-
enum C c;
311-
312-
// CHECK: cir.global external @c = #cir.int<0> : !u32i

clang/test/CIR/CodeGen/basic.cpp

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,36 @@
11
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - 2>&1 | FileCheck %s
22

3+
enum A {
4+
A_one,
5+
A_two
6+
};
7+
enum A a;
8+
9+
// CHECK: cir.global external @a = #cir.int<0> : !u32i
10+
11+
enum B : int;
12+
enum B b;
13+
14+
// CHECK: cir.global external @b = #cir.int<0> : !s32i
15+
16+
enum C : int {
17+
C_one,
18+
C_two
19+
};
20+
enum C c;
21+
22+
// CHECK: cir.global external @c = #cir.int<0> : !s32i
23+
24+
enum class D : int;
25+
enum D d;
26+
27+
// CHECK: cir.global external @d = #cir.int<0> : !s32i
28+
329
int f1() {
430
int i;
531
return i;
632
}
733

8-
// CHECK: module
934
// CHECK: cir.func @_Z2f1v() -> !s32i
1035
// CHECK: %[[RV:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64}
1136
// CHECK: %[[I_PTR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i"] {alignment = 4 : i64}
@@ -145,29 +170,3 @@ void ref_local(short x) {
145170
// CHECK: %[[Y_REF_ADDR:.*]] = cir.alloca !cir.ptr<!s16i>, !cir.ptr<!cir.ptr<!s16i>>, ["y", init, const] {alignment = 8 : i64}
146171
// CHECK: cir.store{{.*}} %[[ARG]], %[[X_ADDR]] : !s16i, !cir.ptr<!s16i>
147172
// CHECK: cir.store{{.*}} %[[X_ADDR]], %[[Y_REF_ADDR]] : !cir.ptr<!s16i>, !cir.ptr<!cir.ptr<!s16i>>
148-
149-
enum A {
150-
A_one,
151-
A_two
152-
};
153-
enum A a;
154-
155-
// CHECK: cir.global external @a = #cir.int<0> : !u32i
156-
157-
enum B : int;
158-
enum B b;
159-
160-
// CHECK: cir.global external @b = #cir.int<0> : !s32i
161-
162-
enum C : int {
163-
C_one,
164-
C_two
165-
};
166-
enum C c;
167-
168-
// CHECK: cir.global external @c = #cir.int<0> : !s32i
169-
170-
enum class D : int;
171-
enum D d;
172-
173-
// CHECK: cir.global external @d = #cir.int<0> : !s32i

clang/test/CIR/CodeGen/string-literals.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -emit-llvm %s -o %t.ll
66
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
77

8+
// CIR: cir.global external @[[STR1_GLOBAL:.*]] = #cir.const_array<"1\00" : !cir.array<!s8i x 2>> : !cir.array<!s8i x 2>
9+
// CIR: cir.global external @[[STR2_GLOBAL:.*]] = #cir.zero : !cir.array<!s8i x 1>
10+
// CIR: cir.global external @[[STR3_GLOBAL:.*]] = #cir.zero : !cir.array<!s8i x 2>
11+
812
// LLVM: @[[STR1_GLOBAL:.*]] = dso_local global [2 x i8] c"1\00"
913
// LLVM: @[[STR2_GLOBAL:.*]] = dso_local global [1 x i8] zeroinitializer
1014
// LLVM: @[[STR3_GLOBAL:.*]] = dso_local global [2 x i8] zeroinitializer
@@ -17,7 +21,6 @@ char *f1() {
1721
return "1";
1822
}
1923

20-
// CIR: cir.global external @[[STR1_GLOBAL:.*]] = #cir.const_array<"1\00" : !cir.array<!s8i x 2>> : !cir.array<!s8i x 2>
2124
// CIR: cir.func @f1()
2225
// CIR: %[[STR:.*]] = cir.get_global @[[STR1_GLOBAL]] : !cir.ptr<!cir.array<!s8i x 2>>
2326

@@ -31,7 +34,6 @@ char *f2() {
3134
return "";
3235
}
3336

34-
// CIR: cir.global external @[[STR2_GLOBAL:.*]] = #cir.zero : !cir.array<!s8i x 1>
3537
// CIR: cir.func @f2()
3638
// CIR: %[[STR2:.*]] = cir.get_global @[[STR2_GLOBAL]] : !cir.ptr<!cir.array<!s8i x 1>>
3739

@@ -45,7 +47,6 @@ char *f3() {
4547
return "\00";
4648
}
4749

48-
// CIR: cir.global external @[[STR3_GLOBAL:.*]] = #cir.zero : !cir.array<!s8i x 2>
4950
// CIR: cir.func @f3()
5051
// CIR: %[[STR3:.*]] = cir.get_global @[[STR3_GLOBAL]] : !cir.ptr<!cir.array<!s8i x 2>>
5152

0 commit comments

Comments
 (0)