| //===----------------------------------------------------------------------===// |
| // |
| // 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 provides C++ code generation targeting the Itanium C++ ABI. The class |
| // in this file generates structures that follow the Itanium C++ ABI, which is |
| // documented at: |
| // https://itanium-cxx-abi.github.io/cxx-abi/abi.html |
| // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html |
| // |
| // It also supports the closely-related ARM ABI, documented at: |
| // https://developer.arm.com/documentation/ihi0041/g/ |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "CIRGenCXXABI.h" |
| #include "CIRGenFunction.h" |
| |
| #include "clang/AST/ExprCXX.h" |
| #include "clang/AST/GlobalDecl.h" |
| #include "clang/CIR/MissingFeatures.h" |
| #include "llvm/Support/ErrorHandling.h" |
| |
| using namespace clang; |
| using namespace clang::CIRGen; |
| |
| namespace { |
| |
| class CIRGenItaniumCXXABI : public CIRGenCXXABI { |
| public: |
| CIRGenItaniumCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) { |
| assert(!cir::MissingFeatures::cxxabiUseARMMethodPtrABI()); |
| assert(!cir::MissingFeatures::cxxabiUseARMGuardVarABI()); |
| } |
| |
| bool needsVTTParameter(clang::GlobalDecl gd) override; |
| |
| void emitInstanceFunctionProlog(SourceLocation loc, |
| CIRGenFunction &cgf) override; |
| |
| void emitCXXConstructors(const clang::CXXConstructorDecl *d) override; |
| void emitCXXStructor(clang::GlobalDecl gd) override; |
| }; |
| |
| } // namespace |
| |
| void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc, |
| CIRGenFunction &cgf) { |
| // Naked functions have no prolog. |
| if (cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<NakedAttr>()) { |
| cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(), |
| "emitInstanceFunctionProlog: Naked"); |
| } |
| |
| /// Initialize the 'this' slot. In the Itanium C++ ABI, no prologue |
| /// adjustments are required, because they are all handled by thunks. |
| setCXXABIThisValue(cgf, loadIncomingCXXThis(cgf)); |
| |
| /// Classic codegen has code here to initialize the 'vtt' slot if |
| // getStructorImplicitParamDecl(cgf) returns a non-null value, but in the |
| // current implementation (of classic codegen) it never does. |
| assert(!cir::MissingFeatures::cxxabiStructorImplicitParam()); |
| |
| /// If this is a function that the ABI specifies returns 'this', initialize |
| /// the return slot to this' at the start of the function. |
| /// |
| /// Unlike the setting of return types, this is done within the ABI |
| /// implementation instead of by clients of CIRGenCXXBI because: |
| /// 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)) { |
| cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(), |
| "emitInstanceFunctionProlog: hasThisReturn"); |
| } |
| } |
| |
| void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) { |
| auto *md = cast<CXXMethodDecl>(gd.getDecl()); |
| auto *cd = dyn_cast<CXXConstructorDecl>(md); |
| |
| if (!cd) { |
| cgm.errorNYI(md->getSourceRange(), "CXCABI emit destructor"); |
| return; |
| } |
| |
| if (cgm.getCodeGenOpts().CXXCtorDtorAliases) |
| cgm.errorNYI(md->getSourceRange(), "Ctor/Dtor aliases"); |
| |
| auto fn = cgm.codegenCXXStructor(gd); |
| |
| cgm.maybeSetTrivialComdat(*md, fn); |
| } |
| |
| void CIRGenItaniumCXXABI::emitCXXConstructors(const CXXConstructorDecl *d) { |
| // Just make sure we're in sync with TargetCXXABI. |
| assert(cgm.getTarget().getCXXABI().hasConstructorVariants()); |
| |
| // The constructor used for constructing this as a base class; |
| // ignores virtual bases. |
| cgm.emitGlobal(GlobalDecl(d, Ctor_Base)); |
| |
| // The constructor used for constructing this as a complete class; |
| // constructs the virtual bases, then calls the base constructor. |
| if (!d->getParent()->isAbstract()) { |
| // We don't need to emit the complete ctro if the class is abstract. |
| cgm.emitGlobal(GlobalDecl(d, Ctor_Complete)); |
| } |
| } |
| |
| /// 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<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; |
| } |
| |
| CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) { |
| switch (cgm.getASTContext().getCXXABIKind()) { |
| case TargetCXXABI::GenericItanium: |
| case TargetCXXABI::GenericAArch64: |
| return new CIRGenItaniumCXXABI(cgm); |
| |
| case TargetCXXABI::AppleARM64: |
| // The general Itanium ABI will do until we implement something that |
| // requires special handling. |
| assert(!cir::MissingFeatures::cxxabiAppleARM64CXXABI()); |
| return new CIRGenItaniumCXXABI(cgm); |
| |
| default: |
| llvm_unreachable("bad or NYI ABI kind"); |
| } |
| } |