Author: Erich Keane Date: 2026-10-07T00:09:11Z New Revision: b46a38ca6d8abab3f1cce34639f9ee2a09bbeaf9
URL: https://github.com/llvm/llvm-project/commit/b46a38ca6d8abab3f1cce34639f9ee2a09bbeaf9 DIFF: https://github.com/llvm/llvm-project/commit/b46a38ca6d8abab3f1cce34639f9ee2a09bbeaf9.diff LOG: [CIR] Correct 'null' init for array types with non-zero init (#229543) The member pointers are supposed to be initialized to -1, so an array of them or a record of them needs to be initialized properly to -1. This patch makes sure we look through array types/etc to get the correct initialization. Also, quite a few places were using 'getZeroAttr' when they meant 'null init', so this changes that as well. Added: Modified: clang/lib/CIR/CodeGen/CIRGenDecl.cpp clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp clang/lib/CIR/CodeGen/CIRGenModule.cpp clang/lib/CIR/CodeGen/CIRGenTypes.cpp clang/test/CIR/CodeGen/member-pointer-null-init.cpp clang/test/CIR/CodeGen/unions-with-zero-init.cpp Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 05776c5579678..1c15c2fd6ec65 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -536,7 +536,7 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &d, d.hasAttr<CUDASharedAttr>() || d.hasAttr<LoaderUninitializedAttr>()) init = cir::UndefAttr::get(lty); else - init = builder.getZeroInitAttr(convertType(ty)); + init = emitNullConstantAttr(ty); mlir::ptr::MemorySpaceAttrInterface addrSpace = cir::toCIRAddressSpaceAttr( getMLIRContext(), getGlobalVarAddressSpace(&d)); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp index bdfe477831e1c..cfe575f4670dd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -676,7 +676,7 @@ class ConstExprEmitter mlir::Attribute VisitImplicitValueInitExpr(ImplicitValueInitExpr *e, QualType t) { - return cgm.getBuilder().getZeroInitAttr(cgm.convertType(t)); + return cgm.emitNullConstantAttr(t); } mlir::Attribute VisitInitListExpr(InitListExpr *ile, QualType t) { @@ -1669,9 +1669,22 @@ mlir::TypedAttr CIRGenModule::emitNullConstantAttr(QualType t) { if (getTypes().isZeroInitializable(t)) return builder.getZeroInitAttr(getTypes().convertTypeForMem(t)); - if (getASTContext().getAsConstantArrayType(t)) { - errorNYI("CIRGenModule::emitNullConstantAttr ConstantArrayType"); - return {}; + if (const ConstantArrayType *cat = + getASTContext().getAsConstantArrayType(t)) { + QualType elementTy = cat->getElementType(); + mlir::TypedAttr elementAttr = emitNullConstantAttr(elementTy); + if (!elementAttr) + return {}; + + auto arrayTy = mlir::cast<cir::ArrayType>(getTypes().convertTypeForMem(t)); + + if (builder.isNullValue(elementAttr)) + return cir::ZeroAttr::get(arrayTy); + + llvm::SmallVector<mlir::Attribute> elements(cat->getZExtSize(), + elementAttr); + return cir::ConstArrayAttr::get( + arrayTy, mlir::ArrayAttr::get(builder.getContext(), elements)); } if (const RecordType *rt = t->getAs<RecordType>()) diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 92c8af433aace..5e1a98a15ad40 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1604,7 +1604,7 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, // exists. A use may still exists, however, so we still may need // to do a RAUW. assert(!vd->getType()->isIncompleteType() && "Unexpected incomplete type"); - init = builder.getZeroInitAttr(convertType(vd->getType())); + init = emitNullConstantAttr(vd->getType()); } else { emitter.emplace(*this); mlir::Attribute initializer = emitter->tryEmitForInitializer(*initDecl); @@ -1617,7 +1617,7 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd, if (initDecl->hasFlexibleArrayInit(astContext)) errorNYI(vd->getSourceRange(), "emitGlobalVarDefinition: flexible array initializer"); - init = builder.getZeroInitAttr(convertType(qt)); + init = emitNullConstantAttr(qt); if (!isDefinitionAvailableExternally) needsGlobalCtor = true; } else { diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index dff1ce1260787..09283cf7362bb 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -735,7 +735,7 @@ CIRGenTypes::getCIRGenRecordLayout(const RecordDecl *rd) { } bool CIRGenTypes::isZeroInitializable(clang::QualType t) { - if (t->getAs<PointerType>()) + if (t->getAs<PointerType>() || t->isNullPtrType()) return astContext.getTargetNullPointerValue(t) == 0; if (const auto *at = astContext.getAsArrayType(t)) { @@ -745,6 +745,8 @@ bool CIRGenTypes::isZeroInitializable(clang::QualType t) { if (const auto *cat = dyn_cast<ConstantArrayType>(at)) if (astContext.getConstantArrayElementCount(cat) == 0) return true; + + t = astContext.getBaseElementType(t); } if (const auto *rd = t->getAsRecordDecl()) diff --git a/clang/test/CIR/CodeGen/member-pointer-null-init.cpp b/clang/test/CIR/CodeGen/member-pointer-null-init.cpp index 74ee344c6f407..ca15d122f5cbb 100644 --- a/clang/test/CIR/CodeGen/member-pointer-null-init.cpp +++ b/clang/test/CIR/CodeGen/member-pointer-null-init.cpp @@ -14,8 +14,55 @@ struct Outer { int b; }; -// Value-init of a heap-allocated struct containing a pointer-to-data-member. -// The member pointer is null (-1), so the stored constant must carry -1. +struct Outer2 { + int Outer::*m[2]; + int b; +}; + +// Arrays of pointer-to-data-member should be all -1s. + +// CIR: cir.global "private" internal dso_local @_ZZ12static_slotsvE8fn_slots = #cir.const_array<[#cir.int<-1> : !s64i, #cir.int<-1> : !s64i]> : !cir.array<!s64i x 2> +// CIR: cir.global external @ns_slots = #cir.const_array<[#cir.int<-1> : !s64i, #cir.int<-1> : !s64i]> : !cir.array<!s64i x 2> + +// LLVM-DAG: @_ZZ12static_slotsvE8fn_slots = internal global [2 x i64] [i64 -1, i64 -1] +// LLVM-DAG: @ns_slots = {{.*}}global [2 x i64] [i64 -1, i64 -1] + +int Inner::*ns_slots[2]; + +void static_slots() { + static int Inner::*fn_slots[2]; + (void)fn_slots; +} + +// CIR: cir.global external @vol_slots = #cir.const_array<[#cir.int<-1> : !s64i, #cir.int<-1> : !s64i]> : !cir.array<!s64i x 2> + +// LLVM-DAG: @vol_slots = {{.*}}global [2 x i64] [i64 -1, i64 -1] + +volatile int Inner::*vol_slots[2]; + +// Array of record-types with the member pointer, also should have -1s. + +// CIR: cir.global external @rec_slots = #cir.const_array<[#cir.const_record<{#cir.int<-1> : !s64i}> : !rec_Inner, #cir.const_record<{#cir.int<-1> : !s64i}> : !rec_Inner]> : !cir.array<!rec_Inner x 2> + +// LLVM-DAG: @rec_slots = {{.*}}global [2 x %struct.Inner] [%struct.Inner { i64 -1 }, %struct.Inner { i64 -1 }] + +Inner rec_slots[2]; + +// A nested (multi-dimensional) array of pointers-to-data-member must have +// -1 in every innermost element. + +// CIR: cir.global external @md_slots = #cir.const_array<[#cir.const_array<[#cir.int<-1> : !s64i, #cir.int<-1> : !s64i, #cir.int<-1> : !s64i]> : !cir.array<!s64i x 3>, #cir.const_array<[#cir.int<-1> : !s64i, #cir.int<-1> : !s64i, #cir.int<-1> : !s64i]> : !cir.array<!s64i x 3>]> : !cir.array<!cir.array<!s64i x 3> x 2> + +// LLVM-DAG: @md_slots = {{.*}}global [2 x [3 x i64]] [{{\[3 x i64\]}} [i64 -1, i64 -1, i64 -1], {{\[3 x i64\]}} [i64 -1, i64 -1, i64 -1]] + +int Inner::*md_slots[2][3]; + +// CIR: cir.global external @initList = #cir.const_record<{#cir.const_array<[#cir.int<-1> : !s64i, #cir.int<-1> : !s64i]> : !cir.array<!s64i x 2>, #cir.int<1> : !s32i}> : !rec_Outer2 align(8) +// LLVM-DAG: @initList = global %struct.Outer2 { [2 x i64] [i64 -1, i64 -1], i32 1 }, align 8 + +Outer2 initList = {.b = 1}; + +// Same with 'new' allocated types. // CIR-LABEL: cir.func {{.*}}@_Z8make_newv // CIR: [[NULL:%.*]] = cir.const #cir.const_record<{#cir.int<-1> : !s64i}> : !rec_Inner @@ -31,8 +78,7 @@ struct Outer { Inner *make_new() { return new Inner(); } -// Partial aggregate init: Inner subobject 'a' is value-initialized because -// it has no designated initializer. +// Aggregate init should also get this right. // CIR-LABEL: cir.func {{.*}}@_Z11runtime_aggi // CIR: cir.const #cir.int<-1> : !s64i diff --git a/clang/test/CIR/CodeGen/unions-with-zero-init.cpp b/clang/test/CIR/CodeGen/unions-with-zero-init.cpp index 9c9cdc0165a15..ebddb95c545eb 100644 --- a/clang/test/CIR/CodeGen/unions-with-zero-init.cpp +++ b/clang/test/CIR/CodeGen/unions-with-zero-init.cpp @@ -47,12 +47,7 @@ int S::* p = nullptr; // CIR-AFTER-LABEL: cir.global external @p = #cir.int<-1> : !s64i // LLVM-DAG: @p = global i64 -1, align 8 -// LLVMCIR gets this diff erent because by the time we see how to do a 'zero' -// field, we've already lost the member-pointer type, because LowerToLLVM is -// doing the 'zeroing'. We could be more clever here, but this is only in cases -// where it gets initialized anyway. -// LLVMCIR-DAG: @outer_a1 = global %union.outer_aggregate zeroinitializer -// OGCG-DAG: @outer_a1 = global %union.outer_aggregate { i64 -1 } +// LLVM-DAG: @outer_a1 = global %union.outer_aggregate { i64 -1 } // LLVM-DAG: @outer_a2 = global { i32, [4 x i8] } { i32 32, [4 x i8] {{.*}} } // LLVM-DAG: @outer_a3 = global %union.outer_aggregate3 { i64 -1 } @@ -79,7 +74,7 @@ union outer_aggregate{int S::*m; int i; } outer_a1 = { p }; // CIR-BEFORE: cir.store {{.*}}%[[LOAD_P]], %[[GET_MEM]] : !cir.data_member<!s32i in !rec_S>, !cir.ptr<!cir.data_member<!s32i in !rec_S>> // CIR-BEFORE: } -// CIR-AFTER-LABEL: cir.global external @outer_a1 = #cir.zero : !rec_outer_aggregate +// CIR-AFTER-LABEL: cir.global external @outer_a1 = #cir.const_record<{#cir.int<-1> : !s64i}> : !rec_outer_aggregate // CIR-AFTER-LABEL: cir.func internal private @__cxx_global_var_init() { // CIR-AFTER: %[[GET_GLOB:.*]] = cir.get_global @outer_a1 : !cir.ptr<!rec_outer_aggregate> // CIR-AFTER: %[[GET_MEM:.*]] = cir.get_member %[[GET_GLOB]][0] {name = "m"} : !cir.ptr<!rec_outer_aggregate> -> !cir.ptr<!s64i> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
