Path: blob/main/contrib/llvm-project/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
213799 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This provides C++ code generation targeting the Itanium C++ ABI. The class9// in this file generates structures that follow the Itanium C++ ABI, which is10// documented at:11// https://itanium-cxx-abi.github.io/cxx-abi/abi.html12// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html13//14// It also supports the closely-related ARM ABI, documented at:15// https://developer.arm.com/documentation/ihi0041/g/16//17//===----------------------------------------------------------------------===//1819#include "CIRGenCXXABI.h"20#include "CIRGenFunction.h"2122#include "clang/AST/ExprCXX.h"23#include "clang/AST/GlobalDecl.h"24#include "clang/CIR/MissingFeatures.h"25#include "llvm/Support/ErrorHandling.h"2627using namespace clang;28using namespace clang::CIRGen;2930namespace {3132class CIRGenItaniumCXXABI : public CIRGenCXXABI {33public:34CIRGenItaniumCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) {35assert(!cir::MissingFeatures::cxxabiUseARMMethodPtrABI());36assert(!cir::MissingFeatures::cxxabiUseARMGuardVarABI());37}3839bool needsVTTParameter(clang::GlobalDecl gd) override;4041void emitInstanceFunctionProlog(SourceLocation loc,42CIRGenFunction &cgf) override;4344void emitCXXConstructors(const clang::CXXConstructorDecl *d) override;45void emitCXXDestructors(const clang::CXXDestructorDecl *d) override;46void emitCXXStructor(clang::GlobalDecl gd) override;4748bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,49CXXDtorType dt) const override {50// Itanium does not emit any destructor variant as an inline thunk.51// Delegating may occur as an optimization, but all variants are either52// emitted with external linkage or as linkonce if they are inline and used.53return false;54}55};5657} // namespace5859void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc,60CIRGenFunction &cgf) {61// Naked functions have no prolog.62if (cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<NakedAttr>()) {63cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(),64"emitInstanceFunctionProlog: Naked");65}6667/// Initialize the 'this' slot. In the Itanium C++ ABI, no prologue68/// adjustments are required, because they are all handled by thunks.69setCXXABIThisValue(cgf, loadIncomingCXXThis(cgf));7071/// Classic codegen has code here to initialize the 'vtt' slot if72// getStructorImplicitParamDecl(cgf) returns a non-null value, but in the73// current implementation (of classic codegen) it never does.74assert(!cir::MissingFeatures::cxxabiStructorImplicitParam());7576/// If this is a function that the ABI specifies returns 'this', initialize77/// the return slot to this' at the start of the function.78///79/// Unlike the setting of return types, this is done within the ABI80/// implementation instead of by clients of CIRGenCXXBI because:81/// 1) getThisValue is currently protected82/// 2) in theory, an ABI could implement 'this' returns some other way;83/// HasThisReturn only specifies a contract, not the implementation84if (hasThisReturn(cgf.curGD)) {85cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(),86"emitInstanceFunctionProlog: hasThisReturn");87}88}8990// Find out how to cirgen the complete destructor and constructor91namespace {92enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT };93}9495static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm,96const CXXMethodDecl *md) {97if (!cgm.getCodeGenOpts().CXXCtorDtorAliases)98return StructorCIRGen::Emit;99100// The complete and base structors are not equivalent if there are any virtual101// bases, so emit separate functions.102if (md->getParent()->getNumVBases()) {103// The return value is correct here, but other support for this is NYI.104cgm.errorNYI(md->getSourceRange(), "getCIRGenToUse: virtual bases");105return StructorCIRGen::Emit;106}107108GlobalDecl aliasDecl;109if (const auto *dd = dyn_cast<CXXDestructorDecl>(md)) {110// The assignment is correct here, but other support for this is NYI.111cgm.errorNYI(md->getSourceRange(), "getCIRGenToUse: dtor");112aliasDecl = GlobalDecl(dd, Dtor_Complete);113} else {114const auto *cd = cast<CXXConstructorDecl>(md);115aliasDecl = GlobalDecl(cd, Ctor_Complete);116}117118cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);119120if (cir::isDiscardableIfUnused(linkage))121return StructorCIRGen::RAUW;122123// FIXME: Should we allow available_externally aliases?124if (!cir::isValidLinkage(linkage))125return StructorCIRGen::RAUW;126127if (cir::isWeakForLinker(linkage)) {128// Only ELF and wasm support COMDATs with arbitrary names (C5/D5).129if (cgm.getTarget().getTriple().isOSBinFormatELF() ||130cgm.getTarget().getTriple().isOSBinFormatWasm())131return StructorCIRGen::COMDAT;132return StructorCIRGen::Emit;133}134135return StructorCIRGen::Alias;136}137138static void emitConstructorDestructorAlias(CIRGenModule &cgm,139GlobalDecl aliasDecl,140GlobalDecl targetDecl) {141cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);142143// Does this function alias already exists?144StringRef mangledName = cgm.getMangledName(aliasDecl);145auto globalValue = dyn_cast_or_null<cir::CIRGlobalValueInterface>(146cgm.getGlobalValue(mangledName));147if (globalValue && !globalValue.isDeclaration())148return;149150auto entry = cast_or_null<cir::FuncOp>(cgm.getGlobalValue(mangledName));151152// Retrieve aliasee info.153auto aliasee = cast<cir::FuncOp>(cgm.getAddrOfGlobal(targetDecl));154155// Populate actual alias.156cgm.emitAliasForGlobal(mangledName, entry, aliasDecl, aliasee, linkage);157}158159void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) {160auto *md = cast<CXXMethodDecl>(gd.getDecl());161StructorCIRGen cirGenType = getCIRGenToUse(cgm, md);162const auto *cd = dyn_cast<CXXConstructorDecl>(md);163164if (cd ? gd.getCtorType() == Ctor_Complete165: gd.getDtorType() == Dtor_Complete) {166GlobalDecl baseDecl =167cd ? gd.getWithCtorType(Ctor_Base) : gd.getWithDtorType(Dtor_Base);168;169170if (cirGenType == StructorCIRGen::Alias ||171cirGenType == StructorCIRGen::COMDAT) {172emitConstructorDestructorAlias(cgm, gd, baseDecl);173return;174}175176if (cirGenType == StructorCIRGen::RAUW) {177StringRef mangledName = cgm.getMangledName(gd);178mlir::Operation *aliasee = cgm.getAddrOfGlobal(baseDecl);179cgm.addReplacement(mangledName, aliasee);180return;181}182}183184auto fn = cgm.codegenCXXStructor(gd);185186cgm.maybeSetTrivialComdat(*md, fn);187}188189void CIRGenItaniumCXXABI::emitCXXConstructors(const CXXConstructorDecl *d) {190// Just make sure we're in sync with TargetCXXABI.191assert(cgm.getTarget().getCXXABI().hasConstructorVariants());192193// The constructor used for constructing this as a base class;194// ignores virtual bases.195cgm.emitGlobal(GlobalDecl(d, Ctor_Base));196197// The constructor used for constructing this as a complete class;198// constructs the virtual bases, then calls the base constructor.199if (!d->getParent()->isAbstract()) {200// We don't need to emit the complete ctro if the class is abstract.201cgm.emitGlobal(GlobalDecl(d, Ctor_Complete));202}203}204205void CIRGenItaniumCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) {206// The destructor used for destructing this as a base class; ignores207// virtual bases.208cgm.emitGlobal(GlobalDecl(d, Dtor_Base));209210// The destructor used for destructing this as a most-derived class;211// call the base destructor and then destructs any virtual bases.212cgm.emitGlobal(GlobalDecl(d, Dtor_Complete));213214// The destructor in a virtual table is always a 'deleting'215// destructor, which calls the complete destructor and then uses the216// appropriate operator delete.217if (d->isVirtual())218cgm.emitGlobal(GlobalDecl(d, Dtor_Deleting));219}220221/// Return whether the given global decl needs a VTT (virtual table table)222/// parameter, which it does if it's a base constructor or destructor with223/// virtual bases.224bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) {225auto *md = cast<CXXMethodDecl>(gd.getDecl());226227// We don't have any virtual bases, just return early.228if (!md->getParent()->getNumVBases())229return false;230231// Check if we have a base constructor.232if (isa<CXXConstructorDecl>(md) && gd.getCtorType() == Ctor_Base)233return true;234235// Check if we have a base destructor.236if (isa<CXXDestructorDecl>(md) && gd.getDtorType() == Dtor_Base)237return true;238239return false;240}241242CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) {243switch (cgm.getASTContext().getCXXABIKind()) {244case TargetCXXABI::GenericItanium:245case TargetCXXABI::GenericAArch64:246return new CIRGenItaniumCXXABI(cgm);247248case TargetCXXABI::AppleARM64:249// The general Itanium ABI will do until we implement something that250// requires special handling.251assert(!cir::MissingFeatures::cxxabiAppleARM64CXXABI());252return new CIRGenItaniumCXXABI(cgm);253254default:255llvm_unreachable("bad or NYI ABI kind");256}257}258259260