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(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>(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>(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(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>(gd.getDecl()); 162 StructorCIRGen cirGenType = getCIRGenToUse(cgm, md); 163 const auto *cd = dyn_cast<CXXConstructorDecl>(md); 164 165 if (cd ? gd.getCtorType() == Ctor_Complete 166 : gd.getDtorType() == Dtor_Complete) { 167 GlobalDecl baseDecl = 168 cd ? gd.getWithCtorType(Ctor_Base) : gd.getWithDtorType(Dtor_Base); 169 ; 170 171 if (cirGenType == StructorCIRGen::Alias || 172 cirGenType == StructorCIRGen::COMDAT) { 173 emitConstructorDestructorAlias(cgm, gd, 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(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(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(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(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(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>(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>(md) && gd.getCtorType() == Ctor_Base) 234 return true; 235 236 // Check if we have a base destructor. 237 if (isa<CXXDestructorDecl>(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