diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 46b001531795..34c8437313a7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -532,6 +532,10 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { // Constant creation helpers // ------------------------- // + cir::ConstantOp getUInt8(uint8_t c, mlir::Location loc) { + auto uInt8Ty = getUInt8Ty(); + return create(loc, uInt8Ty, cir::IntAttr::get(uInt8Ty, c)); + } cir::ConstantOp getSInt32(int32_t c, mlir::Location loc) { auto sInt32Ty = getSInt32Ty(); return create(loc, sInt32Ty, diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 4bc4866e03c7..af0bb71366b9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -876,11 +876,96 @@ void CIRGenFunction::emitNewArrayInitializer( unsigned InitListElements = 0; const Expr *Init = E->getInitializer(); + QualType::DestructionKind DtorKind = ElementType.isDestructedType(); CleanupDeactivationScope deactivation(*this); + CharUnits ElementSize = getContext().getTypeSizeInChars(ElementType); + CharUnits ElementAlign = + BeginPtr.getAlignment().alignmentOfArrayElement(ElementSize); + + // Attempt to perform zero-initialization using memset. + auto TryMemsetInitialization = [&]() -> bool { + auto 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) { + llvm_unreachable("NYI"); + } + + // Create the memset. + auto CastOp = + builder.createPtrBitcast(CurPtr.getPointer(), builder.getVoidTy()); + builder.createMemSet(Loc, CastOp, builder.getUInt8(0, Loc), RemainingSize); + return true; + }; + const InitListExpr *ILE = dyn_cast(Init); - if (ILE) { - llvm_unreachable("NYI"); + const CXXParenListInitExpr *CPLIE = nullptr; + const StringLiteral *SL = nullptr; + const ObjCEncodeExpr *OCEE = nullptr; + const Expr *IgnoreParen = nullptr; + if (!ILE) { + IgnoreParen = Init->IgnoreParenImpCasts(); + CPLIE = dyn_cast(IgnoreParen); + SL = dyn_cast(IgnoreParen); + OCEE = dyn_cast(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) { + llvm_unreachable("NYI"); + } + + ArrayRef 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( + AllocType->getAsArrayTypeUnsafe())) { + llvm_unreachable("NYI"); + } + + // Enter a partial-destruction Cleanup if necessary. + if (DtorKind) { + llvm_unreachable("NYI"); + } + + CharUnits StartAlign = CurPtr.getAlignment(); + for (const Expr *IE : InitExprs) { + llvm_unreachable("NYI"); + } + + // 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(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(BeginPtr.getElementType()); } // If all elements have already been initialized, skip any further @@ -911,6 +996,12 @@ void CIRGenFunction::emitNewArrayInitializer( llvm_unreachable("NYI"); } + // If this is value-initialization, we can usually use memset. + if (isa(Init)) { + if (TryMemsetInitialization()) + return; + llvm_unreachable("NYI"); + } llvm_unreachable("NYI"); } diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index fae2c429dd0a..9134018d8673 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -143,4 +143,21 @@ void t_constant_size_nontrivial2() { // CHECK: %9 = cir.cast(bitcast, %8 : !cir.ptr), !cir.ptr // CHECK: cir.store %9, %0 : !cir.ptr, !cir.ptr> // CHECK: cir.return -// CHECK: } \ No newline at end of file +// CHECK: } + +void t_constant_size_memset_init() { + auto p = new int[16] {}; +} + +// In this test, NUM_ELEMENTS isn't used because no cookie is needed and there +// are no constructor calls needed. + +// CHECK: cir.func @_Z27t_constant_size_memset_initv() +// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<16> : !u64i +// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<64> : !u64i +// CHECK: %[[#ALLOC_PTR:]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr +// CHECK: %[[#ELEM_PTR:]] = cir.cast(bitcast, %[[#ALLOC_PTR]] : !cir.ptr), !cir.ptr +// CHECK: %[[#VOID_PTR:]] = cir.cast(bitcast, %[[#ELEM_PTR]] : !cir.ptr), !cir.ptr +// CHECK: %[[#ZERO:]] = cir.const #cir.int<0> : !u8i +// CHECK: %[[#ZERO_I32:]] = cir.cast(integral, %[[#ZERO]] : !u8i), !s32i +// CHECK: cir.libc.memset %[[#ALLOCATION_SIZE]] bytes from %[[#VOID_PTR]] set to %[[#ZERO_I32]] : !cir.ptr, !s32i, !u64i diff --git a/clang/test/CIR/Lowering/new.cpp b/clang/test/CIR/Lowering/new.cpp index 9c276f53dad3..c4c12531a6b7 100644 --- a/clang/test/CIR/Lowering/new.cpp +++ b/clang/test/CIR/Lowering/new.cpp @@ -57,3 +57,13 @@ void t_constant_size_nontrivial2() { // LLVM: store i64 3, ptr %[[COOKIE_PTR]], align 8 // LLVM: %[[ALLOCATED_PTR:.*]] = getelementptr i8, ptr %[[COOKIE_PTR]], i64 8 // LLVM: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8 + +void t_constant_size_memset_init() { + auto p = new int[16] {}; +} + +// LLVM: @_Z27t_constant_size_memset_initv() +// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8 +// LLVM: %[[ADDR:.*]] = call ptr @_Znam(i64 64) +// LLVM: call void @llvm.memset.p0.i64(ptr %[[ADDR]], i8 0, i64 64, i1 false) +// LLVM: store ptr %[[ADDR]], ptr %[[ALLOCA]], align 8