https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/190834
>From aa9c3f2d26d513575648ff317f5508ab5f5b305d Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Wed, 1 Apr 2026 15:07:42 -0700 Subject: [PATCH 1/4] [CIR] Implement partial array destroy handling This implements EH cleanup handling that performs regular partial array destruction for array constructor loops with a destructed type. Because CIR represents array construction using an abstract operation, we do not go through the normal EH stack mechanism. Instead, we add a partial_dtor region to the cir.array.ctor operation indicating how a single element should be destructed. When the cir.array.ctor operation is expanded during LoweringPrepare, we create a cleanup scope with a partial array dtor loop in an EH cleanup region. This gets further expanded during CFG flattening to produce a control flow equivalent to that generated by classic codegen. Assisted-by: Cursor / claude-4.6-opus-high --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 65 +++++-- clang/lib/CIR/CodeGen/CIRGenClass.cpp | 31 ++-- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 89 +++++++++- .../Dialect/Transforms/LoweringPrepare.cpp | 118 +++++++++---- clang/test/CIR/CodeGen/array-ctor.cpp | 13 ++ .../CIR/CodeGen/partial-array-cleanup.cpp | 163 ++++++++++++++++++ 6 files changed, 420 insertions(+), 59 deletions(-) create mode 100644 clang/test/CIR/CodeGen/partial-array-cleanup.cpp diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index d2fd2df7ab7d1..bbe1ff71da9f3 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4578,8 +4578,17 @@ def CIR_ArrayCtor : CIR_Op<"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 element to initialize. + operation has a `body` region and an optional `partial_dtor` region. + Both regions have a single block whose argument is a pointer to the + current array element. + + The `body` region contains the constructor call for one element. + + The `partial_dtor` region, when non-empty, contains the destructor call + for one element. During lowering, it is used to build a cleanup that + destroys already-constructed elements if a constructor throws. When the + element type has a trivial destructor or exceptions are disabled, the + `partial_dtor` region is left empty. 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. @@ -4591,17 +4600,30 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> { Examples: ```mlir + // Fixed size without partial destructor: cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { ^bb0(%arg0: !cir.ptr<!rec_S>): cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> () cir.yield } + // Variable size without partial destructor: 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 } + + // Fixed size with partial destructor: + cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { + ^bb0(%arg0: !cir.ptr<!rec_S>): + cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> () + cir.yield + } partial_dtor { + ^bb0(%arg0: !cir.ptr<!rec_S>): + cir.call @some_dtor(%arg0) : (!cir.ptr<!rec_S>) -> () + cir.yield + } ``` }]; @@ -4610,32 +4632,41 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> { Optional<CIR_AnyIntType>:$num_elements ); - let regions = (region SizedRegion<1>:$body); - let assemblyFormat = [{ - $addr (`,` $num_elements^)? `:` qualified(type($addr)) - (`,` type($num_elements)^)? $body attr-dict - }]; + let regions = (region SizedRegion<1>:$body, AnyRegion:$partial_dtor); + let hasCustomAssemblyFormat = 1; 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"); + "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$bodyBuilder, + "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$partialDtorBuilder), [{ + assert(bodyBuilder && "builder callback expected"); mlir::OpBuilder::InsertionGuard guard($_builder); - mlir::Region *r = $_state.addRegion(); $_state.addOperands(ValueRange{addr}); - $_builder.createBlock(r); - regionBuilder($_builder, $_state.location); + mlir::Region *body = $_state.addRegion(); + $_builder.createBlock(body); + bodyBuilder($_builder, $_state.location); + mlir::Region *partialDtor = $_state.addRegion(); + if (partialDtorBuilder) { + $_builder.createBlock(partialDtor); + partialDtorBuilder($_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"); + "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$bodyBuilder, + "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)>":$partialDtorBuilder), [{ + assert(bodyBuilder && "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); + mlir::Region *body = $_state.addRegion(); + $_builder.createBlock(body); + bodyBuilder($_builder, $_state.location); + mlir::Region *partialDtor = $_state.addRegion(); + if (partialDtorBuilder) { + $_builder.createBlock(partialDtor); + partialDtorBuilder($_builder, $_state.location); + } }]> ]; diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index f8d65fa9a6d33..02e074200204d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -783,20 +783,15 @@ void CIRGenFunction::emitCXXAggrConstructorCall( { RunCleanupsScope scope(*this); - // 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"); - } + bool needsPartialArrayCleanup = + getLangOpts().Exceptions && + !ctor->getParent()->hasTrivialDestructor(); 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( @@ -809,16 +804,30 @@ void CIRGenFunction::emitCXXAggrConstructorCall( cir::YieldOp::create(b, l); }; - // Emit the per-element initialization. + llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> + emitPartialDtorBody = nullptr; + auto partialDtorBuilder = [&](mlir::OpBuilder &b, mlir::Location l) { + mlir::BlockArgument arg = + b.getInsertionBlock()->addArgument(ptrToElmType, l); + Address curAddr = Address(arg, elementType, eltAlignment); + emitCXXDestructorCall(ctor->getParent()->getDestructor(), Dtor_Complete, + /*forVirtualBase=*/false, + /*delegating=*/false, curAddr, type); + cir::YieldOp::create(b, l); + }; + if (needsPartialArrayCleanup) + emitPartialDtorBody = partialDtorBuilder; + if (useDynamicArrayCtor) { cir::ArrayCtor::create(builder, loc, dynamicElPtr, numElements, - emitCtorBody); + emitCtorBody, emitPartialDtorBody); } else { cir::ArrayType arrayTy = cir::ArrayType::get(elementType, constElementCount); mlir::Value arrayOp = builder.createPtrBitcast(arrayBase.getPointer(), arrayTy); - cir::ArrayCtor::create(builder, loc, arrayOp, emitCtorBody); + cir::ArrayCtor::create(builder, loc, arrayOp, emitCtorBody, + emitPartialDtorBody); } } } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index ab1c0b453ac18..3e020e52ebece 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -341,7 +341,94 @@ template <typename Op> static LogicalResult verifyArrayCtorDtor(Op op) { return success(); } -LogicalResult cir::ArrayCtor::verify() { return verifyArrayCtorDtor(*this); } +ParseResult cir::ArrayCtor::parse(OpAsmParser &parser, OperationState &result) { + OpAsmParser::UnresolvedOperand addrOperand; + OpAsmParser::UnresolvedOperand numElementsOperand; + bool hasNumElements = false; + + if (parser.parseOperand(addrOperand)) + return failure(); + + if (succeeded(parser.parseOptionalComma())) { + if (parser.parseOperand(numElementsOperand)) + return failure(); + hasNumElements = true; + } + + if (parser.parseColon()) + return failure(); + + mlir::Type addrType; + if (parser.parseType(addrType)) + return failure(); + if (parser.resolveOperand(addrOperand, addrType, result.operands)) + return failure(); + + if (hasNumElements) { + if (parser.parseComma()) + return failure(); + mlir::Type numElementsType; + if (parser.parseType(numElementsType)) + return failure(); + if (parser.resolveOperand(numElementsOperand, numElementsType, + result.operands)) + return failure(); + } + + Region *body = result.addRegion(); + if (parser.parseRegion(*body)) + return failure(); + + Region *partialDtor = result.addRegion(); + if (!parser.parseOptionalKeyword("partial_dtor")) { + if (parser.parseRegion(*partialDtor)) + return failure(); + } + + if (parser.parseOptionalAttrDict(result.attributes)) + return failure(); + + return success(); +} + +void cir::ArrayCtor::print(OpAsmPrinter &p) { + p << " " << getAddr(); + if (getNumElements()) + p << ", " << getNumElements(); + + p << " : " << getAddr().getType(); + if (getNumElements()) + p << ", " << getNumElements().getType(); + + p << " "; + p.printRegion(getBody()); + + if (!getPartialDtor().empty()) { + p << " partial_dtor "; + p.printRegion(getPartialDtor()); + } + + p.printOptionalAttrDict(getOperation()->getAttrs()); +} + +LogicalResult cir::ArrayCtor::verify() { + if (failed(verifyArrayCtorDtor(*this))) + return failure(); + + mlir::Region &partialDtor = getPartialDtor(); + if (!partialDtor.empty()) { + mlir::Block &dtorBlock = partialDtor.front(); + if (dtorBlock.getNumArguments() != 1) + return emitOpError( + "partial_dtor must have exactly one block argument"); + + auto bodyArgTy = getBody().front().getArgument(0).getType(); + if (dtorBlock.getArgument(0).getType() != bodyArgTy) + return emitOpError("partial_dtor block argument type must match " + "the body block argument type"); + } + return success(); +} LogicalResult cir::ArrayDtor::verify() { return verifyArrayCtorDtor(*this); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 91f082725711f..f5ab406789882 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -1369,13 +1369,16 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() { cir::ReturnOp::create(builder, f.getLoc()); } +/// Lower a cir.array.ctor or cir.array.dtor into a do-while loop that +/// iterates over every element. For cir.array.ctor ops whose partial_dtor +/// region is non-empty, the ctor loop is wrapped in a cir.cleanup.scope whose +/// EH cleanup performs a reverse destruction loop using the partial dtor body. static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, clang::ASTContext *astCtx, mlir::Operation *op, mlir::Type eltTy, mlir::Value addr, mlir::Value numElements, uint64_t arrayLen, bool isCtor) { - // Generate loop to call into ctor/dtor for every element. mlir::Location loc = op->getLoc(); bool isDynamic = numElements != nullptr; @@ -1432,7 +1435,7 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, // Clone the region body (ctor/dtor call and any setup ops like per-element // zero-init) into the loop, remapping the block argument to the current - // element pointer. + // element pointer. auto cloneRegionBodyInto = [&](mlir::Block *srcBlock, mlir::Value replacement) { mlir::IRMapping map; @@ -1443,34 +1446,89 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, } }; - builder.createDoWhile( - loc, - /*condBuilder=*/ - [&](mlir::OpBuilder &b, mlir::Location loc) { - auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr); - auto cmp = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, - currentElement, stop); - builder.createCondition(cmp); - }, - /*bodyBuilder=*/ - [&](mlir::OpBuilder &b, mlir::Location loc) { - auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr); - if (isCtor) { - cloneRegionBodyInto(bodyBlock, currentElement); - mlir::Value stride = builder.getUnsignedInt(loc, 1, sizeTypeSize); - auto nextElement = cir::PtrStrideOp::create(builder, loc, eltTy, - currentElement, stride); - builder.createStore(loc, nextElement, tmpAddr); - } else { - mlir::Value stride = builder.getSignedInt(loc, -1, sizeTypeSize); - auto prevElement = cir::PtrStrideOp::create(builder, loc, eltTy, - currentElement, stride); - builder.createStore(loc, prevElement, tmpAddr); - cloneRegionBodyInto(bodyBlock, prevElement); - } - - builder.createYield(loc); - }); + mlir::Block *partialDtorBlock = nullptr; + if (auto arrayCtor = mlir::dyn_cast<cir::ArrayCtor>(op)) { + mlir::Region &partialDtor = arrayCtor.getPartialDtor(); + if (!partialDtor.empty()) + partialDtorBlock = &partialDtor.front(); + } + + auto emitCtorDtorLoop = [&]() { + builder.createDoWhile( + loc, + /*condBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr); + auto cmp = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, + currentElement, stop); + builder.createCondition(cmp); + }, + /*bodyBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + auto currentElement = cir::LoadOp::create(b, loc, eltTy, tmpAddr); + if (isCtor) { + cloneRegionBodyInto(bodyBlock, currentElement); + mlir::Value stride = builder.getUnsignedInt(loc, 1, sizeTypeSize); + auto nextElement = cir::PtrStrideOp::create(builder, loc, eltTy, + currentElement, stride); + builder.createStore(loc, nextElement, tmpAddr); + } else { + mlir::Value stride = builder.getSignedInt(loc, -1, sizeTypeSize); + auto prevElement = cir::PtrStrideOp::create(builder, loc, eltTy, + currentElement, stride); + builder.createStore(loc, prevElement, tmpAddr); + cloneRegionBodyInto(bodyBlock, prevElement); + } + + builder.createYield(loc); + }); + }; + + if (partialDtorBlock) { + cir::CleanupScopeOp::create( + builder, loc, cir::CleanupKind::EH, + /*bodyBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + emitCtorDtorLoop(); + builder.createYield(loc); + }, + /*cleanupBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + auto cur = cir::LoadOp::create(b, loc, eltTy, tmpAddr); + auto cmp = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, + cur, begin); + cir::IfOp::create( + builder, loc, cmp, /*withElseRegion=*/false, + [&](mlir::OpBuilder &b, mlir::Location loc) { + builder.createDoWhile( + loc, + /*condBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + auto el = + cir::LoadOp::create(b, loc, eltTy, tmpAddr); + auto neq = cir::CmpOp::create( + builder, loc, cir::CmpOpKind::ne, el, begin); + builder.createCondition(neq); + }, + /*bodyBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + auto el = + cir::LoadOp::create(b, loc, eltTy, tmpAddr); + mlir::Value negOne = + builder.getSignedInt(loc, -1, sizeTypeSize); + auto prev = cir::PtrStrideOp::create( + builder, loc, eltTy, el, negOne); + builder.createStore(loc, prev, tmpAddr); + cloneRegionBodyInto(partialDtorBlock, prev); + builder.createYield(loc); + }); + cir::YieldOp::create(builder, loc); + }); + builder.createYield(loc); + }); + } else { + emitCtorDtorLoop(); + } if (ifOp) cir::YieldOp::create(builder, loc); diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp index 2233529a192c8..f58a46d4afc49 100644 --- a/clang/test/CIR/CodeGen/array-ctor.cpp +++ b/clang/test/CIR/CodeGen/array-ctor.cpp @@ -173,3 +173,16 @@ void multi_dimensional() { // OGCG: br i1 %[[DONE]], label %[[EXIT:.*]], label %[[LOOP]] // OGCG: [[EXIT]]: // OGCG: ret void + +struct HasDtor { + HasDtor(); + ~HasDtor(); +}; + +void test_partial_array_cleanup() { + HasDtor s[4]; +} + +// CIR-BEFORE-LPP: cir.func {{.*}} @_Z26test_partial_array_cleanupv() + +// CIR: cir.func {{.*}} @_Z26test_partial_array_cleanupv() diff --git a/clang/test/CIR/CodeGen/partial-array-cleanup.cpp b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp new file mode 100644 index 0000000000000..f41f80ab601e0 --- /dev/null +++ b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp @@ -0,0 +1,163 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -fexceptions -fcxx-exceptions -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before-lp.cir +// RUN: FileCheck --input-file=%t-before-lp.cir %s -check-prefix=CIR-BEFORE-LPP +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fexceptions -fcxx-exceptions -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 -fexceptions -fcxx-exceptions -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +struct S { + S(); + ~S(); +}; + +void test_partial_array_cleanup() { + S s[4]; +} + +// CIR-BEFORE-LPP: cir.func {{.*}} @_Z26test_partial_array_cleanupv() +// CIR-BEFORE-LPP: %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 4>, !cir.ptr<!cir.array<!rec_S x 4>>, ["s", init] +// CIR-BEFORE-LPP: cir.array.ctor %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 4>> { +// CIR-BEFORE-LPP: ^bb0(%[[CTOR_ARG:.*]]: !cir.ptr<!rec_S>): +// CIR-BEFORE-LPP: cir.call @_ZN1SC1Ev(%[[CTOR_ARG]]) : (!cir.ptr<!rec_S>{{.*}}) -> () +// CIR-BEFORE-LPP: cir.yield +// CIR-BEFORE-LPP: } partial_dtor { +// CIR-BEFORE-LPP: ^bb0(%[[DTOR_ARG:.*]]: !cir.ptr<!rec_S>): +// CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%[[DTOR_ARG]]){{.*}} : (!cir.ptr<!rec_S>{{.*}}) -> () +// CIR-BEFORE-LPP: cir.yield +// CIR-BEFORE-LPP: } + +// CIR: cir.func {{.*}} @_Z26test_partial_array_cleanupv() +// CIR: %[[ARRAY:.*]] = cir.alloca !cir.array<!rec_S x 4>, !cir.ptr<!cir.array<!rec_S x 4>>, ["s", init] +// CIR: %[[CONST4:.*]] = cir.const #cir.int<4> : !u64i +// CIR: %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 4>> -> !cir.ptr<!rec_S> +// CIR: %[[END:.*]] = cir.ptr_stride %[[BEGIN]], %[[CONST4]] : (!cir.ptr<!rec_S>, !u64i) -> !cir.ptr<!rec_S> +// CIR: %[[ITER:.*]] = cir.alloca !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>, ["__array_idx"] +// CIR: cir.store %[[BEGIN]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>> +// CIR: cir.cleanup.scope { +// CIR: cir.do { +// CIR: %[[CUR:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: cir.call @_ZN1SC1Ev(%[[CUR]]) : (!cir.ptr<!rec_S>{{.*}}) -> () +// CIR: %[[CONST1:.*]] = cir.const #cir.int<1> : !u64i +// CIR: %[[NEXT:.*]] = cir.ptr_stride %[[CUR]], %[[CONST1]] : (!cir.ptr<!rec_S>, !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: %[[CUR2:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: %[[CMP:.*]] = cir.cmp ne %[[CUR2]], %[[END]] : !cir.ptr<!rec_S> +// CIR: cir.condition(%[[CMP]]) +// CIR: } +// CIR: cir.yield +// CIR: } cleanup eh { +// CIR: %[[CUR3:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: %[[NE:.*]] = cir.cmp ne %[[CUR3]], %[[BEGIN]] : !cir.ptr<!rec_S> +// CIR: cir.if %[[NE]] { +// CIR: cir.do { +// CIR: %[[EL:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: %[[NEG1:.*]] = cir.const #cir.int<-1> : !s64i +// CIR: %[[PREV:.*]] = cir.ptr_stride %[[EL]], %[[NEG1]] : (!cir.ptr<!rec_S>, !s64i) -> !cir.ptr<!rec_S> +// CIR: cir.store %[[PREV]], %[[ITER]] : !cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>> +// CIR: cir.call @_ZN1SD1Ev(%[[PREV]]){{.*}} : (!cir.ptr<!rec_S>{{.*}}) -> () +// CIR: cir.yield +// CIR: } while { +// CIR: %[[EL2:.*]] = cir.load %[[ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S> +// CIR: %[[NE2:.*]] = cir.cmp ne %[[EL2]], %[[BEGIN]] : !cir.ptr<!rec_S> +// CIR: cir.condition(%[[NE2]]) +// CIR: } +// CIR: } +// CIR: cir.yield +// CIR: } + +// LLVM: define dso_local void @_Z26test_partial_array_cleanupv() +// LLVM: %[[ARRAY:.*]] = alloca [4 x %struct.S] +// LLVM: %[[BEGIN:.*]] = getelementptr %struct.S, ptr %[[ARRAY]], i32 0 +// LLVM: %[[END:.*]] = getelementptr %struct.S, ptr %[[BEGIN]], i64 4 +// LLVM: %[[ITER:.*]] = alloca ptr +// LLVM: store ptr %[[BEGIN]], ptr %[[ITER]] +// +// --- ctor loop condition --- +// LLVM: [[CLEANUP_SCOPE:.*]]: +// LLVM: br label %[[CTOR_LOOP_COND:.*]] +// +// LLVM: [[CTOR_LOOP_COND:]]: +// LLVM: %[[COND_CUR:.*]] = load ptr, ptr %[[ITER]] +// LLVM: %[[CTOR_DONE:.*]] = icmp ne ptr %[[COND_CUR]], %[[END]] +// LLVM: br i1 %[[CTOR_DONE]], label %[[CTOR_BODY:.*]], label %[[CTOR_EXIT:.*]] +// +// --- ctor loop body --- +// LLVM: [[CTOR_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[ITER]] +// LLVM: invoke void @_ZN1SC1Ev(ptr{{.*}} %[[CUR]]) +// LLVM: to label %[[CTOR_CONT:.*]] unwind label %[[LPAD:.*]] +// +// LLVM: [[CTOR_CONT]]: +// LLVM: %[[NEXT:.*]] = getelementptr %struct.S, ptr %[[CUR]], i64 1 +// LLVM: store ptr %[[NEXT]], ptr %[[ITER]] +// LLVM: br label %[[CTOR_LOOP_COND]] +// +// --- landing pad + cleanup guard --- +// LLVM: [[LPAD]]: +// LLVM: landingpad { ptr, i32 } +// LLVM: cleanup +// LLVM: %[[PAD_CUR:.*]] = load ptr, ptr %[[ITER]] +// LLVM: %[[GUARD:.*]] = icmp ne ptr %[[PAD_CUR]], %[[BEGIN]] +// LLVM: br i1 %[[GUARD]], label %[[DTOR_ENTRY:.*]], label %[[EH_RESUME:.*]] +// +// --- partial dtor do-while entry --- +// LLVM: [[DTOR_ENTRY]]: +// LLVM: br label %[[DTOR_BODY:.*]] +// +// --- partial dtor loop condition (back-edge) --- +// LLVM: [[DTOR_LOOP_COND:.*]]: +// LLVM: %[[DTOR_CUR:.*]] = load ptr, ptr %[[ITER]] +// LLVM: %[[DTOR_CONT:.*]] = icmp ne ptr %[[DTOR_CUR]], %[[BEGIN]] +// LLVM: br i1 %[[DTOR_CONT]], label %[[DTOR_BODY]], label %[[DTOR_DONE:.*]] +// +// --- partial dtor loop body --- +// LLVM: [[DTOR_BODY]]: +// LLVM: %[[DCUR:.*]] = load ptr, ptr %[[ITER]] +// LLVM: %[[PREV:.*]] = getelementptr %struct.S, ptr %[[DCUR]], i64 -1 +// LLVM: store ptr %[[PREV]], ptr %[[ITER]] +// LLVM: call void @_ZN1SD1Ev(ptr{{.*}} %[[PREV]]) +// LLVM: br label %[[DTOR_LOOP_COND]] +// +// LLVM: [[DTOR_DONE]]: +// LLVM: br label %[[EH_RESUME]] +// +// LLVM: [[EH_RESUME]]: +// LLVM: resume { ptr, i32 } + +// OGCG: define dso_local void @_Z26test_partial_array_cleanupv() +// OGCG: [[ENTRY:.*]]: +// OGCG: %[[ARRAY:.*]] = alloca [4 x %struct.S] +// OGCG: %[[BEGIN:.*]] = getelementptr inbounds [4 x %struct.S], ptr %[[ARRAY]], i32 0, i32 0 +// OGCG: %[[END:.*]] = getelementptr inbounds %struct.S, ptr %[[BEGIN]], i64 4 +// +// --- ctor loop --- +// OGCG: [[CTOR_BODY:.*]]: +// OGCG: %[[CUR:.*]] = phi ptr [ %[[BEGIN]], %[[ENTRY]] ], [ %[[NEXT:.*]], %[[CONT:.*]] ] +// OGCG: invoke void @_ZN1SC1Ev(ptr{{.*}}) +// OGCG: to label %[[CONT]] unwind label %[[LPAD:.*]] +// +// OGCG: [[CONT]]: +// OGCG: %[[NEXT]] = getelementptr inbounds %struct.S, ptr %[[CUR]], i64 1 +// OGCG: %[[DONE:.*]] = icmp eq ptr %[[NEXT]], %[[END]] +// OGCG: br i1 %[[DONE]], label %[[CTOR_EXIT:.*]], label %[[CTOR_BODY:.*]] +// +// --- landing pad + cleanup guard --- +// OGCG: [[LPAD]]: +// OGCG: landingpad { ptr, i32 } +// OGCG: cleanup +// OGCG: %[[ISEMPTY:.*]] = icmp eq ptr %[[BEGIN]], %[[CUR]] +// OGCG: br i1 %[[ISEMPTY]], label %[[EH_RESUME:.*]], label %[[DTOR_LOOP:.*]] +// +// --- partial dtor loop --- +// OGCG: [[DTOR_LOOP]]: +// OGCG: %[[PAST:.*]] = phi ptr [ %[[CUR]], %[[LPAD]] ], [ %[[PREV:.*]], %[[DTOR_LOOP]] ] +// OGCG: %[[PREV]] = getelementptr inbounds %struct.S, ptr %[[PAST]], i64 -1 +// OGCG: call void @_ZN1SD1Ev(ptr{{.*}} %[[PREV]]) +// OGCG: %[[DDONE:.*]] = icmp eq ptr %[[PREV]], %[[BEGIN]] +// OGCG: br i1 %[[DDONE]], label %[[EH_RESUME]], label %[[DTOR_LOOP]] +// +// OGCG: [[EH_RESUME]]: +// OGCG: resume { ptr, i32 } >From 6fe2848c813506c0b4e182f568b7b0fe8d90b06d Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Tue, 7 Apr 2026 13:07:44 -0700 Subject: [PATCH 2/4] Fix formatting --- clang/lib/CIR/CodeGen/CIRGenClass.cpp | 3 +-- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 3 +-- .../CIR/Dialect/Transforms/LoweringPrepare.cpp | 16 +++++++--------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 02e074200204d..748d450d6dc10 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -784,8 +784,7 @@ void CIRGenFunction::emitCXXAggrConstructorCall( RunCleanupsScope scope(*this); bool needsPartialArrayCleanup = - getLangOpts().Exceptions && - !ctor->getParent()->hasTrivialDestructor(); + getLangOpts().Exceptions && !ctor->getParent()->hasTrivialDestructor(); auto emitCtorBody = [&](mlir::OpBuilder &b, mlir::Location l) { mlir::BlockArgument arg = diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 3e020e52ebece..61f61466c7e2e 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -419,8 +419,7 @@ LogicalResult cir::ArrayCtor::verify() { if (!partialDtor.empty()) { mlir::Block &dtorBlock = partialDtor.front(); if (dtorBlock.getNumArguments() != 1) - return emitOpError( - "partial_dtor must have exactly one block argument"); + return emitOpError("partial_dtor must have exactly one block argument"); auto bodyArgTy = getBody().front().getArgument(0).getType(); if (dtorBlock.getArgument(0).getType() != bodyArgTy) diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index f5ab406789882..5e00e0c8fb146 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -1435,7 +1435,7 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, // Clone the region body (ctor/dtor call and any setup ops like per-element // zero-init) into the loop, remapping the block argument to the current - // element pointer. + // element pointer. auto cloneRegionBodyInto = [&](mlir::Block *srcBlock, mlir::Value replacement) { mlir::IRMapping map; @@ -1495,8 +1495,8 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, /*cleanupBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { auto cur = cir::LoadOp::create(b, loc, eltTy, tmpAddr); - auto cmp = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, - cur, begin); + auto cmp = + cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, cur, begin); cir::IfOp::create( builder, loc, cmp, /*withElseRegion=*/false, [&](mlir::OpBuilder &b, mlir::Location loc) { @@ -1504,20 +1504,18 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, loc, /*condBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { - auto el = - cir::LoadOp::create(b, loc, eltTy, tmpAddr); + auto el = cir::LoadOp::create(b, loc, eltTy, tmpAddr); auto neq = cir::CmpOp::create( builder, loc, cir::CmpOpKind::ne, el, begin); builder.createCondition(neq); }, /*bodyBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { - auto el = - cir::LoadOp::create(b, loc, eltTy, tmpAddr); + auto el = cir::LoadOp::create(b, loc, eltTy, tmpAddr); mlir::Value negOne = builder.getSignedInt(loc, -1, sizeTypeSize); - auto prev = cir::PtrStrideOp::create( - builder, loc, eltTy, el, negOne); + auto prev = cir::PtrStrideOp::create(builder, loc, eltTy, + el, negOne); builder.createStore(loc, prev, tmpAddr); cloneRegionBodyInto(partialDtorBlock, prev); builder.createYield(loc); >From f76854ddc3106d8ca7d5af2e9a7b92dbc5637063 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Tue, 7 Apr 2026 16:37:18 -0700 Subject: [PATCH 3/4] Address review feedback --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 21 +++--- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 70 ------------------- .../Dialect/Transforms/LoweringPrepare.cpp | 6 +- clang/test/CIR/CodeGen/array-ctor.cpp | 2 - clang/test/CIR/CodeGen/array-dtor.cpp | 2 - clang/test/CIR/CodeGen/global-array-dtor.cpp | 1 - clang/test/CIR/CodeGen/global-init.cpp | 1 - clang/test/CIR/CodeGen/new.cpp | 6 -- .../CIR/CodeGen/partial-array-cleanup.cpp | 2 - clang/test/CIR/IR/array-ctor.cir | 4 -- clang/test/CIR/IR/array-dtor.cir | 2 - clang/test/CIR/IR/invalid-array-structor.cir | 11 --- 12 files changed, 15 insertions(+), 113 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index bbe1ff71da9f3..93ca0172b2a7f 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4574,7 +4574,9 @@ def CIR_TrapOp : CIR_Op<"trap", [Terminator]> { // ArrayCtor & ArrayDtor //===----------------------------------------------------------------------===// -def CIR_ArrayCtor : CIR_Op<"array.ctor"> { +def CIR_ArrayCtor : CIR_Op<"array.ctor", [ + SingleBlockImplicitTerminator<"cir::YieldOp"> +]> { let summary = "Initialize array elements with C++ constructors"; let description = [{ Initialize each array element using the same C++ constructor. This @@ -4604,25 +4606,21 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> { cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { ^bb0(%arg0: !cir.ptr<!rec_S>): cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> () - cir.yield } // Variable size without partial destructor: 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 } // Fixed size with partial destructor: cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) { ^bb0(%arg0: !cir.ptr<!rec_S>): cir.call @some_ctor(%arg0) : (!cir.ptr<!rec_S>) -> () - cir.yield } partial_dtor { ^bb0(%arg0: !cir.ptr<!rec_S>): cir.call @some_dtor(%arg0) : (!cir.ptr<!rec_S>) -> () - cir.yield } ``` }]; @@ -4633,7 +4631,12 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> { ); let regions = (region SizedRegion<1>:$body, AnyRegion:$partial_dtor); - let hasCustomAssemblyFormat = 1; + let assemblyFormat = [{ + $addr (`,` $num_elements^)? `:` qualified(type($addr)) + (`,` type($num_elements)^)? $body + (`partial_dtor` $partial_dtor^)? + attr-dict + }]; let builders = [ // Static form: addr is ptr<array<T x N>>, no num_elements. @@ -4674,7 +4677,9 @@ def CIR_ArrayCtor : CIR_Op<"array.ctor"> { let hasLLVMLowering = false; } -def CIR_ArrayDtor : CIR_Op<"array.dtor"> { +def CIR_ArrayDtor : CIR_Op<"array.dtor", [ + SingleBlockImplicitTerminator<"cir::YieldOp"> +]> { let summary = "Destroy array elements with C++ destructors"; let description = [{ Destroy each array element using the same C++ destructor. This operation @@ -4697,14 +4702,12 @@ def CIR_ArrayDtor : CIR_Op<"array.dtor"> { cir.array.dtor %0 : !cir.ptr<!cir.array<!rec_S x 42>> { ^bb0(%arg0: !cir.ptr<!rec_S>): cir.call @_ZN1SD1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () - cir.yield } // Dynamic count (delete[] with destructor): cir.array.dtor %ptr, %n : !cir.ptr<!rec_S>, !u64i { ^bb0(%arg0: !cir.ptr<!rec_S>): cir.call @_ZN1SD1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () - cir.yield } ``` }]; diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 61f61466c7e2e..e99faf840c15a 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -341,76 +341,6 @@ template <typename Op> static LogicalResult verifyArrayCtorDtor(Op op) { return success(); } -ParseResult cir::ArrayCtor::parse(OpAsmParser &parser, OperationState &result) { - OpAsmParser::UnresolvedOperand addrOperand; - OpAsmParser::UnresolvedOperand numElementsOperand; - bool hasNumElements = false; - - if (parser.parseOperand(addrOperand)) - return failure(); - - if (succeeded(parser.parseOptionalComma())) { - if (parser.parseOperand(numElementsOperand)) - return failure(); - hasNumElements = true; - } - - if (parser.parseColon()) - return failure(); - - mlir::Type addrType; - if (parser.parseType(addrType)) - return failure(); - if (parser.resolveOperand(addrOperand, addrType, result.operands)) - return failure(); - - if (hasNumElements) { - if (parser.parseComma()) - return failure(); - mlir::Type numElementsType; - if (parser.parseType(numElementsType)) - return failure(); - if (parser.resolveOperand(numElementsOperand, numElementsType, - result.operands)) - return failure(); - } - - Region *body = result.addRegion(); - if (parser.parseRegion(*body)) - return failure(); - - Region *partialDtor = result.addRegion(); - if (!parser.parseOptionalKeyword("partial_dtor")) { - if (parser.parseRegion(*partialDtor)) - return failure(); - } - - if (parser.parseOptionalAttrDict(result.attributes)) - return failure(); - - return success(); -} - -void cir::ArrayCtor::print(OpAsmPrinter &p) { - p << " " << getAddr(); - if (getNumElements()) - p << ", " << getNumElements(); - - p << " : " << getAddr().getType(); - if (getNumElements()) - p << ", " << getNumElements().getType(); - - p << " "; - p.printRegion(getBody()); - - if (!getPartialDtor().empty()) { - p << " partial_dtor "; - p.printRegion(getPartialDtor()); - } - - p.printOptionalAttrDict(getOperation()->getAttrs()); -} - LogicalResult cir::ArrayCtor::verify() { if (failed(verifyArrayCtorDtor(*this))) return failure(); diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 5e00e0c8fb146..482e73f9f3050 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -1480,7 +1480,7 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, cloneRegionBodyInto(bodyBlock, prevElement); } - builder.createYield(loc); + cir::YieldOp::create(b, loc); }); }; @@ -1490,7 +1490,7 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, /*bodyBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { emitCtorDtorLoop(); - builder.createYield(loc); + cir::YieldOp::create(b, loc); }, /*cleanupBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { @@ -1522,7 +1522,7 @@ static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder, }); cir::YieldOp::create(builder, loc); }); - builder.createYield(loc); + cir::YieldOp::create(b, loc); }); } else { emitCtorDtorLoop(); diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp index f58a46d4afc49..be5856456ed90 100644 --- a/clang/test/CIR/CodeGen/array-ctor.cpp +++ b/clang/test/CIR/CodeGen/array-ctor.cpp @@ -19,7 +19,6 @@ void foo() { // 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: } @@ -115,7 +114,6 @@ void multi_dimensional() { // CIR-BEFORE-LPP: cir.array.ctor %[[FLAT]] : !cir.ptr<!cir.array<!rec_S x 15>> { // 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 diff --git a/clang/test/CIR/CodeGen/array-dtor.cpp b/clang/test/CIR/CodeGen/array-dtor.cpp index d37b6323575d6..5bfe9ac897cb7 100644 --- a/clang/test/CIR/CodeGen/array-dtor.cpp +++ b/clang/test/CIR/CodeGen/array-dtor.cpp @@ -19,7 +19,6 @@ void test_cleanup_array() { // CIR-BEFORE-LPP: cir.array.dtor %[[S]] : !cir.ptr<!cir.array<!rec_S x 42>> { // CIR-BEFORE-LPP: ^bb0(%arg0: !cir.ptr<!rec_S> // CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%arg0) nothrow : (!cir.ptr<!rec_S> {{.*}}) -> () -// CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: cir.return @@ -113,7 +112,6 @@ void multi_dimensional() { // CIR-BEFORE-LPP: cir.array.dtor %[[FLAT]] : !cir.ptr<!cir.array<!rec_S x 15>> { // CIR-BEFORE-LPP: ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_S>): // CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%[[ARG]]) nothrow : (!cir.ptr<!rec_S> {{.*}}) -> () -// CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: cir.return diff --git a/clang/test/CIR/CodeGen/global-array-dtor.cpp b/clang/test/CIR/CodeGen/global-array-dtor.cpp index 61b1717b156fb..49c8e279c2678 100644 --- a/clang/test/CIR/CodeGen/global-array-dtor.cpp +++ b/clang/test/CIR/CodeGen/global-array-dtor.cpp @@ -22,7 +22,6 @@ ArrayDtor arrDtor[16]; // CIR-BEFORE-LPP: cir.array.dtor %[[THIS]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> { // CIR-BEFORE-LPP: ^bb0(%[[ELEM:.*]]: !cir.ptr<!rec_ArrayDtor>): // CIR-BEFORE-LPP: cir.call @_ZN9ArrayDtorD1Ev(%[[ELEM]]) nothrow : (!cir.ptr<!rec_ArrayDtor> {{.*}}) -> () -// CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: } diff --git a/clang/test/CIR/CodeGen/global-init.cpp b/clang/test/CIR/CodeGen/global-init.cpp index 7c6405543b3fe..7ef21cab24940 100644 --- a/clang/test/CIR/CodeGen/global-init.cpp +++ b/clang/test/CIR/CodeGen/global-init.cpp @@ -183,7 +183,6 @@ ArrayDtor arrDtor[16]; // CIR-BEFORE-LPP: cir.array.dtor %[[THIS]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> { // CIR-BEFORE-LPP: ^bb0(%[[ELEM:.*]]: !cir.ptr<!rec_ArrayDtor>): // CIR-BEFORE-LPP: cir.call @_ZN9ArrayDtorD1Ev(%[[ELEM]]) nothrow : (!cir.ptr<!rec_ArrayDtor> {{.*}}) -> () -// CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: } diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index 7da943de355ef..503b395244bd8 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -742,7 +742,6 @@ void test_array_new_with_ctor_init() { // CIR-BEFORE-LPP: cir.array.ctor %[[ARRAY_PTR]] : !cir.ptr<!cir.array<!rec_F x 3>> { // CIR-BEFORE-LPP: ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_F>): // CIR-BEFORE-LPP: cir.call @_ZN1FC1Ev(%[[ARG]]) : (!cir.ptr<!rec_F> {{.*}}) -> () -// CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: cir.store{{.*}} %[[BEGIN]], %[[P_ADDR]] : !cir.ptr<!rec_F>, !cir.ptr<!cir.ptr<!rec_F>> // CIR-BEFORE-LPP: cir.return @@ -868,7 +867,6 @@ void test_const_array_new_value_init() { // CIR-BEFORE-LPP: cir.const #cir.zero : !rec_OuterZero // CIR-BEFORE-LPP: cir.store{{.*}} %{{.*}}, %[[EL]] : !rec_OuterZero, !cir.ptr<!rec_OuterZero> // CIR-BEFORE-LPP: cir.call @_ZN9OuterZeroC1Ev(%[[EL]]) -// CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } // CHECK: cir.func{{.*}} @_Z31test_const_array_new_value_initv @@ -949,7 +947,6 @@ void test_var_array_new_value_init(int n) { // 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 @@ -990,7 +987,6 @@ void test_multidim_array_new_with_ctor() { // CIR-BEFORE-LPP: cir.array.ctor %[[FLAT]] : !cir.ptr<!cir.array<!rec_F x 6>> { // CIR-BEFORE-LPP: ^bb0(%[[ARG:.*]]: !cir.ptr<!rec_F>): // CIR-BEFORE-LPP: cir.call @_ZN1FC1Ev(%[[ARG]]) -// CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: cir.store{{.*}} %[[PTR3]], @@ -1059,7 +1055,6 @@ void test_multidim_var_array_new_with_ctor(int n) { // 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 @@ -1129,7 +1124,6 @@ void test_array_new_with_ctor_partial_init_list() { // CIR-BEFORE-LPP: cir.array.ctor %[[TAIL_ARRAY]] : !cir.ptr<!cir.array<!rec_G x 6>> { // CIR-BEFORE-LPP: ^bb0(%[[ELEM:.*]]: !cir.ptr<!rec_G>): // CIR-BEFORE-LPP: cir.call @_ZN1GC1Ev(%[[ELEM]]) : (!cir.ptr<!rec_G> {{.*}}) -> () -// CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: cir.store{{.*}} %[[BEGIN]], %[[P_ADDR]] // CIR-BEFORE-LPP: cir.return diff --git a/clang/test/CIR/CodeGen/partial-array-cleanup.cpp b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp index f41f80ab601e0..7c260a6f13cb0 100644 --- a/clang/test/CIR/CodeGen/partial-array-cleanup.cpp +++ b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp @@ -20,11 +20,9 @@ void test_partial_array_cleanup() { // CIR-BEFORE-LPP: cir.array.ctor %[[ARRAY]] : !cir.ptr<!cir.array<!rec_S x 4>> { // CIR-BEFORE-LPP: ^bb0(%[[CTOR_ARG:.*]]: !cir.ptr<!rec_S>): // CIR-BEFORE-LPP: cir.call @_ZN1SC1Ev(%[[CTOR_ARG]]) : (!cir.ptr<!rec_S>{{.*}}) -> () -// CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } partial_dtor { // CIR-BEFORE-LPP: ^bb0(%[[DTOR_ARG:.*]]: !cir.ptr<!rec_S>): // CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%[[DTOR_ARG]]){{.*}} : (!cir.ptr<!rec_S>{{.*}}) -> () -// CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } // CIR: cir.func {{.*}} @_Z26test_partial_array_cleanupv() diff --git a/clang/test/CIR/IR/array-ctor.cir b/clang/test/CIR/IR/array-ctor.cir index 0a71b1e4dee6d..b68108b1763eb 100644 --- a/clang/test/CIR/IR/array-ctor.cir +++ b/clang/test/CIR/IR/array-ctor.cir @@ -12,7 +12,6 @@ module { 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 } @@ -23,7 +22,6 @@ module { // 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: } @@ -32,7 +30,6 @@ module { cir.array.ctor %p, %n : !cir.ptr<!rec_S>, !u64i { ^bb0(%e: !cir.ptr<!rec_S>): cir.call @_ZN1SC1Ev(%e) : (!cir.ptr<!rec_S>) -> () - cir.yield } cir.return } @@ -41,7 +38,6 @@ module { // CHECK: cir.array.ctor %{{.*}}, %{{.*}} : !cir.ptr<!rec_S>, !u64i { // CHECK: ^bb0(%{{.*}}: !cir.ptr<!rec_S>): // CHECK: cir.call @_ZN1SC1Ev(%{{.*}}) : (!cir.ptr<!rec_S>) -> () - // CHECK: cir.yield // CHECK: } // CHECK: cir.return // CHECK: } diff --git a/clang/test/CIR/IR/array-dtor.cir b/clang/test/CIR/IR/array-dtor.cir index 1bb9ff9169a9d..37515f98626be 100644 --- a/clang/test/CIR/IR/array-dtor.cir +++ b/clang/test/CIR/IR/array-dtor.cir @@ -10,7 +10,6 @@ module { cir.array.dtor %0 : !cir.ptr<!cir.array<!rec_S x 42>> { ^bb0(%arg0: !cir.ptr<!rec_S>): cir.call @_ZN1SD1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () - cir.yield } cir.return } @@ -21,7 +20,6 @@ module { // CHECK: cir.array.dtor %0 : !cir.ptr<!cir.array<!rec_S x 42>> { // CHECK: ^bb0(%arg0: !cir.ptr<!rec_S>): // CHECK: cir.call @_ZN1SD1Ev(%arg0) : (!cir.ptr<!rec_S>) -> () - // CHECK: cir.yield // CHECK: } // CHECK: cir.return // CHECK: } diff --git a/clang/test/CIR/IR/invalid-array-structor.cir b/clang/test/CIR/IR/invalid-array-structor.cir index 0ab030231f703..233b3524a2369 100644 --- a/clang/test/CIR/IR/invalid-array-structor.cir +++ b/clang/test/CIR/IR/invalid-array-structor.cir @@ -10,7 +10,6 @@ module { // expected-error@+1 {{'cir.array.ctor' op when 'num_elements' is present, 'addr' must be a pointer to a !cir.record type}} cir.array.ctor %p, %n : !cir.ptr<!cir.array<!rec_S x 10>>, !u64i { ^bb0(%e: !cir.ptr<!cir.array<!rec_S x 10>>): - cir.yield } cir.return } @@ -31,7 +30,6 @@ module { cir.array.ctor %p : !cir.ptr<!rec_S> { ^bb0(%e: !cir.ptr<!rec_S>): cir.call @_ZN1SC1Ev(%e) : (!cir.ptr<!rec_S>) -> () - cir.yield } cir.return } @@ -51,7 +49,6 @@ module { cir.array.ctor %p : !cir.ptr<!cir.array<!u8i x 4>> { ^bb0(%e: !cir.ptr<!u8i>): cir.call @construct_int(%e) : (!cir.ptr<!u8i>) -> () - cir.yield } cir.return } @@ -72,7 +69,6 @@ module { // expected-error@+1 {{'cir.array.ctor' op block argument pointee type must match the innermost array element type}} cir.array.ctor %p : !cir.ptr<!cir.array<!rec_S x 10>> { ^bb0(%e: !cir.ptr<!rec_T>): - cir.yield } cir.return } @@ -94,7 +90,6 @@ module { cir.array.ctor %p, %n : !cir.ptr<!rec_T>, !u64i { ^bb0(%e: !cir.ptr<!rec_S>): cir.call @_ZN1SC1Ev(%e) : (!cir.ptr<!rec_S>) -> () - cir.yield } cir.return } @@ -111,7 +106,6 @@ module { // expected-error@+1 {{'cir.array.dtor' op when 'num_elements' is present, 'addr' must be a pointer to a !cir.record type}} cir.array.dtor %p, %n : !cir.ptr<!cir.array<!rec_S x 10>>, !u64i { ^bb0(%e: !cir.ptr<!cir.array<!rec_S x 10>>): - cir.yield } cir.return } @@ -129,7 +123,6 @@ module { // expected-error@+1 {{'cir.array.dtor' op when 'num_elements' is absent, 'addr' must be a pointer to a !cir.array type}} cir.array.dtor %p : !cir.ptr<!rec_S> { ^bb0(%e: !cir.ptr<!rec_S>): - cir.yield } cir.return } @@ -149,7 +142,6 @@ module { cir.array.dtor %p : !cir.ptr<!cir.array<!u8i x 4>> { ^bb0(%e: !cir.ptr<!u8i>): cir.call @destroy_int(%e) : (!cir.ptr<!u8i>) -> () - cir.yield } cir.return } @@ -168,7 +160,6 @@ module { // expected-error@+1 {{'cir.array.dtor' op block argument pointee type must match the innermost array element type}} cir.array.dtor %p: !cir.ptr<!cir.array<!rec_S x 10>> { ^bb0(%e: !cir.ptr<!rec_T>): - cir.yield } cir.return } @@ -189,7 +180,6 @@ module { // expected-error@+1 {{'cir.array.dtor' op block argument pointee type must match the innermost array element type}} cir.array.dtor %p : !cir.ptr<!cir.array<!rec_S x 10>> { ^bb0(%e: !cir.ptr<!rec_T>): - cir.yield } cir.return } @@ -211,7 +201,6 @@ module { cir.array.dtor %p, %n : !cir.ptr<!rec_T>, !u64i { ^bb0(%e: !cir.ptr<!rec_S>): cir.call @_ZN1SD1Ev(%e) : (!cir.ptr<!rec_S>) -> () - cir.yield } cir.return } >From f9b25b24bf1bb9c6b50b665263da5ba179d8052a Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Tue, 7 Apr 2026 16:48:47 -0700 Subject: [PATCH 4/4] Remove stray test I inadvertantly left a test case in array-ctor.cpp that was part of an exploration for the next PR in this series. It wasn't actually testing anything useful here. --- clang/test/CIR/CodeGen/array-ctor.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/clang/test/CIR/CodeGen/array-ctor.cpp b/clang/test/CIR/CodeGen/array-ctor.cpp index be5856456ed90..4a3a4f51db13b 100644 --- a/clang/test/CIR/CodeGen/array-ctor.cpp +++ b/clang/test/CIR/CodeGen/array-ctor.cpp @@ -171,16 +171,3 @@ void multi_dimensional() { // OGCG: br i1 %[[DONE]], label %[[EXIT:.*]], label %[[LOOP]] // OGCG: [[EXIT]]: // OGCG: ret void - -struct HasDtor { - HasDtor(); - ~HasDtor(); -}; - -void test_partial_array_cleanup() { - HasDtor s[4]; -} - -// CIR-BEFORE-LPP: cir.func {{.*}} @_Z26test_partial_array_cleanupv() - -// CIR: cir.func {{.*}} @_Z26test_partial_array_cleanupv() _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
