[clang] [CIR] Implement variable size array cleanup (PR #191247)

2026-04-09 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor closed 
https://github.com/llvm/llvm-project/pull/191247
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Implement variable size array cleanup (PR #191247)

2026-04-09 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor updated 
https://github.com/llvm/llvm-project/pull/191247

>From 7a361f7ef26da96e8efd3ec0ac6005e89dcc3df7 Mon Sep 17 00:00:00 2001
From: Andy Kaylor 
Date: Wed, 1 Apr 2026 16:36:25 -0700
Subject: [PATCH 1/2] [CIR] Implement variable size array cleanup

This implements partial array destruction for variable sized arrays.

Assisted-by: Cursor / claude-4.6-opus-high
---
 clang/lib/CIR/CodeGen/CIRGenDecl.cpp  |  59 +--
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp  |  38 +-
 .../Dialect/Transforms/LoweringPrepare.cpp|   2 -
 .../CIR/CodeGen/partial-array-cleanup.cpp | 499 ++
 4 files changed, 560 insertions(+), 38 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index c3c0ec1c1af0d..e8b66280a5ab2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -1039,7 +1039,7 @@ void CIRGenFunction::pushLifetimeExtendedCleanupToEHStack(
 }
 
 /// Destroys all the elements of the given array, beginning from last to first.
-/// The array cannot be zero-length.
+/// The array cannot be zero-length if its length is constant.
 ///
 /// \param begin - a type* denoting the first element of the array
 /// \param numElements - the number of elements in the array
@@ -1057,33 +1057,32 @@ void CIRGenFunction::emitArrayDestroy(mlir::Value begin,
   mlir::Type cirElementType = convertTypeForMem(elementType);
   cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
 
-  uint64_t size = 0;
+  auto regionBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
+auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
+Address curAddr = Address(arg, cirElementType, elementAlign);
+assert(!cir::MissingFeatures::dtorCleanups());
 
-  // Optimize for a constant array size.
+// Perform the actual destruction there.
+destroyer(*this, curAddr, elementType);
+
+cir::YieldOp::create(b, loc);
+  };
+
+  // For a constant array size, use the static form of ArrayDtor.
   if (auto constantCount = numElements.getDefiningOp()) {
+uint64_t size = 0;
 if (auto constIntAttr = constantCount.getValueAttr())
   size = constIntAttr.getUInt();
-  } else {
-cgm.errorNYI(begin.getDefiningOp()->getLoc(),
- "emitArrayDestroy: dynamic-length array expression");
+auto arrayTy = cir::ArrayType::get(cirElementType, size);
+mlir::Value arrayOp = builder.createPtrBitcast(begin, arrayTy);
+cir::ArrayDtor::create(builder, *currSrcLoc, arrayOp, regionBuilder);
+return;
   }
 
-  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, arrayOp,
-  [&](mlir::OpBuilder &b, mlir::Location loc) {
-auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
-Address curAddr = Address(arg, cirElementType, elementAlign);
-assert(!cir::MissingFeatures::dtorCleanups());
-
-// Perform the actual destruction there.
-destroyer(*this, curAddr, elementType);
-
-cir::YieldOp::create(builder, loc);
-  });
+  // For a dynamic array size (VLA), use the dynamic form of ArrayDtor.
+  mlir::Value elemBegin = builder.createPtrBitcast(begin, cirElementType);
+  cir::ArrayDtor::create(builder, *currSrcLoc, elemBegin, numElements,
+ regionBuilder);
 }
 
 /// Immediately perform the destruction of the given object.
