1515// LLVM: @needsCtor = global %struct.NeedsCtor zeroinitializer, align 1
1616// LLVM: @needsDtor = global %struct.NeedsDtor zeroinitializer, align 1
1717// LLVM: @needsCtorDtor = global %struct.NeedsCtorDtor zeroinitializer, align 1
18+ // LLVM: @arrDtor = global [16 x %struct.ArrayDtor] zeroinitializer, align 16
1819// LLVM: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_[[FILENAME:.*]], ptr null }]
1920
2021// OGCG: @needsCtor = global %struct.NeedsCtor zeroinitializer, align 1
2122// OGCG: @needsDtor = global %struct.NeedsDtor zeroinitializer, align 1
2223// OGCG: @__dso_handle = external hidden global i8
2324// OGCG: @needsCtorDtor = global %struct.NeedsCtorDtor zeroinitializer, align 1
25+ // OGCG: @arrDtor = global [16 x %struct.ArrayDtor] zeroinitializer, align 16
2426// OGCG: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_[[FILENAME:.*]], ptr null }]
2527
2628struct NeedsCtor {
@@ -145,11 +147,11 @@ float fp;
145147int i = (int )fp;
146148
147149// CIR-BEFORE-LPP: cir.global external @i = ctor : !s32i {
148- // CIR-BEFORE-LPP: %0 = cir.get_global @i : !cir.ptr<!s32i>
149- // CIR-BEFORE-LPP: %1 = cir.get_global @fp : !cir.ptr<!cir.float>
150- // CIR-BEFORE-LPP: %2 = cir.load{{.*}} %1 : !cir.ptr<!cir.float>, !cir.float
151- // CIR-BEFORE-LPP: %3 = cir.cast float_to_int %2 : !cir.float -> !s32i
152- // CIR-BEFORE-LPP: cir.store{{.*}} %3 , %0 : !s32i, !cir.ptr<!s32i>
150+ // CIR-BEFORE-LPP: %[[I:.*]] = cir.get_global @i : !cir.ptr<!s32i>
151+ // CIR-BEFORE-LPP: %[[FP:.*]] = cir.get_global @fp : !cir.ptr<!cir.float>
152+ // CIR-BEFORE-LPP: %[[FP_VAL:.*]] = cir.load{{.*}} %[[FP]] : !cir.ptr<!cir.float>, !cir.float
153+ // CIR-BEFORE-LPP: %[[FP_I32:.*]] = cir.cast float_to_int %[[FP_VAL]] : !cir.float -> !s32i
154+ // CIR-BEFORE-LPP: cir.store{{.*}} %[[FP_I32]] , %[[I]] : !s32i, !cir.ptr<!s32i>
153155// CIR-BEFORE-LPP: }
154156
155157// CIR: cir.func internal private @__cxx_global_var_init.4()
@@ -169,6 +171,97 @@ int i = (int)fp;
169171// OGCG: %[[FP_I32:.*]] = fptosi float %[[TMP_FP]] to i32
170172// OGCG: store i32 %[[FP_I32]], ptr @i, align 4
171173
174+ struct ArrayDtor {
175+ ~ArrayDtor ();
176+ };
177+
178+ ArrayDtor arrDtor[16 ];
179+
180+ // CIR-BEFORE-LPP: cir.global external @arrDtor = #cir.zero : !cir.array<!rec_ArrayDtor x 16>
181+ // CIR-BEFORE-LPP-SAME: dtor {
182+ // CIR-BEFORE-LPP: %[[THIS:.*]] = cir.get_global @arrDtor : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>>
183+ // CIR-BEFORE-LPP: cir.array.dtor %[[THIS]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> {
184+ // CIR-BEFORE-LPP: ^bb0(%[[ELEM:.*]]: !cir.ptr<!rec_ArrayDtor>):
185+ // CIR-BEFORE-LPP: cir.call @_ZN9ArrayDtorD1Ev(%[[ELEM]]) nothrow : (!cir.ptr<!rec_ArrayDtor>) -> ()
186+ // CIR-BEFORE-LPP: cir.yield
187+ // CIR-BEFORE-LPP: }
188+ // CIR-BEFORE-LPP: }
189+
190+ // CIR: cir.global external @arrDtor = #cir.zero : !cir.array<!rec_ArrayDtor x 16> {alignment = 16 : i64}
191+ // CIR: cir.func internal private @__cxx_global_array_dtor(%[[ARR_ARG:.*]]: !cir.ptr<!void> {{.*}}) {
192+ // CIR: %[[CONST15:.*]] = cir.const #cir.int<15> : !u64i
193+ // CIR: %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARR_ARG]] : !cir.ptr<!void> -> !cir.ptr<!rec_ArrayDtor>
194+ // CIR: %[[END:.*]] = cir.ptr_stride %[[BEGIN]], %[[CONST15]] : (!cir.ptr<!rec_ArrayDtor>, !u64i) -> !cir.ptr<!rec_ArrayDtor>
195+ // CIR: %[[CUR_ADDR:.*]] = cir.alloca !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, ["__array_idx"]
196+ // CIR: cir.store %[[END]], %[[CUR_ADDR]] : !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>>
197+ // CIR: cir.do {
198+ // CIR: %[[CUR:.*]] = cir.load %[[CUR_ADDR]] : !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, !cir.ptr<!rec_ArrayDtor>
199+ // CIR: cir.call @_ZN9ArrayDtorD1Ev(%[[CUR]]) nothrow : (!cir.ptr<!rec_ArrayDtor>) -> ()
200+ // CIR: %[[NEG_ONE:.*]] = cir.const #cir.int<-1> : !s64i
201+ // CIR: %[[NEXT:.*]] = cir.ptr_stride %[[CUR]], %[[NEG_ONE]] : (!cir.ptr<!rec_ArrayDtor>, !s64i) -> !cir.ptr<!rec_ArrayDtor>
202+ // CIR: cir.store %[[NEXT]], %[[CUR_ADDR]] : !cir.ptr<!rec_ArrayDtor>, !cir.ptr<!cir.ptr<!rec_ArrayDtor>>
203+ // CIR: cir.yield
204+ // CIR: } while {
205+ // CIR: %[[CUR:.*]] = cir.load %[[CUR_ADDR]] : !cir.ptr<!cir.ptr<!rec_ArrayDtor>>, !cir.ptr<!rec_ArrayDtor>
206+ // CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CUR]], %[[BEGIN]]) : !cir.ptr<!rec_ArrayDtor>, !cir.bool
207+ // CIR: cir.condition(%[[CMP]])
208+ // CIR: }
209+ // CIR: cir.return
210+ // CIR: }
211+ //
212+ // CIR: cir.func internal private @__cxx_global_var_init.5() {
213+ // CIR: %[[ARR:.*]] = cir.get_global @arrDtor : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>>
214+ // CIR: %[[DTOR:.*]] = cir.get_global @__cxx_global_array_dtor : !cir.ptr<!cir.func<(!cir.ptr<!void>)>>
215+ // CIR: %[[DTOR_CAST:.*]] = cir.cast bitcast %[[DTOR]] : !cir.ptr<!cir.func<(!cir.ptr<!void>)>> -> !cir.ptr<!cir.func<(!cir.ptr<!void>)>>
216+ // CIR: %[[ARR_CAST:.*]] = cir.cast bitcast %[[ARR]] : !cir.ptr<!cir.array<!rec_ArrayDtor x 16>> -> !cir.ptr<!void>
217+ // CIR: %[[HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr<i8>
218+ // CIR: cir.call @__cxa_atexit(%[[DTOR_CAST]], %[[ARR_CAST]], %[[HANDLE]]) : (!cir.ptr<!cir.func<(!cir.ptr<!void>)>>, !cir.ptr<!void>, !cir.ptr<i8>) -> ()
219+
220+ // LLVM: define internal void @__cxx_global_array_dtor(ptr %[[ARR_ARG:.*]]) {
221+ // LLVM: %[[BEGIN:.*]] = getelementptr %struct.ArrayDtor, ptr %[[ARR_ARG]], i32 0
222+ // LLVM: %[[END:.*]] = getelementptr %struct.ArrayDtor, ptr %[[BEGIN]], i64 15
223+ // LLVM: %[[CUR_ADDR:.*]] = alloca ptr
224+ // LLVM: store ptr %[[END]], ptr %[[CUR_ADDR]]
225+ // LLVM: br label %[[LOOP_BODY:.*]]
226+ // LLVM: [[LOOP_COND:.*]]:
227+ // LLVM: %[[CUR:.*]] = load ptr, ptr %[[CUR_ADDR]]
228+ // LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[BEGIN]]
229+ // LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]]
230+ // LLVM: [[LOOP_BODY]]:
231+ // LLVM: %[[CUR:.*]] = load ptr, ptr %[[CUR_ADDR]]
232+ // LLVM: call void @_ZN9ArrayDtorD1Ev(ptr %[[CUR]]) #0
233+ // LLVM: %[[PREV:.*]] = getelementptr %struct.ArrayDtor, ptr %[[CUR]], i64 -1
234+ // LLVM: store ptr %[[PREV]], ptr %[[CUR_ADDR]]
235+ // LLVM: br label %[[LOOP_COND]]
236+ // LLVM: [[LOOP_END]]:
237+ // LLVM: ret void
238+ // LLVM: }
239+ //
240+ // LLVM: define internal void @__cxx_global_var_init.5() {
241+ // LLVM: call void @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr @arrDtor, ptr @__dso_handle)
242+
243+ // Note: OGCG defines these functions in reverse order of CIR->LLVM.
244+ // Note also: OGCG doesn't pass the address of the array to the destructor function.
245+ // Instead, it uses the global directly in the helper function.
246+
247+ // OGCG: define internal void @__cxx_global_var_init.5() {{.*}} section ".text.startup" {
248+ // OGCG: call i32 @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr null, ptr @__dso_handle)
249+
250+ // OGCG: define internal void @__cxx_global_array_dtor(ptr noundef %[[ARG:.*]]) {{.*}} section ".text.startup" {
251+ // OGCG: entry:
252+ // OGCG: %[[UNUSED_ADDR:.*]] = alloca ptr
253+ // OGCG: store ptr %[[ARG]], ptr %[[UNUSED_ADDR]]
254+ // OGCG: br label %[[LOOP_BODY:.*]]
255+ // OGCG: [[LOOP_BODY]]:
256+ // OGCG: %[[PREV:.*]] = phi ptr [ getelementptr inbounds (%struct.ArrayDtor, ptr @arrDtor, i64 16), %entry ], [ %[[CUR:.*]], %[[LOOP_BODY]] ]
257+ // OGCG: %[[CUR]] = getelementptr inbounds %struct.ArrayDtor, ptr %[[PREV]], i64 -1
258+ // OGCG: call void @_ZN9ArrayDtorD1Ev(ptr noundef nonnull align 1 dereferenceable(1) %[[CUR]])
259+ // OGCG: %[[DONE:.*]] = icmp eq ptr %[[CUR]], @arrDtor
260+ // OGCG: br i1 %[[DONE]], label %[[LOOP_END:.*]], label %[[LOOP_BODY]]
261+ // OGCG: [[LOOP_END]]:
262+ // OGCG: ret void
263+ // OGCG: }
264+
172265// Common init function for all globals with default priority
173266
174267// CIR: cir.func private @_GLOBAL__sub_I_[[FILENAME:.*]]() {
@@ -177,17 +270,20 @@ int i = (int)fp;
177270// CIR: cir.call @__cxx_global_var_init.2() : () -> ()
178271// CIR: cir.call @__cxx_global_var_init.3() : () -> ()
179272// CIR: cir.call @__cxx_global_var_init.4() : () -> ()
273+ // CIR: cir.call @__cxx_global_var_init.5() : () -> ()
180274
181275// LLVM: define void @_GLOBAL__sub_I_[[FILENAME]]()
182276// LLVM: call void @__cxx_global_var_init()
183277// LLVM: call void @__cxx_global_var_init.1()
184278// LLVM: call void @__cxx_global_var_init.2()
185279// LLVM: call void @__cxx_global_var_init.3()
186280// LLVM: call void @__cxx_global_var_init.4()
281+ // LLVM: call void @__cxx_global_var_init.5()
187282
188283// OGCG: define internal void @_GLOBAL__sub_I_[[FILENAME]]() {{.*}} section ".text.startup" {
189284// OGCG: call void @__cxx_global_var_init()
190285// OGCG: call void @__cxx_global_var_init.1()
191286// OGCG: call void @__cxx_global_var_init.2()
192287// OGCG: call void @__cxx_global_var_init.3()
193288// OGCG: call void @__cxx_global_var_init.4()
289+ // OGCG: call void @__cxx_global_var_init.5()
0 commit comments