[Mlir-commits] [clang] [mlir] [CIR] Add limited support for array new (PR #161095)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Sep 29 11:59:31 PDT 2025
https://github.com/jiang1997 updated https://github.com/llvm/llvm-project/pull/161095
>From 34f8b3356aec0d1355314461b76ea40d33d49b21 Mon Sep 17 00:00:00 2001
From: jiang1997 <jieke at live.cn>
Date: Thu, 18 Sep 2025 04:16:24 +0800
Subject: [PATCH 1/4] [MLIR][MemRef] Complete alignment type migration in
OpBuilders
---
.../mlir/Dialect/MemRef/IR/MemRefOps.td | 24 +++++++++----------
.../VectorEmulateMaskedLoadStore.cpp | 9 ++++---
2 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index 671cc05e963b4..bdc505d765b14 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -1237,28 +1237,28 @@ def LoadOp : MemRef_Op<"load",
OpBuilder<(ins "Value":$memref,
"ValueRange":$indices,
CArg<"bool", "false">:$nontemporal,
- CArg<"uint64_t", "0">:$alignment), [{
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment), [{
return build($_builder, $_state, memref, indices, nontemporal,
- alignment != 0 ? $_builder.getI64IntegerAttr(alignment) :
- nullptr);
+ alignment ? $_builder.getI64IntegerAttr(alignment.valueOrOne().value()) :
+ nullptr);
}]>,
OpBuilder<(ins "Type":$resultType,
"Value":$memref,
"ValueRange":$indices,
CArg<"bool", "false">:$nontemporal,
- CArg<"uint64_t", "0">:$alignment), [{
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment), [{
return build($_builder, $_state, resultType, memref, indices, nontemporal,
- alignment != 0 ? $_builder.getI64IntegerAttr(alignment) :
- nullptr);
+ alignment ? $_builder.getI64IntegerAttr(alignment.valueOrOne().value()) :
+ nullptr);
}]>,
OpBuilder<(ins "TypeRange":$resultTypes,
"Value":$memref,
"ValueRange":$indices,
CArg<"bool", "false">:$nontemporal,
- CArg<"uint64_t", "0">:$alignment), [{
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment), [{
return build($_builder, $_state, resultTypes, memref, indices, nontemporal,
- alignment != 0 ? $_builder.getI64IntegerAttr(alignment) :
- nullptr);
+ alignment ? $_builder.getI64IntegerAttr(alignment.valueOrOne().value()) :
+ nullptr);
}]>
];
@@ -1971,10 +1971,10 @@ def MemRef_StoreOp : MemRef_Op<"store",
"Value":$memref,
"ValueRange":$indices,
CArg<"bool", "false">:$nontemporal,
- CArg<"uint64_t", "0">:$alignment), [{
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment), [{
return build($_builder, $_state, valueToStore, memref, indices, nontemporal,
- alignment != 0 ? $_builder.getI64IntegerAttr(alignment) :
- nullptr);
+ alignment ? $_builder.getI64IntegerAttr(alignment.valueOrOne().value()) :
+ nullptr);
}]>,
OpBuilder<(ins "Value":$valueToStore, "Value":$memref), [{
$_state.addOperands(valueToStore);
diff --git a/mlir/lib/Dialect/Vector/Transforms/VectorEmulateMaskedLoadStore.cpp b/mlir/lib/Dialect/Vector/Transforms/VectorEmulateMaskedLoadStore.cpp
index 78f74eef7bee3..bdbb792041e3d 100644
--- a/mlir/lib/Dialect/Vector/Transforms/VectorEmulateMaskedLoadStore.cpp
+++ b/mlir/lib/Dialect/Vector/Transforms/VectorEmulateMaskedLoadStore.cpp
@@ -64,7 +64,6 @@ struct VectorMaskedLoadOpConverter final
Value mask = maskedLoadOp.getMask();
Value base = maskedLoadOp.getBase();
Value iValue = maskedLoadOp.getPassThru();
- std::optional<uint64_t> alignment = maskedLoadOp.getAlignment();
auto indices = llvm::to_vector_of<Value>(maskedLoadOp.getIndices());
Value one = arith::ConstantOp::create(rewriter, loc, indexType,
IntegerAttr::get(indexType, 1));
@@ -76,7 +75,7 @@ struct VectorMaskedLoadOpConverter final
[&](OpBuilder &builder, Location loc) {
auto loadedValue = memref::LoadOp::create(
builder, loc, base, indices, /*nontemporal=*/false,
- alignment.value_or(0));
+ llvm::MaybeAlign(maskedLoadOp.getAlignment().value_or(0)));
auto combinedValue =
vector::InsertOp::create(builder, loc, loadedValue, iValue, i);
scf::YieldOp::create(builder, loc, combinedValue.getResult());
@@ -135,7 +134,6 @@ struct VectorMaskedStoreOpConverter final
Value base = maskedStoreOp.getBase();
Value value = maskedStoreOp.getValueToStore();
bool nontemporal = false;
- std::optional<uint64_t> alignment = maskedStoreOp.getAlignment();
auto indices = llvm::to_vector_of<Value>(maskedStoreOp.getIndices());
Value one = arith::ConstantOp::create(rewriter, loc, indexType,
IntegerAttr::get(indexType, 1));
@@ -145,8 +143,9 @@ struct VectorMaskedStoreOpConverter final
auto ifOp = scf::IfOp::create(rewriter, loc, maskBit, /*else=*/false);
rewriter.setInsertionPointToStart(&ifOp.getThenRegion().front());
auto extractedValue = vector::ExtractOp::create(rewriter, loc, value, i);
- memref::StoreOp::create(rewriter, loc, extractedValue, base, indices,
- nontemporal, alignment.value_or(0));
+ memref::StoreOp::create(
+ rewriter, loc, extractedValue, base, indices, nontemporal,
+ llvm::MaybeAlign(maskedStoreOp.getAlignment().value_or(0)));
rewriter.setInsertionPointAfter(ifOp);
indices.back() =
>From 770a869cb6ca87981f32bed35f6d659c1cabeb96 Mon Sep 17 00:00:00 2001
From: jiang1997 <jieke at live.cn>
Date: Sat, 27 Sep 2025 02:30:04 +0800
Subject: [PATCH 2/4] avoid unnecessary fallback
---
mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index bdc505d765b14..12788a2fbe638 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -1239,7 +1239,7 @@ def LoadOp : MemRef_Op<"load",
CArg<"bool", "false">:$nontemporal,
CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment), [{
return build($_builder, $_state, memref, indices, nontemporal,
- alignment ? $_builder.getI64IntegerAttr(alignment.valueOrOne().value()) :
+ alignment ? $_builder.getI64IntegerAttr(alignment->value()) :
nullptr);
}]>,
OpBuilder<(ins "Type":$resultType,
@@ -1248,7 +1248,7 @@ def LoadOp : MemRef_Op<"load",
CArg<"bool", "false">:$nontemporal,
CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment), [{
return build($_builder, $_state, resultType, memref, indices, nontemporal,
- alignment ? $_builder.getI64IntegerAttr(alignment.valueOrOne().value()) :
+ alignment ? $_builder.getI64IntegerAttr(alignment->value()) :
nullptr);
}]>,
OpBuilder<(ins "TypeRange":$resultTypes,
@@ -1257,7 +1257,7 @@ def LoadOp : MemRef_Op<"load",
CArg<"bool", "false">:$nontemporal,
CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment), [{
return build($_builder, $_state, resultTypes, memref, indices, nontemporal,
- alignment ? $_builder.getI64IntegerAttr(alignment.valueOrOne().value()) :
+ alignment ? $_builder.getI64IntegerAttr(alignment->value()) :
nullptr);
}]>
];
@@ -1973,7 +1973,7 @@ def MemRef_StoreOp : MemRef_Op<"store",
CArg<"bool", "false">:$nontemporal,
CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment), [{
return build($_builder, $_state, valueToStore, memref, indices, nontemporal,
- alignment ? $_builder.getI64IntegerAttr(alignment.valueOrOne().value()) :
+ alignment ? $_builder.getI64IntegerAttr(alignment->value()) :
nullptr);
}]>,
OpBuilder<(ins "Value":$valueToStore, "Value":$memref), [{
>From a13618ec2485b79c1b7669de37feee0b509a15d4 Mon Sep 17 00:00:00 2001
From: jiang1997 <jieke at live.cn>
Date: Sun, 28 Sep 2025 22:20:53 +0800
Subject: [PATCH 3/4] [CIR] Add limited support for array new
---
clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp | 18 +++
clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 15 +++
clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 139 ++++++++++++++++++++++--
clang/lib/CIR/CodeGen/CIRGenFunction.h | 5 +
clang/test/CIR/CodeGen/new.cpp | 53 +++++++++
clang/test/CIR/Lowering/new.cpp | 20 ++++
6 files changed, 243 insertions(+), 7 deletions(-)
create mode 100644 clang/test/CIR/Lowering/new.cpp
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
index 5f1faabde22a5..a6ec2f2981c51 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
@@ -15,6 +15,7 @@
#include "CIRGenFunction.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/GlobalDecl.h"
using namespace clang;
@@ -75,3 +76,20 @@ void CIRGenCXXABI::setCXXABIThisValue(CIRGenFunction &cgf,
assert(getThisDecl(cgf) && "no 'this' variable for function");
cgf.cxxabiThisValue = thisPtr;
}
+
+CharUnits CIRGenCXXABI::getArrayCookieSize(const CXXNewExpr *E) {
+ if (!requiresArrayCookie(E))
+ return CharUnits::Zero();
+
+ cgm.errorNYI(E->getSourceRange(), "CIRGenCXXABI::getArrayCookieSize");
+ return CharUnits::Zero();
+}
+
+bool CIRGenCXXABI::requiresArrayCookie(const CXXNewExpr *E) {
+ // If the class's usual deallocation function takes two arguments,
+ // it needs a cookie.
+ if (E->doesUsualArrayDeleteWantSize())
+ return true;
+
+ return E->getAllocatedType().isDestructedType();
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index ae922599809b8..185db2840c237 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -28,6 +28,8 @@ class CIRGenCXXABI {
CIRGenModule &cgm;
std::unique_ptr<clang::MangleContext> mangleContext;
+ virtual bool requiresArrayCookie(const CXXNewExpr *E);
+
public:
// TODO(cir): make this protected when target-specific CIRGenCXXABIs are
// implemented.
@@ -241,6 +243,19 @@ class CIRGenCXXABI {
void setStructorImplicitParamValue(CIRGenFunction &cgf, mlir::Value val) {
cgf.cxxStructorImplicitParamValue = val;
}
+
+ /**************************** Array cookies ******************************/
+
+ /// Returns the extra size required in order to store the array
+ /// cookie for the given new-expression. May return 0 to indicate that no
+ /// array cookie is required.
+ ///
+ /// Several cases are filtered out before this method is called:
+ /// - non-array allocations never need a cookie
+ /// - calls to \::operator new(size_t, void*) never need a cookie
+ ///
+ /// \param E - the new-expression being allocated.
+ virtual CharUnits getArrayCookieSize(const CXXNewExpr *E);
};
/// Creates and Itanium-family ABI
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
index 1f7e3dd1fa7d2..3ea402b28fd32 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "CIRGenCXXABI.h"
+#include "CIRGenConstantEmitter.h"
#include "CIRGenFunction.h"
#include "clang/AST/DeclCXX.h"
@@ -210,6 +211,19 @@ RValue CIRGenFunction::emitCXXMemberOrOperatorCall(
return emitCall(fnInfo, callee, returnValue, args, nullptr, loc);
}
+static CharUnits calculateCookiePadding(CIRGenFunction &cgf,
+ const CXXNewExpr *e) {
+ if (!e->isArray())
+ return CharUnits::Zero();
+
+ // No cookie is required if the operator new[] being used is the
+ // reserved placement operator new[].
+ if (e->getOperatorNew()->isReservedGlobalPlacementOperator())
+ return CharUnits::Zero();
+
+ return cgf.cgm.getCXXABI().getArrayCookieSize(e);
+}
+
static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
unsigned minElements,
mlir::Value &numElements,
@@ -224,8 +238,98 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
return sizeWithoutCookie;
}
- cgf.cgm.errorNYI(e->getSourceRange(), "emitCXXNewAllocSize: array");
- return {};
+ // The width of size_t.
+ unsigned sizeWidth = cgf.cgm.getDataLayout().getTypeSizeInBits(cgf.SizeTy);
+
+ // The number of elements can be have an arbitrary integer type;
+ // essentially, we need to multiply it by a constant factor, add a
+ // cookie size, and verify that the result is representable as a
+ // size_t. That's just a gloss, though, and it's wrong in one
+ // important way: if the count is negative, it's an error even if
+ // the cookie size would bring the total size >= 0.
+ //
+ // If the array size is constant, Sema will have prevented negative
+ // values and size overflow.
+
+ // Compute the constant factor.
+ llvm::APInt arraySizeMultiplier(sizeWidth, 1);
+ while (const ConstantArrayType *cat =
+ cgf.getContext().getAsConstantArrayType(type)) {
+ type = cat->getElementType();
+ arraySizeMultiplier *= cat->getSize();
+ }
+
+ CharUnits typeSize = cgf.getContext().getTypeSizeInChars(type);
+ llvm::APInt typeSizeMultiplier(sizeWidth, typeSize.getQuantity());
+ typeSizeMultiplier *= arraySizeMultiplier;
+
+ // Figure out the cookie size.
+ llvm::APInt cookieSize(sizeWidth,
+ calculateCookiePadding(cgf, e).getQuantity());
+
+ // This will be a size_t.
+ mlir::Value size;
+
+ // Emit the array size expression.
+ // We multiply the size of all dimensions for NumElements.
+ // e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6.
+ const Expr *arraySize = *e->getArraySize();
+ mlir::Attribute constNumElements =
+ ConstantEmitter(cgf.cgm, &cgf)
+ .emitAbstract(arraySize, arraySize->getType());
+ if (constNumElements) {
+ // Get an APInt from the constant
+ const llvm::APInt &count =
+ mlir::cast<cir::IntAttr>(constNumElements).getValue();
+
+ unsigned numElementsWidth = count.getBitWidth();
+
+ // The equivalent code in CodeGen/CGExprCXX.cpp handles these cases as
+ // overflow, but they should never happen. The size argument is implicitly
+ // cast to a size_t, so it can never be negative and numElementsWidth will
+ // always equal sizeWidth.
+ assert(!count.isNegative() && "Expected non-negative array size");
+ assert(numElementsWidth == sizeWidth &&
+ "Expected a size_t array size constant");
+
+ // Okay, compute a count at the right width.
+ llvm::APInt adjustedCount = count.zextOrTrunc(sizeWidth);
+
+ // Scale numElements by that. This might overflow, but we don't
+ // care because it only overflows if allocationSize does, too, and
+ // if that overflows then we shouldn't use this.
+ // This emits a constant that may not be used, but we can't tell here
+ // whether it will be needed or not.
+ numElements =
+ cgf.getBuilder().getConstInt(loc, adjustedCount * arraySizeMultiplier);
+
+ // Compute the size before cookie, and track whether it overflowed.
+ bool overflow;
+ llvm::APInt allocationSize =
+ adjustedCount.umul_ov(typeSizeMultiplier, overflow);
+
+ // Sema prevents us from hitting this case
+ assert(!overflow && "Overflow in array allocation size");
+
+ // Add in the cookie, and check whether it's overflowed.
+ if (cookieSize != 0) {
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "emitCXXNewAllocSize: array cookie");
+ }
+
+ size = cgf.getBuilder().getConstInt(loc, allocationSize);
+ } else {
+ // TODO: Handle the variable size case
+ cgf.cgm.errorNYI(e->getSourceRange(),
+ "emitCXXNewAllocSize: variable array size");
+ }
+
+ if (cookieSize == 0)
+ sizeWithoutCookie = size;
+ else
+ assert(sizeWithoutCookie && "didn't set sizeWithoutCookie?");
+
+ return size;
}
static void storeAnyExprIntoOneUnit(CIRGenFunction &cgf, const Expr *init,
@@ -254,13 +358,26 @@ static void storeAnyExprIntoOneUnit(CIRGenFunction &cgf, const Expr *init,
llvm_unreachable("bad evaluation kind");
}
+void CIRGenFunction::emitNewArrayInitializer(
+ const CXXNewExpr *e, QualType elementType, mlir::Type elementTy,
+ Address beginPtr, mlir::Value numElements,
+ mlir::Value allocSizeWithoutCookie) {
+ // If we have a type with trivial initialization and no initializer,
+ // there's nothing to do.
+ if (!e->hasInitializer())
+ return;
+
+ llvm_unreachable("NYI");
+}
+
static void emitNewInitializer(CIRGenFunction &cgf, const CXXNewExpr *e,
QualType elementType, mlir::Type elementTy,
Address newPtr, mlir::Value numElements,
mlir::Value allocSizeWithoutCookie) {
assert(!cir::MissingFeatures::generateDebugInfo());
if (e->isArray()) {
- cgf.cgm.errorNYI(e->getSourceRange(), "emitNewInitializer: array");
+ cgf.emitNewArrayInitializer(e, elementType, elementTy, newPtr, numElements,
+ allocSizeWithoutCookie);
} else if (const Expr *init = e->getInitializer()) {
storeAnyExprIntoOneUnit(cgf, init, e->getAllocatedType(), newPtr,
AggValueSlot::DoesNotOverlap);
@@ -418,14 +535,22 @@ mlir::Value CIRGenFunction::emitCXXNewExpr(const CXXNewExpr *e) {
// If there's an operator delete, enter a cleanup to call it if an
// exception is thrown.
- if (e->getOperatorDelete() &&
- !e->getOperatorDelete()->isReservedGlobalPlacementOperator())
- cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: operator delete");
+ // TODO: Handle operator delete cleanup for exception safety
+ // if (e->getOperatorDelete() &&
+ // !e->getOperatorDelete()->isReservedGlobalPlacementOperator())
+ // cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: operator delete");
if (allocSize != allocSizeWithoutCookie)
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: array with cookies");
- mlir::Type elementTy = convertTypeForMem(allocType);
+ mlir::Type elementTy;
+ if (e->isArray()) {
+ // For array new, use the allocated type to handle multidimensional arrays
+ // correctly
+ elementTy = convertTypeForMem(e->getAllocatedType());
+ } else {
+ elementTy = convertTypeForMem(allocType);
+ }
Address result = builder.createElementBitCast(getLoc(e->getSourceRange()),
allocation, elementTy);
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 166435f9e7e9e..91de5a9d792b8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1226,6 +1226,11 @@ class CIRGenFunction : public CIRGenTypeCache {
mlir::Value emitCXXNewExpr(const CXXNewExpr *e);
+ void emitNewArrayInitializer(const CXXNewExpr *E, QualType ElementType,
+ mlir::Type ElementTy, Address BeginPtr,
+ mlir::Value NumElements,
+ mlir::Value AllocSizeWithoutCookie);
+
RValue emitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *e,
const CXXMethodDecl *md,
ReturnValueSlot returnValue);
diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp
index b14bf077cd154..7a8dacc6bc887 100644
--- a/clang/test/CIR/CodeGen/new.cpp
+++ b/clang/test/CIR/CodeGen/new.cpp
@@ -180,3 +180,56 @@ void test_new_with_complex_type() {
// OGCG: store float 1.000000e+00, ptr %[[COMPLEX_REAL_PTR]], align 8
// OGCG: store float 2.000000e+00, ptr %[[COMPLEX_IMAG_PTR]], align 4
// OGCG: store ptr %[[NEW_COMPLEX]], ptr %[[A_ADDR]], align 8
+
+void t_new_constant_size() {
+ auto p = new double[16];
+}
+
+// In this test, NUM_ELEMENTS isn't used because no cookie is needed and there
+// are no constructor calls needed.
+
+// CHECK: cir.func{{.*}} @_Z19t_new_constant_sizev()
+// CHECK: %0 = cir.alloca !cir.ptr<!cir.double>, !cir.ptr<!cir.ptr<!cir.double>>, ["p", init] {alignment = 8 : i64}
+// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<16> : !u64i
+// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<128> : !u64i
+// CHECK: %3 = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void>
+// CHECK: %4 = cir.cast(bitcast, %3 : !cir.ptr<!void>), !cir.ptr<!cir.double>
+// CHECK: cir.store align(8) %4, %0 : !cir.ptr<!cir.double>, !cir.ptr<!cir.ptr<!cir.double>>
+// CHECK: cir.return
+// CHECK: }
+
+// LLVM: define{{.*}} void @_Z19t_new_constant_sizev
+// LLVM: %[[P_ADDR:.*]] = alloca ptr, i64 1, align 8
+// LLVM: %[[CALL:.*]] = call ptr @_Znam(i64 128)
+// LLVM: store ptr %[[CALL]], ptr %[[P_ADDR]], align 8
+
+// OGCG: define{{.*}} void @_Z19t_new_constant_sizev
+// OGCG: %[[P_ADDR:.*]] = alloca ptr, align 8
+// OGCG: %[[CALL:.*]] = call noalias noundef nonnull ptr @_Znam(i64 noundef 128)
+// OGCG: store ptr %[[CALL]], ptr %[[P_ADDR]], align 8
+
+
+void t_new_multidim_constant_size() {
+ auto p = new double[2][3][4];
+}
+
+// As above, NUM_ELEMENTS isn't used.
+
+// CHECK: cir.func{{.*}} @_Z28t_new_multidim_constant_sizev()
+// CHECK: %0 = cir.alloca !cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>>, !cir.ptr<!cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>>>, ["p", init] {alignment = 8 : i64}
+// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<24> : !u64i
+// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<192> : !u64i
+// CHECK: %3 = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void>
+// CHECK: %4 = cir.cast(bitcast, %3 : !cir.ptr<!void>), !cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>>
+// CHECK: cir.store align(8) %4, %0 : !cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>>, !cir.ptr<!cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>>>
+// CHECK: }
+
+// LLVM: define{{.*}} void @_Z28t_new_multidim_constant_sizev
+// LLVM: %[[P_ADDR:.*]] = alloca ptr, i64 1, align 8
+// LLVM: %[[CALL:.*]] = call ptr @_Znam(i64 192)
+// LLVM: store ptr %[[CALL]], ptr %[[P_ADDR]], align 8
+
+// OGCG: define{{.*}} void @_Z28t_new_multidim_constant_sizev
+// OGCG: %[[P_ADDR:.*]] = alloca ptr, align 8
+// OGCG: %[[CALL:.*]] = call noalias noundef nonnull ptr @_Znam(i64 noundef 192)
+// OGCG: store ptr %[[CALL]], ptr %[[P_ADDR]], align 8
diff --git a/clang/test/CIR/Lowering/new.cpp b/clang/test/CIR/Lowering/new.cpp
new file mode 100644
index 0000000000000..3c51d5a5368d7
--- /dev/null
+++ b/clang/test/CIR/Lowering/new.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+void t_new_constant_size() {
+ auto p = new double[16];
+}
+
+// LLVM: @_Z19t_new_constant_sizev()
+// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8
+// LLVM: %[[ADDR:.*]] = call ptr @_Znam(i64 128)
+// LLVM: store ptr %[[ADDR]], ptr %[[ALLOCA]], align 8
+
+void t_new_multidim_constant_size() {
+ auto p = new double[2][3][4];
+}
+
+// LLVM: @_Z28t_new_multidim_constant_sizev()
+// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8
+// LLVM: %[[ADDR:.*]] = call ptr @_Znam(i64 192)
+// LLVM: store ptr %[[ADDR]], ptr %[[ALLOCA]], align 8
\ No newline at end of file
>From d1e96872514f4fe47967d7ccfb36f2a621fb9ebf Mon Sep 17 00:00:00 2001
From: jiang1997 <jieke at live.cn>
Date: Tue, 30 Sep 2025 02:45:09 +0800
Subject: [PATCH 4/4] restore operator delete NYI diagnostics and drop
redundant lowering test
---
clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 9 ++++-----
clang/test/CIR/Lowering/new.cpp | 20 --------------------
2 files changed, 4 insertions(+), 25 deletions(-)
delete mode 100644 clang/test/CIR/Lowering/new.cpp
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
index 3ea402b28fd32..d9c2688ceb9fe 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
@@ -367,7 +367,7 @@ void CIRGenFunction::emitNewArrayInitializer(
if (!e->hasInitializer())
return;
- llvm_unreachable("NYI");
+ cgm.errorNYI(e->getSourceRange(), "emitNewArrayInitializer");
}
static void emitNewInitializer(CIRGenFunction &cgf, const CXXNewExpr *e,
@@ -535,10 +535,9 @@ mlir::Value CIRGenFunction::emitCXXNewExpr(const CXXNewExpr *e) {
// If there's an operator delete, enter a cleanup to call it if an
// exception is thrown.
- // TODO: Handle operator delete cleanup for exception safety
- // if (e->getOperatorDelete() &&
- // !e->getOperatorDelete()->isReservedGlobalPlacementOperator())
- // cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: operator delete");
+ if (e->getOperatorDelete() &&
+ !e->getOperatorDelete()->isReservedGlobalPlacementOperator())
+ cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: operator delete");
if (allocSize != allocSizeWithoutCookie)
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: array with cookies");
diff --git a/clang/test/CIR/Lowering/new.cpp b/clang/test/CIR/Lowering/new.cpp
deleted file mode 100644
index 3c51d5a5368d7..0000000000000
--- a/clang/test/CIR/Lowering/new.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
-// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
-
-void t_new_constant_size() {
- auto p = new double[16];
-}
-
-// LLVM: @_Z19t_new_constant_sizev()
-// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8
-// LLVM: %[[ADDR:.*]] = call ptr @_Znam(i64 128)
-// LLVM: store ptr %[[ADDR]], ptr %[[ALLOCA]], align 8
-
-void t_new_multidim_constant_size() {
- auto p = new double[2][3][4];
-}
-
-// LLVM: @_Z28t_new_multidim_constant_sizev()
-// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8
-// LLVM: %[[ADDR:.*]] = call ptr @_Znam(i64 192)
-// LLVM: store ptr %[[ADDR]], ptr %[[ALLOCA]], align 8
\ No newline at end of file
More information about the Mlir-commits
mailing list