@@ -1104,24 +1103,20 @@ void CIRGenFunction::emitDestroy(Address addr, QualType 
type,
   CharUnits elementAlign = addr.getAlignment().alignmentOfArrayElement(
   getContext().getTypeSizeInChars(type));
 
+  // If the array length is constant, we can check for zero at compile time.
   auto constantCount = length.getDefiningOp();
-  if (!constantCount) {
-assert(!cir::MissingFeatures::vlas());
-cgm.errorNYI("emitDestroy: variable length array");
-return;
+  if (constantCount) {
+auto constIntAttr = mlir::dyn_cast(constantCount.getValue());
+if (constIntAttr && constIntAttr.getUInt() == 0)
+  return;
   }
 
-  auto constIntAttr = mlir::dyn_cast(constantCount.getValue());
-  // If it's constant zero, we can just skip the entire thing.
-  if (constIntAttr && constIntAttr.getUInt() == 0)
-return;
-
   mlir::Value begin = addr.getPointer();
   assert(!cir::MissingFeatures::useEHCleanupForArray());
   emitArrayDestroy(begin, length, type, elementAlign, destroyer);
 
   // If the array destroy didn't use the length op, we can erase it.
-  if (constantCount.use_empty())
+  if (constantCount && constantCount.use_empty())
 constantCount.erase();
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 572addda77cec..f7f9331060956 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ 

[clang] [CIR] Implement variable size array cleanup (PR #191247)

2026-04-09 Thread Amr Hesham via cfe-commits

https://github.com/AmrDeveloper edited 
https://github.com/llvm/llvm-project/pull/191247
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Implement variable size array cleanup (PR #191247)

2026-04-09 Thread Amr Hesham via cfe-commits


@@ -1057,33 +1057,32 @@ void CIRGenFunction::emitArrayDestroy(mlir::Value begin,
   mlir::Type cirElementType = convertTypeForMem(elementType);
   cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
 
-  uint64_t size = 0;
+  auto regionBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
+auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);

AmrDeveloper wrote:

```suggestion
mlir::BlockArgument arg = b.getInsertionBlock()->addArgument(ptrToElmType, 
loc);
```

https://github.com/llvm/llvm-project/pull/191247
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Implement variable size array cleanup (PR #191247)

2026-04-09 Thread Amr Hesham via cfe-commits

https://github.com/AmrDeveloper approved this pull request.

LGTM % nit

https://github.com/llvm/llvm-project/pull/191247
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR] Implement variable size array cleanup (PR #191247)

2026-04-09 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Andy Kaylor (andykaylor)


Changes

This implements partial array destruction for variable sized arrays. The 
cir.array.dtor operation already had support for variable length, so this 
change only needs to add the variable handling in `emitArrayDestroy` and 
`emitArrayLength`.

Assisted-by: Cursor / claude-4.6-opus-high

---

Patch is 32.29 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/191247.diff


4 Files Affected:

- (modified) clang/lib/CIR/CodeGen/CIRGenDecl.cpp (+27-32) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.cpp (+34-4) 
- (modified) clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp (-2) 
- (modified) clang/test/CIR/CodeGen/partial-array-cleanup.cpp (+499) 


``diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index c3c0ec1c1af0d..e8b66280a5ab2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -1039,7 +1039,7 @@ void CIRGenFunction::pushLifetimeExtendedCleanupToEHStack(
 }
 
 /// Destroys all the elements of the given array, beginning from last to first.
-/// The array cannot be zero-length.
+/// The array cannot be zero-length if its length is constant.
 ///
 /// \param begin - a type* denoting the first element of the array
 /// \param numElements - the number of elements in the array
@@ -1057,33 +1057,32 @@ void CIRGenFunction::emitArrayDestroy(mlir::Value begin,
   mlir::Type cirElementType = convertTypeForMem(elementType);
   cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
 
-  uint64_t size = 0;
+  auto regionBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
+auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
+Address curAddr = Address(arg, cirElementType, elementAlign);
+assert(!cir::MissingFeatures::dtorCleanups());
 
-  // Optimize for a constant array size.
+// Perform the actual destruction there.
+destroyer(*this, curAddr, elementType);
+
+cir::YieldOp::create(b, loc);
+  };
+
+  // For a constant array size, use the static form of ArrayDtor.
   if (auto constantCount = numElements.getDefiningOp()) {
+uint64_t size = 0;
 if (auto constIntAttr = constantCount.getValueAttr())
   size = constIntAttr.getUInt();
-  } else {
-cgm.errorNYI(begin.getDefiningOp()->getLoc(),
- "emitArrayDestroy: dynamic-length array expression");
+auto arrayTy = cir::ArrayType::get(cirElementType, size);
+mlir::Value arrayOp = builder.createPtrBitcast(begin, arrayTy);
+cir::ArrayDtor::create(builder, *currSrcLoc, arrayOp, regionBuilder);
+return;
   }
 
-  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, arrayOp,
-  [&](mlir::OpBuilder &b, mlir::Location loc) {
-auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
-Address curAddr = Address(arg, cirElementType, elementAlign);
-assert(!cir::MissingFeatures::dtorCleanups());
-
-// Perform the actual destruction there.
-destroyer(*this, curAddr, elementType);
-
-cir::YieldOp::create(builder, loc);
-  });
+  // For a dynamic array size (VLA), use the dynamic form of ArrayDtor.
+  mlir::Value elemBegin = builder.createPtrBitcast(begin, cirElementType);
+  cir::ArrayDtor::create(builder, *currSrcLoc, elemBegin, numElements,
+ regionBuilder);
 }
 
 /// Immediately perform the destruction of the given object.
@@ -1104,24 +1103,20 @@ void CIRGenFunction::emitDestroy(Address addr, QualType 
type,
   CharUnits elementAlign = addr.getAlignment().alignmentOfArrayElement(
   getContext().getTypeSizeInChars(type));
 
+  // If the array length is constant, we can check for zero at compile time.
   auto constantCount = length.getDefiningOp();
-  if (!constantCount) {
-assert(!cir::MissingFeatures::vlas());
-cgm.errorNYI("emitDestroy: variable length array");
-return;
+  if (constantCount) {
+auto constIntAttr = mlir::dyn_cast(constantCount.getValue());
+if (constIntAttr && constIntAttr.getUInt() == 0)
+  return;
   }
 
-  auto constIntAttr = mlir::dyn_cast(constantCount.getValue());
-  // If it's constant zero, we can just skip the entire thing.
-  if (constIntAttr && constIntAttr.getUInt() == 0)
-return;
-
   mlir::Value begin = addr.getPointer();
   assert(!cir::MissingFeatures::useEHCleanupForArray());
   emitArrayDestroy(begin, length, type, elementAlign, destroyer);
 
   // If the array destroy didn't use the length op, we can erase it.
-  if (constantCount.use_empty())
+  if (constantCount && constantCount.use_empty())
 constantCount.erase();
 }
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/C

[clang] [CIR] Implement variable size array cleanup (PR #191247)

2026-04-09 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor created 
https://github.com/llvm/llvm-project/pull/191247

This implements partial array destruction for variable sized arrays. The 
cir.array.dtor operation already had support for variable length, so this 
change only needs to add the variable handling in `emitArrayDestroy` and 
`emitArrayLength`.

Assisted-by: Cursor / claude-4.6-opus-high

>From 7a361f7ef26da96e8efd3ec0ac6005e89dcc3df7 Mon Sep 17 00:00:00 2001
From: Andy Kaylor 
Date: Wed, 1 Apr 2026 16:36:25 -0700
Subject: [PATCH] [CIR] Implement variable size array cleanup

This implements partial array destruction for variable sized arrays.

Assisted-by: Cursor / claude-4.6-opus-high
---
 clang/lib/CIR/CodeGen/CIRGenDecl.cpp  |  59 +--
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp  |  38 +-
 .../Dialect/Transforms/LoweringPrepare.cpp|   2 -
 .../CIR/CodeGen/partial-array-cleanup.cpp | 499 ++
 4 files changed, 560 insertions(+), 38 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index c3c0ec1c1af0d..e8b66280a5ab2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -1039,7 +1039,7 @@ void CIRGenFunction::pushLifetimeExtendedCleanupToEHStack(
 }
 
 /// Destroys all the elements of the given array, beginning from last to first.
-/// The array cannot be zero-length.
+/// The array cannot be zero-length if its length is constant.
 ///
 /// \param begin - a type* denoting the first element of the array
 /// \param numElements - the number of elements in the array
@@ -1057,33 +1057,32 @@ void CIRGenFunction::emitArrayDestroy(mlir::Value begin,
   mlir::Type cirElementType = convertTypeForMem(elementType);
   cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
 
-  uint64_t size = 0;
+  auto regionBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
+auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
+Address curAddr = Address(arg, cirElementType, elementAlign);
+assert(!cir::MissingFeatures::dtorCleanups());
 
-  // Optimize for a constant array size.
+// Perform the actual destruction there.
+destroyer(*this, curAddr, elementType);
+
+cir::YieldOp::create(b, loc);
+  };
+
+  // For a constant array size, use the static form of ArrayDtor.
   if (auto constantCount = numElements.getDefiningOp()) {
+uint64_t size = 0;
 if (auto constIntAttr = constantCount.getValueAttr())
   size = constIntAttr.getUInt();
-  } else {
-cgm.errorNYI(begin.getDefiningOp()->getLoc(),
- "emitArrayDestroy: dynamic-length array expression");
+auto arrayTy = cir::ArrayType::get(cirElementType, size);
+mlir::Value arrayOp = builder.createPtrBitcast(begin, arrayTy);
+cir::ArrayDtor::create(builder, *currSrcLoc, arrayOp, regionBuilder);
+return;
   }
 
-  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, arrayOp,
-  [&](mlir::OpBuilder &b, mlir::Location loc) {
-auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc);
-Address curAddr = Address(arg, cirElementType, elementAlign);
-assert(!cir::MissingFeatures::dtorCleanups());
-
-// Perform the actual destruction there.
-destroyer(*this, curAddr, elementType);
-
-cir::YieldOp::create(builder, loc);
-  });
+  // For a dynamic array size (VLA), use the dynamic form of ArrayDtor.
+  mlir::Value elemBegin = builder.createPtrBitcast(begin, cirElementType);
+  cir::ArrayDtor::create(builder, *currSrcLoc, elemBegin, numElements,
+ regionBuilder);
 }
 
 /// Immediately perform the destruction of the given object.
@@ -1104,24 +1103,20 @@ void CIRGenFunction::emitDestroy(Address addr, QualType 
type,
   CharUnits elementAlign = addr.getAlignment().alignmentOfArrayElement(
   getContext().getTypeSizeInChars(type));
 
+  // If the array length is constant, we can check for zero at compile time.
   auto constantCount = length.getDefiningOp();
-  if (!constantCount) {
-assert(!cir::MissingFeatures::vlas());
-cgm.errorNYI("emitDestroy: variable length array");
-return;
+  if (constantCount) {
+auto constIntAttr = mlir::dyn_cast(constantCount.getValue());
+if (constIntAttr && constIntAttr.getUInt() == 0)
+  return;
   }
 
-  auto constIntAttr = mlir::dyn_cast(constantCount.getValue());
-  // If it's constant zero, we can just skip the entire thing.
-  if (constIntAttr && constIntAttr.getUInt() == 0)
-return;
-
   mlir::Value begin = addr.getPointer();
   assert(!cir::MissingFeatures::useEHCleanupForArray());
   emitArrayDestroy(begin, length, type, elementAlign, destroyer);
 
   // If the array destroy didn't use the length op, we can erase it.
-  if (constantCount.use_e