From ba2b1d6a36b0163ddc2bb99d66018e94fe8a149f Mon Sep 17 00:00:00 2001 From: Andy Kaylor Date: Fri, 24 Oct 2025 16:54:26 -0700 Subject: [PATCH 1/2] [Clang][CodeGen][NFC] Refactor CGCXXABI classes for code sharing This refactors the CGCXXABI and ItaniumCXXABI classes in LLVM IR codegen and their CIR codegen counterparts so that common code can be shared between the two. This is a small first step towards better code sharing between LLVM IR codegen and CIR codegen. We should be able to expand this significantly as CIR codegen matures. Note that some other code can very nearly, but not quite be shared at this point. For example `AddedStructorArgs` and its uses are nearly identical between LLVM IR and CIR codegen, but the struct contains an `llvm::Value*` member in LLVM IR codegen where it conatins an `mlir::Value` member in CIR codegen. We will need additional refactoring to handle cases like that. --- .../clang/CodeGenShared/CXXABIShared.h | 99 +++++++++++++++ .../clang/CodeGenShared/ItaniumCXXABIShared.h | 118 ++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenCXX.cpp | 2 +- clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 52 ++------ clang/lib/CIR/CodeGen/CIRGenCall.cpp | 6 +- clang/lib/CIR/CodeGen/CIRGenClass.cpp | 10 +- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 2 +- clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 56 ++------- clang/lib/CodeGen/CGCXXABI.cpp | 4 - clang/lib/CodeGen/CGCXXABI.h | 59 +-------- clang/lib/CodeGen/ItaniumCXXABI.cpp | 90 ++----------- 11 files changed, 259 insertions(+), 239 deletions(-) create mode 100644 clang/include/clang/CodeGenShared/CXXABIShared.h create mode 100644 clang/include/clang/CodeGenShared/ItaniumCXXABIShared.h diff --git a/clang/include/clang/CodeGenShared/CXXABIShared.h b/clang/include/clang/CodeGenShared/CXXABIShared.h new file mode 100644 index 0000000000000..957aae749c53b --- /dev/null +++ b/clang/include/clang/CodeGenShared/CXXABIShared.h @@ -0,0 +1,99 @@ +//===----- CXXABIShared.h - Shared C++ ABI Base Class -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides a base class for C++ ABI functionality that can be shared +// between LLVM IR codegen and CIR codegen. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGENSHARED_CXXABISHARED_H +#define LLVM_CLANG_CODEGENSHARED_CXXABISHARED_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/GlobalDecl.h" +#include "clang/AST/Mangle.h" +#include "clang/Basic/ABI.h" + +namespace clang { +class ASTContext; + +/// Implements C++ ABI functionality that can be shared between LLVM IR codegen +/// and CIR codegen. +class CXXABIShared { +protected: + ASTContext &Context; + std::unique_ptr MangleCtx; + + CXXABIShared(ASTContext &Context) + : Context(Context), MangleCtx(Context.createMangleContext()) {} + +public: + virtual ~CXXABIShared() = default; + + /// Similar to AddedStructorArgs, but only notes the number of additional + /// arguments. + struct AddedStructorArgCounts { + unsigned Prefix = 0; + unsigned Suffix = 0; + AddedStructorArgCounts() = default; + AddedStructorArgCounts(unsigned P, unsigned S) : Prefix(P), Suffix(S) {} + static AddedStructorArgCounts prefix(unsigned N) { return {N, 0}; } + static AddedStructorArgCounts suffix(unsigned N) { return {0, N}; } + }; + + /// Get the AST context. + ASTContext &getContext() const { return Context; } + + /// Gets the mangle context. + MangleContext &getMangleContext() { return *MangleCtx; } + + /// Determine whether there's something special about the rules of + /// the ABI tell us that 'this' is a complete object within the + /// given function. Obvious common logic like being defined on a + /// final class will have been taken care of by the caller. + virtual bool isThisCompleteObject(GlobalDecl GD) const = 0; + + /// Returns true if the most-derived return value should be returned. + virtual bool hasMostDerivedReturn(GlobalDecl GD) const { return false; } + + /// Return whether the given global decl needs a VTT parameter. + virtual bool NeedsVTTParameter(GlobalDecl GD) const { return false; } + + /// Returns true if the given constructor or destructor is one of the + /// kinds that the ABI says returns 'this' (only applies when called + /// non-virtually for destructors). + /// + /// There currently is no way to indicate if a destructor returns 'this' + /// when called virtually, and code generation does not support the case. + /// Returns true if the given constructor or destructor is one of the + /// kinds that the ABI says returns 'this' (only applies when called + /// non-virtually for destructors). + /// + /// There currently is no way to indicate if a destructor returns 'this' + /// when called virtually, and code generation does not support the case. + virtual bool HasThisReturn(GlobalDecl GD) const { + if (isa(GD.getDecl()) || + (isa(GD.getDecl()) && + GD.getDtorType() != Dtor_Deleting)) + return constructorsAndDestructorsReturnThis(); + return false; + } + + /// Returns true if the given destructor type should be emitted as a linkonce + /// delegating thunk, regardless of whether the dtor is defined in this TU or + /// not. + virtual bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor, + CXXDtorType DT) const = 0; + +protected: + virtual bool constructorsAndDestructorsReturnThis() const = 0; +}; + +} // namespace clang + +#endif // LLVM_CLANG_CODEGENSHARED_CXXABISHARED_H diff --git a/clang/include/clang/CodeGenShared/ItaniumCXXABIShared.h b/clang/include/clang/CodeGenShared/ItaniumCXXABIShared.h new file mode 100644 index 0000000000000..e1f1d1242aea3 --- /dev/null +++ b/clang/include/clang/CodeGenShared/ItaniumCXXABIShared.h @@ -0,0 +1,118 @@ +//===--- ItaniumCXXABIShared.h - Itanium C++ ABI Shared Base ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides a base class for Itanium C++ ABI implementations that can +// be shared between LLVM IR codegen and CIR codegen. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGENSHARED_ITANIUMCXXABISHARED_H +#define LLVM_CLANG_CODEGENSHARED_ITANIUMCXXABISHARED_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/GlobalDecl.h" +#include "clang/Basic/ABI.h" +#include + +namespace clang { + +template class ItaniumCXXABIShared : public BaseT { +protected: + /// Constructor forwarding to the base ABI class. + template + ItaniumCXXABIShared(Args &&...args) : BaseT(std::forward(args)...) {} + +public: + /// Determine whether there's something special about the rules of + /// the ABI tell us that 'this' is a complete object within the + /// given function. Obvious common logic like being defined on a + /// final class will have been taken care of by the caller. + bool isThisCompleteObject(GlobalDecl GD) const override { + // The Itanium ABI has separate complete-object vs. base-object + // variants of both constructors and destructors. + if (isa(GD.getDecl())) { + switch (GD.getDtorType()) { + case Dtor_Complete: + case Dtor_Deleting: + return true; + + case Dtor_Base: + return false; + + case Dtor_Comdat: + llvm_unreachable("emitting dtor comdat as function?"); + case Dtor_Unified: + llvm_unreachable("emitting unified dtor as function?"); + } + llvm_unreachable("bad dtor kind"); + } + if (isa(GD.getDecl())) { + switch (GD.getCtorType()) { + case Ctor_Complete: + return true; + + case Ctor_Base: + return false; + + case Ctor_CopyingClosure: + case Ctor_DefaultClosure: + llvm_unreachable("closure ctors in Itanium ABI?"); + + case Ctor_Comdat: + llvm_unreachable("emitting ctor comdat as function?"); + + case Ctor_Unified: + llvm_unreachable("emitting unified ctor as function?"); + } + llvm_unreachable("bad ctor kind"); + } + + // No other kinds. + return false; + } + + bool NeedsVTTParameter(GlobalDecl GD) const override { + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // We don't have any virtual bases, just return early. + if (!MD->getParent()->getNumVBases()) + return false; + + // Check if we have a base constructor. + if (isa(MD) && GD.getCtorType() == Ctor_Base) + return true; + + // Check if we have a base destructor. + if (isa(MD) && GD.getDtorType() == Dtor_Base) + return true; + + return false; + } + + /// Returns true if the given destructor type should be emitted as a linkonce + /// delegating thunk, regardless of whether the dtor is defined in this TU or + /// not. + /// + /// Itanium does not emit any destructor variant as an inline thunk. + /// Delegating may occur as an optimization, but all variants are either + /// emitted with external linkage or as linkonce if they are inline and used. + bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor, + CXXDtorType DT) const override { + return false; + } + + /// Returns true if this ABI initializes vptrs in constructors/destructors. + /// For Itanium, this is always true. + bool doStructorsInitializeVPtrs(const CXXRecordDecl *VTableClass) override { + return true; + } +}; + +} // namespace clang + +#endif // LLVM_CLANG_CODEGENSHARED_ITANIUMCXXABISHARED_H diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp index a3e20817d2ca4..2fd6980499edd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp @@ -116,7 +116,7 @@ static void emitDeclDestroy(CIRGenFunction &cgf, const VarDecl *vd, // mismatch. const CXXRecordDecl *record = type->getAsCXXRecordDecl(); bool canRegisterDestructor = - record && (!cgm.getCXXABI().hasThisReturn( + record && (!cgm.getCXXABI().HasThisReturn( GlobalDecl(record->getDestructor(), Dtor_Complete)) || cgm.getCXXABI().canCallMismatchedFunctionType()); diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index 13dc9f305945a..f292ced83259f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -19,23 +19,25 @@ #include "CIRGenFunction.h" #include "CIRGenModule.h" -#include "clang/AST/Mangle.h" +#include "clang/CodeGenShared/CXXABIShared.h" namespace clang::CIRGen { /// Implements C++ ABI-specific code generation functions. -class CIRGenCXXABI { +class CIRGenCXXABI : public CXXABIShared { protected: CIRGenModule &cgm; - std::unique_ptr mangleContext; + + CIRGenCXXABI(CIRGenModule &cgm) + : CXXABIShared(cgm.getASTContext()), cgm(cgm) {} virtual bool requiresArrayCookie(const CXXNewExpr *e); + bool constructorsAndDestructorsReturnThis() const override { + return cgm.getCodeGenOpts().CtorDtorReturnThis; + } + public: - // TODO(cir): make this protected when target-specific CIRGenCXXABIs are - // implemented. - CIRGenCXXABI(CIRGenModule &cgm) - : cgm(cgm), mangleContext(cgm.getASTContext().createMangleContext()) {} virtual ~CIRGenCXXABI(); void setCXXABIThisValue(CIRGenFunction &cgf, mlir::Value thisPtr); @@ -62,17 +64,6 @@ class CIRGenCXXABI { bool isRefCast, Address src) = 0; public: - /// Similar to AddedStructorArgs, but only notes the number of additional - /// arguments. - struct AddedStructorArgCounts { - unsigned prefix = 0; - unsigned suffix = 0; - AddedStructorArgCounts() = default; - AddedStructorArgCounts(unsigned p, unsigned s) : prefix(p), suffix(s) {} - static AddedStructorArgCounts withPrefix(unsigned n) { return {n, 0}; } - static AddedStructorArgCounts withSuffix(unsigned n) { return {0, n}; } - }; - /// Additional implicit arguments to add to the beginning (Prefix) and end /// (Suffix) of a constructor / destructor arg list. /// @@ -138,10 +129,6 @@ class CIRGenCXXABI { return md->getParent(); } - /// Return whether the given global decl needs a VTT (virtual table table) - /// parameter. - virtual bool needsVTTParameter(clang::GlobalDecl gd) { return false; } - /// Perform ABI-specific "this" argument adjustment required prior to /// a call of a virtual function. /// The "VirtualCall" argument is true iff the call itself is virtual. @@ -214,12 +201,6 @@ class CIRGenCXXABI { /// this emits virtual table tables. virtual void emitVirtualInheritanceTables(const CXXRecordDecl *rd) = 0; - /// Returns true if the given destructor type should be emitted as a linkonce - /// delegating thunk, regardless of whether the dtor is defined in this TU or - /// not. - virtual bool useThunkForDtorVariant(const CXXDestructorDecl *dtor, - CXXDtorType dt) const = 0; - virtual cir::GlobalLinkageKind getCXXDestructorLinkage(GVALinkage linkage, const CXXDestructorDecl *dtor, CXXDtorType dt) const; @@ -262,18 +243,6 @@ class CIRGenCXXABI { virtual bool doStructorsInitializeVPtrs(const clang::CXXRecordDecl *vtableClass) = 0; - /// Returns true if the given constructor or destructor is one of the kinds - /// that the ABI says returns 'this' (only applies when called non-virtually - /// for destructors). - /// - /// There currently is no way to indicate if a destructor returns 'this' when - /// called virtually, and CIR generation does not support this case. - virtual bool hasThisReturn(clang::GlobalDecl gd) const { return false; } - - virtual bool hasMostDerivedReturn(clang::GlobalDecl gd) const { - return false; - } - /// Returns true if the target allows calling a function through a pointer /// with a different signature than the actual function (or equivalently, /// bitcasting a function or function pointer to a different function type). @@ -284,9 +253,6 @@ class CIRGenCXXABI { /// for all calls. virtual bool canCallMismatchedFunctionType() const { return true; } - /// Gets the mangle context. - clang::MangleContext &getMangleContext() { return *mangleContext; } - clang::ImplicitParamDecl *&getStructorImplicitParamDecl(CIRGenFunction &cgf) { return cgf.cxxStructorImplicitParamDecl; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 88aef89ddd2b9..f4fb20bc3368c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -206,12 +206,12 @@ CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) { (passParams && md->isVariadic() ? RequiredArgs(argTypes.size()) : RequiredArgs::All); - CanQualType resultType = theCXXABI.hasThisReturn(gd) ? argTypes.front() + CanQualType resultType = theCXXABI.HasThisReturn(gd) ? argTypes.front() : theCXXABI.hasMostDerivedReturn(gd) ? astContext.VoidPtrTy : astContext.VoidTy; - assert(!theCXXABI.hasThisReturn(gd) && + assert(!theCXXABI.HasThisReturn(gd) && "Please send PR with a test and remove this"); assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo()); @@ -350,7 +350,7 @@ const CIRGenFunctionInfo &CIRGenTypes::arrangeCXXConstructorCall( : RequiredArgs::All; GlobalDecl gd(d, ctorKind); - if (theCXXABI.hasThisReturn(gd)) + if (theCXXABI.HasThisReturn(gd)) cgm.errorNYI(d->getSourceRange(), "arrangeCXXConstructorCall: hasThisReturn"); if (theCXXABI.hasMostDerivedReturn(gd)) diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 5046e0945002f..067e6d29ef526 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -759,7 +759,7 @@ void CIRGenFunction::emitDelegateCXXConstructorCall( // FIXME: The location of the VTT parameter in the parameter list is specific // to the Itanium ABI and shouldn't be hardcoded here. - if (cgm.getCXXABI().needsVTTParameter(curGD)) { + if (cgm.getCXXABI().NeedsVTTParameter(curGD)) { cgm.errorNYI(loc, "emitDelegateCXXConstructorCall: VTT parameter"); return; } @@ -1068,7 +1068,7 @@ void CIRGenFunction::emitCXXDestructorCall(const CXXDestructorDecl *dd, mlir::Value CIRGenFunction::getVTTParameter(GlobalDecl gd, bool forVirtualBase, bool delegating) { - if (!cgm.getCXXABI().needsVTTParameter(gd)) + if (!cgm.getCXXABI().NeedsVTTParameter(gd)) return nullptr; const CXXRecordDecl *rd = cast(curCodeDecl)->getParent(); @@ -1082,7 +1082,7 @@ mlir::Value CIRGenFunction::getVTTParameter(GlobalDecl gd, bool forVirtualBase, } 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. - assert(!cgm.getCXXABI().needsVTTParameter(curGD) && + assert(!cgm.getCXXABI().NeedsVTTParameter(curGD) && "doing no-op VTT offset in base dtor/ctor?"); assert(!forVirtualBase && "Can't have same class as virtual base!"); subVTTIndex = 0; @@ -1097,7 +1097,7 @@ mlir::Value CIRGenFunction::getVTTParameter(GlobalDecl gd, bool forVirtualBase, } mlir::Location loc = cgm.getLoc(rd->getBeginLoc()); - if (cgm.getCXXABI().needsVTTParameter(curGD)) { + if (cgm.getCXXABI().NeedsVTTParameter(curGD)) { // A VTT parameter was passed to the constructor, use it. mlir::Value vtt = loadCXXVTT(); return builder.createVTTAddrPoint(loc, vtt.getType(), vtt, subVTTIndex); @@ -1266,7 +1266,7 @@ void CIRGenFunction::emitCXXConstructorCall( // Emit the call. auto calleePtr = cgm.getAddrOfCXXStructor(GlobalDecl(d, type)); const CIRGenFunctionInfo &info = cgm.getTypes().arrangeCXXConstructorCall( - args, d, type, extraArgs.prefix, extraArgs.suffix, passPrototypeArgs); + args, d, type, extraArgs.Prefix, extraArgs.Suffix, passPrototypeArgs); CIRGenCallee callee = CIRGenCallee::forDirect(calleePtr, GlobalDecl(d, type)); cir::CIRCallOpInterface c; emitCall(info, callee, ReturnValueSlot(), args, &c, getLoc(loc)); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 58feb36f78f23..d1affce25e429 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -833,7 +833,7 @@ clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd, const auto *md = dyn_cast(fd); if (md && md->isInstance()) { - if (cgm.getCXXABI().hasThisReturn(gd)) + if (cgm.getCXXABI().HasThisReturn(gd)) cgm.errorNYI(fd->getSourceRange(), "this return"); else if (cgm.getCXXABI().hasMostDerivedReturn(gd)) cgm.errorNYI(fd->getSourceRange(), "most derived return"); diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index 88fedf1acc6a1..7c0732e85b0ac 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -24,6 +24,7 @@ #include "clang/AST/GlobalDecl.h" #include "clang/AST/VTableBuilder.h" #include "clang/CIR/MissingFeatures.h" +#include "clang/CodeGenShared/ItaniumCXXABIShared.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -31,13 +32,14 @@ using namespace clang::CIRGen; namespace { -class CIRGenItaniumCXXABI : public CIRGenCXXABI { +class CIRGenItaniumCXXABI : public ItaniumCXXABIShared { protected: /// All the vtables which have been defined. llvm::DenseMap vtables; public: - CIRGenItaniumCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) { + CIRGenItaniumCXXABI(CIRGenModule &cgm) + : ItaniumCXXABIShared(cgm) { assert(!cir::MissingFeatures::cxxabiUseARMMethodPtrABI()); assert(!cir::MissingFeatures::cxxabiUseARMGuardVarABI()); } @@ -48,8 +50,6 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { bool forVirtualBase, bool delegating) override; - bool needsVTTParameter(clang::GlobalDecl gd) override; - AddedStructorArgCounts buildStructorSignature(GlobalDecl gd, llvm::SmallVectorImpl &argTys) override; @@ -81,13 +81,6 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override; void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override; - bool useThunkForDtorVariant(const CXXDestructorDecl *dtor, - CXXDtorType dt) const override { - // Itanium does not emit any destructor variant as an inline thunk. - // Delegating may occur as an optimization, but all variants are either - // emitted with external linkage or as linkonce if they are inline and used. - return false; - } bool isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf, CIRGenFunction::VPtr vptr) override; @@ -119,10 +112,6 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc, QualType ty) override; - bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override { - return true; - } - void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) override; mlir::Value @@ -205,9 +194,9 @@ void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc, /// 1) getThisValue is currently protected /// 2) in theory, an ABI could implement 'this' returns some other way; /// HasThisReturn only specifies a contract, not the implementation - if (hasThisReturn(cgf.curGD)) { + if (HasThisReturn(cgf.curGD)) { cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(), - "emitInstanceFunctionProlog: hasThisReturn"); + "emitInstanceFunctionProlog: HasThisReturn"); } } @@ -227,7 +216,7 @@ CIRGenItaniumCXXABI::buildStructorSignature( argTys.insert(argTys.begin() + 1, astContext.getPointerType( CanQualType::CreateUnsafe(astContext.VoidPtrTy))); - return AddedStructorArgCounts::withPrefix(1); + return AddedStructorArgCounts::prefix(1); } return AddedStructorArgCounts{}; @@ -334,7 +323,7 @@ void CIRGenItaniumCXXABI::addImplicitStructorParams(CIRGenFunction &cgf, assert(isa(md) || isa(md)); // Check if we need a VTT parameter as well. - if (needsVTTParameter(cgf.curGD)) { + if (NeedsVTTParameter(cgf.curGD)) { ASTContext &astContext = cgm.getASTContext(); // FIXME: avoid the fake decl @@ -383,7 +372,7 @@ void CIRGenItaniumCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) { CIRGenCXXABI::AddedStructorArgs CIRGenItaniumCXXABI::getImplicitConstructorArgs( CIRGenFunction &cgf, const CXXConstructorDecl *d, CXXCtorType type, bool forVirtualBase, bool delegating) { - if (!needsVTTParameter(GlobalDecl(d, type))) + if (!NeedsVTTParameter(GlobalDecl(d, type))) return AddedStructorArgs{}; // Insert the implicit 'vtt' argument as the second argument. Make sure to @@ -397,27 +386,6 @@ CIRGenCXXABI::AddedStructorArgs CIRGenItaniumCXXABI::getImplicitConstructorArgs( return AddedStructorArgs::withPrefix({{vtt, vttTy}}); } -/// Return whether the given global decl needs a VTT (virtual table table) -/// parameter, which it does if it's a base constructor or destructor with -/// virtual bases. -bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) { - auto *md = cast(gd.getDecl()); - - // We don't have any virtual bases, just return early. - if (!md->getParent()->getNumVBases()) - return false; - - // Check if we have a base constructor. - if (isa(md) && gd.getCtorType() == Ctor_Base) - return true; - - // Check if we have a base destructor. - if (isa(md) && gd.getDtorType() == Dtor_Base) - return true; - - return false; -} - void CIRGenItaniumCXXABI::emitVTableDefinitions(CIRGenVTables &cgvt, const CXXRecordDecl *rd) { cir::GlobalOp vtable = getAddrOfVTable(rd, CharUnits()); @@ -1781,7 +1749,7 @@ mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructorWithVTT( CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base, const CXXRecordDecl *nearestVBase) { assert((base.getBase()->getNumVBases() || nearestVBase != nullptr) && - needsVTTParameter(cgf.curGD) && "This class doesn't have VTT"); + NeedsVTTParameter(cgf.curGD) && "This class doesn't have VTT"); // Get the secondary vpointer index. uint64_t virtualPointerIndex = @@ -1827,7 +1795,7 @@ mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructor( clang::BaseSubobject base, const clang::CXXRecordDecl *nearestVBase) { if ((base.getBase()->getNumVBases() || nearestVBase != nullptr) && - needsVTTParameter(cgf.curGD)) { + NeedsVTTParameter(cgf.curGD)) { return getVTableAddressPointInStructorWithVTT(cgf, vtableClass, base, nearestVBase); } @@ -1838,7 +1806,7 @@ bool CIRGenItaniumCXXABI::isVirtualOffsetNeededForVTableField( CIRGenFunction &cgf, CIRGenFunction::VPtr vptr) { if (vptr.nearestVBase == nullptr) return false; - return needsVTTParameter(cgf.curGD); + return NeedsVTTParameter(cgf.curGD); } mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset( diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp index 30e5dc2b6cbd9..edc49a48a5c8a 100644 --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -319,10 +319,6 @@ llvm::GlobalValue::LinkageTypes CGCXXABI::getCXXDestructorLinkage( return CGM.getLLVMLinkageForDeclarator(Dtor, Linkage); } -bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) { - return false; -} - llvm::CallInst * CGCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF, llvm::Value *Exn) { diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 2dd320dbda976..394fdbc270413 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -17,6 +17,7 @@ #include "CodeGenFunction.h" #include "clang/Basic/LLVM.h" #include "clang/CodeGen/CodeGenABITypes.h" +#include "clang/CodeGenShared/CXXABIShared.h" namespace llvm { class Constant; @@ -31,7 +32,6 @@ class CXXConstructorDecl; class CXXDestructorDecl; class CXXMethodDecl; class CXXRecordDecl; -class MangleContext; namespace CodeGen { class CGCallee; @@ -40,15 +40,13 @@ class CodeGenModule; struct CatchTypeInfo; /// Implements C++ ABI-specific code generation functions. -class CGCXXABI { +class CGCXXABI : public CXXABIShared { friend class CodeGenModule; protected: CodeGenModule &CGM; - std::unique_ptr MangleCtx; - CGCXXABI(CodeGenModule &CGM) - : CGM(CGM), MangleCtx(CGM.getContext().createMangleContext()) {} + CGCXXABI(CodeGenModule &CGM) : CXXABIShared(CGM.getContext()), CGM(CGM) {} protected: ImplicitParamDecl *getThisDecl(CodeGenFunction &CGF) { @@ -78,8 +76,6 @@ class CGCXXABI { void setCXXABIThisValue(CodeGenFunction &CGF, llvm::Value *ThisPtr); - ASTContext &getContext() const { return CGM.getContext(); } - bool mayNeedDestruction(const VarDecl *VD) const; /// Determine whether we will definitely emit this variable with a constant @@ -95,13 +91,7 @@ class CGCXXABI { virtual bool requiresArrayCookie(const CXXDeleteExpr *E, QualType eltType); virtual bool requiresArrayCookie(const CXXNewExpr *E); - /// Determine whether there's something special about the rules of - /// the ABI tell us that 'this' is a complete object within the - /// given function. Obvious common logic like being defined on a - /// final class will have been taken care of by the caller. - virtual bool isThisCompleteObject(GlobalDecl GD) const = 0; - - virtual bool constructorsAndDestructorsReturnThis() const { + bool constructorsAndDestructorsReturnThis() const override { return CGM.getCodeGenOpts().CtorDtorReturnThis; } @@ -109,27 +99,6 @@ class CGCXXABI { virtual ~CGCXXABI(); - /// Gets the mangle context. - MangleContext &getMangleContext() { - return *MangleCtx; - } - - /// Returns true if the given constructor or destructor is one of the - /// kinds that the ABI says returns 'this' (only applies when called - /// non-virtually for destructors). - /// - /// There currently is no way to indicate if a destructor returns 'this' - /// when called virtually, and code generation does not support the case. - virtual bool HasThisReturn(GlobalDecl GD) const { - if (isa(GD.getDecl()) || - (isa(GD.getDecl()) && - GD.getDtorType() != Dtor_Deleting)) - return constructorsAndDestructorsReturnThis(); - return false; - } - - virtual bool hasMostDerivedReturn(GlobalDecl GD) const { return false; } - virtual bool useSinitAndSterm() const { return false; } /// Returns true if the target allows calling a function through a pointer @@ -353,17 +322,6 @@ class CGCXXABI { } }; - /// Similar to AddedStructorArgs, but only notes the number of additional - /// arguments. - struct AddedStructorArgCounts { - unsigned Prefix = 0; - unsigned Suffix = 0; - AddedStructorArgCounts() = default; - AddedStructorArgCounts(unsigned P, unsigned S) : Prefix(P), Suffix(S) {} - static AddedStructorArgCounts prefix(unsigned N) { return {N, 0}; } - static AddedStructorArgCounts suffix(unsigned N) { return {0, N}; } - }; - /// Build the signature of the given constructor or destructor variant by /// adding any required parameters. For convenience, ArgTys has been /// initialized with the type of 'this'. @@ -371,12 +329,6 @@ class CGCXXABI { buildStructorSignature(GlobalDecl GD, SmallVectorImpl &ArgTys) = 0; - /// Returns true if the given destructor type should be emitted as a linkonce - /// delegating thunk, regardless of whether the dtor is defined in this TU or - /// not. - virtual bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor, - CXXDtorType DT) const = 0; - virtual void setCXXDestructorDLLStorage(llvm::GlobalValue *GV, const CXXDestructorDecl *Dtor, CXXDtorType DT) const; @@ -583,9 +535,6 @@ class CGCXXABI { QualType ElementType, llvm::Value *&NumElements, llvm::Value *&AllocPtr, CharUnits &CookieSize); - /// Return whether the given global decl needs a VTT parameter. - virtual bool NeedsVTTParameter(GlobalDecl GD); - protected: /// Returns the extra size required in order to store the array /// cookie for the given type. Assumes that an array cookie is diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 65c47633bc5c4..1bbbd9384a7fd 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -30,6 +30,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/Type.h" #include "clang/CodeGen/ConstantInitBuilder.h" +#include "clang/CodeGenShared/ItaniumCXXABIShared.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Instructions.h" @@ -43,7 +44,7 @@ using namespace clang; using namespace CodeGen; namespace { -class ItaniumCXXABI : public CodeGen::CGCXXABI { +class ItaniumCXXABI : public ItaniumCXXABIShared { /// VTables - All the vtables which have been defined. llvm::DenseMap VTables; @@ -61,12 +62,11 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { } public: - ItaniumCXXABI(CodeGen::CodeGenModule &CGM, - bool UseARMMethodPtrABI = false, - bool UseARMGuardVarABI = false) : - CGCXXABI(CGM), UseARMMethodPtrABI(UseARMMethodPtrABI), - UseARMGuardVarABI(UseARMGuardVarABI), - Use32BitVTableOffsetABI(false) { } + ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool UseARMMethodPtrABI = false, + bool UseARMGuardVarABI = false) + : ItaniumCXXABIShared(CGM), + UseARMMethodPtrABI(UseARMMethodPtrABI), + UseARMGuardVarABI(UseARMGuardVarABI), Use32BitVTableOffsetABI(false) {} bool classifyReturnType(CGFunctionInfo &FI) const override; @@ -77,50 +77,6 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { return RAA_Default; } - bool isThisCompleteObject(GlobalDecl GD) const override { - // The Itanium ABI has separate complete-object vs. base-object - // variants of both constructors and destructors. - if (isa(GD.getDecl())) { - switch (GD.getDtorType()) { - case Dtor_Complete: - case Dtor_Deleting: - return true; - - case Dtor_Base: - return false; - - case Dtor_Comdat: - llvm_unreachable("emitting dtor comdat as function?"); - case Dtor_Unified: - llvm_unreachable("emitting unified dtor as function?"); - } - llvm_unreachable("bad dtor kind"); - } - if (isa(GD.getDecl())) { - switch (GD.getCtorType()) { - case Ctor_Complete: - return true; - - case Ctor_Base: - return false; - - case Ctor_CopyingClosure: - case Ctor_DefaultClosure: - llvm_unreachable("closure ctors in Itanium ABI?"); - - case Ctor_Comdat: - llvm_unreachable("emitting ctor comdat as function?"); - - case Ctor_Unified: - llvm_unreachable("emitting unified ctor as function?"); - } - llvm_unreachable("bad dtor kind"); - } - - // No other kinds. - return false; - } - bool isZeroInitializable(const MemberPointerType *MPT) override; llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override; @@ -263,13 +219,6 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { buildStructorSignature(GlobalDecl GD, SmallVectorImpl &ArgTys) override; - bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor, - CXXDtorType DT) const override { - // Itanium does not emit any destructor variant as an inline thunk. - // Delegating may occur as an optimization, but all variants are either - // emitted with external linkage or as linkonce if they are inline and used. - return false; - } void EmitCXXDestructors(const CXXDestructorDecl *D) override; @@ -301,9 +250,6 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { bool isVirtualOffsetNeededForVTableField(CodeGenFunction &CGF, CodeGenFunction::VPtr Vptr) override; - bool doStructorsInitializeVPtrs(const CXXRecordDecl *VTableClass) override { - return true; - } llvm::Constant * getVTableAddressPoint(BaseSubobject Base, @@ -396,8 +342,6 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD, QualType LValType) override; - bool NeedsVTTParameter(GlobalDecl GD) override; - llvm::Constant * getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD); @@ -3407,26 +3351,6 @@ LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, return LV; } -/// Return whether the given global decl needs a VTT parameter, which it does -/// if it's a base constructor or destructor with virtual bases. -bool ItaniumCXXABI::NeedsVTTParameter(GlobalDecl GD) { - const CXXMethodDecl *MD = cast(GD.getDecl()); - - // We don't have any virtual bases, just return early. - if (!MD->getParent()->getNumVBases()) - return false; - - // Check if we have a base constructor. - if (isa(MD) && GD.getCtorType() == Ctor_Base) - return true; - - // Check if we have a base destructor. - if (isa(MD) && GD.getDtorType() == Dtor_Base) - return true; - - return false; -} - llvm::Constant * ItaniumCXXABI::getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD) { SmallString<256> MethodName; From ba1637a62434e04ebeb3d382107f71f4eeaec487 Mon Sep 17 00:00:00 2001 From: Andy Kaylor Date: Sun, 26 Oct 2025 20:11:52 -0700 Subject: [PATCH 2/2] Fix formatting --- clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 1 - clang/lib/CodeGen/ItaniumCXXABI.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index 7c0732e85b0ac..5f0905daf1e1e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -81,7 +81,6 @@ class CIRGenItaniumCXXABI : public ItaniumCXXABIShared { void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override; void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override; - bool isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf, CIRGenFunction::VPtr vptr) override; diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 1bbbd9384a7fd..ada8d06c86097 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -219,7 +219,6 @@ class ItaniumCXXABI : public ItaniumCXXABIShared { buildStructorSignature(GlobalDecl GD, SmallVectorImpl &ArgTys) override; - void EmitCXXDestructors(const CXXDestructorDecl *D) override; void addImplicitStructorParams(CodeGenFunction &CGF, QualType &ResTy, @@ -250,7 +249,6 @@ class ItaniumCXXABI : public ItaniumCXXABIShared { bool isVirtualOffsetNeededForVTableField(CodeGenFunction &CGF, CodeGenFunction::VPtr Vptr) override; - llvm::Constant * getVTableAddressPoint(BaseSubobject Base, const CXXRecordDecl *VTableClass) override;