diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp index e5fda5a6bb15..b15b7f3aaf2e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp @@ -736,12 +736,27 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, const CXXRecordDecl *VTableClass, CharUnits Offset) { const ASTRecordLayout &Layout = CGM.getASTContext().getASTRecordLayout(RD); - if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) { // Add a vtable pointer, if we need one and it hasn't already been added. - if (Layout.hasOwnVFPtr()) - llvm_unreachable("NYI"); - + if (Layout.hasOwnVFPtr()) { + CIRGenBuilderTy &builder = CGM.getBuilder(); + cir::GlobalOp vtable = + CGM.getCXXABI().getAddrOfVTable(VTableClass, CharUnits()); + clang::VTableLayout::AddressPointLocation addressPoint = + CGM.getItaniumVTableContext() + .getVTableLayout(VTableClass) + .getAddressPoint(BaseSubobject(CD, Offset)); + assert(!cir::MissingFeatures::ptrAuth()); + mlir::ArrayAttr indices = builder.getArrayAttr({ + builder.getI32IntegerAttr(0), + builder.getI32IntegerAttr(addressPoint.VTableIndex), + builder.getI32IntegerAttr(addressPoint.AddressPointIndex), + }); + cir::GlobalViewAttr vtableInit = + CGM.getBuilder().getGlobalViewAttr(vtable, indices); + if (!AppendBytes(Offset, vtableInit)) + return false; + } // Accumulate and sort bases, in order to visit them in address order, which // may not be the same as declaration order. SmallVector<BaseInfo, 8> Bases; diff --git a/clang/test/CIR/CodeGen/vtable-emission.cpp b/clang/test/CIR/CodeGen/vtable-emission.cpp index f63a9fe3cd97..6691167488c5 100644 --- a/clang/test/CIR/CodeGen/vtable-emission.cpp +++ b/clang/test/CIR/CodeGen/vtable-emission.cpp @@ -1,15 +1,29 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -o - %s \ +// RUN: | opt -S -passes=instcombine,mem2reg,simplifycfg -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s struct S { virtual void key(); virtual void nonKey() {} -}; +} sobj; void S::key() {} +// CHECK-DAG: !ty_anon_struct1 = !cir.struct<struct {!cir.array<!cir.ptr<!u8i> x 4>}> +// CHECK-DAG: !ty_anon_struct2 = !cir.struct<struct {!cir.ptr<!ty_anon_struct1>}> + // The definition of the key function should result in the vtable being emitted. // CHECK: cir.global external @_ZTV1S = #cir.vtable +// LLVM: @_ZTV1S = global { [4 x ptr] } { [4 x ptr] +// LLVM-SAME: [ptr null, ptr @_ZTI1S, ptr @_ZN1S3keyEv, ptr @_ZN1S6nonKeyEv] }, align 8 + +// CHECK: cir.global external @sobj = #cir.const_struct +// CHECK-SAME: <{#cir.global_view<@_ZTV1S, [0 : i32, 0 : i32, 2 : i32]> : +// CHECK-SAME: !cir.ptr<!ty_anon_struct1>}> : !ty_anon_struct2 {alignment = 8 : i64} +// LLVM: @sobj = global { ptr } { ptr getelementptr inbounds +// LLVM-SAME: ({ [4 x ptr] }, ptr @_ZTV1S, i32 0, i32 0, i32 2) }, align 8 // The reference from the vtable should result in nonKey being emitted. // CHECK: cir.func linkonce_odr @_ZN1S6nonKeyEv({{.*}} {