// 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, !cir.ptr>, ["s", init] // CIR-BEFORE-LPP: cir.array.ctor %[[ARRAY]] : !cir.ptr> { // CIR-BEFORE-LPP: ^bb0(%[[CTOR_ARG:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SC1Ev(%[[CTOR_ARG]]) : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } partial_dtor { // CIR-BEFORE-LPP: ^bb0(%[[DTOR_ARG:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%[[DTOR_ARG]]){{.*}} : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } // CIR: cir.func {{.*}} @_Z26test_partial_array_cleanupv() // CIR: %[[ARRAY:.*]] = cir.alloca !cir.array, !cir.ptr>, ["s", init] // CIR: %[[CONST4:.*]] = cir.const #cir.int<4> : !u64i // CIR: %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARRAY]] : !cir.ptr> -> !cir.ptr // CIR: %[[END:.*]] = cir.ptr_stride %[[BEGIN]], %[[CONST4]] : (!cir.ptr, !u64i) -> !cir.ptr // CIR: %[[ITER:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["__array_idx"] // CIR: cir.store %[[BEGIN]], %[[ITER]] : !cir.ptr, !cir.ptr> // CIR: cir.cleanup.scope { // CIR: cir.do { // CIR: %[[CUR:.*]] = cir.load %[[ITER]] : !cir.ptr>, !cir.ptr // CIR: cir.call @_ZN1SC1Ev(%[[CUR]]) : (!cir.ptr{{.*}}) -> () // CIR: %[[CONST1:.*]] = cir.const #cir.int<1> : !u64i // CIR: %[[NEXT:.*]] = cir.ptr_stride %[[CUR]], %[[CONST1]] : (!cir.ptr, !u64i) -> !cir.ptr // CIR: cir.store %[[NEXT]], %[[ITER]] : !cir.ptr, !cir.ptr> // CIR: cir.yield // CIR: } while { // CIR: %[[CUR2:.*]] = cir.load %[[ITER]] : !cir.ptr>, !cir.ptr // CIR: %[[CMP:.*]] = cir.cmp ne %[[CUR2]], %[[END]] : !cir.ptr // CIR: cir.condition(%[[CMP]]) // CIR: } // CIR: cir.yield // CIR: } cleanup eh { // CIR: %[[CUR3:.*]] = cir.load %[[ITER]] : !cir.ptr>, !cir.ptr // CIR: %[[NE:.*]] = cir.cmp ne %[[CUR3]], %[[BEGIN]] : !cir.ptr // CIR: cir.if %[[NE]] { // CIR: cir.do { // CIR: %[[EL:.*]] = cir.load %[[ITER]] : !cir.ptr>, !cir.ptr // CIR: %[[NEG1:.*]] = cir.const #cir.int<-1> : !s64i // CIR: %[[PREV:.*]] = cir.ptr_stride %[[EL]], %[[NEG1]] : (!cir.ptr, !s64i) -> !cir.ptr // CIR: cir.store %[[PREV]], %[[ITER]] : !cir.ptr, !cir.ptr> // CIR: cir.call @_ZN1SD1Ev(%[[PREV]]){{.*}} : (!cir.ptr{{.*}}) -> () // CIR: cir.yield // CIR: } while { // CIR: %[[EL2:.*]] = cir.load %[[ITER]] : !cir.ptr>, !cir.ptr // CIR: %[[NE2:.*]] = cir.cmp ne %[[EL2]], %[[BEGIN]] : !cir.ptr // 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 } void test_variable_size_partial_array_cleanup(int n) { S s[n]; } // CIR-BEFORE-LPP: cir.func {{.*}} @_Z40test_variable_size_partial_array_cleanupi // CIR-BEFORE-LPP: %[[N_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["n", init] // CIR-BEFORE-LPP: %[[N_VAL:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr, !s32i // CIR-BEFORE-LPP: %[[N:.*]] = cir.cast integral %[[N_VAL]] : !s32i -> !u64i // CIR-BEFORE-LPP: cir.stacksave // CIR-BEFORE-LPP: cir.cleanup.scope { // CIR-BEFORE-LPP: %[[VLA:.*]] = cir.alloca !rec_S, !cir.ptr, %[[N]] : !u64i, ["s", init] // CIR-BEFORE-LPP: cir.array.ctor %[[VLA]], %[[N]] : !cir.ptr, !u64i { // CIR-BEFORE-LPP: ^bb0(%[[CTOR_ARG:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SC1Ev(%[[CTOR_ARG]]) : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } partial_dtor { // CIR-BEFORE-LPP: ^bb0(%[[DTOR_ARG:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%[[DTOR_ARG]]){{.*}} : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: cir.cleanup.scope { // CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } cleanup all { // CIR-BEFORE-LPP: cir.array.dtor %[[VLA]], %[[N]] : !cir.ptr, !u64i { // CIR-BEFORE-LPP: ^bb0(%[[DTOR_ARG2:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%[[DTOR_ARG2]]){{.*}} : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: } cleanup normal { // CIR-BEFORE-LPP: cir.stackrestore // CIR-BEFORE-LPP: } // CIR: cir.func {{.*}} @_Z40test_variable_size_partial_array_cleanupi // CIR: %[[N_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["n", init] // CIR: %[[SAVED_STACK:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["saved_stack"] // CIR: %[[N_VAL:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr, !s32i // CIR: %[[N:.*]] = cir.cast integral %[[N_VAL]] : !s32i -> !u64i // CIR: %[[STACK:.*]] = cir.stacksave : !cir.ptr // CIR: cir.store {{.*}} %[[STACK]], %[[SAVED_STACK]] : !cir.ptr, !cir.ptr> // CIR: cir.cleanup.scope { // CIR: %[[BEGIN:.*]] = cir.alloca !rec_S, !cir.ptr, %[[N]] : !u64i, ["s", init] // CIR: %[[END:.*]] = cir.ptr_stride %[[BEGIN]], %[[N]] : (!cir.ptr, !u64i) -> !cir.ptr // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u64i // CIR: %[[IS_NONZERO:.*]] = cir.cmp ne %[[N]], %[[ZERO]] : !u64i // CIR: cir.if %[[IS_NONZERO]] { // CIR: %[[ITER:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["__array_idx"] // CIR: cir.store %[[BEGIN]], %[[ITER]] : !cir.ptr, !cir.ptr> // CIR: cir.cleanup.scope { // CIR: cir.do { // CIR: %[[CUR:.*]] = cir.load %[[ITER]] : !cir.ptr>, !cir.ptr // CIR: cir.call @_ZN1SC1Ev(%[[CUR]]) : (!cir.ptr{{.*}}) -> () // CIR: %[[CONST1:.*]] = cir.const #cir.int<1> : !u64i // CIR: %[[NEXT:.*]] = cir.ptr_stride %[[CUR]], %[[CONST1]] : (!cir.ptr, !u64i) -> !cir.ptr // CIR: cir.store %[[NEXT]], %[[ITER]] : !cir.ptr, !cir.ptr> // CIR: cir.yield // CIR: } while { // CIR: %[[CUR2:.*]] = cir.load %[[ITER]] : !cir.ptr>, !cir.ptr // CIR: %[[CMP:.*]] = cir.cmp ne %[[CUR2]], %[[END]] : !cir.ptr // CIR: cir.condition(%[[CMP]]) // CIR: } // CIR: cir.yield // CIR: } cleanup eh { // CIR: %[[CUR3:.*]] = cir.load %[[ITER]] : !cir.ptr>, !cir.ptr // CIR: %[[NE:.*]] = cir.cmp ne %[[CUR3]], %[[BEGIN]] : !cir.ptr // CIR: cir.if %[[NE]] { // CIR: cir.do { // CIR: %[[EL:.*]] = cir.load %[[ITER]] : !cir.ptr>, !cir.ptr // CIR: %[[NEG1:.*]] = cir.const #cir.int<-1> : !s64i // CIR: %[[PREV:.*]] = cir.ptr_stride %[[EL]], %[[NEG1]] : (!cir.ptr, !s64i) -> !cir.ptr // CIR: cir.store %[[PREV]], %[[ITER]] : !cir.ptr, !cir.ptr> // CIR: cir.call @_ZN1SD1Ev(%[[PREV]]){{.*}} : (!cir.ptr{{.*}}) -> () // CIR: cir.yield // CIR: } while { // CIR: %[[EL2:.*]] = cir.load %[[ITER]] : !cir.ptr>, !cir.ptr // CIR: %[[NE2:.*]] = cir.cmp ne %[[EL2]], %[[BEGIN]] : !cir.ptr // CIR: cir.condition(%[[NE2]]) // CIR: } // CIR: } // CIR: cir.yield // CIR: } // CIR: } // // --- normal dtor --- // CIR: } cleanup all { // CIR: %[[LAST:.*]] = cir.ptr_stride %[[BEGIN]], %[[N]] : (!cir.ptr, !u64i) -> !cir.ptr // CIR: %[[DTOR_NE:.*]] = cir.cmp ne %[[LAST]], %[[BEGIN]] : !cir.ptr // CIR: cir.if %[[DTOR_NE]] { // CIR: %[[DTOR_ITER:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["__array_idx"] // CIR: cir.store %[[LAST]], %[[DTOR_ITER]] : !cir.ptr, !cir.ptr> // CIR: cir.do { // CIR: %[[DTOR_CUR:.*]] = cir.load %[[DTOR_ITER]] : !cir.ptr>, !cir.ptr // CIR: %[[DTOR_NEG1:.*]] = cir.const #cir.int<-1> : !s64i // CIR: %[[DTOR_PREV:.*]] = cir.ptr_stride %[[DTOR_CUR]], %[[DTOR_NEG1]] : (!cir.ptr, !s64i) -> !cir.ptr // CIR: cir.store %[[DTOR_PREV]], %[[DTOR_ITER]] : !cir.ptr, !cir.ptr> // CIR: cir.call @_ZN1SD1Ev(%[[DTOR_PREV]]){{.*}} : (!cir.ptr{{.*}}) -> () // CIR: cir.yield // CIR: } while { // CIR: %[[DTOR_CUR2:.*]] = cir.load %[[DTOR_ITER]] : !cir.ptr>, !cir.ptr // CIR: %[[DTOR_NE2:.*]] = cir.cmp ne %[[DTOR_CUR2]], %[[BEGIN]] : !cir.ptr // CIR: cir.condition(%[[DTOR_NE2]]) // CIR: } // CIR: } // CIR: cir.yield // CIR: } // CIR: cir.yield // CIR: } cleanup normal { // CIR: cir.stackrestore {{.*}} : !cir.ptr // CIR: cir.yield // CIR: } // LLVM: define dso_local void @_Z40test_variable_size_partial_array_cleanupi // LLVM: %[[N_I32:.*]] = load i32, ptr %{{.*}} // LLVM: %[[N:.*]] = sext i32 %[[N_I32]] to i64 // LLVM: call ptr @llvm.stacksave.p0() // // --- VLA alloca + zero check --- // LLVM: %[[BEGIN:.*]] = alloca %struct.S, i64 %[[N]] // LLVM: %[[END:.*]] = getelementptr %struct.S, ptr %[[BEGIN]], i64 %[[N]] // LLVM: %[[IS_NONZERO:.*]] = icmp ne i64 %[[N]], 0 // LLVM: br i1 %[[IS_NONZERO]], label %[[CTOR_SETUP:.*]], label %[[AFTER_CTOR:.*]] // // --- ctor init --- // LLVM: [[CTOR_SETUP]]: // LLVM: store ptr %[[BEGIN]], ptr %[[CTOR_ITER:.*]] // LLVM: br label %[[CTOR_ENTRY:.*]] // // LLVM: [[CTOR_ENTRY]]: // LLVM: br label %[[CTOR_BODY:.*]] // // --- ctor loop condition (back-edge) --- // LLVM: [[CTOR_LOOP_COND:.*]]: // LLVM: %[[COND_CUR:.*]] = load ptr, ptr %[[CTOR_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 %[[CTOR_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 %[[CTOR_ITER]] // LLVM: br label %[[CTOR_LOOP_COND]] // // LLVM: [[CTOR_EXIT]]: // LLVM: br label %[[CTOR_JOIN:.*]] // // --- landing pad + cleanup guard --- // LLVM: [[LPAD]]: // LLVM: landingpad { ptr, i32 } // LLVM: cleanup // LLVM: %[[PAD_CUR:.*]] = load ptr, ptr %[[CTOR_ITER]] // LLVM: %[[GUARD:.*]] = icmp ne ptr %[[PAD_CUR]], %[[BEGIN]] // LLVM: br i1 %[[GUARD]], label %[[PDTOR_ENTRY:.*]], label %[[EH_RESUME:.*]] // // --- partial dtor do-while entry --- // LLVM: [[PDTOR_ENTRY]]: // LLVM: br label %[[PDTOR_BODY:.*]] // // --- partial dtor loop condition (back-edge) --- // LLVM: [[PDTOR_LOOP_COND:.*]]: // LLVM: %[[PDTOR_CUR:.*]] = load ptr, ptr %[[CTOR_ITER]] // LLVM: %[[PDTOR_CONT:.*]] = icmp ne ptr %[[PDTOR_CUR]], %[[BEGIN]] // LLVM: br i1 %[[PDTOR_CONT]], label %[[PDTOR_BODY]], label %[[PDTOR_DONE:.*]] // // --- partial dtor loop body --- // LLVM: [[PDTOR_BODY]]: // LLVM: %[[PDCUR:.*]] = load ptr, ptr %[[CTOR_ITER]] // LLVM: %[[PPREV:.*]] = getelementptr %struct.S, ptr %[[PDCUR]], i64 -1 // LLVM: store ptr %[[PPREV]], ptr %[[CTOR_ITER]] // LLVM: call void @_ZN1SD1Ev(ptr{{.*}} %[[PPREV]]) // LLVM: br label %[[PDTOR_LOOP_COND]] // // LLVM: [[PDTOR_DONE]]: // LLVM: br label %[[EH_RESUME]] // // LLVM: [[EH_RESUME]]: // LLVM: resume { ptr, i32 } // // --- ctor done join --- // LLVM: [[CTOR_JOIN]]: // LLVM: br label %[[AFTER_CTOR]] // // --- normal dtor setup --- // LLVM: [[AFTER_CTOR]]: // LLVM: %[[LAST:.*]] = getelementptr %struct.S, ptr %[[BEGIN]], i64 %[[N]] // LLVM: %[[DTOR_NE:.*]] = icmp ne ptr %[[LAST]], %[[BEGIN]] // LLVM: br i1 %[[DTOR_NE]], label %[[NDTOR_ENTRY:.*]], label %[[NDTOR_DONE:.*]] // // LLVM: [[NDTOR_ENTRY]]: // LLVM: store ptr %[[LAST]], ptr %[[DTOR_ITER:.*]] // LLVM: br label %[[NDTOR_BODY:.*]] // // --- normal dtor loop condition (back-edge) --- // LLVM: [[NDTOR_LOOP_COND:.*]]: // LLVM: %[[NDCUR_CHECK:.*]] = load ptr, ptr %[[DTOR_ITER]] // LLVM: %[[NDTOR_CONT:.*]] = icmp ne ptr %[[NDCUR_CHECK]], %[[BEGIN]] // LLVM: br i1 %[[NDTOR_CONT]], label %[[NDTOR_BODY]], label %[[NDTOR_EXIT:.*]] // // --- normal dtor loop body --- // LLVM: [[NDTOR_BODY]]: // LLVM: %[[NDCUR:.*]] = load ptr, ptr %[[DTOR_ITER]] // LLVM: %[[NDPREV:.*]] = getelementptr %struct.S, ptr %[[NDCUR]], i64 -1 // LLVM: store ptr %[[NDPREV]], ptr %[[DTOR_ITER]] // LLVM: call void @_ZN1SD1Ev(ptr{{.*}} %[[NDPREV]]) // LLVM: br label %[[NDTOR_LOOP_COND]] // // LLVM: [[NDTOR_EXIT]]: // LLVM: br label %[[NDTOR_DONE]] // // LLVM: [[NDTOR_DONE]]: // LLVM: call void @llvm.stackrestore.p0 // LLVM: ret void // OGCG: define dso_local void @_Z40test_variable_size_partial_array_cleanupi // OGCG: [[ENTRY:.*]]: // OGCG: %[[N:.*]] = zext i32 %{{.*}} to i64 // OGCG: %[[VLA:.*]] = alloca %struct.S, i64 %[[N]] // OGCG: %[[ISEMPTY:.*]] = icmp eq i64 %[[N]], 0 // OGCG: br i1 %[[ISEMPTY]], label %[[CTOR_CONT:.*]], label %[[CTOR_LOOP_ENTRY:.*]] // // --- ctor loop --- // OGCG: [[CTOR_LOOP_ENTRY]]: // OGCG: %[[CTOR_END:.*]] = getelementptr inbounds %struct.S, ptr %[[VLA]], i64 %[[N]] // OGCG: br label %[[CTOR_LOOP:.*]] // // OGCG: [[CTOR_LOOP]]: // OGCG: %[[CUR:.*]] = phi ptr [ %[[VLA]], %[[CTOR_LOOP_ENTRY]] ], [ %[[NEXT:.*]], %[[INVOKE_CONT:.*]] ] // OGCG: invoke void @_ZN1SC1Ev(ptr{{.*}}) // OGCG: to label %[[INVOKE_CONT]] unwind label %[[LPAD:.*]] // // OGCG: [[INVOKE_CONT]]: // OGCG: %[[NEXT]] = getelementptr inbounds %struct.S, ptr %[[CUR]], i64 1 // OGCG: %[[DONE:.*]] = icmp eq ptr %[[NEXT]], %[[CTOR_END]] // OGCG: br i1 %[[DONE]], label %[[CTOR_CONT]], label %[[CTOR_LOOP]] // // --- normal dtor --- // OGCG: [[CTOR_CONT]]: // OGCG: %[[DTOR_END:.*]] = getelementptr inbounds %struct.S, ptr %[[VLA]], i64 %[[N]] // OGCG: %[[DTOR_ISEMPTY:.*]] = icmp eq ptr %[[VLA]], %[[DTOR_END]] // OGCG: br i1 %[[DTOR_ISEMPTY]], label %[[DTOR_DONE:.*]], label %[[DTOR_LOOP:.*]] // // OGCG: [[DTOR_LOOP]]: // OGCG: %[[PAST:.*]] = phi ptr [ %[[DTOR_END]], %[[CTOR_CONT]] ], [ %[[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]], %[[VLA]] // OGCG: br i1 %[[DDONE]], label %[[DTOR_DONE]], label %[[DTOR_LOOP]] // // OGCG: [[DTOR_DONE]]: // OGCG: call void @llvm.stackrestore.p0(ptr %{{.*}}) // OGCG: ret void // // --- landing pad + cleanup guard --- // OGCG: [[LPAD]]: // OGCG: landingpad { ptr, i32 } // OGCG: cleanup // OGCG: %[[PISEMPTY:.*]] = icmp eq ptr %[[VLA]], %[[CUR]] // OGCG: br i1 %[[PISEMPTY]], label %[[PDTOR_DONE:.*]], label %[[PDTOR_LOOP:.*]] // // --- partial dtor loop --- // OGCG: [[PDTOR_LOOP]]: // OGCG: %[[PPAST:.*]] = phi ptr [ %[[CUR]], %[[LPAD]] ], [ %[[PPREV:.*]], %[[PDTOR_LOOP]] ] // OGCG: %[[PPREV]] = getelementptr inbounds %struct.S, ptr %[[PPAST]], i64 -1 // OGCG: call void @_ZN1SD1Ev(ptr{{.*}} %[[PPREV]]) // OGCG: %[[PDDONE:.*]] = icmp eq ptr %[[PPREV]], %[[VLA]] // OGCG: br i1 %[[PDDONE]], label %[[PDTOR_DONE]], label %[[PDTOR_LOOP]] // // OGCG: [[PDTOR_DONE]]: // OGCG: br label %[[EH_RESUME:.*]] // // OGCG: [[EH_RESUME]]: // OGCG: resume { ptr, i32 } void test_multi_dim_vla(int n, int m) { S s[n][m]; } // CIR-BEFORE-LPP: cir.func {{.*}} @_Z18test_multi_dim_vlaii // CIR-BEFORE-LPP: %[[N_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["n", init] // CIR-BEFORE-LPP: %[[M_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["m", init] // CIR-BEFORE-LPP: %[[N_VAL:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr, !s32i // CIR-BEFORE-LPP: %[[N:.*]] = cir.cast integral %[[N_VAL]] : !s32i -> !u64i // CIR-BEFORE-LPP: %[[M_VAL:.*]] = cir.load {{.*}} %[[M_ADDR]] : !cir.ptr, !s32i // CIR-BEFORE-LPP: %[[M:.*]] = cir.cast integral %[[M_VAL]] : !s32i -> !u64i // CIR-BEFORE-LPP: cir.stacksave // CIR-BEFORE-LPP: cir.cleanup.scope { // CIR-BEFORE-LPP: %[[NM:.*]] = cir.mul nuw %[[N]], %[[M]] : !u64i // CIR-BEFORE-LPP: %[[VLA:.*]] = cir.alloca !rec_S, !cir.ptr, %[[NM]] : !u64i, ["s", init] // CIR-BEFORE-LPP: cir.array.ctor %[[VLA]], {{.*}} : !cir.ptr, !u64i { // CIR-BEFORE-LPP: ^bb0(%[[CTOR_ARG:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SC1Ev(%[[CTOR_ARG]]) : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } partial_dtor { // CIR-BEFORE-LPP: ^bb0(%[[DTOR_ARG:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%[[DTOR_ARG]]){{.*}} : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: cir.cleanup.scope { // CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } cleanup all { // CIR-BEFORE-LPP: cir.array.dtor %[[VLA]], {{.*}} : !cir.ptr, !u64i { // CIR-BEFORE-LPP: ^bb0(%[[DTOR_ARG2:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%[[DTOR_ARG2]]){{.*}} : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: } cleanup normal { // CIR-BEFORE-LPP: cir.stackrestore // CIR-BEFORE-LPP: } // CIR: cir.func {{.*}} @_Z18test_multi_dim_vlaii // CIR: %[[N_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["n", init] // CIR: %[[M_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["m", init] // CIR: %[[SAVED_STACK:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["saved_stack"] // CIR: %[[N_VAL:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr, !s32i // CIR: %[[N:.*]] = cir.cast integral %[[N_VAL]] : !s32i -> !u64i // CIR: %[[M_VAL:.*]] = cir.load {{.*}} %[[M_ADDR]] : !cir.ptr, !s32i // CIR: %[[M:.*]] = cir.cast integral %[[M_VAL]] : !s32i -> !u64i // CIR: cir.cleanup.scope { // CIR: %[[NM:.*]] = cir.mul nuw %[[N]], %[[M]] : !u64i // CIR: %[[BEGIN:.*]] = cir.alloca !rec_S, !cir.ptr, %[[NM]] : !u64i, ["s", init] // CIR: cir.call @_ZN1SC1Ev // CIR: } cleanup eh { // CIR: cir.call @_ZN1SD1Ev // CIR: } cleanup all { // CIR: %[[NM3:.*]] = cir.mul nuw %[[N]], %[[M]] : !u64i // CIR: cir.call @_ZN1SD1Ev // CIR: } cleanup normal { // CIR: cir.stackrestore {{.*}} : !cir.ptr // CIR: } // LLVM: define dso_local void @_Z18test_multi_dim_vlaii // LLVM: %[[N_I32:.*]] = load i32, ptr %{{.*}} // LLVM: %[[N:.*]] = sext i32 %[[N_I32]] to i64 // LLVM: %[[M_I32:.*]] = load i32, ptr %{{.*}} // LLVM: %[[M:.*]] = sext i32 %[[M_I32]] to i64 // LLVM: call ptr @llvm.stacksave.p0() // // --- VLA alloca with n*m --- // LLVM: %[[NM:.*]] = mul nuw i64 %[[N]], %[[M]] // LLVM: %[[BEGIN:.*]] = alloca %struct.S, i64 %[[NM]] // // --- ctor loop --- // LLVM: invoke void @_ZN1SC1Ev(ptr{{.*}}) // LLVM: to label %{{.*}} unwind label %[[LPAD:.*]] // // --- landing pad + partial dtor --- // LLVM: [[LPAD]]: // LLVM: landingpad { ptr, i32 } // LLVM: cleanup // LLVM: call void @_ZN1SD1Ev // LLVM: resume { ptr, i32 } // // --- normal dtor --- // LLVM: %[[NM2:.*]] = mul nuw i64 %[[N]], %[[M]] // LLVM: %[[LAST:.*]] = getelementptr %struct.S, ptr %[[BEGIN]], i64 %[[NM2]] // LLVM: %[[DTOR_NE:.*]] = icmp ne ptr %[[LAST]], %[[BEGIN]] // LLVM: call void @_ZN1SD1Ev // LLVM: call void @llvm.stackrestore.p0 // LLVM: ret void // OGCG: define dso_local void @_Z18test_multi_dim_vlaii // OGCG: [[ENTRY:.*]]: // OGCG: %[[N:.*]] = zext i32 %{{.*}} to i64 // OGCG: %[[M:.*]] = zext i32 %{{.*}} to i64 // OGCG: %[[NM:.*]] = mul nuw i64 %[[N]], %[[M]] // OGCG: %[[VLA:.*]] = alloca %struct.S, i64 %[[NM]] // OGCG: %[[ISEMPTY:.*]] = icmp eq i64 %{{.*}}, 0 // OGCG: br i1 %[[ISEMPTY]], label %[[CTOR_CONT:.*]], label %[[CTOR_LOOP_ENTRY:.*]] // // --- ctor loop --- // OGCG: [[CTOR_LOOP_ENTRY]]: // OGCG: invoke void @_ZN1SC1Ev(ptr{{.*}}) // OGCG: to label %{{.*}} unwind label %[[LPAD:.*]] // // --- normal dtor --- // OGCG: [[CTOR_CONT]]: // OGCG: %[[NM2:.*]] = mul nuw i64 %[[N]], %[[M]] // OGCG: call void @_ZN1SD1Ev // // OGCG: call void @llvm.stackrestore.p0(ptr %{{.*}}) // OGCG: ret void // // --- landing pad + partial dtor --- // OGCG: [[LPAD]]: // OGCG: landingpad { ptr, i32 } // OGCG: cleanup // OGCG: call void @_ZN1SD1Ev // // OGCG: resume { ptr, i32 } void test_vla_of_constant_array(int n) { S s[n][4]; } // CIR-BEFORE-LPP: cir.func {{.*}} @_Z26test_vla_of_constant_arrayi // CIR-BEFORE-LPP: %[[N_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["n", init] // CIR-BEFORE-LPP: %[[N_VAL:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr, !s32i // CIR-BEFORE-LPP: %[[N:.*]] = cir.cast integral %[[N_VAL]] : !s32i -> !u64i // CIR-BEFORE-LPP: cir.stacksave // CIR-BEFORE-LPP: cir.cleanup.scope { // CIR-BEFORE-LPP: %[[VLA:.*]] = cir.alloca !cir.array, !cir.ptr>, %[[N]] : !u64i, ["s", init] // CIR-BEFORE-LPP: %[[FOUR:.*]] = cir.const #cir.int<4> : !u64i // CIR-BEFORE-LPP: %[[TOTAL:.*]] = cir.mul nuw %[[N]], %[[FOUR]] : !u64i // CIR-BEFORE-LPP: %[[ELEM_PTR:.*]] = cir.cast bitcast %[[VLA]] : !cir.ptr> -> !cir.ptr // CIR-BEFORE-LPP: cir.array.ctor %[[ELEM_PTR]], %[[TOTAL]] : !cir.ptr, !u64i { // CIR-BEFORE-LPP: ^bb0(%[[CTOR_ARG:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SC1Ev(%[[CTOR_ARG]]) : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } partial_dtor { // CIR-BEFORE-LPP: ^bb0(%[[DTOR_ARG:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%[[DTOR_ARG]]){{.*}} : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: cir.cleanup.scope { // CIR-BEFORE-LPP: cir.yield // CIR-BEFORE-LPP: } cleanup all { // CIR-BEFORE-LPP: %{{.*}} = cir.const #cir.int<4> : !u64i // CIR-BEFORE-LPP: %{{.*}} = cir.mul nuw %[[N]], %{{.*}} : !u64i // CIR-BEFORE-LPP: %{{.*}} = cir.cast bitcast %[[VLA]] : !cir.ptr> -> !cir.ptr // CIR-BEFORE-LPP: cir.array.dtor {{.*}} : !cir.ptr, !u64i { // CIR-BEFORE-LPP: ^bb0(%[[DTOR_ARG2:.*]]: !cir.ptr): // CIR-BEFORE-LPP: cir.call @_ZN1SD1Ev(%[[DTOR_ARG2]]){{.*}} : (!cir.ptr{{.*}}) -> () // CIR-BEFORE-LPP: } // CIR-BEFORE-LPP: } cleanup normal { // CIR-BEFORE-LPP: cir.stackrestore // CIR-BEFORE-LPP: } // CIR: cir.func {{.*}} @_Z26test_vla_of_constant_arrayi // CIR: %[[N_ADDR:.*]] = cir.alloca !s32i, !cir.ptr, ["n", init] // CIR: %[[N_VAL:.*]] = cir.load {{.*}} %[[N_ADDR]] : !cir.ptr, !s32i // CIR: %[[N:.*]] = cir.cast integral %[[N_VAL]] : !s32i -> !u64i // CIR: cir.cleanup.scope { // CIR: %[[VLA:.*]] = cir.alloca !cir.array, !cir.ptr>, %[[N]] : !u64i, ["s", init] // CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !u64i // CIR: %[[TOTAL:.*]] = cir.mul nuw %[[N]], %[[FOUR]] : !u64i // CIR: %[[ELEM_PTR:.*]] = cir.cast bitcast %[[VLA]] : !cir.ptr> -> !cir.ptr // CIR: cir.call @_ZN1SC1Ev // CIR: } cleanup eh { // CIR: cir.call @_ZN1SD1Ev // CIR: } cleanup all { // CIR: %{{.*}} = cir.const #cir.int<4> : !u64i // CIR: %{{.*}} = cir.mul nuw %[[N]], %{{.*}} : !u64i // CIR: %{{.*}} = cir.cast bitcast %[[VLA]] : !cir.ptr> -> !cir.ptr // CIR: cir.call @_ZN1SD1Ev // CIR: } cleanup normal { // CIR: cir.stackrestore {{.*}} : !cir.ptr // CIR: } // LLVM: define dso_local void @_Z26test_vla_of_constant_arrayi // LLVM: %[[N_I32:.*]] = load i32, ptr %{{.*}} // LLVM: %[[N:.*]] = sext i32 %[[N_I32]] to i64 // LLVM: call ptr @llvm.stacksave.p0() // // --- VLA alloca with [4 x %struct.S] --- // LLVM: %[[BEGIN:.*]] = alloca [4 x %struct.S], i64 %[[N]] // LLVM: %[[TOTAL:.*]] = mul nuw i64 %[[N]], 4 // // --- ctor loop --- // LLVM: invoke void @_ZN1SC1Ev(ptr{{.*}}) // LLVM: to label %{{.*}} unwind label %[[LPAD:.*]] // // --- landing pad + partial dtor --- // LLVM: [[LPAD]]: // LLVM: landingpad { ptr, i32 } // LLVM: cleanup // LLVM: call void @_ZN1SD1Ev // LLVM: resume { ptr, i32 } // // --- normal dtor --- // LLVM: %[[TOTAL2:.*]] = mul nuw i64 %[[N]], 4 // LLVM: call void @_ZN1SD1Ev // LLVM: call void @llvm.stackrestore.p0 // LLVM: ret void // OGCG: define dso_local void @_Z26test_vla_of_constant_arrayi // OGCG: [[ENTRY:.*]]: // OGCG: %[[N:.*]] = zext i32 %{{.*}} to i64 // OGCG: %[[VLA:.*]] = alloca [4 x %struct.S], i64 %[[N]] // OGCG: %[[ARRAY_BEGIN:.*]] = getelementptr inbounds [4 x %struct.S], ptr %[[VLA]], i32 0, i32 0 // OGCG: %[[TOTAL:.*]] = mul nuw i64 %[[N]], 4 // OGCG: %[[ISEMPTY:.*]] = icmp eq i64 %[[TOTAL]], 0 // OGCG: br i1 %[[ISEMPTY]], label %[[CTOR_CONT:.*]], label %[[CTOR_LOOP_ENTRY:.*]] // // --- ctor loop --- // OGCG: [[CTOR_LOOP_ENTRY]]: // OGCG: invoke void @_ZN1SC1Ev(ptr{{.*}}) // OGCG: to label %{{.*}} unwind label %[[LPAD:.*]] // // --- normal dtor --- // OGCG: [[CTOR_CONT]]: // OGCG: %[[TOTAL2:.*]] = mul nuw i64 %[[N]], 4 // OGCG: call void @_ZN1SD1Ev // // OGCG: call void @llvm.stackrestore.p0(ptr %{{.*}}) // OGCG: ret void // // --- landing pad + partial dtor --- // OGCG: [[LPAD]]: // OGCG: landingpad { ptr, i32 } // OGCG: cleanup // OGCG: call void @_ZN1SD1Ev // // OGCG: resume { ptr, i32 } void test_init_list_partial_array_cleanup() { S arr[4] = { S(), S() }; } // CIR-LABEL: cir.func {{.*}} @_Z36test_init_list_partial_array_cleanupv() // CIR: %[[ARRAY:.*]] = cir.alloca !cir.array, !cir.ptr>, ["arr", init] // CIR: %[[END_OF_INIT:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["arrayinit.endOfInit"] // CIR: %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARRAY]] : !cir.ptr> -> !cir.ptr // CIR: cir.store {{.*}} %[[BEGIN]], %[[END_OF_INIT]] : !cir.ptr, !cir.ptr> // CIR: cir.cleanup.scope { // --- first explicit init --- // CIR: cir.call @_ZN1SC1Ev(%[[BEGIN]]) // --- advance + update endOfInit for second element --- // CIR: %[[SECOND:.*]] = cir.ptr_stride %[[BEGIN]], %{{.*}} // CIR: cir.store {{.*}} %[[SECOND]], %[[END_OF_INIT]] // --- second explicit init --- // CIR: cir.call @_ZN1SC1Ev(%[[SECOND]]) // --- advance + update endOfInit for filler start --- // CIR: %[[FILLER_START:.*]] = cir.ptr_stride %[[SECOND]], %{{.*}} // CIR: cir.store {{.*}} %[[FILLER_START]], %[[END_OF_INIT]] // --- do-while filler loop --- // CIR: cir.do { // CIR: %[[CUR:.*]] = cir.load {{.*}} %{{.*}} : !cir.ptr>, !cir.ptr // CIR: cir.call @_ZN1SC1Ev(%[[CUR]]) // CIR: %[[NEXT:.*]] = cir.ptr_stride %[[CUR]], %{{.*}} // CIR: cir.store {{.*}} %[[NEXT]], %[[END_OF_INIT]] // CIR: cir.yield // CIR: } while { // CIR: cir.condition(%{{.*}}) // CIR: } // CIR: cir.yield // --- EH cleanup: partial destruction --- // CIR: } cleanup eh { // CIR: %[[END_VAL:.*]] = cir.load {{.*}} %[[END_OF_INIT]] : !cir.ptr>, !cir.ptr // CIR: %[[NE:.*]] = cir.cmp ne %[[END_VAL]], %[[BEGIN]] : !cir.ptr // CIR: cir.if %[[NE]] { // CIR: cir.do { // CIR: %[[EL:.*]] = cir.load {{.*}} %{{.*}} : !cir.ptr>, !cir.ptr // CIR: %[[NEG1:.*]] = cir.const #cir.int<-1> : !s64i // CIR: %[[PREV:.*]] = cir.ptr_stride %[[EL]], %[[NEG1]] : (!cir.ptr, !s64i) -> !cir.ptr // CIR: cir.call @_ZN1SD1Ev(%[[PREV]]) // CIR: cir.yield // CIR: } while { // CIR: %[[EL2:.*]] = cir.load {{.*}} %{{.*}} : !cir.ptr>, !cir.ptr // CIR: %[[NE2:.*]] = cir.cmp ne %[[EL2]], %[[BEGIN]] : !cir.ptr // CIR: cir.condition(%[[NE2]]) // CIR: } // CIR: } // CIR: cir.yield // CIR: } // LLVM-LABEL: define dso_local void @_Z36test_init_list_partial_array_cleanupv() // LLVM: %[[ARRAY:.*]] = alloca [4 x %struct.S] // LLVM: %[[BEGIN:.*]] = getelementptr %struct.S, ptr %[[ARRAY]], i32 0 // LLVM: store ptr %[[BEGIN]], ptr %[[END_OF_INIT:.*]] // // --- first ctor --- // LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[BEGIN]]) // LLVM: to label %[[CONT1:.*]] unwind label %[[LPAD:.*]] // // --- second ctor --- // LLVM: [[CONT1]]: // LLVM: %[[SECOND:.*]] = getelementptr %struct.S, ptr %[[BEGIN]], i64 1 // LLVM: store ptr %[[SECOND]], ptr %[[END_OF_INIT]] // LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[SECOND]]) // LLVM: to label %{{.*}} unwind label %[[LPAD]] // // --- filler loop with invoke --- // LLVM: invoke void @_ZN1SC1Ev(ptr {{.*}}) // LLVM: to label %[[FILLER_CONT:.*]] unwind label %[[LPAD]] // // LLVM: [[FILLER_CONT]]: // LLVM: %[[FNEXT:.*]] = getelementptr %struct.S, ptr %{{.*}}, i64 1 // LLVM: store ptr %[[FNEXT]], ptr %[[END_OF_INIT]] // // --- landing pad + cleanup guard --- // LLVM: [[LPAD]]: // LLVM: landingpad { ptr, i32 } // LLVM: cleanup // LLVM: %[[PAD_CUR:.*]] = load ptr, ptr %[[END_OF_INIT]] // LLVM: %[[GUARD:.*]] = icmp ne ptr %[[PAD_CUR]], %[[BEGIN]] // LLVM: br i1 %[[GUARD]], label %[[DTOR_ENTRY:.*]], label %[[EH_RESUME:.*]] // // --- partial dtor do-while loop --- // LLVM: [[DTOR_ENTRY]]: // LLVM: store ptr %[[PAD_CUR]], ptr %[[DTOR_ITER:.*]] // LLVM: br label %[[DTOR_BODY:.*]] // // LLVM: [[DTOR_LOOP_COND:.*]]: // LLVM: %[[DTOR_CUR:.*]] = load ptr, ptr %[[DTOR_ITER]] // LLVM: %[[DTOR_CONT:.*]] = icmp ne ptr %[[DTOR_CUR]], %[[BEGIN]] // LLVM: br i1 %[[DTOR_CONT]], label %[[DTOR_BODY]], label %[[DTOR_DONE:.*]] // // LLVM: [[DTOR_BODY]]: // LLVM: %[[DCUR:.*]] = load ptr, ptr %[[DTOR_ITER]] // LLVM: %[[PREV:.*]] = getelementptr %struct.S, ptr %[[DCUR]], i64 -1 // LLVM: store ptr %[[PREV]], ptr %[[DTOR_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-LABEL: define dso_local void @_Z36test_init_list_partial_array_cleanupv() // OGCG: %[[ARR:.*]] = alloca [4 x %struct.S] // OGCG: %[[END_OF_INIT:.*]] = alloca ptr // OGCG: store ptr %[[ARR]], ptr %[[END_OF_INIT]] // // --- first explicit ctor --- // OGCG: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[ARR]]) // OGCG: to label %[[CONT1:.*]] unwind label %[[LPAD:.*]] // // --- second explicit ctor --- // OGCG: [[CONT1]]: // OGCG: %[[EL1:.*]] = getelementptr inbounds %struct.S, ptr %[[ARR]], i64 1 // OGCG: store ptr %[[EL1]], ptr %[[END_OF_INIT]] // OGCG: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[EL1]]) // OGCG: to label %[[CONT2:.*]] unwind label %[[LPAD]] // // --- filler loop setup --- // OGCG: [[CONT2]]: // OGCG: %[[FILLER_START:.*]] = getelementptr inbounds %struct.S, ptr %[[ARR]], i64 2 // OGCG: store ptr %[[FILLER_START]], ptr %[[END_OF_INIT]] // OGCG: %[[FILLER_END:.*]] = getelementptr inbounds %struct.S, ptr %[[ARR]], i64 4 // OGCG: br label %[[FILLER_BODY:.*]] // // --- filler loop body --- // OGCG: [[FILLER_BODY]]: // OGCG: %[[FILLER_CUR:.*]] = phi ptr [ %[[FILLER_START]], %[[CONT2]] ], [ %[[FILLER_NEXT:.*]], %[[FILLER_CONT:.*]] ] // OGCG: invoke void @_ZN1SC1Ev(ptr {{.*}} %[[FILLER_CUR]]) // OGCG: to label %[[FILLER_CONT]] unwind label %[[LPAD]] // // OGCG: [[FILLER_CONT]]: // OGCG: %[[FILLER_NEXT]] = getelementptr inbounds %struct.S, ptr %[[FILLER_CUR]], i64 1 // OGCG: store ptr %[[FILLER_NEXT]], ptr %[[END_OF_INIT]] // OGCG: %[[FILLER_DONE:.*]] = icmp eq ptr %[[FILLER_NEXT]], %[[FILLER_END]] // OGCG: br i1 %[[FILLER_DONE]], label %{{.*}}, label %[[FILLER_BODY]] // // --- landing pad + partial destruction --- // OGCG: [[LPAD]]: // OGCG: landingpad { ptr, i32 } // OGCG: cleanup // OGCG: %[[PAD_END:.*]] = load ptr, ptr %[[END_OF_INIT]] // OGCG: %[[ISEMPTY:.*]] = icmp eq ptr %[[ARR]], %[[PAD_END]] // OGCG: br i1 %[[ISEMPTY]], label %[[DTOR_DONE:.*]], label %[[DTOR_LOOP:.*]] // // OGCG: [[DTOR_LOOP]]: // OGCG: %[[DTOR_PAST:.*]] = phi ptr [ %[[PAD_END]], %[[LPAD]] ], [ %[[DTOR_PREV:.*]], %[[DTOR_LOOP]] ] // OGCG: %[[DTOR_PREV]] = getelementptr inbounds %struct.S, ptr %[[DTOR_PAST]], i64 -1 // OGCG: call void @_ZN1SD1Ev(ptr {{.*}} %[[DTOR_PREV]]) // OGCG: %[[DTOR_CONT:.*]] = icmp eq ptr %[[DTOR_PREV]], %[[ARR]] // OGCG: br i1 %[[DTOR_CONT]], label %[[DTOR_DONE]], label %[[DTOR_LOOP]] // // OGCG: [[DTOR_DONE]]: // OGCG: br label %[[EH_RESUME:.*]] // // OGCG: [[EH_RESUME]]: // OGCG: resume { ptr, i32 }