https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/149142
>From 9814dc290952184c3a1080ea49ddd29b603ecdae Mon Sep 17 00:00:00 2001 From: Morris Hafner <mhaf...@nvidia.com> Date: Wed, 16 Jul 2025 18:48:52 +0200 Subject: [PATCH 1/5] [CIR] Add support for array constructors This patch upstreams support for creating arrays of classes that require calling a constructor. * Adds the ArrayCtor operation * New lowering pass for lowering ArrayCtor to a loop --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 38 +++++- .../CIR/Dialect/IR/CIRTypeConstraints.td | 8 ++ clang/lib/CIR/CodeGen/CIRGenClass.cpp | 110 ++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 59 +++++----- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 45 +++++++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 12 ++ .../Dialect/Transforms/LoweringPrepare.cpp | 78 ++++++++++++- clang/test/CIR/CodeGen/array-ctor.cpp | 70 +++++++++++ clang/test/CIR/IR/array-ctor.cir | 29 +++++ 9 files changed, 417 insertions(+), 32 deletions(-) create mode 100644 clang/test/CIR/CodeGen/array-ctor.cpp create mode 100644 clang/test/CIR/IR/array-ctor.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 694e3691c9361..096537fc78839 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -607,7 +607,7 @@ def CIR_ConditionOp : CIR_Op<"condition", [ //===----------------------------------------------------------------------===// defvar CIR_YieldableScopes = [ - "CaseOp", "DoWhileOp", "ForOp", "IfOp", "ScopeOp", "SwitchOp", + "ArrayCtor", "CaseOp", "DoWhileOp", "ForOp", "IfOp", "ScopeOp", "SwitchOp", "TernaryOp", "WhileOp" ]; @@ -2228,6 +2228,42 @@ def CIR_TrapOp : CIR_Op<"trap", [Terminator]> { let assemblyFormat = "attr-dict"; } +//===----------------------------------------------------------------------===// +// ArrayCtor +//===----------------------------------------------------------------------===// + +class CIR_ArrayInitDestroy<string mnemonic> : CIR_Op<mnemonic> { + let arguments = (ins + Arg<CIR_PtrToArray, "array address", [MemWrite, MemRead]>:$addr + ); + + let regions = (region SizedRegion<1>:$body); + let assemblyFormat = [{ + `(` $addr `:` qualified(type($addr)) `)` $body attr-dict + }]; + + let builders = [ + OpBuilder<(ins "mlir::Value":$addr, + "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$regionBuilder), [{ + assert(regionBuilder && "builder callback expected"); + mlir::OpBuilder::InsertionGuard guard($_builder); + mlir::Region *r = $_state.addRegion(); + $_state.addOperands(ValueRange{addr}); + $_builder.createBlock(r); + regionBuilder($_builder, $_state.location); + }]> + ]; +} + +def CIR_ArrayCtor : CIR_ArrayInitDestroy<"array.ctor"> { + let summary = "Initialize array elements with C++ constructors"; + let description = [{ + Initialize each array element using the same C++ constructor. This + operation has one region, with one single block. The block has an + incoming argument for the current array index to initialize. + }]; +} + //===----------------------------------------------------------------------===// // VecCreate //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td index 2bf77583465a6..d7d55dfbc0654 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td @@ -165,6 +165,12 @@ def CIR_AnyIntOrFloatType : AnyTypeOf<[CIR_AnyFloatType, CIR_AnyIntType], def CIR_AnyComplexType : CIR_TypeBase<"::cir::ComplexType", "complex type">; +//===----------------------------------------------------------------------===// +// Array Type predicates +//===----------------------------------------------------------------------===// + +def CIR_AnyArrayType : CIR_TypeBase<"::cir::ArrayType", "array type">; + //===----------------------------------------------------------------------===// // Pointer Type predicates //===----------------------------------------------------------------------===// @@ -216,6 +222,8 @@ def CIR_PtrToIntOrFloatType : CIR_PtrToType<CIR_AnyIntOrFloatType>; def CIR_PtrToComplexType : CIR_PtrToType<CIR_AnyComplexType>; +def CIR_PtrToArray : CIR_PtrToType<CIR_AnyArrayType>; + //===----------------------------------------------------------------------===// // Vector Type predicates //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index fbf53dbdf385b..5a661bf11b114 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -12,6 +12,7 @@ #include "CIRGenCXXABI.h" #include "CIRGenFunction.h" +#include "CIRGenValue.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" @@ -311,6 +312,115 @@ void CIRGenFunction::emitInitializerForField(FieldDecl *field, LValue lhs, assert(!cir::MissingFeatures::requiresCleanups()); } +/// Emit a loop to call a particular constructor for each of several members +/// of an array. +/// +/// \param ctor the constructor to call for each element +/// \param arrayType the type of the array to initialize +/// \param arrayBegin an arrayType* +/// \param zeroInitialize true if each element should be +/// zero-initialized before it is constructed +void CIRGenFunction::emitCXXAggrConstructorCall( + const CXXConstructorDecl *ctor, const clang::ArrayType *arrayType, + Address arrayBegin, const CXXConstructExpr *e, bool newPointerIsChecked, + bool zeroInitialize) { + QualType elementType; + mlir::Value numElements = emitArrayLength(arrayType, elementType, arrayBegin); + emitCXXAggrConstructorCall(ctor, numElements, arrayBegin, e, + newPointerIsChecked, zeroInitialize); +} + +/// Emit a loop to call a particular constructor for each of several members +/// of an array. +/// +/// \param ctor the constructor to call for each element +/// \param numElements the number of elements in the array; +/// may be zero +/// \param arrayBase a T*, where T is the type constructed by ctor +/// \param zeroInitialize true if each element should be +/// zero-initialized before it is constructed +void CIRGenFunction::emitCXXAggrConstructorCall( + const CXXConstructorDecl *ctor, mlir::Value numElements, Address arrayBase, + const CXXConstructExpr *e, bool newPointerIsChecked, bool zeroInitialize) { + // It's legal for numElements to be zero. This can happen both + // dynamically, because x can be zero in 'new A[x]', and statically, + // because of GCC extensions that permit zero-length arrays. There + // are probably legitimate places where we could assume that this + // doesn't happen, but it's not clear that it's worth it. + + // Optimize for a constant count. + auto constantCount = dyn_cast<cir::ConstantOp>(numElements.getDefiningOp()); + if (constantCount) { + auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constantCount.getValue()); + // Just skip out if the constant count is zero. + if (constIntAttr && constIntAttr.getUInt() == 0) + return; + // Otherwise, emit the check. + } else { + cgm.errorNYI(e->getSourceRange(), "dynamic-length array expression"); + } + + auto arrayTy = mlir::dyn_cast<cir::ArrayType>(arrayBase.getElementType()); + assert(arrayTy && "expected array type"); + mlir::Type elementType = arrayTy.getElementType(); + cir::PointerType ptrToElmType = builder.getPointerTo(elementType); + + // Tradional LLVM codegen emits a loop here. CIR lowers to a loop as part of + // LoweringPrepare. + + // The alignment of the base, adjusted by the size of a single element, + // provides a conservative estimate of the alignment of every element. + // (This assumes we never start tracking offsetted alignments.) + // + // Note that these are complete objects and so we don't need to + // use the non-virtual size or alignment. + QualType type = getContext().getTypeDeclType(ctor->getParent()); + CharUnits eltAlignment = arrayBase.getAlignment().alignmentOfArrayElement( + getContext().getTypeSizeInChars(type)); + + // Zero initialize the storage, if requested. + if (zeroInitialize) + emitNullInitialization(*currSrcLoc, arrayBase, type); + + // C++ [class.temporary]p4: + // There are two contexts in which temporaries are destroyed at a different + // point than the end of the full-expression. The first context is when a + // default constructor is called to initialize an element of an array. + // If the constructor has one or more default arguments, the destruction of + // every temporary created in a default argument expression is sequenced + // before the construction of the next array element, if any. + { + assert(!cir::MissingFeatures::runCleanupsScope()); + + // Evaluate the constructor and its arguments in a regular + // partial-destroy cleanup. + if (getLangOpts().Exceptions && + !ctor->getParent()->hasTrivialDestructor()) { + cgm.errorNYI(e->getSourceRange(), "partial array cleanups"); + } + + // Emit the constructor call that will execute for every array element. + auto arrayOp = builder.createPtrBitcast(arrayBase.getPointer(), arrayTy); + builder.create<cir::ArrayCtor>( + *currSrcLoc, arrayOp, [&](mlir::OpBuilder &b, mlir::Location loc) { + auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc); + Address curAddr = Address(arg, elementType, eltAlignment); + assert(!cir::MissingFeatures::sanitizers()); + auto currAVS = AggValueSlot::forAddr( + curAddr, type.getQualifiers(), AggValueSlot::IsDestructed, + AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap, + AggValueSlot::IsNotZeroed); + emitCXXConstructorCall(ctor, Ctor_Complete, + /*ForVirtualBase=*/false, + /*Delegating=*/false, currAVS, e); + builder.create<cir::YieldOp>(loc); + }); + } + + if (constantCount.use_empty()) + constantCount.erase(); +} + void CIRGenFunction::emitDelegateCXXConstructorCall( const CXXConstructorDecl *ctor, CXXCtorType ctorType, const FunctionArgList &args, SourceLocation loc) { diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 1f64801926887..7ff5f26be21b4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1657,37 +1657,38 @@ void CIRGenFunction::emitCXXConstructExpr(const CXXConstructExpr *e, return; } - if (getContext().getAsArrayType(e->getType())) { - cgm.errorNYI(e->getSourceRange(), "emitCXXConstructExpr: array type"); - return; - } + if (const ArrayType *arrayType = getContext().getAsArrayType(e->getType())) { + assert(!cir::MissingFeatures::sanitizers()); + emitCXXAggrConstructorCall(cd, arrayType, dest.getAddress(), e, false); + } else { - clang::CXXCtorType type = Ctor_Complete; - bool forVirtualBase = false; - bool delegating = false; - - switch (e->getConstructionKind()) { - case CXXConstructionKind::Complete: - type = Ctor_Complete; - break; - case CXXConstructionKind::Delegating: - // We should be emitting a constructor; GlobalDecl will assert this - type = curGD.getCtorType(); - delegating = true; - break; - case CXXConstructionKind::VirtualBase: - // This should just set 'forVirtualBase' to true and fall through, but - // virtual base class support is otherwise missing, so this needs to wait - // until it can be tested. - cgm.errorNYI(e->getSourceRange(), - "emitCXXConstructExpr: virtual base constructor"); - return; - case CXXConstructionKind::NonVirtualBase: - type = Ctor_Base; - break; - } + clang::CXXCtorType type = Ctor_Complete; + bool forVirtualBase = false; + bool delegating = false; - emitCXXConstructorCall(cd, type, forVirtualBase, delegating, dest, e); + switch (e->getConstructionKind()) { + case CXXConstructionKind::Complete: + type = Ctor_Complete; + break; + case CXXConstructionKind::Delegating: + // We should be emitting a constructor; GlobalDecl will assert this + type = curGD.getCtorType(); + delegating = true; + break; + case CXXConstructionKind::VirtualBase: + // This should just set 'forVirtualBase' to true and fall through, but + // virtual base class support is otherwise missing, so this needs to wait + // until it can be tested. + cgm.errorNYI(e->getSourceRange(), + "emitCXXConstructExpr: virtual base constructor"); + return; + case CXXConstructionKind::NonVirtualBase: + type = Ctor_Base; + break; + } + + emitCXXConstructorCall(cd, type, forVirtualBase, delegating, dest, e); + } } RValue CIRGenFunction::emitReferenceBindingToExpr(const Expr *e) { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 3e69e5673dd86..8e073ef22cc4e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -808,4 +808,49 @@ bool CIRGenFunction::shouldNullCheckClassCastValue(const CastExpr *ce) { return true; } +/// Computes the length of an array in elements, as well as the base +/// element type and a properly-typed first element pointer. +mlir::Value +CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType, + QualType &baseType, Address &addr) { + const clang::ArrayType *arrayType = origArrayType; + + // If it's a VLA, we have to load the stored size. Note that + // this is the size of the VLA in bytes, not its size in elements. + if (isa<VariableArrayType>(arrayType)) { + cgm.errorNYI(*currSrcLoc, "VLAs"); + return builder.getConstInt(*currSrcLoc, SizeTy, 0); + } + + uint64_t countFromCLAs = 1; + QualType eltType; + + auto cirArrayType = mlir::dyn_cast<cir::ArrayType>(addr.getElementType()); + + while (cirArrayType) { + assert(isa<ConstantArrayType>(arrayType)); + countFromCLAs *= cirArrayType.getSize(); + eltType = arrayType->getElementType(); + + cirArrayType = + mlir::dyn_cast<cir::ArrayType>(cirArrayType.getElementType()); + + arrayType = getContext().getAsArrayType(arrayType->getElementType()); + assert((!cirArrayType || arrayType) && + "CIR and Clang types are out-of-sync"); + } + + if (arrayType) { + // From this point onwards, the Clang array type has been emitted + // as some other type (probably a packed struct). Compute the array + // size, and just emit the 'begin' expression as a bitcast. + cgm.errorNYI(*currSrcLoc, "length for non-array underlying types"); + } + + baseType = eltType; + auto numElements = builder.getConstInt(*currSrcLoc, SizeTy, countFromCLAs); + + return numElements; +} + } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 2aceeef793385..83e7f63773c3c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -766,6 +766,8 @@ class CIRGenFunction : public CIRGenTypeCache { /// even if no aggregate location is provided. RValue emitAnyExprToTemp(const clang::Expr *e); + mlir::Value emitArrayLength(const clang::ArrayType *arrayType, + QualType &baseType, Address &addr); LValue emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e); Address emitArrayToPointerDecay(const Expr *array); @@ -843,6 +845,16 @@ class CIRGenFunction : public CIRGenTypeCache { void emitCXXConstructExpr(const clang::CXXConstructExpr *e, AggValueSlot dest); + void emitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, + const clang::ArrayType *arrayType, + Address arrayBegin, const CXXConstructExpr *e, + bool newPointerIsChecked, + bool zeroInitialize = false); + void emitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, + mlir::Value numElements, Address arrayBase, + const CXXConstructExpr *e, + bool newPointerIsChecked, + bool zeroInitialize); void emitCXXConstructorCall(const clang::CXXConstructorDecl *d, clang::CXXCtorType type, bool forVirtualBase, bool delegating, AggValueSlot thisAVS, diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 8f848c7345610..3f0291729c0f5 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -8,6 +8,7 @@ #include "PassDetail.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" #include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" @@ -25,6 +26,7 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { void runOnOp(mlir::Operation *op); void lowerUnaryOp(cir::UnaryOp op); + void lowerArrayCtor(ArrayCtor op); }; } // namespace @@ -71,9 +73,81 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { op.erase(); } +static void lowerArrayDtorCtorIntoLoop(CIRBaseBuilderTy &builder, + mlir::Operation *op, mlir::Type eltTy, + mlir::Value arrayAddr, + uint64_t arrayLen) { + // Generate loop to call into ctor/dtor for every element. + Location loc = op->getLoc(); + + // TODO: instead of fixed integer size, create alias for PtrDiffTy and unify + // with CIRGen stuff. + auto ptrDiffTy = + cir::IntType::get(builder.getContext(), 64, /*isSigned=*/false); + auto numArrayElementsConst = builder.create<cir::ConstantOp>( + loc, ptrDiffTy, cir::IntAttr::get(ptrDiffTy, arrayLen)); + + auto begin = builder.create<cir::CastOp>( + loc, eltTy, cir::CastKind::array_to_ptrdecay, arrayAddr); + mlir::Value end = builder.create<cir::PtrStrideOp>(loc, eltTy, begin, + numArrayElementsConst); + + mlir::Value tmpAddr = builder.createAlloca( + loc, /*addr type*/ builder.getPointerTo(eltTy), + /*var type*/ eltTy, "__array_idx", builder.getAlignmentAttr(1)); + builder.createStore(loc, begin, tmpAddr); + + cir::DoWhileOp loop = builder.createDoWhile( + loc, + /*condBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + auto currentElement = b.create<cir::LoadOp>(loc, eltTy, tmpAddr); + mlir::Type boolTy = cir::BoolType::get(b.getContext()); + auto cmp = builder.create<cir::CmpOp>(loc, boolTy, cir::CmpOpKind::eq, + currentElement, end); + builder.createCondition(cmp); + }, + /*bodyBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + auto currentElement = b.create<cir::LoadOp>(loc, eltTy, tmpAddr); + + CallOp ctorCall; + op->walk([&](CallOp c) { ctorCall = c; }); + assert(ctorCall && "expected ctor call"); + + auto one = builder.create<cir::ConstantOp>( + loc, ptrDiffTy, cir::IntAttr::get(ptrDiffTy, 1)); + + ctorCall->moveAfter(one); + ctorCall->setOperand(0, currentElement); + + // Advance pointer and store them to temporary variable + auto nextElement = + builder.create<cir::PtrStrideOp>(loc, eltTy, currentElement, one); + builder.createStore(loc, nextElement, tmpAddr); + builder.createYield(loc); + }); + + op->replaceAllUsesWith(loop); + op->erase(); +} + +void LoweringPreparePass::lowerArrayCtor(ArrayCtor op) { + CIRBaseBuilderTy builder(getContext()); + builder.setInsertionPointAfter(op.getOperation()); + + Type eltTy = op->getRegion(0).getArgument(0).getType(); + auto arrayLen = + mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize(); + lowerArrayDtorCtorIntoLoop(builder, op, eltTy, op.getAddr(), arrayLen); +} + void LoweringPreparePass::runOnOp(mlir::Operation *op) { - if (auto unary = dyn_cast<cir::UnaryOp>(op)) + if (auto unary = dyn_cast<cir::UnaryOp>(op)) { lowerUnaryOp(unary); + } else if (auto arrayCtor = dyn_cast<ArrayCtor>(op)) { + lowerArrayCtor(arrayCtor); + } } void LoweringPreparePass::runOnOperation() { @@ -82,7 +156,7 @@ void LoweringPreparePass::runOnOperation() { llvm::SmallVector<mlir::Operation *> opsToTransform; op->walk([&](mlir::Operation *op) { - if (mlir::isa<cir::UnaryOp>(op)) + if (mlir::isa<cir::UnaryOp, ArrayCtor>(op)) opsToTransform.push_back(op); }); diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp new file mode 100644 index 0000000000000..0a2661248f908 --- /dev/null +++ b/clang/test/CIR/CodeGen/array-ctor.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +struct S { + S(); +}; + +void foo() { + S s[42]; +} + +// CIR: cir.func dso_local @_Z3foov() +// CIR: %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] +// CIR: %[[CONST42:.*]] = cir.const #cir.int<42> : !u64i +// CIR: %[[DECAY:.*]] = cir.cast(array_to_ptrdecay, %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 42>>), !cir.ptr<!rec_S> +// CIR: %[[END_PTR:.*]] = cir.ptr_stride(%[[DECAY]] : !cir.ptr<!rec_S>, %[[CONST42]] : !u64i), !cir.ptr<!rec_S> +// CIR: %[[ITER:.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["__array_idx"] +// CIR: cir.store %[[DECAY]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>> +// CIR: cir.do { +// CIR: %[[CURRENT:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: %[[CONST1:.*]] = cir.const #cir.int<1> : !u64i +// CIR: cir.call @_ZN1SC1Ev(%[[CURRENT]]) : (!cir.ptr<!rec_S>) -> () +// CIR: %[[NEXT:.*]] = cir.ptr_stride(%[[CURRENT]] : !cir.ptr<!rec_S>, %[[CONST1]] : !u64i), !cir.ptr<!rec_S> +// CIR: cir.store %[[NEXT]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[CURRENT2:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: %[[CMP:.*]] = cir.cmp(eq, %[[CURRENT2]], %[[END_PTR]]) : !cir.ptr<!rec_S>, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } +// CIR: cir.return +// CIR: } + +// LLVM: define dso_local void @_Z3foov() +// LLVM: %[[ARRAY:.*]] = alloca [42 x %struct.S] +// LLVM: %[[START:.*]] = getelementptr %struct.S, ptr %[[ARRAY]], i32 0 +// LLVM: %[[END:.*]] = getelementptr %struct.S, ptr %[[START]], i64 42 +// LLVM: %[[ITER:.*]] = alloca ptr +// LLVM: store ptr %[[START]], ptr %[[ITER]] +// LLVM: br label %[[LOOP:.*]] +// LLVM: [[COND:.*]]: +// LLVM: %[[CURRENT_CHECK:.*]] = load ptr, ptr %[[ITER]] +// LLVM: %[[DONE:.*]] = icmp eq ptr %[[CURRENT_CHECK]], %[[END]] +// LLVM: br i1 %[[DONE]], label %[[LOOP]], label %[[EXIT:.*]] +// LLVM: [[LOOP]]: +// LLVM: %[[CURRENT:.*]] = load ptr, ptr %[[ITER]] +// LLVM: call void @_ZN1SC1Ev(ptr %[[CURRENT]]) +// LLVM: %[[NEXT:.*]] = getelementptr %struct.S, ptr %[[CURRENT]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[ITER]] +// LLVM: br label %[[COND]] +// LLVM: [[EXIT]]: +// LLVM: ret void + +// OGCG: define dso_local void @_Z3foov() +// OGCG: %[[ARRAY:.*]] = alloca [42 x %struct.S] +// OGCG: %[[START:.*]] = getelementptr{{.*}} %struct.S{{.*}} +// OGCG: %[[END:.*]] = getelementptr{{.*}} %struct.S{{.*}} i64 42 +// OGCG: br label %[[LOOP:.*]] +// OGCG: [[LOOP]]: +// OGCG: %[[CURRENT:.*]] = phi ptr [ %[[START]], %{{.*}} ], [ %[[NEXT:.*]], %[[LOOP]] ] +// OGCG: call void @_ZN1SC1Ev(ptr{{.*}}) +// OGCG: %[[NEXT]] = getelementptr{{.*}} %struct.S{{.*}} i64 1 +// OGCG: %[[DONE:.*]] = icmp eq ptr %[[NEXT]], %[[END]] +// OGCG: br i1 %[[DONE]], label %[[EXIT:.*]], label %[[LOOP]] +// OGCG: [[EXIT]]: +// OGCG: ret void diff --git a/clang/test/CIR/IR/array-ctor.cir b/clang/test/CIR/IR/array-ctor.cir new file mode 100644 index 0000000000000..a039d7d2ca6b0 --- /dev/null +++ b/clang/test/CIR/IR/array-ctor.cir @@ -0,0 +1,29 @@ + +// RUN: cir-opt %s | FileCheck %s + +!u8i = !cir.int<u, 8> +!rec_S = !cir.record<struct "S" padded {!u8i}> + +module { + cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>) + cir.func dso_local @_Z3foov() { + %0 = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] {alignment = 16 : i64} + cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { + ^bb0(%arg0: !cir.ptr<!rec_S>): + cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () + cir.yield + } + cir.return + } + + // CHECK: cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>) + // CHECK: cir.func dso_local @_Z3foov() { + // CHECK: %0 = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] {alignment = 16 : i64} + // CHECK: cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { + // CHECK: ^bb0(%arg0: !cir.ptr<!rec_S>): + // CHECK: cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () + // CHECK: cir.yield + // CHECK: } + // CHECK: cir.return + // CHECK: } +} >From e3cd6304d87755b31c927e9fa10a79d04f39ba3a Mon Sep 17 00:00:00 2001 From: Morris Hafner <m...@users.noreply.github.com> Date: Thu, 17 Jul 2025 15:06:16 +0200 Subject: [PATCH 2/5] Apply suggestions from code review Co-authored-by: Andy Kaylor <akay...@nvidia.com> Co-authored-by: Henrich Lauko <xla...@mail.muni.cz> --- clang/lib/CIR/CodeGen/CIRGenClass.cpp | 5 ++--- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 2 +- .../Dialect/Transforms/LoweringPrepare.cpp | 19 ++++++++----------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 5a661bf11b114..6351ad418dd74 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -360,8 +360,7 @@ void CIRGenFunction::emitCXXAggrConstructorCall( cgm.errorNYI(e->getSourceRange(), "dynamic-length array expression"); } - auto arrayTy = mlir::dyn_cast<cir::ArrayType>(arrayBase.getElementType()); - assert(arrayTy && "expected array type"); + auto arrayTy = mlir::cast<cir::ArrayType>(arrayBase.getElementType()); mlir::Type elementType = arrayTy.getElementType(); cir::PointerType ptrToElmType = builder.getPointerTo(elementType); @@ -400,7 +399,7 @@ void CIRGenFunction::emitCXXAggrConstructorCall( } // Emit the constructor call that will execute for every array element. - auto arrayOp = builder.createPtrBitcast(arrayBase.getPointer(), arrayTy); + mlir::Value arrayOp = builder.createPtrBitcast(arrayBase.getPointer(), arrayTy); builder.create<cir::ArrayCtor>( *currSrcLoc, arrayOp, [&](mlir::OpBuilder &b, mlir::Location loc) { auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 8e073ef22cc4e..4abbf65cbfe01 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -848,7 +848,7 @@ CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType, } baseType = eltType; - auto numElements = builder.getConstInt(*currSrcLoc, SizeTy, countFromCLAs); + cir::ConstantOp numElements = builder.getConstInt(*currSrcLoc, SizeTy, countFromCLAs); return numElements; } diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 3f0291729c0f5..6a436b1841f05 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -73,19 +73,16 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { op.erase(); } -static void lowerArrayDtorCtorIntoLoop(CIRBaseBuilderTy &builder, +static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, mlir::Operation *op, mlir::Type eltTy, mlir::Value arrayAddr, uint64_t arrayLen) { // Generate loop to call into ctor/dtor for every element. - Location loc = op->getLoc(); + mlir::Location loc = op->getLoc(); // TODO: instead of fixed integer size, create alias for PtrDiffTy and unify // with CIRGen stuff. - auto ptrDiffTy = - cir::IntType::get(builder.getContext(), 64, /*isSigned=*/false); - auto numArrayElementsConst = builder.create<cir::ConstantOp>( - loc, ptrDiffTy, cir::IntAttr::get(ptrDiffTy, arrayLen)); + cir::ConstantOp numArrayElementsConst = builder.getUnsignedInt(loc, 64, arrayLen); auto begin = builder.create<cir::CastOp>( loc, eltTy, cir::CastKind::array_to_ptrdecay, arrayAddr); @@ -111,8 +108,8 @@ static void lowerArrayDtorCtorIntoLoop(CIRBaseBuilderTy &builder, [&](mlir::OpBuilder &b, mlir::Location loc) { auto currentElement = b.create<cir::LoadOp>(loc, eltTy, tmpAddr); - CallOp ctorCall; - op->walk([&](CallOp c) { ctorCall = c; }); + cir::CallOp ctorCall; + op->walk([&](cir::CallOp c) { ctorCall = c; }); assert(ctorCall && "expected ctor call"); auto one = builder.create<cir::ConstantOp>( @@ -132,11 +129,11 @@ static void lowerArrayDtorCtorIntoLoop(CIRBaseBuilderTy &builder, op->erase(); } -void LoweringPreparePass::lowerArrayCtor(ArrayCtor op) { - CIRBaseBuilderTy builder(getContext()); +void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) { + cir::CIRBaseBuilderTy builder(getContext()); builder.setInsertionPointAfter(op.getOperation()); - Type eltTy = op->getRegion(0).getArgument(0).getType(); + mlir::Type eltTy = op->getRegion(0).getArgument(0).getType(); auto arrayLen = mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize(); lowerArrayDtorCtorIntoLoop(builder, op, eltTy, op.getAddr(), arrayLen); >From 6cb9af033d1ad4fff0d7218540ec26c0faef7c3b Mon Sep 17 00:00:00 2001 From: Morris Hafner <mhaf...@nvidia.com> Date: Thu, 17 Jul 2025 15:34:27 +0200 Subject: [PATCH 3/5] Fix compilation errors after applying suggestions --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 6 +++++ clang/include/clang/CIR/Dialect/Passes.h | 1 + .../Dialect/Transforms/LoweringPrepare.cpp | 25 +++++++++++++++++-- clang/lib/CIR/Lowering/CIRPasses.cpp | 2 +- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 25baf278bba38..5c04d59475b6a 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -75,6 +75,12 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return getConstant(loc, cir::IntAttr::get(ty, value)); } + mlir::Value getUnsignedInt(mlir::Location loc, uint64_t val, + unsigned numBits) { + auto type = cir::IntType::get(getContext(), numBits, /*isSigned=*/false); + return getConstAPInt(loc, type, llvm::APInt(numBits, val)); + } + // Creates constant null value for integral type ty. cir::ConstantOp getNullValue(mlir::Type ty, mlir::Location loc) { return getConstant(loc, getZeroInitAttr(ty)); diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h index 02210ec0a8336..7a202b1e04ef9 100644 --- a/clang/include/clang/CIR/Dialect/Passes.h +++ b/clang/include/clang/CIR/Dialect/Passes.h @@ -25,6 +25,7 @@ std::unique_ptr<Pass> createCIRFlattenCFGPass(); std::unique_ptr<Pass> createCIRSimplifyPass(); std::unique_ptr<Pass> createHoistAllocasPass(); std::unique_ptr<Pass> createLoweringPreparePass(); +std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx); void populateCIRPreLoweringPasses(mlir::OpPassManager &pm); diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 6a436b1841f05..30d3060013f67 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -27,6 +27,14 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { void runOnOp(mlir::Operation *op); void lowerUnaryOp(cir::UnaryOp op); void lowerArrayCtor(ArrayCtor op); + + /// + /// AST related + /// ----------- + + clang::ASTContext *astCtx; + + void setASTContext(clang::ASTContext *c) { astCtx = c; } }; } // namespace @@ -74,6 +82,7 @@ void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { } static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, + clang::ASTContext *astCtx, mlir::Operation *op, mlir::Type eltTy, mlir::Value arrayAddr, uint64_t arrayLen) { @@ -82,7 +91,11 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, // TODO: instead of fixed integer size, create alias for PtrDiffTy and unify // with CIRGen stuff. - cir::ConstantOp numArrayElementsConst = builder.getUnsignedInt(loc, 64, arrayLen); + const unsigned sizeTypeSize = + astCtx->getTypeSize(astCtx->getSignedSizeType()); + auto ptrDiffTy = + cir::IntType::get(builder.getContext(), sizeTypeSize, /*isSigned=*/false); + mlir::Value numArrayElementsConst = builder.getUnsignedInt(loc, arrayLen, 64); auto begin = builder.create<cir::CastOp>( loc, eltTy, cir::CastKind::array_to_ptrdecay, arrayAddr); @@ -136,7 +149,8 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) { mlir::Type eltTy = op->getRegion(0).getArgument(0).getType(); auto arrayLen = mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize(); - lowerArrayDtorCtorIntoLoop(builder, op, eltTy, op.getAddr(), arrayLen); + lowerArrayDtorCtorIntoLoop(builder, astCtx, op, eltTy, op.getAddr(), + arrayLen); } void LoweringPreparePass::runOnOp(mlir::Operation *op) { @@ -164,3 +178,10 @@ void LoweringPreparePass::runOnOperation() { std::unique_ptr<Pass> mlir::createLoweringPreparePass() { return std::make_unique<LoweringPreparePass>(); } + +std::unique_ptr<Pass> +mlir::createLoweringPreparePass(clang::ASTContext *astCtx) { + auto pass = std::make_unique<LoweringPreparePass>(); + pass->setASTContext(astCtx); + return std::move(pass); +} diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp b/clang/lib/CIR/Lowering/CIRPasses.cpp index 5607abc98e319..bb9781be897eb 100644 --- a/clang/lib/CIR/Lowering/CIRPasses.cpp +++ b/clang/lib/CIR/Lowering/CIRPasses.cpp @@ -31,7 +31,7 @@ mlir::LogicalResult runCIRToCIRPasses(mlir::ModuleOp theModule, if (enableCIRSimplify) pm.addPass(mlir::createCIRSimplifyPass()); - pm.addPass(mlir::createLoweringPreparePass()); + pm.addPass(mlir::createLoweringPreparePass(&astContext)); pm.enableVerifier(enableVerifier); (void)mlir::applyPassManagerCLOptions(pm); >From e1aaaf53a46079068e3d6cdd323e5c87cded6278 Mon Sep 17 00:00:00 2001 From: Morris Hafner <mhaf...@nvidia.com> Date: Thu, 17 Jul 2025 17:35:06 +0200 Subject: [PATCH 4/5] Address some review feedback --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 8 ++++++++ clang/include/clang/CIR/MissingFeatures.h | 1 + clang/lib/CIR/CodeGen/CIRGenClass.cpp | 5 +++-- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 1 + clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp | 2 ++ clang/test/CIR/CodeGen/array-ctor.cpp | 8 ++++++++ 6 files changed, 23 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 096537fc78839..5f43b257554e0 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2261,6 +2261,14 @@ def CIR_ArrayCtor : CIR_ArrayInitDestroy<"array.ctor"> { Initialize each array element using the same C++ constructor. This operation has one region, with one single block. The block has an incoming argument for the current array index to initialize. + + ```mlir + cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { + ^bb0(%arg0: !cir.ptr<!rec_S>): + cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () + cir.yield + } + ``` }]; } diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 37e0a4c8c1b6b..098c2cad46f67 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -254,6 +254,7 @@ struct MissingFeatures { static bool dtorCleanups() { return false; } static bool vtableInitialization() { return false; } static bool msvcBuiltins() { return false; } + static bool vlas() { return false; } // Missing types static bool dataMemberType() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 6351ad418dd74..46a5b2a1a7379 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -355,8 +355,8 @@ void CIRGenFunction::emitCXXAggrConstructorCall( // Just skip out if the constant count is zero. if (constIntAttr && constIntAttr.getUInt() == 0) return; - // Otherwise, emit the check. } else { + // Otherwise, emit the check. cgm.errorNYI(e->getSourceRange(), "dynamic-length array expression"); } @@ -399,7 +399,8 @@ void CIRGenFunction::emitCXXAggrConstructorCall( } // Emit the constructor call that will execute for every array element. - mlir::Value arrayOp = builder.createPtrBitcast(arrayBase.getPointer(), arrayTy); + mlir::Value arrayOp = + builder.createPtrBitcast(arrayBase.getPointer(), arrayTy); builder.create<cir::ArrayCtor>( *currSrcLoc, arrayOp, [&](mlir::OpBuilder &b, mlir::Location loc) { auto arg = b.getInsertionBlock()->addArgument(ptrToElmType, loc); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 4abbf65cbfe01..97ba226745d40 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -818,6 +818,7 @@ CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType, // If it's a VLA, we have to load the stored size. Note that // this is the size of the VLA in bytes, not its size in elements. if (isa<VariableArrayType>(arrayType)) { + assert(cir::MissingFeatures::vlas()); cgm.errorNYI(*currSrcLoc, "VLAs"); return builder.getConstInt(*currSrcLoc, SizeTy, 0); } diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 30d3060013f67..c7d6f008e7c93 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -13,6 +13,7 @@ #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/Passes.h" +#include "clang/CIR/MissingFeatures.h" #include <memory> @@ -147,6 +148,7 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) { builder.setInsertionPointAfter(op.getOperation()); mlir::Type eltTy = op->getRegion(0).getArgument(0).getType(); + assert(!cir::MissingFeatures::vlas()); auto arrayLen = mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize(); lowerArrayDtorCtorIntoLoop(builder, astCtx, op, eltTy, op.getAddr(), diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp index 0a2661248f908..d927db3189270 100644 --- a/clang/test/CIR/CodeGen/array-ctor.cpp +++ b/clang/test/CIR/CodeGen/array-ctor.cpp @@ -68,3 +68,11 @@ void foo() { // OGCG: br i1 %[[DONE]], label %[[EXIT:.*]], label %[[LOOP]] // OGCG: [[EXIT]]: // OGCG: ret void + +void zero_sized() { + int s[0]; +} + +// CIR: cir.func dso_local @_Z10zero_sizedv() +// CIR-NOT: cir.do +// CIR: cir.return >From 7331eb4ff98de1d99708b8ac35e439833ad23db3 Mon Sep 17 00:00:00 2001 From: Morris Hafner <mhaf...@nvidia.com> Date: Tue, 22 Jul 2025 18:21:26 +0200 Subject: [PATCH 5/5] more review feedback --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 ++-- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 4 +--- clang/test/CIR/CodeGen/array-ctor.cpp | 15 +++++++++++++++ clang/test/CIR/IR/array-ctor.cir | 4 ++-- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 5f43b257554e0..177382c360e3f 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2239,7 +2239,7 @@ class CIR_ArrayInitDestroy<string mnemonic> : CIR_Op<mnemonic> { let regions = (region SizedRegion<1>:$body); let assemblyFormat = [{ - `(` $addr `:` qualified(type($addr)) `)` $body attr-dict + $addr `:` qualified(type($addr)) $body attr-dict }]; let builders = [ @@ -2265,7 +2265,7 @@ def CIR_ArrayCtor : CIR_ArrayInitDestroy<"array.ctor"> { ```mlir cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { ^bb0(%arg0: !cir.ptr<!rec_S>): - cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () + cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> () cir.yield } ``` diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 97ba226745d40..afdb1927f952e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -849,9 +849,7 @@ CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType, } baseType = eltType; - cir::ConstantOp numElements = builder.getConstInt(*currSrcLoc, SizeTy, countFromCLAs); - - return numElements; + return builder.getConstInt(*currSrcLoc, SizeTy, countFromCLAs); } } // namespace clang::CIRGen diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp index d927db3189270..788bc8cfcba78 100644 --- a/clang/test/CIR/CodeGen/array-ctor.cpp +++ b/clang/test/CIR/CodeGen/array-ctor.cpp @@ -1,3 +1,4 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o - 2>&1 | FileCheck --check-prefixes=CIR-BEFORE-LPP %s // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll @@ -13,6 +14,16 @@ void foo() { S s[42]; } +// CIR-BEFORE-LPP: cir.func dso_local @_Z3foov() +// CIR-BEFORE-LPP: %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] +// CIR-BEFORE-LPP: cir.array.ctor %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 42>> { +// CIR-BEFORE-LPP: ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_S>): +// CIR-BEFORE-LPP: cir.call @_ZN1SC1Ev(%[[ARG]]) : (!cir.ptr<!rec_S>) -> () +// CIR-BEFORE-LPP: cir.yield +// CIR-BEFORE-LPP: } +// CIR-BEFORE-LPP: cir.return +// CIR-BEFORE-LPP: } + // CIR: cir.func dso_local @_Z3foov() // CIR: %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] // CIR: %[[CONST42:.*]] = cir.const #cir.int<42> : !u64i @@ -73,6 +84,10 @@ void zero_sized() { int s[0]; } +// CIR-BEFORE-LPP: cir.func dso_local @_Z10zero_sizedv() +// CIR-BEFORE-LPP-NOT: cir.array.ctor +// CIR-BEFORE-LPP: cir.return + // CIR: cir.func dso_local @_Z10zero_sizedv() // CIR-NOT: cir.do // CIR: cir.return diff --git a/clang/test/CIR/IR/array-ctor.cir b/clang/test/CIR/IR/array-ctor.cir index a039d7d2ca6b0..2378992bbd9fc 100644 --- a/clang/test/CIR/IR/array-ctor.cir +++ b/clang/test/CIR/IR/array-ctor.cir @@ -8,7 +8,7 @@ module { cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>) cir.func dso_local @_Z3foov() { %0 = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] {alignment = 16 : i64} - cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { + cir.array.ctor %0 : !cir.ptr<!cir.array<!rec_S x 42>> { ^bb0(%arg0: !cir.ptr<!rec_S>): cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () cir.yield @@ -19,7 +19,7 @@ module { // CHECK: cir.func private @_ZN1SC1Ev(!cir.ptr<!rec_S>) // CHECK: cir.func dso_local @_Z3foov() { // CHECK: %0 = cir.alloca !cir.array<!rec_S x 42>, !cir.ptr<!cir.array<!rec_S x 42>>, ["s", init] {alignment = 16 : i64} - // CHECK: cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { + // CHECK: cir.array.ctor %0 : !cir.ptr<!cir.array<!rec_S x 42>> { // CHECK: ^bb0(%arg0: !cir.ptr<!rec_S>): // CHECK: cir.call @_ZN1SC1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () // CHECK: cir.yield _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits