Skip to content

Commit 0c65f1c

Browse files
committed
[CIR][CodeGen] support array def after decl with unknown bound
Arrays can be first declared without a known bound, and then defined with a known bound. clangir crashes on generating CIR for this case. This patch adds support.
1 parent 38e962d commit 0c65f1c

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,34 @@ void CIRGenModule::setCommonAttributes(GlobalDecl GD, mlir::Operation *GV) {
501501
assert(!UnimplementedFeature::setCommonAttributes());
502502
}
503503

504+
/// Given the type of a previously-seen declaration and the type of a new
505+
/// declaration, determine whether the new declaration can re-declare the
506+
/// previous declaration.
507+
///
508+
/// This typically requires that the given two types are identical. However
509+
/// there are some exceptions:
510+
/// - If the given two types are array types with identical element type,
511+
/// and PreviousTy has unknown array bound, this function returns true.
512+
static bool isValidRedeclarationType(mlir::Type PreviousTy, mlir::Type NowTy) {
513+
if (PreviousTy == NowTy)
514+
return true;
515+
516+
if (isa<mlir::cir::ArrayType>(PreviousTy) &&
517+
isa<mlir::cir::ArrayType>(NowTy)) {
518+
auto PreviousArrayTy = cast<mlir::cir::ArrayType>(PreviousTy);
519+
auto NowArrayTy = cast<mlir::cir::ArrayType>(NowTy);
520+
521+
if (PreviousArrayTy.getEltType() != NowArrayTy.getEltType())
522+
return false;
523+
524+
// At this point PreviousTy and NowTy cannot have identical sizes because
525+
// this would make PreviousTy and NowTy identical.
526+
return PreviousArrayTy.getSize() == 0;
527+
}
528+
529+
return false;
530+
}
531+
504532
/// If the specified mangled name is not in the module,
505533
/// create and return an mlir GlobalOp with the specified type (TODO(cir):
506534
/// address space).
@@ -546,7 +574,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty,
546574
assert(0 && "not implemented");
547575

548576
// TODO(cir): check TargetAS matches Entry address space
549-
if (Entry.getSymType() == Ty &&
577+
if (isValidRedeclarationType(Entry.getSymType(), Ty) &&
550578
!UnimplementedFeature::addressSpaceInGlobalVar())
551579
return Entry;
552580

@@ -909,7 +937,7 @@ void CIRGenModule::buildGlobalVarDefinition(const clang::VarDecl *D,
909937
// from the type of the global (this happens with unions).
910938
if (!GV || GV.getSymType() != InitType) {
911939
// TODO(cir): this should include an address space check as well.
912-
assert(0 && "not implemented");
940+
setTypeOfGlobal(GV, InitType);
913941
}
914942

915943
maybeHandleStaticInExternC(D, GV);
@@ -1512,6 +1540,28 @@ mlir::cir::GlobalLinkageKind CIRGenModule::getCIRLinkageForDeclarator(
15121540
return mlir::cir::GlobalLinkageKind::ExternalLinkage;
15131541
}
15141542

1543+
void CIRGenModule::setTypeOfGlobal(mlir::cir::GlobalOp &Op, mlir::Type Ty) {
1544+
if (Op.getSymType() == Ty)
1545+
return;
1546+
1547+
Op.setSymType(Ty);
1548+
auto Sym = cast<mlir::SymbolOpInterface>(Op.getOperation());
1549+
1550+
// Replace the types at every use site.
1551+
auto SymUses = Sym.getSymbolUses(theModule.getOperation());
1552+
if (!SymUses.has_value())
1553+
return;
1554+
1555+
for (auto SymUse : *SymUses) {
1556+
auto UseOp = dyn_cast<mlir::cir::GetGlobalOp>(SymUse.getUser());
1557+
assert(UseOp && "symbol users of GlobalOp is not a GetGlobalOp");
1558+
1559+
auto UseOpResultValue = UseOp.getAddr();
1560+
UseOpResultValue.setType(
1561+
mlir::cir::PointerType::get(builder.getContext(), Ty));
1562+
}
1563+
}
1564+
15151565
/// This function is called when we implement a function with no prototype, e.g.
15161566
/// "int foo() {}". If there are existing call uses of the old function in the
15171567
/// module, this adjusts them to call the new function directly.

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,10 @@ class CIRGenModule : public CIRGenTypeCache {
567567
getMLIRVisibilityFromCIRLinkage(L));
568568
}
569569

570+
/// Set the type of the given GlobalOp to the given type, and replace the
571+
/// types accordingly at every use site of the given GlobalOp.
572+
void setTypeOfGlobal(mlir::cir::GlobalOp &Op, mlir::Type Ty);
573+
570574
mlir::cir::GlobalLinkageKind getCIRLinkageVarDefinition(const VarDecl *VD,
571575
bool IsConstant);
572576

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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 test() { return table[1]; }
7+
// CHECK: cir.func @_Z4testv() -> !s32i extra( {inline = #cir.inline<no>, optnone = #cir.optnone} ) {
8+
// CHECK-NEXT: %0 = cir.alloca !s32i, cir.ptr <!s32i>, ["__retval"] {alignment = 4 : i64}
9+
// CHECK-NEXT: %1 = cir.get_global @table : cir.ptr <!cir.array<!s32i x 3>>
10+
11+
int table[3] {1, 2, 3};

0 commit comments

Comments
 (0)