diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 11a256e7de10..402752d8204d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -1536,7 +1536,8 @@ mlir::Value CIRGenFunction::GetVTTParameter(GlobalDecl GD, bool ForVirtualBase, uint64_t SubVTTIndex; if (Delegating) { - llvm_unreachable("NYI"); + // If this is a delegating constructor call, just load the VTT. + return LoadCXXVTT(); } else if (RD == Base) { // If the record matches the base, this is the complete ctor/dtor // variant calling the base variant in a class with virtual bases. diff --git a/clang/test/CIR/CodeGen/delegating-ctor.cpp b/clang/test/CIR/CodeGen/delegating-ctor.cpp index 70fdabaaae75..7139c4252b1f 100644 --- a/clang/test/CIR/CodeGen/delegating-ctor.cpp +++ b/clang/test/CIR/CodeGen/delegating-ctor.cpp @@ -1,5 +1,9 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -fexceptions -fcxx-exceptions %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s struct Delegating { Delegating(); @@ -10,14 +14,14 @@ struct Delegating { // arguments. Delegating::Delegating() : Delegating(0) {} -// CHECK-LABEL: cir.func dso_local @_ZN10DelegatingC2Ev(%arg0: !cir.ptr {{.*}}) {{.*}} { -// CHECK-NEXT: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["this", init] {alignment = 8 : i64} -// CHECK-NEXT: cir.store{{.*}} %arg0, %0 : !cir.ptr, !cir.ptr> -// CHECK-NEXT: %1 = cir.load %0 : !cir.ptr>, !cir.ptr -// CHECK-NEXT: %2 = cir.const #cir.int<0> : !s32i -// CHECK-NEXT: cir.call @_ZN10DelegatingC2Ei(%1, %2) : (!cir.ptr, !s32i) -> () -// CHECK-NEXT: cir.return -// CHECK-NEXT: } +// CIR-LABEL: cir.func dso_local @_ZN10DelegatingC2Ev(%arg0: !cir.ptr {{.*}}) {{.*}} { +// CIR-NEXT: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["this", init] {alignment = 8 : i64} +// CIR-NEXT: cir.store{{.*}} %arg0, %0 : !cir.ptr, !cir.ptr> +// CIR-NEXT: %1 = cir.load %0 : !cir.ptr>, !cir.ptr +// CIR-NEXT: %2 = cir.const #cir.int<0> : !s32i +// CIR-NEXT: cir.call @_ZN10DelegatingC2Ei(%1, %2) : (!cir.ptr, !s32i) -> () +// CIR-NEXT: cir.return +// CIR-NEXT: } struct DelegatingWithZeroing { int i; @@ -30,18 +34,21 @@ struct DelegatingWithZeroing { // call to it in a lowering pass. DelegatingWithZeroing::DelegatingWithZeroing(int) : DelegatingWithZeroing() {} -// CHECK-LABEL: cir.func dso_local @_ZN21DelegatingWithZeroingC2Ei(%arg0: !cir.ptr {{.*}}, %arg1: !s32i {{.*}}) {{.*}} { -// CHECK-NEXT: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["this", init] {alignment = 8 : i64} -// CHECK-NEXT: %1 = cir.alloca !s32i, !cir.ptr, ["", init] {alignment = 4 : i64} -// CHECK-NEXT: cir.store{{.*}} %arg0, %0 : !cir.ptr, !cir.ptr> -// CHECK-NEXT: cir.store{{.*}} %arg1, %1 : !s32i, !cir.ptr -// CHECK-NEXT: %2 = cir.load %0 : !cir.ptr>, !cir.ptr -// CHECK-NEXT: %3 = cir.const #cir.zero : !rec_DelegatingWithZeroing -// CHECK-NEXT: cir.store{{.*}} %3, %2 : !rec_DelegatingWithZeroing, !cir.ptr -// CHECK-NEXT: cir.call @_ZN21DelegatingWithZeroingC2Ev(%2) : (!cir.ptr) -> () extra(#fn_attr{{[0-9]*}}) -// CHECK-NEXT: cir.return -// CHECK-NEXT: } +// CIR-LABEL: cir.func dso_local @_ZN21DelegatingWithZeroingC2Ei(%arg0: !cir.ptr {{.*}}, %arg1: !s32i {{.*}}) {{.*}} { +// CIR-NEXT: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["this", init] {alignment = 8 : i64} +// CIR-NEXT: %1 = cir.alloca !s32i, !cir.ptr, ["", init] {alignment = 4 : i64} +// CIR-NEXT: cir.store{{.*}} %arg0, %0 : !cir.ptr, !cir.ptr> +// CIR-NEXT: cir.store{{.*}} %arg1, %1 : !s32i, !cir.ptr +// CIR-NEXT: %2 = cir.load %0 : !cir.ptr>, !cir.ptr +// CIR-NEXT: %3 = cir.const #cir.zero : !rec_DelegatingWithZeroing +// CIR-NEXT: cir.store{{.*}} %3, %2 : !rec_DelegatingWithZeroing, !cir.ptr +// CIR-NEXT: cir.call @_ZN21DelegatingWithZeroingC2Ev(%2) : (!cir.ptr) -> () extra(#fn_attr{{[0-9]*}}) +// CIR-NEXT: cir.return +// CIR-NEXT: } +// Check that we call the destructor whenever a cleanup is needed. +// FIXME: enable and check this when exceptions are fully supported. +#if 0 void canThrow(); struct HasNonTrivialDestructor { HasNonTrivialDestructor(); @@ -49,9 +56,6 @@ struct HasNonTrivialDestructor { ~HasNonTrivialDestructor(); }; -// Check that we call the destructor whenever a cleanup is needed. -// FIXME: enable and check this when exceptions are fully supported. -#if 0 HasNonTrivialDestructor::HasNonTrivialDestructor(int) : HasNonTrivialDestructor() { canThrow(); @@ -60,29 +64,265 @@ HasNonTrivialDestructor::HasNonTrivialDestructor(int) // From clang/test/CodeGenCXX/cxx0x-delegating-ctors.cpp, check that virtual // inheritance and delegating constructors interact correctly. -// FIXME: enable and check this when virtual inheritance is fully supported. -#if 0 -namespace PR14588 { void other(); class Base { public: Base() { squawk(); } - virtual ~Base() {} - virtual void squawk() { other(); } + virtual void squawk(); }; -class Foo : public virtual Base { +class Derived : public virtual Base { public: - Foo(); - Foo(const void *inVoid); - virtual ~Foo() {} + Derived(); + Derived(const void *inVoid); - virtual void squawk() { other(); } + virtual void squawk(); }; -Foo::Foo() : Foo(nullptr) { other(); } -Foo::Foo(const void *inVoid) { squawk(); } -} // namespace PR14588 -#endif +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 +// CIR-SAME: %[[VTT_ARG:.*]]: !cir.ptr> +// CIR-SAME: %[[INVOID_ARG:.*]]: !cir.ptr +// 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>, offset = 0 -> !cir.ptr> +// CIR: %[[VPTR_PTR:.*]] = cir.cast(bitcast, %[[VPTR_GLOBAL_ADDR]] : !cir.ptr>), !cir.ptr +// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_PTR]] : !cir.ptr, !cir.vptr +// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr -> !cir.ptr +// CIR: cir.store{{.*}} %[[VPTR]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr +// CIR: %[[VPTR_BASE_ADDR:.*]] = cir.vtt.address_point %[[VTT]] : !cir.ptr>, offset = 1 -> !cir.ptr> +// CIR: %[[VPTR_BASE_PTR:.*]] = cir.cast(bitcast, %[[VPTR_BASE_ADDR]] : !cir.ptr>), !cir.ptr +// CIR: %[[VPTR_BASE:.*]] = cir.load{{.*}} %[[VPTR_BASE_PTR]] : !cir.ptr, !cir.vptr +// CIR: %[[VPTR_DERIVED_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr -> !cir.ptr +// CIR: %[[VPTR_DERIVED:.*]] = cir.load{{.*}} %[[VPTR_DERIVED_ADDR]] : !cir.ptr, !cir.vptr +// CIR: %[[VPTR_DERIVED_AS_I8PTR:.*]] = cir.cast(bitcast, %[[VPTR_DERIVED]] : !cir.vptr), !cir.ptr +// CIR: %[[BASE_LOC_OFFSET:.*]] = cir.const #cir.int<-32> : !s64i +// CIR: %[[BASE_OFFSET_PTR:.*]] = cir.ptr_stride(%[[VPTR_DERIVED_AS_I8PTR]] : !cir.ptr, %[[BASE_LOC_OFFSET]] : !s64i), !cir.ptr +// CIR: %[[BASE_OFFSET_I64PTR:.*]] = cir.cast(bitcast, %[[BASE_OFFSET_PTR]] : !cir.ptr), !cir.ptr +// CIR: %[[BASE_OFFSET:.*]] = cir.load{{.*}} %[[BASE_OFFSET_I64PTR]] : !cir.ptr, !s64i +// CIR: %[[THIS_AS_I8PTR:.*]] = cir.cast(bitcast, %[[THIS]] : !cir.ptr), !cir.ptr +// CIR: %[[BASE_PTR:.*]] = cir.ptr_stride(%[[THIS_AS_I8PTR]] : !cir.ptr, %[[BASE_OFFSET]] : !s64i), !cir.ptr +// CIR: %[[BASE_AS_I8PTR:.*]] = cir.cast(bitcast, %[[BASE_PTR]] : !cir.ptr), !cir.ptr +// CIR: %[[BASE_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[BASE_AS_I8PTR]] : !cir.ptr -> !cir.ptr +// CIR: cir.store{{.*}} %[[VPTR_BASE]], %[[BASE_VPTR_ADDR]] : !cir.vptr, !cir.ptr +// CIR: %[[VPTR_BASE_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr -> !cir.ptr +// CIR: %[[VPTR_BASE:.*]] = cir.load{{.*}} %[[VPTR_BASE_ADDR]] : !cir.ptr, !cir.vptr +// CIR: %[[SQUAWK_FN_ADDR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR_BASE]][0] : !cir.vptr -> !cir.ptr)>>> +// CIR: %[[SQUAWK:.*]] = cir.load{{.*}} %[[SQUAWK_FN_ADDR]] : !cir.ptr)>>>, !cir.ptr)>> +// CIR: cir.call %[[SQUAWK]](%[[THIS]]) : (!cir.ptr)>>, !cir.ptr) -> () +// 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 {{.*}}, %[[VTT_ARG:.*]]: !cir.ptr> {{.*}}) +// 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 : !cir.ptr +// CIR: cir.call @_ZN7DerivedC2EPKv(%[[THIS]], %[[VTT]], %[[NULLPTR]]) : (!cir.ptr, !cir.ptr>, !cir.ptr) -> () +// 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 + +// CIR: cir.func {{.*}} @_ZN4BaseC2Ev(%[[THIS_ARG:.*]]: !cir.ptr {{.*}}) +// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init] +// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]] +// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] +// CIR: %[[VTT_ADDR_POINT:.*]] = cir.vtable.address_point(@_ZTV4Base, address_point = ) : !cir.vptr +// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr -> !cir.ptr +// CIR: cir.store{{.*}} %[[VTT_ADDR_POINT]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr +// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr -> !cir.ptr +// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]] : !cir.ptr, !cir.vptr +// CIR: %[[VIRTUAL_FN_ADDR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR]][0] : !cir.vptr -> !cir.ptr)>>> +// CIR: %[[VIRTUAL_FN:.*]] = cir.load{{.*}} %[[VIRTUAL_FN_ADDR]] : !cir.ptr)>>>, !cir.ptr)>> +// CIR: cir.call %[[VIRTUAL_FN]](%[[THIS]]) : (!cir.ptr)>>, !cir.ptr) -> () +// CIR: cir.return + +// LLVM: define {{.*}} void @_ZN4BaseC2Ev(ptr %[[THIS_ARG:.*]]) +// LLVM: %[[THIS_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV4Base, i64 16), ptr %[[THIS]] +// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[THIS]] +// LLVM: %[[SQUAWK_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i32 0 +// LLVM: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_ADDR]] +// LLVM: call void %[[SQUAWK]](ptr %[[THIS]]) +// LLVM: ret void + +// The base constructor is emitted last for OGCG. +// The _ZN7DerivedC1Ev constructor is emitted earlier for OGCG. + +// OGCG: define {{.*}} void @_ZN7DerivedC1Ev(ptr {{.*}} %[[THIS_ARG:.*]]) +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// OGCG: call void @_ZN7DerivedC1EPKv(ptr {{.*}} %[[THIS]], ptr {{.*}} null) +// OGCG: call void @_Z5otherv() +// OGCG: ret void + +// CIR: cir.func {{.*}} @_ZN7DerivedC1EPKv(%[[THIS_ARG:.*]]: !cir.ptr {{.*}}, %[[INVOID_ARG:.*]]: !cir.ptr {{.*}}) +// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init] +// CIR: %[[INVOID_ADDR:.*]] = cir.alloca {{.*}} ["inVoid", init] +// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]] +// CIR: cir.store %[[INVOID_ARG]], %[[INVOID_ADDR]] +// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] +// CIR: %[[BASE:.*]] = cir.base_class_addr %[[THIS]] : !cir.ptr nonnull [0] -> !cir.ptr +// CIR: cir.call @_ZN4BaseC2Ev(%[[BASE]]) +// CIR: %[[VPTR_GLOBAL:.*]] = cir.vtable.address_point(@_ZTV7Derived, address_point = ) : !cir.vptr +// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr -> !cir.ptr +// CIR: cir.store{{.*}} %[[VPTR_GLOBAL]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr +// CIR: %[[VPTR_GLOBAL:.*]] = cir.vtable.address_point(@_ZTV7Derived, address_point = ) : !cir.vptr +// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr -> !cir.ptr +// CIR: cir.store{{.*}} %[[VPTR_GLOBAL]], %[[VPTR_ADDR]] : !cir.vptr, !cir.ptr +// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[THIS]] : !cir.ptr -> !cir.ptr +// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]] : !cir.ptr, !cir.vptr +// CIR: %[[SQUAWK_ADDR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR]][0] : !cir.vptr -> !cir.ptr)>>> +// CIR: %[[SQUAWK:.*]] = cir.load{{.*}} %[[SQUAWK_ADDR]] : !cir.ptr)>>>, !cir.ptr)>> +// CIR: cir.call %[[SQUAWK]](%[[THIS]]) +// CIR: cir.return + +// LLVM: define {{.*}} void @_ZN7DerivedC1EPKv(ptr %[[THIS_ARG:.*]], ptr %[[INVOID_ARG:.*]]) +// LLVM: %[[THIS_ADDR:.*]] = alloca ptr +// LLVM: %[[INVOID_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// LLVM: store ptr %[[INVOID_ARG]], ptr %[[INVOID_ADDR]] +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// LLVM: call void @_ZN4BaseC2Ev(ptr %[[THIS]]) +// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV7Derived, i64 32), ptr %[[THIS]] +// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV7Derived, i64 32), ptr %[[THIS]] +// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[THIS]] +// LLVM: %[[SQUAWK_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i32 0 +// LLVM: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_ADDR]] +// LLVM: call void %[[SQUAWK]](ptr %[[THIS]]) +// LLVM: ret void + +// OGCG: define {{.*}} void @_ZN7DerivedC1EPKv(ptr {{.*}} %[[THIS_ARG:.*]], ptr {{.*}} %[[INVOID_ARG:.*]]) +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr +// OGCG: %[[INVOID_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// OGCG: store ptr %[[INVOID_ARG]], ptr %[[INVOID_ADDR]] +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// OGCG: call void @_ZN4BaseC2Ev(ptr {{.*}} %[[THIS]]) +// OGCG: store ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV7Derived, i32 0, i32 0, i32 4), ptr %[[THIS]] +// OGCG: store ptr getelementptr inbounds inrange(-32, 8) ({ [5 x ptr] }, ptr @_ZTV7Derived, i32 0, i32 0, i32 4), ptr %[[THIS]] +// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[THIS]] +// OGCG: %[[SQUAWK_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i64 0 +// OGCG: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_ADDR]] +// OGCG: call void %[[SQUAWK]](ptr {{.*}} %[[THIS]]) +// OGCG: ret void + +// CIR: cir.func {{.*}} @_ZN7DerivedC1Ev(%[[THIS_ARG:.*]]: !cir.ptr {{.*}}) +// CIR: %[[THIS_ADDR:.*]] = cir.alloca {{.*}} ["this", init] +// CIR: cir.store %[[THIS_ARG]], %[[THIS_ADDR]] +// CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] +// CIR: %[[NULLPTR:.*]] = cir.const #cir.ptr : !cir.ptr +// CIR: cir.call @_ZN7DerivedC1EPKv(%[[THIS]], %[[NULLPTR]]) : (!cir.ptr, !cir.ptr) -> () +// CIR: cir.call @_Z5otherv() : () -> () +// CIR: cir.return + +// LLVM: define {{.*}} void @_ZN7DerivedC1Ev(ptr %[[THIS_ARG:.*]]) +// LLVM: %[[THIS_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// LLVM: call void @_ZN7DerivedC1EPKv(ptr %[[THIS]], ptr null) +// LLVM: call void @_Z5otherv() +// LLVM: ret void + +// The _ZN7DerivedC1Ev constructor was emitted earlier for OGCG. + +// OGCG: define {{.*}} void @_ZN4BaseC2Ev(ptr {{.*}} %[[THIS_ARG:.*]]) +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ADDR]] +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// OGCG: store ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTV4Base, i32 0, i32 0, i32 2), ptr %[[THIS]] +// OGCG: %[[VPTR:.*]] = load ptr, ptr %[[THIS]] +// OGCG: %[[SQUAWK_ADDR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i64 0 +// OGCG: %[[SQUAWK:.*]] = load ptr, ptr %[[SQUAWK_ADDR]] +// OGCG: call void %[[SQUAWK]](ptr {{.*}} %[[THIS]]) +// OGCG: ret void