https://github.com/AbdallahRashed created 
https://github.com/llvm/llvm-project/pull/205641


Implement the VisitInitListExpr array path in ConstExprEmitter, which handles 
constant array initialization from InitListExpr nodes directly. Previously this 
path returned null, falling back to non-constant initialization. Now arrays are 
emitted as proper CIR constant arrays via emitArrayConstant.

This produces better output for string literal arrays in array initializers 
(compact string representation instead of per-character int arrays) and enables 
constant-folding of array globals that go through the ConstExprEmitter visitor.

Remove the constEmitterArrayILE MissingFeatures flag.

>From bad67eee47bee6675ab380b78b056d40b0fa5a8d Mon Sep 17 00:00:00 2001
From: AbdallahRashed <[email protected]>
Date: Sun, 31 May 2026 20:17:08 +0200
Subject: [PATCH] [CIR][CodeGen] Implement ConstExprEmitter array
 initialization from InitListExpr

Implement the VisitInitListExpr array path in ConstExprEmitter, which
handles constant array initialization from InitListExpr nodes directly.
Previously this path returned null, falling back to non-constant
initialization. Now arrays are emitted as proper CIR constant arrays
via emitArrayConstant.

This produces better output for string literal arrays in array
initializers (compact string representation instead of per-character
int arrays) and enables constant-folding of array globals that go
through the ConstExprEmitter visitor.

Remove the constEmitterArrayILE MissingFeatures flag.
---
 clang/include/clang/CIR/MissingFeatures.h    |  1 -
 clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp | 55 +++++++++++++++++---
 clang/test/CIR/CodeGen/agg-expr-lvalue.c     |  2 +-
 clang/test/CIR/CodeGen/const-array-init.c    | 48 +++++++++++++++++
 4 files changed, 98 insertions(+), 8 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/const-array-init.c

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 9a1546fe14e65..c4acd6b6b9df9 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -205,7 +205,6 @@ struct MissingFeatures {
   static bool cleanupAfterErrorDiags() { return false; }
   static bool cleanupDeactivationScope() { return false; }
   static bool cleanupsToDeactivate() { return false; }
-  static bool constEmitterArrayILE() { return false; }
   static bool constEmitterVectorILE() { return false; }
   static bool constantFoldSwitchStatement() { return false; }
   static bool constructABIArgDirectExtend() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index c29b66ac2f8bc..c9d212770f6ab 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -1048,16 +1048,59 @@ class ConstExprEmitter
     return cgm.getBuilder().getZeroInitAttr(cgm.convertType(t));
   }
 
+  mlir::Attribute emitArrayInitialization(InitListExpr *ile, QualType t) {
+    auto *cat = cgm.getASTContext().getAsConstantArrayType(ile->getType());
+    assert(cat && "can't emit array init for non-constant-bound array");
+    const unsigned numInitElements = ile->getNumInits();
+    const unsigned numElements = cat->getZExtSize();
+
+    // Initialising an array requires us to automatically
+    // initialise any elements that have not been initialised explicitly.
+    unsigned numInitableElts = std::min(numInitElements, numElements);
+
+    QualType eltType = cat->getElementType();
+
+    // Initialize remaining array elements.
+    mlir::TypedAttr fillC;
+    if (const Expr *filler = ile->getArrayFiller()) {
+      fillC = mlir::dyn_cast_or_null<mlir::TypedAttr>(
+          emitter.tryEmitPrivateForMemory(filler, eltType));
+      if (!fillC)
+        return {};
+    }
+
+    // Copy initializer elements.
+    SmallVector<mlir::TypedAttr, 16> elts;
+    if (fillC && cgm.getBuilder().isNullValue(fillC))
+      elts.reserve(numInitableElts + 1);
+    else
+      elts.reserve(numElements);
+
+    mlir::Type commonElementType;
+    for (unsigned i = 0; i < numInitableElts; ++i) {
+      const Expr *init = ile->getInit(i);
+      mlir::Attribute c = emitter.tryEmitPrivateForMemory(init, eltType);
+      if (!c)
+        return {};
+      auto typedC = mlir::cast<mlir::TypedAttr>(c);
+      if (i == 0)
+        commonElementType = typedC.getType();
+      else if (typedC.getType() != commonElementType)
+        commonElementType = {};
+      elts.push_back(typedC);
+    }
+
+    mlir::Type desiredType = cgm.convertType(ile->getType());
+    return emitArrayConstant(cgm, desiredType, commonElementType, numElements,
+                             elts, fillC);
+  }
+
   mlir::Attribute VisitInitListExpr(InitListExpr *ile, QualType t) {
     if (ile->isTransparent())
       return Visit(ile->getInit(0), t);
 
-    if (ile->getType()->isArrayType()) {
-      // If we return null here, the non-constant initializer will take care of
-      // it, but we would prefer to handle it here.
-      assert(!cir::MissingFeatures::constEmitterArrayILE());
-      return {};
-    }
+    if (ile->getType()->isArrayType())
+      return emitArrayInitialization(ile, t);
 
     if (ile->getType()->isRecordType()) {
       return ConstRecordBuilder::buildRecord(emitter, ile, t);
diff --git a/clang/test/CIR/CodeGen/agg-expr-lvalue.c 
b/clang/test/CIR/CodeGen/agg-expr-lvalue.c
index 51109d3082ab0..f230ed8c3b785 100644
--- a/clang/test/CIR/CodeGen/agg-expr-lvalue.c
+++ b/clang/test/CIR/CodeGen/agg-expr-lvalue.c
@@ -21,7 +21,7 @@ void test_member_in_array(void) {
 }
 
 // CIR-DAG: cir.global "private" constant cir_private @[[LINE_CONST:.*]] = 
#cir.const_record<{#cir.const_record<{#cir.int<1> : !s32i, #cir.int<2> : 
!s32i}> : !rec_Point, #cir.const_record<{#cir.int<3> : !s32i, #cir.int<4> : 
!s32i}> : !rec_Point}> : !rec_Line
-// CIR-DAG: cir.global "private" constant cir_private @[[MATRIX_CONST:.*]] = 
#cir.const_array<[#cir.const_array<[#cir.int<104> : !s8i, #cir.int<101> : !s8i, 
#cir.int<108> : !s8i, #cir.int<108> : !s8i, #cir.int<111> : !s8i, #cir.int<0> : 
!s8i]> : !cir.array<!s8i x 6>, #cir.const_array<[#cir.int<119> : !s8i, 
#cir.int<111> : !s8i, #cir.int<114> : !s8i, #cir.int<108> : !s8i, #cir.int<100> 
: !s8i, #cir.int<0> : !s8i]> : !cir.array<!s8i x 6>]>
+// CIR-DAG: cir.global "private" constant cir_private @[[MATRIX_CONST:.*]] = 
#cir.const_array<[#cir.const_array<"hello" : !cir.array<!s8i x 5>, 
trailing_zeros> : !cir.array<!s8i x 6>, #cir.const_array<"world" : 
!cir.array<!s8i x 5>, trailing_zeros> : !cir.array<!s8i x 6>]>
 
 // LLVM-DAG: @[[LINE_CONST:.*]] = private constant %struct.Line { 
%struct.Point { i32 1, i32 2 }, %struct.Point { i32 3, i32 4 } }
 // LLVM-DAG: @[[MATRIX_CONST:.*]] = private constant [2 x [6 x i8]] {{.*}}
diff --git a/clang/test/CIR/CodeGen/const-array-init.c 
b/clang/test/CIR/CodeGen/const-array-init.c
new file mode 100644
index 0000000000000..0a3f390899ce0
--- /dev/null
+++ b/clang/test/CIR/CodeGen/const-array-init.c
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+// Fully initialized array.
+int arr1[5] = {1, 2, 3, 4, 5};
+// CIR: cir.global external @arr1 = #cir.const_array<[#cir.int<1> : !s32i, 
#cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : 
!s32i]> : !cir.array<!s32i x 5>
+// LLVM: @arr1 = global [5 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5]
+// OGCG: @arr1 = global [5 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5]
+
+// Partial initialization with implicit zero fill (< 8 trailing zeros).
+int arr2[7] = {1, 2, 3};
+// CIR: cir.global external @arr2 = #cir.const_array<[#cir.int<1> : !s32i, 
#cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<0> : !s32i, #cir.int<0> : 
!s32i, #cir.int<0> : !s32i, #cir.int<0> : !s32i]> : !cir.array<!s32i x 7>
+// LLVM: @arr2 = global [7 x i32] [i32 1, i32 2, i32 3, i32 0, i32 0, i32 0, 
i32 0]
+// OGCG: @arr2 = global [7 x i32] [i32 1, i32 2, i32 3, i32 0, i32 0, i32 0, 
i32 0]
+
+// All-zero array from {0}.
+int arr3[4] = {0};
+// CIR: cir.global external @arr3 = #cir.zero : !cir.array<!s32i x 4>
+// LLVM: @arr3 = global [4 x i32] zeroinitializer
+// OGCG: @arr3 = global [4 x i32] zeroinitializer
+
+// Nested 2D array.
+int arr4[2][3] = {{1, 2, 3}, {4, 5, 6}};
+// CIR: cir.global external @arr4 = 
#cir.const_array<[#cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, 
#cir.int<3> : !s32i]> : !cir.array<!s32i x 3>, #cir.const_array<[#cir.int<4> : 
!s32i, #cir.int<5> : !s32i, #cir.int<6> : !s32i]> : !cir.array<!s32i x 3>]> : 
!cir.array<!cir.array<!s32i x 3> x 2>
+// LLVM: @arr4 = global [2 x [3 x i32]] {{\[}}[3 x i32] [i32 1, i32 2, i32 3], 
[3 x i32] [i32 4, i32 5, i32 6]]
+// OGCG: @arr4 = global [2 x [3 x i32]] {{\[}}[3 x i32] [i32 1, i32 2, i32 3], 
[3 x i32] [i32 4, i32 5, i32 6]]
+
+// Float array.
+float arr5[3] = {1.0f, 2.0f, 3.0f};
+// CIR: cir.global external @arr5 = #cir.const_array<[#cir.fp<1.000000e+00> : 
!cir.float, #cir.fp<2.000000e+00> : !cir.float, #cir.fp<3.000000e+00> : 
!cir.float]> : !cir.array<!cir.float x 3>
+// LLVM: @arr5 = global [3 x float] [float 1.000000e+00, float 2.000000e+00, 
float 3.000000e+00]
+// OGCG: @arr5 = global [3 x float] [float 1.000000e+00, float 2.000000e+00, 
float 3.000000e+00]
+
+// Large trailing zeros (>= 8) triggers struct packing in emitArrayConstant.
+int arr6[20] = {1, 2, 3};
+// CIR: cir.global external @arr6 = #cir.const_record<{#cir.int<1> : !s32i, 
#cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.zero : !cir.array<!s32i x 17>}>
+// LLVM: @arr6 = global <{ i32, i32, i32, [17 x i32] }> <{ i32 1, i32 2, i32 
3, [17 x i32] zeroinitializer }>
+// OGCG: @arr6 = global <{ i32, i32, i32, [17 x i32] }> <{ i32 1, i32 2, i32 
3, [17 x i32] zeroinitializer }>
+
+// Char array from string literal.
+char str[] = "hello";
+// CIR: cir.global external @str = #cir.const_array<"hello" : !cir.array<!s8i 
x 5>, trailing_zeros> : !cir.array<!s8i x 6>
+// LLVM: @str = global [6 x i8] c"hello\00"
+// OGCG: @str = global [6 x i8] c"hello\00"

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to