Author: Andy Kaylor
Date: 2026-03-12T16:55:48-07:00
New Revision: ec934142e4b470881ae0081ff505881fd5bb532c

URL: 
https://github.com/llvm/llvm-project/commit/ec934142e4b470881ae0081ff505881fd5bb532c
DIFF: 
https://github.com/llvm/llvm-project/commit/ec934142e4b470881ae0081ff505881fd5bb532c.diff

LOG: [CIR] Implement array delete for destructed types (#186248)

This extends the cir.delete_array lowering code to introduce a loop that
calls destructors when the array being deleted represents a destructed
type. The lowering introduces the destructors by way of a cir.array.dtor
operation, which is further expanded during LoweringPrepare. This also
required updating the cir.array.dtor operation to accept a raw pointer
to the element type and a value representing the number of elements to
be destructed.

This does not yet handle the possibility of destructors throwing
exceptions.

Added: 
    

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIROps.td
    clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
    clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
    clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
    clang/test/CIR/CodeGen/delete-array.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index d10bed40e75d4..a9b98b1f43b3f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4331,7 +4331,24 @@ def CIR_TrapOp : CIR_Op<"trap", [Terminator]> {
 // ArrayCtor & ArrayDtor
 
//===----------------------------------------------------------------------===//
 
-class CIR_ArrayInitDestroy<string mnemonic> : CIR_Op<mnemonic> {
+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.
+
+    Example:
+
+    ```mlir
+    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
+    }
+    ```
+  }];
+
   let arguments = (ins
     Arg<CIR_PtrToArray, "array address", [MemWrite, MemRead]>:$addr
   );
@@ -4356,42 +4373,77 @@ class CIR_ArrayInitDestroy<string mnemonic> : 
CIR_Op<mnemonic> {
   let hasLLVMLowering = false;
 }
 
-def CIR_ArrayCtor : CIR_ArrayInitDestroy<"array.ctor"> {
-  let summary = "Initialize array elements with C++ constructors";
+def CIR_ArrayDtor : CIR_Op<"array.dtor"> {
+  let summary = "Destroy array elements with C++ destructors";
   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.
+    Destroy each array element using the same C++ destructor. This operation
+    has one region with one block whose argument is a pointer to the current
+    array element.
 
-    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 (e.g. from an array
+    cookie for `delete[]`).
+
+    Elements are destroyed in reverse order.
+
+    Examples:
 
     ```mlir
-    cir.array.ctor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) {
+    // Fixed-size (stack array, global):
+    cir.array.dtor %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.call @_ZN1SD1Ev(%arg0) : (!cir.ptr<!rec_S>) -> ()
         cir.yield
     }
-    ```
-  }];
-}
-
-def CIR_ArrayDtor : CIR_ArrayInitDestroy<"array.dtor"> {
-  let summary = "Destroy array elements with C++ dtors";
-  let description = [{
-    Destroy each array element using the same C++ destructor. This
-    operation has one region, with one single block. The block has an
-    incoming argument for the current array element to destruct.
-
-    Example:
 
-    ```mlir
-    cir.array.dtor(%0 : !cir.ptr<!cir.array<!rec_S x 42>>) {
+    // Dynamic count (delete[] with destructor):
+    cir.array.dtor %ptr, %n : !cir.ptr<!rec_S>, !u64i {
       ^bb0(%arg0: !cir.ptr<!rec_S>):
-        cir.call @some_dtor(%arg0) : (!cir.ptr<!rec_S>) -> ()
+        cir.call @_ZN1SD1Ev(%arg0) : (!cir.ptr<!rec_S>) -> ()
         cir.yield
     }
     ```
   }];
+
+  let arguments = (ins
+    Arg<CIR_AnyPtrType, "array or element address", [MemWrite, MemRead]>:$addr,
+    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 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");
+        mlir::OpBuilder::InsertionGuard guard($_builder);
+        mlir::Region *r = $_state.addRegion();
+        $_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 hasLLVMLowering = false;
 }
 
 
//===----------------------------------------------------------------------===//

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
index 0ba7384e307fb..50617a8d04f6d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
@@ -1233,12 +1233,6 @@ void CIRGenFunction::emitCXXDeleteExpr(const 
CXXDeleteExpr *e) {
   }
 
   if (e->isArrayForm()) {
-    // This will be handled in CXXABILowering, but we can emit a better
-    // diagnostic here.
-    if (deleteTy.isDestructedType()) {
-      cgm.errorNYI(e->getSourceRange(),
-                   "emitCXXDeleteExpr: array delete of destructed type");
-    }
     const FunctionDecl *operatorDelete = e->getOperatorDelete();
     cir::FuncOp operatorDeleteFn = cgm.getAddrOfFunction(operatorDelete);
     auto deleteFn =
@@ -1247,8 +1241,24 @@ void CIRGenFunction::emitCXXDeleteExpr(const 
CXXDeleteExpr *e) {
     auto deleteParams = cir::UsualDeleteParamsAttr::get(
         builder.getContext(), udp.Size, isAlignedAllocation(udp.Alignment),
         isTypeAwareAllocation(udp.TypeAwareDelete), udp.DestroyingDelete);
+
+    mlir::FlatSymbolRefAttr elementDtor;
+    if (const auto *rd = deleteTy->getAsCXXRecordDecl()) {
+      if (rd->hasDefinition() && !rd->hasTrivialDestructor()) {
+        const CXXDestructorDecl *dtor = rd->getDestructor();
+        if (dtor->getType()->castAs<FunctionProtoType>()->canThrow())
+          cgm.errorNYI(e->getSourceRange(),
+                       "emitCXXDeleteExpr: throwing destructor");
+        cir::FuncOp dtorFn =
+            cgm.getAddrOfCXXStructor(GlobalDecl(dtor, Dtor_Complete));
+        elementDtor = mlir::FlatSymbolRefAttr::get(builder.getContext(),
+                                                   dtorFn.getSymNameAttr());
+      }
+    }
+
     cir::DeleteArrayOp::create(builder, ptr.getPointer().getLoc(),
-                               ptr.getPointer(), deleteFn, deleteParams);
+                               ptr.getPointer(), deleteFn, deleteParams,
+                               elementDtor);
   } else {
     emitObjectDelete(*this, e, ptr, deleteTy);
   }

diff  --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index f74474cbcfbff..d2c7ac37e8a96 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -15,6 +15,7 @@
 #include "mlir/Transforms/DialectConversion.h"
 #include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
 #include "clang/CIR/Dialect/IR/CIRAttrs.h"
+#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 #include "clang/CIR/Dialect/Passes.h"
@@ -327,7 +328,9 @@ mlir::LogicalResult 
CIRDeleteArrayOpABILowering::matchAndRewrite(
   mlir::Value loweredAddress = adaptor.getAddress();
 
   cir::UsualDeleteParamsAttr deleteParams = op.getDeleteParams();
-  bool sizeNeeded = deleteParams.getSize();
+  bool cookieRequired = deleteParams.getSize();
+  assert((deleteParams.getSize() || !op.getElementDtorAttr()) &&
+         "Expected size parameter when dtor fn is provided!");
 
   if (deleteParams.getTypeAwareDelete() || deleteParams.getDestroyingDelete() 
||
       deleteParams.getAlignment())
@@ -339,7 +342,7 @@ mlir::LogicalResult 
CIRDeleteArrayOpABILowering::matchAndRewrite(
   mlir::Value deletePtr;
   llvm::SmallVector<mlir::Value> callArgs;
 
-  if (sizeNeeded) {
+  if (cookieRequired) {
     mlir::Value numElements;
     clang::CharUnits cookieSize;
     auto ptrTy = mlir::cast<cir::PointerType>(loweredAddress.getType());
@@ -347,6 +350,23 @@ mlir::LogicalResult 
CIRDeleteArrayOpABILowering::matchAndRewrite(
 
     cxxABI.readArrayCookie(loc, loweredAddress, dl, cirBuilder, numElements,
                            deletePtr, cookieSize);
+
+    // If a dtor function is provided, create an array dtor operation.
+    // This will get expanded during LoweringPrepare.
+    mlir::FlatSymbolRefAttr dtorFn = op.getElementDtorAttr();
+    if (dtorFn) {
+      auto eltPtrTy = cir::PointerType::get(ptrTy.getPointee());
+      cir::ArrayDtor::create(
+          rewriter, loc, loweredAddress, numElements,
+          [&](mlir::OpBuilder &b, mlir::Location l) {
+            auto arg = b.getInsertionBlock()->addArgument(eltPtrTy, l);
+            cir::CallOp::create(b, l, dtorFn, cir::VoidType(),
+                                mlir::ValueRange{arg});
+            cir::YieldOp::create(b, l);
+          });
+    }
+
+    // Compute the total allocation size and add it to the call arguments.
     callArgs.push_back(deletePtr);
     uint64_t eltSizeBytes = dl.getTypeSizeInBits(ptrTy.getPointee()) / 8;
     unsigned ptrWidth =

diff  --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp 
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 232d320d71f37..82bf8dbccba97 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1337,32 +1337,57 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() {
 static void lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder,
                                        clang::ASTContext *astCtx,
                                        mlir::Operation *op, mlir::Type eltTy,
-                                       mlir::Value arrayAddr, uint64_t 
arrayLen,
-                                       bool isCtor) {
+                                       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;
 
   // TODO: instead of getting the size from the AST context, create alias for
   // PtrDiffTy and unify with CIRGen stuff.
   const unsigned sizeTypeSize =
       astCtx->getTypeSize(astCtx->getSignedSizeType());
-  uint64_t endOffset = isCtor ? arrayLen : arrayLen - 1;
-  mlir::Value endOffsetVal =
-      builder.getUnsignedInt(loc, endOffset, sizeTypeSize);
-
-  auto begin = cir::CastOp::create(builder, loc, eltTy,
-                                   cir::CastKind::array_to_ptrdecay, 
arrayAddr);
-  mlir::Value end =
-      cir::PtrStrideOp::create(builder, loc, eltTy, begin, endOffsetVal);
+
+  mlir::Value begin, end;
+  if (isDynamic) {
+    assert(!isCtor && "Unexpected dynamic ctor loop");
+    mlir::Value one = builder.getUnsignedInt(loc, 1, sizeTypeSize);
+    mlir::Value endOffsetVal = builder.createSub(loc, numElements, one);
+    begin = addr;
+    end = cir::PtrStrideOp::create(builder, loc, eltTy, begin, endOffsetVal);
+  } else {
+    // Static: emit endOffset const first, then array_to_ptrdecay, matching
+    // the expected IR ordering.
+    uint64_t endOffset = isCtor ? arrayLen : arrayLen - 1;
+    mlir::Value endOffsetVal =
+        builder.getUnsignedInt(loc, endOffset, sizeTypeSize);
+    begin = cir::CastOp::create(builder, loc, eltTy,
+                                cir::CastKind::array_to_ptrdecay, addr);
+    end = cir::PtrStrideOp::create(builder, loc, eltTy, begin, endOffsetVal);
+  }
+
   mlir::Value start = isCtor ? begin : end;
   mlir::Value stop = isCtor ? end : begin;
 
+  // For dynamic destructors, guard against zero elements.
+  // 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,
+                             /*withElseRegion=*/false,
+                             [&](mlir::OpBuilder &, mlir::Location) {});
+    builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
+  }
+
   mlir::Value tmpAddr = builder.createAlloca(
       loc, /*addr type*/ builder.getPointerTo(eltTy),
       /*var type*/ eltTy, "__array_idx", builder.getAlignmentAttr(1));
   builder.createStore(loc, start, tmpAddr);
 
-  cir::DoWhileOp loop = builder.createDoWhile(
+  builder.createDoWhile(
       loc,
       /*condBuilder=*/
       [&](mlir::OpBuilder &b, mlir::Location loc) {
@@ -1396,7 +1421,9 @@ static void 
lowerArrayDtorCtorIntoLoop(cir::CIRBaseBuilderTy &builder,
         builder.createYield(loc);
       });
 
-  op->replaceAllUsesWith(loop);
+  if (ifOp)
+    cir::YieldOp::create(builder, loc);
+
   op->erase();
 }
 
@@ -1405,11 +1432,20 @@ void LoweringPreparePass::lowerArrayDtor(cir::ArrayDtor 
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=*/false);
+    return;
+  }
+
   assert(!cir::MissingFeatures::vlas());
   auto arrayLen =
       
mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize();
-  lowerArrayDtorCtorIntoLoop(builder, astCtx, op, eltTy, op.getAddr(), 
arrayLen,
-                             false);
+  lowerArrayDtorCtorIntoLoop(builder, astCtx, op, eltTy, op.getAddr(),
+                             /*numElements=*/nullptr, arrayLen,
+                             /*isCtor=*/false);
 }
 
 void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor op) {
@@ -1420,8 +1456,9 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor 
op) {
   assert(!cir::MissingFeatures::vlas());
   auto arrayLen =
       
mlir::cast<cir::ArrayType>(op.getAddr().getType().getPointee()).getSize();
-  lowerArrayDtorCtorIntoLoop(builder, astCtx, op, eltTy, op.getAddr(), 
arrayLen,
-                             true);
+  lowerArrayDtorCtorIntoLoop(builder, astCtx, op, eltTy, op.getAddr(),
+                             /*numElements=*/nullptr, arrayLen,
+                             /*isCtor=*/true);
 }
 
 void LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {

diff  --git a/clang/test/CIR/CodeGen/delete-array.cpp 
b/clang/test/CIR/CodeGen/delete-array.cpp
index 117943f005a0a..2ce2880b9d464 100644
--- a/clang/test/CIR/CodeGen/delete-array.cpp
+++ b/clang/test/CIR/CodeGen/delete-array.cpp
@@ -153,3 +153,124 @@ void test_sized_array_delete(SizedArrayDelete *ptr) {
 // OGCG:   call void @_ZN16SizedArrayDeletedaEPvm(ptr {{.*}} %[[ALLOC_PTR]], 
i64 {{.*}} %[[TOTAL_SIZE]])
 // OGCG:   br label %[[DELETE_END]]
 // OGCG: [[DELETE_END]]:
+
+struct Destructed {
+  ~Destructed();
+  int x;
+};
+void test_delete_array_destructed(Destructed *ptr) {
+  delete[] ptr;
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z28test_delete_array_destructedP10Destructed
+// CIR-BEFORE:   %[[PTR:.*]] = cir.load
+// CIR-BEFORE:   %[[NULL:.*]] = cir.const #cir.ptr<null> : 
!cir.ptr<!rec_Destructed>
+// CIR-BEFORE:   %[[NOT_NULL:.*]] = cir.cmp ne %[[PTR]], %[[NULL]] : 
!cir.ptr<!rec_Destructed>
+// CIR-BEFORE:   cir.if %[[NOT_NULL]] {
+// CIR-BEFORE:     cir.delete_array %[[PTR]] : !cir.ptr<!rec_Destructed> {
+// CIR-BEFORE-SAME:       delete_fn = @_ZdaPvm,
+// CIR-BEFORE-SAME:       delete_params = #cir.usual_delete_params<size = 
true>,
+// CIR-BEFORE-SAME:       element_dtor = @_ZN10DestructedD1Ev}
+// CIR-BEFORE:   }
+
+// CIR: cir.func {{.*}} @_Z28test_delete_array_destructedP10Destructed
+// CIR:   %[[PTR:.*]] = cir.load
+// CIR:   %[[NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_Destructed>
+// CIR:   %[[NOT_NULL:.*]] = cir.cmp ne %[[PTR]], %[[NULL]] : 
!cir.ptr<!rec_Destructed>
+// CIR:   cir.if %[[NOT_NULL]] {
+//
+// Read the array cookie.
+// CIR:     %[[BYTE_PTR:.*]] = cir.cast bitcast %[[PTR]] : 
!cir.ptr<!rec_Destructed> -> !cir.ptr<!u8i>
+// CIR:     %[[NEG_COOKIE:.*]] = cir.const #cir.int<-8> : !s64i
+// CIR:     %[[ALLOC_BYTE_PTR:.*]] = cir.ptr_stride %[[BYTE_PTR]], 
%[[NEG_COOKIE]] : (!cir.ptr<!u8i>, !s64i) -> !cir.ptr<!u8i>
+// CIR:     %[[VOID_PTR:.*]] = cir.cast bitcast %[[ALLOC_BYTE_PTR]] : 
!cir.ptr<!u8i> -> !cir.ptr<!void>
+// CIR:     %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[ALLOC_BYTE_PTR]] : 
!cir.ptr<!u8i> -> !cir.ptr<!u64i>
+// CIR:     %[[NUM_ELEM:.*]] = cir.load{{.*}} %[[COOKIE_PTR]] : 
!cir.ptr<!u64i>, !u64i
+//
+// Destruct elements in reverse order.
+// CIR:     %[[ONE:.*]] = cir.const #cir.int<1> : !u64i
+// CIR:     %[[NUM_ELEM_MINUS_ONE:.*]] = cir.sub %[[NUM_ELEM]], %[[ONE]] : 
!u64i
+// CIR:     %[[END:.*]] = cir.ptr_stride %[[PTR]], %[[NUM_ELEM_MINUS_ONE]] : 
(!cir.ptr<!rec_Destructed>, !u64i) -> !cir.ptr<!rec_Destructed>
+// CIR:     %[[NOT_EMPTY:.*]] = cir.cmp ne %[[END]], %[[PTR]] : 
!cir.ptr<!rec_Destructed>
+// CIR:     cir.if %[[NOT_EMPTY]] {
+// CIR:       %[[ARR_IDX:.*]] = cir.alloca !cir.ptr<!rec_Destructed>, 
!cir.ptr<!cir.ptr<!rec_Destructed>>, ["__array_idx"] {alignment = 1 : i64}
+// CIR:       cir.store %[[END]], %[[ARR_IDX]] : !cir.ptr<!rec_Destructed>, 
!cir.ptr<!cir.ptr<!rec_Destructed>>
+// CIR:       cir.do {
+// CIR:         %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_IDX]] : 
!cir.ptr<!cir.ptr<!rec_Destructed>>, !cir.ptr<!rec_Destructed>
+// CIR:         cir.call @_ZN10DestructedD1Ev(%[[ARR_CUR]]) : 
(!cir.ptr<!rec_Destructed>) -> ()
+// CIR:         %[[NEG_ONE:.*]] = cir.const #cir.int<-1> : !s64i
+// CIR:         %[[ARR_NEXT:.*]] = cir.ptr_stride %[[ARR_CUR]], %[[NEG_ONE]] : 
(!cir.ptr<!rec_Destructed>, !s64i) -> !cir.ptr<!rec_Destructed>
+// CIR:         cir.store %[[ARR_NEXT]], %[[ARR_IDX]] : 
!cir.ptr<!rec_Destructed>, !cir.ptr<!cir.ptr<!rec_Destructed>>
+// CIR:         cir.yield
+// CIR:       } while {
+// CIR:         %[[ARR_CUR:.*]] = cir.load{{.*}} %[[ARR_IDX]] : 
!cir.ptr<!cir.ptr<!rec_Destructed>>, !cir.ptr<!rec_Destructed>
+// CIR:         %[[CMP:.*]] = cir.cmp ne %[[ARR_CUR]], %[[PTR]] : 
!cir.ptr<!rec_Destructed>
+// CIR:         cir.condition(%[[CMP]])
+// CIR:       }
+// CIR:     }
+//
+// Compute total size and call delete function.
+// CIR:     %[[ELEM_SIZE:.*]] = cir.const #cir.int<4> : !u64i
+// CIR:     %[[ARRAY_SIZE:.*]] = cir.mul %[[ELEM_SIZE]], %[[NUM_ELEM]] : !u64i
+// CIR:     %[[COOKIE_SIZE:.*]] = cir.const #cir.int<8> : !u64i
+// CIR:     %[[TOTAL_SIZE:.*]] = cir.add %[[ARRAY_SIZE]], %[[COOKIE_SIZE]] : 
!u64i
+// CIR:     cir.call @_ZdaPvm(%[[VOID_PTR]], %[[TOTAL_SIZE]])
+// CIR:   }
+
+// LLVM: define {{.*}} void @_Z28test_delete_array_destructedP10Destructed
+// LLVM:   %[[PTR:.*]] = load ptr, ptr %{{.*}}
+// LLVM:   %[[NOT_NULL:.*]] = icmp ne ptr %[[PTR]], null
+// LLVM:   br i1 %[[NOT_NULL]], label %[[DELETE_NOTNULL:.*]], label 
%[[DONE:.*]]
+// LLVM: [[DELETE_NOTNULL]]:
+// LLVM:   %[[ALLOC_PTR:.*]] = getelementptr i8, ptr %[[PTR]], i64 -8
+// LLVM:   %[[NUM_ELEM:.*]] = load i64, ptr %[[ALLOC_PTR]], align 4
+// LLVM:   %[[NUM_ELEM_MINUS_ONE:.*]] = sub i64 %[[NUM_ELEM]], 1
+// LLVM:   %[[ARR_END:.*]] = getelementptr %struct.Destructed, ptr %[[PTR]], 
i64 %[[NUM_ELEM_MINUS_ONE]]
+// LLVM:   %[[NOT_EMPTY:.*]] = icmp ne ptr %[[ARR_END]], %[[PTR]]
+// LLVM:   br i1 %[[NOT_EMPTY]], label %[[DESTROY_ELEMENTS:.*]], label 
%[[CALL_DELETE:.*]]
+// LLVM: [[DESTROY_ELEMENTS:.*]]:
+// LLVM:   store ptr %[[ARR_END]], ptr %[[ARR_IDX:.*]]
+// LLVM:   br label %[[DELETE_ELEMENT:.*]]
+// LLVM: [[LOOP_CONDITION:.*]]
+// LLVM:   %[[ARR_CUR:.*]] = load ptr, ptr %[[ARR_IDX]]
+// LLVM:   %[[CMP:.*]] = icmp ne ptr %[[ARR_CUR]], %[[PTR]]
+// LLVM:   br i1 %[[CMP]], label %[[DELETE_ELEMENT:.*]], label %[[LOOP_END:.*]]
+// LLVM: [[DELETE_ELEMENT]]:
+// LLVM:   %[[ELEM:.*]] = load ptr, ptr %[[ARR_IDX]]
+// LLVM:   call void @_ZN10DestructedD1Ev(ptr %[[ELEM]])
+// LLVM:   %[[NEXT:.*]] = getelementptr %struct.Destructed, ptr %[[ELEM]], i64 
-1
+// LLVM:   store ptr %[[NEXT]], ptr %[[ARR_IDX]]
+// LLVM:   br label %[[LOOP_CONDITION]]
+// LLVM: [[LOOP_END]]:
+// LLVM:   br label %[[CALL_DELETE]]
+// LLVM: [[CALL_DELETE]]:
+// LLVM:   %[[ARRAY_SIZE:.*]] = mul i64 4, %[[NUM_ELEM]]
+// LLVM:   %[[TOTAL_SIZE:.*]] = add i64 %[[ARRAY_SIZE]], 8
+// LLVM:   call void @_ZdaPvm(ptr %[[ALLOC_PTR]], i64 %[[TOTAL_SIZE]])
+// LLVM:   br label %[[DONE]]
+// LLVM: [[DONE]]:
+// LLVM:   ret void
+
+// OGCG: define {{.*}} void @_Z28test_delete_array_destructedP10Destructed
+// OGCG:   %[[PTR:.*]] = load ptr, ptr %{{.*}}
+// OGCG:   %[[IS_NULL:.*]] = icmp eq ptr %[[PTR]], null
+// OGCG:   br i1 %[[IS_NULL]], label %[[DELETE_END:.*]], label 
%[[DELETE_NOT_NULL:.*]]
+// OGCG: [[DELETE_NOT_NULL]]:
+// OGCG:   %[[ALLOC_PTR:.*]] = getelementptr inbounds i8, ptr %[[PTR]], i64 -8
+// OGCG:   %[[NUM_ELEM:.*]] = load i64, ptr %[[ALLOC_PTR]], align 4
+// OGCG:   %[[ARR_END:.*]] = getelementptr inbounds %struct.Destructed, ptr 
%[[PTR]], i64 %[[NUM_ELEM]]
+// OGCG:   %[[ARR_IS_EMPTY:.*]] = icmp eq ptr %[[PTR]], %[[ARR_END]]
+// OGCG:   br i1 %[[ARR_IS_EMPTY]], label %[[ARRAY_DESTROY_DONE1:.*]], label 
%[[ARRAY_DESTROY_BODY:.*]]
+// OGCG: [[ARRAY_DESTROY_BODY]]:
+// OGCG:   %[[ARRAY_DESTROY_ELEMENT_PAST:.*]] = phi ptr [ %[[ARR_END]], 
%[[DELETE_NOT_NULL]] ], [ %[[ARRAY_DESTROY_ELEMENT:.*]], 
%[[ARRAY_DESTROY_BODY]] ]
+// OGCG:   %[[ARRAY_DESTROY_ELEMENT]] = getelementptr inbounds 
%struct.Destructed, ptr %[[ARRAY_DESTROY_ELEMENT_PAST]], i64 -1
+// OGCG:   call void @_ZN10DestructedD1Ev(ptr {{.*}} 
%[[ARRAY_DESTROY_ELEMENT]])
+// OGCG:   %[[ARRAY_DESTROY_DONE:.*]] = icmp eq ptr 
%[[ARRAY_DESTROY_ELEMENT]], %[[PTR]]
+// OGCG:   br i1 %[[ARRAY_DESTROY_DONE]], label %[[ARRAY_DESTROY_DONE1:.*]], 
label %[[ARRAY_DESTROY_BODY]]
+// OGCG: [[ARRAY_DESTROY_DONE1]]:
+// OGCG:   %[[ARRAY_SIZE:.*]] = mul i64 4, %[[NUM_ELEM]]
+// OGCG:   %[[TOTAL_SIZE:.*]] = add i64 %[[ARRAY_SIZE]], 8
+// OGCG:   call void @_ZdaPvm(ptr {{.*}} %[[ALLOC_PTR]], i64 {{.*}} 
%[[TOTAL_SIZE]])
+// OGCG:   br label %[[DELETE_END]]
+// OGCG: [[DELETE_END]]:
+// OGCG:   ret void


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to