- 
                Notifications
    You must be signed in to change notification settings 
- Fork 15k
[Clang][CodeGen][CIR][NFC] Refactor CGCXXABI classes for code sharing #165078
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -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<MangleContext> 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; } | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed there's a mismatch of style among the methods, they should be consistent. Not sure which one we want to stick with given clang vs MLIR differences, but I'd vote for camelBack for this! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe we should match the style of the rest of clang - I'm somewhat concerned about the current divergence from the clang naming style (although I do really hate the style, it is the style clang is meant to be using) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, sorry, this is method names, not variables - I think we should match the clang style, but at this point I don't know what that actually is for method names :D (@AaronBallman what is the correct case convention?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not saying this is the right thing to do, but what I intended for this PR was to keep the names the same as they were in the LLVM IR codegen implementation. A few of those names were out-of-date with the latest coding style. Maybe this is a good time to update them? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think given this movement it is entirely reasonable to update to the current style | ||
|  | ||
| /// 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<CXXConstructorDecl>(GD.getDecl()) || | ||
| (isa<CXXDestructorDecl>(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 | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -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 <utility> | ||
|  | ||
| namespace clang { | ||
|  | ||
| template <typename BaseT> class ItaniumCXXABIShared : public BaseT { | ||
| protected: | ||
| /// Constructor forwarding to the base ABI class. | ||
| template <typename... Args> | ||
| ItaniumCXXABIShared(Args &&...args) : BaseT(std::forward<Args>(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<CXXDestructorDecl>(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<CXXConstructorDecl>(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<CXXMethodDecl>(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<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base) | ||
| return true; | ||
|  | ||
| // Check if we have a base destructor. | ||
| if (isa<CXXDestructorDecl>(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 | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: how about 'CXXABICommon' (or maybe just 'CXXABIBase')? IMO "Shared" might give extra room for interpretation given other idiomatic c++ stuff (e.g. shared pointers, etc)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would swear I had made a comment to this effect but apparently saving comments is too much to ask of myself.
I just did a quick grep of the clang tree and it looks like
*Baseis what is used most consistently