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..5f0905daf1e1e 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,14 +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 +111,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 +193,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 +215,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 +322,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 +371,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 +385,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 +1748,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 +1794,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 +1805,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..ada8d06c86097 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,14 +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; void addImplicitStructorParams(CodeGenFunction &CGF, QualType &ResTy, @@ -301,10 +249,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, const CXXRecordDecl *VTableClass) override; @@ -396,8 +340,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 +3349,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;