From c8e3813d44a7569ea6f96982d5dad736d33d22f8 Mon Sep 17 00:00:00 2001 From: jiang1997 Date: Sun, 28 Sep 2025 22:20:53 +0800 Subject: [PATCH 1/5] [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 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 83208bf226882..224b12e67455d 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" @@ -264,6 +265,19 @@ static UsualDeleteParams getUsualDeleteParams(const FunctionDecl *fd) { return params; } +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, @@ -278,8 +292,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(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, @@ -308,13 +412,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); @@ -583,14 +700,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 ef07db3d48ffc..6f13a8cb8fb61 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1228,6 +1228,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.ptr>, ["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 +// CHECK: %4 = cir.cast(bitcast, %3 : !cir.ptr), !cir.ptr +// CHECK: cir.store align(8) %4, %0 : !cir.ptr, !cir.ptr> +// 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 x 3>>, !cir.ptr 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 +// CHECK: %4 = cir.cast(bitcast, %3 : !cir.ptr), !cir.ptr x 3>> +// CHECK: cir.store align(8) %4, %0 : !cir.ptr x 3>>, !cir.ptr 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 47647f6e32666b774e1c9b397ee42bf1578fc304 Mon Sep 17 00:00:00 2001 From: jiang1997 Date: Tue, 30 Sep 2025 02:45:09 +0800 Subject: [PATCH 2/5] 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 224b12e67455d..30d4e03aba523 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -421,7 +421,7 @@ void CIRGenFunction::emitNewArrayInitializer( if (!e->hasInitializer()) return; - llvm_unreachable("NYI"); + cgm.errorNYI(e->getSourceRange(), "emitNewArrayInitializer"); } static void emitNewInitializer(CIRGenFunction &cgf, const CXXNewExpr *e, @@ -700,10 +700,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 From 61c116add39b9a10220d836b543c4b368e1e2eea Mon Sep 17 00:00:00 2001 From: jiang1997 Date: Wed, 1 Oct 2025 00:09:06 +0800 Subject: [PATCH 3/5] Add regexes for all SSA values --- clang/test/CIR/CodeGen/new.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index 7a8dacc6bc887..2dba2a322ff06 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -189,12 +189,12 @@ void t_new_constant_size() { // are no constructor calls needed. // CHECK: cir.func{{.*}} @_Z19t_new_constant_sizev() -// CHECK: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["p", init] {alignment = 8 : i64} +// CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["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 -// CHECK: %4 = cir.cast(bitcast, %3 : !cir.ptr), !cir.ptr -// CHECK: cir.store align(8) %4, %0 : !cir.ptr, !cir.ptr> +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr +// CHECK: %[[TYPED_PTR:.*]] = cir.cast(bitcast, %[[RAW_PTR]] : !cir.ptr), !cir.ptr +// CHECK: cir.store align(8) %[[TYPED_PTR]], %[[P_ADDR]] : !cir.ptr, !cir.ptr> // CHECK: cir.return // CHECK: } @@ -216,12 +216,12 @@ void t_new_multidim_constant_size() { // As above, NUM_ELEMENTS isn't used. // CHECK: cir.func{{.*}} @_Z28t_new_multidim_constant_sizev() -// CHECK: %0 = cir.alloca !cir.ptr x 3>>, !cir.ptr x 3>>>, ["p", init] {alignment = 8 : i64} +// CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr x 3>>, !cir.ptr 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 -// CHECK: %4 = cir.cast(bitcast, %3 : !cir.ptr), !cir.ptr x 3>> -// CHECK: cir.store align(8) %4, %0 : !cir.ptr x 3>>, !cir.ptr x 3>>> +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr +// CHECK: %[[TYPED_PTR:.*]] = cir.cast(bitcast, %[[RAW_PTR]] : !cir.ptr), !cir.ptr x 3>> +// CHECK: cir.store align(8) %[[TYPED_PTR]], %[[P_ADDR]] : !cir.ptr x 3>>, !cir.ptr x 3>>> // CHECK: } // LLVM: define{{.*}} void @_Z28t_new_multidim_constant_sizev From 513fd2f1b304c59014d99c791be28c1ec422c9e1 Mon Sep 17 00:00:00 2001 From: jiang1997 Date: Fri, 3 Oct 2025 02:07:49 +0800 Subject: [PATCH 4/5] Follow LLVM naming conventions for function parameters --- clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp | 12 ++++++------ clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 4 ++-- clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp index a6ec2f2981c51..df42af828b0a3 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp @@ -77,19 +77,19 @@ void CIRGenCXXABI::setCXXABIThisValue(CIRGenFunction &cgf, cgf.cxxabiThisValue = thisPtr; } -CharUnits CIRGenCXXABI::getArrayCookieSize(const CXXNewExpr *E) { - if (!requiresArrayCookie(E)) +CharUnits CIRGenCXXABI::getArrayCookieSize(const CXXNewExpr *e) { + if (!requiresArrayCookie(e)) return CharUnits::Zero(); - cgm.errorNYI(E->getSourceRange(), "CIRGenCXXABI::getArrayCookieSize"); + cgm.errorNYI(e->getSourceRange(), "CIRGenCXXABI::getArrayCookieSize"); return CharUnits::Zero(); } -bool CIRGenCXXABI::requiresArrayCookie(const CXXNewExpr *E) { +bool CIRGenCXXABI::requiresArrayCookie(const CXXNewExpr *e) { // If the class's usual deallocation function takes two arguments, // it needs a cookie. - if (E->doesUsualArrayDeleteWantSize()) + if (e->doesUsualArrayDeleteWantSize()) return true; - return E->getAllocatedType().isDestructedType(); + return e->getAllocatedType().isDestructedType(); } diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index 185db2840c237..cc631653a8f62 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -28,7 +28,7 @@ class CIRGenCXXABI { CIRGenModule &cgm; std::unique_ptr mangleContext; - virtual bool requiresArrayCookie(const CXXNewExpr *E); + virtual bool requiresArrayCookie(const CXXNewExpr *e); public: // TODO(cir): make this protected when target-specific CIRGenCXXABIs are @@ -255,7 +255,7 @@ class CIRGenCXXABI { /// - calls to \::operator new(size_t, void*) never need a cookie /// /// \param E - the new-expression being allocated. - virtual CharUnits getArrayCookieSize(const CXXNewExpr *E); + 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 30d4e03aba523..97a30e6331ea4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -339,7 +339,7 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e, 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 + // overflow, but that 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"); @@ -350,7 +350,7 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e, 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 + // 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. From e957c9cf0bc84d59830a67e54ffe9e8e687a2a1f Mon Sep 17 00:00:00 2001 From: jiang1997 Date: Fri, 3 Oct 2025 03:46:25 +0800 Subject: [PATCH 5/5] Remove unused getUsualDeleteParams function and update cast syntax in tests --- clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 54 ------------------------- clang/test/CIR/CodeGen/new.cpp | 4 +- 2 files changed, 2 insertions(+), 56 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 1d31c69baf8fb..4eb8ca8b5b397 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -211,60 +211,6 @@ RValue CIRGenFunction::emitCXXMemberOrOperatorCall( return emitCall(fnInfo, callee, returnValue, args, nullptr, loc); } -namespace { -/// The parameters to pass to a usual operator delete. -struct UsualDeleteParams { - TypeAwareAllocationMode typeAwareDelete = TypeAwareAllocationMode::No; - bool destroyingDelete = false; - bool size = false; - AlignedAllocationMode alignment = AlignedAllocationMode::No; -}; -} // namespace - -// FIXME(cir): this should be shared with LLVM codegen -static UsualDeleteParams getUsualDeleteParams(const FunctionDecl *fd) { - UsualDeleteParams params; - - const FunctionProtoType *fpt = fd->getType()->castAs(); - auto ai = fpt->param_type_begin(), ae = fpt->param_type_end(); - - if (fd->isTypeAwareOperatorNewOrDelete()) { - params.typeAwareDelete = TypeAwareAllocationMode::Yes; - assert(ai != ae); - ++ai; - } - - // The first argument after the type-identity parameter (if any) is - // always a void* (or C* for a destroying operator delete for class - // type C). - ++ai; - - // The next parameter may be a std::destroying_delete_t. - if (fd->isDestroyingOperatorDelete()) { - params.destroyingDelete = true; - assert(ai != ae); - ++ai; - } - - // Figure out what other parameters we should be implicitly passing. - if (ai != ae && (*ai)->isIntegerType()) { - params.size = true; - ++ai; - } else { - assert(!isTypeAwareAllocation(params.typeAwareDelete)); - } - - if (ai != ae && (*ai)->isAlignValT()) { - params.alignment = AlignedAllocationMode::Yes; - ++ai; - } else { - assert(!isTypeAwareAllocation(params.typeAwareDelete)); - } - - assert(ai == ae && "unexpected usual deallocation function parameter"); - return params; -} - static CharUnits calculateCookiePadding(CIRGenFunction &cgf, const CXXNewExpr *e) { if (!e->isArray()) diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index 7d2e716b5ffc0..91eeaef2a3e27 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -193,7 +193,7 @@ void t_new_constant_size() { // CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<16> : !u64i // CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<128> : !u64i // CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr -// CHECK: %[[TYPED_PTR:.*]] = cir.cast(bitcast, %[[RAW_PTR]] : !cir.ptr), !cir.ptr +// CHECK: %[[TYPED_PTR:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr -> !cir.ptr // CHECK: cir.store align(8) %[[TYPED_PTR]], %[[P_ADDR]] : !cir.ptr, !cir.ptr> // CHECK: cir.return // CHECK: } @@ -220,7 +220,7 @@ void t_new_multidim_constant_size() { // CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<24> : !u64i // CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<192> : !u64i // CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr -// CHECK: %[[TYPED_PTR:.*]] = cir.cast(bitcast, %[[RAW_PTR]] : !cir.ptr), !cir.ptr x 3>> +// CHECK: %[[TYPED_PTR:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr -> !cir.ptr x 3>> // CHECK: cir.store align(8) %[[TYPED_PTR]], %[[P_ADDR]] : !cir.ptr x 3>>, !cir.ptr x 3>>> // CHECK: }