https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/178806
>From 284889dcb1164cafcc86b9b0d1b8e7ed19c766d2 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Thu, 29 Jan 2026 17:05:23 -0800 Subject: [PATCH 1/4] [CIR] Upstream support for array new with empty initializer list This adds CIR support for array new with an empty initializer list for zero-initializable types. --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 35 ++++++ clang/include/clang/CIR/MissingFeatures.h | 1 + clang/lib/CIR/CodeGen/CIRGenBuilder.h | 6 + clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 114 +++++++++++++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 12 ++ clang/test/CIR/CodeGen/new.cpp | 66 ++++++---- 6 files changed, 208 insertions(+), 26 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index ee84df93b4933..b6db00e11c639 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3540,6 +3540,41 @@ def CIR_MemCpyOp : CIR_MemOp<"libc.memcpy"> { // TODO: MemMoveOp +//===----------------------------------------------------------------------===// +// MemSetOp +//===----------------------------------------------------------------------===// + +def CIR_MemSetOp : CIR_Op<"libc.memset"> { + let summary = "Equivalent to libc's `memset`"; + let description = [{ + Given the CIR pointer, `dst`, `cir.libc.memset` will set the first `len` + bytes of the memory pointed by `dst` to the specified `val`. + + Examples: + + ```mlir + // Set 2 bytes from a record to 0: + %2 = cir.const #cir.int<2> : !u32i + %3 = cir.const #cir.int<0> : !u32i + %zero = cir.cast integral %3 : !s32i -> !u8i + cir.libc.memset %2 bytes from %record set to %zero : !cir.ptr<!void>, + !s32i, !u64i + ``` + }]; + + let arguments = (ins + Arg<CIR_VoidPtrType, "", [MemWrite]>:$dst, + CIR_SInt32:$val, + CIR_AnyFundamentalUIntType:$len + ); + + let assemblyFormat = [{ + $len `bytes` `from` $dst `set` `to` $val attr-dict + `:` qualified(type($dst)) `,` type($val) `,` type($len) + }]; +} + + //===----------------------------------------------------------------------===// // ReturnAddrOp and FrameAddrOp //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index cdd9fb950b8b2..12575f51366fa 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -238,6 +238,7 @@ struct MissingFeatures { static bool cleanupAfterErrorDiags() { return false; } static bool cleanupAppendInsts() { return false; } static bool cleanupBranchThrough() { return false; } + static bool cleanupDeactivationScope() { return false; } static bool cleanupIndexAndBIAdjustment() { return false; } static bool cleanupWithPreservedValues() { return false; } static bool cleanupsToDeactivate() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index dedb369bf3f67..51c5a238cf258 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -197,6 +197,12 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { mlir::Value src, mlir::Value len) { return cir::MemCpyOp::create(*this, loc, dst, src, len); } + + cir::MemSetOp createMemSet(mlir::Location loc, mlir::Value dst, + mlir::Value val, mlir::Value len) { + val = createIntCast(val, cir::IntType::get(getContext(), 32, true)); + return cir::MemSetOp::create(*this, loc, dst, val, len); + } // --------------------------- cir::DataMemberAttr getDataMemberAttr(cir::DataMemberType ty, diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 98cf75f0d69e0..087607f19e332 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -16,6 +16,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/Basic/OperatorKinds.h" #include "clang/CIR/MissingFeatures.h" @@ -568,13 +569,111 @@ void CIRGenFunction::emitNewArrayInitializer( if (!e->hasInitializer()) return; + Address curPtr = beginPtr; + unsigned initListElements = 0; const Expr *init = e->getInitializer(); + Address endOfInit = Address::invalid(); + QualType::DestructionKind dtorKind = elementType.isDestructedType(); + assert(!cir::MissingFeatures::cleanupDeactivationScope()); + + // Attempt to perform zero-initialization using memset. + auto tryMemsetInitialization = [&]() -> bool { + mlir::Location loc = numElements.getLoc(); + + // FIXME: If the type is a pointer-to-data-member under the Itanium ABI, + // we can initialize with a memset to -1. + if (!cgm.getTypes().isZeroInitializable(elementType)) + return false; + + // Optimization: since zero initialization will just set the memory + // to all zeroes, generate a single memset to do it in one shot. + + // Subtract out the size of any elements we've already initialized. + auto remainingSize = allocSizeWithoutCookie; + if (initListElements) { + // We know this can't overflow; we check this when doing the allocation. + unsigned initializedSize = + getContext().getTypeSizeInChars(elementType).getQuantity() * + initListElements; + cir::ConstantOp initSizeOp = + builder.getConstInt(loc, remainingSize.getType(), initializedSize); + remainingSize = builder.createSub(loc, remainingSize, initSizeOp); + } + + // Create the memset. + mlir::Value castOp = + builder.createPtrBitcast(curPtr.getPointer(), cgm.voidTy); + builder.createMemSet(loc, castOp, builder.getConstInt(loc, cgm.sInt32Ty, 0), + remainingSize); + return true; + }; + const InitListExpr *ile = dyn_cast<InitListExpr>(init); - if (ile) { - cgm.errorNYI(ile->getSourceRange(), "emitNewArrayInitializer: init list"); - return; + const CXXParenListInitExpr *cplie = nullptr; + const StringLiteral *sl = nullptr; + const ObjCEncodeExpr *ocee = nullptr; + const Expr *ignoreParen = nullptr; + if (!ile) { + ignoreParen = init->IgnoreParenImpCasts(); + cplie = dyn_cast<CXXParenListInitExpr>(ignoreParen); + sl = dyn_cast<StringLiteral>(ignoreParen); + ocee = dyn_cast<ObjCEncodeExpr>(ignoreParen); + } + // If the initializer is an initializer list, first do the explicit elements. + if (ile || cplie || sl || ocee) { + // Initializing from a (braced) string literal is a special case; the init + // list element does not initialize a (single) array element. + if ((ile && ile->isStringLiteralInit()) || sl || ocee) { + cgm.errorNYI(ile->getSourceRange(), + "emitNewArrayInitializer: string literal init"); + return; + } + + ArrayRef<const Expr *> initExprs = + ile ? ile->inits() : cplie->getInitExprs(); + initListElements = initExprs.size(); + + // If this is a multi-dimensional array new, we will initialize multiple + // elements with each init list element. + QualType allocType = e->getAllocatedType(); + if (const ConstantArrayType *cat = dyn_cast_or_null<ConstantArrayType>( + allocType->getAsArrayTypeUnsafe())) { + cgm.errorNYI(ile->getSourceRange(), + "emitNewArrayInitializer: constant array init"); + return; + } + + // Enter a partial-destruction Cleanup if necessary. + if (dtorKind) { + cgm.errorNYI(ile->getSourceRange(), + "emitNewArrayInitializer: init requires dtor"); + return; + } + + if (!initExprs.empty()) { + cgm.errorNYI(ile->getSourceRange(), + "emitNewArrayInitializer: non-empty init list"); + return; + } + + // The remaining elements are filled with the array filler expression. + init = ile ? ile->getArrayFiller() : cplie->getArrayFiller(); + + // Extract the initializer for the individual array elements by pulling + // out the array filler from all the nested initializer lists. This avoids + // generating a nested loop for the initialization. + while (init && init->getType()->isConstantArrayType()) { + auto *subIle = dyn_cast<InitListExpr>(init); + if (!subIle) + break; + assert(subIle->getNumInits() == 0 && "explicit inits in array filler?"); + init = subIle->getArrayFiller(); + } + + // Switch back to initializing one base element at a time. + curPtr = curPtr.withElementType(builder, beginPtr.getElementType()); } // If all elements have already been initialized, skip any further @@ -609,6 +708,15 @@ void CIRGenFunction::emitNewArrayInitializer( return; } + // If this is value-initialization, we can usually use memset. + if (isa<ImplicitValueInitExpr>(init)) { + if (tryMemsetInitialization()) + return; + cgm.errorNYI(init->getSourceRange(), + "emitNewArrayInitializer: implicit value init"); + return; + } + cgm.errorNYI(init->getSourceRange(), "emitNewArrayInitializer: unsupported initializer"); return; diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 091489c404642..871eb2920d170 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -196,6 +196,18 @@ mlir::LogicalResult CIRToLLVMMemCpyOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMMemSetOpLowering::matchAndRewrite( + cir::MemSetOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + auto converted = mlir::LLVM::TruncOp::create( + rewriter, op.getLoc(), mlir::IntegerType::get(op.getContext(), 8), + adaptor.getVal()); + rewriter.replaceOpWithNewOp<mlir::LLVM::MemsetOp>(op, adaptor.getDst(), + converted, adaptor.getLen(), + /*isVolatile=*/false); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMSqrtOpLowering::matchAndRewrite( cir::SqrtOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index 80a4b476226af..c097d88c9114d 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -187,8 +187,8 @@ void t_new_constant_size() { // CHECK: cir.func{{.*}} @_Z19t_new_constant_sizev() // CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!cir.double>, !cir.ptr<!cir.ptr<!cir.double>>, ["p", init] {alignment = 8 : i64} -// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<128> : !u64i -// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<128> : !u64i +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> // CHECK: %[[TYPED_PTR:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.double> // CHECK: cir.store align(8) %[[TYPED_PTR]], %[[P_ADDR]] : !cir.ptr<!cir.double>, !cir.ptr<!cir.ptr<!cir.double>> // CHECK: cir.return @@ -215,14 +215,14 @@ void t_constant_size_nontrivial() { // CHECK: cir.func{{.*}} @_Z26t_constant_size_nontrivialv() // CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["p", init] {alignment = 8 : i64} -// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<3> : !u64i -// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<11> : !u64i -// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<3> : !u64i +// CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<11> : !u64i +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> // CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>> // CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_BASE]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i> -// CHECK: cir.store align(8) %[[#NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i> -// CHECK: %[[#COOKIE_SIZE:]] = cir.const #cir.int<8> : !s32i -// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[#COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> +// CHECK: cir.store align(8) %[[NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i> +// CHECK: %[[COOKIE_SIZE:.*]] = cir.const #cir.int<8> : !s32i +// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> // CHECK: %[[DATA_PTR_VOID:.*]] = cir.cast bitcast %[[DATA_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!void> // CHECK: %[[DATA_PTR:.*]] = cir.cast bitcast %[[DATA_PTR_VOID]] : !cir.ptr<!void> -> !cir.ptr<!rec_C> // CHECK: cir.store align(8) %[[DATA_PTR]], %[[P_ADDR]] : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>> @@ -255,14 +255,14 @@ void t_constant_size_nontrivial2() { // CHECK: cir.func{{.*}} @_Z27t_constant_size_nontrivial2v() // CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_D>, !cir.ptr<!cir.ptr<!rec_D>>, ["p", init] {alignment = 8 : i64} -// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<3> : !u64i -// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<20> : !u64i -// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<3> : !u64i +// CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<20> : !u64i +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> // CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>> // CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_BASE]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i> -// CHECK: cir.store align(8) %[[#NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i> -// CHECK: %[[#COOKIE_SIZE:]] = cir.const #cir.int<8> : !s32i -// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[#COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> +// CHECK: cir.store align(8) %[[NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i> +// CHECK: %[[COOKIE_SIZE:.*]] = cir.const #cir.int<8> : !s32i +// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> // CHECK: %[[DATA_PTR_VOID:.*]] = cir.cast bitcast %[[DATA_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!void> // CHECK: %[[DATA_PTR:.*]] = cir.cast bitcast %[[DATA_PTR_VOID]] : !cir.ptr<!void> -> !cir.ptr<!rec_D> // CHECK: cir.store align(8) %[[DATA_PTR]], %[[P_ADDR]] : !cir.ptr<!rec_D>, !cir.ptr<!cir.ptr<!rec_D>> @@ -287,16 +287,16 @@ void t_align16_nontrivial() { // CHECK: cir.func{{.*}} @_Z20t_align16_nontrivialv() // CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_E>, !cir.ptr<!cir.ptr<!rec_E>>, ["p", init] {alignment = 8 : i64} -// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<2> : !u64i -// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<48> : !u64i -// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<2> : !u64i +// CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<48> : !u64i +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> // CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>> // CHECK: %[[COOKIE_OFFSET:.*]] = cir.const #cir.int<8> : !s32i // CHECK: %[[COOKIE_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[COOKIE_OFFSET]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> // CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i> -// CHECK: cir.store align(8) %[[#NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i> -// CHECK: %[[#COOKIE_SIZE:]] = cir.const #cir.int<16> : !s32i -// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[#COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> +// CHECK: cir.store align(8) %[[NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i> +// CHECK: %[[COOKIE_SIZE:.*]] = cir.const #cir.int<16> : !s32i +// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>> // CHECK: %[[DATA_PTR_VOID:.*]] = cir.cast bitcast %[[DATA_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!void> // CHECK: %[[DATA_PTR:.*]] = cir.cast bitcast %[[DATA_PTR_VOID]] : !cir.ptr<!void> -> !cir.ptr<!rec_E> // CHECK: cir.store align(8) %[[DATA_PTR]], %[[P_ADDR]] : !cir.ptr<!rec_E>, !cir.ptr<!cir.ptr<!rec_E>> @@ -324,10 +324,10 @@ void t_new_multidim_constant_size() { auto p = new double[2][3][4]; } -// CHECK: cir.func{{.*}} @_Z28t_new_multidim_constant_sizev() +// CHECK: cir.func{{.*}} @_Z28t_new_multidim_constant_sizev() // CHECK: %[[P_ADDR:.*]] = 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: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<192> : !u64i -// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<192> : !u64i +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> // CHECK: %[[TYPED_PTR:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.array<!cir.array<!cir.double x 4> x 3>> // CHECK: cir.store align(8) %[[TYPED_PTR]], %[[P_ADDR]] : !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: } @@ -341,3 +341,23 @@ void t_new_multidim_constant_size() { // 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 + +void t_constant_size_memset_init() { + auto p = new int[16] {}; +} + +// CHECK: cir.func {{.*}} @_Z27t_constant_size_memset_initv() +// CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<64> : !u64i +// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> +// CHECK: %[[ELEM_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : !cir.ptr<!void> -> !cir.ptr<!s32i> +// CHECK: %[[VOID_PTR:.*]] = cir.cast bitcast %[[ELEM_PTR]] : !cir.ptr<!s32i> -> !cir.ptr<!void> +// CHECK: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CHECK: cir.libc.memset %[[ALLOCATION_SIZE]] bytes from %[[VOID_PTR]] set to %[[ZERO]] : !cir.ptr<!void>, !s32i, !u64i + +// LLVM: define {{.*}} void @_Z27t_constant_size_memset_initv() +// LLVM: %[[P:.*]] = call ptr @_Znam(i64 64) +// LLVM: call void @llvm.memset.p0.i64(ptr %[[P]], i8 0, i64 64, i1 false) + +// 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) >From c4d56169dedf9fbb638c0c8aa8bbe76ef800196d Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Thu, 29 Jan 2026 18:01:52 -0800 Subject: [PATCH 2/4] Fix unused variables --- clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 087607f19e332..7f87d9b0f73b7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -574,7 +574,6 @@ void CIRGenFunction::emitNewArrayInitializer( unsigned initListElements = 0; const Expr *init = e->getInitializer(); - Address endOfInit = Address::invalid(); QualType::DestructionKind dtorKind = elementType.isDestructedType(); assert(!cir::MissingFeatures::cleanupDeactivationScope()); @@ -640,6 +639,7 @@ void CIRGenFunction::emitNewArrayInitializer( QualType allocType = e->getAllocatedType(); if (const ConstantArrayType *cat = dyn_cast_or_null<ConstantArrayType>( allocType->getAsArrayTypeUnsafe())) { + (void)cat; cgm.errorNYI(ile->getSourceRange(), "emitNewArrayInitializer: constant array init"); return; >From a57c4cbf5d03311cdb63c445b53b14ce0a4cc974 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Fri, 30 Jan 2026 11:01:30 -0800 Subject: [PATCH 3/4] Address review feedback --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 16 +++++++--------- clang/lib/CIR/CodeGen/CIRGenBuilder.h | 2 +- clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 2 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 9 +++------ clang/test/CIR/CodeGen/new.cpp | 4 ++-- 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index b6db00e11c639..344f2d20bdf9c 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3553,28 +3553,26 @@ def CIR_MemSetOp : CIR_Op<"libc.memset"> { Examples: ```mlir - // Set 2 bytes from a record to 0: - %2 = cir.const #cir.int<2> : !u32i - %3 = cir.const #cir.int<0> : !u32i - %zero = cir.cast integral %3 : !s32i -> !u8i - cir.libc.memset %2 bytes from %record set to %zero : !cir.ptr<!void>, - !s32i, !u64i + // Set 2 bytes in a record to 0: + %len = cir.const #cir.int<2> : !u32i + %zero = cir.const #cir.int<0> : !u8i + cir.libc.memset %len bytes at %record to %zero : !cir.ptr<!void>, + !s32i, !u64i ``` }]; let arguments = (ins Arg<CIR_VoidPtrType, "", [MemWrite]>:$dst, - CIR_SInt32:$val, + CIR_UInt8:$val, CIR_AnyFundamentalUIntType:$len ); let assemblyFormat = [{ - $len `bytes` `from` $dst `set` `to` $val attr-dict + $len `bytes` `at` $dst `to` $val attr-dict `:` qualified(type($dst)) `,` type($val) `,` type($len) }]; } - //===----------------------------------------------------------------------===// // ReturnAddrOp and FrameAddrOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 51c5a238cf258..af9c4fcdeb8c7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -200,7 +200,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { cir::MemSetOp createMemSet(mlir::Location loc, mlir::Value dst, mlir::Value val, mlir::Value len) { - val = createIntCast(val, cir::IntType::get(getContext(), 32, true)); + val = createIntCast(val, getUInt8Ty()); return cir::MemSetOp::create(*this, loc, dst, val, len); } // --------------------------- diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 7f87d9b0f73b7..3731773cffa45 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -604,7 +604,7 @@ void CIRGenFunction::emitNewArrayInitializer( // Create the memset. mlir::Value castOp = builder.createPtrBitcast(curPtr.getPointer(), cgm.voidTy); - builder.createMemSet(loc, castOp, builder.getConstInt(loc, cgm.sInt32Ty, 0), + builder.createMemSet(loc, castOp, builder.getConstInt(loc, cgm.uInt8Ty, 0), remainingSize); return true; }; diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 871eb2920d170..485f61d3d6a9d 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -199,12 +199,9 @@ mlir::LogicalResult CIRToLLVMMemCpyOpLowering::matchAndRewrite( mlir::LogicalResult CIRToLLVMMemSetOpLowering::matchAndRewrite( cir::MemSetOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { - auto converted = mlir::LLVM::TruncOp::create( - rewriter, op.getLoc(), mlir::IntegerType::get(op.getContext(), 8), - adaptor.getVal()); - rewriter.replaceOpWithNewOp<mlir::LLVM::MemsetOp>(op, adaptor.getDst(), - converted, adaptor.getLen(), - /*isVolatile=*/false); + rewriter.replaceOpWithNewOp<mlir::LLVM::MemsetOp>( + op, adaptor.getDst(), adaptor.getVal(), adaptor.getLen(), + /*isVolatile=*/false); return mlir::success(); } diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index c097d88c9114d..9f454770e3960 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -351,8 +351,8 @@ void t_constant_size_memset_init() { // CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void> // CHECK: %[[ELEM_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : !cir.ptr<!void> -> !cir.ptr<!s32i> // CHECK: %[[VOID_PTR:.*]] = cir.cast bitcast %[[ELEM_PTR]] : !cir.ptr<!s32i> -> !cir.ptr<!void> -// CHECK: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i -// CHECK: cir.libc.memset %[[ALLOCATION_SIZE]] bytes from %[[VOID_PTR]] set to %[[ZERO]] : !cir.ptr<!void>, !s32i, !u64i +// CHECK: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i +// CHECK: cir.libc.memset %[[ALLOCATION_SIZE]] bytes at %[[VOID_PTR]] to %[[ZERO]] : !cir.ptr<!void>, !u8i, !u64i // LLVM: define {{.*}} void @_Z27t_constant_size_memset_initv() // LLVM: %[[P:.*]] = call ptr @_Znam(i64 64) >From f46ce89d21563ef580c65f2e415af71d88453b3c Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Fri, 30 Jan 2026 12:08:06 -0800 Subject: [PATCH 4/4] Replace cast with assert --- clang/lib/CIR/CodeGen/CIRGenBuilder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index af9c4fcdeb8c7..99a8152e7d365 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -200,7 +200,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { cir::MemSetOp createMemSet(mlir::Location loc, mlir::Value dst, mlir::Value val, mlir::Value len) { - val = createIntCast(val, getUInt8Ty()); + assert(val.getType() == getUInt8Ty()); return cir::MemSetOp::create(*this, loc, dst, val, len); } // --------------------------- _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
