https://github.com/jiang1997 updated https://github.com/llvm/llvm-project/pull/161095
>From 34f8b3356aec0d1355314461b76ea40d33d49b21 Mon Sep 17 00:00:00 2001 From: jiang1997 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
