From c06467556a336eed37e16dd337042acdade4a945 Mon Sep 17 00:00:00 2001 From: Shoaib Meenai Date: Wed, 4 Sep 2024 17:18:11 -0700 Subject: [PATCH] [CIR][CIRGen] Support pure and deleted virtual functions This is a straightforward adaption of existing CodeGen logic. While I'm here, move block comments inside their blocks, so that they look nicer. --- clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 6 +++ clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 5 +++ clang/lib/CIR/CodeGen/CIRGenVTables.cpp | 43 ++++++++----------- clang/lib/CIR/CodeGen/CIRGenVTables.h | 9 ++-- .../test/CIR/CodeGen/special-virtual-func.cpp | 16 +++++++ 5 files changed, 51 insertions(+), 28 deletions(-) create mode 100644 clang/test/CIR/CodeGen/special-virtual-func.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index 2aea122f9759..6c67e849a4c4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -235,6 +235,12 @@ class CIRGenCXXABI { BaseSubobject Base, const CXXRecordDecl *NearestVBase) = 0; + /// Gets the pure virtual member call function. + virtual StringRef getPureVirtualCallName() = 0; + + /// Gets the deleted virtual member call name. + virtual StringRef getDeletedVirtualCallName() = 0; + /// Specify how one should pass an argument of a record type. enum class RecordArgABI { /// Pass it using the normal C aggregate rules for the ABI, potentially diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index ae4cb4eca2d6..5f50a264c1f4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -215,6 +215,11 @@ class CIRGenItaniumCXXABI : public cir::CIRGenCXXABI { return false; } + StringRef getPureVirtualCallName() override { return "__cxa_pure_virtual"; } + StringRef getDeletedVirtualCallName() override { + return "__cxa_deleted_virtual"; + } + /// TODO(cir): seems like could be shared between LLVM IR and CIR codegen. bool mayNeedDestruction(const VarDecl *VD) const { if (VD->needsDestruction(getContext())) diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp index b10a12d9e0da..3c2af8fbbfdf 100644 --- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp @@ -217,8 +217,7 @@ void CIRGenVTables::addVTableComponent(ConstantArrayBuilder &builder, llvm_unreachable("NYI"); } - [[maybe_unused]] auto getSpecialVirtualFn = - [&](StringRef name) -> mlir::Attribute { + auto getSpecialVirtualFn = [&](StringRef name) -> mlir::cir::FuncOp { // FIXME(PR43094): When merging comdat groups, lld can select a local // symbol as the signature symbol even though it cannot be accessed // outside that symbol's TU. The relative vtables ABI would make @@ -235,45 +234,41 @@ void CIRGenVTables::addVTableComponent(ConstantArrayBuilder &builder, CGM.getTriple().isNVPTX()) llvm_unreachable("NYI"); - llvm_unreachable("NYI"); - // llvm::FunctionType *fnTy = - // llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); - // llvm::Constant *fn = cast( - // CGM.CreateRuntimeFunction(fnTy, name).getCallee()); - // if (auto f = dyn_cast(fn)) - // f->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - // return llvm::ConstantExpr::getBitCast(fn, CGM.Int8PtrTy); + mlir::cir::FuncType fnTy = + CGM.getBuilder().getFuncType({}, CGM.getBuilder().getVoidTy()); + mlir::cir::FuncOp fnPtr = CGM.createRuntimeFunction(fnTy, name); + // LLVM codegen handles unnamedAddr + assert(!MissingFeatures::unnamedAddr()); + return fnPtr; }; mlir::cir::FuncOp fnPtr; - // Pure virtual member functions. if (cast(GD.getDecl())->isPureVirtual()) { - llvm_unreachable("NYI"); - // if (!PureVirtualFn) - // PureVirtualFn = - // getSpecialVirtualFn(CGM.getCXXABI().GetPureVirtualCallName()); - // fnPtr = PureVirtualFn; + // Pure virtual member functions. + if (!PureVirtualFn) + PureVirtualFn = + getSpecialVirtualFn(CGM.getCXXABI().getPureVirtualCallName()); + fnPtr = PureVirtualFn; - // Deleted virtual member functions. } else if (cast(GD.getDecl())->isDeleted()) { - llvm_unreachable("NYI"); - // if (!DeletedVirtualFn) - // DeletedVirtualFn = - // getSpecialVirtualFn(CGM.getCXXABI().GetDeletedVirtualCallName()); - // fnPtr = DeletedVirtualFn; + // Deleted virtual member functions. + if (!DeletedVirtualFn) + DeletedVirtualFn = + getSpecialVirtualFn(CGM.getCXXABI().getDeletedVirtualCallName()); + fnPtr = DeletedVirtualFn; - // Thunks. } else if (nextVTableThunkIndex < layout.vtable_thunks().size() && layout.vtable_thunks()[nextVTableThunkIndex].first == componentIndex) { + // Thunks. llvm_unreachable("NYI"); // auto &thunkInfo = layout.vtable_thunks()[nextVTableThunkIndex].second; // nextVTableThunkIndex++; // fnPtr = maybeEmitThunk(GD, thunkInfo, /*ForVTable=*/true); - // Otherwise we can use the method definition directly. } else { + // Otherwise we can use the method definition directly. auto fnTy = CGM.getTypes().GetFunctionTypeForVTable(GD); fnPtr = CGM.GetAddrOfFunction(GD, fnTy, /*ForVTable=*/true); } diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.h b/clang/lib/CIR/CodeGen/CIRGenVTables.h index e92f60394270..2def67ab1bc6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenVTables.h +++ b/clang/lib/CIR/CodeGen/CIRGenVTables.h @@ -19,6 +19,7 @@ #include "clang/AST/GlobalDecl.h" #include "clang/AST/VTableBuilder.h" #include "clang/Basic/ABI.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" #include "llvm/ADT/DenseMap.h" namespace clang { @@ -52,11 +53,11 @@ class CIRGenVTables { /// indices. SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices; - // /// Cache for the pure virtual member call function. - // llvm::Constant *PureVirtualFn = nullptr; + /// Cache for the pure virtual member call function. + mlir::cir::FuncOp PureVirtualFn = nullptr; - // /// Cache for the deleted virtual member call function. - // llvm::Constant *DeletedVirtualFn = nullptr; + /// Cache for the deleted virtual member call function. + mlir::cir::FuncOp DeletedVirtualFn = nullptr; // /// Get the address of a thunk and emit it if necessary. // llvm::Constant *maybeEmitThunk(GlobalDecl GD, diff --git a/clang/test/CIR/CodeGen/special-virtual-func.cpp b/clang/test/CIR/CodeGen/special-virtual-func.cpp new file mode 100644 index 000000000000..83e2a27b82f0 --- /dev/null +++ b/clang/test/CIR/CodeGen/special-virtual-func.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +// Check that pure and deleted virtual functions are correctly emitted in the +// vtable. +class A { + A(); + virtual void pure() = 0; + virtual void deleted() = delete; +}; + +A::A() = default; + +// CHECK: @_ZTV1A = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.global_view<@_ZTI1A> : !cir.ptr, #cir.global_view<@__cxa_pure_virtual> : !cir.ptr, #cir.global_view<@__cxa_deleted_virtual> : !cir.ptr]> +// CHECK: cir.func private @__cxa_pure_virtual() +// CHECK: cir.func private @__cxa_deleted_virtual()