https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/179556
>From 47e79012eaa430aa5e85c87728be030f43c5d1b1 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Fri, 30 Jan 2026 13:07:56 -0800 Subject: [PATCH 1/2] [CIR] Upstream support for array new with non-empty ILE This adds CIR support for handling array new initialization with a non-empty initializer list. --- clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 30 +++++++-- clang/test/CIR/CodeGen/new.cpp | 89 +++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 3731773cffa45..2210fa86d9aca 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -14,6 +14,7 @@ #include "CIRGenConstantEmitter.h" #include "CIRGenFunction.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -574,6 +575,7 @@ void CIRGenFunction::emitNewArrayInitializer( unsigned initListElements = 0; const Expr *init = e->getInitializer(); + Address endOfInit = Address::invalid(); QualType::DestructionKind dtorKind = elementType.isDestructedType(); assert(!cir::MissingFeatures::cleanupDeactivationScope()); @@ -652,10 +654,30 @@ void CIRGenFunction::emitNewArrayInitializer( return; } - if (!initExprs.empty()) { - cgm.errorNYI(ile->getSourceRange(), - "emitNewArrayInitializer: non-empty init list"); - return; + CharUnits elementSize = getContext().getTypeSizeInChars(elementType); + CharUnits startAlign = curPtr.getAlignment(); + unsigned i = 0; + for (const Expr *ie : initExprs) { + // Tell the cleanup that it needs to destroy up to this + // element. TODO: some of these stores can be trivially + // observed to be unnecessary. + if (endOfInit.isValid()) { + cgm.errorNYI(ie->getSourceRange(), + "emitNewArrayInitializer: update dtor cleanup ptr"); + return; + } + // FIXME: If the last initializer is an incomplete initializer list for + // an array, and we have an array filler, we can fold together the two + // initialization loops. + storeAnyExprIntoOneUnit(*this, ie, ie->getType(), curPtr, + AggValueSlot::DoesNotOverlap); + mlir::Location loc = getLoc(ie->getExprLoc()); + mlir::Value castOp = builder.createPtrBitcast( + curPtr.getPointer(), convertTypeForMem(allocType)); + mlir::Value offsetOp = builder.getSignedInt(loc, 1, /*width=*/32); + mlir::Value dataPtr = builder.createPtrStride(loc, castOp, offsetOp); + curPtr = Address(dataPtr, curPtr.getElementType(), + startAlign.alignmentAtOffset((++i) * elementSize)); } // The remaining elements are filled with the array filler expression. diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index ed6f5b6450fb2..b6ccffe1cd86d 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -361,3 +361,92 @@ void t_constant_size_memset_init() { // OGCG: define {{.*}} void @_Z27t_constant_size_memset_initv() // OGCG: %[[P:.*]] = call{{.*}} ptr @_Znam(i64{{.*}} 64) // OGCG: call void @llvm.memset.p0.i64(ptr{{.*}} %[[P]], i8 0, i64 64, i1 false) + +void t_constant_size_full_init() { + auto p = new int[4] { 1, 2, 3, 4 }; +} + +// CHECK: cir.func {{.*}} @_Z25t_constant_size_full_initv() +// CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<16> : !u64i +// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[ELEM_0_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : !cir.ptr<!void> -> !cir.ptr<!s32i> +// CHECK: %[[CONST_ONE:.*]] = cir.const #cir.int<1> : !s32i +// CHECK: cir.store{{.*}} %[[CONST_ONE]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> +// CHECK: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s32i +// CHECK: %[[ELEM_1_PTR:.*]] = cir.ptr_stride %[[ELEM_0_PTR]], %[[OFFSET]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i> +// CHECK: %[[CONST_TWO:.*]] = cir.const #cir.int<2> : !s32i +// CHECK: cir.store{{.*}} %[[CONST_TWO]], %[[ELEM_1_PTR]] : !s32i, !cir.ptr<!s32i> +// CHECK: %[[OFFSET1:.*]] = cir.const #cir.int<1> : !s32i +// CHECK: %[[ELEM_2_PTR:.*]] = cir.ptr_stride %[[ELEM_1_PTR]], %[[OFFSET1]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i> +// CHECK: %[[CONST_THREE:.*]] = cir.const #cir.int<3> : !s32i +// CHECK: cir.store{{.*}} %[[CONST_THREE]], %[[ELEM_2_PTR]] : !s32i, !cir.ptr<!s32i> +// CHECK: %[[OFFSET2:.*]] = cir.const #cir.int<1> : !s32i +// CHECK: %[[ELEM_3_PTR:.*]] = cir.ptr_stride %[[ELEM_2_PTR]], %[[OFFSET2]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i> +// CHECK: %[[CONST_FOUR:.*]] = cir.const #cir.int<4> : !s32i +// CHECK: cir.store{{.*}} %[[CONST_FOUR]], %[[ELEM_3_PTR]] : !s32i, !cir.ptr<!s32i> + +// LLVM: define {{.*}} void @_Z25t_constant_size_full_initv() +// LLVM: %[[P:.*]] = call ptr @_Znam(i64 16) +// LLVM: store i32 1, ptr %[[CALL]] +// LLVM: %[[ELEM_1:.*]] = getelementptr i32, ptr %[[P]], i64 1 +// LLVM: store i32 2, ptr %[[ELEM_1]] +// LLVM: %[[ELEM_2:.*]] = getelementptr i32, ptr %[[ELEM_1]], i64 1 +// LLVM: store i32 3, ptr %[[ELEM_2]] +// LLVM: %[[ELEM_3:.*]] = getelementptr i32, ptr %[[ELEM_2]], i64 1 +// LLVM: store i32 4, ptr %[[ELEM_3]] + +// OGCG: define {{.*}} void @_Z25t_constant_size_full_initv() +// OGCG: %[[P:.*]] = call{{.*}} ptr @_Znam(i64{{.*}} 16) +// OGCG: store i32 1, ptr %[[P]] +// OGCG: %[[ELEM_1:.*]] = getelementptr inbounds i32, ptr %[[P]], i64 1 +// OGCG: store i32 2, ptr %[[ELEM_1]] +// OGCG: %[[ELEM_2:.*]] = getelementptr inbounds i32, ptr %[[ELEM_1]], i64 1 +// OGCG: store i32 3, ptr %[[ELEM_2]] +// OGCG: %[[ELEM_3:.*]] = getelementptr inbounds i32, ptr %[[ELEM_2]], i64 1 +// OGCG: store i32 4, ptr %[[ELEM_3]] + +void t_constant_size_partial_init() { + auto p = new int[16] { 1, 2, 3 }; +} + +// CHECK: cir.func {{.*}} @_Z28t_constant_size_partial_initv() +// CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<64> : !u64i +// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[ELEM_0_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : !cir.ptr<!void> -> !cir.ptr<!s32i> +// CHECK: %[[CONST_ONE:.*]] = cir.const #cir.int<1> : !s32i +// CHECK: cir.store{{.*}} %[[CONST_ONE]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> +// CHECK: %[[OFFSET:.*]] = cir.const #cir.int<1> : !s32i +// CHECK: %[[ELEM_1_PTR:.*]] = cir.ptr_stride %[[ELEM_0_PTR]], %[[OFFSET]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i> +// CHECK: %[[CONST_TWO:.*]] = cir.const #cir.int<2> : !s32i +// CHECK: cir.store{{.*}} %[[CONST_TWO]], %[[ELEM_1_PTR]] : !s32i, !cir.ptr<!s32i> +// CHECK: %[[OFFSET1:.*]] = cir.const #cir.int<1> : !s32i +// CHECK: %[[ELEM_2_PTR:.*]] = cir.ptr_stride %[[ELEM_1_PTR]], %[[OFFSET1]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i> +// CHECK: %[[CONST_THREE:.*]] = cir.const #cir.int<3> : !s32i +// CHECK: cir.store{{.*}} %[[CONST_THREE]], %[[ELEM_2_PTR]] : !s32i, !cir.ptr<!s32i> +// CHECK: %[[OFFSET2:.*]] = cir.const #cir.int<1> : !s32i +// CHECK: %[[ELEM_3_PTR:.*]] = cir.ptr_stride %[[ELEM_2_PTR]], %[[OFFSET2]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i> +// CHECK: %[[INIT_SIZE:.*]] = cir.const #cir.int<12> : !u64i +// CHECK: %[[REMAINING_SIZE:.*]] = cir.binop(sub, %[[ALLOCATION_SIZE]], %[[INIT_SIZE]]) : !u64i +// CHECK: %[[VOID_PTR:.*]] = cir.cast bitcast %[[ELEM_3_PTR]] : !cir.ptr<!s32i> -> !cir.ptr<!void> +// CHECK: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i +// CHECK: cir.libc.memset %[[REMAINING_SIZE]] bytes at %[[VOID_PTR]] to %[[ZERO]] : !cir.ptr<!void>, !u8i, !u64i + +// LLVM: define {{.*}} void @_Z28t_constant_size_partial_initv() +// LLVM: %[[P:.*]] = call ptr @_Znam(i64 64) +// LLVM: store i32 1, ptr %[[P]] +// LLVM: %[[ELEM_1:.*]] = getelementptr i32, ptr %[[P]], i64 1 +// LLVM: store i32 2, ptr %[[ELEM_1]] +// LLVM: %[[ELEM_2:.*]] = getelementptr i32, ptr %[[ELEM_1]], i64 1 +// LLVM: store i32 3, ptr %[[ELEM_2]] +// LLVM: %[[ELEM_3:.*]] = getelementptr i32, ptr %[[ELEM_2]], i64 1 +// LLVM: call void @llvm.memset.p0.i64(ptr %[[ELEM_3]], i8 0, i64 52, i1 false) + +// OGCG: define {{.*}} void @_Z28t_constant_size_partial_initv() +// OGCG: %[[P:.*]] = call{{.*}} ptr @_Znam(i64{{.*}} 64) +// OGCG: store i32 1, ptr %[[P]] +// OGCG: %[[ELEM_1:.*]] = getelementptr inbounds i32, ptr %[[P]], i64 1 +// OGCG: store i32 2, ptr %[[ELEM_1]] +// OGCG: %[[ELEM_2:.*]] = getelementptr inbounds i32, ptr %[[ELEM_1]], i64 1 +// OGCG: store i32 3, ptr %[[ELEM_2]] +// OGCG: %[[ELEM_3:.*]] = getelementptr inbounds i32, ptr %[[ELEM_2]], i64 1 +// OGCG: call void @llvm.memset.p0.i64(ptr{{.*}} %[[ELEM_3]], i8 0, i64 52, i1 false) >From fbf24fec6d4c07dadf977439820f7a1d4a94a5c0 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Wed, 4 Feb 2026 11:32:21 -0800 Subject: [PATCH 2/2] Add checks for allocsize attribute --- clang/test/CIR/CodeGen/new.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index b6ccffe1cd86d..db2adbdce7f1c 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -368,7 +368,7 @@ void t_constant_size_full_init() { // CHECK: cir.func {{.*}} @_Z25t_constant_size_full_initv() // CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<16> : !u64i -// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array<i32: 0>} : (!u64i) -> !cir.ptr<!void> // CHECK: %[[ELEM_0_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : !cir.ptr<!void> -> !cir.ptr<!s32i> // CHECK: %[[CONST_ONE:.*]] = cir.const #cir.int<1> : !s32i // CHECK: cir.store{{.*}} %[[CONST_ONE]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> @@ -411,7 +411,7 @@ void t_constant_size_partial_init() { // CHECK: cir.func {{.*}} @_Z28t_constant_size_partial_initv() // CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<64> : !u64i -// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array<i32: 0>} : (!u64i) -> !cir.ptr<!void> // CHECK: %[[ELEM_0_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : !cir.ptr<!void> -> !cir.ptr<!s32i> // CHECK: %[[CONST_ONE:.*]] = cir.const #cir.int<1> : !s32i // CHECK: cir.store{{.*}} %[[CONST_ONE]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
