llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) <details> <summary>Changes</summary> This change adds support for array new with variable size. This required extending the cir.array.ctor operation to accept a value for the size and a direct pointer to the element size instead of a pointer to an array. Assisted-by: Cursor / claude-4.6-opus-high Assisted-by: Cursor / composer-2-fast --- Patch is 27.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/190656.diff 7 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+31-3) - (modified) clang/lib/CIR/CodeGen/CIRGenClass.cpp (+49-45) - (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+44) - (modified) clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp (+20-4) - (modified) clang/test/CIR/CodeGen/new.cpp (+146) - (modified) clang/test/CIR/IR/array-ctor.cir (+19) - (added) clang/test/CIR/IR/invalid-array-structor.cir (+143) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 04884beaa5685..74d79db5e11c6 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4563,7 +4563,14 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> { operation has one region, with one single block. The block has an incoming argument for the current array element to initialize. - Example: + When `num_elements` is absent, `addr` must be a pointer to a fixed-size + CIR array type and the element count is derived from that array type. + + When `num_elements` is present, `addr` is a pointer to the first element + and `num_elements` provides the runtime element count (for example `new + T[n]`). + + Examples: ```mlir cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { @@ -4571,19 +4578,28 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> { cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> () cir.yield } + + cir.array.ctor(%ptr, %n : !cir.ptr<!rec_S>, !u64i) { + ^bb0(%arg0: !cir.ptr<!rec_S>): + cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> () + cir.yield + } ``` }]; let arguments = (ins - Arg<CIR_PtrToArray, "array address", [MemWrite, MemRead]>:$addr + Arg<CIR_AnyPtrType, "array or element address", [MemWrite, MemRead]>:$addr, + Optional<CIR_AnyIntType>:$num_elements ); let regions = (region SizedRegion<1>:$body); let assemblyFormat = [{ - $addr `:` qualified(type($addr)) $body attr-dict + $addr (`,` $num_elements^)? `:` qualified(type($addr)) + (`,` type($num_elements)^)? $body attr-dict }]; let builders = [ + // Static form: addr is ptr<array<T x N>>, no num_elements. OpBuilder<(ins "mlir::Value":$addr, "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$regionBuilder), [{ assert(regionBuilder && "builder callback expected"); @@ -4592,9 +4608,20 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> { $_state.addOperands(ValueRange{addr}); $_builder.createBlock(r); regionBuilder($_builder, $_state.location); + }]>, + // Dynamic form: addr is ptr<T>, num_elements is the runtime count. + OpBuilder<(ins "mlir::Value":$addr, "mlir::Value":$num_elements, + "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({addr, num_elements}); + $_builder.createBlock(r); + regionBuilder($_builder, $_state.location); }]> ]; + let hasVerifier = 1; let hasLLVMLowering = false; } @@ -4668,6 +4695,7 @@ def CIR_ArrayDtor : CIR_Op<"array.dtor"> { }]> ]; + let hasVerifier = 1; let hasLLVMLowering = false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index e54514950e00f..f8d65fa9a6d33 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -735,31 +735,22 @@ void CIRGenFunction::emitCXXAggrConstructorCall( // are probably legitimate places where we could assume that this // doesn't happen, but it's not clear that it's worth it. - auto arrayTy = mlir::cast<cir::ArrayType>(arrayBase.getElementType()); - mlir::Type elementType = arrayTy.getElementType(); - - // This might be a multi-dimensional array. Find the innermost element type. + // Peel any array types wrapped in the address element type down to the CIR + // type of a single constructed object. + mlir::Type elementType = arrayBase.getElementType(); while (auto maybeArrayTy = mlir::dyn_cast<cir::ArrayType>(elementType)) elementType = maybeArrayTy.getElementType(); cir::PointerType ptrToElmType = builder.getPointerTo(elementType); - // Optimize for a constant count. - if (auto constantCount = numElements.getDefiningOp<cir::ConstantOp>()) { - if (auto constIntAttr = constantCount.getValueAttr<cir::IntAttr>()) { - // Just skip out if the constant count is zero. - if (constIntAttr.getUInt() == 0) - return; - - arrayTy = cir::ArrayType::get(elementType, constIntAttr.getUInt()); - // Otherwise, emit the check. - } - - if (constantCount.use_empty()) - constantCount.erase(); - } else { - // Otherwise, emit the check. - cgm.errorNYI(e->getSourceRange(), - "emitCXXAggrConstructorCall: dynamic-length array expression"); + bool useDynamicArrayCtor = true; + uint64_t constElementCount = 0; + if (auto constantOp = numElements.getDefiningOp<cir::ConstantOp>()) { + constElementCount = CIRGenFunction::getZExtIntValueFromConstOp(constantOp); + if (constElementCount == 0) + return; + if (constantOp.use_empty()) + constantOp.erase(); + useDynamicArrayCtor = false; } // Traditional LLVM codegen emits a loop here. CIR lowers to a loop as part of @@ -775,6 +766,13 @@ void CIRGenFunction::emitCXXAggrConstructorCall( CharUnits eltAlignment = arrayBase.getAlignment().alignmentOfArrayElement( getContext().getTypeSizeInChars(type)); + mlir::Location loc = *currSrcLoc; + + mlir::Value dynamicElPtr; + if (useDynamicArrayCtor) + dynamicElPtr = + builder.createPtrBitcast(arrayBase.getPointer(), elementType); + // 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 @@ -792,30 +790,36 @@ void CIRGenFunction::emitCXXAggrConstructorCall( cgm.errorNYI(e->getSourceRange(), "partial array cleanups"); } - // Emit the constructor call that will execute for every array element. - mlir::Value arrayOp = - builder.createPtrBitcast(arrayBase.getPointer(), arrayTy); - cir::ArrayCtor::create( - builder, *currSrcLoc, arrayOp, - [&](mlir::OpBuilder &b, mlir::Location loc) { - mlir::BlockArgument arg = - b.getInsertionBlock()->addArgument(ptrToElmType, loc); - Address curAddr = Address(arg, elementType, eltAlignment); - assert(!cir::MissingFeatures::sanitizers()); - // Zero-initialize each element before invoking its constructor, - // matching CGClass::EmitCXXAggrConstructorCall which does per-element - // zero-init inside the array ctor loop. - if (zeroInitialize) - emitNullInitialization(loc, curAddr, type); - 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); - cir::YieldOp::create(b, loc); - }); + auto emitCtorBody = [&](mlir::OpBuilder &b, mlir::Location l) { + mlir::BlockArgument arg = + b.getInsertionBlock()->addArgument(ptrToElmType, l); + Address curAddr = Address(arg, elementType, eltAlignment); + assert(!cir::MissingFeatures::sanitizers()); + // Match CGClass::EmitCXXAggrConstructorCall: zero-initialize each element + // in the array-ctor loop before invoking the constructor for that slot. + if (zeroInitialize) + emitNullInitialization(l, curAddr, type); + 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); + cir::YieldOp::create(b, l); + }; + + // Emit the per-element initialization. + if (useDynamicArrayCtor) { + cir::ArrayCtor::create(builder, loc, dynamicElPtr, numElements, + emitCtorBody); + } else { + cir::ArrayType arrayTy = + cir::ArrayType::get(elementType, constElementCount); + mlir::Value arrayOp = + builder.createPtrBitcast(arrayBase.getPointer(), arrayTy); + cir::ArrayCtor::create(builder, loc, arrayOp, emitCtorBody); + } } } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index a0b11f7f46b97..9dad642344cc0 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -289,6 +289,50 @@ void cir::AllocaOp::build(mlir::OpBuilder &odsBuilder, odsState.addTypes(addr); } +//===----------------------------------------------------------------------===// +// ArrayCtor & ArrayDtor +//===----------------------------------------------------------------------===// + +template <typename Op> static LogicalResult verifyArrayCtorDtor(Op op) { + auto ptrTy = mlir::cast<cir::PointerType>(op.getAddr().getType()); + mlir::Type pointeeTy = ptrTy.getPointee(); + + mlir::Block &body = op.getBody().front(); + if (body.getNumArguments() != 1) + return op.emitOpError("body must have exactly one block argument"); + + auto expectedEltPtrTy = + mlir::dyn_cast<cir::PointerType>(body.getArgument(0).getType()); + if (!expectedEltPtrTy) + return op.emitOpError("block argument must be a !cir.ptr type"); + + if (op.getNumElements()) { + if (expectedEltPtrTy != ptrTy) + return op.emitOpError("when 'num_elements' is present, 'addr' type must " + "match the block argument type"); + } else { + auto arrayTy = mlir::dyn_cast<cir::ArrayType>(pointeeTy); + if (!arrayTy) + return op.emitOpError( + "when 'num_elements' is absent, 'addr' must be a pointer to a " + "!cir.array type"); + + mlir::Type innerEltTy = arrayTy.getElementType(); + while (auto nested = mlir::dyn_cast<cir::ArrayType>(innerEltTy)) + innerEltTy = nested.getElementType(); + + if (expectedEltPtrTy.getPointee() != innerEltTy) + return op.emitOpError( + "block argument pointee type must match the innermost array " + "element type"); + } + + return success(); +} + +LogicalResult cir::ArrayCtor::verify() { return verifyArrayCtorDtor(*this); } +LogicalResult cir::ArrayDtor::verify() { return verifyArrayCtorDtor(*this); } + //===----------------------------------------------------------------------===// // BreakOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 4d0c7b179f260..91f082725711f 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -1389,7 +1389,6 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, // from end, decrementing before calling the destructor on each element. mlir::Value begin, end; if (isDynamic) { - assert(!isCtor && "Unexpected dynamic ctor loop"); begin = addr; end = cir::PtrStrideOp::create(builder, loc, eltTy, begin, numElements); } else { @@ -1407,9 +1406,18 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, // This places the destructor loop emitted below inside the if block. cir::IfOp ifOp; if (isDynamic) { - mlir::Value isEmpty = - cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, start, stop); - ifOp = cir::IfOp::create(builder, loc, isEmpty, + mlir::Value guardCond; + if (isCtor) { + mlir::Value zero = builder.getUnsignedInt(loc, 0, sizeTypeSize); + guardCond = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, + numElements, zero); + } else { + // We could check for numElements != 0 in this case too, but this matches + // what classic codegen does. + guardCond = + cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, start, stop); + } + ifOp = cir::IfOp::create(builder, loc, guardCond, /*withElseRegion=*/false, [&](mlir::OpBuilder &, mlir::Location) {}); builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); @@ -1496,6 +1504,14 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) { builder.setInsertionPointAfter(op.getOperation()); mlir::Type eltTy = op->getRegion(0).getArgument(0).getType(); + + if (op.getNumElements()) { + lowerArrayDtorCtorIntoLoop(builder, astCtx, op, eltTy, op.getAddr(), + op.getNumElements(), /*arrayLen=*/0, + /*isCtor=*/true); + return; + } + assert(!cir::MissingFeatures::vlas()); auto arrayLen = mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize(); diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index 55c7507346500..7da943de355ef 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -806,6 +806,43 @@ void test_array_new_with_ctor_init() { // OGCG: ret void // +void test_array_new_var_sized_with_ctor_init(int size) { + auto p = new F[size]; +} + +// CIR-BEFORE-LPP: cir.func{{.*}} @_Z39test_array_new_var_sized_with_ctor_initi +// CIR-BEFORE-LPP: %[[N64:.*]] = cir.cast integral{{.*}} : !s32i -> !u64i +// CIR-BEFORE-LPP: %[[RAW:.*]] = cir.call @_Znam(%[[N64]]) +// CIR-BEFORE-LPP: cir.cast bitcast %[[RAW]] : !cir.ptr<!void> -> !cir.ptr<!rec_F> +// CIR-BEFORE-LPP: cir.array.ctor %{{.*}}, %[[N64]] : !cir.ptr<!rec_F>, !u64i { +// CIR-BEFORE-LPP: ^bb0({{.*}}: !cir.ptr<!rec_F>): +// CIR-BEFORE-LPP: cir.call @_ZN1FC1Ev({{.*}}) : (!cir.ptr<!rec_F> + +// CHECK: cir.func{{.*}} @_Z39test_array_new_var_sized_with_ctor_initi +// CHECK: %[[N64:.*]] = cir.cast integral{{.*}} : !s32i -> !u64i +// CHECK: %[[RAW:.*]] = cir.call @_Znam(%[[N64]]) +// CHECK: %[[BEGIN:.*]] = cir.cast bitcast %[[RAW]] : !cir.ptr<!void> -> !cir.ptr<!rec_F> +// CHECK: %[[END:.*]] = cir.ptr_stride %{{.*}}, %[[N64]] : (!cir.ptr<!rec_F>, !u64i) -> !cir.ptr<!rec_F> +// CHECK: cir.cmp ne %[[N64]], %{{.*}} : !u64i +// CHECK: cir.if +// CHECK: cir.call @_ZN1FC1Ev( +// CHECK: cir.store{{.*}} %[[BEGIN]], +// CHECK: cir.return + +// LLVM: define{{.*}} void @_Z39test_array_new_var_sized_with_ctor_initi +// LLVM: %[[N:.*]] = load i32, ptr %{{.+}} +// LLVM: %[[N64:.*]] = sext i32 %[[N]] to i64 +// LLVM: %[[RAW:.*]] = call noundef ptr @_Znam(i64 {{.*}} %[[N64]]) +// LLVM: %[[CMP:.*]] = icmp ne i64 %[[N64]], 0 +// LLVM: br i1 %[[CMP]] + +// OGCG: define{{.*}} void @_Z39test_array_new_var_sized_with_ctor_initi +// OGCG: %[[N:.*]] = load i32, ptr %{{.+}} +// OGCG: %[[N64:.*]] = sext i32 %[[N]] to i64 +// OGCG: %[[RAW:.*]] = call{{.*}} ptr @_Znam(i64 {{.*}} %[[N64]]) +// OGCG: %[[CMP:.*]] = icmp eq i64 %[[N64]], 0 +// OGCG: br i1 %[[CMP]] + // Non-trivial member => non-trivial implicit OuterZero default constructor. // Value-initialization `new OuterZero[3]()` needs zero-init before each ctor // (CXXConstructExpr::requiresZeroInitialization). @@ -890,6 +927,56 @@ void test_const_array_new_value_init() { // OGCG: store ptr %[[RAW]], ptr %{{.*}}, align 8 // OGCG: ret void +void test_var_array_new_value_init(int n) { + auto p = new OuterZero[n](); +} + +// --- Per-element zero-init before ctor (dynamic array new + value-init): +// OG emits @llvm.memset of i64 1 then C1Ev inside its arrayctor.loop. CIR +// stores #cir.zero per element in the cir.array.ctor region, then the same +// ctor call. There must be no bulk clear of the whole allocation before the +// lowered loop (no libc.memset / memset scaled by element count in the +// lowering-prepare input). + +// CIR-BEFORE-LPP-LABEL: cir.func{{.*}} @_Z29test_var_array_new_value_initi +// CIR-BEFORE-LPP: %[[N:.*]] = cir.cast integral{{.*}} : !s32i -> !u64i +// CIR-BEFORE-LPP-NEXT: %{{.*}} = cir.call @_Znam(%[[N]]){{.*}} +// CIR-BEFORE-LPP-NEXT: cir.cast bitcast %{{.*}} : !cir.ptr<!void> -> !cir.ptr<!rec_OuterZero> +// CIR-BEFORE-LPP-NEXT: cir.cast bitcast %{{.*}} : !cir.ptr<!rec_OuterZero> -> !cir.ptr<!cir.array<!rec_OuterZero x 0>> +// CIR-BEFORE-LPP-NEXT: cir.cast bitcast %{{.*}} : !cir.ptr<!cir.array<!rec_OuterZero x 0>> -> !cir.ptr<!rec_OuterZero> +// CIR-BEFORE-LPP-NEXT: cir.array.ctor %{{.*}}, %[[N]] : !cir.ptr<!rec_OuterZero>, !u64i { +// CIR-BEFORE-LPP-NEXT: ^bb0(%[[EL:.*]]: !cir.ptr<!rec_OuterZero>): +// CIR-BEFORE-LPP-NEXT: cir.const #cir.zero : !rec_OuterZero +// CIR-BEFORE-LPP-NEXT: cir.store{{.*}} %{{.*}}, %[[EL]] : !rec_OuterZero, !cir.ptr<!rec_OuterZero> +// CIR-BEFORE-LPP-NEXT: cir.call @_ZN9OuterZeroC1Ev(%[[EL]]) : (!cir.ptr<!rec_OuterZero> {llvm.align = 1 : i64, llvm.dereferenceable = 1 : i64, llvm.nonnull, llvm.noundef}) -> () +// CIR-BEFORE-LPP-NEXT: cir.yield +// CIR-BEFORE-LPP-NEXT: } + +// CHECK-LABEL: cir.func{{.*}} @_Z29test_var_array_new_value_initi +// CHECK: cir.do { +// CHECK: cir.load{{.*}} : !cir.ptr<!cir.ptr<!rec_OuterZero>>, !cir.ptr<!rec_OuterZero> +// CHECK: cir.const #cir.zero : !rec_OuterZero +// CHECK: cir.store{{.*}} : !rec_OuterZero, !cir.ptr<!rec_OuterZero> +// CHECK: cir.call @_ZN9OuterZeroC1Ev( +// CHECK: cir.ptr_stride +// CHECK: cir.store{{.*}} : !cir.ptr<!rec_OuterZero>, !cir.ptr<!cir.ptr<!rec_OuterZero>> +// CHECK: cir.yield +// CHECK: } while { +// CHECK: cir.load{{.*}} : !cir.ptr<!cir.ptr<!rec_OuterZero>>, !cir.ptr<!rec_OuterZero> +// CHECK: cir.cmp ne +// CHECK: cir.condition +// CHECK: } +// CHECK: cir.return + +// LLVM-LABEL: define{{.*}} void @_Z29test_var_array_new_value_initi +// LLVM-NOT: call void @llvm.memset.p0.i64 +// LLVM: store %class.OuterZero zeroinitializer, ptr %[[CUR:.*]], align 1 +// LLVM-NEXT: call void @_ZN9OuterZeroC1Ev(ptr noundef nonnull align 1 dereferenceable(1) %[[CUR]]) + +// OGCG-LABEL: define{{.*}} void @_Z29test_var_array_new_value_initi +// OGCG: call void @llvm.memset.p0.i64(ptr align 1 %[[CUR:.*]], i8 0, i64 1, i1 false) +// OGCG-NEXT: call void @_ZN9OuterZeroC1Ev(ptr noundef nonnull align 1 dereferenceable(1) %[[CUR]]) + void test_multidim_array_new_with_ctor() { auto p = new F[2][3]; } @@ -956,6 +1043,65 @@ void test_multidim_array_new_with_ctor() { // OGCG: store ptr %[[RAW]], ptr %{{.*}}, align 8 // OGCG: ret void +void test_multidim_var_array_new_with_ctor(int n) { + auto p = new F[n][3]; +} + +// CIR-BEFORE-LPP-LABEL: cir.func{{.*}} @_Z37test_multidim_var_array_new_with_ctori +// CIR-BEFORE-LPP: %[[N64:.*]] = cir.cast integral %{{.*}} : !s32i -> !u64i +// CIR-BEFORE-LPP: %[[THREE:.*]] = cir.const #cir.int<3> : !u64i +// CIR-BEFORE-LPP: %[[TOTAL:.*]], %{{.*}} = cir.mul.overflow %[[N64]], %[[THREE]] : !u64i +// CIR-BEFORE-LPP: cir.select +// CIR-BEFORE-LPP: cir.call @_Znam +// CIR-BEFORE-LPP: cir.cast bitcast %{{.*}} : !cir.ptr<!void> -> !cir.ptr<!cir.array<!rec_F x 3>> +// CIR-BEFORE-LPP: cir.cast bitcast %{{.*}} : !cir.ptr<!cir.array<!rec_F x 3>> -> !cir.ptr<!cir.array<!cir.array<!rec_F x 3> x 0>> +// CIR-BEFORE-LPP: %[[ELPTR:.*]] = cir.cast bitcast %{{.*}} : !cir.ptr<!cir.array<!cir.array<!rec_F x 3> x 0>> -> !cir.ptr<!rec_F> +// CIR-BEFORE-LPP: cir.array.ctor %[[ELPTR]], %[[TOTAL]] : !cir.ptr<!rec_F>, !u64i { +// CIR-BEFORE-LPP: ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_F>): +// CIR-BEFORE-LPP: cir.call @_ZN1FC1Ev(%[[ARG]]) +// CIR-BEFORE-LPP: cir.yield +// CIR-BEFORE-LPP: } + +// CHECK-LABEL: cir.func{{.*}} @_Z37test_multidim_var_array_new_with_ctori +// CHECK: %[[N64:.*]] = cir.cast integral %{{.*}} : !s32i -> !u64i +// CHECK: %[[TOTAL:.*]], %{{.*}} = cir.mul.overflow %[[N64]], %{{.*}} : !u64i +// CHECK: cir.call @_Znam +// CHECK: cir.ptr_stride %{{.*}}, %[[TOTAL]] : (!cir.ptr<!rec_F>, !u64i) -> !cir.ptr<!rec_F> +// CHECK: cir.cmp ne %[[TOTAL]], %{{.*}} : !u64i +// CHECK: cir.if %{{.*}} { +// CHECK: cir.do { +// CHECK: cir.call @_ZN1FC1Ev( +// CHECK: cir.ptr_stride +// CHECK:... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/190656 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
