Author: Erich Keane
Date: 2026-08-31T15:48:37-07:00
New Revision: b74db1bb01cfd37c9694df0035d5f0770c665f53

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

LOG: [CIR] Teach partial-array-destruction to work with arrays-of-records 
(#220045)

We currently assume that a partial-array destruction was a 1D array.
This is incorrect, as it can obviously be a MD array.

This patch comprehends the destruction across the array by using the
same begin/end iterators, but deleting these as element nodes.

Classic codegen does a full descent into the array types to do this
destruction, but I believe that is a side-effect of how it is going
through it. Treating arrays as contiguous and flattening the iterators
is effectively identical.

Note: Claude helped me extensively on the test, I believe all the
check-lines are correct, but I also pushed to make sure we got the full
structure checking correctly, so I hope this shows the differences above
properly.

Added: 
    

Modified: 
    clang/lib/CIR/CodeGen/CIRGenDecl.cpp
    clang/test/CIR/CodeGen/partial-array-cleanup.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index c46f40d0c0f2c..22138bd040d44 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -1113,14 +1113,24 @@ struct IrregularPartialArrayDestroy final : 
EHScopeStack::Cleanup {
 
     mlir::Value arrayEnd = builder.createLoad(loc, arrayEndPointer);
 
-    // The cleanup is destroying elements in reverse from arrayEnd back to
-    // arrayBegin, but only if arrayEnd != arrayBegin (i.e. something was
-    // constructed).
-    mlir::Type cirElementType = cgf.convertTypeForMem(elementType);
+    // baseElementType gets us the final 'element' type, which should be the
+    // RecordType, looking through any multi-dimension arrays.
+    QualType baseElementType = 
cgf.getContext().getBaseElementType(elementType);
+
+    mlir::Type cirElementType = cgf.convertTypeForMem(baseElementType);
     cir::PointerType ptrToElmType = builder.getPointerTo(cirElementType);
 
-    mlir::Value ne = cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne,
-                                        arrayEnd, arrayBegin);
+    mlir::Value begin = arrayBegin;
+    if (baseElementType != elementType) {
+      begin = builder.createPtrBitcast(begin, cirElementType);
+      arrayEnd = builder.createPtrBitcast(arrayEnd, cirElementType);
+    }
+
+    // The cleanup is destroying elements in reverse from arrayEnd back to
+    // begin, but only if arrayEnd != begin (i.e. something was
+    // constructed).
+    mlir::Value ne =
+        cir::CmpOp::create(builder, loc, cir::CmpOpKind::ne, arrayEnd, begin);
     cir::IfOp::create(
         builder, loc, ne, /*withElseRegion=*/false,
         [&](mlir::OpBuilder &b, mlir::Location loc) {
@@ -1133,7 +1143,7 @@ struct IrregularPartialArrayDestroy final : 
EHScopeStack::Cleanup {
               [&](mlir::OpBuilder &b, mlir::Location loc) {
                 mlir::Value cur = builder.createLoad(loc, iterAddr);
                 mlir::Value cmp = cir::CmpOp::create(
-                    builder, loc, cir::CmpOpKind::ne, cur, arrayBegin);
+                    builder, loc, cir::CmpOpKind::ne, cur, begin);
                 builder.createCondition(cmp);
               },
               /*bodyBuilder=*/
@@ -1145,7 +1155,7 @@ struct IrregularPartialArrayDestroy final : 
EHScopeStack::Cleanup {
                     builder, loc, ptrToElmType, cur, negOne);
                 builder.createStore(loc, prev, iterAddr);
                 Address elemAddr = Address(prev, cirElementType, elementAlign);
-                destroyer(cgf, elemAddr, elementType);
+                destroyer(cgf, elemAddr, baseElementType);
                 builder.createYield(loc);
               });
           builder.createYield(loc);

diff  --git a/clang/test/CIR/CodeGen/partial-array-cleanup.cpp 
b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
index 25d23f234e6ba..6ae7e19ba3bdb 100644
--- a/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
+++ b/clang/test/CIR/CodeGen/partial-array-cleanup.cpp
@@ -821,6 +821,371 @@ void test_init_list_partial_array_cleanup() {
 // OGCG:     [[EH_RESUME]]:
 // OGCG:       resume { ptr, i32 }
 
+void test_multi_dim_init_list_partial_array_cleanup() {
+    S arr[2][2] = { {S(), S()}, {S(), S()} };
+}
+
+// There are three nested EH cleanups here, innermost first:
+//  - row 1's S[2] init list (elementType S, already non-array)
+//  - row 0's S[2] init list (elementType S, already non-array)
+//  - the outer S[2][2] init list (elementType S[2], STILL an array --
+//    this is the one that needs the bitcast down to S)
+// CIR-BEFORE-LPP-LABEL: cir.func {{.*}} 
@_Z46test_multi_dim_init_list_partial_array_cleanupv()
+// CIR-BEFORE-LPP:       %[[ARR:.*]] = cir.alloca "arr" {{.*}} init : 
!cir.ptr<!cir.array<!cir.array<!rec_S x 2> x 2>>
+// CIR-BEFORE-LPP:       %[[OUTER_END:.*]] = cir.alloca "arrayinit.endOfInit" 
{{.*}} : !cir.ptr<!cir.ptr<!cir.array<!rec_S x 2>>>
+// CIR-BEFORE-LPP:       %[[ROW0_END:.*]] = cir.alloca "arrayinit.endOfInit" 
{{.*}} : !cir.ptr<!cir.ptr<!rec_S>>
+// CIR-BEFORE-LPP:       %[[ROW1_END:.*]] = cir.alloca "arrayinit.endOfInit" 
{{.*}} : !cir.ptr<!cir.ptr<!rec_S>>
+// CIR-BEFORE-LPP:       %[[ROW1_ITER:.*]] = cir.alloca "__array_idx" {{.*}} : 
!cir.ptr<!cir.ptr<!rec_S>>
+// CIR-BEFORE-LPP:       %[[ROW0_ITER:.*]] = cir.alloca "__array_idx" {{.*}} : 
!cir.ptr<!cir.ptr<!rec_S>>
+// CIR-BEFORE-LPP:       %[[OUTER_ITER:.*]] = cir.alloca "__array_idx" {{.*}} 
: !cir.ptr<!cir.ptr<!rec_S>>
+// CIR-BEFORE-LPP:       %[[ROW0_BEGIN:.*]] = cir.cast array_to_ptrdecay 
%[[ARR]] : !cir.ptr<!cir.array<!cir.array<!rec_S x 2> x 2>> -> 
!cir.ptr<!cir.array<!rec_S x 2>>
+// CIR-BEFORE-LPP:       cir.store {{.*}} %[[ROW0_BEGIN]], %[[OUTER_END]] : 
!cir.ptr<!cir.array<!rec_S x 2>>, !cir.ptr<!cir.ptr<!cir.array<!rec_S x 2>>>
+// CIR-BEFORE-LPP:       cir.cleanup.scope {
+// CIR-BEFORE-LPP:         %[[ROW0_ELT0:.*]] = cir.cast array_to_ptrdecay 
%[[ROW0_BEGIN]] : !cir.ptr<!cir.array<!rec_S x 2>> -> !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:         cir.store {{.*}} %[[ROW0_ELT0]], %[[ROW0_END]] : 
!cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>
+// CIR-BEFORE-LPP:         cir.cleanup.scope {
+//                           --- row 0: S(), S() ---
+// CIR-BEFORE-LPP:           cir.call @_ZN1SC1Ev(%[[ROW0_ELT0]])
+// CIR-BEFORE-LPP:           %[[ROW0_ELT1:.*]] = cir.ptr_stride 
%[[ROW0_ELT0]], %{{.*}} : (!cir.ptr<!rec_S>, !s64i) -> !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:           cir.store {{.*}} %[[ROW0_ELT1]], %[[ROW0_END]]
+// CIR-BEFORE-LPP:           cir.call @_ZN1SC1Ev(%[[ROW0_ELT1]])
+// CIR-BEFORE-LPP:           %[[ROW1_BEGIN:.*]] = cir.ptr_stride 
%[[ROW0_BEGIN]], %{{.*}} : (!cir.ptr<!cir.array<!rec_S x 2>>, !s64i) -> 
!cir.ptr<!cir.array<!rec_S x 2>>
+// CIR-BEFORE-LPP:           cir.store {{.*}} %[[ROW1_BEGIN]], %[[OUTER_END]]
+// CIR-BEFORE-LPP:           %[[ROW1_ELT0:.*]] = cir.cast array_to_ptrdecay 
%[[ROW1_BEGIN]] : !cir.ptr<!cir.array<!rec_S x 2>> -> !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:           cir.store {{.*}} %[[ROW1_ELT0]], %[[ROW1_END]]
+// CIR-BEFORE-LPP:           cir.cleanup.scope {
+//                             --- row 1: S(), S() ---
+// CIR-BEFORE-LPP:             cir.call @_ZN1SC1Ev(%[[ROW1_ELT0]])
+// CIR-BEFORE-LPP:             %[[ROW1_ELT1:.*]] = cir.ptr_stride 
%[[ROW1_ELT0]], %{{.*}} : (!cir.ptr<!rec_S>, !s64i) -> !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:             cir.store {{.*}} %[[ROW1_ELT1]], %[[ROW1_END]]
+// CIR-BEFORE-LPP:             cir.call @_ZN1SC1Ev(%[[ROW1_ELT1]])
+// CIR-BEFORE-LPP:             cir.yield
+//                             --- innermost EH cleanup (row 1): elementType 
is already S, no bitcast ---
+// CIR-BEFORE-LPP:           } cleanup eh {
+// CIR-BEFORE-LPP:             %[[ROW1_EH_END:.*]] = cir.load {{.*}} 
%[[ROW1_END]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:             %[[ROW1_EH_NE:.*]] = cir.cmp ne 
%[[ROW1_EH_END]], %[[ROW1_ELT0]] : !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:             cir.if %[[ROW1_EH_NE]] {
+// CIR-BEFORE-LPP:               cir.store {{.*}} %[[ROW1_EH_END]], 
%[[ROW1_ITER]]
+// CIR-BEFORE-LPP:               cir.do {
+// CIR-BEFORE-LPP:                 %[[ROW1_EH_CUR:.*]] = cir.load {{.*}} 
%[[ROW1_ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:                 %[[ROW1_EH_PREV:.*]] = cir.ptr_stride 
%[[ROW1_EH_CUR]], %{{.*}} : (!cir.ptr<!rec_S>, !s64i) -> !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:                 cir.store {{.*}} %[[ROW1_EH_PREV]], 
%[[ROW1_ITER]]
+// CIR-BEFORE-LPP:                 cir.call @_ZN1SD1Ev(%[[ROW1_EH_PREV]]) 
nothrow
+// CIR-BEFORE-LPP:                 cir.yield
+// CIR-BEFORE-LPP:               } while {
+// CIR-BEFORE-LPP:                 %[[ROW1_EH_CUR2:.*]] = cir.load {{.*}} 
%[[ROW1_ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:                 %[[ROW1_EH_CONT:.*]] = cir.cmp ne 
%[[ROW1_EH_CUR2]], %[[ROW1_ELT0]] : !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:                 cir.condition(%[[ROW1_EH_CONT]])
+// CIR-BEFORE-LPP:               }
+// CIR-BEFORE-LPP:             }
+// CIR-BEFORE-LPP:             cir.yield
+// CIR-BEFORE-LPP:           }
+// CIR-BEFORE-LPP:           cir.yield
+//                           --- middle EH cleanup (row 0): elementType is 
already S, no bitcast ---
+// CIR-BEFORE-LPP:         } cleanup eh {
+// CIR-BEFORE-LPP:           %[[ROW0_EH_END:.*]] = cir.load {{.*}} 
%[[ROW0_END]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:           %[[ROW0_EH_NE:.*]] = cir.cmp ne %[[ROW0_EH_END]], 
%[[ROW0_ELT0]] : !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:           cir.if %[[ROW0_EH_NE]] {
+// CIR-BEFORE-LPP:             cir.store {{.*}} %[[ROW0_EH_END]], 
%[[ROW0_ITER]]
+// CIR-BEFORE-LPP:             cir.do {
+// CIR-BEFORE-LPP:               %[[ROW0_EH_CUR:.*]] = cir.load {{.*}} 
%[[ROW0_ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:               %[[ROW0_EH_PREV:.*]] = cir.ptr_stride 
%[[ROW0_EH_CUR]], %{{.*}} : (!cir.ptr<!rec_S>, !s64i) -> !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:               cir.store {{.*}} %[[ROW0_EH_PREV]], 
%[[ROW0_ITER]]
+// CIR-BEFORE-LPP:               cir.call @_ZN1SD1Ev(%[[ROW0_EH_PREV]]) nothrow
+// CIR-BEFORE-LPP:               cir.yield
+// CIR-BEFORE-LPP:             } while {
+// CIR-BEFORE-LPP:               %[[ROW0_EH_CUR2:.*]] = cir.load {{.*}} 
%[[ROW0_ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:               %[[ROW0_EH_CONT:.*]] = cir.cmp ne 
%[[ROW0_EH_CUR2]], %[[ROW0_ELT0]] : !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:               cir.condition(%[[ROW0_EH_CONT]])
+// CIR-BEFORE-LPP:             }
+// CIR-BEFORE-LPP:           }
+// CIR-BEFORE-LPP:           cir.yield
+// CIR-BEFORE-LPP:         }
+// CIR-BEFORE-LPP:         cir.yield
+//                         --- outer EH cleanup (S[2][2]): elementType is 
still S[2] here, so the
+//                             cleanup must bitcast down to the base non-array 
element type (S)
+//                             before comparing pointers and destroying -- 
this is the regression ---
+// CIR-BEFORE-LPP:       } cleanup eh {
+// CIR-BEFORE-LPP:         %[[OUTER_EH_END:.*]] = cir.load {{.*}} 
%[[OUTER_END]] : !cir.ptr<!cir.ptr<!cir.array<!rec_S x 2>>>, 
!cir.ptr<!cir.array<!rec_S x 2>>
+// CIR-BEFORE-LPP:         %[[OUTER_EH_BEGIN_BASE:.*]] = cir.cast bitcast 
%[[ROW0_BEGIN]] : !cir.ptr<!cir.array<!rec_S x 2>> -> !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:         %[[OUTER_EH_END_BASE:.*]] = cir.cast bitcast 
%[[OUTER_EH_END]] : !cir.ptr<!cir.array<!rec_S x 2>> -> !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:         %[[OUTER_EH_NE:.*]] = cir.cmp ne 
%[[OUTER_EH_END_BASE]], %[[OUTER_EH_BEGIN_BASE]] : !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:         cir.if %[[OUTER_EH_NE]] {
+// CIR-BEFORE-LPP:           cir.store {{.*}} %[[OUTER_EH_END_BASE]], 
%[[OUTER_ITER]]
+// CIR-BEFORE-LPP:           cir.do {
+// CIR-BEFORE-LPP:             %[[OUTER_EH_CUR:.*]] = cir.load {{.*}} 
%[[OUTER_ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:             %[[OUTER_EH_PREV:.*]] = cir.ptr_stride 
%[[OUTER_EH_CUR]], %{{.*}} : (!cir.ptr<!rec_S>, !s64i) -> !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:             cir.store {{.*}} %[[OUTER_EH_PREV]], 
%[[OUTER_ITER]]
+// CIR-BEFORE-LPP:             cir.call @_ZN1SD1Ev(%[[OUTER_EH_PREV]]) nothrow
+// CIR-BEFORE-LPP:             cir.yield
+// CIR-BEFORE-LPP:           } while {
+// CIR-BEFORE-LPP:             %[[OUTER_EH_CUR2:.*]] = cir.load {{.*}} 
%[[OUTER_ITER]] : !cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:             %[[OUTER_EH_CONT:.*]] = cir.cmp ne 
%[[OUTER_EH_CUR2]], %[[OUTER_EH_BEGIN_BASE]] : !cir.ptr<!rec_S>
+// CIR-BEFORE-LPP:             cir.condition(%[[OUTER_EH_CONT]])
+// CIR-BEFORE-LPP:           }
+// CIR-BEFORE-LPP:         }
+// CIR-BEFORE-LPP:         cir.yield
+// CIR-BEFORE-LPP:       }
+//                       --- normal (non-EH) cleanup: unconditional, uses the 
array.dtor sugar
+//                           over the fully-flattened S[4] view (this path was 
never buggy) ---
+// CIR-BEFORE-LPP:       cir.cleanup.scope {
+// CIR-BEFORE-LPP:         cir.yield
+// CIR-BEFORE-LPP:       } cleanup all {
+// CIR-BEFORE-LPP:         %[[FLAT:.*]] = cir.cast bitcast %[[ARR]] : 
!cir.ptr<!cir.array<!cir.array<!rec_S x 2> x 2>> -> !cir.ptr<!cir.array<!rec_S 
x 4>>
+// CIR-BEFORE-LPP:         cir.array.dtor %[[FLAT]] : 
!cir.ptr<!cir.array<!rec_S x 4>> {
+// CIR-BEFORE-LPP:         ^bb0(%[[DTOR_ARG:.*]]: !cir.ptr<!rec_S>):
+// CIR-BEFORE-LPP:           cir.call @_ZN1SD1Ev(%[[DTOR_ARG]]) nothrow
+// CIR-BEFORE-LPP:         }
+// CIR-BEFORE-LPP:         cir.yield
+// CIR-BEFORE-LPP:       }
+// CIR-BEFORE-LPP:       cir.return
+
+// CIR-LABEL: cir.func {{.*}} 
@_Z46test_multi_dim_init_list_partial_array_cleanupv()
+// CIR:       %[[ARRAY:.*]] = cir.alloca "arr" {{.*}} init : 
!cir.ptr<!cir.array<!cir.array<!rec_S x 2> x 2>>
+// CIR:       %[[END_OF_INIT:.*]] = cir.alloca "arrayinit.endOfInit" {{.*}} : 
!cir.ptr<!cir.ptr<!cir.array<!rec_S x 2>>>
+// CIR:       %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARRAY]] : 
!cir.ptr<!cir.array<!cir.array<!rec_S x 2> x 2>> -> !cir.ptr<!cir.array<!rec_S 
x 2>>
+// CIR:       cir.store {{.*}} %[[BEGIN]], %[[END_OF_INIT]] : 
!cir.ptr<!cir.array<!rec_S x 2>>, !cir.ptr<!cir.ptr<!cir.array<!rec_S x 2>>>
+// CIR:       cir.cleanup.scope {
+//              --- explicit inits for both rows ---
+// CIR:         cir.call @_ZN1SC1Ev
+// CIR:         cir.call @_ZN1SC1Ev
+// CIR:         cir.call @_ZN1SC1Ev
+// CIR:         cir.call @_ZN1SC1Ev
+//              --- outer EH cleanup: drill the still-array elementType (S[2])
+//                  down to the base non-array element type (S) via bitcast ---
+// CIR:       } cleanup eh {
+// CIR:         %[[END_VAL:.*]] = cir.load {{.*}} %[[END_OF_INIT]] : 
!cir.ptr<!cir.ptr<!cir.array<!rec_S x 2>>>, !cir.ptr<!cir.array<!rec_S x 2>>
+// CIR:         %[[BEGIN_BASE:.*]] = cir.cast bitcast %[[BEGIN]] : 
!cir.ptr<!cir.array<!rec_S x 2>> -> !cir.ptr<!rec_S>
+// CIR:         %[[END_BASE:.*]] = cir.cast bitcast %[[END_VAL]] : 
!cir.ptr<!cir.array<!rec_S x 2>> -> !cir.ptr<!rec_S>
+// CIR:         %[[NE:.*]] = cir.cmp ne %[[END_BASE]], %[[BEGIN_BASE]] : 
!cir.ptr<!rec_S>
+// CIR:         cir.if %[[NE]] {
+// CIR:           cir.store {{.*}} %[[END_BASE]], %[[ITER:.*]] : 
!cir.ptr<!rec_S>, !cir.ptr<!cir.ptr<!rec_S>>
+// 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:             cir.call @_ZN1SD1Ev(%[[PREV]]) nothrow
+// CIR:             cir.yield
+// CIR:           } while {
+// CIR:             %[[EL2:.*]] = cir.load {{.*}} %[[ITER]] : 
!cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+// CIR:             %[[CONT:.*]] = cir.cmp ne %[[EL2]], %[[BEGIN_BASE]] : 
!cir.ptr<!rec_S>
+// CIR:             cir.condition(%[[CONT]])
+// CIR:           }
+// CIR:         }
+// CIR:         cir.yield
+// CIR:       }
+//              --- normal (non-EH) cleanup: array.dtor has been expanded into 
an
+//                  explicit do-while loop over the flattened S[4] view ---
+// CIR:       cir.cleanup.scope {
+// CIR:         cir.yield
+// CIR:       } cleanup all {
+// CIR:         %[[FLAT:.*]] = cir.cast bitcast %[[ARRAY]] : 
!cir.ptr<!cir.array<!cir.array<!rec_S x 2> x 2>> -> !cir.ptr<!cir.array<!rec_S 
x 4>>
+// CIR:         %[[FOUR:.*]] = cir.const #cir.int<4> : !u64i
+// CIR:         %[[FLAT_BEGIN:.*]] = cir.cast array_to_ptrdecay %[[FLAT]] : 
!cir.ptr<!cir.array<!rec_S x 4>> -> !cir.ptr<!rec_S>
+// CIR:         %[[FLAT_END:.*]] = cir.ptr_stride %[[FLAT_BEGIN]], %[[FOUR]] : 
(!cir.ptr<!rec_S>, !u64i) -> !cir.ptr<!rec_S>
+// CIR:         cir.do {
+// CIR:           cir.call @_ZN1SD1Ev
+// CIR:           cir.yield
+// CIR:         } while {
+// CIR:           cir.condition
+// CIR:         }
+// CIR:         cir.yield
+// CIR:       }
+
+// LLVM-LABEL: define 
{{.*}}@_Z46test_multi_dim_init_list_partial_array_cleanupv()
+// LLVM:      %[[ARR:.*]] = alloca [2 x [2 x %struct.S]]
+// LLVM:      %[[OUTER_END_A:.*]] = alloca ptr
+//
+//            --- row 0: element 0, element 1 ---
+// LLVM:      %[[ROW0_BEGIN:.*]] = getelementptr [2 x %struct.S], ptr 
%[[ARR]], i32 0
+// LLVM:      store ptr %[[ROW0_BEGIN]], ptr %[[OUTER_END_A]]
+// LLVM:      %[[ROW0_ELT0:.*]] = getelementptr %struct.S, ptr 
%[[ROW0_BEGIN]], i32 0
+// LLVM:      store ptr %[[ROW0_ELT0]], ptr %[[ROW0_END_A:.*]]
+// LLVM:      invoke void @_ZN1SC1Ev(ptr {{.*}} %[[ROW0_ELT0]])
+// LLVM:        to label %{{.*}} unwind label %[[ROW0_LPAD:.*]]
+//
+// LLVM:      %[[ROW0_ELT1:.*]] = getelementptr %struct.S, ptr %[[ROW0_ELT0]], 
i64 1
+// LLVM:      store ptr %[[ROW0_ELT1]], ptr %[[ROW0_END_A]]
+// LLVM:      invoke void @_ZN1SC1Ev(ptr {{.*}} %[[ROW0_ELT1]])
+// LLVM:        to label %{{.*}} unwind label %[[ROW0_LPAD]]
+//
+//            --- row 1: element 0, element 1 ---
+// LLVM:      %[[ROW1_BEGIN:.*]] = getelementptr [2 x %struct.S], ptr 
%[[ROW0_BEGIN]], i64 1
+// LLVM:      store ptr %[[ROW1_BEGIN]], ptr %[[OUTER_END_A]]
+// LLVM:      %[[ROW1_ELT0:.*]] = getelementptr %struct.S, ptr 
%[[ROW1_BEGIN]], i32 0
+// LLVM:      store ptr %[[ROW1_ELT0]], ptr %[[ROW1_END_A:.*]]
+// LLVM:      invoke void @_ZN1SC1Ev(ptr {{.*}} %[[ROW1_ELT0]])
+// LLVM:        to label %{{.*}} unwind label %[[ROW1_LPAD:.*]]
+//
+// LLVM:      %[[ROW1_ELT1:.*]] = getelementptr %struct.S, ptr %[[ROW1_ELT0]], 
i64 1
+// LLVM:      store ptr %[[ROW1_ELT1]], ptr %[[ROW1_END_A]]
+// LLVM:      invoke void @_ZN1SC1Ev(ptr {{.*}} %[[ROW1_ELT1]])
+// LLVM:        to label %{{.*}} unwind label %[[ROW1_LPAD]]
+//
+//            --- row 1 EH cleanup (elementType S, no bitcast needed) ---
+// LLVM:      [[ROW1_LPAD]]:
+// LLVM:        landingpad { ptr, i32 }
+// LLVM:          cleanup
+// LLVM:        %[[ROW1_EH_END:.*]] = load ptr, ptr %[[ROW1_END_A]]
+// LLVM:        %[[ROW1_EH_NE:.*]] = icmp ne ptr %[[ROW1_EH_END]], 
%[[ROW1_ELT0]]
+// LLVM:        br i1 %[[ROW1_EH_NE]], label %[[ROW1_DTOR:.*]], label %{{.*}}
+//
+// LLVM:      [[ROW1_DTOR]]:
+// LLVM:        store ptr %[[ROW1_EH_END]], ptr %[[ROW1_ITER:.*]]
+// LLVM:        br label %[[ROW1_DTOR_BODY:.*]]
+//
+// LLVM:      [[ROW1_DTOR_BODY]]:
+// LLVM:        %[[ROW1_DCUR:.*]] = load ptr, ptr %[[ROW1_ITER]]
+// LLVM:        %[[ROW1_DPREV:.*]] = getelementptr %struct.S, ptr 
%[[ROW1_DCUR]], i64 -1
+// LLVM:        store ptr %[[ROW1_DPREV]], ptr %[[ROW1_ITER]]
+// LLVM:        call void @_ZN1SD1Ev(ptr {{.*}} %[[ROW1_DPREV]])
+//
+//            --- row 0 EH cleanup (elementType S, no bitcast needed) ---
+// LLVM:      [[ROW0_LPAD]]:
+// LLVM:        landingpad { ptr, i32 }
+// LLVM:          cleanup
+// LLVM:        %[[ROW0_EH_END:.*]] = load ptr, ptr %[[ROW0_END_A]]
+// LLVM:        %[[ROW0_EH_NE:.*]] = icmp ne ptr %[[ROW0_EH_END]], 
%[[ROW0_ELT0]]
+// LLVM:        br i1 %[[ROW0_EH_NE]], label %[[ROW0_DTOR:.*]], label %{{.*}}
+//
+// LLVM:      [[ROW0_DTOR]]:
+// LLVM:        store ptr %[[ROW0_EH_END]], ptr %[[ROW0_ITER:.*]]
+// LLVM:        br label %[[ROW0_DTOR_BODY:.*]]
+//
+// LLVM:      [[ROW0_DTOR_BODY]]:
+// LLVM:        %[[ROW0_DCUR:.*]] = load ptr, ptr %[[ROW0_ITER]]
+// LLVM:        %[[ROW0_DPREV:.*]] = getelementptr %struct.S, ptr 
%[[ROW0_DCUR]], i64 -1
+// LLVM:        store ptr %[[ROW0_DPREV]], ptr %[[ROW0_ITER]]
+// LLVM:        call void @_ZN1SD1Ev(ptr {{.*}} %[[ROW0_DPREV]])
+//
+//            --- outer EH cleanup
+// LLVM:        %[[OUTER_EH_END:.*]] = load ptr, ptr %[[OUTER_END_A]]
+// LLVM:        %[[OUTER_EH_NE:.*]] = icmp ne ptr %[[OUTER_EH_END]], 
%[[ROW0_BEGIN]]
+// LLVM:        br i1 %[[OUTER_EH_NE]], label %[[OUTER_DTOR:.*]], label %{{.*}}
+//
+// LLVM:      [[OUTER_DTOR]]:
+// LLVM:        store ptr %[[OUTER_EH_END]], ptr %[[OUTER_ITER:.*]]
+// LLVM:        br label %[[OUTER_DTOR_BODY:.*]]
+//
+// LLVM:      [[OUTER_DTOR_BODY]]:
+// LLVM:        %[[OUTER_DCUR:.*]] = load ptr, ptr %[[OUTER_ITER]]
+// LLVM:        %[[OUTER_DPREV:.*]] = getelementptr %struct.S, ptr 
%[[OUTER_DCUR]], i64 -1
+// LLVM:        store ptr %[[OUTER_DPREV]], ptr %[[OUTER_ITER]]
+// LLVM:        call void @_ZN1SD1Ev(ptr {{.*}} %[[OUTER_DPREV]])
+// LLVM:        resume { ptr, i32 }
+//
+//            --- normal (non-EH) cleanup: destroys all 4 elements ---
+// LLVM:      %[[FLAT_BEGIN:.*]] = getelementptr %struct.S, ptr %[[ARR]], i32 0
+// LLVM:      %[[FLAT_END:.*]] = getelementptr %struct.S, ptr %[[FLAT_BEGIN]], 
i64 4
+// LLVM:      store ptr %[[FLAT_END]], ptr %[[NORM_ITER:.*]]
+// LLVM:      br label %[[NORM_BODY:.*]]
+//
+// LLVM:      [[NORM_BODY]]:
+// LLVM:        %[[NORM_CUR:.*]] = load ptr, ptr %[[NORM_ITER]]
+// LLVM:        %[[NORM_PREV:.*]] = getelementptr %struct.S, ptr 
%[[NORM_CUR]], i64 -1
+// LLVM:        store ptr %[[NORM_PREV]], ptr %[[NORM_ITER]]
+// LLVM:        call void @_ZN1SD1Ev(ptr {{.*}} %[[NORM_PREV]])
+// LLVM:      ret void
+
+// OGCG-LABEL: define 
{{.*}}@_Z46test_multi_dim_init_list_partial_array_cleanupv()
+// OGCG:      %[[ARR:.*]] = alloca [2 x [2 x %struct.S]]
+// OGCG:      %[[OUTER_END_A:.*]] = alloca ptr
+// OGCG:      %[[ROW0_END_A:.*]] = alloca ptr
+// OGCG:      store ptr %[[ARR]], ptr %[[OUTER_END_A]]
+// OGCG:      store ptr %[[ARR]], ptr %[[ROW0_END_A]]
+//
+//            --- row 0: element 0, element 1 ---
+// OGCG:      invoke void @_ZN1SC1Ev(ptr {{.*}} %[[ARR]])
+// OGCG:        to label %{{.*}} unwind label %[[ROW0_LPAD:.*]]
+//
+// OGCG:      %[[ROW0_ELT1:.*]] = getelementptr inbounds %struct.S, ptr 
%[[ARR]], i64 1
+// OGCG:      store ptr %[[ROW0_ELT1]], ptr %[[ROW0_END_A]]
+// OGCG:      invoke void @_ZN1SC1Ev(ptr {{.*}} %[[ROW0_ELT1]])
+// OGCG:        to label %{{.*}} unwind label %[[ROW0_LPAD]]
+//
+//            --- row 1: element 0, element 1 ---
+// OGCG:      %[[ROW1_BEGIN:.*]] = getelementptr inbounds [2 x %struct.S], ptr 
%[[ARR]], i64 1
+// OGCG:      store ptr %[[ROW1_BEGIN]], ptr %[[OUTER_END_A]]
+// OGCG:      store ptr %[[ROW1_BEGIN]], ptr %[[ROW1_END_A:.*]]
+// OGCG:      invoke void @_ZN1SC1Ev(ptr {{.*}} %[[ROW1_BEGIN]])
+// OGCG:        to label %{{.*}} unwind label %[[ROW1_LPAD:.*]]
+//
+// OGCG:      %[[ROW1_ELT1:.*]] = getelementptr inbounds %struct.S, ptr 
%[[ROW1_BEGIN]], i64 1
+// OGCG:      store ptr %[[ROW1_ELT1]], ptr %[[ROW1_END_A]]
+// OGCG:      invoke void @_ZN1SC1Ev(ptr {{.*}} %[[ROW1_ELT1]])
+// OGCG:        to label %[[CTOR_DONE:.*]] unwind label %[[ROW1_LPAD]]
+//
+//            --- normal (non-EH) cleanup: destroys all 4 elements ---
+// OGCG:      [[CTOR_DONE]]:
+// OGCG:      %[[FLAT_BEGIN:.*]] = getelementptr inbounds [2 x [2 x 
%struct.S]], ptr %[[ARR]], i32 0, i32 0, i32 0
+// OGCG:      %[[FLAT_END:.*]] = getelementptr inbounds %struct.S, ptr 
%[[FLAT_BEGIN]], i64 4
+// OGCG:      br label %[[NORM_BODY:.*]]
+//
+// OGCG:      [[NORM_BODY]]:
+// OGCG:      %[[NORM_PAST:.*]] = phi ptr [ %[[FLAT_END]], %[[CTOR_DONE]] ], [ 
%[[NORM_PREV:.*]], %[[NORM_BODY]] ]
+// OGCG:      %[[NORM_PREV]] = getelementptr inbounds %struct.S, ptr 
%[[NORM_PAST]], i64 -1
+// OGCG:      call void @_ZN1SD1Ev(ptr {{.*}} %[[NORM_PREV]])
+// OGCG:      %[[NORM_DONE:.*]] = icmp eq ptr %[[NORM_PREV]], %[[FLAT_BEGIN]]
+// OGCG:      br i1 %[[NORM_DONE]], label %{{.*}}, label %[[NORM_BODY]]
+//
+//            --- row 0 EH cleanup (elementType S, no bitcast needed) ---
+// OGCG:      [[ROW0_LPAD]]:
+// OGCG:        landingpad { ptr, i32 }
+// OGCG:          cleanup
+// OGCG:        %[[ROW0_EH_END:.*]] = load ptr, ptr %[[ROW0_END_A]]
+// OGCG:        %[[ROW0_EH_EMPTY:.*]] = icmp eq ptr %[[ARR]], %[[ROW0_EH_END]]
+// OGCG:        br i1 %[[ROW0_EH_EMPTY]], label %[[ROW0_EH_DONE:.*]], label 
%[[ROW0_DTOR:.*]]
+//
+// OGCG:      [[ROW0_DTOR]]:
+// OGCG:      %[[ROW0_DPAST:.*]] = phi ptr [ %[[ROW0_EH_END]], %[[ROW0_LPAD]] 
], [ %[[ROW0_DPREV:.*]], %[[ROW0_DTOR]] ]
+// OGCG:      %[[ROW0_DPREV]] = getelementptr inbounds %struct.S, ptr 
%[[ROW0_DPAST]], i64 -1
+// OGCG:      call void @_ZN1SD1Ev(ptr {{.*}} %[[ROW0_DPREV]])
+// OGCG:      %[[ROW0_DDONE:.*]] = icmp eq ptr %[[ROW0_DPREV]], %[[ARR]]
+// OGCG:      br i1 %[[ROW0_DDONE]], label %[[ROW0_EH_DONE]], label 
%[[ROW0_DTOR]]
+//
+// OGCG:      [[ROW0_EH_DONE]]:
+// OGCG:      br label %[[EHCLEANUP:.*]]
+//
+//            --- row 1 EH cleanup (elementType S, no bitcast needed) ---
+// OGCG:      [[ROW1_LPAD]]:
+// OGCG:        landingpad { ptr, i32 }
+// OGCG:          cleanup
+// OGCG:        %[[ROW1_EH_END:.*]] = load ptr, ptr %[[ROW1_END_A]]
+// OGCG:        %[[ROW1_EH_EMPTY:.*]] = icmp eq ptr %[[ROW1_BEGIN]], 
%[[ROW1_EH_END]]
+// OGCG:        br i1 %[[ROW1_EH_EMPTY]], label %[[ROW1_EH_DONE:.*]], label 
%[[ROW1_DTOR:.*]]
+//
+// OGCG:      [[ROW1_DTOR]]:
+// OGCG:      %[[ROW1_DPAST:.*]] = phi ptr [ %[[ROW1_EH_END]], %[[ROW1_LPAD]] 
], [ %[[ROW1_DPREV:.*]], %[[ROW1_DTOR]] ]
+// OGCG:      %[[ROW1_DPREV]] = getelementptr inbounds %struct.S, ptr 
%[[ROW1_DPAST]], i64 -1
+// OGCG:      call void @_ZN1SD1Ev(ptr {{.*}} %[[ROW1_DPREV]])
+// OGCG:      %[[ROW1_DDONE:.*]] = icmp eq ptr %[[ROW1_DPREV]], %[[ROW1_BEGIN]]
+// OGCG:      br i1 %[[ROW1_DDONE]], label %[[ROW1_EH_DONE]], label 
%[[ROW1_DTOR]]
+//
+// OGCG:      [[ROW1_EH_DONE]]:
+// OGCG:      br label %[[EHCLEANUP]]
+//
+//            --- Classic-codegen does this in 2 steps/2 loops vs CIR just 
doing it as 1 loop.
+// OGCG:      [[EHCLEANUP]]:
+// OGCG:      %[[OUTER_EH_END:.*]] = load ptr, ptr %[[OUTER_END_A]]
+// OGCG:      %[[OUTER_EH_BEGIN_BASE:.*]] = getelementptr inbounds [2 x 
%struct.S], ptr %[[ARR]], i64 0, i64 0
+// OGCG:      %[[OUTER_EH_END_BASE:.*]] = getelementptr inbounds [2 x 
%struct.S], ptr %[[OUTER_EH_END]], i64 0, i64 0
+// OGCG:      %[[OUTER_EH_EMPTY:.*]] = icmp eq ptr %[[OUTER_EH_BEGIN_BASE]], 
%[[OUTER_EH_END_BASE]]
+// OGCG:      br i1 %[[OUTER_EH_EMPTY]], label %[[OUTER_EH_DONE:.*]], label 
%[[OUTER_DTOR:.*]]
+//
+// OGCG:      [[OUTER_DTOR]]:
+// OGCG:      %[[OUTER_DPAST:.*]] = phi ptr [ %[[OUTER_EH_END_BASE]], 
%[[EHCLEANUP]] ], [ %[[OUTER_DPREV:.*]], %[[OUTER_DTOR]] ]
+// OGCG:      %[[OUTER_DPREV]] = getelementptr inbounds %struct.S, ptr 
%[[OUTER_DPAST]], i64 -1
+// OGCG:      call void @_ZN1SD1Ev(ptr {{.*}} %[[OUTER_DPREV]])
+// OGCG:      %[[OUTER_DDONE:.*]] = icmp eq ptr %[[OUTER_DPREV]], 
%[[OUTER_EH_BEGIN_BASE]]
+// OGCG:      br i1 %[[OUTER_DDONE]], label %[[OUTER_EH_DONE]], label 
%[[OUTER_DTOR]]
+//
+// OGCG:      [[OUTER_EH_DONE]]:
+// OGCG:      br label %[[EH_RESUME:.*]]
+//
+// OGCG:      [[EH_RESUME]]:
+// OGCG:      resume { ptr, i32 }
+
 struct Temp2 {
   Temp2();
   ~Temp2();


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

Reply via email to