diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 8dfd3c89678a..9da9ab441c4c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -501,6 +501,34 @@ void CIRGenModule::setCommonAttributes(GlobalDecl GD, mlir::Operation *GV) { assert(!UnimplementedFeature::setCommonAttributes()); } +/// Given the type of a previously-seen declaration and the type of a new +/// declaration, determine whether the new declaration can re-declare the +/// previous declaration. +/// +/// This typically requires that the given two types are identical. However +/// there are some exceptions: +/// - If the given two types are array types with identical element type, +/// and PreviousTy has unknown array bound, this function returns true. +static bool isValidRedeclarationType(mlir::Type PreviousTy, mlir::Type NowTy) { + if (PreviousTy == NowTy) + return true; + + if (isa(PreviousTy) && + isa(NowTy)) { + auto PreviousArrayTy = cast(PreviousTy); + auto NowArrayTy = cast(NowTy); + + if (PreviousArrayTy.getEltType() != NowArrayTy.getEltType()) + return false; + + // At this point PreviousTy and NowTy cannot have identical sizes because + // this would make PreviousTy and NowTy identical. + return PreviousArrayTy.getSize() == 0; + } + + return false; +} + /// If the specified mangled name is not in the module, /// create and return an mlir GlobalOp with the specified type (TODO(cir): /// address space). @@ -546,7 +574,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef MangledName, mlir::Type Ty, assert(0 && "not implemented"); // TODO(cir): check TargetAS matches Entry address space - if (Entry.getSymType() == Ty && + if (isValidRedeclarationType(Entry.getSymType(), Ty) && !UnimplementedFeature::addressSpaceInGlobalVar()) return Entry; @@ -909,7 +937,7 @@ void CIRGenModule::buildGlobalVarDefinition(const clang::VarDecl *D, // from the type of the global (this happens with unions). if (!GV || GV.getSymType() != InitType) { // TODO(cir): this should include an address space check as well. - assert(0 && "not implemented"); + setTypeOfGlobal(GV, InitType); } maybeHandleStaticInExternC(D, GV); @@ -1512,6 +1540,28 @@ mlir::cir::GlobalLinkageKind CIRGenModule::getCIRLinkageForDeclarator( return mlir::cir::GlobalLinkageKind::ExternalLinkage; } +void CIRGenModule::setTypeOfGlobal(mlir::cir::GlobalOp &Op, mlir::Type Ty) { + if (Op.getSymType() == Ty) + return; + + Op.setSymType(Ty); + auto Sym = cast(Op.getOperation()); + + // Replace the types at every use site. + auto SymUses = Sym.getSymbolUses(theModule.getOperation()); + if (!SymUses.has_value()) + return; + + for (auto SymUse : *SymUses) { + auto UseOp = dyn_cast(SymUse.getUser()); + assert(UseOp && "symbol users of GlobalOp is not a GetGlobalOp"); + + auto UseOpResultValue = UseOp.getAddr(); + UseOpResultValue.setType( + mlir::cir::PointerType::get(builder.getContext(), Ty)); + } +} + /// This function is called when we implement a function with no prototype, e.g. /// "int foo() {}". If there are existing call uses of the old function in the /// module, this adjusts them to call the new function directly. diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index aeb1313b38c4..883b071cb0fd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -567,6 +567,10 @@ class CIRGenModule : public CIRGenTypeCache { getMLIRVisibilityFromCIRLinkage(L)); } + /// Set the type of the given GlobalOp to the given type, and replace the + /// types accordingly at every use site of the given GlobalOp. + void setTypeOfGlobal(mlir::cir::GlobalOp &Op, mlir::Type Ty); + mlir::cir::GlobalLinkageKind getCIRLinkageVarDefinition(const VarDecl *VD, bool IsConstant); diff --git a/clang/test/CIR/CodeGen/array-unknown-bound.cpp b/clang/test/CIR/CodeGen/array-unknown-bound.cpp new file mode 100644 index 000000000000..9989c7a25dd3 --- /dev/null +++ b/clang/test/CIR/CodeGen/array-unknown-bound.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-cir %s -o - | FileCheck %s + +extern int table[]; +// CHECK: cir.global external @table = #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i]> : !cir.array + +int test() { return table[1]; } +// CHECK: cir.func @_Z4testv() -> !s32i extra( {inline = #cir.inline, optnone = #cir.optnone} ) { +// CHECK-NEXT: %0 = cir.alloca !s32i, cir.ptr , ["__retval"] {alignment = 4 : i64} +// CHECK-NEXT: %1 = cir.get_global @table : cir.ptr > + +int table[3] {1, 2, 3};