Skip to content

Commit 0f7f250

Browse files
Lancernlanza
authored andcommitted
[CIR][CIRGen] Support array def after decl with unknown bound (#375)
Arrays can be first declared without a known bound, and then defined with a known bound. For example: ```cpp extern int data[]; int test() { return data[1]; } int data[3] {1, 2, 3}; ``` Currently `clangir` crashes on generating CIR for this case. This is due to the type of the `data` definition being different from its declaration. This patch adds support for such a case.
1 parent 2d4adfe commit 0f7f250

File tree

3 files changed

+67
-7
lines changed

3 files changed

+67
-7
lines changed

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,8 @@ mlir::Value CIRGenModule::getGlobalValue(const Decl *D) {
471471
mlir::cir::GlobalOp CIRGenModule::createGlobalOp(CIRGenModule &CGM,
472472
mlir::Location loc,
473473
StringRef name, mlir::Type t,
474-
bool isCst) {
474+
bool isCst,
475+
mlir::Operation *insertPoint) {
475476
mlir::cir::GlobalOp g;
476477
auto &builder = CGM.getBuilder();
477478
{
@@ -486,8 +487,12 @@ mlir::cir::GlobalOp CIRGenModule::createGlobalOp(CIRGenModule &CGM,
486487
builder.setInsertionPoint(curCGF->CurFn);
487488

488489
g = builder.create<mlir::cir::GlobalOp>(loc, name, t, isCst);
489-
if (!curCGF)
490-
CGM.getModule().push_back(g);
490+
if (!curCGF) {
491+
if (insertPoint)
492+
CGM.getModule().insert(insertPoint, g);
493+
else
494+
CGM.getModule().push_back(g);
495+
}
491496

492497
// Default to private until we can judge based on the initializer,
493498
// since MLIR doesn't allow public declarations.
@@ -501,6 +506,35 @@ void CIRGenModule::setCommonAttributes(GlobalDecl GD, mlir::Operation *GV) {
501506
assert(!UnimplementedFeature::setCommonAttributes());
502507
}
503508

509+
void CIRGenModule::replaceGlobal(mlir::cir::GlobalOp Old,
510+
mlir::cir::GlobalOp New) {
511+
assert(Old.getSymName() == New.getSymName() && "symbol names must match");
512+
513+
// If the types does not match, update all references to Old to the new type.
514+
auto OldTy = Old.getSymType();
515+
auto NewTy = New.getSymType();
516+
if (OldTy != NewTy) {
517+
auto OldSymUses = Old.getSymbolUses(theModule.getOperation());
518+
if (OldSymUses.has_value()) {
519+
for (auto Use : *OldSymUses) {
520+
auto *UserOp = Use.getUser();
521+
assert((isa<mlir::cir::GetGlobalOp>(UserOp) ||
522+
isa<mlir::cir::GlobalOp>(UserOp)) &&
523+
"GlobalOp symbol user is neither a GetGlobalOp nor a GlobalOp");
524+
525+
if (auto GGO = dyn_cast<mlir::cir::GetGlobalOp>(Use.getUser())) {
526+
auto UseOpResultValue = GGO.getAddr();
527+
UseOpResultValue.setType(
528+
mlir::cir::PointerType::get(builder.getContext(), NewTy));
529+
}
530+
}
531+
}
532+
}
533+
534+
// Remove old global from the module.
535+
Old.erase();
536+
}
537+
504538
/// If the specified mangled name is not in the module,
505539
/// create and return an mlir GlobalOp with the specified type (TODO(cir):
506540
/// address space).
@@ -592,11 +626,14 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
592626
// mlir::SymbolTable::Visibility::Public is the default, no need to explicitly
593627
// mark it as such.
594628
auto GV = CIRGenModule::createGlobalOp(*this, loc, MangledName, Ty,
595-
/*isConstant=*/false);
629+
/*isConstant=*/false,
630+
/*insertPoint=*/Entry.getOperation());
596631

597632
// If we already created a global with the same mangled name (but different
598-
// type) before, take its name and remove it from its parent.
599-
assert(!Entry && "not implemented");
633+
// type) before, replace it with the new global.
634+
if (Entry) {
635+
replaceGlobal(Entry, GV);
636+
}
600637

601638
// This is the first use or definition of a mangled name. If there is a
602639
// deferred decl with this name, remember that we need to emit it at the end

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ class CIRGenModule : public CIRGenTypeCache {
220220

221221
static mlir::cir::GlobalOp createGlobalOp(CIRGenModule &CGM,
222222
mlir::Location loc, StringRef name,
223-
mlir::Type t, bool isCst = false);
223+
mlir::Type t, bool isCst = false,
224+
mlir::Operation *insertPoint = nullptr);
224225

225226
/// Return the mlir::Value for the address of the given global variable.
226227
/// If Ty is non-null and if the global doesn't exist, then it will be created
@@ -445,6 +446,14 @@ class CIRGenModule : public CIRGenTypeCache {
445446
void setGVProperties(mlir::Operation *Op, const NamedDecl *D) const;
446447
void setGVPropertiesAux(mlir::Operation *Op, const NamedDecl *D) const;
447448

449+
/// Replace the present global `Old` with the given global `New`. Their symbol
450+
/// names must match; their types can be different. Usages of the old global
451+
/// will be automatically updated if their types mismatch.
452+
///
453+
/// This function will erase the old global. This function will NOT insert the
454+
/// new global into the module.
455+
void replaceGlobal(mlir::cir::GlobalOp Old, mlir::cir::GlobalOp New);
456+
448457
/// Determine whether the definition must be emitted; if this returns \c
449458
/// false, the definition can be emitted lazily if it's used.
450459
bool MustBeEmitted(const clang::ValueDecl *D);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o - | FileCheck %s
2+
3+
extern int table[];
4+
// CHECK: cir.global external @table = #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i]> : !cir.array<!s32i x 3>
5+
6+
int *table_ptr = table;
7+
// CHECK: cir.global external @table_ptr = #cir.global_view<@table> : !cir.ptr<!s32i>
8+
9+
int test() { return table[1]; }
10+
// CHECK: cir.func @_Z4testv() -> !s32i extra( {inline = #cir.inline<no>, optnone = #cir.optnone} ) {
11+
// CHECK-NEXT: %0 = cir.alloca !s32i, cir.ptr <!s32i>, ["__retval"] {alignment = 4 : i64}
12+
// CHECK-NEXT: %1 = cir.get_global @table : cir.ptr <!cir.array<!s32i x 3>>
13+
14+
int table[3] {1, 2, 3};

0 commit comments

Comments
 (0)