clang 24.0.0git
CIRGenItaniumCXXABI.cpp
Go to the documentation of this file.
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"
25#include "clang/AST/Mangle.h"
26#include "clang/AST/TypeBase.h"
30#include "llvm/ADT/SmallString.h"
31#include "llvm/Support/ErrorHandling.h"
32#include "llvm/Support/raw_ostream.h"
33
34using namespace clang;
35using namespace clang::CIRGen;
36
37namespace {
38
39class CIRGenItaniumCXXABI : public CIRGenCXXABI {
40protected:
41 /// All the vtables which have been defined.
42 llvm::DenseMap<const CXXRecordDecl *, cir::GlobalOp> vtables;
43
44public:
45 CIRGenItaniumCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) {
48 }
49
50 AddedStructorArgs getImplicitConstructorArgs(CIRGenFunction &cgf,
51 const CXXConstructorDecl *d,
53 bool forVirtualBase,
54 bool delegating) override;
55
56 bool needsVTTParameter(clang::GlobalDecl gd) override;
57
58 AddedStructorArgCounts
59 buildStructorSignature(GlobalDecl gd,
60 llvm::SmallVectorImpl<CanQualType> &argTys) override;
61
62 void emitInstanceFunctionProlog(SourceLocation loc,
63 CIRGenFunction &cgf) override;
64
65 void addImplicitStructorParams(CIRGenFunction &cgf, QualType &resTy,
66 FunctionArgList &params) override;
67 mlir::Value getCXXDestructorImplicitParam(CIRGenFunction &cgf,
68 const CXXDestructorDecl *dd,
70 bool forVirtualBase,
71 bool delegating) override;
72 void emitCXXConstructors(const clang::CXXConstructorDecl *d) override;
73 void emitCXXDestructors(const clang::CXXDestructorDecl *d) override;
74 void emitCXXStructor(clang::GlobalDecl gd) override;
75
76 void emitDestructorCall(CIRGenFunction &cgf, const CXXDestructorDecl *dd,
77 CXXDtorType type, bool forVirtualBase,
78 bool delegating, Address thisAddr,
79 QualType thisTy) override;
80 void registerGlobalDtor(const VarDecl *vd, cir::FuncOp dtor,
81 mlir::Value addr) override;
82 void emitVirtualObjectDelete(CIRGenFunction &cgf, const CXXDeleteExpr *de,
83 Address ptr, QualType elementType,
84 const CXXDestructorDecl *dtor) override;
85
86 void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
87 void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
88
89 bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
90 CXXDtorType dt) const override {
91 // Itanium does not emit any destructor variant as an inline thunk.
92 // Delegating may occur as an optimization, but all variants are either
93 // emitted with external linkage or as linkonce if they are inline and used.
94 return false;
95 }
96
97 bool isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf,
98 CIRGenFunction::VPtr vptr) override;
99
100 cir::GlobalOp getAddrOfVTable(const CXXRecordDecl *rd,
101 CharUnits vptrOffset) override;
102 CIRGenCallee getVirtualFunctionPointer(CIRGenFunction &cgf,
103 clang::GlobalDecl gd, Address thisAddr,
104 mlir::Type ty,
105 SourceLocation loc) override;
106 mlir::Value emitVirtualDestructorCall(CIRGenFunction &cgf,
107 const CXXDestructorDecl *dtor,
108 CXXDtorType dtorType, Address thisAddr,
109 DeleteOrMemberCallExpr e) override;
110
111 bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const override;
112 bool canSpeculativelyEmitVTableAsBaseClass(const CXXRecordDecl *RD) const;
113
114 mlir::Value getVTableAddressPoint(BaseSubobject base,
115 const CXXRecordDecl *vtableClass) override;
116 mlir::Value getVTableAddressPointInStructorWithVTT(
117 CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,
118 const CXXRecordDecl *nearestVBase);
119
120 mlir::Value getVTableAddressPointInStructor(
121 CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
122 clang::BaseSubobject base,
123 const clang::CXXRecordDecl *nearestVBase) override;
124 void emitVTableDefinitions(CIRGenVTables &cgvt,
125 const CXXRecordDecl *rd) override;
126 void emitVirtualInheritanceTables(const CXXRecordDecl *rd) override;
127
128 void setThunkLinkage(cir::FuncOp thunk, bool forVTable, GlobalDecl gd,
129 bool returnAdjustment) override {
130 if (forVTable && !thunk.hasLocalLinkage())
131 thunk.setLinkage(cir::GlobalLinkageKind::AvailableExternallyLinkage);
132 const auto *nd = cast<NamedDecl>(gd.getDecl());
133 cgm.setGVProperties(thunk, nd);
134 }
135
136 bool exportThunk() override { return true; }
137
138 mlir::Value performThisAdjustment(CIRGenFunction &cgf, Address thisAddr,
139 const CXXRecordDecl *unadjustedClass,
140 const ThunkInfo &ti) override;
141
142 mlir::Value performReturnAdjustment(CIRGenFunction &cgf, Address ret,
143 const CXXRecordDecl *unadjustedClass,
144 const ReturnAdjustment &ra) override;
145
146 bool shouldTypeidBeNullChecked(QualType srcTy) override;
147 mlir::Value emitTypeid(CIRGenFunction &cgf, QualType SrcRecordTy,
148 Address thisPtr, mlir::Type StdTypeInfoPtrTy) override;
149 void emitBadTypeidCall(CIRGenFunction &cgf, mlir::Location loc) override;
150
151 mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
152 QualType ty) override;
153
154 StringRef getPureVirtualCallName() override { return "__cxa_pure_virtual"; }
155 StringRef getDeletedVirtualCallName() override {
156 return "__cxa_deleted_virtual";
157 }
158
159 CatchTypeInfo
160 getAddrOfCXXCatchHandlerType(mlir::Location loc, QualType ty,
161 QualType catchHandlerType) override {
162 auto rtti = dyn_cast<cir::GlobalViewAttr>(getAddrOfRTTIDescriptor(loc, ty));
163 assert(rtti && "expected GlobalViewAttr");
164 return CatchTypeInfo{rtti, 0};
165 }
166
167 bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
168 return true;
169 }
170
171 size_t getSrcArgforCopyCtor(const CXXConstructorDecl *,
172 FunctionArgList &args) const override {
173 assert(!args.empty() && "expected the arglist to not be empty!");
174 return args.size() - 1;
175 }
176
177 void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) override;
178
179 mlir::Value
180 getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf,
181 Address thisAddr, const CXXRecordDecl *classDecl,
182 const CXXRecordDecl *baseClassDecl) override;
183
184 // The traditional clang CodeGen emits calls to `__dynamic_cast` directly into
185 // LLVM in the `emitDynamicCastCall` function. In CIR, `dynamic_cast`
186 // expressions are lowered to `cir.dyn_cast` ops instead of calls to runtime
187 // functions. So during CIRGen we don't need the `emitDynamicCastCall`
188 // function that clang CodeGen has.
189 mlir::Value emitDynamicCast(CIRGenFunction &cgf, mlir::Location loc,
190 QualType srcRecordTy, QualType destRecordTy,
191 cir::PointerType destCIRTy, bool isRefCast,
192 Address src) override;
193
194 cir::MethodAttr buildVirtualMethodAttr(cir::MethodType methodTy,
195 const CXXMethodDecl *md) override;
196
197 Address initializeArrayCookie(CIRGenFunction &cgf, Address newPtr,
198 mlir::Value numElements, const CXXNewExpr *e,
199 QualType elementType) override;
200
201 bool isZeroInitializable(const MemberPointerType *MPT) override;
202
203protected:
204 CharUnits getArrayCookieSizeImpl(QualType elementType) override;
205
206 /**************************** RTTI Uniqueness ******************************/
207 /// Returns true if the ABI requires RTTI type_info objects to be unique
208 /// across a program.
209 virtual bool shouldRTTIBeUnique() const { return true; }
210
211public:
212 /// What sort of unique-RTTI behavior should we use?
213 enum RTTIUniquenessKind {
214 /// We are guaranteeing, or need to guarantee, that the RTTI string
215 /// is unique.
216 RUK_Unique,
217
218 /// We are not guaranteeing uniqueness for the RTTI string, so we
219 /// can demote to hidden visibility but must use string comparisons.
220 RUK_NonUniqueHidden,
221
222 /// We are not guaranteeing uniqueness for the RTTI string, so we
223 /// have to use string comparisons, but we also have to emit it with
224 /// non-hidden visibility.
225 RUK_NonUniqueVisible
226 };
227
228 /// Return the required visibility status for the given type and linkage in
229 /// the current ABI.
230 RTTIUniquenessKind
231 classifyRTTIUniqueness(QualType canTy, cir::GlobalLinkageKind linkage) const;
232
233private:
234 bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *rd) const;
235 bool isVTableHidden(const CXXRecordDecl *rd) const;
236};
237
238} // namespace
239
240void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc,
241 CIRGenFunction &cgf) {
242 // Naked functions have no prolog.
243 if (cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<NakedAttr>()) {
245 "emitInstanceFunctionProlog: Naked");
246 }
247
248 /// Initialize the 'this' slot. In the Itanium C++ ABI, no prologue
249 /// adjustments are required, because they are all handled by thunks.
250 setCXXABIThisValue(cgf, loadIncomingCXXThis(cgf));
251
252 /// Initialize the 'vtt' slot if needed.
253 if (getStructorImplicitParamDecl(cgf)) {
254 cir::LoadOp val = cgf.getBuilder().createLoad(
255 cgf.getLoc(loc),
256 cgf.getAddrOfLocalVar(getStructorImplicitParamDecl(cgf)));
257 setStructorImplicitParamValue(cgf, val);
258 }
259
260 /// If this is a function that the ABI specifies returns 'this', initialize
261 /// the return slot to this' at the start of the function.
262 ///
263 /// Unlike the setting of return types, this is done within the ABI
264 /// implementation instead of by clients of CIRGenCXXBI because:
265 /// 1) getThisValue is currently protected
266 /// 2) in theory, an ABI could implement 'this' returns some other way;
267 /// HasThisReturn only specifies a contract, not the implementation
268 if (hasThisReturn(cgf.curGD)) {
270 "emitInstanceFunctionProlog: hasThisReturn");
271 }
272}
273
274CIRGenCXXABI::AddedStructorArgCounts
275CIRGenItaniumCXXABI::buildStructorSignature(
276 GlobalDecl gd, llvm::SmallVectorImpl<CanQualType> &argTys) {
277 clang::ASTContext &astContext = cgm.getASTContext();
278
279 // All parameters are already in place except VTT, which goes after 'this'.
280 // These are clang types, so we don't need to worry about sret yet.
281
282 // Check if we need to add a VTT parameter (which has type void **).
284 : gd.getDtorType() == Dtor_Base) &&
285 cast<CXXMethodDecl>(gd.getDecl())->getParent()->getNumVBases() != 0) {
287 argTys.insert(argTys.begin() + 1,
288 astContext.getPointerType(
290 return AddedStructorArgCounts::withPrefix(1);
291 }
292
293 return AddedStructorArgCounts{};
294}
295
296// Find out how to cirgen the complete destructor and constructor
297namespace {
298enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT };
299}
300
301static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm,
302 const CXXMethodDecl *md) {
303 if (!cgm.getCodeGenOpts().CXXCtorDtorAliases)
304 return StructorCIRGen::Emit;
305
306 // The complete and base structors are not equivalent if there are any virtual
307 // bases, so emit separate functions.
308 if (md->getParent()->getNumVBases())
309 return StructorCIRGen::Emit;
310
311 GlobalDecl aliasDecl;
312 if (const auto *dd = dyn_cast<CXXDestructorDecl>(md)) {
313 aliasDecl = GlobalDecl(dd, Dtor_Complete);
314 } else {
315 const auto *cd = cast<CXXConstructorDecl>(md);
316 aliasDecl = GlobalDecl(cd, Ctor_Complete);
317 }
318
319 cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);
320
321 if (cir::isDiscardableIfUnused(linkage))
322 return StructorCIRGen::RAUW;
323
324 // FIXME: Should we allow available_externally aliases?
325 if (!cir::isValidLinkage(linkage))
326 return StructorCIRGen::RAUW;
327
328 if (cir::isWeakForLinker(linkage)) {
329 // Only ELF and wasm support COMDATs with arbitrary names (C5/D5).
330 if (cgm.getTarget().getTriple().isOSBinFormatELF() ||
331 cgm.getTarget().getTriple().isOSBinFormatWasm())
332 return StructorCIRGen::COMDAT;
333 return StructorCIRGen::Emit;
334 }
335
336 return StructorCIRGen::Alias;
337}
338
340 GlobalDecl aliasDecl,
341 GlobalDecl targetDecl) {
342 cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);
343
344 // Does this function alias already exists?
345 StringRef mangledName = cgm.getMangledName(aliasDecl);
346 auto globalValue = dyn_cast_or_null<cir::CIRGlobalValueInterface>(
347 cgm.getGlobalValue(mangledName));
348 if (globalValue && !globalValue.isDeclaration())
349 return;
350
351 auto entry = cast_or_null<cir::FuncOp>(cgm.getGlobalValue(mangledName));
352
353 // Retrieve aliasee info.
354 auto aliasee = cast<cir::FuncOp>(cgm.getAddrOfGlobal(targetDecl));
355
356 // Populate actual alias.
357 cgm.emitAliasForGlobal(mangledName, entry, aliasDecl, aliasee, linkage);
358}
359
360void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) {
361 auto *md = cast<CXXMethodDecl>(gd.getDecl());
362 StructorCIRGen cirGenType = getCIRGenToUse(cgm, md);
363 const auto *cd = dyn_cast<CXXConstructorDecl>(md);
364 const CXXDestructorDecl *dd = cd ? nullptr : cast<CXXDestructorDecl>(md);
365
366 if (cd ? gd.getCtorType() == Ctor_Complete
367 : gd.getDtorType() == Dtor_Complete) {
368 GlobalDecl baseDecl =
370 ;
371
372 if (cirGenType == StructorCIRGen::Alias ||
373 cirGenType == StructorCIRGen::COMDAT) {
374 emitConstructorDestructorAlias(cgm, gd, baseDecl);
375 return;
376 }
377
378 if (cirGenType == StructorCIRGen::RAUW) {
379 StringRef mangledName = cgm.getMangledName(gd);
380 mlir::Operation *aliasee = cgm.getAddrOfGlobal(baseDecl);
381 cgm.addReplacement(mangledName, aliasee);
382 return;
383 }
384 }
385
386 auto fn = cgm.codegenCXXStructor(gd);
387
388 if (cirGenType == StructorCIRGen::COMDAT) {
389 llvm::SmallString<256> comdatKey;
390 llvm::raw_svector_ostream out(comdatKey);
391 ItaniumMangleContext &mangler =
393 if (dd)
394 mangler.mangleCXXDtorComdat(dd, out);
395 else
396 mangler.mangleCXXCtorComdat(cd, out);
397 fn.setComdat(llvm::StringRef(comdatKey));
398 } else {
399 cgm.maybeSetTrivialComdat(*md, fn);
400 }
401}
402
403void CIRGenItaniumCXXABI::addImplicitStructorParams(CIRGenFunction &cgf,
404 QualType &resTy,
405 FunctionArgList &params) {
406 const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());
408
409 // Check if we need a VTT parameter as well.
410 if (needsVTTParameter(cgf.curGD)) {
411 ASTContext &astContext = cgm.getASTContext();
412
413 // FIXME: avoid the fake decl
415 QualType t = astContext.getPointerType(astContext.VoidPtrTy);
416 auto *vttDecl = ImplicitParamDecl::Create(
417 astContext, /*DC=*/nullptr, md->getLocation(),
418 &astContext.Idents.get("vtt"), t, ImplicitParamKind::CXXVTT);
419 params.insert(params.begin() + 1, vttDecl);
420 getStructorImplicitParamDecl(cgf) = vttDecl;
421 }
422}
423
424void CIRGenItaniumCXXABI::emitCXXConstructors(const CXXConstructorDecl *d) {
425 // Just make sure we're in sync with TargetCXXABI.
427
428 // The constructor used for constructing this as a base class;
429 // ignores virtual bases.
430 cgm.emitGlobal(GlobalDecl(d, Ctor_Base));
431
432 // The constructor used for constructing this as a complete class;
433 // constructs the virtual bases, then calls the base constructor.
434 if (!d->getParent()->isAbstract()) {
435 // We don't need to emit the complete ctro if the class is abstract.
436 cgm.emitGlobal(GlobalDecl(d, Ctor_Complete));
437 }
438}
439
440void CIRGenItaniumCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) {
441 // The destructor used for destructing this as a base class; ignores
442 // virtual bases.
443 cgm.emitGlobal(GlobalDecl(d, Dtor_Base));
444
445 // The destructor used for destructing this as a most-derived class;
446 // call the base destructor and then destructs any virtual bases.
447 cgm.emitGlobal(GlobalDecl(d, Dtor_Complete));
448
449 // The destructor in a virtual table is always a 'deleting'
450 // destructor, which calls the complete destructor and then uses the
451 // appropriate operator delete.
452 if (d->isVirtual())
453 cgm.emitGlobal(GlobalDecl(d, Dtor_Deleting));
454}
455
456CIRGenCXXABI::AddedStructorArgs CIRGenItaniumCXXABI::getImplicitConstructorArgs(
457 CIRGenFunction &cgf, const CXXConstructorDecl *d, CXXCtorType type,
458 bool forVirtualBase, bool delegating) {
459 if (!needsVTTParameter(GlobalDecl(d, type)))
460 return AddedStructorArgs{};
461
462 // Insert the implicit 'vtt' argument as the second argument. Make sure to
463 // correctly reflect its address space, which can differ from generic on
464 // some targets.
465 mlir::Value vtt =
466 cgf.getVTTParameter(GlobalDecl(d, type), forVirtualBase, delegating);
467 QualType vttTy =
470 return AddedStructorArgs::withPrefix({{vtt, vttTy}});
471}
472
473/// Return whether the given global decl needs a VTT (virtual table table)
474/// parameter, which it does if it's a base constructor or destructor with
475/// virtual bases.
476bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) {
477 auto *md = cast<CXXMethodDecl>(gd.getDecl());
478
479 // We don't have any virtual bases, just return early.
480 if (!md->getParent()->getNumVBases())
481 return false;
482
483 // Check if we have a base constructor.
485 return true;
486
487 // Check if we have a base destructor.
489 return true;
490
491 return false;
492}
493
494void CIRGenItaniumCXXABI::emitVTableDefinitions(CIRGenVTables &cgvt,
495 const CXXRecordDecl *rd) {
496 cir::GlobalOp vtable = getAddrOfVTable(rd, CharUnits());
497 if (vtable.hasInitializer())
498 return;
499
500 ItaniumVTableContext &vtContext = cgm.getItaniumVTableContext();
501 const VTableLayout &vtLayout = vtContext.getVTableLayout(rd);
502 cir::GlobalLinkageKind linkage = cgm.getVTableLinkage(rd);
503 mlir::Attribute rtti =
506
507 // Classic codegen uses ConstantInitBuilder here, which is a very general
508 // and feature-rich class to generate initializers for global values.
509 // For now, this is using a simpler approach to create the initializer in CIR.
510 cgvt.createVTableInitializer(vtable, vtLayout, rtti,
511 cir::isLocalLinkage(linkage));
512
513 // Set the correct linkage.
514 vtable.setLinkage(linkage);
515
516 if (cgm.supportsCOMDAT() && cir::isWeakForLinker(linkage))
517 vtable.setSelfComdat();
518
519 // Set the right visibility.
520 cgm.setGVProperties(vtable, rd);
521
522 // If this is the magic class __cxxabiv1::__fundamental_type_info,
523 // we will emit the typeinfo for the fundamental types. This is the
524 // same behaviour as GCC.
525 const DeclContext *DC = rd->getDeclContext();
526 if (rd->getIdentifier() &&
527 rd->getIdentifier()->isStr("__fundamental_type_info") &&
528 isa<NamespaceDecl>(DC) && cast<NamespaceDecl>(DC)->getIdentifier() &&
529 cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
530 DC->getParent()->isTranslationUnit()) {
531 cgm.errorNYI(rd->getSourceRange(),
532 "emitVTableDefinitions: __fundamental_type_info");
533 }
534
535 [[maybe_unused]] auto vtableAsGlobalValue =
536 dyn_cast<cir::CIRGlobalValueInterface>(*vtable);
537 assert(vtableAsGlobalValue && "VTable must support CIRGlobalValueInterface");
538 // Always emit type metadata on non-available_externally definitions, and on
539 // available_externally definitions if we are performing whole program
540 // devirtualization. For WPD we need the type metadata on all vtable
541 // definitions to ensure we associate derived classes with base classes
542 // defined in headers but with a strong definition only in a shared
543 // library.
545 if (cgm.getCodeGenOpts().WholeProgramVTables) {
546 cgm.errorNYI(rd->getSourceRange(),
547 "emitVTableDefinitions: WholeProgramVTables");
548 }
549
551 if (cgm.getLangOpts().RelativeCXXABIVTables) {
552 cgm.errorNYI(rd->getSourceRange(), "vtableRelativeLayout");
553 }
554}
555
556mlir::Value CIRGenItaniumCXXABI::emitVirtualDestructorCall(
557 CIRGenFunction &cgf, const CXXDestructorDecl *dtor, CXXDtorType dtorType,
558 Address thisAddr, DeleteOrMemberCallExpr expr) {
559 auto *callExpr = dyn_cast<const CXXMemberCallExpr *>(expr);
560 auto *delExpr = dyn_cast<const CXXDeleteExpr *>(expr);
561 assert((callExpr != nullptr) ^ (delExpr != nullptr));
562 assert(callExpr == nullptr || callExpr->arg_begin() == callExpr->arg_end());
563 assert(dtorType == Dtor_Deleting || dtorType == Dtor_Complete);
564
565 GlobalDecl globalDecl(dtor, dtorType);
566 const CIRGenFunctionInfo *fnInfo =
567 &cgm.getTypes().arrangeCXXStructorDeclaration(globalDecl);
568 const cir::FuncType &fnTy = cgm.getTypes().getFunctionType(*fnInfo);
569 auto callee = CIRGenCallee::forVirtual(callExpr, globalDecl, thisAddr, fnTy);
570
571 QualType thisTy =
572 callExpr ? callExpr->getObjectType() : delExpr->getDestroyedType();
573
574 cgf.emitCXXDestructorCall(globalDecl, callee, thisAddr.emitRawPointer(),
575 thisTy, nullptr, QualType(), nullptr);
576 return nullptr;
577}
578
579void CIRGenItaniumCXXABI::emitVirtualInheritanceTables(
580 const CXXRecordDecl *rd) {
581 CIRGenVTables &vtables = cgm.getVTables();
582 cir::GlobalOp vtt = vtables.getAddrOfVTT(rd);
583 vtables.emitVTTDefinition(vtt, cgm.getVTableLinkage(rd), rd);
584}
585
586namespace {
587class CIRGenItaniumRTTIBuilder {
588 CIRGenModule &cgm; // Per-module state.
589 const CIRGenItaniumCXXABI &cxxABI; // Per-module state.
590
591 /// The fields of the RTTI descriptor currently being built.
592 SmallVector<mlir::Attribute, 16> fields;
593
594 // Returns the mangled type name of the given type.
595 cir::GlobalOp getAddrOfTypeName(mlir::Location loc, QualType ty,
596 cir::GlobalLinkageKind linkage);
597
598 /// descriptor of the given type.
599 mlir::Attribute getAddrOfExternalRTTIDescriptor(mlir::Location loc,
600 QualType ty);
601
602 /// Build the vtable pointer for the given type.
603 void buildVTablePointer(mlir::Location loc, const Type *ty);
604
605 /// Build an abi::__si_class_type_info, used for single inheritance, according
606 /// to the Itanium C++ ABI, 2.9.5p6b.
607 void buildSIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
608
609 /// Build an abi::__vmi_class_type_info, used for
610 /// classes with bases that do not satisfy the abi::__si_class_type_info
611 /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
612 void buildVMIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
613
614 /// Build an abi::__pointer_type_info, used for pointer types, according
615 /// to the Itanium C++ ABI, 2.9.4p7.
616 void buildPointerTypeInfo(mlir::Location loc, QualType ty);
617
618 /// Build an abi::__pointer_to_member_type_info, used for pointer to member
619 /// types, according to the Itanium C++ ABI, 2.9.4p9.
620
621 /// Build an abi::__pointer_to_member_type_info
622 /// struct, used for member pointer types.
623 void buildPointerToMemberTypeInfo(mlir::Location loc,
624 const MemberPointerType *ty);
625
626public:
627 CIRGenItaniumRTTIBuilder(const CIRGenItaniumCXXABI &abi, CIRGenModule &cgm)
628 : cgm(cgm), cxxABI(abi) {}
629
630 /// Build the RTTI type info struct for the given type, or
631 /// link to an existing RTTI descriptor if one already exists.
632 mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty);
633
634 /// Build the RTTI type info struct for the given type.
635 mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty,
636 cir::GlobalLinkageKind linkage,
637 mlir::SymbolTable::Visibility visibility);
638};
639
640/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
641/// the given type exists somewhere else, and that we should not emit the type
642/// information in this translation unit. Assumes that it is not a
643/// standard-library type.
644static bool shouldUseExternalRttiDescriptor(CIRGenModule &cgm, QualType ty) {
645 ASTContext &context = cgm.getASTContext();
646
647 // If RTTI is disabled, assume it might be disabled in the
648 // translation unit that defines any potential key function, too.
649 if (!context.getLangOpts().RTTI)
650 return false;
651
652 if (const auto *recordTy = dyn_cast<RecordType>(ty)) {
653 const auto *rd =
654 cast<CXXRecordDecl>(recordTy->getDecl())->getDefinitionOrSelf();
655 if (!rd->hasDefinition())
656 return false;
657
658 if (!rd->isDynamicClass())
659 return false;
660
661 // FIXME: this may need to be reconsidered if the key function
662 // changes.
663 // N.B. We must always emit the RTTI data ourselves if there exists a key
664 // function.
665 bool isDLLImport = rd->hasAttr<DLLImportAttr>();
666
667 // Don't import the RTTI but emit it locally.
668 if (cgm.getTriple().isOSCygMing())
669 return false;
670
671 if (cgm.getVTables().isVTableExternal(rd)) {
673 return true;
674
675 return !isDLLImport || cgm.getTriple().isWindowsItaniumEnvironment();
676 }
677
678 if (isDLLImport)
679 return true;
680 }
681
682 return false;
683}
684
685const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
686 // abi::__class_type_info.
687 static const char *const classTypeInfo =
688 "_ZTVN10__cxxabiv117__class_type_infoE";
689 // abi::__si_class_type_info.
690 static const char *const siClassTypeInfo =
691 "_ZTVN10__cxxabiv120__si_class_type_infoE";
692 // abi::__vmi_class_type_info.
693 static const char *const vmiClassTypeInfo =
694 "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
695
696 switch (ty->getTypeClass()) {
697#define TYPE(Class, Base)
698#define ABSTRACT_TYPE(Class, Base)
699#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
700#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
701#define DEPENDENT_TYPE(Class, Base) case Type::Class:
702#include "clang/AST/TypeNodes.inc"
703 llvm_unreachable("Non-canonical and dependent types shouldn't get here");
704
705 case Type::LValueReference:
706 case Type::RValueReference:
707 llvm_unreachable("References shouldn't get here");
708
709 case Type::Auto:
710 case Type::DeducedTemplateSpecialization:
711 llvm_unreachable("Undeduced type shouldn't get here");
712
713 case Type::Pipe:
714 llvm_unreachable("Pipe types shouldn't get here");
715
716 case Type::ArrayParameter:
717 llvm_unreachable("Array Parameter types should not get here.");
718
719 case Type::Builtin:
720 case Type::BitInt:
721 case Type::OverflowBehavior:
722 // GCC treats vector and complex types as fundamental types.
723 case Type::Vector:
724 case Type::ExtVector:
725 case Type::ConstantMatrix:
726 case Type::Complex:
727 case Type::Atomic:
728 // FIXME: GCC treats block pointers as fundamental types?!
729 case Type::BlockPointer:
730 return "_ZTVN10__cxxabiv123__fundamental_type_infoE";
731 case Type::ConstantArray:
732 case Type::IncompleteArray:
733 case Type::VariableArray:
734 // abi::__array_type_info.
735 return "_ZTVN10__cxxabiv117__array_type_infoE";
736
737 case Type::FunctionNoProto:
738 case Type::FunctionProto:
739 // abi::__function_type_info.
740 return "_ZTVN10__cxxabiv120__function_type_infoE";
741
742 case Type::Enum:
743 return "_ZTVN10__cxxabiv116__enum_type_infoE";
744
745 case Type::Record: {
746 const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl())
747 ->getDefinitionOrSelf();
748
749 if (!rd->hasDefinition() || !rd->getNumBases()) {
750 return classTypeInfo;
751 }
752
754 return siClassTypeInfo;
755 }
756
757 return vmiClassTypeInfo;
758 }
759
760 case Type::ObjCObject:
761 cgm.errorNYI("VTableClassNameForType: ObjCObject");
762 break;
763
764 case Type::ObjCInterface:
765 cgm.errorNYI("VTableClassNameForType: ObjCInterface");
766 break;
767
768 case Type::ObjCObjectPointer:
769 case Type::Pointer:
770 // abi::__pointer_type_info.
771 return "_ZTVN10__cxxabiv119__pointer_type_infoE";
772
773 case Type::MemberPointer:
774 // abi::__pointer_to_member_type_info.
775 return "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
776
777 case Type::HLSLAttributedResource:
778 case Type::HLSLInlineSpirv:
779 llvm_unreachable("HLSL doesn't support virtual functions");
780 }
781
782 return nullptr;
783}
784} // namespace
785
786/// Return the linkage that the type info and type info name constants
787/// should have for the given type.
788static cir::GlobalLinkageKind getTypeInfoLinkage(CIRGenModule &cgm,
789 QualType ty) {
790 // In addition, it and all of the intermediate abi::__pointer_type_info
791 // structs in the chain down to the abi::__class_type_info for the
792 // incomplete class type must be prevented from resolving to the
793 // corresponding type_info structs for the complete class type, possibly
794 // by making them local static objects. Finally, a dummy class RTTI is
795 // generated for the incomplete type that will not resolve to the final
796 // complete class RTTI (because the latter need not exist), possibly by
797 // making it a local static object.
799 return cir::GlobalLinkageKind::InternalLinkage;
800
801 switch (ty->getLinkage()) {
802 case Linkage::Invalid:
803 llvm_unreachable("Linkage hasn't been computed!");
804
805 case Linkage::None:
808 return cir::GlobalLinkageKind::InternalLinkage;
809
811 case Linkage::Module:
813 // RTTI is not enabled, which means that this type info struct is going
814 // to be used for exception handling. Give it linkonce_odr linkage.
815 if (!cgm.getLangOpts().RTTI)
816 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
817
818 if (const RecordType *record = dyn_cast<RecordType>(ty)) {
819 const auto *rd =
820 cast<CXXRecordDecl>(record->getDecl())->getDefinitionOrSelf();
821 if (rd->hasAttr<WeakAttr>())
822 return cir::GlobalLinkageKind::WeakODRLinkage;
823
824 if (cgm.getTriple().isWindowsItaniumEnvironment())
825 if (rd->hasAttr<DLLImportAttr>() &&
826 shouldUseExternalRttiDescriptor(cgm, ty))
827 return cir::GlobalLinkageKind::ExternalLinkage;
828
829 // MinGW always uses LinkOnceODRLinkage for type info.
830 if (rd->isDynamicClass() && !cgm.getASTContext()
832 .getTriple()
833 .isWindowsGNUEnvironment())
834 return cgm.getVTableLinkage(rd);
835 }
836
837 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
838 }
839
840 llvm_unreachable("Invalid linkage!");
841}
842
843cir::GlobalOp
844CIRGenItaniumRTTIBuilder::getAddrOfTypeName(mlir::Location loc, QualType ty,
845 cir::GlobalLinkageKind linkage) {
846 CIRGenBuilderTy &builder = cgm.getBuilder();
847 SmallString<256> name;
848 llvm::raw_svector_ostream out(name);
850
851 // We know that the mangled name of the type starts at index 4 of the
852 // mangled name of the typename, so we can just index into it in order to
853 // get the mangled name of the type.
854 mlir::Attribute init = builder.getString(
855 name.substr(4), cgm.convertType(cgm.getASTContext().CharTy),
856 std::nullopt);
857
858 CharUnits align =
860
861 // builder.getString can return a #cir.zero if the string given to it only
862 // contains null bytes. However, type names cannot be full of null bytes.
863 // So cast Init to a ConstArrayAttr should be safe.
864 auto initStr = cast<cir::ConstArrayAttr>(init);
865
866 cir::GlobalOp gv = cgm.createOrReplaceCXXRuntimeVariable(
867 loc, name, initStr.getType(), linkage, align);
869 return gv;
870}
871
872mlir::Attribute
873CIRGenItaniumRTTIBuilder::getAddrOfExternalRTTIDescriptor(mlir::Location loc,
874 QualType ty) {
875 // Mangle the RTTI name.
876 SmallString<256> name;
877 llvm::raw_svector_ostream out(name);
879 CIRGenBuilderTy &builder = cgm.getBuilder();
880
881 // Look for an existing global.
882 cir::GlobalOp gv = dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue(name));
883
884 if (!gv) {
885 // Create a new global variable.
886 // From LLVM codegen => Note for the future: If we would ever like to do
887 // deferred emission of RTTI, check if emitting vtables opportunistically
888 // need any adjustment.
889 gv = cgm.createGlobalOp(loc, name, builder.getUInt8PtrTy(),
890 /*isConstant=*/true);
891 const CXXRecordDecl *rd = ty->getAsCXXRecordDecl();
892 cgm.setGVProperties(gv, rd);
893
894 // Import the typeinfo symbol when all non-inline virtual methods are
895 // imported.
896 if (cgm.getTarget().hasPS4DLLImportExport()) {
897 cgm.errorNYI("getAddrOfExternalRTTIDescriptor: hasPS4DLLImportExport");
898 }
899 }
900
901 return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv);
902}
903
904void CIRGenItaniumRTTIBuilder::buildVTablePointer(mlir::Location loc,
905 const Type *ty) {
906 CIRGenBuilderTy &builder = cgm.getBuilder();
907 const char *vTableName = vTableClassNameForType(cgm, ty);
908
909 // Check if the alias exists. If it doesn't, then get or create the global.
910 if (cgm.getLangOpts().RelativeCXXABIVTables) {
911 cgm.errorNYI("buildVTablePointer: isRelativeLayout");
912 return;
913 }
914
915 mlir::Type vtableGlobalTy = builder.getPointerTo(builder.getUInt8PtrTy());
916 llvm::Align align = cgm.getDataLayout().getABITypeAlign(vtableGlobalTy);
917 cir::GlobalOp vTable = cgm.createOrReplaceCXXRuntimeVariable(
918 loc, vTableName, vtableGlobalTy, cir::GlobalLinkageKind::ExternalLinkage,
920 // Note: createOrReplaceCXXRuntimeVariable isn't exactly what classic-codegen
921 // does here: it just does a getOrInsertGlobal at the module level. However,
922 // the above function does MOST of what we want, except it sets the global as
923 // constant, when we don't want that. So set it here instead.
924 vTable.setConstant(false);
925
926 // The vtable address point is 2.
927 mlir::Attribute field{};
928 if (cgm.getLangOpts().RelativeCXXABIVTables) {
929 cgm.errorNYI("buildVTablePointer: isRelativeLayout");
930 } else {
931 SmallVector<mlir::Attribute, 4> offsets{
932 cgm.getBuilder().getI32IntegerAttr(2)};
933 auto indices = mlir::ArrayAttr::get(builder.getContext(), offsets);
935 vTable, indices);
936 }
937
938 assert(field && "expected attribute");
939 fields.push_back(field);
940}
941
942/// Build an abi::__si_class_type_info, used for single inheritance, according
943/// to the Itanium C++ ABI, 2.95p6b.
944void CIRGenItaniumRTTIBuilder::buildSIClassTypeInfo(mlir::Location loc,
945 const CXXRecordDecl *rd) {
946 // Itanium C++ ABI 2.9.5p6b:
947 // It adds to abi::__class_type_info a single member pointing to the
948 // type_info structure for the base type,
949 mlir::Attribute baseTypeInfo =
950 CIRGenItaniumRTTIBuilder(cxxABI, cgm)
951 .buildTypeInfo(loc, rd->bases_begin()->getType());
952 fields.push_back(baseTypeInfo);
953}
954
955/// Build an abi::__vmi_class_type_info, used for
956/// classes with bases that do not satisfy the abi::__si_class_type_info
957/// constraints, according to the Itanium C++ ABI, 2.9.5p5c.
958void CIRGenItaniumRTTIBuilder::buildVMIClassTypeInfo(mlir::Location loc,
959 const CXXRecordDecl *rd) {
960 mlir::Type unsignedIntLTy =
962
963 // Itanium C++ ABI 2.9.5p6c:
964 // __flags is a word with flags describing details about the class
965 // structure, which may be referenced by using the __flags_masks
966 // enumeration. These flags refer to both direct and indirect bases.
968 fields.push_back(cir::IntAttr::get(unsignedIntLTy, flags));
969
970 // Itanium C++ ABI 2.9.5p6c:
971 // __base_count is a word with the number of direct proper base class
972 // descriptions that follow.
973 fields.push_back(cir::IntAttr::get(unsignedIntLTy, rd->getNumBases()));
974
975 if (!rd->getNumBases())
976 return;
977
978 // Now add the base class descriptions.
979
980 // Itanium C++ ABI 2.9.5p6c:
981 // __base_info[] is an array of base class descriptions -- one for every
982 // direct proper base. Each description is of the type:
983 //
984 // struct abi::__base_class_type_info {
985 // public:
986 // const __class_type_info *__base_type;
987 // long __offset_flags;
988 //
989 // enum __offset_flags_masks {
990 // __virtual_mask = 0x1,
991 // __public_mask = 0x2,
992 // __offset_shift = 8
993 // };
994 // };
995
996 // If we're in mingw and 'long' isn't wide enough for a pointer, use 'long
997 // long' instead of 'long' for __offset_flags. libstdc++abi uses long long on
998 // LLP64 platforms.
999 // FIXME: Consider updating libc++abi to match, and extend this logic to all
1000 // LLP64 platforms.
1001 QualType offsetFlagsTy = cgm.getASTContext().LongTy;
1002 const TargetInfo &ti = cgm.getASTContext().getTargetInfo();
1003 if (ti.getTriple().isOSCygMing() &&
1004 ti.getPointerWidth(LangAS::Default) > ti.getLongWidth())
1005 offsetFlagsTy = cgm.getASTContext().LongLongTy;
1006 mlir::Type offsetFlagsLTy = cgm.convertType(offsetFlagsTy);
1007
1008 for (const CXXBaseSpecifier &base : rd->bases()) {
1009 // The __base_type member points to the RTTI for the base type.
1010 fields.push_back(CIRGenItaniumRTTIBuilder(cxxABI, cgm)
1011 .buildTypeInfo(loc, base.getType()));
1012
1013 CXXRecordDecl *baseDecl = base.getType()->castAsCXXRecordDecl();
1014 int64_t offsetFlags = 0;
1015
1016 // All but the lower 8 bits of __offset_flags are a signed offset.
1017 // For a non-virtual base, this is the offset in the object of the base
1018 // subobject. For a virtual base, this is the offset in the virtual table of
1019 // the virtual base offset for the virtual base referenced (negative).
1020 CharUnits offset;
1021 if (base.isVirtual())
1023 rd, baseDecl);
1024 else {
1025 const ASTRecordLayout &layout =
1027 offset = layout.getBaseClassOffset(baseDecl);
1028 }
1029 offsetFlags = uint64_t(offset.getQuantity()) << 8;
1030
1031 // The low-order byte of __offset_flags contains flags, as given by the
1032 // masks from the enumeration __offset_flags_masks.
1033 if (base.isVirtual())
1034 offsetFlags |= CodeGenUtils::BCTI_Virtual;
1035 if (base.getAccessSpecifier() == AS_public)
1036 offsetFlags |= CodeGenUtils::BCTI_Public;
1037
1038 fields.push_back(cir::IntAttr::get(offsetFlagsLTy, offsetFlags));
1039 }
1040}
1041
1042void CIRGenItaniumRTTIBuilder::buildPointerTypeInfo(mlir::Location loc,
1043 QualType ty) {
1044 // Itanium C++ ABI 2.9.4p7:
1045 // abi::__pbase_type_info is a base for both pointer types and
1046 // pointer-to-member types. It adds two data members:
1047 //
1048 // class __pbase_type_info : public std::type_info {
1049 // public:
1050 // unsigned int __flags;
1051 // const std::type_info *__pointee;
1052 //
1053 // enum __masks {
1054 // __const_mask = 0x1,
1055 // __volatile_mask = 0x2,
1056 // __restrict_mask = 0x4,
1057 // __incomplete_mask = 0x8,
1058 // __incomplete_class_mask = 0x10,
1059 // __transaction_safe_mask = 0x20
1060 // __noexcept_mask = 0x40
1061 // };
1062 // };
1063 const unsigned int flags =
1065
1066 mlir::Type unsignedIntTy = cgm.convertType(cgm.getASTContext().UnsignedIntTy);
1067 mlir::Attribute flagsAttr = cir::IntAttr::get(unsignedIntTy, flags);
1068 fields.push_back(flagsAttr);
1069
1070 mlir::Attribute pointeeTypeInfo =
1071 CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, ty);
1072 fields.push_back(pointeeTypeInfo);
1073}
1074
1075void CIRGenItaniumRTTIBuilder::buildPointerToMemberTypeInfo(
1076 mlir::Location loc, const MemberPointerType *ty) {
1077
1078 // The abi::__pointer_to_member_type_info type adds one field to
1079 // abi::__pbase_type_info:
1080 //
1081 // class __pointer_to_member_type_info : public __pbase_type_info {
1082 // public:
1083 // const abi::__class_type_info *__context;
1084 // };
1085 QualType pointeeTy = ty->getPointeeType();
1086
1087 unsigned flags =
1089
1090 const auto *rd = ty->getMostRecentCXXRecordDecl();
1091 if (!rd->hasDefinition())
1093
1094 mlir::Type unsignedIntTy = cgm.convertType(cgm.getASTContext().UnsignedIntTy);
1095 mlir::Attribute flagsAttr = cir::IntAttr::get(unsignedIntTy, flags);
1096 fields.push_back(flagsAttr);
1097
1098 mlir::Attribute pointeeTypeInfo =
1099 CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, pointeeTy);
1100 fields.push_back(pointeeTypeInfo);
1101
1102 CanQualType contextTy = cgm.getASTContext().getCanonicalTagType(rd);
1103 mlir::Attribute classTypeInfo =
1104 CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, contextTy);
1105 fields.push_back(classTypeInfo);
1106}
1107
1108mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(mlir::Location loc,
1109 QualType ty) {
1110 // We want to operate on the canonical type.
1111 ty = ty.getCanonicalType();
1112
1113 // Check if we've already emitted an RTTI descriptor for this type.
1114 SmallString<256> name;
1115 llvm::raw_svector_ostream out(name);
1117
1118 auto oldGV = dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue(name));
1119
1120 if (oldGV && !oldGV.isDeclaration()) {
1121 assert(!oldGV.hasAvailableExternallyLinkage() &&
1122 "available_externally typeinfos not yet implemented");
1124 oldGV);
1125 }
1126
1127 // Check if there is already an external RTTI descriptor for this type.
1129 shouldUseExternalRttiDescriptor(cgm, ty))
1130 return getAddrOfExternalRTTIDescriptor(loc, ty);
1131
1132 // Emit the standard library with external linkage.
1133 cir::GlobalLinkageKind linkage = getTypeInfoLinkage(cgm, ty);
1134
1135 // Give the type_info object and name the formal visibility of the
1136 // type itself.
1139
1140 mlir::SymbolTable::Visibility symVisibility;
1141 if (cir::isLocalLinkage(linkage))
1142 // If the linkage is local, only default visibility makes sense.
1143 symVisibility = mlir::SymbolTable::Visibility::Public;
1144 else if (cxxABI.classifyRTTIUniqueness(ty, linkage) ==
1145 CIRGenItaniumCXXABI::RUK_NonUniqueHidden) {
1146 cgm.errorNYI(
1147 "buildTypeInfo: classifyRTTIUniqueness == RUK_NonUniqueHidden");
1148 symVisibility = CIRGenModule::getMLIRVisibility(ty->getVisibility());
1149 } else
1150 symVisibility = CIRGenModule::getMLIRVisibility(ty->getVisibility());
1151
1152 return buildTypeInfo(loc, ty, linkage, symVisibility);
1153}
1154
1155mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(
1156 mlir::Location loc, QualType ty, cir::GlobalLinkageKind linkage,
1157 mlir::SymbolTable::Visibility visibility) {
1158 CIRGenBuilderTy &builder = cgm.getBuilder();
1159
1161
1162 // Add the vtable pointer.
1163 buildVTablePointer(loc, cast<Type>(ty));
1164
1165 // And the name.
1166 cir::GlobalOp typeName = getAddrOfTypeName(loc, ty, linkage);
1167 mlir::Attribute typeNameField;
1168
1169 // If we're supposed to demote the visibility, be sure to set a flag
1170 // to use a string comparison for type_info comparisons.
1171 CIRGenItaniumCXXABI::RTTIUniquenessKind rttiUniqueness =
1172 cxxABI.classifyRTTIUniqueness(ty, linkage);
1173 if (rttiUniqueness != CIRGenItaniumCXXABI::RUK_Unique) {
1174 // The flag is the sign bit, which on ARM64 is defined to be clear
1175 // for global pointers. This is very ARM64-specific.
1176 cgm.errorNYI(
1177 "buildTypeInfo: rttiUniqueness != CIRGenItaniumCXXABI::RUK_Unique");
1178 } else {
1179 typeNameField =
1180 builder.getGlobalViewAttr(builder.getUInt8PtrTy(), typeName);
1181 }
1182
1183 fields.push_back(typeNameField);
1184
1185 switch (ty->getTypeClass()) {
1186#define TYPE(Class, Base)
1187#define ABSTRACT_TYPE(Class, Base)
1188#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
1189#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
1190#define DEPENDENT_TYPE(Class, Base) case Type::Class:
1191#include "clang/AST/TypeNodes.inc"
1192 llvm_unreachable("Non-canonical and dependent types shouldn't get here");
1193
1194 // GCC treats vector types as fundamental types.
1195 case Type::Builtin:
1196 case Type::Vector:
1197 case Type::ExtVector:
1198 case Type::ConstantMatrix:
1199 case Type::Complex:
1200 case Type::BlockPointer:
1201 // Itanium C++ ABI 2.9.5p4:
1202 // abi::__fundamental_type_info adds no data members to std::type_info.
1203 break;
1204
1205 case Type::LValueReference:
1206 case Type::RValueReference:
1207 llvm_unreachable("References shouldn't get here");
1208
1209 case Type::Auto:
1210 case Type::DeducedTemplateSpecialization:
1211 llvm_unreachable("Undeduced type shouldn't get here");
1212
1213 case Type::Pipe:
1214 break;
1215
1216 case Type::BitInt:
1217 break;
1218
1219 case Type::OverflowBehavior:
1220 break;
1221
1222 case Type::ConstantArray:
1223 case Type::IncompleteArray:
1224 case Type::VariableArray:
1225 case Type::ArrayParameter:
1226 // Itanium C++ ABI 2.9.5p5:
1227 // abi::__array_type_info adds no data members to std::type_info.
1228 break;
1229
1230 case Type::FunctionNoProto:
1231 case Type::FunctionProto:
1232 // Itanium C++ ABI 2.9.5p5:
1233 // abi::__function_type_info adds no data members to std::type_info.
1234 break;
1235
1236 case Type::Enum:
1237 // Itanium C++ ABI 2.9.5p5:
1238 // abi::__enum_type_info adds no data members to std::type_info.
1239 break;
1240
1241 case Type::Record: {
1242 const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl())
1243 ->getDefinitionOrSelf();
1244 if (!rd->hasDefinition() || !rd->getNumBases()) {
1245 // We don't need to emit any fields.
1246 break;
1247 }
1248
1250 buildSIClassTypeInfo(loc, rd);
1251 } else {
1252 buildVMIClassTypeInfo(loc, rd);
1253 }
1254
1255 break;
1256 }
1257
1258 case Type::ObjCObject:
1259 case Type::ObjCInterface:
1260 cgm.errorNYI("buildTypeInfo: ObjCObject & ObjCInterface");
1261 break;
1262
1263 case Type::ObjCObjectPointer:
1264 cgm.errorNYI("buildTypeInfo: ObjCObjectPointer");
1265 break;
1266
1267 case Type::Pointer:
1268 // We need to get the type info for the pointee type.
1269 buildPointerTypeInfo(loc, cast<PointerType>(ty)->getPointeeType());
1270 break;
1271
1272 case Type::MemberPointer:
1273 buildPointerToMemberTypeInfo(loc, cast<MemberPointerType>(ty));
1274 break;
1275
1276 case Type::Atomic:
1277 // No fields, at least for the moment.
1278 break;
1279
1280 case Type::HLSLAttributedResource:
1281 case Type::HLSLInlineSpirv:
1282 llvm_unreachable("HLSL doesn't support RTTI");
1283 }
1284
1286 cir::TypeInfoAttr init = builder.getTypeInfo(builder.getArrayAttr(fields));
1287
1288 SmallString<256> name;
1289 llvm::raw_svector_ostream out(name);
1291
1292 // Create new global and search for an existing global.
1293 auto oldGV = dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue(name));
1294
1295 cir::GlobalOp gv = cgm.createGlobalOp(loc, name, init.getType(),
1296 /*isConstant=*/true);
1297 gv.setLinkage(linkage);
1298
1299 // Export the typeinfo in the same circumstances as the vtable is
1300 // exported.
1301 if (cgm.getTarget().hasPS4DLLImportExport()) {
1302 cgm.errorNYI("buildTypeInfo: target hasPS4DLLImportExport");
1303 return {};
1304 }
1305
1306 // If there's already an old global variable, replace it with the new one.
1307 if (oldGV) {
1308 // Replace occurrences of the old variable if needed.
1309 gv.setName(oldGV.getName());
1310 if (!oldGV->use_empty()) {
1311 cgm.errorNYI("buildTypeInfo: old GV !use_empty");
1312 return {};
1313 }
1314 cgm.eraseGlobalSymbol(oldGV);
1315 oldGV->erase();
1316 }
1317
1318 if (cgm.supportsCOMDAT() && cir::isWeakForLinker(linkage))
1319 gv.setSelfComdat();
1320
1321 CharUnits align = cgm.getASTContext().toCharUnitsFromBits(
1322 cgm.getTarget().getPointerAlign(LangAS::Default));
1323 gv.setAlignmentAttr(cgm.getSize(align));
1324
1325 // The Itanium ABI specifies that type_info objects must be globally
1326 // unique, with one exception: if the type is an incomplete class
1327 // type or a (possibly indirect) pointer to one. That exception
1328 // affects the general case of comparing type_info objects produced
1329 // by the typeid operator, which is why the comparison operators on
1330 // std::type_info generally use the type_info name pointers instead
1331 // of the object addresses. However, the language's built-in uses
1332 // of RTTI generally require class types to be complete, even when
1333 // manipulating pointers to those class types. This allows the
1334 // implementation of dynamic_cast to rely on address equality tests,
1335 // which is much faster.
1336
1337 // All of this is to say that it's important that both the type_info
1338 // object and the type_info name be uniqued when weakly emitted.
1339
1340 mlir::SymbolTable::setSymbolVisibility(typeName, visibility);
1344
1345 mlir::SymbolTable::setSymbolVisibility(gv, visibility);
1349
1351 return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv);
1352}
1353
1354bool CIRGenItaniumCXXABI::shouldTypeidBeNullChecked(QualType srcTy) {
1355 return true;
1356}
1357
1358void CIRGenItaniumCXXABI::emitBadTypeidCall(CIRGenFunction &cgf,
1359 mlir::Location loc) {
1360 // void __cxa_bad_typeid();
1361 cir::FuncType fnTy =
1362 cgf.getBuilder().getFuncType({}, cgf.getBuilder().getVoidTy());
1363 mlir::NamedAttrList attrs;
1364 attrs.set(cir::CIRDialect::getNoReturnAttrName(),
1365 mlir::UnitAttr::get(&cgf.cgm.getMLIRContext()));
1366
1367 cgf.emitRuntimeCall(
1368 loc, cgf.cgm.createRuntimeFunction(fnTy, "__cxa_bad_typeid", attrs), {},
1369 attrs);
1370 cir::UnreachableOp::create(cgf.getBuilder(), loc);
1371}
1372
1373mlir::Value CIRGenItaniumCXXABI::emitTypeid(CIRGenFunction &cgf, QualType srcTy,
1374 Address thisPtr,
1375 mlir::Type typeInfoPtrTy) {
1376 auto *classDecl = srcTy->castAsCXXRecordDecl();
1377 mlir::Location loc = cgm.getLoc(classDecl->getSourceRange());
1378 mlir::Value vptr = cgf.getVTablePtr(loc, thisPtr, classDecl);
1379 mlir::Value vtbl;
1380
1381 // TODO(cir): In classic codegen relative layouts cause us to do a
1382 // 'load_relative' of -4 here. We probably don't want to reprensent this in
1383 // CIR at all, but we should have the NYI here since this could be
1384 // meaningful/notable for implementation of relative layout in the future.
1385 if (cgm.getLangOpts().RelativeCXXABIVTables)
1386 cgm.errorNYI("buildVTablePointer: isRelativeLayout");
1387 else
1388 vtbl = cir::VTableGetTypeInfoOp::create(
1389 cgf.getBuilder(), loc, cgf.getBuilder().getPointerTo(typeInfoPtrTy),
1390 vptr);
1391
1392 return cgf.getBuilder().createAlignedLoad(loc, typeInfoPtrTy, vtbl,
1393 cgf.getPointerAlign());
1394}
1395
1396mlir::Attribute CIRGenItaniumCXXABI::getAddrOfRTTIDescriptor(mlir::Location loc,
1397 QualType ty) {
1398 return CIRGenItaniumRTTIBuilder(*this, cgm).buildTypeInfo(loc, ty);
1399}
1400
1401/// What sort of uniqueness rules should we use for the RTTI for the
1402/// given type?
1403CIRGenItaniumCXXABI::RTTIUniquenessKind
1404CIRGenItaniumCXXABI::classifyRTTIUniqueness(
1405 QualType canTy, cir::GlobalLinkageKind linkage) const {
1406 if (shouldRTTIBeUnique())
1407 return RUK_Unique;
1408
1409 // It's only necessary for linkonce_odr or weak_odr linkage.
1410 if (linkage != cir::GlobalLinkageKind::LinkOnceODRLinkage &&
1411 linkage != cir::GlobalLinkageKind::WeakODRLinkage)
1412 return RUK_Unique;
1413
1414 // It's only necessary with default visibility.
1415 if (canTy->getVisibility() != DefaultVisibility)
1416 return RUK_Unique;
1417
1418 // If we're not required to publish this symbol, hide it.
1419 if (linkage == cir::GlobalLinkageKind::LinkOnceODRLinkage)
1420 return RUK_NonUniqueHidden;
1421
1422 // If we're required to publish this symbol, as we might be under an
1423 // explicit instantiation, leave it with default visibility but
1424 // enable string-comparisons.
1425 assert(linkage == cir::GlobalLinkageKind::WeakODRLinkage);
1426 return RUK_NonUniqueVisible;
1427}
1428
1429void CIRGenItaniumCXXABI::emitDestructorCall(
1430 CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
1431 bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy) {
1432 GlobalDecl gd(dd, type);
1433 mlir::Value vtt =
1434 getCXXDestructorImplicitParam(cgf, dd, type, forVirtualBase, delegating);
1435 ASTContext &astContext = cgm.getASTContext();
1436 QualType vttTy = astContext.getPointerType(astContext.VoidPtrTy);
1438 CIRGenCallee callee =
1440
1441 cgf.emitCXXDestructorCall(gd, callee, thisAddr.getPointer(), thisTy, vtt,
1442 vttTy, nullptr);
1443}
1444
1445void CIRGenItaniumCXXABI::registerGlobalDtor(const VarDecl *vd,
1446 cir::FuncOp dtor,
1447 mlir::Value addr) {
1448 if (vd->isNoDestroy(cgm.getASTContext()))
1449 return;
1450
1451 // HLSL doesn't support atexit.
1452 if (cgm.getLangOpts().HLSL) {
1453 cgm.errorNYI(vd->getSourceRange(), "registerGlobalDtor: HLSL");
1454 return;
1455 }
1456
1457 // The default behavior is to use atexit. This is handled in lowering
1458 // prepare. Nothing to be done for CIR here.
1459}
1460
1461mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam(
1462 CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
1463 bool forVirtualBase, bool delegating) {
1464 GlobalDecl gd(dd, type);
1465 return cgf.getVTTParameter(gd, forVirtualBase, delegating);
1466}
1467
1468// The idea here is creating a separate block for the throw with an
1469// `UnreachableOp` as the terminator. So, we branch from the current block
1470// to the throw block and create a block for the remaining operations.
1471static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc,
1472 mlir::Value exceptionPtr = {},
1473 mlir::FlatSymbolRefAttr typeInfo = {},
1474 mlir::FlatSymbolRefAttr dtor = {}) {
1475 mlir::Block *currentBlock = builder.getInsertionBlock();
1476 mlir::Region *region = currentBlock->getParent();
1477
1478 if (currentBlock->empty()) {
1479 cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
1480 cir::UnreachableOp::create(builder, loc);
1481 } else {
1482 mlir::Block *throwBlock = builder.createBlock(region);
1483
1484 cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
1485 cir::UnreachableOp::create(builder, loc);
1486
1487 builder.setInsertionPointToEnd(currentBlock);
1488 cir::BrOp::create(builder, loc, throwBlock);
1489 }
1490
1491 (void)builder.createBlock(region);
1492}
1493
1494void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) {
1495 // void __cxa_rethrow();
1496 if (isNoReturn) {
1497 CIRGenBuilderTy &builder = cgf.getBuilder();
1498 assert(cgf.currSrcLoc && "expected source location");
1499 mlir::Location loc = cgf.getLoc(*cgf.currSrcLoc);
1500 insertThrowAndSplit(builder, loc);
1501 } else {
1502 cgm.errorNYI("emitRethrow with isNoReturn false");
1503 }
1504}
1505
1506void CIRGenItaniumCXXABI::emitThrow(CIRGenFunction &cgf,
1507 const CXXThrowExpr *e) {
1508 // This differs a bit from LLVM codegen, CIR has native operations for some
1509 // cxa functions, and defers allocation size computation, always pass the dtor
1510 // symbol, etc. CIRGen also does not use getAllocateExceptionFn / getThrowFn.
1511
1512 // Now allocate the exception object.
1513 CIRGenBuilderTy &builder = cgf.getBuilder();
1514 QualType clangThrowType = e->getSubExpr()->getType();
1515 cir::PointerType throwTy =
1516 builder.getPointerTo(cgf.convertType(clangThrowType));
1517 uint64_t typeSize =
1518 cgf.getContext().getTypeSizeInChars(clangThrowType).getQuantity();
1519 mlir::Location subExprLoc = cgf.getLoc(e->getSubExpr()->getSourceRange());
1520
1521 // Defer computing allocation size to some later lowering pass.
1522 mlir::TypedValue<cir::PointerType> exceptionPtr =
1523 cir::AllocExceptionOp::create(builder, subExprLoc, throwTy,
1524 builder.getI64IntegerAttr(typeSize))
1525 .getAddr();
1526
1527 // Build expression and store its result into exceptionPtr.
1528 CharUnits exnAlign = cgf.getContext().getExnObjectAlignment();
1529 cgf.emitAnyExprToExn(e->getSubExpr(), Address(exceptionPtr, exnAlign));
1530
1531 // Get the RTTI symbol address.
1532 auto typeInfo = mlir::cast<cir::GlobalViewAttr>(
1533 cgm.getAddrOfRTTIDescriptor(subExprLoc, clangThrowType,
1534 /*forEH=*/true));
1535 assert(!typeInfo.getIndices() && "expected no indirection");
1536
1537 // The address of the destructor.
1538 //
1539 // Note: LLVM codegen already optimizes out the dtor if the
1540 // type is a record with trivial dtor (by passing down a
1541 // null dtor). In CIR, we forward this info and allow for
1542 // Lowering pass to skip passing the trivial function.
1543 //
1544 const auto *cxxrd = clangThrowType->getAsCXXRecordDecl();
1545 mlir::FlatSymbolRefAttr dtor{};
1546 if (cxxrd && !cxxrd->hasTrivialDestructor()) {
1547 // __cxa_throw is declared to take its destructor as void (*)(void *). We
1548 // must match that if function pointers can be authenticated with a
1549 // discriminator based on their type.
1551 CXXDestructorDecl *dtorD = cxxrd->getDestructor();
1552 dtor = mlir::FlatSymbolRefAttr::get(
1553 cgm.getAddrOfCXXStructor(GlobalDecl(dtorD, Dtor_Complete))
1554 .getSymNameAttr());
1555 }
1556
1557 // Now throw the exception.
1558 mlir::Location loc = cgf.getLoc(e->getSourceRange());
1559 insertThrowAndSplit(builder, loc, exceptionPtr, typeInfo.getSymbol(), dtor);
1560}
1561
1563 switch (cgm.getASTContext().getCXXABIKind()) {
1564 case TargetCXXABI::GenericItanium:
1565 case TargetCXXABI::GenericAArch64:
1566 case TargetCXXABI::GenericARM:
1567 return new CIRGenItaniumCXXABI(cgm);
1568
1569 case TargetCXXABI::AppleARM64:
1570 // The general Itanium ABI will do until we implement something that
1571 // requires special handling.
1573 return new CIRGenItaniumCXXABI(cgm);
1574
1575 default:
1576 llvm_unreachable("bad or NYI ABI kind");
1577 }
1578}
1579
1580cir::GlobalOp CIRGenItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *rd,
1581 CharUnits vptrOffset) {
1582 assert(vptrOffset.isZero() && "Itanium ABI only supports zero vptr offsets");
1583 cir::GlobalOp &vtable = vtables[rd];
1584 if (vtable)
1585 return vtable;
1586
1587 // Queue up this vtable for possible deferred emission.
1588 cgm.addDeferredVTable(rd);
1589
1590 SmallString<256> name;
1591 llvm::raw_svector_ostream out(name);
1592 getMangleContext().mangleCXXVTable(rd, out);
1593
1594 const VTableLayout &vtLayout =
1596 mlir::Type vtableType = cgm.getVTables().getVTableType(vtLayout);
1597
1598 // Use pointer alignment for the vtable. Otherwise we would align them based
1599 // on the size of the initializer which doesn't make sense as only single
1600 // values are read.
1601 unsigned ptrAlign = cgm.getLangOpts().RelativeCXXABIVTables
1602 ? 32
1604
1606 cgm.getLoc(rd->getSourceRange()), name, vtableType,
1607 cir::GlobalLinkageKind::ExternalLinkage,
1608 cgm.getASTContext().toCharUnitsFromBits(ptrAlign));
1609 // LLVM codegen handles unnamedAddr
1611
1612 // In MS C++ if you have a class with virtual functions in which you are using
1613 // selective member import/export, then all virtual functions must be exported
1614 // unless they are inline, otherwise a link error will result. To match this
1615 // behavior, for such classes, we dllimport the vtable if it is defined
1616 // externally and all the non-inline virtual methods are marked dllimport, and
1617 // we dllexport the vtable if it is defined in this TU and all the non-inline
1618 // virtual methods are marked dllexport.
1619 if (cgm.getTarget().hasPS4DLLImportExport())
1620 cgm.errorNYI(rd->getSourceRange(),
1621 "getAddrOfVTable: PS4 DLL import/export");
1622
1623 cgm.setGVProperties(vtable, rd);
1624 return vtable;
1625}
1626
1627CIRGenCallee CIRGenItaniumCXXABI::getVirtualFunctionPointer(
1628 CIRGenFunction &cgf, clang::GlobalDecl gd, Address thisAddr, mlir::Type ty,
1629 SourceLocation srcLoc) {
1630 CIRGenBuilderTy &builder = cgm.getBuilder();
1631 mlir::Location loc = cgf.getLoc(srcLoc);
1632 cir::PointerType tyPtr = builder.getPointerTo(ty);
1633 auto *methodDecl = cast<CXXMethodDecl>(gd.getDecl());
1634 mlir::Value vtable = cgf.getVTablePtr(loc, thisAddr, methodDecl->getParent());
1635
1636 uint64_t vtableIndex = cgm.getItaniumVTableContext().getMethodVTableIndex(gd);
1637 mlir::Value vfunc{};
1638 if (cgf.shouldEmitVTableTypeCheckedLoad(methodDecl->getParent())) {
1639 cgm.errorNYI(loc, "getVirtualFunctionPointer: emitVTableTypeCheckedLoad");
1640 } else {
1642
1643 mlir::Value vfuncLoad;
1644 if (cgm.getLangOpts().RelativeCXXABIVTables) {
1646 cgm.errorNYI(loc, "getVirtualFunctionPointer: isRelativeLayout");
1647 } else {
1648 auto vtableSlotPtr = cir::VTableGetVirtualFnAddrOp::create(
1649 builder, loc, builder.getPointerTo(tyPtr), vtable, vtableIndex);
1650 vfuncLoad = builder.createAlignedLoad(loc, tyPtr, vtableSlotPtr,
1651 cgf.getPointerAlign());
1652 }
1653
1654 // Set invariant on the cir.load of virtual function pointer to indicate
1655 // that function didn't change inside vtable.
1656 // It's safe to add it without -fstrict-vtable-pointers, but it would not
1657 // help in devirtualization because it will only matter if we will have 2
1658 // the same virtual function loads from the same vtable load, which won't
1659 // happen without enabled devirtualization with -fstrict-vtable-pointers.
1660 if (cgm.getCodeGenOpts().OptimizationLevel > 0 &&
1661 cgm.getCodeGenOpts().StrictVTablePointers)
1662 if (auto loadOp = vfuncLoad.getDefiningOp<cir::LoadOp>())
1663 loadOp.setInvariant(true);
1664
1665 vfunc = vfuncLoad;
1666 }
1667
1668 CIRGenCallee callee(gd, vfunc.getDefiningOp());
1669 return callee;
1670}
1671
1672mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructorWithVTT(
1673 CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,
1674 const CXXRecordDecl *nearestVBase) {
1675 assert((base.getBase()->getNumVBases() || nearestVBase != nullptr) &&
1676 needsVTTParameter(cgf.curGD) && "This class doesn't have VTT");
1677
1678 // Get the secondary vpointer index.
1679 uint64_t virtualPointerIndex =
1680 cgm.getVTables().getSecondaryVirtualPointerIndex(vtableClass, base);
1681
1682 /// Load the VTT.
1683 mlir::Value vttPtr = cgf.loadCXXVTT();
1684 mlir::Location loc = cgf.getLoc(vtableClass->getSourceRange());
1685 // Calculate the address point from the VTT, and the offset may be zero.
1686 vttPtr = cgf.getBuilder().createVTTAddrPoint(loc, vttPtr.getType(), vttPtr,
1687 virtualPointerIndex);
1688 // And load the address point from the VTT.
1689 auto vptrType = cir::VPtrType::get(cgf.getBuilder().getContext());
1690 return cgf.getBuilder().createAlignedLoad(loc, vptrType, vttPtr,
1691 cgf.getPointerAlign());
1692}
1693
1694mlir::Value
1695CIRGenItaniumCXXABI::getVTableAddressPoint(BaseSubobject base,
1696 const CXXRecordDecl *vtableClass) {
1697 cir::GlobalOp vtable = getAddrOfVTable(vtableClass, CharUnits());
1698
1699 // Find the appropriate vtable within the vtable group, and the address point
1700 // within that vtable.
1701 VTableLayout::AddressPointLocation addressPoint =
1703 .getVTableLayout(vtableClass)
1704 .getAddressPoint(base);
1705
1706 mlir::OpBuilder &builder = cgm.getBuilder();
1707 auto vtablePtrTy = cir::VPtrType::get(builder.getContext());
1708
1709 return cir::VTableAddrPointOp::create(
1710 builder, cgm.getLoc(vtableClass->getSourceRange()), vtablePtrTy,
1711 mlir::FlatSymbolRefAttr::get(vtable.getSymNameAttr()),
1712 cir::AddressPointAttr::get(cgm.getBuilder().getContext(),
1713 addressPoint.VTableIndex,
1714 addressPoint.AddressPointIndex));
1715}
1716
1717mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructor(
1718 CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
1719 clang::BaseSubobject base, const clang::CXXRecordDecl *nearestVBase) {
1720
1721 if ((base.getBase()->getNumVBases() || nearestVBase != nullptr) &&
1722 needsVTTParameter(cgf.curGD)) {
1723 return getVTableAddressPointInStructorWithVTT(cgf, vtableClass, base,
1724 nearestVBase);
1725 }
1726 return getVTableAddressPoint(base, vtableClass);
1727}
1728
1729bool CIRGenItaniumCXXABI::isVirtualOffsetNeededForVTableField(
1730 CIRGenFunction &cgf, CIRGenFunction::VPtr vptr) {
1731 if (vptr.nearestVBase == nullptr)
1732 return false;
1733 return needsVTTParameter(cgf.curGD);
1734}
1735
1736mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset(
1737 mlir::Location loc, CIRGenFunction &cgf, Address thisAddr,
1738 const CXXRecordDecl *classDecl, const CXXRecordDecl *baseClassDecl) {
1739 CIRGenBuilderTy &builder = cgf.getBuilder();
1740 mlir::Value vtablePtr = cgf.getVTablePtr(loc, thisAddr, classDecl);
1741 mlir::Value vtableBytePtr = builder.createBitcast(vtablePtr, cgm.uInt8PtrTy);
1742 CharUnits vbaseOffsetOffset =
1744 baseClassDecl);
1745 mlir::Value offsetVal =
1746 builder.getSInt64(vbaseOffsetOffset.getQuantity(), loc);
1747 auto vbaseOffsetPtr = cir::PtrStrideOp::create(builder, loc, cgm.uInt8PtrTy,
1748 vtableBytePtr, offsetVal);
1749
1750 mlir::Value vbaseOffset;
1751 if (cgm.getLangOpts().RelativeCXXABIVTables) {
1753 cgm.errorNYI(loc, "getVirtualBaseClassOffset: relative layout");
1754 } else {
1755 mlir::Value offsetPtr = builder.createBitcast(
1756 vbaseOffsetPtr, builder.getPointerTo(cgm.ptrDiffTy));
1757 vbaseOffset = builder.createLoad(
1758 loc, Address(offsetPtr, cgm.ptrDiffTy, cgf.getPointerAlign()));
1759 }
1760 return vbaseOffset;
1761}
1762
1763static cir::FuncOp getBadCastFn(CIRGenFunction &cgf) {
1764 // Prototype: void __cxa_bad_cast();
1765
1766 // TODO(cir): set the calling convention of the runtime function.
1768
1769 cir::FuncType fnTy =
1770 cgf.getBuilder().getFuncType({}, cgf.getBuilder().getVoidTy());
1771 return cgf.cgm.createRuntimeFunction(fnTy, "__cxa_bad_cast");
1772}
1773
1774static void emitCallToBadCast(CIRGenFunction &cgf, mlir::Location loc) {
1775 // TODO(cir): set the calling convention to the runtime function.
1777
1778 mlir::NamedAttrList attrs;
1779 attrs.set(cir::CIRDialect::getNoReturnAttrName(),
1780 mlir::UnitAttr::get(&cgf.cgm.getMLIRContext()));
1781
1782 cgf.emitRuntimeCall(loc, getBadCastFn(cgf), {}, attrs);
1783 cir::UnreachableOp::create(cgf.getBuilder(), loc);
1784 cgf.getBuilder().clearInsertionPoint();
1785}
1786
1787void CIRGenItaniumCXXABI::emitBadCastCall(CIRGenFunction &cgf,
1788 mlir::Location loc) {
1789 emitCallToBadCast(cgf, loc);
1790}
1791
1792static cir::FuncOp getItaniumDynamicCastFn(CIRGenFunction &cgf) {
1793 // Prototype:
1794 // void *__dynamic_cast(const void *sub,
1795 // global_as const abi::__class_type_info *src,
1796 // global_as const abi::__class_type_info *dst,
1797 // std::ptrdiff_t src2dst_offset);
1798
1799 mlir::Type voidPtrTy = cgf.getBuilder().getVoidPtrTy();
1800 mlir::Type rttiPtrTy = cgf.getBuilder().getUInt8PtrTy();
1801 mlir::Type ptrDiffTy = cgf.convertType(cgf.getContext().getPointerDiffType());
1802
1803 // TODO(cir): mark the function as willreturn readonly.
1806
1807 // TODO(cir): set the calling convention of the runtime function.
1809
1810 cir::FuncType FTy = cgf.getBuilder().getFuncType(
1811 {voidPtrTy, rttiPtrTy, rttiPtrTy, ptrDiffTy}, voidPtrTy);
1812 cir::FuncOp fn = cgf.cgm.createRuntimeFunction(FTy, "__dynamic_cast");
1813 fn->setAttr(cir::CIRDialect::getNoThrowAttrName(),
1814 mlir::UnitAttr::get(cgf.getBuilder().getContext()));
1815 return fn;
1816}
1817
1818static Address emitDynamicCastToVoid(CIRGenFunction &cgf, mlir::Location loc,
1819 QualType srcRecordTy, Address src) {
1820 bool vtableUsesRelativeLayout = cgf.cgm.getLangOpts().RelativeCXXABIVTables;
1821 mlir::Value ptr = cgf.getBuilder().createDynCastToVoid(
1822 loc, src.getPointer(), vtableUsesRelativeLayout);
1823 return Address{ptr, src.getAlignment()};
1824}
1825
1826static mlir::Value emitExactDynamicCast(CIRGenItaniumCXXABI &abi,
1827 CIRGenFunction &cgf, mlir::Location loc,
1828 QualType srcRecordTy,
1829 QualType destRecordTy,
1830 cir::PointerType destCIRTy,
1831 bool isRefCast, Address src) {
1832 // Find all the inheritance paths from SrcRecordTy to DestRecordTy.
1833 const CXXRecordDecl *srcDecl = srcRecordTy->getAsCXXRecordDecl();
1834 const CXXRecordDecl *destDecl = destRecordTy->getAsCXXRecordDecl();
1835 CXXBasePaths paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
1836 /*DetectVirtual=*/false);
1837 (void)destDecl->isDerivedFrom(srcDecl, paths);
1838
1839 // Find an offset within `destDecl` where a `srcDecl` instance and its vptr
1840 // might appear.
1841 std::optional<CharUnits> offset;
1842 for (const CXXBasePath &path : paths) {
1843 // dynamic_cast only finds public inheritance paths.
1844 if (path.Access != AS_public)
1845 continue;
1846
1847 CharUnits pathOffset;
1848 for (const CXXBasePathElement &pathElement : path) {
1849 // Find the offset along this inheritance step.
1850 const CXXRecordDecl *base =
1851 pathElement.Base->getType()->getAsCXXRecordDecl();
1852 if (pathElement.Base->isVirtual()) {
1853 // For a virtual base class, we know that the derived class is exactly
1854 // destDecl, so we can use the vbase offset from its layout.
1855 const ASTRecordLayout &layout =
1856 cgf.getContext().getASTRecordLayout(destDecl);
1857 pathOffset = layout.getVBaseClassOffset(base);
1858 } else {
1859 const ASTRecordLayout &layout =
1860 cgf.getContext().getASTRecordLayout(pathElement.Class);
1861 pathOffset += layout.getBaseClassOffset(base);
1862 }
1863 }
1864
1865 if (!offset) {
1866 offset = pathOffset;
1867 } else if (offset != pathOffset) {
1868 // base appears in at least two different places. Find the most-derived
1869 // object and see if it's a DestDecl. Note that the most-derived object
1870 // must be at least as aligned as this base class subobject, and must
1871 // have a vptr at offset 0.
1872 src = emitDynamicCastToVoid(cgf, loc, srcRecordTy, src);
1873 srcDecl = destDecl;
1874 offset = CharUnits::Zero();
1875 break;
1876 }
1877 }
1878
1879 CIRGenBuilderTy &builder = cgf.getBuilder();
1880
1881 if (!offset) {
1882 // If there are no public inheritance paths, the cast always fails.
1883 mlir::Value nullPtrValue = builder.getNullPtr(destCIRTy, loc);
1884 if (isRefCast) {
1885 mlir::Region *currentRegion = builder.getBlock()->getParent();
1886 emitCallToBadCast(cgf, loc);
1887
1888 // The call to bad_cast will terminate the block. Create a new block to
1889 // hold any follow up code.
1890 builder.createBlock(currentRegion, currentRegion->end());
1891 }
1892
1893 return nullPtrValue;
1894 }
1895
1896 // Compare the vptr against the expected vptr for the destination type at
1897 // this offset. Note that we do not know what type src points to in the case
1898 // where the derived class multiply inherits from the base class so we can't
1899 // use getVTablePtr, so we load the vptr directly instead.
1900
1901 mlir::Value expectedVPtr =
1902 abi.getVTableAddressPoint(BaseSubobject(srcDecl, *offset), destDecl);
1903
1904 // TODO(cir): handle address space here.
1906 mlir::Type vptrTy = expectedVPtr.getType();
1907 mlir::Type vptrPtrTy = builder.getPointerTo(vptrTy);
1908 Address srcVPtrPtr(builder.createBitcast(src.getPointer(), vptrPtrTy),
1909 src.getAlignment());
1910 mlir::Value srcVPtr = builder.createLoad(loc, srcVPtrPtr);
1911
1912 // TODO(cir): decorate SrcVPtr with TBAA info.
1914
1915 mlir::Value success =
1916 builder.createCompare(loc, cir::CmpOpKind::eq, srcVPtr, expectedVPtr);
1917
1918 auto emitCastResult = [&] {
1919 if (offset->isZero())
1920 return builder.createBitcast(src.getPointer(), destCIRTy);
1921
1922 // TODO(cir): handle address space here.
1924 mlir::Type u8PtrTy = builder.getUInt8PtrTy();
1925
1926 mlir::Value strideToApply =
1927 builder.getConstInt(loc, builder.getUInt64Ty(), -offset->getQuantity());
1928 mlir::Value srcU8Ptr = builder.createBitcast(src.getPointer(), u8PtrTy);
1929 mlir::Value resultU8Ptr = cir::PtrStrideOp::create(builder, loc, u8PtrTy,
1930 srcU8Ptr, strideToApply);
1931 return builder.createBitcast(resultU8Ptr, destCIRTy);
1932 };
1933
1934 if (isRefCast) {
1935 mlir::Value failed = builder.createNot(success);
1936 cir::IfOp::create(builder, loc, failed, /*withElseRegion=*/false,
1937 [&](mlir::OpBuilder &, mlir::Location) {
1938 emitCallToBadCast(cgf, loc);
1939 });
1940 return emitCastResult();
1941 }
1942
1943 return cir::TernaryOp::create(
1944 builder, loc, success,
1945 [&](mlir::OpBuilder &, mlir::Location) {
1946 auto result = emitCastResult();
1947 builder.createYield(loc, result);
1948 },
1949 [&](mlir::OpBuilder &, mlir::Location) {
1950 mlir::Value nullPtrValue = builder.getNullPtr(destCIRTy, loc);
1951 builder.createYield(loc, nullPtrValue);
1952 })
1953 .getResult();
1954}
1955
1956static cir::DynamicCastInfoAttr emitDynamicCastInfo(CIRGenFunction &cgf,
1957 mlir::Location loc,
1958 QualType srcRecordTy,
1959 QualType destRecordTy) {
1960 auto srcRtti = mlir::cast<cir::GlobalViewAttr>(
1961 cgf.cgm.getAddrOfRTTIDescriptor(loc, srcRecordTy.getUnqualifiedType()));
1962 auto destRtti = mlir::cast<cir::GlobalViewAttr>(
1963 cgf.cgm.getAddrOfRTTIDescriptor(loc, destRecordTy.getUnqualifiedType()));
1964
1965 cir::FuncOp runtimeFuncOp = getItaniumDynamicCastFn(cgf);
1966 cir::FuncOp badCastFuncOp = getBadCastFn(cgf);
1967 auto runtimeFuncRef = mlir::FlatSymbolRefAttr::get(runtimeFuncOp);
1968 auto badCastFuncRef = mlir::FlatSymbolRefAttr::get(badCastFuncOp);
1969
1970 const CXXRecordDecl *srcDecl = srcRecordTy->getAsCXXRecordDecl();
1971 const CXXRecordDecl *destDecl = destRecordTy->getAsCXXRecordDecl();
1972 CharUnits offsetHint =
1973 CodeGenUtils::computeOffsetHint(cgf.getContext(), srcDecl, destDecl);
1974
1975 mlir::Type ptrdiffTy = cgf.convertType(cgf.getContext().getPointerDiffType());
1976 auto offsetHintAttr = cir::IntAttr::get(ptrdiffTy, offsetHint.getQuantity());
1977
1978 return cir::DynamicCastInfoAttr::get(srcRtti, destRtti, runtimeFuncRef,
1979 badCastFuncRef, offsetHintAttr);
1980}
1981
1982mlir::Value CIRGenItaniumCXXABI::emitDynamicCast(CIRGenFunction &cgf,
1983 mlir::Location loc,
1984 QualType srcRecordTy,
1985 QualType destRecordTy,
1986 cir::PointerType destCIRTy,
1987 bool isRefCast, Address src) {
1988 bool isCastToVoid = destRecordTy.isNull();
1989 assert((!isCastToVoid || !isRefCast) && "cannot cast to void reference");
1990
1991 if (isCastToVoid)
1992 return emitDynamicCastToVoid(cgf, loc, srcRecordTy, src).getPointer();
1993
1994 // If the destination is effectively final, the cast succeeds if and only
1995 // if the dynamic type of the pointer is exactly the destination type.
1996 if (destRecordTy->getAsCXXRecordDecl()->isEffectivelyFinal() &&
1997 cgf.cgm.getCodeGenOpts().OptimizationLevel > 0) {
1998 CIRGenBuilderTy &builder = cgf.getBuilder();
1999 // If this isn't a reference cast, check the pointer to see if it's null.
2000 if (!isRefCast) {
2001 mlir::Value srcPtrIsNull = builder.createPtrIsNull(src.getPointer());
2002 return cir::TernaryOp::create(
2003 builder, loc, srcPtrIsNull,
2004 [&](mlir::OpBuilder, mlir::Location) {
2005 builder.createYield(
2006 loc, builder.getNullPtr(destCIRTy, loc).getResult());
2007 },
2008 [&](mlir::OpBuilder &, mlir::Location) {
2009 mlir::Value exactCast = emitExactDynamicCast(
2010 *this, cgf, loc, srcRecordTy, destRecordTy, destCIRTy,
2011 isRefCast, src);
2012 builder.createYield(loc, exactCast);
2013 })
2014 .getResult();
2015 }
2016
2017 return emitExactDynamicCast(*this, cgf, loc, srcRecordTy, destRecordTy,
2018 destCIRTy, isRefCast, src);
2019 }
2020
2021 cir::DynamicCastInfoAttr castInfo =
2022 emitDynamicCastInfo(cgf, loc, srcRecordTy, destRecordTy);
2023 return cgf.getBuilder().createDynCast(loc, src.getPointer(), destCIRTy,
2024 isRefCast, castInfo);
2025}
2026
2027cir::MethodAttr
2028CIRGenItaniumCXXABI::buildVirtualMethodAttr(cir::MethodType methodTy,
2029 const CXXMethodDecl *md) {
2030 assert(md->isVirtual() && "only deal with virtual member functions");
2031
2033 uint64_t vtableOffset;
2034 if (cgm.getLangOpts().RelativeCXXABIVTables) {
2035 // Multiply by 4-byte relative offsets.
2036 vtableOffset = index * 4;
2037 } else {
2038 const ASTContext &astContext = cgm.getASTContext();
2039 CharUnits pointerWidth = astContext.toCharUnitsFromBits(
2040 astContext.getTargetInfo().getPointerWidth(LangAS::Default));
2041 vtableOffset = index * pointerWidth.getQuantity();
2042 }
2043
2044 return cir::MethodAttr::get(methodTy, vtableOffset);
2045}
2046/// The Itanium ABI always places an offset to the complete object
2047/// at entry -2 in the vtable.
2048void CIRGenItaniumCXXABI::emitVirtualObjectDelete(
2049 CIRGenFunction &cgf, const CXXDeleteExpr *delExpr, Address ptr,
2050 QualType elementType, const CXXDestructorDecl *dtor) {
2051 bool useGlobalDelete = delExpr->isGlobalDelete();
2052 if (useGlobalDelete) {
2053 cgf.cgm.errorNYI(delExpr->getSourceRange(),
2054 "emitVirtualObjectDelete: global delete");
2055 }
2056
2057 CXXDtorType dtorType = useGlobalDelete ? Dtor_Complete : Dtor_Deleting;
2058 emitVirtualDestructorCall(cgf, dtor, dtorType, ptr, delExpr);
2059}
2060
2061/************************** Array allocation cookies **************************/
2062
2063CharUnits CIRGenItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {
2064 // The array cookie is a size_t; pad that up to the element alignment.
2065 // The cookie is actually right-justified in that space.
2066 return std::max(
2067 cgm.getSizeSize(),
2068 cgm.getASTContext().getPreferredTypeAlignInChars(elementType));
2069}
2070
2071Address CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
2072 Address newPtr,
2073 mlir::Value numElements,
2074 const CXXNewExpr *e,
2075 QualType elementType) {
2076 assert(requiresArrayCookie(e));
2077
2078 // TODO: When sanitizer support is implemented, we'll need to
2079 // get the address space from `newPtr`.
2082
2083 ASTContext &ctx = cgm.getASTContext();
2084 CharUnits sizeSize = cgf.getSizeSize();
2085 mlir::Location loc = cgf.getLoc(e->getSourceRange());
2086
2087 // The size of the cookie.
2088 CharUnits cookieSize =
2089 std::max(sizeSize, ctx.getPreferredTypeAlignInChars(elementType));
2090 assert(cookieSize == getArrayCookieSizeImpl(elementType));
2091
2092 mlir::Type u8Ty = cgf.getBuilder().getUInt8Ty();
2093 cir::PointerType u8PtrTy = cgf.getBuilder().getUInt8PtrTy();
2094 mlir::Value baseBytePtr =
2095 cgf.getBuilder().createBitcast(newPtr.getPointer(), u8PtrTy);
2096
2097 // Compute an offset to the cookie.
2098 CharUnits cookieOffset = cookieSize - sizeSize;
2099 mlir::Value cookiePtrValue = baseBytePtr;
2100 if (!cookieOffset.isZero()) {
2101 mlir::Value offsetOp = cgf.getBuilder().getSignedInt(
2102 loc, cookieOffset.getQuantity(), /*width=*/32);
2103 cookiePtrValue =
2104 cgf.getBuilder().createPtrStride(loc, cookiePtrValue, offsetOp);
2105 }
2106
2107 CharUnits baseAlignment = newPtr.getAlignment();
2108 CharUnits cookiePtrAlignment = baseAlignment.alignmentAtOffset(cookieOffset);
2109 Address cookiePtr(cookiePtrValue, u8Ty, cookiePtrAlignment);
2110
2111 // Write the number of elements into the appropriate slot.
2112 Address numElementsPtr =
2113 cookiePtr.withElementType(cgf.getBuilder(), cgf.sizeTy);
2114 cgf.getBuilder().createStore(loc, numElements, numElementsPtr);
2115
2116 // Finally, compute a pointer to the actual data buffer by skipping
2117 // over the cookie completely.
2118 mlir::Value dataOffset =
2119 cgf.getBuilder().getSignedInt(loc, cookieSize.getQuantity(),
2120 /*width=*/32);
2121 mlir::Value dataPtr =
2122 cgf.getBuilder().createPtrStride(loc, baseBytePtr, dataOffset);
2123 mlir::Value finalPtr =
2124 cgf.getBuilder().createPtrBitcast(dataPtr, newPtr.getElementType());
2125 CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
2126 return Address(finalPtr, newPtr.getElementType(), finalAlignment);
2127}
2128
2129bool CIRGenItaniumCXXABI::hasAnyUnusedVirtualInlineFunction(
2130 const CXXRecordDecl *rd) const {
2131 const auto &vtableLayout = cgm.getItaniumVTableContext().getVTableLayout(rd);
2132
2133 for (const auto &vtableComponent : vtableLayout.vtable_components()) {
2134 // Skip empty slot.
2135 if (!vtableComponent.isUsedFunctionPointerKind())
2136 continue;
2137
2138 const CXXMethodDecl *method = vtableComponent.getFunctionDecl();
2139 const FunctionDecl *fd = method->getDefinition();
2140 const bool isInlined =
2141 method->getCanonicalDecl()->isInlined() || (fd && fd->isInlined());
2142 if (!isInlined)
2143 continue;
2144
2145 StringRef name = cgm.getMangledName(
2146 vtableComponent.getGlobalDecl(/*HasVectorDeletingDtors=*/false));
2147 auto entry = dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue(name));
2148 // This checks if virtual inline function has already been emitted.
2149 // Note that it is possible that this inline function would be emitted
2150 // after trying to emit vtable speculatively. Because of this we do
2151 // an extra pass after emitting all deferred vtables to find and emit
2152 // these vtables opportunistically.
2153 if (!entry || entry.isDeclaration())
2154 return true;
2155 }
2156 return false;
2157}
2158
2159bool CIRGenItaniumCXXABI::isVTableHidden(const CXXRecordDecl *rd) const {
2160 const auto &vtableLayout = cgm.getItaniumVTableContext().getVTableLayout(rd);
2161
2162 for (const auto &vtableComponent : vtableLayout.vtable_components()) {
2163 if (vtableComponent.isRTTIKind()) {
2164 const CXXRecordDecl *rttiDecl = vtableComponent.getRTTIDecl();
2165 if (rttiDecl->getVisibility() == Visibility::HiddenVisibility)
2166 return true;
2167 } else if (vtableComponent.isUsedFunctionPointerKind()) {
2168 const CXXMethodDecl *method = vtableComponent.getFunctionDecl();
2169 if (method->getVisibility() == Visibility::HiddenVisibility &&
2170 !method->isDefined())
2171 return true;
2172 }
2173 }
2174 return false;
2175}
2176
2177bool CIRGenItaniumCXXABI::canSpeculativelyEmitVTableAsBaseClass(
2178 const CXXRecordDecl *rd) const {
2179 // We don't emit available_externally vtables if we are in -fapple-kext mode
2180 // because kext mode does not permit devirtualization.
2181 if (cgm.getLangOpts().AppleKext)
2182 return false;
2183
2184 // If the vtable is hidden then it is not safe to emit an available_externally
2185 // copy of vtable.
2186 if (isVTableHidden(rd))
2187 return false;
2188
2189 if (cgm.getCodeGenOpts().ForceEmitVTables)
2190 return true;
2191
2192 // A speculative vtable can only be generated if all virtual inline functions
2193 // defined by this class are emitted. The vtable in the final program contains
2194 // for each virtual inline function not used in the current TU a function that
2195 // is equivalent to the unused function. The function in the actual vtable
2196 // does not have to be declared under the same symbol (e.g., a virtual
2197 // destructor that can be substituted with its base class's destructor). Since
2198 // inline functions are emitted lazily and this emissions does not account for
2199 // speculative emission of a vtable, we might generate a speculative vtable
2200 // with references to inline functions that are not emitted under that name.
2201 // This can lead to problems when devirtualizing a call to such a function,
2202 // that result in linking errors. Hence, if there are any unused virtual
2203 // inline function, we cannot emit the speculative vtable.
2204 // FIXME we can still emit a copy of the vtable if we
2205 // can emit definition of the inline functions.
2206 if (hasAnyUnusedVirtualInlineFunction(rd))
2207 return false;
2208
2209 // For a class with virtual bases, we must also be able to speculatively
2210 // emit the VTT, because CodeGen doesn't have separate notions of "can emit
2211 // the vtable" and "can emit the VTT". For a base subobject, this means we
2212 // need to be able to emit non-virtual base vtables.
2213 if (rd->getNumVBases()) {
2214 for (const auto &b : rd->bases()) {
2215 auto *brd = b.getType()->getAsCXXRecordDecl();
2216 assert(brd && "no class for base specifier");
2217 if (b.isVirtual() || !brd->isDynamicClass())
2218 continue;
2219 if (!canSpeculativelyEmitVTableAsBaseClass(brd))
2220 return false;
2221 }
2222 }
2223
2224 return true;
2225}
2226
2227bool CIRGenItaniumCXXABI::canSpeculativelyEmitVTable(
2228 const CXXRecordDecl *rd) const {
2229 if (!canSpeculativelyEmitVTableAsBaseClass(rd))
2230 return false;
2231
2233 return false;
2234
2235 // For a complete-object vtable (or more specifically, for the VTT), we need
2236 // to be able to speculatively emit the vtables of all dynamic virtual bases.
2237 for (const auto &b : rd->vbases()) {
2238 auto *brd = b.getType()->getAsCXXRecordDecl();
2239 assert(brd && "no class for base specifier");
2240 if (!brd->isDynamicClass())
2241 continue;
2242 if (!canSpeculativelyEmitVTableAsBaseClass(brd))
2243 return false;
2244 }
2245
2246 return true;
2247}
2248
2250 Address initialPtr,
2251 const CXXRecordDecl *unadjustedClass,
2252 int64_t nonVirtualAdjustment,
2253 int64_t virtualAdjustment,
2254 bool isReturnAdjustment) {
2255 if (!nonVirtualAdjustment && !virtualAdjustment)
2256 return initialPtr.getPointer();
2257
2258 CIRGenBuilderTy &builder = cgf.getBuilder();
2259 mlir::Location loc = builder.getUnknownLoc();
2260 cir::PointerType i8PtrTy = builder.getUInt8PtrTy();
2261 mlir::Value v = builder.createBitcast(initialPtr.getPointer(), i8PtrTy);
2262
2263 // In a base-to-derived cast, the non-virtual adjustment is applied first.
2264 if (nonVirtualAdjustment && !isReturnAdjustment) {
2265 cir::ConstantOp offsetConst = builder.getSInt64(nonVirtualAdjustment, loc);
2266 v = cir::PtrStrideOp::create(builder, loc, i8PtrTy, v, offsetConst);
2267 }
2268
2269 // Perform the virtual adjustment if we have one.
2270 mlir::Value resultPtr;
2271 if (virtualAdjustment) {
2272 mlir::Value vtablePtr = cgf.getVTablePtr(
2273 loc, Address(v, clang::CharUnits::One()), unadjustedClass);
2274 vtablePtr = builder.createBitcast(vtablePtr, i8PtrTy);
2275
2276 mlir::Value offset;
2277 mlir::Value offsetPtr =
2278 cir::PtrStrideOp::create(builder, loc, i8PtrTy, vtablePtr,
2279 builder.getSInt64(virtualAdjustment, loc));
2280 if (cgf.cgm.getLangOpts().RelativeCXXABIVTables) {
2282 cgf.cgm.errorNYI("virtual adjustment for relative layout vtables");
2283 } else {
2284 offset = builder.createAlignedLoad(loc, cgf.ptrDiffTy, offsetPtr,
2285 cgf.getPointerAlign());
2286 }
2287
2288 resultPtr = cir::PtrStrideOp::create(builder, loc, i8PtrTy, v, offset);
2289 } else {
2290 resultPtr = v;
2291 }
2292
2293 // In a derived-to-base conversion, the non-virtual adjustment is
2294 // applied second.
2295 if (nonVirtualAdjustment && isReturnAdjustment) {
2296 cir::ConstantOp offsetConst = builder.getSInt64(nonVirtualAdjustment, loc);
2297 resultPtr =
2298 cir::PtrStrideOp::create(builder, loc, i8PtrTy, resultPtr, offsetConst);
2299 }
2300
2301 // Cast back to original pointer type.
2302 return builder.createBitcast(resultPtr, initialPtr.getType());
2303}
2304
2305mlir::Value CIRGenItaniumCXXABI::performThisAdjustment(
2306 CIRGenFunction &cgf, Address thisAddr, const CXXRecordDecl *unadjustedClass,
2307 const ThunkInfo &ti) {
2308 return performTypeAdjustment(cgf, thisAddr, unadjustedClass,
2309 ti.This.NonVirtual,
2311 /*isReturnAdjustment=*/false);
2312}
2313
2314mlir::Value CIRGenItaniumCXXABI::performReturnAdjustment(
2315 CIRGenFunction &cgf, Address ret, const CXXRecordDecl *unadjustedClass,
2316 const ReturnAdjustment &ra) {
2317 return performTypeAdjustment(cgf, ret, unadjustedClass, ra.NonVirtual,
2319 /*isReturnAdjustment=*/true);
2320}
2321
2322bool CIRGenItaniumCXXABI::isZeroInitializable(const MemberPointerType *mpt) {
2323 return mpt->isMemberFunctionPointer();
2324}
static void emitConstructorDestructorAlias(CIRGenModule &cgm, GlobalDecl aliasDecl, GlobalDecl targetDecl)
static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc, mlir::Value exceptionPtr={}, mlir::FlatSymbolRefAttr typeInfo={}, mlir::FlatSymbolRefAttr dtor={})
static Address emitDynamicCastToVoid(CIRGenFunction &cgf, mlir::Location loc, QualType srcRecordTy, Address src)
static cir::DynamicCastInfoAttr emitDynamicCastInfo(CIRGenFunction &cgf, mlir::Location loc, QualType srcRecordTy, QualType destRecordTy)
static cir::GlobalLinkageKind getTypeInfoLinkage(CIRGenModule &cgm, QualType ty)
Return the linkage that the type info and type info name constants should have for the given type.
static mlir::Value performTypeAdjustment(CIRGenFunction &cgf, Address initialPtr, const CXXRecordDecl *unadjustedClass, int64_t nonVirtualAdjustment, int64_t virtualAdjustment, bool isReturnAdjustment)
static mlir::Value emitExactDynamicCast(CIRGenItaniumCXXABI &abi, CIRGenFunction &cgf, mlir::Location loc, QualType srcRecordTy, QualType destRecordTy, cir::PointerType destCIRTy, bool isRefCast, Address src)
static void emitCallToBadCast(CIRGenFunction &cgf, mlir::Location loc)
static cir::FuncOp getItaniumDynamicCastFn(CIRGenFunction &cgf)
static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm, const CXXMethodDecl *md)
static cir::FuncOp getBadCastFn(CIRGenFunction &cgf)
static RValue performReturnAdjustment(CIRGenFunction &cgf, QualType resultType, RValue rv, const ThunkInfo &thunk)
Defines the clang::Expr interface and subclasses for C++ expressions.
static QualType getPointeeType(const MemRegion *R)
C Language Family Type Representation.
cir::GlobalViewAttr getGlobalViewAttr(cir::GlobalOp globalOp, mlir::ArrayAttr indices={})
Get constant address of a global variable as an MLIR attribute.
mlir::Value createPtrIsNull(mlir::Value ptr)
cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base, mlir::Value stride)
cir::PointerType getPointerTo(mlir::Type ty)
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc)
mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy)
mlir::Value getSignedInt(mlir::Location loc, int64_t val, unsigned numBits)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind, mlir::Value lhs, mlir::Value rhs)
mlir::Value createNot(mlir::Location loc, mlir::Value value)
cir::PointerType getVoidPtrTy(clang::LangAS langAS=clang::LangAS::Default)
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
llvm::Align getABITypeAlign(mlir::Type ty) const
CharUnits getTypeAlignInChars(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in characters.
CanQualType LongTy
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
CanQualType VoidPtrTy
IdentifierTable & Idents
Definition ASTContext.h:856
const LangOptions & getLangOpts() const
QualType getPointerDiffType() const
Return the unique type for "ptrdiff_t" (C99 7.17) defined in <stddef.h>.
CanQualType CharTy
CharUnits getExnObjectAlignment() const
Return the alignment (in bytes) of the thrown exception object.
CharUnits getPreferredTypeAlignInChars(QualType T) const
Return the PreferredAlignment of a (complete) type T, in characters.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedIntTy
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:975
CharUnits toCharUnitsFromBits(int64_t BitSize) const
Convert a size in bits to a size in characters.
TargetCXXABI::Kind getCXXABIKind() const
Return the C++ ABI kind that should be used.
CanQualType LongLongTy
CanQualType getCanonicalTagType(const TagDecl *TD) const
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const
getVBaseClassOffset - Get the offset, in chars, for the given base class.
const CXXRecordDecl * getBase() const
getBase - Returns the base class declaration.
mlir::Value getPointer() const
Definition Address.h:98
mlir::Type getElementType() const
Definition Address.h:125
clang::CharUnits getAlignment() const
Definition Address.h:138
mlir::Type getType() const
Definition Address.h:117
mlir::Value emitRawPointer() const
Return the pointer contained in this class after authenticating it and adding offset to it if necessa...
Definition Address.h:112
cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr)
cir::ConstantOp getSInt64(uint64_t c, mlir::Location loc)
cir::PointerType getUInt8PtrTy()
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false, bool isNontemporal=false)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, bool isNontemporal=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr, llvm::MaybeAlign align)
cir::FuncType getFuncType(llvm::ArrayRef< mlir::Type > params, mlir::Type retTy, bool isVarArg=false)
mlir::Value createDynCastToVoid(mlir::Location loc, mlir::Value src, bool vtableUseRelativeLayout)
mlir::Value createDynCast(mlir::Location loc, mlir::Value src, cir::PointerType destType, bool isRefCast, cir::DynamicCastInfoAttr info)
mlir::Attribute getString(llvm::StringRef str, mlir::Type eltTy, std::optional< size_t > size, bool ensureNullTerm=true)
Get a cir::ConstArrayAttr for a string literal.
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
mlir::Value createVTTAddrPoint(mlir::Location loc, mlir::Type retTy, mlir::Value addr, uint64_t offset)
Implements C++ ABI-specific code generation functions.
clang::MangleContext & getMangleContext()
Gets the mangle context.
static CIRGenCallee forDirect(mlir::Operation *funcPtr, const CIRGenCalleeInfo &abstractInfo=CIRGenCalleeInfo())
Definition CIRGenCall.h:92
static CIRGenCallee forVirtual(const clang::CallExpr *ce, clang::GlobalDecl md, Address addr, cir::FuncType fTy)
Definition CIRGenCall.h:154
mlir::Type convertType(clang::QualType t)
clang::GlobalDecl curGD
The GlobalDecl for the current function being compiled or the global variable currently being initial...
const clang::Decl * curFuncDecl
Address getAddrOfLocalVar(const clang::VarDecl *vd)
Return the address of a local variable.
void emitAnyExprToExn(const Expr *e, Address addr)
mlir::Value getVTTParameter(GlobalDecl gd, bool forVirtualBase, bool delegating)
Return the VTT parameter that should be passed to a base constructor/destructor with virtual bases.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
mlir::Value loadCXXVTT()
Load the VTT parameter to base constructors/destructors have virtual bases.
mlir::Value getVTablePtr(mlir::Location loc, Address thisAddr, const clang::CXXRecordDecl *vtableClass)
Return the Value of the vtable pointer member pointed to by thisAddr.
bool shouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *rd)
Returns whether we should perform a type checked load when loading a virtual function for virtual cal...
CIRGenBuilderTy & getBuilder()
mlir::Value emitRuntimeCall(mlir::Location loc, cir::FuncOp callee, llvm::ArrayRef< mlir::Value > args={}, mlir::NamedAttrList attrs={})
std::optional< SourceRange > currSrcLoc
Use to track source locations across nested visitor traversals.
void emitCXXDestructorCall(const CXXDestructorDecl *dd, CXXDtorType type, bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy)
clang::ASTContext & getContext() const
This class organizes the cross-function state that is used while generating CIR code.
llvm::StringRef getMangledName(clang::GlobalDecl gd)
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
clang::ASTContext & getASTContext() const
cir::FuncOp getAddrOfCXXStructor(clang::GlobalDecl gd, const CIRGenFunctionInfo *fnInfo=nullptr, cir::FuncType fnType=nullptr, bool dontDefer=false, ForDefinition_t isForDefinition=NotForDefinition)
void addReplacement(llvm::StringRef name, mlir::Operation *op)
mlir::Type convertType(clang::QualType type)
mlir::IntegerAttr getSize(CharUnits size)
CIRGenBuilderTy & getBuilder()
ItaniumVTableContext & getItaniumVTableContext()
void setGVProperties(mlir::Operation *op, const NamedDecl *d) const
Set visibility, dllimport/dllexport and dso_local.
mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc, QualType ty, bool forEH=false)
Get the address of the RTTI descriptor for the given type.
const clang::TargetInfo & getTarget() const
const llvm::Triple & getTriple() const
static mlir::SymbolTable::Visibility getMLIRVisibility(Visibility v)
const cir::CIRDataLayout & getDataLayout() const
cir::GlobalOp createOrReplaceCXXRuntimeVariable(mlir::Location loc, llvm::StringRef name, mlir::Type ty, cir::GlobalLinkageKind linkage, clang::CharUnits alignment)
Will return a global variable of the given type.
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, mlir::NamedAttrList extraAttrs={}, bool isLocal=false, bool assumeConvergent=false)
void emitAliasForGlobal(llvm::StringRef mangledName, mlir::Operation *op, GlobalDecl aliasGD, cir::FuncOp aliasee, cir::GlobalLinkageKind linkage)
void eraseGlobalSymbol(mlir::Operation *op)
static void setInitializer(cir::GlobalOp &op, mlir::Attribute value)
cir::GlobalLinkageKind getFunctionLinkage(GlobalDecl gd)
const clang::CodeGenOptions & getCodeGenOpts() const
const clang::LangOptions & getLangOpts() const
cir::GlobalOp createGlobalOp(mlir::Location loc, llvm::StringRef name, mlir::Type t, bool isConstant=false, mlir::ptr::MemorySpaceAttrInterface addrSpace={}, mlir::Operation *insertPoint=nullptr)
void addDeferredVTable(const CXXRecordDecl *rd)
cir::FuncOp codegenCXXStructor(clang::GlobalDecl gd)
mlir::Location getLoc(clang::SourceLocation cLoc)
Helpers to convert the presumed location of Clang's SourceLocation to an MLIR Location.
mlir::Operation * getGlobalValue(llvm::StringRef ref)
mlir::MLIRContext & getMLIRContext()
mlir::Operation * getAddrOfGlobal(clang::GlobalDecl gd, ForDefinition_t isForDefinition=NotForDefinition)
void maybeSetTrivialComdat(const clang::Decl &d, mlir::Operation *op)
CIRGenCXXABI & getCXXABI() const
void emitGlobal(clang::GlobalDecl gd)
Emit code for a single global function or variable declaration.
CIRGenVTables & getVTables()
cir::GlobalLinkageKind getVTableLinkage(const CXXRecordDecl *rd)
Return the appropriate linkage for the vtable, VTT, and type information of the given class.
const CIRGenFunctionInfo & arrangeCXXStructorDeclaration(clang::GlobalDecl gd)
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info)
Get the CIR function type for.
cir::RecordType getVTableType(const clang::VTableLayout &layout)
Returns the type of a vtable with the given layout.
void createVTableInitializer(cir::GlobalOp &vtable, const clang::VTableLayout &layout, mlir::Attribute rtti, bool vtableHasLocalLinkage)
Add vtable components for the given vtable layout to the given global initializer.
void emitVTTDefinition(cir::GlobalOp vttOp, cir::GlobalLinkageKind linkage, const CXXRecordDecl *rd)
Emit the definition of the given vtable.
cir::GlobalOp getAddrOfVTT(const CXXRecordDecl *rd)
Get the address of the VTT for the given record decl.
bool isVTableExternal(const clang::CXXRecordDecl *rd)
At this point in the translation unit, does it appear that can we rely on the vtable being defined el...
uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *rd, BaseSubobject base)
Return the index in the VTT where the virtual pointer for the given subobject is located.
Represents a path from a specific derived class (which is not represented as part of the path) to a p...
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
QualType getType() const
Retrieves the type of the base class.
Definition DeclCXX.h:249
bool isGlobalDelete() const
Definition ExprCXX.h:2656
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2150
bool isVirtual() const
Definition DeclCXX.h:2205
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2293
CXXMethodDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition DeclCXX.h:2263
SourceRange getSourceRange() const
Definition ExprCXX.h:2615
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool isEffectivelyFinal() const
Determine whether it's impossible for a class to be derived from this class.
Definition DeclCXX.cpp:2341
base_class_range bases()
Definition DeclCXX.h:609
unsigned getNumBases() const
Retrieves the number of base classes of this class.
Definition DeclCXX.h:603
base_class_iterator bases_begin()
Definition DeclCXX.h:616
base_class_range vbases()
Definition DeclCXX.h:626
bool isAbstract() const
Determine whether this class has a pure virtual function.
Definition DeclCXX.h:1231
bool isDynamicClass() const
Definition DeclCXX.h:575
bool hasDefinition() const
Definition DeclCXX.h:562
unsigned getNumVBases() const
Retrieves the number of virtual base classes of this class.
Definition DeclCXX.h:624
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
const Expr * getSubExpr() const
Definition ExprCXX.h:1233
static CanQual< Type > CreateUnsafe(QualType Other)
This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
CharUnits alignmentAtOffset(CharUnits offset) const
Given that this is a non-zero alignment value, what is the alignment at the given offset?
Definition CharUnits.h:177
bool isZero() const
Test whether the quantity equals zero.
Definition CharUnits.h:101
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
Definition CharUnits.h:155
static CharUnits One()
Construct a CharUnits quantity of one.
Definition CharUnits.h:55
static CharUnits fromQuantity(QuantityType Quantity)
Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:58
static CharUnits Zero()
Construct a CharUnits quantity of zero.
Definition CharUnits.h:52
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2120
bool isTranslationUnit() const
Definition DeclBase.h:2216
SourceLocation getLocation() const
Definition DeclBase.h:447
DeclContext * getDeclContext()
Definition DeclBase.h:456
bool hasAttr() const
Definition DeclBase.h:585
bool shouldEmitInExternalSource() const
Whether the definition of the declaration should be emitted in external sources.
QualType getType() const
Definition Expr.h:145
bool isInlined() const
Determine whether this function should be inlined, because it is either marked "inline" or "constexpr...
Definition Decl.h:3056
FunctionDecl * getDefinition()
Get the definition for this declaration.
Definition Decl.h:2396
bool isDefined(const FunctionDecl *&Definition, bool CheckForPendingFriendDefinition=false) const
Returns true if the function has a definition that does not need to be instantiated.
Definition Decl.cpp:3238
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:60
GlobalDecl getWithCtorType(CXXCtorType Type)
Definition GlobalDecl.h:176
CXXCtorType getCtorType() const
Definition GlobalDecl.h:117
GlobalDecl getWithDtorType(CXXDtorType Type)
Definition GlobalDecl.h:183
CXXDtorType getDtorType() const
Definition GlobalDecl.h:122
const Decl * getDecl() const
Definition GlobalDecl.h:115
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
static ImplicitParamDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, ImplicitParamKind ParamKind)
Create implicit parameter.
Definition Decl.cpp:5683
virtual void mangleCXXCtorComdat(const CXXConstructorDecl *D, raw_ostream &)=0
virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D, raw_ostream &)=0
uint64_t getMethodVTableIndex(GlobalDecl GD)
Locate a virtual function in the vtable.
const VTableLayout & getVTableLayout(const CXXRecordDecl *RD)
CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, const CXXRecordDecl *VBase)
Return the offset in chars (relative to the vtable address point) where the offset of the virtual bas...
virtual void mangleCXXRTTI(QualType T, raw_ostream &)=0
virtual void mangleCXXRTTIName(QualType T, raw_ostream &, bool NormalizeIntegers=false)=0
CXXRecordDecl * getMostRecentCXXRecordDecl() const
Note: this can trigger extra deserialization when external AST sources are used.
Definition Type.cpp:5847
QualType getPointeeType() const
Definition TypeBase.h:3769
bool isMemberFunctionPointer() const
Returns true if the member type (i.e.
Definition TypeBase.h:3773
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:296
Visibility getVisibility() const
Determines the visibility of this entity.
Definition Decl.h:445
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
QualType getCanonicalType() const
Definition TypeBase.h:8498
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8540
Encodes a location in the source.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:4974
bool hasConstructorVariants() const
Does this ABI have different entrypoints for complete-object and base-subobject constructors?
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
uint64_t getPointerWidth(LangAS AddrSpace) const
Return the width of pointers on this target, for the specified address space.
Definition TargetInfo.h:497
virtual bool hasPS4DLLImportExport() const
uint64_t getPointerAlign(LangAS AddrSpace) const
Definition TargetInfo.h:501
TargetCXXABI getCXXABI() const
Get the C++ ABI currently in use.
unsigned getLongWidth() const
getLongWidth/Align - Return the size of 'signed long' and 'unsigned long' for this target,...
Definition TargetInfo.h:543
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h:3686
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
CXXRecordDecl * castAsCXXRecordDecl() const
Definition Type.h:36
Visibility getVisibility() const
Determine the visibility of this type.
Definition TypeBase.h:3146
Linkage getLinkage() const
Determine the linkage of this type.
Definition Type.cpp:5202
TypeClass getTypeClass() const
Definition TypeBase.h:2449
AddressPointLocation getAddressPoint(BaseSubobject Base) const
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2170
bool isNoDestroy(const ASTContext &) const
Is destruction of this variable entirely suppressed?
Definition Decl.cpp:2811
static bool isLocalLinkage(GlobalLinkageKind linkage)
Definition CIROpsEnums.h:51
static bool isValidLinkage(GlobalLinkageKind gl)
static bool isWeakForLinker(GlobalLinkageKind linkage)
Whether the definition of this global may be replaced at link time.
static bool isDiscardableIfUnused(GlobalLinkageKind linkage)
Whether the definition of this global may be discarded if it is not used in its compilation unit.
Definition CIROpsEnums.h:95
CIRGenCXXABI * CreateCIRGenItaniumCXXABI(CIRGenModule &cgm)
Creates and Itanium-family ABI.
unsigned extractPBaseFlags(const ASTContext &Ctx, QualType &Type)
Compute the flags for a __pbase_type_info, and remove the corresponding pieces from Type.
bool containsIncompleteClassType(QualType Ty)
Returns whether the given type contains an incomplete class type.
bool canUseSingleInheritance(const CXXRecordDecl *RD)
Return whether the given record decl has a "single, public, non-virtual base at offset zero (i....
unsigned computeVMIClassTypeInfoFlags(const CXXRecordDecl *RD)
Compute the value of the flags member in abi::__vmi_class_type_info.
CharUnits computeOffsetHint(ASTContext &Ctx, const CXXRecordDecl *Src, const CXXRecordDecl *Dst)
Compute the src2dst_offset hint as described in the Itanium C++ ABI [2.9.7].
bool isStandardLibraryRTTIDescriptor(QualType Ty)
Returns whether the type information for the given type exists in the standard library.
@ BCTI_Virtual
BCTI_Virtual - Base class is virtual.
@ BCTI_Public
BCTI_Public - Base class is public.
@ PTI_ContainingClassIncomplete
PTI_ContainingClassIncomplete - Containing class is incomplete.
llvm::Value * getCXXDestructorImplicitParam(CodeGenModule &CGM, llvm::BasicBlock *InsertBlock, llvm::BasicBlock::iterator InsertPoint, const CXXDestructorDecl *D, CXXDtorType Type, bool ForVirtualBase, bool Delegating)
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition PrimType.h:218
@ Address
A pointer to a ValueDecl.
Definition Primitives.h:28
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
Top level wrappers for InstallAPI frontend operations.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
CXXCtorType
C++ constructor types.
Definition ABI.h:24
@ Ctor_Base
Base object ctor.
Definition ABI.h:26
@ Ctor_Complete
Complete object ctor.
Definition ABI.h:25
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ AS_public
Definition Specifiers.h:128
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ VisibleNone
No linkage according to the standard, but is visible from other translation units because of types de...
Definition Linkage.h:48
@ None
No linkage, which means that the entity is unique and can only be referred to from within its scope.
Definition Linkage.h:30
@ UniqueExternal
External linkage within a unique namespace.
Definition Linkage.h:44
@ Internal
Internal linkage, which indicates that the entity can be referred to from within the translation unit...
Definition Linkage.h:35
@ External
External linkage, which indicates that the entity can be referred to from other translation units.
Definition Linkage.h:58
@ Module
Module linkage, which indicates that the entity can be referred to from other translation units withi...
Definition Linkage.h:54
CXXDtorType
C++ destructor types.
Definition ABI.h:34
@ Dtor_Base
Base object dtor.
Definition ABI.h:37
@ Dtor_Complete
Complete object dtor.
Definition ABI.h:36
@ Dtor_Deleting
Deleting dtor.
Definition ABI.h:35
U cast(CodeGen::Address addr)
Definition Address.h:327
@ DefaultVisibility
Objects with "default" visibility are seen by the dynamic linker and act like normal objects.
Definition Visibility.h:46
unsigned long uint64_t
long int64_t
static bool addressSpace()
static bool opGlobalUnnamedAddr()
static bool vtableEmitMetadata()
static bool emitTypeMetadataCodeForVCall()
static bool opFuncReadOnly()
static bool setDLLStorageClass()
static bool hiddenVisibility()
static bool cxxabiAppleARM64CXXABI()
static bool opGlobalDLLImportExport()
static bool opGlobalPartition()
static bool pointerAuthentication()
static bool opFuncCallingConv()
static bool opFuncWillReturn()
static bool protectedVisibility()
static bool cxxabiUseARMGuardVarABI()
static bool cxxabiUseARMMethodPtrABI()
static bool setDSOLocal()
static bool vtableRelativeLayout()
const clang::CXXRecordDecl * nearestVBase
clang::CharUnits getPointerAlign() const
clang::CharUnits getSizeSize() const
Represents an element in a path from a derived class to a base class.
union clang::ReturnAdjustment::VirtualAdjustment Virtual
int64_t NonVirtual
The non-virtual adjustment from the derived object to its nearest virtual base.
Definition Thunk.h:30
union clang::ThisAdjustment::VirtualAdjustment Virtual
int64_t NonVirtual
The non-virtual adjustment from the derived object to its nearest virtual base.
Definition Thunk.h:95
ThisAdjustment This
The this pointer adjustment.
Definition Thunk.h:159
struct clang::ReturnAdjustment::VirtualAdjustment::@103031170252120233124322035264172076254313213024 Itanium
int64_t VBaseOffsetOffset
The offset (in bytes), relative to the address point of the virtual base class offset.
Definition Thunk.h:39
struct clang::ThisAdjustment::VirtualAdjustment::@106065375072164260365214033034320247050276346205 Itanium
int64_t VCallOffsetOffset
The offset (in bytes), relative to the address point, of the virtual call offset.
Definition Thunk.h:104