| 1 | //===----------------------------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This provides C++ code generation targeting the Itanium C++ ABI. The class |
| 10 | // in this file generates structures that follow the Itanium C++ ABI, which is |
| 11 | // documented at: |
| 12 | // https://itanium-cxx-abi.github.io/cxx-abi/abi.html |
| 13 | // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html |
| 14 | // |
| 15 | // It also supports the closely-related ARM ABI, documented at: |
| 16 | // https://developer.arm.com/documentation/ihi0041/g/ |
| 17 | // |
| 18 | //===----------------------------------------------------------------------===// |
| 19 | |
| 20 | #include "CIRGenCXXABI.h" |
| 21 | #include "CIRGenFunction.h" |
| 22 | |
| 23 | #include "clang/AST/ExprCXX.h" |
| 24 | #include "clang/AST/GlobalDecl.h" |
| 25 | #include "clang/CIR/MissingFeatures.h" |
| 26 | #include "llvm/Support/ErrorHandling.h" |
| 27 | |
| 28 | using namespace clang; |
| 29 | using namespace clang::CIRGen; |
| 30 | |
| 31 | namespace { |
| 32 | |
| 33 | class CIRGenItaniumCXXABI : public CIRGenCXXABI { |
| 34 | public: |
| 35 | CIRGenItaniumCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) { |
| 36 | assert(!cir::MissingFeatures::cxxabiUseARMMethodPtrABI()); |
| 37 | assert(!cir::MissingFeatures::cxxabiUseARMGuardVarABI()); |
| 38 | } |
| 39 | |
| 40 | bool needsVTTParameter(clang::GlobalDecl gd) override; |
| 41 | |
| 42 | void emitInstanceFunctionProlog(SourceLocation loc, |
| 43 | CIRGenFunction &cgf) override; |
| 44 | |
| 45 | void emitCXXConstructors(const clang::CXXConstructorDecl *d) override; |
| 46 | void emitCXXDestructors(const clang::CXXDestructorDecl *d) override; |
| 47 | void emitCXXStructor(clang::GlobalDecl gd) override; |
| 48 | |
| 49 | bool useThunkForDtorVariant(const CXXDestructorDecl *dtor, |
| 50 | CXXDtorType dt) const override { |
| 51 | // Itanium does not emit any destructor variant as an inline thunk. |
| 52 | // Delegating may occur as an optimization, but all variants are either |
| 53 | // emitted with external linkage or as linkonce if they are inline and used. |
| 54 | return false; |
| 55 | } |
| 56 | }; |
| 57 | |
| 58 | } // namespace |
| 59 | |
| 60 | void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc, |
| 61 | CIRGenFunction &cgf) { |
| 62 | // Naked functions have no prolog. |
| 63 | if (cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<NakedAttr>()) { |
| 64 | cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(), |
| 65 | "emitInstanceFunctionProlog: Naked" ); |
| 66 | } |
| 67 | |
| 68 | /// Initialize the 'this' slot. In the Itanium C++ ABI, no prologue |
| 69 | /// adjustments are required, because they are all handled by thunks. |
| 70 | setCXXABIThisValue(cgf, loadIncomingCXXThis(cgf)); |
| 71 | |
| 72 | /// Classic codegen has code here to initialize the 'vtt' slot if |
| 73 | // getStructorImplicitParamDecl(cgf) returns a non-null value, but in the |
| 74 | // current implementation (of classic codegen) it never does. |
| 75 | assert(!cir::MissingFeatures::cxxabiStructorImplicitParam()); |
| 76 | |
| 77 | /// If this is a function that the ABI specifies returns 'this', initialize |
| 78 | /// the return slot to this' at the start of the function. |
| 79 | /// |
| 80 | /// Unlike the setting of return types, this is done within the ABI |
| 81 | /// implementation instead of by clients of CIRGenCXXBI because: |
| 82 | /// 1) getThisValue is currently protected |
| 83 | /// 2) in theory, an ABI could implement 'this' returns some other way; |
| 84 | /// HasThisReturn only specifies a contract, not the implementation |
| 85 | if (hasThisReturn(gd: cgf.curGD)) { |
| 86 | cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(), |
| 87 | "emitInstanceFunctionProlog: hasThisReturn" ); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | // Find out how to cirgen the complete destructor and constructor |
| 92 | namespace { |
| 93 | enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT }; |
| 94 | } |
| 95 | |
| 96 | static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm, |
| 97 | const CXXMethodDecl *md) { |
| 98 | if (!cgm.getCodeGenOpts().CXXCtorDtorAliases) |
| 99 | return StructorCIRGen::Emit; |
| 100 | |
| 101 | // The complete and base structors are not equivalent if there are any virtual |
| 102 | // bases, so emit separate functions. |
| 103 | if (md->getParent()->getNumVBases()) { |
| 104 | // The return value is correct here, but other support for this is NYI. |
| 105 | cgm.errorNYI(md->getSourceRange(), "getCIRGenToUse: virtual bases" ); |
| 106 | return StructorCIRGen::Emit; |
| 107 | } |
| 108 | |
| 109 | GlobalDecl aliasDecl; |
| 110 | if (const auto *dd = dyn_cast<CXXDestructorDecl>(Val: md)) { |
| 111 | // The assignment is correct here, but other support for this is NYI. |
| 112 | cgm.errorNYI(md->getSourceRange(), "getCIRGenToUse: dtor" ); |
| 113 | aliasDecl = GlobalDecl(dd, Dtor_Complete); |
| 114 | } else { |
| 115 | const auto *cd = cast<CXXConstructorDecl>(Val: md); |
| 116 | aliasDecl = GlobalDecl(cd, Ctor_Complete); |
| 117 | } |
| 118 | |
| 119 | cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl); |
| 120 | |
| 121 | if (cir::isDiscardableIfUnused(linkage)) |
| 122 | return StructorCIRGen::RAUW; |
| 123 | |
| 124 | // FIXME: Should we allow available_externally aliases? |
| 125 | if (!cir::isValidLinkage(linkage)) |
| 126 | return StructorCIRGen::RAUW; |
| 127 | |
| 128 | if (cir::isWeakForLinker(linkage)) { |
| 129 | // Only ELF and wasm support COMDATs with arbitrary names (C5/D5). |
| 130 | if (cgm.getTarget().getTriple().isOSBinFormatELF() || |
| 131 | cgm.getTarget().getTriple().isOSBinFormatWasm()) |
| 132 | return StructorCIRGen::COMDAT; |
| 133 | return StructorCIRGen::Emit; |
| 134 | } |
| 135 | |
| 136 | return StructorCIRGen::Alias; |
| 137 | } |
| 138 | |
| 139 | static void emitConstructorDestructorAlias(CIRGenModule &cgm, |
| 140 | GlobalDecl aliasDecl, |
| 141 | GlobalDecl targetDecl) { |
| 142 | cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl); |
| 143 | |
| 144 | // Does this function alias already exists? |
| 145 | StringRef mangledName = cgm.getMangledName(gd: aliasDecl); |
| 146 | auto globalValue = dyn_cast_or_null<cir::CIRGlobalValueInterface>( |
| 147 | cgm.getGlobalValue(mangledName)); |
| 148 | if (globalValue && !globalValue.isDeclaration()) |
| 149 | return; |
| 150 | |
| 151 | auto entry = cast_or_null<cir::FuncOp>(cgm.getGlobalValue(mangledName)); |
| 152 | |
| 153 | // Retrieve aliasee info. |
| 154 | auto aliasee = cast<cir::FuncOp>(cgm.getAddrOfGlobal(targetDecl)); |
| 155 | |
| 156 | // Populate actual alias. |
| 157 | cgm.emitAliasForGlobal(mangledName, entry, aliasDecl, aliasee, linkage); |
| 158 | } |
| 159 | |
| 160 | void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) { |
| 161 | auto *md = cast<CXXMethodDecl>(Val: gd.getDecl()); |
| 162 | StructorCIRGen cirGenType = getCIRGenToUse(cgm, md); |
| 163 | const auto *cd = dyn_cast<CXXConstructorDecl>(Val: md); |
| 164 | |
| 165 | if (cd ? gd.getCtorType() == Ctor_Complete |
| 166 | : gd.getDtorType() == Dtor_Complete) { |
| 167 | GlobalDecl baseDecl = |
| 168 | cd ? gd.getWithCtorType(Type: Ctor_Base) : gd.getWithDtorType(Type: Dtor_Base); |
| 169 | ; |
| 170 | |
| 171 | if (cirGenType == StructorCIRGen::Alias || |
| 172 | cirGenType == StructorCIRGen::COMDAT) { |
| 173 | emitConstructorDestructorAlias(cgm, aliasDecl: gd, targetDecl: baseDecl); |
| 174 | return; |
| 175 | } |
| 176 | |
| 177 | if (cirGenType == StructorCIRGen::RAUW) { |
| 178 | StringRef mangledName = cgm.getMangledName(gd); |
| 179 | mlir::Operation *aliasee = cgm.getAddrOfGlobal(baseDecl); |
| 180 | cgm.addReplacement(mangledName, aliasee); |
| 181 | return; |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | auto fn = cgm.codegenCXXStructor(gd); |
| 186 | |
| 187 | cgm.maybeSetTrivialComdat(*md, fn); |
| 188 | } |
| 189 | |
| 190 | void CIRGenItaniumCXXABI::emitCXXConstructors(const CXXConstructorDecl *d) { |
| 191 | // Just make sure we're in sync with TargetCXXABI. |
| 192 | assert(cgm.getTarget().getCXXABI().hasConstructorVariants()); |
| 193 | |
| 194 | // The constructor used for constructing this as a base class; |
| 195 | // ignores virtual bases. |
| 196 | cgm.emitGlobal(gd: GlobalDecl(d, Ctor_Base)); |
| 197 | |
| 198 | // The constructor used for constructing this as a complete class; |
| 199 | // constructs the virtual bases, then calls the base constructor. |
| 200 | if (!d->getParent()->isAbstract()) { |
| 201 | // We don't need to emit the complete ctro if the class is abstract. |
| 202 | cgm.emitGlobal(gd: GlobalDecl(d, Ctor_Complete)); |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | void CIRGenItaniumCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) { |
| 207 | // The destructor used for destructing this as a base class; ignores |
| 208 | // virtual bases. |
| 209 | cgm.emitGlobal(gd: GlobalDecl(d, Dtor_Base)); |
| 210 | |
| 211 | // The destructor used for destructing this as a most-derived class; |
| 212 | // call the base destructor and then destructs any virtual bases. |
| 213 | cgm.emitGlobal(gd: GlobalDecl(d, Dtor_Complete)); |
| 214 | |
| 215 | // The destructor in a virtual table is always a 'deleting' |
| 216 | // destructor, which calls the complete destructor and then uses the |
| 217 | // appropriate operator delete. |
| 218 | if (d->isVirtual()) |
| 219 | cgm.emitGlobal(gd: GlobalDecl(d, Dtor_Deleting)); |
| 220 | } |
| 221 | |
| 222 | /// Return whether the given global decl needs a VTT (virtual table table) |
| 223 | /// parameter, which it does if it's a base constructor or destructor with |
| 224 | /// virtual bases. |
| 225 | bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) { |
| 226 | auto *md = cast<CXXMethodDecl>(Val: gd.getDecl()); |
| 227 | |
| 228 | // We don't have any virtual bases, just return early. |
| 229 | if (!md->getParent()->getNumVBases()) |
| 230 | return false; |
| 231 | |
| 232 | // Check if we have a base constructor. |
| 233 | if (isa<CXXConstructorDecl>(Val: md) && gd.getCtorType() == Ctor_Base) |
| 234 | return true; |
| 235 | |
| 236 | // Check if we have a base destructor. |
| 237 | if (isa<CXXDestructorDecl>(Val: md) && gd.getDtorType() == Dtor_Base) |
| 238 | return true; |
| 239 | |
| 240 | return false; |
| 241 | } |
| 242 | |
| 243 | CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) { |
| 244 | switch (cgm.getASTContext().getCXXABIKind()) { |
| 245 | case TargetCXXABI::GenericItanium: |
| 246 | case TargetCXXABI::GenericAArch64: |
| 247 | return new CIRGenItaniumCXXABI(cgm); |
| 248 | |
| 249 | case TargetCXXABI::AppleARM64: |
| 250 | // The general Itanium ABI will do until we implement something that |
| 251 | // requires special handling. |
| 252 | assert(!cir::MissingFeatures::cxxabiAppleARM64CXXABI()); |
| 253 | return new CIRGenItaniumCXXABI(cgm); |
| 254 | |
| 255 | default: |
| 256 | llvm_unreachable("bad or NYI ABI kind" ); |
| 257 | } |
| 258 | } |
| 259 | |