[clang] [CIR] Add support for delegating constructors with VTT args (PR #156970)
Morris Hafner via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 4 14:50:50 PDT 2025
================
@@ -70,3 +70,266 @@ DelegatingWithZeroing::DelegatingWithZeroing(int) : DelegatingWithZeroing() {}
// OGCG: store i32 %[[I_ARG]], ptr %[[I_ADDR]]
// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
// OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[THIS]], i8 0, i64 4, i1 false)
+
+void other();
+
+class Base {
+public:
+ Base() { squawk(); }
+
+ virtual void squawk();
+};
+
+class Derived : public virtual Base {
+public:
+ Derived();
+ Derived(const void *inVoid);
+
+ virtual void squawk();
+};
+
+Derived::Derived() : Derived(nullptr) { other(); }
+Derived::Derived(const void *inVoid) { squawk(); }
+
+// Note: OGCG emits the constructors in a different order.
+// OGCG: define {{.*}} void @_ZN7DerivedC2Ev(ptr {{.*}} %[[THIS_ARG:.*]], ptr {{.*}} %[[VTT_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: %[[VTT_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// OGCG: call void @_ZN7DerivedC2EPKv(ptr {{.*}} %[[THIS]], ptr {{.*}} %[[VTT]], ptr {{.*}} null)
+// OGCG: call void @_Z5otherv()
+// OGCG: ret void
+
+// CIR: cir.func {{.*}} @_ZN7DerivedC2EPKv(
+// CIR-SAME: %[[THIS_ARG:.*]]: !cir.ptr<!rec_Derived>
+// CIR-SAME: %[[VTT_ARG:.*]]: !cir.ptr<!cir.ptr<!void>>
+// CIR-SAME: %[[INVOID_ARG:.*]]: !cir.ptr<!void>
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: %[[VTT_ADDR:.*]] = cir.alloca {{.*}} ["vtt", init]
+// CIR: %[[INVOID_ADDR:.*]] = cir.alloca {{.*}} ["inVoid", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: cir.store %[[VTT_ARG]], %[[VTT_ADDR]]
+// CIR: cir.store %[[INVOID_ARG]], %[[INVOID_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[VTT:.*]] = cir.load{{.*}} %[[VTT_ADDR]]
+// CIR: %[[VPTR_GLOBAL_ADDR:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 0 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[VPTR_PTR:.*]] = cir.cast(bitcast, %[[VPTR_GLOBAL_ADDR]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[VPTR]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_BASE_ADDR:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr<!cir.ptr<!void>>, offset = 1 -> !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[VPTR_BASE_PTR:.*]] = cir.cast(bitcast, %[[VPTR_BASE_ADDR]] : !cir.ptr<!cir.ptr<!void>>), !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_BASE:.*]] = cir.load{{.*}} %[[VPTR_BASE_PTR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[VPTR_DERIVED_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_DERIVED:.*]] = cir.load{{.*}} %[[VPTR_DERIVED_ADDR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[VPTR_DERIVED_AS_I8PTR:.*]] = cir.cast(bitcast, %[[VPTR_DERIVED]] : !cir.vptr), !cir.ptr<!u8i>
+// CIR: %[[BASE_LOC_OFFSET:.*]] = cir.const #cir.int<-32> : !s64i
+// CIR: %[[BASE_OFFSET_PTR:.*]] = cir.ptr_stride(%[[VPTR_DERIVED_AS_I8PTR]] : !cir.ptr<!u8i>, %[[BASE_LOC_OFFSET]] : !s64i), !cir.ptr<!u8i>
+// CIR: %[[BASE_OFFSET_I64PTR:.*]] = cir.cast(bitcast, %[[BASE_OFFSET_PTR]] : !cir.ptr<!u8i>), !cir.ptr<!s64i>
+// CIR: %[[BASE_OFFSET:.*]] = cir.load{{.*}} %[[BASE_OFFSET_I64PTR]] : !cir.ptr<!s64i>, !s64i
+// CIR: %[[THIS_AS_I8PTR:.*]] = cir.cast(bitcast, %[[THIS]] : !cir.ptr<!rec_Derived>), !cir.ptr<!u8i>
+// CIR: %[[BASE_PTR:.*]] = cir.ptr_stride(%[[THIS_AS_I8PTR]] : !cir.ptr<!u8i>, %[[BASE_OFFSET]] : !s64i), !cir.ptr<!u8i>
+// CIR: %[[BASE_AS_I8PTR:.*]] = cir.cast(bitcast, %[[BASE_PTR]] : !cir.ptr<!u8i>), !cir.ptr<!rec_Derived>
+// CIR: %[[BASE_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[BASE_AS_I8PTR]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: cir.store{{.*}} %[[VPTR_BASE]], %[[BASE_VPTR_ADDR]] : !cir.vptr, !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_BASE_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr<!rec_Derived> -> !cir.ptr<!cir.vptr>
+// CIR: %[[VPTR_BASE:.*]] = cir.load{{.*}} %[[VPTR_BASE_ADDR]] : !cir.ptr<!cir.vptr>, !cir.vptr
+// CIR: %[[SQUAWK_FN_ADDR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR_BASE]][0] : !cir.vptr -> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>>
+// CIR: %[[SQUAWK:.*]] = cir.load{{.*}} %[[SQUAWK_FN_ADDR]] : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>>, !cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>
+// CIR: cir.call %[[SQUAWK]](%[[THIS]]) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_Derived>)>>, !cir.ptr<!rec_Derived>) -> ()
+// CIR: cir.return
+
+// LLVM: define {{.*}} void @_ZN7DerivedC2EPKv(ptr %[[THIS_ARG:.*]], ptr %[[VTT_ARG:.*]], ptr %[[INVOID_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: %[[VTT_ADDR:.*]] = alloca ptr
+// LLVM: %[[INVOID_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// LLVM: store ptr %[[INVOID_ARG]], ptr %[[INVOID_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[VTT]]
+// LLVM: store ptr %[[VPTR]], ptr %[[THIS]]
+// LLVM: %[[VTT_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i32 1
+// LLVM: %[[VPTR_BASE:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// LLVM: %[[BASE_OFFSET_ADDR:.*]] = getelementptr i8, ptr %[[VPTR]], i64 -32
+// LLVM: %[[BASE_OFFSET:.*]] = load i64, ptr %[[BASE_OFFSET_ADDR]]
+// LLVM: %[[BASE_PTR:.*]] = getelementptr i8, ptr %[[THIS]], i64 %[[BASE_OFFSET]]
+// LLVM: store ptr %[[VPTR_BASE]], ptr %[[BASE_PTR]]
+// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// LLVM: %[[SQUAWK_FN_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i32 0
+// LLVM: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_FN_ADDR]]
+// LLVM: call void %[[SQUAWK]](ptr %[[THIS]])
+// LLVM: ret void
+
+// OGCG: define {{.*}} void @_ZN7DerivedC2EPKv(ptr {{.*}} %[[THIS_ARG:.*]], ptr {{.*}} %[[VTT_ARG:.*]], ptr {{.*}} %[[INVOID_ARG:.*]])
+// OGCG: %[[THIS_ADDR:.*]] = alloca ptr
+// OGCG: %[[VTT_ADDR:.*]] = alloca ptr
+// OGCG: %[[INVOID_ADDR:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// OGCG: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// OGCG: store ptr %[[INVOID_ARG]], ptr %[[INVOID_ADDR]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// OGCG: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[VTT]]
+// OGCG: store ptr %[[VPTR]], ptr %[[THIS]]
+// OGCG: %[[VTT_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VTT]], i64 1
+// OGCG: %[[VPTR_BASE:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// OGCG: %[[BASE_OFFSET_ADDR:.*]] = getelementptr i8, ptr %[[VPTR]], i64 -32
+// OGCG: %[[BASE_OFFSET:.*]] = load i64, ptr %[[BASE_OFFSET_ADDR]]
+// OGCG: %[[BASE_PTR:.*]] = getelementptr inbounds i8, ptr %[[THIS]], i64 %[[BASE_OFFSET]]
+// OGCG: store ptr %[[VPTR_BASE]], ptr %[[BASE_PTR]]
+// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[THIS]]
+// OGCG: %[[SQUAWK_FN_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i64 0
+// OGCG: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_FN_ADDR]]
+// OGCG: call void %[[SQUAWK]](ptr {{.*}} %[[THIS]])
+// OGCG: ret void
+
+// CIR: cir.func {{.*}} @_ZN7DerivedC2Ev(%[[THIS_ARG:.*]]: !cir.ptr<!rec_Derived> {{.*}}, %[[VTT_ARG:.*]]: !cir.ptr<!cir.ptr<!void>> {{.*}})
+// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init]
+// CIR: %[[VTT_ADDR:.*]] = cir.alloca {{.*}} ["vtt", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]]
+// CIR: cir.store %[[VTT_ARG]], %[[VTT_ADDR]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]]
+// CIR: %[[VTT:.*]] = cir.load {{.*}} %[[VTT_ADDR]]
+// CIR: %[[NULLPTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!void>
+// CIR: cir.call @_ZN7DerivedC2EPKv(%[[THIS]], %[[VTT]], %[[NULLPTR]]) : (!cir.ptr<!rec_Derived>, !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>) -> ()
+// CIR: cir.call @_Z5otherv() : () -> ()
+// CIR: cir.return
+
+// LLVM: define {{.*}} void @_ZN7DerivedC2Ev(ptr %[[THIS_ARG:.*]], ptr %[[VTT_ARG:.*]])
+// LLVM: %[[THIS_ADDR:.*]] = alloca ptr
+// LLVM: %[[VTT_ADDR:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]]
+// LLVM: store ptr %[[VTT_ARG]], ptr %[[VTT_ADDR]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]]
+// LLVM: %[[VTT:.*]] = load ptr, ptr %[[VTT_ADDR]]
+// LLVM: call void @_ZN7DerivedC2EPKv(ptr %[[THIS]], ptr %[[VTT]], ptr null)
+// LLVM: call void @_Z5otherv()
+// LLVM: ret void
+
+// See above for the OGCG _ZN7DerivedC2Ev constructor.
+
+// TODO: add the Derived C1 constructors and Base
----------------
mmha wrote:
Is this TODO still relevant? the C1 constructor of `Derived` is here and the complete `Base` ctor isn't used in this test.
https://github.com/llvm/llvm-project/pull/156970
More information about the cfe-commits
mailing list