From b0553a8a745760605209572e119f62ddc2d0f8f0 Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Wed, 26 Nov 2025 20:11:51 +0100 Subject: [PATCH 1/2] [CIR] Backport CountOf VLA with Array element type --- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 46 ++++++++++++------- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 8 ++++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 4 ++ clang/test/CIR/CodeGen/count-of.c | 52 ++++++++++++++++++++++ 4 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 clang/test/CIR/CodeGen/count-of.c diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 0875cc11d05a..0472a98d44ac 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -3028,28 +3028,44 @@ mlir::Value ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr( const UnaryExprOrTypeTraitExpr *E) { QualType TypeToSize = E->getTypeOfArgument(); - if (E->getKind() == UETT_SizeOf) { + if (auto kind = E->getKind(); + kind == UETT_SizeOf || kind == UETT_DataSizeOf | kind == UETT_CountOf) { if (const VariableArrayType *VAT = CGF.getContext().getAsVariableArrayType(TypeToSize)) { - if (E->isArgumentType()) { - // sizeof(type) - make sure to emit the VLA size. - CGF.emitVariablyModifiedType(TypeToSize); - } else { - // C99 6.5.3.4p2: If the argument is an expression of type - // VLA, it is evaluated. - CGF.emitIgnoredExpr(E->getArgumentExpr()); + // For _Countof, we only want to evaluate if the extent is actually + // variable as opposed to a multi-dimensional array whose extent is + // constant but whose element type is variable. + bool evaluateExtent = true; + if (kind == UETT_CountOf && VAT->getElementType()->isArrayType()) { + evaluateExtent = + !VAT->getSizeExpr()->isIntegerConstantExpr(CGF.getContext()); } - auto VlaSize = CGF.getVLASize(VAT); - mlir::Value size = VlaSize.NumElts; + if (evaluateExtent) { + if (E->isArgumentType()) { + // sizeof(type) - make sure to emit the VLA size. + CGF.emitVariablyModifiedType(TypeToSize); + } else { + // C99 6.5.3.4p2: If the argument is an expression of type + // VLA, it is evaluated. + CGF.emitIgnoredExpr(E->getArgumentExpr()); + } + + // For _Countof, we just want to return the size of a single dimension. + if (kind == UETT_CountOf) + return CGF.getVLAElements1D(VAT).NumElts; + + auto VlaSize = CGF.getVLASize(VAT); + mlir::Value size = VlaSize.NumElts; - // Scale the number of non-VLA elements by the non-VLA element size. - CharUnits eltSize = CGF.getContext().getTypeSizeInChars(VlaSize.Type); - if (!eltSize.isOne()) - size = Builder.createMul(size, CGF.CGM.getSize(eltSize).getValue()); + // Scale the number of non-VLA elements by the non-VLA element size. + CharUnits eltSize = CGF.getContext().getTypeSizeInChars(VlaSize.Type); + if (!eltSize.isOne()) + size = Builder.createMul(size, CGF.CGM.getSize(eltSize).getValue()); - return size; + return size; + } } } else if (E->getKind() == UETT_OpenMPRequiredSimdAlign) { llvm_unreachable("NYI"); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 808fe95af5b2..3d81fe34228b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -1808,6 +1808,14 @@ CIRGenFunction::getVLASize(const VariableArrayType *type) { return {numElements, elementType}; } +CIRGenFunction::VlaSizePair +CIRGenFunction::getVLAElements1D(const VariableArrayType *vla) { + mlir::Value vlaSize = VLASizeMap[vla->getSizeExpr()]; + assert(vlaSize && "no size for VLA!"); + assert(vlaSize.getType() == sizeTy); + return {vlaSize, vla->getElementType()}; +} + // TODO(cir): most part of this function can be shared between CIRGen // and traditional LLVM codegen void CIRGenFunction::emitVariablyModifiedType(QualType type) { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 081136b33e8f..55c2642ebb19 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -683,6 +683,10 @@ class CIRGenFunction : public CIRGenTypeCache { VlaSizePair(mlir::Value NE, QualType T) : NumElts(NE), Type(T) {} }; + /// Return the number of elements for a single dimension + /// for the given array type. + VlaSizePair getVLAElements1D(const VariableArrayType *vla); + /// Returns an MLIR value that corresponds to the size, /// in non-variably-sized elements, of a variable length array type, /// plus that largest non-variably-sized element type. Assumes that diff --git a/clang/test/CIR/CodeGen/count-of.c b/clang/test/CIR/CodeGen/count-of.c new file mode 100644 index 000000000000..1fd1290c42e6 --- /dev/null +++ b/clang/test/CIR/CodeGen/count-of.c @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -std=c2y -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +unsigned long vla_with_array_element_type_with_const_size() { + long size; + return _Countof(int[5][size]); +} + +// CIR: %[[RET_ADDR:.*]] = cir.alloca !u64i, !cir.ptr, ["__retval"] +// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !s64i, !cir.ptr, ["size"] +// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !u64i +// CIR: cir.store %[[CONST_5]], %[[RET_ADDR]] : !u64i, !cir.ptr +// CIR: %[[RET_VAL:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr, !u64i +// CIR: cir.return %[[RET_VAL]] : !u64i + +// LLVM: %[[RET_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: store i64 5, ptr %[[RET_ADDR]], align 8 +// LLVM: %[[RET_VAL:.*]] = load i64, ptr %[[RET_ADDR]], align 8 +// LLVM: ret i64 %[[RET_VAL]] + +// OGCG: %[[SIZE_ADDR:.*]] = alloca i64, align 8 +// OGCG: ret i64 5 + +unsigned long vla_with_array_element_type_non_const_size() { + long size; + return _Countof(int[size][size]); +} + +// CIR: %[[REET_ADDR:.*]] = cir.alloca !u64i, !cir.ptr, ["__retval"] +// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !s64i, !cir.ptr, ["size"] +// CIR: %[[TMP_SIZE:.*]] = cir.load {{.*}} %[[SIZE_ADDR]] : !cir.ptr, !s64i +// CIR: %[[TMP_SIZE_U64:.*]] = cir.cast integral %[[TMP_SIZE]] : !s64i -> !u64i +// CIR: cir.store %[[TMP_SIZE_U64]], %[[RET_ADDR]] : !u64i, !cir.ptr +// CIR: %[[TMP_RET:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr, !u64i +// CIR: cir.return %[[TMP_RET]] : !u64i + +// LLVM: %[[RET_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[SIZE_ADDR:.*]] = alloca i64, i64 1, align 8 +// LLVM: %[[TMP_SIZE:.*]] = load i64, ptr %[[SIZE_ADDR]], align 8 +// LLVM: store i64 %[[TMP_SIZE]], ptr %[[RET_ADDR]], align 8 +// LLVM: %[[TMP_RET:.*]] = load i64, ptr %[[RET_ADDR]], align 8 +// LLVM: ret i64 %[[TMP_RET]] + +// OGCG: %[[SIZE_ADDR:.*]] = alloca i64, align 8 +// OGCG: %[[TMP_SIZE:.*]] = load i64, ptr %[[SIZE_ADDR]], align 8 +// OGCG: %[[TMP_SIZE_2:.*]] = load i64, ptr %[[SIZE_ADDR]], align 8 +// OGCG: ret i64 %[[TMP_SIZE]] From b7b848b46703be3689a0336724566bb946af42ea Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Thu, 27 Nov 2025 20:53:02 +0100 Subject: [PATCH 2/2] Fix building with asserts --- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 3d81fe34228b..7f958275c672 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -1812,7 +1812,7 @@ CIRGenFunction::VlaSizePair CIRGenFunction::getVLAElements1D(const VariableArrayType *vla) { mlir::Value vlaSize = VLASizeMap[vla->getSizeExpr()]; assert(vlaSize && "no size for VLA!"); - assert(vlaSize.getType() == sizeTy); + assert(vlaSize.getType() == SizeTy); return {vlaSize, vla->getElementType()}; }