[clang] [CIR] Add support for variable sized array new. (PR #190656)
https://github.com/erichkeane approved this pull request. https://github.com/llvm/llvm-project/pull/190656 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
https://github.com/andykaylor closed https://github.com/llvm/llvm-project/pull/190656 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
@@ -735,31 +735,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(arrayBase.getElementType());
- mlir::Type elementType = arrayTy.getElementType();
-
- // This might be a multi-dimensional array. Find the innermost element type.
+ // Peel any array types wrapped in the address element type down to the CIR
+ // type of a single constructed object.
+ mlir::Type elementType = arrayBase.getElementType();
while (auto maybeArrayTy = mlir::dyn_cast(elementType))
elementType = maybeArrayTy.getElementType();
cir::PointerType ptrToElmType = builder.getPointerTo(elementType);
- // Optimize for a constant count.
- if (auto constantCount = numElements.getDefiningOp()) {
-if (auto constIntAttr = constantCount.getValueAttr()) {
- // 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.
-}
-
-if (constantCount.use_empty())
- constantCount.erase();
- } else {
-// Otherwise, emit the check.
-cgm.errorNYI(e->getSourceRange(),
- "emitCXXAggrConstructorCall: dynamic-length array
expression");
+ bool useDynamicArrayCtor = true;
+ uint64_t constElementCount = 0;
+ if (auto constantOp = numElements.getDefiningOp()) {
+constElementCount = CIRGenFunction::getZExtIntValueFromConstOp(constantOp);
+if (constElementCount == 0)
andykaylor wrote:
I don't believe classic codegen does any folding in this case:
```
struct S {
S();
};
void foo() {
int N = 5;
S *p = new S[N];
}
```
https://godbolt.org/z/5fz74bYGT
https://github.com/llvm/llvm-project/pull/190656
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
@@ -735,31 +735,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(arrayBase.getElementType());
- mlir::Type elementType = arrayTy.getElementType();
-
- // This might be a multi-dimensional array. Find the innermost element type.
+ // Peel any array types wrapped in the address element type down to the CIR
+ // type of a single constructed object.
+ mlir::Type elementType = arrayBase.getElementType();
while (auto maybeArrayTy = mlir::dyn_cast(elementType))
elementType = maybeArrayTy.getElementType();
cir::PointerType ptrToElmType = builder.getPointerTo(elementType);
- // Optimize for a constant count.
- if (auto constantCount = numElements.getDefiningOp()) {
-if (auto constIntAttr = constantCount.getValueAttr()) {
- // 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.
-}
-
-if (constantCount.use_empty())
- constantCount.erase();
- } else {
-// Otherwise, emit the check.
-cgm.errorNYI(e->getSourceRange(),
- "emitCXXAggrConstructorCall: dynamic-length array
expression");
+ bool useDynamicArrayCtor = true;
+ uint64_t constElementCount = 0;
+ if (auto constantOp = numElements.getDefiningOp()) {
+constElementCount = CIRGenFunction::getZExtIntValueFromConstOp(constantOp);
+if (constElementCount == 0)
erichkeane wrote:
Yes, sure. This is the sort of thing that classic-codegen sometimes does with
his normal "constant-folder" thing, so its a shame to lose. We should at
least at one point think about an opt pass to figure this stuff out.
https://github.com/llvm/llvm-project/pull/190656
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
https://github.com/AmrDeveloper approved this pull request. LGTM https://github.com/llvm/llvm-project/pull/190656 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
https://github.com/andykaylor updated
https://github.com/llvm/llvm-project/pull/190656
>From 03b66a546a12a5aec2c88fbce0ca6415a633b29b Mon Sep 17 00:00:00 2001
From: Andy Kaylor
Date: Thu, 19 Mar 2026 18:10:13 -0700
Subject: [PATCH 1/2] [CIR] Add support for variable sized array new.
This change adds support for array new with variable size. This required
extending the cir.array.ctor operation to accept a value for the size
and a direct pointer to the element size instead of a pointer to an array.
Assisted-by: Cursor / claude-4.6-opus-high
Assisted-by: Cursor / composer-2-fast
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 34 +++-
clang/lib/CIR/CodeGen/CIRGenClass.cpp | 94 +--
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 44 ++
.../Dialect/Transforms/LoweringPrepare.cpp| 24 ++-
clang/test/CIR/CodeGen/new.cpp| 146 ++
clang/test/CIR/IR/array-ctor.cir | 19 +++
clang/test/CIR/IR/invalid-array-structor.cir | 143 +
7 files changed, 452 insertions(+), 52 deletions(-)
create mode 100644 clang/test/CIR/IR/invalid-array-structor.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 04884beaa5685..74d79db5e11c6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4563,7 +4563,14 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
operation has one region, with one single block. The block has an
incoming argument for the current array element to initialize.
-Example:
+When `num_elements` is absent, `addr` must be a pointer to a fixed-size
+CIR array type and the element count is derived from that array type.
+
+When `num_elements` is present, `addr` is a pointer to the first element
+and `num_elements` provides the runtime element count (for example `new
+T[n]`).
+
+Examples:
```mlir
cir.array.ctor(%0 : !cir.ptr>) {
@@ -4571,19 +4578,28 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
cir.call @some_ctor(%arg0) : (!cir.ptr) -> ()
cir.yield
}
+
+cir.array.ctor(%ptr, %n : !cir.ptr, !u64i) {
+ ^bb0(%arg0: !cir.ptr):
+cir.call @some_ctor(%arg0) : (!cir.ptr) -> ()
+cir.yield
+}
```
}];
let arguments = (ins
-Arg:$addr
+Arg:$addr,
+Optional:$num_elements
);
let regions = (region SizedRegion<1>:$body);
let assemblyFormat = [{
-$addr `:` qualified(type($addr)) $body attr-dict
+$addr (`,` $num_elements^)? `:` qualified(type($addr))
+(`,` type($num_elements)^)? $body attr-dict
}];
let builders = [
+// Static form: addr is ptr>, no num_elements.
OpBuilder<(ins "mlir::Value":$addr,
"llvm::function_ref":$regionBuilder), [{
assert(regionBuilder && "builder callback expected");
@@ -4592,9 +4608,20 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
$_state.addOperands(ValueRange{addr});
$_builder.createBlock(r);
regionBuilder($_builder, $_state.location);
+}]>,
+// Dynamic form: addr is ptr, num_elements is the runtime count.
+OpBuilder<(ins "mlir::Value":$addr, "mlir::Value":$num_elements,
+ "llvm::function_ref":$regionBuilder), [{
+assert(regionBuilder && "builder callback expected");
+mlir::OpBuilder::InsertionGuard guard($_builder);
+mlir::Region *r = $_state.addRegion();
+$_state.addOperands({addr, num_elements});
+$_builder.createBlock(r);
+regionBuilder($_builder, $_state.location);
}]>
];
+ let hasVerifier = 1;
let hasLLVMLowering = false;
}
@@ -4668,6 +4695,7 @@ def CIR_ArrayDtor : CIR_Op<"array.dtor"> {
}]>
];
+ let hasVerifier = 1;
let hasLLVMLowering = false;
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index e54514950e00f..f8d65fa9a6d33 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -735,31 +735,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(arrayBase.getElementType());
- mlir::Type elementType = arrayTy.getElementType();
-
- // This might be a multi-dimensional array. Find the innermost element type.
+ // Peel any array types wrapped in the address element type down to the CIR
+ // type of a single constructed object.
+ mlir::Type elementType = arrayBase.getElementType();
while (auto maybeArrayTy = mlir::dyn_cast(elementType))
elementType = maybeArrayTy.getElementType();
cir::PointerType ptrToElmType = builder.getPointerTo(elementType);
- // Optimize for a constant count.
- if (auto constantCount = numElements.getDefiningOp()) {
-if (auto constIntAttr = constantCount.getValueAttr()) {
- // Just skip out if
[clang] [CIR] Add support for variable sized array new. (PR #190656)
@@ -735,31 +735,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(arrayBase.getElementType());
- mlir::Type elementType = arrayTy.getElementType();
-
- // This might be a multi-dimensional array. Find the innermost element type.
+ // Peel any array types wrapped in the address element type down to the CIR
+ // type of a single constructed object.
+ mlir::Type elementType = arrayBase.getElementType();
while (auto maybeArrayTy = mlir::dyn_cast(elementType))
elementType = maybeArrayTy.getElementType();
cir::PointerType ptrToElmType = builder.getPointerTo(elementType);
- // Optimize for a constant count.
- if (auto constantCount = numElements.getDefiningOp()) {
-if (auto constIntAttr = constantCount.getValueAttr()) {
- // 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.
-}
-
-if (constantCount.use_empty())
- constantCount.erase();
- } else {
-// Otherwise, emit the check.
-cgm.errorNYI(e->getSourceRange(),
- "emitCXXAggrConstructorCall: dynamic-length array
expression");
+ bool useDynamicArrayCtor = true;
+ uint64_t constElementCount = 0;
+ if (auto constantOp = numElements.getDefiningOp()) {
+constElementCount = CIRGenFunction::getZExtIntValueFromConstOp(constantOp);
+if (constElementCount == 0)
andykaylor wrote:
I guess this gets into the philosophical debate about how much optimization the
front end should do. If the folding is really trivial, we'll have done it
before we get here. For instance, the code below gets us here with a constant 4:
```
struct S {
S();
};
void foo() {
S *p = new S[2+2];
}
```
The case you mentioned with a temporary that has a single assigned value would
require some more extensive analysis.
https://github.com/llvm/llvm-project/pull/190656
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
@@ -4592,9 +4608,20 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
$_state.addOperands(ValueRange{addr});
$_builder.createBlock(r);
regionBuilder($_builder, $_state.location);
+}]>,
+// Dynamic form: addr is ptr, num_elements is the runtime count.
+OpBuilder<(ins "mlir::Value":$addr, "mlir::Value":$num_elements,
+ "llvm::function_ref":$regionBuilder), [{
+assert(regionBuilder && "builder callback expected");
andykaylor wrote:
I don't think we should attempt that level of constant folding in the front
end. We get the array length as an l-value. To constant fold it, we'd have to
look back at where it was written and infer the constant from that. That's kind
of trivial, but I don't see much value in it at this stage.
https://github.com/llvm/llvm-project/pull/190656
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
github-actions[bot] wrote: # :penguin: Linux x64 Test Results * 88458 tests passed * 775 tests skipped * 1 test failed ## Failed Tests (click on a test name to see its output) ### lldb-api lldb-api.python_api/run_locker/TestRunLocker.py ``` Script: -- /usr/bin/python3 /home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib --env LLVM_INCLUDE_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include --env LLVM_TOOLS_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin --libcxx-include-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/include/c++/v1 --libcxx-include-target-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/include/x86_64-unknown-linux-gnu/c++/v1 --libcxx-library-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib/x86_64-unknown-linux-gnu --arch x86_64 --build-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build.noindex --lldb-module-cache-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/lldb --compiler /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/clang --dsymutil /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin --lldb-obj-root /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/lldb --lldb-libs-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib --cmake-build-type Release /home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/python_api/run_locker -p TestRunLocker.py -- Exit Code: 1 Command Output (stdout): -- lldb version 23.0.0git (https://github.com/llvm/llvm-project revision 53bdc93afdf6f2c683a4a7e553fd5cb89108f404) clang revision 53bdc93afdf6f2c683a4a7e553fd5cb89108f404 llvm revision 53bdc93afdf6f2c683a4a7e553fd5cb89108f404 "can't evaluate expressions when the process is running." Skipping the following test categories: msvcstl, dsym, pdb, gmodules, debugserver, objc -- Command Output (stderr): -- Traceback (most recent call last): File "", line 1, in AttributeError: 'NoneType' object has no attribute 'EvaluateExpression' FAIL: LLDB (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-x86_64) :: test_run_locker (TestRunLocker.TestRunLocker.test_run_locker) Log Files: - /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build.noindex/python_api/run_locker/TestRunLocker/Failure_test_run_locker.log PASS: LLDB (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-x86_64) :: test_run_locker_stop_at_entry (TestRunLocker.TestRunLocker.test_run_locker_stop_at_entry) == FAIL: test_run_locker (TestRunLocker.TestRunLocker.test_run_locker) Test that the run locker is set correctly when we launch -- Traceback (most recent call last): File "/home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/packages/Python/lldbsuite/test/decorators.py", line 160, in wrapper return func(*args, **kwargs) ^ File "/home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/python_api/run_locker/TestRunLocker.py", line 23, in test_run_locker self.runlocker_test(False) File "/home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/python_api/run_locker/TestRunLocker.py", line 110, in runlocker_test self.assertIn( AssertionError: "can't evaluate expressions when the process is running" not found in '' Config=x86_64-/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang -- Ran 2 tests in 0.681s FAILED (failures=1) -- ``` 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. https://github.com/llvm/llvm-project/pull/190656 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
@@ -4592,9 +4608,20 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
$_state.addOperands(ValueRange{addr});
$_builder.createBlock(r);
regionBuilder($_builder, $_state.location);
+}]>,
+// Dynamic form: addr is ptr, num_elements is the runtime count.
+OpBuilder<(ins "mlir::Value":$addr, "mlir::Value":$num_elements,
+ "llvm::function_ref":$regionBuilder), [{
+assert(regionBuilder && "builder callback expected");
erichkeane wrote:
What should we do if `num_elements` ends up being a constant? I wonder if we
should either auto-const-fold here (to convert this to the other form if we can
figure out the type?), or have a transform for it?
Consider:
```
void foo() {
int N = 5;
int arr[N]; // Technically non-constant/a VLA, but we could 'promote' this in
CIR since we know the size.
}
```
https://github.com/llvm/llvm-project/pull/190656
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
@@ -735,31 +735,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(arrayBase.getElementType());
- mlir::Type elementType = arrayTy.getElementType();
-
- // This might be a multi-dimensional array. Find the innermost element type.
+ // Peel any array types wrapped in the address element type down to the CIR
+ // type of a single constructed object.
+ mlir::Type elementType = arrayBase.getElementType();
while (auto maybeArrayTy = mlir::dyn_cast(elementType))
elementType = maybeArrayTy.getElementType();
cir::PointerType ptrToElmType = builder.getPointerTo(elementType);
- // Optimize for a constant count.
- if (auto constantCount = numElements.getDefiningOp()) {
-if (auto constIntAttr = constantCount.getValueAttr()) {
- // 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.
-}
-
-if (constantCount.use_empty())
- constantCount.erase();
- } else {
-// Otherwise, emit the check.
-cgm.errorNYI(e->getSourceRange(),
- "emitCXXAggrConstructorCall: dynamic-length array
expression");
+ bool useDynamicArrayCtor = true;
+ uint64_t constElementCount = 0;
+ if (auto constantOp = numElements.getDefiningOp()) {
+constElementCount = CIRGenFunction::getZExtIntValueFromConstOp(constantOp);
+if (constElementCount == 0)
erichkeane wrote:
Oh, is that what is happening here? Though, `ConstantOp` vs `trivially folded`
are different, right? Woudl be cool if we could 'try harder'.
https://github.com/llvm/llvm-project/pull/190656
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
https://github.com/erichkeane approved this pull request. https://github.com/llvm/llvm-project/pull/190656 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
@@ -4563,27 +4563,43 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
operation has one region, with one single block. The block has an
incoming argument for the current array element to initialize.
-Example:
+When `num_elements` is absent, `addr` must be a pointer to a fixed-size
+CIR array type and the element count is derived from that array type.
+
+When `num_elements` is present, `addr` is a pointer to the first element
+and `num_elements` provides the runtime element count (for example `new
+T[n]`).
+
+Examples:
```mlir
cir.array.ctor(%0 : !cir.ptr>) {
^bb0(%arg0: !cir.ptr):
cir.call @some_ctor(%arg0) : (!cir.ptr) -> ()
cir.yield
}
+
+cir.array.ctor(%ptr, %n : !cir.ptr, !u64i) {
+ ^bb0(%arg0: !cir.ptr):
+cir.call @some_ctor(%arg0) : (!cir.ptr) -> ()
+cir.yield
+}
```
}];
let arguments = (ins
-Arg:$addr
+Arg:$addr,
+Optional:$num_elements
);
let regions = (region SizedRegion<1>:$body);
let assemblyFormat = [{
-$addr `:` qualified(type($addr)) $body attr-dict
+$addr (`,` $num_elements^)? `:` qualified(type($addr))
+(`,` type($num_elements)^)? $body attr-dict
}];
let builders = [
+// Static form: addr is ptr>, no num_elements.
erichkeane wrote:
Can we either assert this is the case, or add this to the verifier?
https://github.com/llvm/llvm-project/pull/190656
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Add support for variable sized array new. (PR #190656)
llvmbot wrote:
@llvm/pr-subscribers-clangir
Author: Andy Kaylor (andykaylor)
Changes
This change adds support for array new with variable size. This required
extending the cir.array.ctor operation to accept a value for the size and a
direct pointer to the element size instead of a pointer to an array.
Assisted-by: Cursor / claude-4.6-opus-high
Assisted-by: Cursor / composer-2-fast
---
Patch is 27.04 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/190656.diff
7 Files Affected:
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+31-3)
- (modified) clang/lib/CIR/CodeGen/CIRGenClass.cpp (+49-45)
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+44)
- (modified) clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp (+20-4)
- (modified) clang/test/CIR/CodeGen/new.cpp (+146)
- (modified) clang/test/CIR/IR/array-ctor.cir (+19)
- (added) clang/test/CIR/IR/invalid-array-structor.cir (+143)
``diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 04884beaa5685..74d79db5e11c6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4563,7 +4563,14 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
operation has one region, with one single block. The block has an
incoming argument for the current array element to initialize.
-Example:
+When `num_elements` is absent, `addr` must be a pointer to a fixed-size
+CIR array type and the element count is derived from that array type.
+
+When `num_elements` is present, `addr` is a pointer to the first element
+and `num_elements` provides the runtime element count (for example `new
+T[n]`).
+
+Examples:
```mlir
cir.array.ctor(%0 : !cir.ptr>) {
@@ -4571,19 +4578,28 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
cir.call @some_ctor(%arg0) : (!cir.ptr) -> ()
cir.yield
}
+
+cir.array.ctor(%ptr, %n : !cir.ptr, !u64i) {
+ ^bb0(%arg0: !cir.ptr):
+cir.call @some_ctor(%arg0) : (!cir.ptr) -> ()
+cir.yield
+}
```
}];
let arguments = (ins
-Arg:$addr
+Arg:$addr,
+Optional:$num_elements
);
let regions = (region SizedRegion<1>:$body);
let assemblyFormat = [{
-$addr `:` qualified(type($addr)) $body attr-dict
+$addr (`,` $num_elements^)? `:` qualified(type($addr))
+(`,` type($num_elements)^)? $body attr-dict
}];
let builders = [
+// Static form: addr is ptr>, no num_elements.
OpBuilder<(ins "mlir::Value":$addr,
"llvm::function_ref":$regionBuilder), [{
assert(regionBuilder && "builder callback expected");
@@ -4592,9 +4608,20 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
$_state.addOperands(ValueRange{addr});
$_builder.createBlock(r);
regionBuilder($_builder, $_state.location);
+}]>,
+// Dynamic form: addr is ptr, num_elements is the runtime count.
+OpBuilder<(ins "mlir::Value":$addr, "mlir::Value":$num_elements,
+ "llvm::function_ref":$regionBuilder), [{
+assert(regionBuilder && "builder callback expected");
+mlir::OpBuilder::InsertionGuard guard($_builder);
+mlir::Region *r = $_state.addRegion();
+$_state.addOperands({addr, num_elements});
+$_builder.createBlock(r);
+regionBuilder($_builder, $_state.location);
}]>
];
+ let hasVerifier = 1;
let hasLLVMLowering = false;
}
@@ -4668,6 +4695,7 @@ def CIR_ArrayDtor : CIR_Op<"array.dtor"> {
}]>
];
+ let hasVerifier = 1;
let hasLLVMLowering = false;
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index e54514950e00f..f8d65fa9a6d33 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -735,31 +735,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(arrayBase.getElementType());
- mlir::Type elementType = arrayTy.getElementType();
-
- // This might be a multi-dimensional array. Find the innermost element type.
+ // Peel any array types wrapped in the address element type down to the CIR
+ // type of a single constructed object.
+ mlir::Type elementType = arrayBase.getElementType();
while (auto maybeArrayTy = mlir::dyn_cast(elementType))
elementType = maybeArrayTy.getElementType();
cir::PointerType ptrToElmType = builder.getPointerTo(elementType);
- // Optimize for a constant count.
- if (auto constantCount = numElements.getDefiningOp()) {
-if (auto constIntAttr = constantCount.getValueAttr()) {
- // Just skip out if the constant count is zero.
- if (constIntAttr.getUInt() == 0)
-return;
-
- arrayTy = cir::ArrayType::get(elementType, constIntAttr.getUInt());
[clang] [CIR] Add support for variable sized array new. (PR #190656)
llvmbot wrote:
@llvm/pr-subscribers-clang
Author: Andy Kaylor (andykaylor)
Changes
This change adds support for array new with variable size. This required
extending the cir.array.ctor operation to accept a value for the size and a
direct pointer to the element size instead of a pointer to an array.
Assisted-by: Cursor / claude-4.6-opus-high
Assisted-by: Cursor / composer-2-fast
---
Patch is 27.04 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/190656.diff
7 Files Affected:
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+31-3)
- (modified) clang/lib/CIR/CodeGen/CIRGenClass.cpp (+49-45)
- (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+44)
- (modified) clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp (+20-4)
- (modified) clang/test/CIR/CodeGen/new.cpp (+146)
- (modified) clang/test/CIR/IR/array-ctor.cir (+19)
- (added) clang/test/CIR/IR/invalid-array-structor.cir (+143)
``diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 04884beaa5685..74d79db5e11c6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4563,7 +4563,14 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
operation has one region, with one single block. The block has an
incoming argument for the current array element to initialize.
-Example:
+When `num_elements` is absent, `addr` must be a pointer to a fixed-size
+CIR array type and the element count is derived from that array type.
+
+When `num_elements` is present, `addr` is a pointer to the first element
+and `num_elements` provides the runtime element count (for example `new
+T[n]`).
+
+Examples:
```mlir
cir.array.ctor(%0 : !cir.ptr>) {
@@ -4571,19 +4578,28 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
cir.call @some_ctor(%arg0) : (!cir.ptr) -> ()
cir.yield
}
+
+cir.array.ctor(%ptr, %n : !cir.ptr, !u64i) {
+ ^bb0(%arg0: !cir.ptr):
+cir.call @some_ctor(%arg0) : (!cir.ptr) -> ()
+cir.yield
+}
```
}];
let arguments = (ins
-Arg:$addr
+Arg:$addr,
+Optional:$num_elements
);
let regions = (region SizedRegion<1>:$body);
let assemblyFormat = [{
-$addr `:` qualified(type($addr)) $body attr-dict
+$addr (`,` $num_elements^)? `:` qualified(type($addr))
+(`,` type($num_elements)^)? $body attr-dict
}];
let builders = [
+// Static form: addr is ptr>, no num_elements.
OpBuilder<(ins "mlir::Value":$addr,
"llvm::function_ref":$regionBuilder), [{
assert(regionBuilder && "builder callback expected");
@@ -4592,9 +4608,20 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
$_state.addOperands(ValueRange{addr});
$_builder.createBlock(r);
regionBuilder($_builder, $_state.location);
+}]>,
+// Dynamic form: addr is ptr, num_elements is the runtime count.
+OpBuilder<(ins "mlir::Value":$addr, "mlir::Value":$num_elements,
+ "llvm::function_ref":$regionBuilder), [{
+assert(regionBuilder && "builder callback expected");
+mlir::OpBuilder::InsertionGuard guard($_builder);
+mlir::Region *r = $_state.addRegion();
+$_state.addOperands({addr, num_elements});
+$_builder.createBlock(r);
+regionBuilder($_builder, $_state.location);
}]>
];
+ let hasVerifier = 1;
let hasLLVMLowering = false;
}
@@ -4668,6 +4695,7 @@ def CIR_ArrayDtor : CIR_Op<"array.dtor"> {
}]>
];
+ let hasVerifier = 1;
let hasLLVMLowering = false;
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index e54514950e00f..f8d65fa9a6d33 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -735,31 +735,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(arrayBase.getElementType());
- mlir::Type elementType = arrayTy.getElementType();
-
- // This might be a multi-dimensional array. Find the innermost element type.
+ // Peel any array types wrapped in the address element type down to the CIR
+ // type of a single constructed object.
+ mlir::Type elementType = arrayBase.getElementType();
while (auto maybeArrayTy = mlir::dyn_cast(elementType))
elementType = maybeArrayTy.getElementType();
cir::PointerType ptrToElmType = builder.getPointerTo(elementType);
- // Optimize for a constant count.
- if (auto constantCount = numElements.getDefiningOp()) {
-if (auto constIntAttr = constantCount.getValueAttr()) {
- // Just skip out if the constant count is zero.
- if (constIntAttr.getUInt() == 0)
-return;
-
- arrayTy = cir::ArrayType::get(elementType, constIntAttr.getUInt());
-
[clang] [CIR] Add support for variable sized array new. (PR #190656)
https://github.com/andykaylor created
https://github.com/llvm/llvm-project/pull/190656
This change adds support for array new with variable size. This required
extending the cir.array.ctor operation to accept a value for the size and a
direct pointer to the element size instead of a pointer to an array.
Assisted-by: Cursor / claude-4.6-opus-high
Assisted-by: Cursor / composer-2-fast
>From 03b66a546a12a5aec2c88fbce0ca6415a633b29b Mon Sep 17 00:00:00 2001
From: Andy Kaylor
Date: Thu, 19 Mar 2026 18:10:13 -0700
Subject: [PATCH] [CIR] Add support for variable sized array new.
This change adds support for array new with variable size. This required
extending the cir.array.ctor operation to accept a value for the size
and a direct pointer to the element size instead of a pointer to an array.
Assisted-by: Cursor / claude-4.6-opus-high
Assisted-by: Cursor / composer-2-fast
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 34 +++-
clang/lib/CIR/CodeGen/CIRGenClass.cpp | 94 +--
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 44 ++
.../Dialect/Transforms/LoweringPrepare.cpp| 24 ++-
clang/test/CIR/CodeGen/new.cpp| 146 ++
clang/test/CIR/IR/array-ctor.cir | 19 +++
clang/test/CIR/IR/invalid-array-structor.cir | 143 +
7 files changed, 452 insertions(+), 52 deletions(-)
create mode 100644 clang/test/CIR/IR/invalid-array-structor.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 04884beaa5685..74d79db5e11c6 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4563,7 +4563,14 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
operation has one region, with one single block. The block has an
incoming argument for the current array element to initialize.
-Example:
+When `num_elements` is absent, `addr` must be a pointer to a fixed-size
+CIR array type and the element count is derived from that array type.
+
+When `num_elements` is present, `addr` is a pointer to the first element
+and `num_elements` provides the runtime element count (for example `new
+T[n]`).
+
+Examples:
```mlir
cir.array.ctor(%0 : !cir.ptr>) {
@@ -4571,19 +4578,28 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
cir.call @some_ctor(%arg0) : (!cir.ptr) -> ()
cir.yield
}
+
+cir.array.ctor(%ptr, %n : !cir.ptr, !u64i) {
+ ^bb0(%arg0: !cir.ptr):
+cir.call @some_ctor(%arg0) : (!cir.ptr) -> ()
+cir.yield
+}
```
}];
let arguments = (ins
-Arg:$addr
+Arg:$addr,
+Optional:$num_elements
);
let regions = (region SizedRegion<1>:$body);
let assemblyFormat = [{
-$addr `:` qualified(type($addr)) $body attr-dict
+$addr (`,` $num_elements^)? `:` qualified(type($addr))
+(`,` type($num_elements)^)? $body attr-dict
}];
let builders = [
+// Static form: addr is ptr>, no num_elements.
OpBuilder<(ins "mlir::Value":$addr,
"llvm::function_ref":$regionBuilder), [{
assert(regionBuilder && "builder callback expected");
@@ -4592,9 +4608,20 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> {
$_state.addOperands(ValueRange{addr});
$_builder.createBlock(r);
regionBuilder($_builder, $_state.location);
+}]>,
+// Dynamic form: addr is ptr, num_elements is the runtime count.
+OpBuilder<(ins "mlir::Value":$addr, "mlir::Value":$num_elements,
+ "llvm::function_ref":$regionBuilder), [{
+assert(regionBuilder && "builder callback expected");
+mlir::OpBuilder::InsertionGuard guard($_builder);
+mlir::Region *r = $_state.addRegion();
+$_state.addOperands({addr, num_elements});
+$_builder.createBlock(r);
+regionBuilder($_builder, $_state.location);
}]>
];
+ let hasVerifier = 1;
let hasLLVMLowering = false;
}
@@ -4668,6 +4695,7 @@ def CIR_ArrayDtor : CIR_Op<"array.dtor"> {
}]>
];
+ let hasVerifier = 1;
let hasLLVMLowering = false;
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index e54514950e00f..f8d65fa9a6d33 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -735,31 +735,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(arrayBase.getElementType());
- mlir::Type elementType = arrayTy.getElementType();
-
- // This might be a multi-dimensional array. Find the innermost element type.
+ // Peel any array types wrapped in the address element type down to the CIR
+ // type of a single constructed object.
+ mlir::Type elementType = arrayBase.getElementType();
while (auto maybeArrayTy = mlir::dyn_cast(elementType))
el
