Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CIR][CIRGen] Support pure and deleted virtual functions #823

Merged
merged 1 commit into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCXXABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
Expand Down
43 changes: 19 additions & 24 deletions clang/lib/CIR/CodeGen/CIRGenVTables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<llvm::Constant>(
// CGM.CreateRuntimeFunction(fnTy, name).getCallee());
// if (auto f = dyn_cast<llvm::Function>(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<CXXMethodDecl>(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<CXXMethodDecl>(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);
}
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/CIR/CodeGen/CIRGenVTables.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
16 changes: 16 additions & 0 deletions clang/test/CIR/CodeGen/special-virtual-func.cpp
Original file line number Diff line number Diff line change
@@ -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<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1A> : !cir.ptr<!u8i>, #cir.global_view<@__cxa_pure_virtual> : !cir.ptr<!u8i>, #cir.global_view<@__cxa_deleted_virtual> : !cir.ptr<!u8i>]>
// CHECK: cir.func private @__cxa_pure_virtual()
// CHECK: cir.func private @__cxa_deleted_virtual()