Skip to content

Conversation

@AmrDeveloper
Copy link
Member

Implement CountOf on VariableArrayType with IntegerConstant SizeExpr

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Nov 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 24, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clangir

Author: Amr Hesham (AmrDeveloper)

Changes

Implement CountOf on VariableArrayType with IntegerConstant SizeExpr


Full diff: https://github.com/llvm/llvm-project/pull/169404.diff

2 Files Affected:

  • (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+21-8)
  • (added) clang/test/CIR/CodeGen/count-of.c (+28)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 7c94743d5ffc6..feb019292715c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -2325,14 +2325,27 @@ mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
   const QualType typeToSize = e->getTypeOfArgument();
   const mlir::Location loc = cgf.getLoc(e->getSourceRange());
   if (auto kind = e->getKind();
-      kind == UETT_SizeOf || kind == UETT_DataSizeOf) {
-    if (cgf.getContext().getAsVariableArrayType(typeToSize)) {
-      cgf.getCIRGenModule().errorNYI(e->getSourceRange(),
-                                     "sizeof operator for VariableArrayType",
-                                     e->getStmtClassName());
-      return builder.getConstant(
-          loc, cir::IntAttr::get(cgf.cgm.uInt64Ty,
-                                 llvm::APSInt(llvm::APInt(64, 1), true)));
+      kind == UETT_SizeOf || kind == UETT_DataSizeOf || kind == UETT_CountOf) {
+    if (const VariableArrayType *vat =
+            cgf.getContext().getAsVariableArrayType(typeToSize)) {
+      // 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());
+      }
+
+      if (evaluateExtent) {
+        cgf.getCIRGenModule().errorNYI(
+            e->getSourceRange(),
+            "sizeof operator for VariableArrayType & evaluateExtent",
+            e->getStmtClassName());
+        return builder.getConstant(
+            loc, cir::IntAttr::get(cgf.cgm.uInt64Ty,
+                                   -llvm::APSInt(llvm::APInt(64, 1), true)));
+      }
     }
   } else if (e->getKind() == UETT_OpenMPRequiredSimdAlign) {
     cgf.getCIRGenModule().errorNYI(
diff --git a/clang/test/CIR/CodeGen/count-of.c b/clang/test/CIR/CodeGen/count-of.c
new file mode 100644
index 0000000000000..78c905e285969
--- /dev/null
+++ b/clang/test/CIR/CodeGen/count-of.c
@@ -0,0 +1,28 @@
+// 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() {
+  long size;
+#define int_arr int[5]
+  return _Countof(int_arr[size]);
+}
+
+// CIR: %[[RET_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["__retval"]
+// CIR: %[[SIZE_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["size"]
+// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !u64i
+// CIR: cir.store %[[CONST_5]], %[[RET_ADDR]] : !u64i, !cir.ptr<!u64i>
+// CIR: %[[RET_VAL:.*]] = cir.load %[[RET_ADDR]] : !cir.ptr<!u64i>, !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

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks fine, except for an issue with the test case. The implementation for evaluateExtent looks small. Why not include that in this same PR?

Comment on lines 10 to 11
#define int_arr int[5]
return _Countof(int_arr[size]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an off way to represent the array. Why are you using #define here? Also, I believe this is using an uninitialized variable to describe a two-dimensional array, which is likely UB. Maybe make the variable an argument?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this test case, I want to create an array type, not an array int[5][size] 🤔, i think it's TypeExpr and will not init array right?

https://godbolt.org/z/PEc69zWhz

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the evaluateExtent implementation has one part related to CountOf and other parts are related to sizeof, I will address the countof part here and all sizeof part will be in follow up PR if thats okey

@github-actions
Copy link

🐧 Linux x64 Test Results

  • 3053 tests passed
  • 7 tests skipped

All tests passed but another part of the build failed. Click on a failure below to see the details.

tools/clang/lib/CIR/CodeGen/CMakeFiles/obj.clangCIR.dir/CIRGenFunction.cpp.o
FAILED: tools/clang/lib/CIR/CodeGen/CMakeFiles/obj.clangCIR.dir/CIRGenFunction.cpp.o
sccache /opt/llvm/bin/clang++ -DCLANG_EXPORTS -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/lib/CIR/CodeGen -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CIR/CodeGen -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/../mlir/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/mlir/include -gmlt -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG -std=c++17  -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT tools/clang/lib/CIR/CodeGen/CMakeFiles/obj.clangCIR.dir/CIRGenFunction.cpp.o -MF tools/clang/lib/CIR/CodeGen/CMakeFiles/obj.clangCIR.dir/CIRGenFunction.cpp.o.d -o tools/clang/lib/CIR/CodeGen/CMakeFiles/obj.clangCIR.dir/CIRGenFunction.cpp.o -c /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CIR/CodeGen/CIRGenFunction.cpp:1145:17: error: member reference type 'mlir::Value' is not a pointer; did you mean to use '.'?
1145 |   assert(vlaSize->getType() == sizeTy);
|          ~~~~~~~^~
|                 .
/usr/include/assert.h:103:27: note: expanded from macro 'assert'
103 |      (static_cast <bool> (expr)                                         \
|                           ^~~~
1 error generated.

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

@AmrDeveloper AmrDeveloper force-pushed the cir_count_of_vla_of_array branch from d12ce8d to 8eede9c Compare November 26, 2025 17:49
@AmrDeveloper AmrDeveloper enabled auto-merge (squash) November 26, 2025 17:50
@AmrDeveloper AmrDeveloper merged commit 18805b6 into llvm:main Nov 26, 2025
7 of 9 checks passed
CIRGenFunction::getVLAElements1D(const VariableArrayType *vla) {
mlir::Value vlaSize = vlaSizeMap[vla->getSizeExpr()];
assert(vlaSize && "no size for VLA!");
assert(vlaSize->getType() == sizeTy);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vlaSize isn't a pointer, so this fails to build:

runner/_work/llvm-project/llvm-project/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
2025-11-26T19:23:08.6857824Z /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CIR/CodeGen/CIRGenFunction.cpp:1145:17: error: member reference type 'mlir::Value' is not a pointer; did you mean to use '.'?
2025-11-26T19:23:08.6859083Z  1145 |   assert(vlaSize->getType() == sizeTy);
2025-11-26T19:23:08.6859503Z       |          ~~~~~~~^~
2025-11-26T19:23:08.6859814Z       |                 .
2025-11-26T19:23:08.6860251Z /usr/include/assert.h:103:27: note: expanded from macro 'assert'
2025-11-26T19:23:08.6860727Z   103 |      (static_cast <bool> (expr)                                         \
2025-11-26T19:23:08.6861052Z       |                           ^~~~

Note this seems to have been caught by pre-commit CI as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm preparing a fix for it now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for catching it

tanji-dg pushed a commit to tanji-dg/llvm-project that referenced this pull request Nov 27, 2025
Implement CountOf on VariableArrayType with IntegerConstant SizeExpr
GeneraluseAI pushed a commit to GeneraluseAI/llvm-project that referenced this pull request Nov 27, 2025
Implement CountOf on VariableArrayType with IntegerConstant SizeExpr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants