https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/159820

>From 74e5b0e06a04db341038ecbba4081f4719b04592 Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhaf...@nvidia.com>
Date: Fri, 19 Sep 2025 19:25:27 +0200
Subject: [PATCH 1/3] [CIR] Fix structors for multidimensional arrrays

This patchs implements array constructors and destructors for multidimensional 
arrays. This works by bitcasting the pointer to the first element to a 
one-dimensional array type of the same extent before lowering to a loop.
---
 clang/lib/CIR/CodeGen/CIRGenClass.cpp | 14 ++++--
 clang/lib/CIR/CodeGen/CIRGenDecl.cpp  | 26 ++++++++--
 clang/test/CIR/CodeGen/array-ctor.cpp | 69 ++++++++++++++++++++++++++
 clang/test/CIR/CodeGen/array-dtor.cpp | 71 +++++++++++++++++++++++++++
 4 files changed, 171 insertions(+), 9 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp 
b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index 0a8dc2b62fe21..be416f6f69eb0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -639,12 +639,22 @@ void CIRGenFunction::emitCXXAggrConstructorCall(
   // are probably legitimate places where we could assume that this
   // doesn't happen, but it's not clear that it's worth it.
 
+  auto arrayTy = mlir::cast<cir::ArrayType>(arrayBase.getElementType());
+  mlir::Type elementType = arrayTy.getElementType();
+
+  // This might be a multi-dimensional array. Find the innermost element type.
+  while(auto maybeArrayTy = mlir::dyn_cast<cir::ArrayType>(elementType))
+    elementType = maybeArrayTy.getElementType();
+  cir::PointerType ptrToElmType = builder.getPointerTo(elementType);
+
   // Optimize for a constant count.
   if (auto constantCount = numElements.getDefiningOp<cir::ConstantOp>()) {
     if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>()) {
       // Just skip out if the constant count is zero.
       if (constIntAttr.getUInt() == 0)
         return;
+
+      arrayTy = cir::ArrayType::get(elementType, constIntAttr.getUInt());
       // Otherwise, emit the check.
     }
 
@@ -655,10 +665,6 @@ void CIRGenFunction::emitCXXAggrConstructorCall(
     cgm.errorNYI(e->getSourceRange(), "dynamic-length array expression");
   }
 
-  auto arrayTy = mlir::cast<cir::ArrayType>(arrayBase.getElementType());
-  mlir::Type elementType = arrayTy.getElementType();
-  cir::PointerType ptrToElmType = builder.getPointerTo(elementType);
-
   // Tradional LLVM codegen emits a loop here. CIR lowers to a loop as part of
   // LoweringPrepare.
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index d028a98eaad02..65e3e71ad9852 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -713,10 +713,11 @@ void CIRGenFunction::pushDestroy(CleanupKind cleanupKind, 
Address addr,
 /// The array cannot be zero-length.
 ///
 /// \param begin - a type* denoting the first element of the array
-/// \param end - a type* denoting one past the end of the array
+/// \param numElements - the number of elements in the array
 /// \param elementType - the element type of the array
 /// \param destroyer - the function to call to destroy elements
-void CIRGenFunction::emitArrayDestroy(mlir::Value begin, mlir::Value end,
+void CIRGenFunction::emitArrayDestroy(mlir::Value begin,
+                                      mlir::Value numElements,
                                       QualType elementType,
                                       CharUnits elementAlign,
                                       Destroyer *destroyer) {
@@ -727,9 +728,25 @@ void CIRGenFunction::emitArrayDestroy(mlir::Value begin, 
mlir::Value end,
   mlir::Type cirElementType = convertTypeForMem(elementType);
   cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
 
+  uint64_t size = 0;
+
+  // Optimize for a constant array size.
+  if (auto constantCount = numElements.getDefiningOp<cir::ConstantOp>()) {
+    if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>()) {
+      size = constIntAttr.getUInt();
+    }
+  } else {
+    cgm.errorNYI(begin.getDefiningOp()->getLoc(),
+                 "dynamic-length array expression");
+  }
+
+  auto arrayTy = cir::ArrayType::get(cirElementType, size);
+  mlir::Value arrayOp = builder.createPtrBitcast(begin, arrayTy);
+
   // Emit the dtor call that will execute for every array element.
   cir::ArrayDtor::create(
-      builder, *currSrcLoc, begin, [&](mlir::OpBuilder &b, mlir::Location loc) 
{
+      builder, *currSrcLoc, arrayOp,
+      [&](mlir::OpBuilder &b, mlir::Location loc) {
         auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
         Address curAddr = Address(arg, cirElementType, elementAlign);
         assert(!cir::MissingFeatures::dtorCleanups());
@@ -772,8 +789,7 @@ void CIRGenFunction::emitDestroy(Address addr, QualType 
type,
     return;
 
   mlir::Value begin = addr.getPointer();
-  mlir::Value end; // This will be used for future non-constant counts.
-  emitArrayDestroy(begin, end, type, elementAlign, destroyer);
+  emitArrayDestroy(begin, length, type, elementAlign, destroyer);
 
   // If the array destroy didn't use the length op, we can erase it.
   if (constantCount.use_empty())
diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp 
b/clang/test/CIR/CodeGen/array-ctor.cpp
index c373acf0bff8c..bad4868ed8c34 100644
--- a/clang/test/CIR/CodeGen/array-ctor.cpp
+++ b/clang/test/CIR/CodeGen/array-ctor.cpp
@@ -104,3 +104,72 @@ void zero_sized() {
 // OGCG:       alloca [0 x %struct.S]
 // OGCG-NOT:   call void @_ZN1SC1Ev
 // OGCG:       ret void
+
+void multi_dimensional() {
+    S s[3][5];
+}
+
+// CIR-BEFORE-LPP:     cir.func{{.*}} @_Z17multi_dimensionalv()
+// CIR-BEFORE-LPP:       %[[S:.*]] = cir.alloca !cir.array<!cir.array<!rec_S x 
5> x 3>, !cir.ptr<!cir.array<!cir.array<!rec_S x 5> x 3>>, ["s", init]
+// CIR-BEFORE-LPP:       %[[FLAT:.*]] = cir.cast(bitcast, %[[S]] : 
!cir.ptr<!cir.array<!cir.array<!rec_S x 5> x 3>>), !cir.ptr<!cir.array<!rec_S x 
15>>
+// CIR-BEFORE-LPP:       cir.array.ctor %[[FLAT]] : !cir.ptr<!cir.array<!rec_S 
x 15>> {
+// CIR-BEFORE-LPP:        ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_S>):
+// CIR-BEFORE-LPP:          cir.call @_ZN1SC1Ev(%[[ARG]]) : (!cir.ptr<!rec_S>) 
-> ()
+// CIR-BEFORE-LPP:          cir.yield
+// CIR-BEFORE-LPP:       }
+// CIR-BEFORE-LPP:       cir.return
+
+// CIR:     cir.func{{.*}} @_Z17multi_dimensionalv()
+// CIR:       %[[S:.*]] = cir.alloca !cir.array<!cir.array<!rec_S x 5> x 3>, 
!cir.ptr<!cir.array<!cir.array<!rec_S x 5> x 3>>, ["s", init]
+// CIR:       %[[CONST15:.*]] = cir.const #cir.int<15> : !u64i
+// CIR:       %[[DECAY:.*]] = cir.cast(array_to_ptrdecay, {{.*}} : 
!cir.ptr<!cir.array<!rec_S x 15>>), !cir.ptr<!rec_S>
+// CIR:       %[[END_PTR:.*]] = cir.ptr_stride(%[[DECAY]] : !cir.ptr<!rec_S>, 
%[[CONST15]] : !u64i), !cir.ptr<!rec_S>
+// CIR:       %[[ITER:.*]] = cir.alloca !cir.ptr<!rec_S>, 
!cir.ptr<!cir.ptr<!rec_S>>, ["__array_idx"]
+// CIR:       cir.store %[[DECAY]], %[[ITER]] : !cir.ptr<!rec_S>, 
!cir.ptr<!cir.ptr<!rec_S>>
+// CIR:       cir.do {
+// CIR:         %[[CURRENT:.*]] = cir.load %[[ITER]] : 
!cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR:         cir.call @_ZN1SC1Ev(%[[CURRENT]]) : (!cir.ptr<!rec_S>) -> ()
+// CIR:         %[[CONST1:.*]] = cir.const #cir.int<1> : !u64i
+// CIR:         %[[NEXT:.*]] = cir.ptr_stride(%[[CURRENT]] : !cir.ptr<!rec_S>, 
%[[CONST1]] : !u64i), !cir.ptr<!rec_S>
+// CIR:         cir.store %[[NEXT]], %[[ITER]] : !cir.ptr<!rec_S>, 
!cir.ptr<!cir.ptr<!rec_S>>
+// CIR:         cir.yield
+// CIR:       } while {
+// CIR:         %[[CURRENT2:.*]] = cir.load %[[ITER]] : 
!cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR:         %[[CMP:.*]] = cir.cmp(ne, %[[CURRENT2]], %[[END_PTR]]) : 
!cir.ptr<!rec_S>, !cir.bool
+// CIR:         cir.condition(%[[CMP]])
+// CIR:       }
+// CIR:       cir.return
+
+// LLVM:     define{{.*}} @_Z17multi_dimensionalv()
+// LLVM:       %[[S:.*]] = alloca [3 x [5 x %struct.S]]
+// LLVM:       %[[START:.*]] = getelementptr %struct.S, ptr %[[S]], i32 0
+// LLVM:       %[[END:.*]] = getelementptr %struct.S, ptr %[[START]], i64 15
+// LLVM:       %[[ITER:.*]] = alloca ptr
+// LLVM:       store ptr %[[START]], ptr %[[ITER]]
+// LLVM:       br label %[[LOOP:.*]]
+// LLVM:     [[COND:.*]]:
+// LLVM:       %[[CURRENT_CHECK:.*]] = load ptr, ptr %[[ITER]]
+// LLVM:       %[[DONE:.*]] = icmp ne ptr %[[CURRENT_CHECK]], %[[END]]
+// LLVM:       br i1 %[[DONE]], label %[[LOOP]], label %[[EXIT:.*]]
+// LLVM:     [[LOOP]]:
+// LLVM:       %[[CURRENT:.*]] = load ptr, ptr %[[ITER]]
+// LLVM:       call void @_ZN1SC1Ev(ptr %[[CURRENT]])
+// LLVM:       %[[NEXT:.*]] = getelementptr %struct.S, ptr %[[CURRENT]], i64 1
+// LLVM:       store ptr %[[NEXT]], ptr %[[ITER]]
+// LLVM:       br label %[[COND]]
+// LLVM:     [[EXIT]]:
+// LLVM:       ret void
+
+// OGCG:     define{{.*}} @_Z17multi_dimensionalv()
+// OGCG:       %[[S:.*]] = alloca [3 x [5 x %struct.S]]
+// OGCG:       %[[START:.*]] = getelementptr{{.*}} %struct.S{{.*}}
+// OGCG:       %[[END:.*]] = getelementptr{{.*}} %struct.S{{.*}} i64 15
+// OGCG:       br label %[[LOOP:.*]]
+// OGCG:     [[LOOP]]:
+// OGCG:       %[[CURRENT:.*]] = phi ptr [ %[[START]], %{{.*}} ], [ 
%[[NEXT:.*]], %[[LOOP]] ]
+// OGCG:       call void @_ZN1SC1Ev(ptr{{.*}})
+// OGCG:       %[[NEXT]] = getelementptr{{.*}} %struct.S{{.*}} i64 1
+// OGCG:       %[[DONE:.*]] = icmp eq ptr %[[NEXT]], %[[END]]
+// OGCG:       br i1 %[[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
+// OGCG:     [[EXIT]]:
+// OGCG:       ret void
diff --git a/clang/test/CIR/CodeGen/array-dtor.cpp 
b/clang/test/CIR/CodeGen/array-dtor.cpp
index 3edc6f1a6538d..36db265a6dfed 100644
--- a/clang/test/CIR/CodeGen/array-dtor.cpp
+++ b/clang/test/CIR/CodeGen/array-dtor.cpp
@@ -102,3 +102,74 @@ void test_cleanup_zero_length_array() {
 // OGCG:       alloca [0 x %struct.S]
 // OGCG-NOT:   call void @_ZN1SD1Ev
 // OGCG:       ret void
+
+void multi_dimensional() {
+    S s[3][5];
+}
+
+// CIR-BEFORE-LPP:     cir.func{{.*}} @_Z17multi_dimensionalv()
+// CIR-BEFORE-LPP:       %[[S:.*]] = cir.alloca !cir.array<!cir.array<!rec_S x 
5> x 3>, !cir.ptr<!cir.array<!cir.array<!rec_S x 5> x 3>>, ["s"]
+// CIR-BEFORE-LPP:       %[[FLAT:.*]] = cir.cast(bitcast, %[[S]] : 
!cir.ptr<!cir.array<!cir.array<!rec_S x 5> x 3>>), !cir.ptr<!cir.array<!rec_S x 
15>>
+// CIR-BEFORE-LPP:       cir.array.dtor %[[FLAT]] : !cir.ptr<!cir.array<!rec_S 
x 15>> {
+// CIR-BEFORE-LPP:       ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_S>):
+// CIR-BEFORE-LPP:         cir.call @_ZN1SD1Ev(%[[ARG]]) nothrow : 
(!cir.ptr<!rec_S>) -> ()
+// CIR-BEFORE-LPP:         cir.yield
+// CIR-BEFORE-LPP:       }
+// CIR-BEFORE-LPP:       cir.return
+
+// CIR:     cir.func{{.*}} @_Z17multi_dimensionalv()
+// CIR:       %[[S:.*]] = cir.alloca !cir.array<!cir.array<!rec_S x 5> x 3>, 
!cir.ptr<!cir.array<!cir.array<!rec_S x 5> x 3>>, ["s"]
+// CIR:       %[[FLAT:.*]] = cir.cast(bitcast, %[[S]] : 
!cir.ptr<!cir.array<!cir.array<!rec_S x 5> x 3>>), !cir.ptr<!cir.array<!rec_S x 
15>>
+// CIR:       %[[CONST14:.*]] = cir.const #cir.int<14> : !u64i
+// CIR:       %[[DECAY:.*]] = cir.cast(array_to_ptrdecay, %[[FLAT]] : 
!cir.ptr<!cir.array<!rec_S x 15>>), !cir.ptr<!rec_S>
+// CIR:       %[[END_PTR:.*]] = cir.ptr_stride(%[[DECAY]] : !cir.ptr<!rec_S>, 
%[[CONST14]] : !u64i), !cir.ptr<!rec_S>
+// CIR:       %[[ITER:.*]] = cir.alloca !cir.ptr<!rec_S>, 
!cir.ptr<!cir.ptr<!rec_S>>, ["__array_idx"]
+// CIR:       cir.store %[[END_PTR]], %[[ITER]] : !cir.ptr<!rec_S>, 
!cir.ptr<!cir.ptr<!rec_S>>
+// CIR:       cir.do {
+// CIR:         %[[CUR:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, 
!cir.ptr<!rec_S>
+// CIR:         cir.call @_ZN1SD1Ev(%[[CUR]]) nothrow : (!cir.ptr<!rec_S>) -> 
()
+// CIR:         %[[NEG1:.*]] = cir.const #cir.int<-1> : !s64i
+// CIR:         %[[PREV:.*]] = cir.ptr_stride(%[[CUR]] : !cir.ptr<!rec_S>, 
%[[NEG1]] : !s64i), !cir.ptr<!rec_S>
+// CIR:         cir.store %[[PREV]], %[[ITER]] : !cir.ptr<!rec_S>, 
!cir.ptr<!cir.ptr<!rec_S>>
+// CIR:         cir.yield
+// CIR:       } while {
+// CIR:         %[[CHK:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, 
!cir.ptr<!rec_S>
+// CIR:         %[[CMP:.*]] = cir.cmp(ne, %[[CHK]], %[[DECAY]])
+// CIR:         cir.condition(%[[CMP]])
+// CIR:       }
+// CIR:       cir.return
+
+// LLVM:     define{{.*}} void @_Z17multi_dimensionalv()
+// LLVM:       %[[S:.*]] = alloca [3 x [5 x %struct.S]]
+// LLVM:       %[[START:.*]] = getelementptr %struct.S, ptr %[[S]], i32 0
+// LLVM:       %[[END:.*]] = getelementptr %struct.S, ptr %[[START]], i64 14
+// LLVM:       %[[ITER:.*]] = alloca ptr
+// LLVM:       store ptr %[[END]], ptr %[[ITER]]
+// LLVM:       br label %[[LOOP:.*]]
+// LLVM: [[COND:.*]]:
+// LLVM:       %[[CURRENT_CHECK:.*]] = load ptr, ptr %[[ITER]]
+// LLVM:       %[[DONE:.*]] = icmp ne ptr %[[CURRENT_CHECK]], %[[START]]
+// LLVM:       br i1 %[[DONE]], label %[[LOOP]], label %[[EXIT:.*]]
+// LLVM: [[LOOP]]:
+// LLVM:       %[[CUR:.*]] = load ptr, ptr %[[ITER]]
+// LLVM:       call void @_ZN1SD1Ev(ptr %[[CUR]])
+// LLVM:       %[[PREV:.*]] = getelementptr %struct.S, ptr %[[CUR]], i64 -1
+// LLVM:       store ptr %[[PREV]], ptr %[[ITER]]
+// LLVM:       br label %[[COND]]
+// LLVM: [[EXIT]]:
+// LLVM:       ret void
+
+// OGCG:     define{{.*}} void @_Z17multi_dimensionalv()
+// OGCG:       %[[ARRAY:.*]] = alloca [3 x [5 x %struct.S]]
+// OGCG:       %[[START:.*]] = getelementptr{{.*}} %struct.S{{.*}}
+// OGCG:       %[[END:.*]] = getelementptr{{.*}} %struct.S{{.*}} i64 15
+// OGCG:       br label %[[LOOP:.*]]
+// OGCG: [[LOOP]]:
+// OGCG:       %[[NEXT:.*]] = phi ptr [ %[[END]], %{{.*}} ], [ %[[LAST:.*]], 
%[[LOOP]] ]
+// OGCG:       %[[LAST]] = getelementptr{{.*}} %struct.S{{.*}}, ptr %[[NEXT]], 
i64 -1
+// OGCG:       call void @_ZN1SD1Ev(ptr{{.*}} %[[LAST]])
+// OGCG:       %[[DONE:.*]] = icmp eq ptr %[[LAST]], %[[START]]
+// OGCG:       br i1 %[[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
+// OGCG: [[EXIT]]:
+// OGCG:       ret void
+

>From 37c6d42c9ec1e3c1d43fe4f0b25d1949027bc59c Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhaf...@nvidia.com>
Date: Fri, 19 Sep 2025 19:32:34 +0200
Subject: [PATCH 2/3] clang-format

---
 clang/lib/CIR/CodeGen/CIRGenClass.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp 
b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index be416f6f69eb0..1a557beb610ea 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -643,7 +643,7 @@ void CIRGenFunction::emitCXXAggrConstructorCall(
   mlir::Type elementType = arrayTy.getElementType();
 
   // This might be a multi-dimensional array. Find the innermost element type.
-  while(auto maybeArrayTy = mlir::dyn_cast<cir::ArrayType>(elementType))
+  while (auto maybeArrayTy = mlir::dyn_cast<cir::ArrayType>(elementType))
     elementType = maybeArrayTy.getElementType();
   cir::PointerType ptrToElmType = builder.getPointerTo(elementType);
 

>From c1587593c47cf6f6038ae29d30aa91c1764152be Mon Sep 17 00:00:00 2001
From: Morris Hafner <mhaf...@nvidia.com>
Date: Fri, 19 Sep 2025 23:03:16 +0200
Subject: [PATCH 3/3] remove braces

---
 clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index 65e3e71ad9852..2f221b9dd26a5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -732,9 +732,8 @@ void CIRGenFunction::emitArrayDestroy(mlir::Value begin,
 
   // Optimize for a constant array size.
   if (auto constantCount = numElements.getDefiningOp<cir::ConstantOp>()) {
-    if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>()) {
+    if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>())
       size = constIntAttr.getUInt();
-    }
   } else {
     cgm.errorNYI(begin.getDefiningOp()->getLoc(),
                  "dynamic-length array expression");

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to