[clang] [CIR] Implement variable size array cleanup (PR #191247)
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)
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)
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)
@@ -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)
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)
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)
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
