2269 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This provides C++ code generation targeting the Itanium C++ ABI. The class10// in this file generates structures that follow the Itanium C++ ABI, which is11// documented at:12// https://itanium-cxx-abi.github.io/cxx-abi/abi.html13// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html14//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/AST/VTableBuilder.h"26#include "clang/CIR/MissingFeatures.h"27#include "llvm/Support/ErrorHandling.h"28 29using namespace clang;30using namespace clang::CIRGen;31 32namespace {33 34class CIRGenItaniumCXXABI : public CIRGenCXXABI {35protected:36 /// All the vtables which have been defined.37 llvm::DenseMap<const CXXRecordDecl *, cir::GlobalOp> vtables;38 39public:40 CIRGenItaniumCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) {41 assert(!cir::MissingFeatures::cxxabiUseARMMethodPtrABI());42 assert(!cir::MissingFeatures::cxxabiUseARMGuardVarABI());43 }44 45 AddedStructorArgs getImplicitConstructorArgs(CIRGenFunction &cgf,46 const CXXConstructorDecl *d,47 CXXCtorType type,48 bool forVirtualBase,49 bool delegating) override;50 51 bool needsVTTParameter(clang::GlobalDecl gd) override;52 53 AddedStructorArgCounts54 buildStructorSignature(GlobalDecl gd,55 llvm::SmallVectorImpl<CanQualType> &argTys) override;56 57 void emitInstanceFunctionProlog(SourceLocation loc,58 CIRGenFunction &cgf) override;59 60 void addImplicitStructorParams(CIRGenFunction &cgf, QualType &resTy,61 FunctionArgList ¶ms) override;62 mlir::Value getCXXDestructorImplicitParam(CIRGenFunction &cgf,63 const CXXDestructorDecl *dd,64 CXXDtorType type,65 bool forVirtualBase,66 bool delegating) override;67 void emitCXXConstructors(const clang::CXXConstructorDecl *d) override;68 void emitCXXDestructors(const clang::CXXDestructorDecl *d) override;69 void emitCXXStructor(clang::GlobalDecl gd) override;70 71 void emitDestructorCall(CIRGenFunction &cgf, const CXXDestructorDecl *dd,72 CXXDtorType type, bool forVirtualBase,73 bool delegating, Address thisAddr,74 QualType thisTy) override;75 void registerGlobalDtor(const VarDecl *vd, cir::FuncOp dtor,76 mlir::Value addr) override;77 void emitVirtualObjectDelete(CIRGenFunction &cgf, const CXXDeleteExpr *de,78 Address ptr, QualType elementType,79 const CXXDestructorDecl *dtor) override;80 81 void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;82 void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;83 84 bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,85 CXXDtorType dt) const override {86 // Itanium does not emit any destructor variant as an inline thunk.87 // Delegating may occur as an optimization, but all variants are either88 // emitted with external linkage or as linkonce if they are inline and used.89 return false;90 }91 92 bool isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf,93 CIRGenFunction::VPtr vptr) override;94 95 cir::GlobalOp getAddrOfVTable(const CXXRecordDecl *rd,96 CharUnits vptrOffset) override;97 CIRGenCallee getVirtualFunctionPointer(CIRGenFunction &cgf,98 clang::GlobalDecl gd, Address thisAddr,99 mlir::Type ty,100 SourceLocation loc) override;101 mlir::Value emitVirtualDestructorCall(CIRGenFunction &cgf,102 const CXXDestructorDecl *dtor,103 CXXDtorType dtorType, Address thisAddr,104 DeleteOrMemberCallExpr e) override;105 mlir::Value getVTableAddressPoint(BaseSubobject base,106 const CXXRecordDecl *vtableClass) override;107 mlir::Value getVTableAddressPointInStructorWithVTT(108 CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,109 const CXXRecordDecl *nearestVBase);110 111 mlir::Value getVTableAddressPointInStructor(112 CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,113 clang::BaseSubobject base,114 const clang::CXXRecordDecl *nearestVBase) override;115 void emitVTableDefinitions(CIRGenVTables &cgvt,116 const CXXRecordDecl *rd) override;117 void emitVirtualInheritanceTables(const CXXRecordDecl *rd) override;118 119 mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,120 QualType ty) override;121 122 bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {123 return true;124 }125 126 size_t getSrcArgforCopyCtor(const CXXConstructorDecl *,127 FunctionArgList &args) const override {128 assert(!args.empty() && "expected the arglist to not be empty!");129 return args.size() - 1;130 }131 132 void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) override;133 134 mlir::Value135 getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf,136 Address thisAddr, const CXXRecordDecl *classDecl,137 const CXXRecordDecl *baseClassDecl) override;138 139 // The traditional clang CodeGen emits calls to `__dynamic_cast` directly into140 // LLVM in the `emitDynamicCastCall` function. In CIR, `dynamic_cast`141 // expressions are lowered to `cir.dyn_cast` ops instead of calls to runtime142 // functions. So during CIRGen we don't need the `emitDynamicCastCall`143 // function that clang CodeGen has.144 mlir::Value emitDynamicCast(CIRGenFunction &cgf, mlir::Location loc,145 QualType srcRecordTy, QualType destRecordTy,146 cir::PointerType destCIRTy, bool isRefCast,147 Address src) override;148 149 Address initializeArrayCookie(CIRGenFunction &cgf, Address newPtr,150 mlir::Value numElements, const CXXNewExpr *e,151 QualType elementType) override;152 153protected:154 CharUnits getArrayCookieSizeImpl(QualType elementType) override;155 156 /**************************** RTTI Uniqueness ******************************/157 /// Returns true if the ABI requires RTTI type_info objects to be unique158 /// across a program.159 virtual bool shouldRTTIBeUnique() const { return true; }160 161public:162 /// What sort of unique-RTTI behavior should we use?163 enum RTTIUniquenessKind {164 /// We are guaranteeing, or need to guarantee, that the RTTI string165 /// is unique.166 RUK_Unique,167 168 /// We are not guaranteeing uniqueness for the RTTI string, so we169 /// can demote to hidden visibility but must use string comparisons.170 RUK_NonUniqueHidden,171 172 /// We are not guaranteeing uniqueness for the RTTI string, so we173 /// have to use string comparisons, but we also have to emit it with174 /// non-hidden visibility.175 RUK_NonUniqueVisible176 };177 178 /// Return the required visibility status for the given type and linkage in179 /// the current ABI.180 RTTIUniquenessKind181 classifyRTTIUniqueness(QualType canTy, cir::GlobalLinkageKind linkage) const;182};183 184} // namespace185 186void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc,187 CIRGenFunction &cgf) {188 // Naked functions have no prolog.189 if (cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<NakedAttr>()) {190 cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(),191 "emitInstanceFunctionProlog: Naked");192 }193 194 /// Initialize the 'this' slot. In the Itanium C++ ABI, no prologue195 /// adjustments are required, because they are all handled by thunks.196 setCXXABIThisValue(cgf, loadIncomingCXXThis(cgf));197 198 /// Initialize the 'vtt' slot if needed.199 if (getStructorImplicitParamDecl(cgf)) {200 cir::LoadOp val = cgf.getBuilder().createLoad(201 cgf.getLoc(loc),202 cgf.getAddrOfLocalVar(getStructorImplicitParamDecl(cgf)));203 setStructorImplicitParamValue(cgf, val);204 }205 206 /// If this is a function that the ABI specifies returns 'this', initialize207 /// the return slot to this' at the start of the function.208 ///209 /// Unlike the setting of return types, this is done within the ABI210 /// implementation instead of by clients of CIRGenCXXBI because:211 /// 1) getThisValue is currently protected212 /// 2) in theory, an ABI could implement 'this' returns some other way;213 /// HasThisReturn only specifies a contract, not the implementation214 if (hasThisReturn(cgf.curGD)) {215 cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(),216 "emitInstanceFunctionProlog: hasThisReturn");217 }218}219 220CIRGenCXXABI::AddedStructorArgCounts221CIRGenItaniumCXXABI::buildStructorSignature(222 GlobalDecl gd, llvm::SmallVectorImpl<CanQualType> &argTys) {223 clang::ASTContext &astContext = cgm.getASTContext();224 225 // All parameters are already in place except VTT, which goes after 'this'.226 // These are clang types, so we don't need to worry about sret yet.227 228 // Check if we need to add a VTT parameter (which has type void **).229 if ((isa<CXXConstructorDecl>(gd.getDecl()) ? gd.getCtorType() == Ctor_Base230 : gd.getDtorType() == Dtor_Base) &&231 cast<CXXMethodDecl>(gd.getDecl())->getParent()->getNumVBases() != 0) {232 assert(!cir::MissingFeatures::addressSpace());233 argTys.insert(argTys.begin() + 1,234 astContext.getPointerType(235 CanQualType::CreateUnsafe(astContext.VoidPtrTy)));236 return AddedStructorArgCounts::withPrefix(1);237 }238 239 return AddedStructorArgCounts{};240}241 242// Find out how to cirgen the complete destructor and constructor243namespace {244enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT };245}246 247static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm,248 const CXXMethodDecl *md) {249 if (!cgm.getCodeGenOpts().CXXCtorDtorAliases)250 return StructorCIRGen::Emit;251 252 // The complete and base structors are not equivalent if there are any virtual253 // bases, so emit separate functions.254 if (md->getParent()->getNumVBases())255 return StructorCIRGen::Emit;256 257 GlobalDecl aliasDecl;258 if (const auto *dd = dyn_cast<CXXDestructorDecl>(md)) {259 aliasDecl = GlobalDecl(dd, Dtor_Complete);260 } else {261 const auto *cd = cast<CXXConstructorDecl>(md);262 aliasDecl = GlobalDecl(cd, Ctor_Complete);263 }264 265 cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);266 267 if (cir::isDiscardableIfUnused(linkage))268 return StructorCIRGen::RAUW;269 270 // FIXME: Should we allow available_externally aliases?271 if (!cir::isValidLinkage(linkage))272 return StructorCIRGen::RAUW;273 274 if (cir::isWeakForLinker(linkage)) {275 // Only ELF and wasm support COMDATs with arbitrary names (C5/D5).276 if (cgm.getTarget().getTriple().isOSBinFormatELF() ||277 cgm.getTarget().getTriple().isOSBinFormatWasm())278 return StructorCIRGen::COMDAT;279 return StructorCIRGen::Emit;280 }281 282 return StructorCIRGen::Alias;283}284 285static void emitConstructorDestructorAlias(CIRGenModule &cgm,286 GlobalDecl aliasDecl,287 GlobalDecl targetDecl) {288 cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);289 290 // Does this function alias already exists?291 StringRef mangledName = cgm.getMangledName(aliasDecl);292 auto globalValue = dyn_cast_or_null<cir::CIRGlobalValueInterface>(293 cgm.getGlobalValue(mangledName));294 if (globalValue && !globalValue.isDeclaration())295 return;296 297 auto entry = cast_or_null<cir::FuncOp>(cgm.getGlobalValue(mangledName));298 299 // Retrieve aliasee info.300 auto aliasee = cast<cir::FuncOp>(cgm.getAddrOfGlobal(targetDecl));301 302 // Populate actual alias.303 cgm.emitAliasForGlobal(mangledName, entry, aliasDecl, aliasee, linkage);304}305 306void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) {307 auto *md = cast<CXXMethodDecl>(gd.getDecl());308 StructorCIRGen cirGenType = getCIRGenToUse(cgm, md);309 const auto *cd = dyn_cast<CXXConstructorDecl>(md);310 311 if (cd ? gd.getCtorType() == Ctor_Complete312 : gd.getDtorType() == Dtor_Complete) {313 GlobalDecl baseDecl =314 cd ? gd.getWithCtorType(Ctor_Base) : gd.getWithDtorType(Dtor_Base);315 ;316 317 if (cirGenType == StructorCIRGen::Alias ||318 cirGenType == StructorCIRGen::COMDAT) {319 emitConstructorDestructorAlias(cgm, gd, baseDecl);320 return;321 }322 323 if (cirGenType == StructorCIRGen::RAUW) {324 StringRef mangledName = cgm.getMangledName(gd);325 mlir::Operation *aliasee = cgm.getAddrOfGlobal(baseDecl);326 cgm.addReplacement(mangledName, aliasee);327 return;328 }329 }330 331 auto fn = cgm.codegenCXXStructor(gd);332 333 cgm.maybeSetTrivialComdat(*md, fn);334}335 336void CIRGenItaniumCXXABI::addImplicitStructorParams(CIRGenFunction &cgf,337 QualType &resTy,338 FunctionArgList ¶ms) {339 const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());340 assert(isa<CXXConstructorDecl>(md) || isa<CXXDestructorDecl>(md));341 342 // Check if we need a VTT parameter as well.343 if (needsVTTParameter(cgf.curGD)) {344 ASTContext &astContext = cgm.getASTContext();345 346 // FIXME: avoid the fake decl347 assert(!cir::MissingFeatures::addressSpace());348 QualType t = astContext.getPointerType(astContext.VoidPtrTy);349 auto *vttDecl = ImplicitParamDecl::Create(350 astContext, /*DC=*/nullptr, md->getLocation(),351 &astContext.Idents.get("vtt"), t, ImplicitParamKind::CXXVTT);352 params.insert(params.begin() + 1, vttDecl);353 getStructorImplicitParamDecl(cgf) = vttDecl;354 }355}356 357void CIRGenItaniumCXXABI::emitCXXConstructors(const CXXConstructorDecl *d) {358 // Just make sure we're in sync with TargetCXXABI.359 assert(cgm.getTarget().getCXXABI().hasConstructorVariants());360 361 // The constructor used for constructing this as a base class;362 // ignores virtual bases.363 cgm.emitGlobal(GlobalDecl(d, Ctor_Base));364 365 // The constructor used for constructing this as a complete class;366 // constructs the virtual bases, then calls the base constructor.367 if (!d->getParent()->isAbstract()) {368 // We don't need to emit the complete ctro if the class is abstract.369 cgm.emitGlobal(GlobalDecl(d, Ctor_Complete));370 }371}372 373void CIRGenItaniumCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) {374 // The destructor used for destructing this as a base class; ignores375 // virtual bases.376 cgm.emitGlobal(GlobalDecl(d, Dtor_Base));377 378 // The destructor used for destructing this as a most-derived class;379 // call the base destructor and then destructs any virtual bases.380 cgm.emitGlobal(GlobalDecl(d, Dtor_Complete));381 382 // The destructor in a virtual table is always a 'deleting'383 // destructor, which calls the complete destructor and then uses the384 // appropriate operator delete.385 if (d->isVirtual())386 cgm.emitGlobal(GlobalDecl(d, Dtor_Deleting));387}388 389CIRGenCXXABI::AddedStructorArgs CIRGenItaniumCXXABI::getImplicitConstructorArgs(390 CIRGenFunction &cgf, const CXXConstructorDecl *d, CXXCtorType type,391 bool forVirtualBase, bool delegating) {392 if (!needsVTTParameter(GlobalDecl(d, type)))393 return AddedStructorArgs{};394 395 // Insert the implicit 'vtt' argument as the second argument. Make sure to396 // correctly reflect its address space, which can differ from generic on397 // some targets.398 mlir::Value vtt =399 cgf.getVTTParameter(GlobalDecl(d, type), forVirtualBase, delegating);400 QualType vttTy =401 cgm.getASTContext().getPointerType(cgm.getASTContext().VoidPtrTy);402 assert(!cir::MissingFeatures::addressSpace());403 return AddedStructorArgs::withPrefix({{vtt, vttTy}});404}405 406/// Return whether the given global decl needs a VTT (virtual table table)407/// parameter, which it does if it's a base constructor or destructor with408/// virtual bases.409bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) {410 auto *md = cast<CXXMethodDecl>(gd.getDecl());411 412 // We don't have any virtual bases, just return early.413 if (!md->getParent()->getNumVBases())414 return false;415 416 // Check if we have a base constructor.417 if (isa<CXXConstructorDecl>(md) && gd.getCtorType() == Ctor_Base)418 return true;419 420 // Check if we have a base destructor.421 if (isa<CXXDestructorDecl>(md) && gd.getDtorType() == Dtor_Base)422 return true;423 424 return false;425}426 427void CIRGenItaniumCXXABI::emitVTableDefinitions(CIRGenVTables &cgvt,428 const CXXRecordDecl *rd) {429 cir::GlobalOp vtable = getAddrOfVTable(rd, CharUnits());430 if (vtable.hasInitializer())431 return;432 433 ItaniumVTableContext &vtContext = cgm.getItaniumVTableContext();434 const VTableLayout &vtLayout = vtContext.getVTableLayout(rd);435 cir::GlobalLinkageKind linkage = cgm.getVTableLinkage(rd);436 mlir::Attribute rtti =437 cgm.getAddrOfRTTIDescriptor(cgm.getLoc(rd->getBeginLoc()),438 cgm.getASTContext().getCanonicalTagType(rd));439 440 // Classic codegen uses ConstantInitBuilder here, which is a very general441 // and feature-rich class to generate initializers for global values.442 // For now, this is using a simpler approach to create the initializer in CIR.443 cgvt.createVTableInitializer(vtable, vtLayout, rtti,444 cir::isLocalLinkage(linkage));445 446 // Set the correct linkage.447 vtable.setLinkage(linkage);448 449 if (cgm.supportsCOMDAT() && cir::isWeakForLinker(linkage))450 vtable.setComdat(true);451 452 // Set the right visibility.453 cgm.setGVProperties(vtable, rd);454 455 // If this is the magic class __cxxabiv1::__fundamental_type_info,456 // we will emit the typeinfo for the fundamental types. This is the457 // same behaviour as GCC.458 const DeclContext *DC = rd->getDeclContext();459 if (rd->getIdentifier() &&460 rd->getIdentifier()->isStr("__fundamental_type_info") &&461 isa<NamespaceDecl>(DC) && cast<NamespaceDecl>(DC)->getIdentifier() &&462 cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&463 DC->getParent()->isTranslationUnit()) {464 cgm.errorNYI(rd->getSourceRange(),465 "emitVTableDefinitions: __fundamental_type_info");466 }467 468 [[maybe_unused]] auto vtableAsGlobalValue =469 dyn_cast<cir::CIRGlobalValueInterface>(*vtable);470 assert(vtableAsGlobalValue && "VTable must support CIRGlobalValueInterface");471 // Always emit type metadata on non-available_externally definitions, and on472 // available_externally definitions if we are performing whole program473 // devirtualization. For WPD we need the type metadata on all vtable474 // definitions to ensure we associate derived classes with base classes475 // defined in headers but with a strong definition only in a shared476 // library.477 assert(!cir::MissingFeatures::vtableEmitMetadata());478 if (cgm.getCodeGenOpts().WholeProgramVTables) {479 cgm.errorNYI(rd->getSourceRange(),480 "emitVTableDefinitions: WholeProgramVTables");481 }482 483 assert(!cir::MissingFeatures::vtableRelativeLayout());484 if (vtContext.isRelativeLayout()) {485 cgm.errorNYI(rd->getSourceRange(), "vtableRelativeLayout");486 }487}488 489mlir::Value CIRGenItaniumCXXABI::emitVirtualDestructorCall(490 CIRGenFunction &cgf, const CXXDestructorDecl *dtor, CXXDtorType dtorType,491 Address thisAddr, DeleteOrMemberCallExpr expr) {492 auto *callExpr = dyn_cast<const CXXMemberCallExpr *>(expr);493 auto *delExpr = dyn_cast<const CXXDeleteExpr *>(expr);494 assert((callExpr != nullptr) ^ (delExpr != nullptr));495 assert(callExpr == nullptr || callExpr->arg_begin() == callExpr->arg_end());496 assert(dtorType == Dtor_Deleting || dtorType == Dtor_Complete);497 498 GlobalDecl globalDecl(dtor, dtorType);499 const CIRGenFunctionInfo *fnInfo =500 &cgm.getTypes().arrangeCXXStructorDeclaration(globalDecl);501 const cir::FuncType &fnTy = cgm.getTypes().getFunctionType(*fnInfo);502 auto callee = CIRGenCallee::forVirtual(callExpr, globalDecl, thisAddr, fnTy);503 504 QualType thisTy =505 callExpr ? callExpr->getObjectType() : delExpr->getDestroyedType();506 507 cgf.emitCXXDestructorCall(globalDecl, callee, thisAddr.emitRawPointer(),508 thisTy, nullptr, QualType(), nullptr);509 return nullptr;510}511 512void CIRGenItaniumCXXABI::emitVirtualInheritanceTables(513 const CXXRecordDecl *rd) {514 CIRGenVTables &vtables = cgm.getVTables();515 cir::GlobalOp vtt = vtables.getAddrOfVTT(rd);516 vtables.emitVTTDefinition(vtt, cgm.getVTableLinkage(rd), rd);517}518 519namespace {520class CIRGenItaniumRTTIBuilder {521 CIRGenModule &cgm; // Per-module state.522 const CIRGenItaniumCXXABI &cxxABI; // Per-module state.523 524 /// The fields of the RTTI descriptor currently being built.525 SmallVector<mlir::Attribute, 16> fields;526 527 // Returns the mangled type name of the given type.528 cir::GlobalOp getAddrOfTypeName(mlir::Location loc, QualType ty,529 cir::GlobalLinkageKind linkage);530 531 /// descriptor of the given type.532 mlir::Attribute getAddrOfExternalRTTIDescriptor(mlir::Location loc,533 QualType ty);534 535 /// Build the vtable pointer for the given type.536 void buildVTablePointer(mlir::Location loc, const Type *ty);537 538 /// Build an abi::__si_class_type_info, used for single inheritance, according539 /// to the Itanium C++ ABI, 2.9.5p6b.540 void buildSIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);541 542 /// Build an abi::__vmi_class_type_info, used for543 /// classes with bases that do not satisfy the abi::__si_class_type_info544 /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.545 void buildVMIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);546 547public:548 CIRGenItaniumRTTIBuilder(const CIRGenItaniumCXXABI &abi, CIRGenModule &cgm)549 : cgm(cgm), cxxABI(abi) {}550 551 /// Build the RTTI type info struct for the given type, or552 /// link to an existing RTTI descriptor if one already exists.553 mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty);554 555 /// Build the RTTI type info struct for the given type.556 mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty,557 cir::GlobalLinkageKind linkage,558 mlir::SymbolTable::Visibility visibility);559};560} // namespace561 562// TODO(cir): Will be removed after sharing them with the classical codegen563namespace {564 565// Pointer type info flags.566enum {567 /// PTI_Const - Type has const qualifier.568 PTI_Const = 0x1,569 570 /// PTI_Volatile - Type has volatile qualifier.571 PTI_Volatile = 0x2,572 573 /// PTI_Restrict - Type has restrict qualifier.574 PTI_Restrict = 0x4,575 576 /// PTI_Incomplete - Type is incomplete.577 PTI_Incomplete = 0x8,578 579 /// PTI_ContainingClassIncomplete - Containing class is incomplete.580 /// (in pointer to member).581 PTI_ContainingClassIncomplete = 0x10,582 583 /// PTI_TransactionSafe - Pointee is transaction_safe function (C++ TM TS).584 // PTI_TransactionSafe = 0x20,585 586 /// PTI_Noexcept - Pointee is noexcept function (C++1z).587 PTI_Noexcept = 0x40,588};589 590// VMI type info flags.591enum {592 /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.593 VMI_NonDiamondRepeat = 0x1,594 595 /// VMI_DiamondShaped - Class is diamond shaped.596 VMI_DiamondShaped = 0x2597};598 599// Base class type info flags.600enum {601 /// BCTI_Virtual - Base class is virtual.602 BCTI_Virtual = 0x1,603 604 /// BCTI_Public - Base class is public.605 BCTI_Public = 0x2606};607 608/// Given a builtin type, returns whether the type609/// info for that type is defined in the standard library.610/// TODO(cir): this can unified with LLVM codegen611static bool typeInfoIsInStandardLibrary(const BuiltinType *ty) {612 // Itanium C++ ABI 2.9.2:613 // Basic type information (e.g. for "int", "bool", etc.) will be kept in614 // the run-time support library. Specifically, the run-time support615 // library should contain type_info objects for the types X, X* and616 // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char,617 // unsigned char, signed char, short, unsigned short, int, unsigned int,618 // long, unsigned long, long long, unsigned long long, float, double,619 // long double, char16_t, char32_t, and the IEEE 754r decimal and620 // half-precision floating point types.621 //622 // GCC also emits RTTI for __int128.623 // FIXME: We do not emit RTTI information for decimal types here.624 625 // Types added here must also be added to emitFundamentalRTTIDescriptors.626 switch (ty->getKind()) {627 case BuiltinType::WasmExternRef:628 case BuiltinType::HLSLResource:629 llvm_unreachable("NYI");630 case BuiltinType::Void:631 case BuiltinType::NullPtr:632 case BuiltinType::Bool:633 case BuiltinType::WChar_S:634 case BuiltinType::WChar_U:635 case BuiltinType::Char_U:636 case BuiltinType::Char_S:637 case BuiltinType::UChar:638 case BuiltinType::SChar:639 case BuiltinType::Short:640 case BuiltinType::UShort:641 case BuiltinType::Int:642 case BuiltinType::UInt:643 case BuiltinType::Long:644 case BuiltinType::ULong:645 case BuiltinType::LongLong:646 case BuiltinType::ULongLong:647 case BuiltinType::Half:648 case BuiltinType::Float:649 case BuiltinType::Double:650 case BuiltinType::LongDouble:651 case BuiltinType::Float16:652 case BuiltinType::Float128:653 case BuiltinType::Ibm128:654 case BuiltinType::Char8:655 case BuiltinType::Char16:656 case BuiltinType::Char32:657 case BuiltinType::Int128:658 case BuiltinType::UInt128:659 return true;660 661#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \662 case BuiltinType::Id:663#include "clang/Basic/OpenCLImageTypes.def"664#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:665#include "clang/Basic/OpenCLExtensionTypes.def"666 case BuiltinType::OCLSampler:667 case BuiltinType::OCLEvent:668 case BuiltinType::OCLClkEvent:669 case BuiltinType::OCLQueue:670 case BuiltinType::OCLReserveID:671#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:672#include "clang/Basic/AArch64ACLETypes.def"673#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:674#include "clang/Basic/PPCTypes.def"675#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:676#include "clang/Basic/RISCVVTypes.def"677#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:678#include "clang/Basic/AMDGPUTypes.def"679 case BuiltinType::ShortAccum:680 case BuiltinType::Accum:681 case BuiltinType::LongAccum:682 case BuiltinType::UShortAccum:683 case BuiltinType::UAccum:684 case BuiltinType::ULongAccum:685 case BuiltinType::ShortFract:686 case BuiltinType::Fract:687 case BuiltinType::LongFract:688 case BuiltinType::UShortFract:689 case BuiltinType::UFract:690 case BuiltinType::ULongFract:691 case BuiltinType::SatShortAccum:692 case BuiltinType::SatAccum:693 case BuiltinType::SatLongAccum:694 case BuiltinType::SatUShortAccum:695 case BuiltinType::SatUAccum:696 case BuiltinType::SatULongAccum:697 case BuiltinType::SatShortFract:698 case BuiltinType::SatFract:699 case BuiltinType::SatLongFract:700 case BuiltinType::SatUShortFract:701 case BuiltinType::SatUFract:702 case BuiltinType::SatULongFract:703 case BuiltinType::BFloat16:704 return false;705 706 case BuiltinType::Dependent:707#define BUILTIN_TYPE(Id, SingletonId)708#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:709#include "clang/AST/BuiltinTypes.def"710 llvm_unreachable("asking for RRTI for a placeholder type!");711 712 case BuiltinType::ObjCId:713 case BuiltinType::ObjCClass:714 case BuiltinType::ObjCSel:715 llvm_unreachable("FIXME: Objective-C types are unsupported!");716 }717 718 llvm_unreachable("Invalid BuiltinType Kind!");719}720 721static bool typeInfoIsInStandardLibrary(const PointerType *pointerTy) {722 QualType pointeeTy = pointerTy->getPointeeType();723 const auto *builtinTy = dyn_cast<BuiltinType>(pointeeTy);724 if (!builtinTy)725 return false;726 727 // Check the qualifiers.728 Qualifiers quals = pointeeTy.getQualifiers();729 quals.removeConst();730 731 if (!quals.empty())732 return false;733 734 return typeInfoIsInStandardLibrary(builtinTy);735}736 737/// IsStandardLibraryRTTIDescriptor - Returns whether the type738/// information for the given type exists in the standard library.739static bool isStandardLibraryRttiDescriptor(QualType ty) {740 // Type info for builtin types is defined in the standard library.741 if (const auto *builtinTy = dyn_cast<BuiltinType>(ty))742 return typeInfoIsInStandardLibrary(builtinTy);743 744 // Type info for some pointer types to builtin types is defined in the745 // standard library.746 if (const auto *pointerTy = dyn_cast<PointerType>(ty))747 return typeInfoIsInStandardLibrary(pointerTy);748 749 return false;750}751 752/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for753/// the given type exists somewhere else, and that we should not emit the type754/// information in this translation unit. Assumes that it is not a755/// standard-library type.756static bool shouldUseExternalRttiDescriptor(CIRGenModule &cgm, QualType ty) {757 ASTContext &context = cgm.getASTContext();758 759 // If RTTI is disabled, assume it might be disabled in the760 // translation unit that defines any potential key function, too.761 if (!context.getLangOpts().RTTI)762 return false;763 764 if (const auto *recordTy = dyn_cast<RecordType>(ty)) {765 const auto *rd =766 cast<CXXRecordDecl>(recordTy->getDecl())->getDefinitionOrSelf();767 if (!rd->hasDefinition())768 return false;769 770 if (!rd->isDynamicClass())771 return false;772 773 // FIXME: this may need to be reconsidered if the key function774 // changes.775 // N.B. We must always emit the RTTI data ourselves if there exists a key776 // function.777 bool isDLLImport = rd->hasAttr<DLLImportAttr>();778 779 // Don't import the RTTI but emit it locally.780 if (cgm.getTriple().isOSCygMing())781 return false;782 783 if (cgm.getVTables().isVTableExternal(rd)) {784 if (cgm.getTarget().hasPS4DLLImportExport())785 return true;786 787 return !isDLLImport || cgm.getTriple().isWindowsItaniumEnvironment();788 }789 790 if (isDLLImport)791 return true;792 }793 794 return false;795}796 797/// Contains virtual and non-virtual bases seen when traversing a class798/// hierarchy.799struct SeenBases {800 llvm::SmallPtrSet<const CXXRecordDecl *, 16> nonVirtualBases;801 llvm::SmallPtrSet<const CXXRecordDecl *, 16> virtualBases;802};803 804/// Compute the value of the flags member in abi::__vmi_class_type_info.805///806static unsigned computeVmiClassTypeInfoFlags(const CXXBaseSpecifier *base,807 SeenBases &bases) {808 809 unsigned flags = 0;810 auto *baseDecl = base->getType()->castAsCXXRecordDecl();811 812 if (base->isVirtual()) {813 // Mark the virtual base as seen.814 if (!bases.virtualBases.insert(baseDecl).second) {815 // If this virtual base has been seen before, then the class is diamond816 // shaped.817 flags |= VMI_DiamondShaped;818 } else {819 if (bases.nonVirtualBases.count(baseDecl))820 flags |= VMI_NonDiamondRepeat;821 }822 } else {823 // Mark the non-virtual base as seen.824 if (!bases.nonVirtualBases.insert(baseDecl).second) {825 // If this non-virtual base has been seen before, then the class has non-826 // diamond shaped repeated inheritance.827 flags |= VMI_NonDiamondRepeat;828 } else {829 if (bases.virtualBases.count(baseDecl))830 flags |= VMI_NonDiamondRepeat;831 }832 }833 834 // Walk all bases.835 for (const auto &bs : baseDecl->bases())836 flags |= computeVmiClassTypeInfoFlags(&bs, bases);837 838 return flags;839}840 841static unsigned computeVmiClassTypeInfoFlags(const CXXRecordDecl *rd) {842 unsigned flags = 0;843 SeenBases bases;844 845 // Walk all bases.846 for (const auto &bs : rd->bases())847 flags |= computeVmiClassTypeInfoFlags(&bs, bases);848 849 return flags;850}851 852// Return whether the given record decl has a "single,853// public, non-virtual base at offset zero (i.e. the derived class is dynamic854// iff the base is)", according to Itanium C++ ABI, 2.95p6b.855// TODO(cir): this can unified with LLVM codegen856static bool canUseSingleInheritance(const CXXRecordDecl *rd) {857 // Check the number of bases.858 if (rd->getNumBases() != 1)859 return false;860 861 // Get the base.862 CXXRecordDecl::base_class_const_iterator base = rd->bases_begin();863 864 // Check that the base is not virtual.865 if (base->isVirtual())866 return false;867 868 // Check that the base is public.869 if (base->getAccessSpecifier() != AS_public)870 return false;871 872 // Check that the class is dynamic iff the base is.873 auto *baseDecl = base->getType()->castAsCXXRecordDecl();874 return baseDecl->isEmpty() ||875 baseDecl->isDynamicClass() == rd->isDynamicClass();876}877 878/// IsIncompleteClassType - Returns whether the given record type is incomplete.879static bool isIncompleteClassType(const RecordType *recordTy) {880 return !recordTy->getDecl()->getDefinitionOrSelf()->isCompleteDefinition();881}882 883/// Returns whether the given type contains an884/// incomplete class type. This is true if885///886/// * The given type is an incomplete class type.887/// * The given type is a pointer type whose pointee type contains an888/// incomplete class type.889/// * The given type is a member pointer type whose class is an incomplete890/// class type.891/// * The given type is a member pointer type whoise pointee type contains an892/// incomplete class type.893/// is an indirect or direct pointer to an incomplete class type.894static bool containsIncompleteClassType(QualType ty) {895 if (const auto *recordTy = dyn_cast<RecordType>(ty)) {896 if (isIncompleteClassType(recordTy))897 return true;898 }899 900 if (const auto *pointerTy = dyn_cast<PointerType>(ty))901 return containsIncompleteClassType(pointerTy->getPointeeType());902 903 if (const auto *memberPointerTy = dyn_cast<MemberPointerType>(ty)) {904 // Check if the class type is incomplete.905 if (!memberPointerTy->getMostRecentCXXRecordDecl()->hasDefinition())906 return true;907 908 return containsIncompleteClassType(memberPointerTy->getPointeeType());909 }910 911 return false;912}913 914const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {915 // abi::__class_type_info.916 static const char *const classTypeInfo =917 "_ZTVN10__cxxabiv117__class_type_infoE";918 // abi::__si_class_type_info.919 static const char *const siClassTypeInfo =920 "_ZTVN10__cxxabiv120__si_class_type_infoE";921 // abi::__vmi_class_type_info.922 static const char *const vmiClassTypeInfo =923 "_ZTVN10__cxxabiv121__vmi_class_type_infoE";924 925 switch (ty->getTypeClass()) {926#define TYPE(Class, Base)927#define ABSTRACT_TYPE(Class, Base)928#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:929#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:930#define DEPENDENT_TYPE(Class, Base) case Type::Class:931#include "clang/AST/TypeNodes.inc"932 llvm_unreachable("Non-canonical and dependent types shouldn't get here");933 934 case Type::LValueReference:935 case Type::RValueReference:936 llvm_unreachable("References shouldn't get here");937 938 case Type::Auto:939 case Type::DeducedTemplateSpecialization:940 llvm_unreachable("Undeduced type shouldn't get here");941 942 case Type::Pipe:943 llvm_unreachable("Pipe types shouldn't get here");944 945 case Type::ArrayParameter:946 llvm_unreachable("Array Parameter types should not get here.");947 948 case Type::Builtin:949 case Type::BitInt:950 // GCC treats vector and complex types as fundamental types.951 case Type::Vector:952 case Type::ExtVector:953 case Type::ConstantMatrix:954 case Type::Complex:955 case Type::Atomic:956 // FIXME: GCC treats block pointers as fundamental types?!957 case Type::BlockPointer:958 return "_ZTVN10__cxxabiv123__fundamental_type_infoE";959 case Type::ConstantArray:960 case Type::IncompleteArray:961 case Type::VariableArray:962 cgm.errorNYI("VTableClassNameForType: __array_type_info");963 break;964 965 case Type::FunctionNoProto:966 case Type::FunctionProto:967 cgm.errorNYI("VTableClassNameForType: __function_type_info");968 break;969 970 case Type::Enum:971 return "_ZTVN10__cxxabiv116__enum_type_infoE";972 973 case Type::Record: {974 const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl())975 ->getDefinitionOrSelf();976 977 if (!rd->hasDefinition() || !rd->getNumBases()) {978 return classTypeInfo;979 }980 981 if (canUseSingleInheritance(rd)) {982 return siClassTypeInfo;983 }984 985 return vmiClassTypeInfo;986 }987 988 case Type::ObjCObject:989 cgm.errorNYI("VTableClassNameForType: ObjCObject");990 break;991 992 case Type::ObjCInterface:993 cgm.errorNYI("VTableClassNameForType: ObjCInterface");994 break;995 996 case Type::ObjCObjectPointer:997 case Type::Pointer:998 cgm.errorNYI("VTableClassNameForType: __pointer_type_info");999 break;1000 1001 case Type::MemberPointer:1002 cgm.errorNYI("VTableClassNameForType: __pointer_to_member_type_info");1003 break;1004 1005 case Type::HLSLAttributedResource:1006 case Type::HLSLInlineSpirv:1007 llvm_unreachable("HLSL doesn't support virtual functions");1008 }1009 1010 return nullptr;1011}1012} // namespace1013 1014/// Return the linkage that the type info and type info name constants1015/// should have for the given type.1016static cir::GlobalLinkageKind getTypeInfoLinkage(CIRGenModule &cgm,1017 QualType ty) {1018 // In addition, it and all of the intermediate abi::__pointer_type_info1019 // structs in the chain down to the abi::__class_type_info for the1020 // incomplete class type must be prevented from resolving to the1021 // corresponding type_info structs for the complete class type, possibly1022 // by making them local static objects. Finally, a dummy class RTTI is1023 // generated for the incomplete type that will not resolve to the final1024 // complete class RTTI (because the latter need not exist), possibly by1025 // making it a local static object.1026 if (containsIncompleteClassType(ty))1027 return cir::GlobalLinkageKind::InternalLinkage;1028 1029 switch (ty->getLinkage()) {1030 case Linkage::Invalid:1031 llvm_unreachable("Linkage hasn't been computed!");1032 1033 case Linkage::None:1034 case Linkage::Internal:1035 case Linkage::UniqueExternal:1036 return cir::GlobalLinkageKind::InternalLinkage;1037 1038 case Linkage::VisibleNone:1039 case Linkage::Module:1040 case Linkage::External:1041 // RTTI is not enabled, which means that this type info struct is going1042 // to be used for exception handling. Give it linkonce_odr linkage.1043 if (!cgm.getLangOpts().RTTI)1044 return cir::GlobalLinkageKind::LinkOnceODRLinkage;1045 1046 if (const RecordType *record = dyn_cast<RecordType>(ty)) {1047 const auto *rd =1048 cast<CXXRecordDecl>(record->getDecl())->getDefinitionOrSelf();1049 if (rd->hasAttr<WeakAttr>())1050 return cir::GlobalLinkageKind::WeakODRLinkage;1051 1052 if (cgm.getTriple().isWindowsItaniumEnvironment())1053 if (rd->hasAttr<DLLImportAttr>() &&1054 shouldUseExternalRttiDescriptor(cgm, ty))1055 return cir::GlobalLinkageKind::ExternalLinkage;1056 1057 // MinGW always uses LinkOnceODRLinkage for type info.1058 if (rd->isDynamicClass() && !cgm.getASTContext()1059 .getTargetInfo()1060 .getTriple()1061 .isWindowsGNUEnvironment())1062 return cgm.getVTableLinkage(rd);1063 }1064 1065 return cir::GlobalLinkageKind::LinkOnceODRLinkage;1066 }1067 1068 llvm_unreachable("Invalid linkage!");1069}1070 1071cir::GlobalOp1072CIRGenItaniumRTTIBuilder::getAddrOfTypeName(mlir::Location loc, QualType ty,1073 cir::GlobalLinkageKind linkage) {1074 CIRGenBuilderTy &builder = cgm.getBuilder();1075 SmallString<256> name;1076 llvm::raw_svector_ostream out(name);1077 cgm.getCXXABI().getMangleContext().mangleCXXRTTIName(ty, out);1078 1079 // We know that the mangled name of the type starts at index 4 of the1080 // mangled name of the typename, so we can just index into it in order to1081 // get the mangled name of the type.1082 mlir::Attribute init = builder.getString(1083 name.substr(4), cgm.convertType(cgm.getASTContext().CharTy),1084 std::nullopt);1085 1086 CharUnits align =1087 cgm.getASTContext().getTypeAlignInChars(cgm.getASTContext().CharTy);1088 1089 // builder.getString can return a #cir.zero if the string given to it only1090 // contains null bytes. However, type names cannot be full of null bytes.1091 // So cast Init to a ConstArrayAttr should be safe.1092 auto initStr = cast<cir::ConstArrayAttr>(init);1093 1094 cir::GlobalOp gv = cgm.createOrReplaceCXXRuntimeVariable(1095 loc, name, initStr.getType(), linkage, align);1096 CIRGenModule::setInitializer(gv, init);1097 return gv;1098}1099 1100mlir::Attribute1101CIRGenItaniumRTTIBuilder::getAddrOfExternalRTTIDescriptor(mlir::Location loc,1102 QualType ty) {1103 // Mangle the RTTI name.1104 SmallString<256> name;1105 llvm::raw_svector_ostream out(name);1106 cgm.getCXXABI().getMangleContext().mangleCXXRTTI(ty, out);1107 CIRGenBuilderTy &builder = cgm.getBuilder();1108 1109 // Look for an existing global.1110 cir::GlobalOp gv = dyn_cast_or_null<cir::GlobalOp>(1111 mlir::SymbolTable::lookupSymbolIn(cgm.getModule(), name));1112 1113 if (!gv) {1114 // Create a new global variable.1115 // From LLVM codegen => Note for the future: If we would ever like to do1116 // deferred emission of RTTI, check if emitting vtables opportunistically1117 // need any adjustment.1118 gv = CIRGenModule::createGlobalOp(cgm, loc, name, builder.getUInt8PtrTy(),1119 /*isConstant=*/true);1120 const CXXRecordDecl *rd = ty->getAsCXXRecordDecl();1121 cgm.setGVProperties(gv, rd);1122 1123 // Import the typeinfo symbol when all non-inline virtual methods are1124 // imported.1125 if (cgm.getTarget().hasPS4DLLImportExport()) {1126 cgm.errorNYI("getAddrOfExternalRTTIDescriptor: hasPS4DLLImportExport");1127 }1128 }1129 1130 return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv);1131}1132 1133void CIRGenItaniumRTTIBuilder::buildVTablePointer(mlir::Location loc,1134 const Type *ty) {1135 CIRGenBuilderTy &builder = cgm.getBuilder();1136 const char *vTableName = vTableClassNameForType(cgm, ty);1137 1138 // Check if the alias exists. If it doesn't, then get or create the global.1139 if (cgm.getItaniumVTableContext().isRelativeLayout()) {1140 cgm.errorNYI("buildVTablePointer: isRelativeLayout");1141 return;1142 }1143 1144 mlir::Type vtableGlobalTy = builder.getPointerTo(builder.getUInt8PtrTy());1145 llvm::Align align = cgm.getDataLayout().getABITypeAlign(vtableGlobalTy);1146 cir::GlobalOp vTable = cgm.createOrReplaceCXXRuntimeVariable(1147 loc, vTableName, vtableGlobalTy, cir::GlobalLinkageKind::ExternalLinkage,1148 CharUnits::fromQuantity(align));1149 1150 // The vtable address point is 2.1151 mlir::Attribute field{};1152 if (cgm.getItaniumVTableContext().isRelativeLayout()) {1153 cgm.errorNYI("buildVTablePointer: isRelativeLayout");1154 } else {1155 SmallVector<mlir::Attribute, 4> offsets{1156 cgm.getBuilder().getI32IntegerAttr(2)};1157 auto indices = mlir::ArrayAttr::get(builder.getContext(), offsets);1158 field = cgm.getBuilder().getGlobalViewAttr(cgm.getBuilder().getUInt8PtrTy(),1159 vTable, indices);1160 }1161 1162 assert(field && "expected attribute");1163 fields.push_back(field);1164}1165 1166/// Build an abi::__si_class_type_info, used for single inheritance, according1167/// to the Itanium C++ ABI, 2.95p6b.1168void CIRGenItaniumRTTIBuilder::buildSIClassTypeInfo(mlir::Location loc,1169 const CXXRecordDecl *rd) {1170 // Itanium C++ ABI 2.9.5p6b:1171 // It adds to abi::__class_type_info a single member pointing to the1172 // type_info structure for the base type,1173 mlir::Attribute baseTypeInfo =1174 CIRGenItaniumRTTIBuilder(cxxABI, cgm)1175 .buildTypeInfo(loc, rd->bases_begin()->getType());1176 fields.push_back(baseTypeInfo);1177}1178 1179/// Build an abi::__vmi_class_type_info, used for1180/// classes with bases that do not satisfy the abi::__si_class_type_info1181/// constraints, according to the Itanium C++ ABI, 2.9.5p5c.1182void CIRGenItaniumRTTIBuilder::buildVMIClassTypeInfo(mlir::Location loc,1183 const CXXRecordDecl *rd) {1184 mlir::Type unsignedIntLTy =1185 cgm.convertType(cgm.getASTContext().UnsignedIntTy);1186 1187 // Itanium C++ ABI 2.9.5p6c:1188 // __flags is a word with flags describing details about the class1189 // structure, which may be referenced by using the __flags_masks1190 // enumeration. These flags refer to both direct and indirect bases.1191 unsigned flags = computeVmiClassTypeInfoFlags(rd);1192 fields.push_back(cir::IntAttr::get(unsignedIntLTy, flags));1193 1194 // Itanium C++ ABI 2.9.5p6c:1195 // __base_count is a word with the number of direct proper base class1196 // descriptions that follow.1197 fields.push_back(cir::IntAttr::get(unsignedIntLTy, rd->getNumBases()));1198 1199 if (!rd->getNumBases())1200 return;1201 1202 // Now add the base class descriptions.1203 1204 // Itanium C++ ABI 2.9.5p6c:1205 // __base_info[] is an array of base class descriptions -- one for every1206 // direct proper base. Each description is of the type:1207 //1208 // struct abi::__base_class_type_info {1209 // public:1210 // const __class_type_info *__base_type;1211 // long __offset_flags;1212 //1213 // enum __offset_flags_masks {1214 // __virtual_mask = 0x1,1215 // __public_mask = 0x2,1216 // __offset_shift = 81217 // };1218 // };1219 1220 // If we're in mingw and 'long' isn't wide enough for a pointer, use 'long1221 // long' instead of 'long' for __offset_flags. libstdc++abi uses long long on1222 // LLP64 platforms.1223 // FIXME: Consider updating libc++abi to match, and extend this logic to all1224 // LLP64 platforms.1225 QualType offsetFlagsTy = cgm.getASTContext().LongTy;1226 const TargetInfo &ti = cgm.getASTContext().getTargetInfo();1227 if (ti.getTriple().isOSCygMing() &&1228 ti.getPointerWidth(LangAS::Default) > ti.getLongWidth())1229 offsetFlagsTy = cgm.getASTContext().LongLongTy;1230 mlir::Type offsetFlagsLTy = cgm.convertType(offsetFlagsTy);1231 1232 for (const CXXBaseSpecifier &base : rd->bases()) {1233 // The __base_type member points to the RTTI for the base type.1234 fields.push_back(CIRGenItaniumRTTIBuilder(cxxABI, cgm)1235 .buildTypeInfo(loc, base.getType()));1236 1237 CXXRecordDecl *baseDecl = base.getType()->castAsCXXRecordDecl();1238 int64_t offsetFlags = 0;1239 1240 // All but the lower 8 bits of __offset_flags are a signed offset.1241 // For a non-virtual base, this is the offset in the object of the base1242 // subobject. For a virtual base, this is the offset in the virtual table of1243 // the virtual base offset for the virtual base referenced (negative).1244 CharUnits offset;1245 if (base.isVirtual())1246 offset = cgm.getItaniumVTableContext().getVirtualBaseOffsetOffset(1247 rd, baseDecl);1248 else {1249 const ASTRecordLayout &layout =1250 cgm.getASTContext().getASTRecordLayout(rd);1251 offset = layout.getBaseClassOffset(baseDecl);1252 }1253 offsetFlags = uint64_t(offset.getQuantity()) << 8;1254 1255 // The low-order byte of __offset_flags contains flags, as given by the1256 // masks from the enumeration __offset_flags_masks.1257 if (base.isVirtual())1258 offsetFlags |= BCTI_Virtual;1259 if (base.getAccessSpecifier() == AS_public)1260 offsetFlags |= BCTI_Public;1261 1262 fields.push_back(cir::IntAttr::get(offsetFlagsLTy, offsetFlags));1263 }1264}1265 1266mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(mlir::Location loc,1267 QualType ty) {1268 // We want to operate on the canonical type.1269 ty = ty.getCanonicalType();1270 1271 // Check if we've already emitted an RTTI descriptor for this type.1272 SmallString<256> name;1273 llvm::raw_svector_ostream out(name);1274 cgm.getCXXABI().getMangleContext().mangleCXXRTTI(ty, out);1275 1276 auto oldGV = dyn_cast_or_null<cir::GlobalOp>(1277 mlir::SymbolTable::lookupSymbolIn(cgm.getModule(), name));1278 1279 if (oldGV && !oldGV.isDeclaration()) {1280 assert(!oldGV.hasAvailableExternallyLinkage() &&1281 "available_externally typeinfos not yet implemented");1282 return cgm.getBuilder().getGlobalViewAttr(cgm.getBuilder().getUInt8PtrTy(),1283 oldGV);1284 }1285 1286 // Check if there is already an external RTTI descriptor for this type.1287 if (isStandardLibraryRttiDescriptor(ty) ||1288 shouldUseExternalRttiDescriptor(cgm, ty))1289 return getAddrOfExternalRTTIDescriptor(loc, ty);1290 1291 // Emit the standard library with external linkage.1292 cir::GlobalLinkageKind linkage = getTypeInfoLinkage(cgm, ty);1293 1294 // Give the type_info object and name the formal visibility of the1295 // type itself.1296 assert(!cir::MissingFeatures::hiddenVisibility());1297 assert(!cir::MissingFeatures::protectedVisibility());1298 1299 mlir::SymbolTable::Visibility symVisibility;1300 if (cir::isLocalLinkage(linkage))1301 // If the linkage is local, only default visibility makes sense.1302 symVisibility = mlir::SymbolTable::Visibility::Public;1303 else if (cxxABI.classifyRTTIUniqueness(ty, linkage) ==1304 CIRGenItaniumCXXABI::RUK_NonUniqueHidden) {1305 cgm.errorNYI(1306 "buildTypeInfo: classifyRTTIUniqueness == RUK_NonUniqueHidden");1307 symVisibility = CIRGenModule::getMLIRVisibility(ty->getVisibility());1308 } else1309 symVisibility = CIRGenModule::getMLIRVisibility(ty->getVisibility());1310 1311 return buildTypeInfo(loc, ty, linkage, symVisibility);1312}1313 1314mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(1315 mlir::Location loc, QualType ty, cir::GlobalLinkageKind linkage,1316 mlir::SymbolTable::Visibility visibility) {1317 CIRGenBuilderTy &builder = cgm.getBuilder();1318 1319 assert(!cir::MissingFeatures::setDLLStorageClass());1320 1321 // Add the vtable pointer.1322 buildVTablePointer(loc, cast<Type>(ty));1323 1324 // And the name.1325 cir::GlobalOp typeName = getAddrOfTypeName(loc, ty, linkage);1326 mlir::Attribute typeNameField;1327 1328 // If we're supposed to demote the visibility, be sure to set a flag1329 // to use a string comparison for type_info comparisons.1330 CIRGenItaniumCXXABI::RTTIUniquenessKind rttiUniqueness =1331 cxxABI.classifyRTTIUniqueness(ty, linkage);1332 if (rttiUniqueness != CIRGenItaniumCXXABI::RUK_Unique) {1333 // The flag is the sign bit, which on ARM64 is defined to be clear1334 // for global pointers. This is very ARM64-specific.1335 cgm.errorNYI(1336 "buildTypeInfo: rttiUniqueness != CIRGenItaniumCXXABI::RUK_Unique");1337 } else {1338 typeNameField =1339 builder.getGlobalViewAttr(builder.getUInt8PtrTy(), typeName);1340 }1341 1342 fields.push_back(typeNameField);1343 1344 switch (ty->getTypeClass()) {1345#define TYPE(Class, Base)1346#define ABSTRACT_TYPE(Class, Base)1347#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:1348#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:1349#define DEPENDENT_TYPE(Class, Base) case Type::Class:1350#include "clang/AST/TypeNodes.inc"1351 llvm_unreachable("Non-canonical and dependent types shouldn't get here");1352 1353 // GCC treats vector types as fundamental types.1354 case Type::Builtin:1355 case Type::Vector:1356 case Type::ExtVector:1357 case Type::ConstantMatrix:1358 case Type::Complex:1359 case Type::BlockPointer:1360 // Itanium C++ ABI 2.9.5p4:1361 // abi::__fundamental_type_info adds no data members to std::type_info.1362 break;1363 1364 case Type::LValueReference:1365 case Type::RValueReference:1366 llvm_unreachable("References shouldn't get here");1367 1368 case Type::Auto:1369 case Type::DeducedTemplateSpecialization:1370 llvm_unreachable("Undeduced type shouldn't get here");1371 1372 case Type::Pipe:1373 break;1374 1375 case Type::BitInt:1376 break;1377 1378 case Type::ConstantArray:1379 case Type::IncompleteArray:1380 case Type::VariableArray:1381 case Type::ArrayParameter:1382 // Itanium C++ ABI 2.9.5p5:1383 // abi::__array_type_info adds no data members to std::type_info.1384 break;1385 1386 case Type::FunctionNoProto:1387 case Type::FunctionProto:1388 // Itanium C++ ABI 2.9.5p5:1389 // abi::__function_type_info adds no data members to std::type_info.1390 break;1391 1392 case Type::Enum:1393 // Itanium C++ ABI 2.9.5p5:1394 // abi::__enum_type_info adds no data members to std::type_info.1395 break;1396 1397 case Type::Record: {1398 const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl())1399 ->getDefinitionOrSelf();1400 if (!rd->hasDefinition() || !rd->getNumBases()) {1401 // We don't need to emit any fields.1402 break;1403 }1404 1405 if (canUseSingleInheritance(rd)) {1406 buildSIClassTypeInfo(loc, rd);1407 } else {1408 buildVMIClassTypeInfo(loc, rd);1409 }1410 1411 break;1412 }1413 1414 case Type::ObjCObject:1415 case Type::ObjCInterface:1416 cgm.errorNYI("buildTypeInfo: ObjCObject & ObjCInterface");1417 break;1418 1419 case Type::ObjCObjectPointer:1420 cgm.errorNYI("buildTypeInfo: ObjCObjectPointer");1421 break;1422 1423 case Type::Pointer:1424 cgm.errorNYI("buildTypeInfo: Pointer");1425 break;1426 1427 case Type::MemberPointer:1428 cgm.errorNYI("buildTypeInfo: MemberPointer");1429 break;1430 1431 case Type::Atomic:1432 // No fields, at least for the moment.1433 break;1434 1435 case Type::HLSLAttributedResource:1436 case Type::HLSLInlineSpirv:1437 llvm_unreachable("HLSL doesn't support RTTI");1438 }1439 1440 assert(!cir::MissingFeatures::opGlobalDLLImportExport());1441 cir::TypeInfoAttr init = builder.getTypeInfo(builder.getArrayAttr(fields));1442 1443 SmallString<256> name;1444 llvm::raw_svector_ostream out(name);1445 cgm.getCXXABI().getMangleContext().mangleCXXRTTI(ty, out);1446 1447 // Create new global and search for an existing global.1448 auto oldGV = dyn_cast_or_null<cir::GlobalOp>(1449 mlir::SymbolTable::lookupSymbolIn(cgm.getModule(), name));1450 1451 cir::GlobalOp gv =1452 CIRGenModule::createGlobalOp(cgm, loc, name, init.getType(),1453 /*isConstant=*/true);1454 1455 // Export the typeinfo in the same circumstances as the vtable is1456 // exported.1457 if (cgm.getTarget().hasPS4DLLImportExport()) {1458 cgm.errorNYI("buildTypeInfo: target hasPS4DLLImportExport");1459 return {};1460 }1461 1462 // If there's already an old global variable, replace it with the new one.1463 if (oldGV) {1464 // Replace occurrences of the old variable if needed.1465 gv.setName(oldGV.getName());1466 if (!oldGV->use_empty()) {1467 cgm.errorNYI("buildTypeInfo: old GV !use_empty");1468 return {};1469 }1470 oldGV->erase();1471 }1472 1473 if (cgm.supportsCOMDAT() && cir::isWeakForLinker(gv.getLinkage())) {1474 assert(!cir::MissingFeatures::setComdat());1475 cgm.errorNYI("buildTypeInfo: supportsCOMDAT & isWeakForLinker");1476 return {};1477 }1478 1479 CharUnits align = cgm.getASTContext().toCharUnitsFromBits(1480 cgm.getTarget().getPointerAlign(LangAS::Default));1481 gv.setAlignmentAttr(cgm.getSize(align));1482 1483 // The Itanium ABI specifies that type_info objects must be globally1484 // unique, with one exception: if the type is an incomplete class1485 // type or a (possibly indirect) pointer to one. That exception1486 // affects the general case of comparing type_info objects produced1487 // by the typeid operator, which is why the comparison operators on1488 // std::type_info generally use the type_info name pointers instead1489 // of the object addresses. However, the language's built-in uses1490 // of RTTI generally require class types to be complete, even when1491 // manipulating pointers to those class types. This allows the1492 // implementation of dynamic_cast to rely on address equality tests,1493 // which is much faster.1494 1495 // All of this is to say that it's important that both the type_info1496 // object and the type_info name be uniqued when weakly emitted.1497 1498 mlir::SymbolTable::setSymbolVisibility(typeName, visibility);1499 assert(!cir::MissingFeatures::setDLLStorageClass());1500 assert(!cir::MissingFeatures::opGlobalPartition());1501 assert(!cir::MissingFeatures::setDSOLocal());1502 1503 mlir::SymbolTable::setSymbolVisibility(gv, visibility);1504 assert(!cir::MissingFeatures::setDLLStorageClass());1505 assert(!cir::MissingFeatures::opGlobalPartition());1506 assert(!cir::MissingFeatures::setDSOLocal());1507 1508 CIRGenModule::setInitializer(gv, init);1509 return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv);1510}1511 1512mlir::Attribute CIRGenItaniumCXXABI::getAddrOfRTTIDescriptor(mlir::Location loc,1513 QualType ty) {1514 return CIRGenItaniumRTTIBuilder(*this, cgm).buildTypeInfo(loc, ty);1515}1516 1517/// What sort of uniqueness rules should we use for the RTTI for the1518/// given type?1519CIRGenItaniumCXXABI::RTTIUniquenessKind1520CIRGenItaniumCXXABI::classifyRTTIUniqueness(1521 QualType canTy, cir::GlobalLinkageKind linkage) const {1522 if (shouldRTTIBeUnique())1523 return RUK_Unique;1524 1525 // It's only necessary for linkonce_odr or weak_odr linkage.1526 if (linkage != cir::GlobalLinkageKind::LinkOnceODRLinkage &&1527 linkage != cir::GlobalLinkageKind::WeakODRLinkage)1528 return RUK_Unique;1529 1530 // It's only necessary with default visibility.1531 if (canTy->getVisibility() != DefaultVisibility)1532 return RUK_Unique;1533 1534 // If we're not required to publish this symbol, hide it.1535 if (linkage == cir::GlobalLinkageKind::LinkOnceODRLinkage)1536 return RUK_NonUniqueHidden;1537 1538 // If we're required to publish this symbol, as we might be under an1539 // explicit instantiation, leave it with default visibility but1540 // enable string-comparisons.1541 assert(linkage == cir::GlobalLinkageKind::WeakODRLinkage);1542 return RUK_NonUniqueVisible;1543}1544 1545void CIRGenItaniumCXXABI::emitDestructorCall(1546 CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,1547 bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy) {1548 GlobalDecl gd(dd, type);1549 mlir::Value vtt =1550 getCXXDestructorImplicitParam(cgf, dd, type, forVirtualBase, delegating);1551 ASTContext &astContext = cgm.getASTContext();1552 QualType vttTy = astContext.getPointerType(astContext.VoidPtrTy);1553 assert(!cir::MissingFeatures::appleKext());1554 CIRGenCallee callee =1555 CIRGenCallee::forDirect(cgm.getAddrOfCXXStructor(gd), gd);1556 1557 cgf.emitCXXDestructorCall(gd, callee, thisAddr.getPointer(), thisTy, vtt,1558 vttTy, nullptr);1559}1560 1561void CIRGenItaniumCXXABI::registerGlobalDtor(const VarDecl *vd,1562 cir::FuncOp dtor,1563 mlir::Value addr) {1564 if (vd->isNoDestroy(cgm.getASTContext()))1565 return;1566 1567 if (vd->getTLSKind()) {1568 cgm.errorNYI(vd->getSourceRange(), "registerGlobalDtor: TLS");1569 return;1570 }1571 1572 // HLSL doesn't support atexit.1573 if (cgm.getLangOpts().HLSL) {1574 cgm.errorNYI(vd->getSourceRange(), "registerGlobalDtor: HLSL");1575 return;1576 }1577 1578 // The default behavior is to use atexit. This is handled in lowering1579 // prepare. Nothing to be done for CIR here.1580}1581 1582mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam(1583 CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,1584 bool forVirtualBase, bool delegating) {1585 GlobalDecl gd(dd, type);1586 return cgf.getVTTParameter(gd, forVirtualBase, delegating);1587}1588 1589// The idea here is creating a separate block for the throw with an1590// `UnreachableOp` as the terminator. So, we branch from the current block1591// to the throw block and create a block for the remaining operations.1592static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc,1593 mlir::Value exceptionPtr = {},1594 mlir::FlatSymbolRefAttr typeInfo = {},1595 mlir::FlatSymbolRefAttr dtor = {}) {1596 mlir::Block *currentBlock = builder.getInsertionBlock();1597 mlir::Region *region = currentBlock->getParent();1598 1599 if (currentBlock->empty()) {1600 cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);1601 cir::UnreachableOp::create(builder, loc);1602 } else {1603 mlir::Block *throwBlock = builder.createBlock(region);1604 1605 cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);1606 cir::UnreachableOp::create(builder, loc);1607 1608 builder.setInsertionPointToEnd(currentBlock);1609 cir::BrOp::create(builder, loc, throwBlock);1610 }1611 1612 (void)builder.createBlock(region);1613}1614 1615void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) {1616 // void __cxa_rethrow();1617 if (isNoReturn) {1618 CIRGenBuilderTy &builder = cgf.getBuilder();1619 assert(cgf.currSrcLoc && "expected source location");1620 mlir::Location loc = *cgf.currSrcLoc;1621 insertThrowAndSplit(builder, loc);1622 } else {1623 cgm.errorNYI("emitRethrow with isNoReturn false");1624 }1625}1626 1627void CIRGenItaniumCXXABI::emitThrow(CIRGenFunction &cgf,1628 const CXXThrowExpr *e) {1629 // This differs a bit from LLVM codegen, CIR has native operations for some1630 // cxa functions, and defers allocation size computation, always pass the dtor1631 // symbol, etc. CIRGen also does not use getAllocateExceptionFn / getThrowFn.1632 1633 // Now allocate the exception object.1634 CIRGenBuilderTy &builder = cgf.getBuilder();1635 QualType clangThrowType = e->getSubExpr()->getType();1636 cir::PointerType throwTy =1637 builder.getPointerTo(cgf.convertType(clangThrowType));1638 uint64_t typeSize =1639 cgf.getContext().getTypeSizeInChars(clangThrowType).getQuantity();1640 mlir::Location subExprLoc = cgf.getLoc(e->getSubExpr()->getSourceRange());1641 1642 // Defer computing allocation size to some later lowering pass.1643 mlir::TypedValue<cir::PointerType> exceptionPtr =1644 cir::AllocExceptionOp::create(builder, subExprLoc, throwTy,1645 builder.getI64IntegerAttr(typeSize))1646 .getAddr();1647 1648 // Build expression and store its result into exceptionPtr.1649 CharUnits exnAlign = cgf.getContext().getExnObjectAlignment();1650 cgf.emitAnyExprToExn(e->getSubExpr(), Address(exceptionPtr, exnAlign));1651 1652 // Get the RTTI symbol address.1653 auto typeInfo = mlir::cast<cir::GlobalViewAttr>(1654 cgm.getAddrOfRTTIDescriptor(subExprLoc, clangThrowType,1655 /*forEH=*/true));1656 assert(!typeInfo.getIndices() && "expected no indirection");1657 1658 // The address of the destructor.1659 //1660 // Note: LLVM codegen already optimizes out the dtor if the1661 // type is a record with trivial dtor (by passing down a1662 // null dtor). In CIR, we forward this info and allow for1663 // Lowering pass to skip passing the trivial function.1664 //1665 if (const RecordType *recordTy = clangThrowType->getAs<RecordType>()) {1666 auto *rec = cast<CXXRecordDecl>(recordTy->getDecl()->getDefinition());1667 assert(!cir::MissingFeatures::isTrivialCtorOrDtor());1668 if (!rec->hasTrivialDestructor()) {1669 cgm.errorNYI("emitThrow: non-trivial destructor");1670 return;1671 }1672 }1673 1674 // Now throw the exception.1675 mlir::Location loc = cgf.getLoc(e->getSourceRange());1676 insertThrowAndSplit(builder, loc, exceptionPtr, typeInfo.getSymbol());1677}1678 1679CIRGenCXXABI *clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) {1680 switch (cgm.getASTContext().getCXXABIKind()) {1681 case TargetCXXABI::GenericItanium:1682 case TargetCXXABI::GenericAArch64:1683 return new CIRGenItaniumCXXABI(cgm);1684 1685 case TargetCXXABI::AppleARM64:1686 // The general Itanium ABI will do until we implement something that1687 // requires special handling.1688 assert(!cir::MissingFeatures::cxxabiAppleARM64CXXABI());1689 return new CIRGenItaniumCXXABI(cgm);1690 1691 default:1692 llvm_unreachable("bad or NYI ABI kind");1693 }1694}1695 1696cir::GlobalOp CIRGenItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *rd,1697 CharUnits vptrOffset) {1698 assert(vptrOffset.isZero() && "Itanium ABI only supports zero vptr offsets");1699 cir::GlobalOp &vtable = vtables[rd];1700 if (vtable)1701 return vtable;1702 1703 // Queue up this vtable for possible deferred emission.1704 assert(!cir::MissingFeatures::deferredVtables());1705 1706 SmallString<256> name;1707 llvm::raw_svector_ostream out(name);1708 getMangleContext().mangleCXXVTable(rd, out);1709 1710 const VTableLayout &vtLayout =1711 cgm.getItaniumVTableContext().getVTableLayout(rd);1712 mlir::Type vtableType = cgm.getVTables().getVTableType(vtLayout);1713 1714 // Use pointer alignment for the vtable. Otherwise we would align them based1715 // on the size of the initializer which doesn't make sense as only single1716 // values are read.1717 unsigned ptrAlign = cgm.getItaniumVTableContext().isRelativeLayout()1718 ? 321719 : cgm.getTarget().getPointerAlign(LangAS::Default);1720 1721 vtable = cgm.createOrReplaceCXXRuntimeVariable(1722 cgm.getLoc(rd->getSourceRange()), name, vtableType,1723 cir::GlobalLinkageKind::ExternalLinkage,1724 cgm.getASTContext().toCharUnitsFromBits(ptrAlign));1725 // LLVM codegen handles unnamedAddr1726 assert(!cir::MissingFeatures::opGlobalUnnamedAddr());1727 1728 // In MS C++ if you have a class with virtual functions in which you are using1729 // selective member import/export, then all virtual functions must be exported1730 // unless they are inline, otherwise a link error will result. To match this1731 // behavior, for such classes, we dllimport the vtable if it is defined1732 // externally and all the non-inline virtual methods are marked dllimport, and1733 // we dllexport the vtable if it is defined in this TU and all the non-inline1734 // virtual methods are marked dllexport.1735 if (cgm.getTarget().hasPS4DLLImportExport())1736 cgm.errorNYI(rd->getSourceRange(),1737 "getAddrOfVTable: PS4 DLL import/export");1738 1739 cgm.setGVProperties(vtable, rd);1740 return vtable;1741}1742 1743CIRGenCallee CIRGenItaniumCXXABI::getVirtualFunctionPointer(1744 CIRGenFunction &cgf, clang::GlobalDecl gd, Address thisAddr, mlir::Type ty,1745 SourceLocation srcLoc) {1746 CIRGenBuilderTy &builder = cgm.getBuilder();1747 mlir::Location loc = cgf.getLoc(srcLoc);1748 cir::PointerType tyPtr = builder.getPointerTo(ty);1749 auto *methodDecl = cast<CXXMethodDecl>(gd.getDecl());1750 mlir::Value vtable = cgf.getVTablePtr(loc, thisAddr, methodDecl->getParent());1751 1752 uint64_t vtableIndex = cgm.getItaniumVTableContext().getMethodVTableIndex(gd);1753 mlir::Value vfunc{};1754 if (cgf.shouldEmitVTableTypeCheckedLoad(methodDecl->getParent())) {1755 cgm.errorNYI(loc, "getVirtualFunctionPointer: emitVTableTypeCheckedLoad");1756 } else {1757 assert(!cir::MissingFeatures::emitTypeMetadataCodeForVCall());1758 1759 mlir::Value vfuncLoad;1760 if (cgm.getItaniumVTableContext().isRelativeLayout()) {1761 assert(!cir::MissingFeatures::vtableRelativeLayout());1762 cgm.errorNYI(loc, "getVirtualFunctionPointer: isRelativeLayout");1763 } else {1764 auto vtableSlotPtr = cir::VTableGetVirtualFnAddrOp::create(1765 builder, loc, builder.getPointerTo(tyPtr), vtable, vtableIndex);1766 vfuncLoad = builder.createAlignedLoad(loc, tyPtr, vtableSlotPtr,1767 cgf.getPointerAlign());1768 }1769 1770 // Add !invariant.load md to virtual function load to indicate that1771 // function didn't change inside vtable.1772 // It's safe to add it without -fstrict-vtable-pointers, but it would not1773 // help in devirtualization because it will only matter if we will have 21774 // the same virtual function loads from the same vtable load, which won't1775 // happen without enabled devirtualization with -fstrict-vtable-pointers.1776 if (cgm.getCodeGenOpts().OptimizationLevel > 0 &&1777 cgm.getCodeGenOpts().StrictVTablePointers) {1778 cgm.errorNYI(loc, "getVirtualFunctionPointer: strictVTablePointers");1779 }1780 vfunc = vfuncLoad;1781 }1782 1783 CIRGenCallee callee(gd, vfunc.getDefiningOp());1784 return callee;1785}1786 1787mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructorWithVTT(1788 CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,1789 const CXXRecordDecl *nearestVBase) {1790 assert((base.getBase()->getNumVBases() || nearestVBase != nullptr) &&1791 needsVTTParameter(cgf.curGD) && "This class doesn't have VTT");1792 1793 // Get the secondary vpointer index.1794 uint64_t virtualPointerIndex =1795 cgm.getVTables().getSecondaryVirtualPointerIndex(vtableClass, base);1796 1797 /// Load the VTT.1798 mlir::Value vttPtr = cgf.loadCXXVTT();1799 mlir::Location loc = cgf.getLoc(vtableClass->getSourceRange());1800 // Calculate the address point from the VTT, and the offset may be zero.1801 vttPtr = cgf.getBuilder().createVTTAddrPoint(loc, vttPtr.getType(), vttPtr,1802 virtualPointerIndex);1803 // And load the address point from the VTT.1804 auto vptrType = cir::VPtrType::get(cgf.getBuilder().getContext());1805 return cgf.getBuilder().createAlignedLoad(loc, vptrType, vttPtr,1806 cgf.getPointerAlign());1807}1808 1809mlir::Value1810CIRGenItaniumCXXABI::getVTableAddressPoint(BaseSubobject base,1811 const CXXRecordDecl *vtableClass) {1812 cir::GlobalOp vtable = getAddrOfVTable(vtableClass, CharUnits());1813 1814 // Find the appropriate vtable within the vtable group, and the address point1815 // within that vtable.1816 VTableLayout::AddressPointLocation addressPoint =1817 cgm.getItaniumVTableContext()1818 .getVTableLayout(vtableClass)1819 .getAddressPoint(base);1820 1821 mlir::OpBuilder &builder = cgm.getBuilder();1822 auto vtablePtrTy = cir::VPtrType::get(builder.getContext());1823 1824 return cir::VTableAddrPointOp::create(1825 builder, cgm.getLoc(vtableClass->getSourceRange()), vtablePtrTy,1826 mlir::FlatSymbolRefAttr::get(vtable.getSymNameAttr()),1827 cir::AddressPointAttr::get(cgm.getBuilder().getContext(),1828 addressPoint.VTableIndex,1829 addressPoint.AddressPointIndex));1830}1831 1832mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructor(1833 CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,1834 clang::BaseSubobject base, const clang::CXXRecordDecl *nearestVBase) {1835 1836 if ((base.getBase()->getNumVBases() || nearestVBase != nullptr) &&1837 needsVTTParameter(cgf.curGD)) {1838 return getVTableAddressPointInStructorWithVTT(cgf, vtableClass, base,1839 nearestVBase);1840 }1841 return getVTableAddressPoint(base, vtableClass);1842}1843 1844bool CIRGenItaniumCXXABI::isVirtualOffsetNeededForVTableField(1845 CIRGenFunction &cgf, CIRGenFunction::VPtr vptr) {1846 if (vptr.nearestVBase == nullptr)1847 return false;1848 return needsVTTParameter(cgf.curGD);1849}1850 1851mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset(1852 mlir::Location loc, CIRGenFunction &cgf, Address thisAddr,1853 const CXXRecordDecl *classDecl, const CXXRecordDecl *baseClassDecl) {1854 CIRGenBuilderTy &builder = cgf.getBuilder();1855 mlir::Value vtablePtr = cgf.getVTablePtr(loc, thisAddr, classDecl);1856 mlir::Value vtableBytePtr = builder.createBitcast(vtablePtr, cgm.uInt8PtrTy);1857 CharUnits vbaseOffsetOffset =1858 cgm.getItaniumVTableContext().getVirtualBaseOffsetOffset(classDecl,1859 baseClassDecl);1860 mlir::Value offsetVal =1861 builder.getSInt64(vbaseOffsetOffset.getQuantity(), loc);1862 auto vbaseOffsetPtr = cir::PtrStrideOp::create(builder, loc, cgm.uInt8PtrTy,1863 vtableBytePtr, offsetVal);1864 1865 mlir::Value vbaseOffset;1866 if (cgm.getItaniumVTableContext().isRelativeLayout()) {1867 assert(!cir::MissingFeatures::vtableRelativeLayout());1868 cgm.errorNYI(loc, "getVirtualBaseClassOffset: relative layout");1869 } else {1870 mlir::Value offsetPtr = builder.createBitcast(1871 vbaseOffsetPtr, builder.getPointerTo(cgm.ptrDiffTy));1872 vbaseOffset = builder.createLoad(1873 loc, Address(offsetPtr, cgm.ptrDiffTy, cgf.getPointerAlign()));1874 }1875 return vbaseOffset;1876}1877 1878static cir::FuncOp getBadCastFn(CIRGenFunction &cgf) {1879 // Prototype: void __cxa_bad_cast();1880 1881 // TODO(cir): set the calling convention of the runtime function.1882 assert(!cir::MissingFeatures::opFuncCallingConv());1883 1884 cir::FuncType fnTy =1885 cgf.getBuilder().getFuncType({}, cgf.getBuilder().getVoidTy());1886 return cgf.cgm.createRuntimeFunction(fnTy, "__cxa_bad_cast");1887}1888 1889static void emitCallToBadCast(CIRGenFunction &cgf, mlir::Location loc) {1890 // TODO(cir): set the calling convention to the runtime function.1891 assert(!cir::MissingFeatures::opFuncCallingConv());1892 1893 cgf.emitRuntimeCall(loc, getBadCastFn(cgf));1894 cir::UnreachableOp::create(cgf.getBuilder(), loc);1895 cgf.getBuilder().clearInsertionPoint();1896}1897 1898void CIRGenItaniumCXXABI::emitBadCastCall(CIRGenFunction &cgf,1899 mlir::Location loc) {1900 emitCallToBadCast(cgf, loc);1901}1902 1903// TODO(cir): This could be shared with classic codegen.1904static CharUnits computeOffsetHint(ASTContext &astContext,1905 const CXXRecordDecl *src,1906 const CXXRecordDecl *dst) {1907 CXXBasePaths paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,1908 /*DetectVirtual=*/false);1909 1910 // If Dst is not derived from Src we can skip the whole computation below and1911 // return that Src is not a public base of Dst. Record all inheritance paths.1912 if (!dst->isDerivedFrom(src, paths))1913 return CharUnits::fromQuantity(-2ULL);1914 1915 unsigned numPublicPaths = 0;1916 CharUnits offset;1917 1918 // Now walk all possible inheritance paths.1919 for (const CXXBasePath &path : paths) {1920 if (path.Access != AS_public) // Ignore non-public inheritance.1921 continue;1922 1923 ++numPublicPaths;1924 1925 for (const CXXBasePathElement &pathElement : path) {1926 // If the path contains a virtual base class we can't give any hint.1927 // -1: no hint.1928 if (pathElement.Base->isVirtual())1929 return CharUnits::fromQuantity(-1ULL);1930 1931 if (numPublicPaths > 1) // Won't use offsets, skip computation.1932 continue;1933 1934 // Accumulate the base class offsets.1935 const ASTRecordLayout &L =1936 astContext.getASTRecordLayout(pathElement.Class);1937 offset += L.getBaseClassOffset(1938 pathElement.Base->getType()->getAsCXXRecordDecl());1939 }1940 }1941 1942 // -2: Src is not a public base of Dst.1943 if (numPublicPaths == 0)1944 return CharUnits::fromQuantity(-2ULL);1945 1946 // -3: Src is a multiple public base type but never a virtual base type.1947 if (numPublicPaths > 1)1948 return CharUnits::fromQuantity(-3ULL);1949 1950 // Otherwise, the Src type is a unique public nonvirtual base type of Dst.1951 // Return the offset of Src from the origin of Dst.1952 return offset;1953}1954 1955static cir::FuncOp getItaniumDynamicCastFn(CIRGenFunction &cgf) {1956 // Prototype:1957 // void *__dynamic_cast(const void *sub,1958 // global_as const abi::__class_type_info *src,1959 // global_as const abi::__class_type_info *dst,1960 // std::ptrdiff_t src2dst_offset);1961 1962 mlir::Type voidPtrTy = cgf.getBuilder().getVoidPtrTy();1963 mlir::Type rttiPtrTy = cgf.getBuilder().getUInt8PtrTy();1964 mlir::Type ptrDiffTy = cgf.convertType(cgf.getContext().getPointerDiffType());1965 1966 // TODO(cir): mark the function as nowind willreturn readonly.1967 assert(!cir::MissingFeatures::opFuncNoUnwind());1968 assert(!cir::MissingFeatures::opFuncWillReturn());1969 assert(!cir::MissingFeatures::opFuncReadOnly());1970 1971 // TODO(cir): set the calling convention of the runtime function.1972 assert(!cir::MissingFeatures::opFuncCallingConv());1973 1974 cir::FuncType FTy = cgf.getBuilder().getFuncType(1975 {voidPtrTy, rttiPtrTy, rttiPtrTy, ptrDiffTy}, voidPtrTy);1976 return cgf.cgm.createRuntimeFunction(FTy, "__dynamic_cast");1977}1978 1979static Address emitDynamicCastToVoid(CIRGenFunction &cgf, mlir::Location loc,1980 QualType srcRecordTy, Address src) {1981 bool vtableUsesRelativeLayout =1982 cgf.cgm.getItaniumVTableContext().isRelativeLayout();1983 mlir::Value ptr = cgf.getBuilder().createDynCastToVoid(1984 loc, src.getPointer(), vtableUsesRelativeLayout);1985 return Address{ptr, src.getAlignment()};1986}1987 1988static mlir::Value emitExactDynamicCast(CIRGenItaniumCXXABI &abi,1989 CIRGenFunction &cgf, mlir::Location loc,1990 QualType srcRecordTy,1991 QualType destRecordTy,1992 cir::PointerType destCIRTy,1993 bool isRefCast, Address src) {1994 // Find all the inheritance paths from SrcRecordTy to DestRecordTy.1995 const CXXRecordDecl *srcDecl = srcRecordTy->getAsCXXRecordDecl();1996 const CXXRecordDecl *destDecl = destRecordTy->getAsCXXRecordDecl();1997 CXXBasePaths paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,1998 /*DetectVirtual=*/false);1999 (void)destDecl->isDerivedFrom(srcDecl, paths);2000 2001 // Find an offset within `destDecl` where a `srcDecl` instance and its vptr2002 // might appear.2003 std::optional<CharUnits> offset;2004 for (const CXXBasePath &path : paths) {2005 // dynamic_cast only finds public inheritance paths.2006 if (path.Access != AS_public)2007 continue;2008 2009 CharUnits pathOffset;2010 for (const CXXBasePathElement &pathElement : path) {2011 // Find the offset along this inheritance step.2012 const CXXRecordDecl *base =2013 pathElement.Base->getType()->getAsCXXRecordDecl();2014 if (pathElement.Base->isVirtual()) {2015 // For a virtual base class, we know that the derived class is exactly2016 // destDecl, so we can use the vbase offset from its layout.2017 const ASTRecordLayout &layout =2018 cgf.getContext().getASTRecordLayout(destDecl);2019 pathOffset = layout.getVBaseClassOffset(base);2020 } else {2021 const ASTRecordLayout &layout =2022 cgf.getContext().getASTRecordLayout(pathElement.Class);2023 pathOffset += layout.getBaseClassOffset(base);2024 }2025 }2026 2027 if (!offset) {2028 offset = pathOffset;2029 } else if (offset != pathOffset) {2030 // base appears in at least two different places. Find the most-derived2031 // object and see if it's a DestDecl. Note that the most-derived object2032 // must be at least as aligned as this base class subobject, and must2033 // have a vptr at offset 0.2034 src = emitDynamicCastToVoid(cgf, loc, srcRecordTy, src);2035 srcDecl = destDecl;2036 offset = CharUnits::Zero();2037 break;2038 }2039 }2040 2041 CIRGenBuilderTy &builder = cgf.getBuilder();2042 2043 if (!offset) {2044 // If there are no public inheritance paths, the cast always fails.2045 mlir::Value nullPtrValue = builder.getNullPtr(destCIRTy, loc);2046 if (isRefCast) {2047 mlir::Region *currentRegion = builder.getBlock()->getParent();2048 emitCallToBadCast(cgf, loc);2049 2050 // The call to bad_cast will terminate the block. Create a new block to2051 // hold any follow up code.2052 builder.createBlock(currentRegion, currentRegion->end());2053 }2054 2055 return nullPtrValue;2056 }2057 2058 // Compare the vptr against the expected vptr for the destination type at2059 // this offset. Note that we do not know what type src points to in the case2060 // where the derived class multiply inherits from the base class so we can't2061 // use getVTablePtr, so we load the vptr directly instead.2062 2063 mlir::Value expectedVPtr =2064 abi.getVTableAddressPoint(BaseSubobject(srcDecl, *offset), destDecl);2065 2066 // TODO(cir): handle address space here.2067 assert(!cir::MissingFeatures::addressSpace());2068 mlir::Type vptrTy = expectedVPtr.getType();2069 mlir::Type vptrPtrTy = builder.getPointerTo(vptrTy);2070 Address srcVPtrPtr(builder.createBitcast(src.getPointer(), vptrPtrTy),2071 src.getAlignment());2072 mlir::Value srcVPtr = builder.createLoad(loc, srcVPtrPtr);2073 2074 // TODO(cir): decorate SrcVPtr with TBAA info.2075 assert(!cir::MissingFeatures::opTBAA());2076 2077 mlir::Value success =2078 builder.createCompare(loc, cir::CmpOpKind::eq, srcVPtr, expectedVPtr);2079 2080 auto emitCastResult = [&] {2081 if (offset->isZero())2082 return builder.createBitcast(src.getPointer(), destCIRTy);2083 2084 // TODO(cir): handle address space here.2085 assert(!cir::MissingFeatures::addressSpace());2086 mlir::Type u8PtrTy = builder.getUInt8PtrTy();2087 2088 mlir::Value strideToApply =2089 builder.getConstInt(loc, builder.getUInt64Ty(), -offset->getQuantity());2090 mlir::Value srcU8Ptr = builder.createBitcast(src.getPointer(), u8PtrTy);2091 mlir::Value resultU8Ptr = cir::PtrStrideOp::create(builder, loc, u8PtrTy,2092 srcU8Ptr, strideToApply);2093 return builder.createBitcast(resultU8Ptr, destCIRTy);2094 };2095 2096 if (isRefCast) {2097 mlir::Value failed = builder.createNot(success);2098 cir::IfOp::create(builder, loc, failed, /*withElseRegion=*/false,2099 [&](mlir::OpBuilder &, mlir::Location) {2100 emitCallToBadCast(cgf, loc);2101 });2102 return emitCastResult();2103 }2104 2105 return cir::TernaryOp::create(2106 builder, loc, success,2107 [&](mlir::OpBuilder &, mlir::Location) {2108 auto result = emitCastResult();2109 builder.createYield(loc, result);2110 },2111 [&](mlir::OpBuilder &, mlir::Location) {2112 mlir::Value nullPtrValue = builder.getNullPtr(destCIRTy, loc);2113 builder.createYield(loc, nullPtrValue);2114 })2115 .getResult();2116}2117 2118static cir::DynamicCastInfoAttr emitDynamicCastInfo(CIRGenFunction &cgf,2119 mlir::Location loc,2120 QualType srcRecordTy,2121 QualType destRecordTy) {2122 auto srcRtti = mlir::cast<cir::GlobalViewAttr>(2123 cgf.cgm.getAddrOfRTTIDescriptor(loc, srcRecordTy));2124 auto destRtti = mlir::cast<cir::GlobalViewAttr>(2125 cgf.cgm.getAddrOfRTTIDescriptor(loc, destRecordTy));2126 2127 cir::FuncOp runtimeFuncOp = getItaniumDynamicCastFn(cgf);2128 cir::FuncOp badCastFuncOp = getBadCastFn(cgf);2129 auto runtimeFuncRef = mlir::FlatSymbolRefAttr::get(runtimeFuncOp);2130 auto badCastFuncRef = mlir::FlatSymbolRefAttr::get(badCastFuncOp);2131 2132 const CXXRecordDecl *srcDecl = srcRecordTy->getAsCXXRecordDecl();2133 const CXXRecordDecl *destDecl = destRecordTy->getAsCXXRecordDecl();2134 CharUnits offsetHint = computeOffsetHint(cgf.getContext(), srcDecl, destDecl);2135 2136 mlir::Type ptrdiffTy = cgf.convertType(cgf.getContext().getPointerDiffType());2137 auto offsetHintAttr = cir::IntAttr::get(ptrdiffTy, offsetHint.getQuantity());2138 2139 return cir::DynamicCastInfoAttr::get(srcRtti, destRtti, runtimeFuncRef,2140 badCastFuncRef, offsetHintAttr);2141}2142 2143mlir::Value CIRGenItaniumCXXABI::emitDynamicCast(CIRGenFunction &cgf,2144 mlir::Location loc,2145 QualType srcRecordTy,2146 QualType destRecordTy,2147 cir::PointerType destCIRTy,2148 bool isRefCast, Address src) {2149 bool isCastToVoid = destRecordTy.isNull();2150 assert((!isCastToVoid || !isRefCast) && "cannot cast to void reference");2151 2152 if (isCastToVoid)2153 return emitDynamicCastToVoid(cgf, loc, srcRecordTy, src).getPointer();2154 2155 // If the destination is effectively final, the cast succeeds if and only2156 // if the dynamic type of the pointer is exactly the destination type.2157 if (destRecordTy->getAsCXXRecordDecl()->isEffectivelyFinal() &&2158 cgf.cgm.getCodeGenOpts().OptimizationLevel > 0) {2159 CIRGenBuilderTy &builder = cgf.getBuilder();2160 // If this isn't a reference cast, check the pointer to see if it's null.2161 if (!isRefCast) {2162 mlir::Value srcPtrIsNull = builder.createPtrIsNull(src.getPointer());2163 return cir::TernaryOp::create(2164 builder, loc, srcPtrIsNull,2165 [&](mlir::OpBuilder, mlir::Location) {2166 builder.createYield(2167 loc, builder.getNullPtr(destCIRTy, loc).getResult());2168 },2169 [&](mlir::OpBuilder &, mlir::Location) {2170 mlir::Value exactCast = emitExactDynamicCast(2171 *this, cgf, loc, srcRecordTy, destRecordTy, destCIRTy,2172 isRefCast, src);2173 builder.createYield(loc, exactCast);2174 })2175 .getResult();2176 }2177 2178 return emitExactDynamicCast(*this, cgf, loc, srcRecordTy, destRecordTy,2179 destCIRTy, isRefCast, src);2180 }2181 2182 cir::DynamicCastInfoAttr castInfo =2183 emitDynamicCastInfo(cgf, loc, srcRecordTy, destRecordTy);2184 return cgf.getBuilder().createDynCast(loc, src.getPointer(), destCIRTy,2185 isRefCast, castInfo);2186}2187 2188/// The Itanium ABI always places an offset to the complete object2189/// at entry -2 in the vtable.2190void CIRGenItaniumCXXABI::emitVirtualObjectDelete(2191 CIRGenFunction &cgf, const CXXDeleteExpr *delExpr, Address ptr,2192 QualType elementType, const CXXDestructorDecl *dtor) {2193 bool useGlobalDelete = delExpr->isGlobalDelete();2194 if (useGlobalDelete) {2195 cgf.cgm.errorNYI(delExpr->getSourceRange(),2196 "emitVirtualObjectDelete: global delete");2197 }2198 2199 CXXDtorType dtorType = useGlobalDelete ? Dtor_Complete : Dtor_Deleting;2200 emitVirtualDestructorCall(cgf, dtor, dtorType, ptr, delExpr);2201}2202 2203/************************** Array allocation cookies **************************/2204 2205CharUnits CIRGenItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {2206 // The array cookie is a size_t; pad that up to the element alignment.2207 // The cookie is actually right-justified in that space.2208 return std::max(2209 cgm.getSizeSize(),2210 cgm.getASTContext().getPreferredTypeAlignInChars(elementType));2211}2212 2213Address CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,2214 Address newPtr,2215 mlir::Value numElements,2216 const CXXNewExpr *e,2217 QualType elementType) {2218 assert(requiresArrayCookie(e));2219 2220 // TODO: When sanitizer support is implemented, we'll need to2221 // get the address space from `newPtr`.2222 assert(!cir::MissingFeatures::addressSpace());2223 assert(!cir::MissingFeatures::sanitizers());2224 2225 ASTContext &ctx = cgm.getASTContext();2226 CharUnits sizeSize = cgf.getSizeSize();2227 mlir::Location loc = cgf.getLoc(e->getSourceRange());2228 2229 // The size of the cookie.2230 CharUnits cookieSize =2231 std::max(sizeSize, ctx.getPreferredTypeAlignInChars(elementType));2232 assert(cookieSize == getArrayCookieSizeImpl(elementType));2233 2234 cir::PointerType u8PtrTy = cgf.getBuilder().getUInt8PtrTy();2235 mlir::Value baseBytePtr =2236 cgf.getBuilder().createPtrBitcast(newPtr.getPointer(), u8PtrTy);2237 2238 // Compute an offset to the cookie.2239 CharUnits cookieOffset = cookieSize - sizeSize;2240 mlir::Value cookiePtrValue = baseBytePtr;2241 if (!cookieOffset.isZero()) {2242 mlir::Value offsetOp = cgf.getBuilder().getSignedInt(2243 loc, cookieOffset.getQuantity(), /*width=*/32);2244 cookiePtrValue =2245 cgf.getBuilder().createPtrStride(loc, cookiePtrValue, offsetOp);2246 }2247 2248 CharUnits baseAlignment = newPtr.getAlignment();2249 CharUnits cookiePtrAlignment = baseAlignment.alignmentAtOffset(cookieOffset);2250 Address cookiePtr(cookiePtrValue, u8PtrTy, cookiePtrAlignment);2251 2252 // Write the number of elements into the appropriate slot.2253 Address numElementsPtr =2254 cookiePtr.withElementType(cgf.getBuilder(), cgf.sizeTy);2255 cgf.getBuilder().createStore(loc, numElements, numElementsPtr);2256 2257 // Finally, compute a pointer to the actual data buffer by skipping2258 // over the cookie completely.2259 mlir::Value dataOffset =2260 cgf.getBuilder().getSignedInt(loc, cookieSize.getQuantity(),2261 /*width=*/32);2262 mlir::Value dataPtr =2263 cgf.getBuilder().createPtrStride(loc, baseBytePtr, dataOffset);2264 mlir::Value finalPtr =2265 cgf.getBuilder().createPtrBitcast(dataPtr, newPtr.getElementType());2266 CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);2267 return Address(finalPtr, newPtr.getElementType(), finalAlignment);2268}2269