[clang] [CIR] Add support for variable sized array new. (PR #190656)

2026-04-07 Thread Erich Keane via cfe-commits

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)

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

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)

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


@@ -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)

2026-04-07 Thread Erich Keane via cfe-commits


@@ -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)

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

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)

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

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)

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


@@ -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)

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


@@ -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)

2026-04-06 Thread via cfe-commits

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)

2026-04-06 Thread Erich Keane via cfe-commits


@@ -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)

2026-04-06 Thread Erich Keane via cfe-commits


@@ -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)

2026-04-06 Thread Erich Keane via cfe-commits

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)

2026-04-06 Thread Erich Keane via cfe-commits


@@ -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)

2026-04-06 Thread via cfe-commits

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)

2026-04-06 Thread via cfe-commits

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)

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

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