clang 23.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/TypeBase.h"
28#include "llvm/Support/ErrorHandling.h"
29
30using namespace clang;
31using namespace clang::CIRGen;
32
33namespace {
34
35class CIRGenItaniumCXXABI : public CIRGenCXXABI {
36protected:
37 /// All the vtables which have been defined.
38 llvm::DenseMap<const CXXRecordDecl *, cir::GlobalOp> vtables;
39
40public:
41 CIRGenItaniumCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) {
44 }
45
46 AddedStructorArgs getImplicitConstructorArgs(CIRGenFunction &cgf,
47 const CXXConstructorDecl *d,
49 bool forVirtualBase,
50 bool delegating) override;
51
52 bool needsVTTParameter(clang::GlobalDecl gd) override;
53
54 AddedStructorArgCounts
55 buildStructorSignature(GlobalDecl gd,
56 llvm::SmallVectorImpl<CanQualType> &argTys) override;
57
58 void emitInstanceFunctionProlog(SourceLocation loc,
59 CIRGenFunction &cgf) override;
60
61 void addImplicitStructorParams(CIRGenFunction &cgf, QualType &resTy,
62 FunctionArgList &params) override;
63 mlir::Value getCXXDestructorImplicitParam(CIRGenFunction &cgf,
64 const CXXDestructorDecl *dd,
66 bool forVirtualBase,
67 bool delegating) override;
68 void emitCXXConstructors(const clang::CXXConstructorDecl *d) override;
69 void emitCXXDestructors(const clang::CXXDestructorDecl *d) override;
70 void emitCXXStructor(clang::GlobalDecl gd) override;
71
72 void emitDestructorCall(CIRGenFunction &cgf, const CXXDestructorDecl *dd,
73 CXXDtorType type, bool forVirtualBase,
74 bool delegating, Address thisAddr,
75 QualType thisTy) override;
76 void registerGlobalDtor(const VarDecl *vd, cir::FuncOp dtor,
77 mlir::Value addr) override;
78 void emitVirtualObjectDelete(CIRGenFunction &cgf, const CXXDeleteExpr *de,
79 Address ptr, QualType elementType,
80 const CXXDestructorDecl *dtor) override;
81
82 void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
83 void emitThrow(CIRGenFunction &cgf, const CXXThrowExpr *e) override;
84
85 void emitBeginCatch(CIRGenFunction &cgf, const CXXCatchStmt *catchStmt,
86 mlir::Value ehToken) override;
87
88 bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
89 CXXDtorType dt) const override {
90 // Itanium does not emit any destructor variant as an inline thunk.
91 // Delegating may occur as an optimization, but all variants are either
92 // emitted with external linkage or as linkonce if they are inline and used.
93 return false;
94 }
95
96 bool isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf,
97 CIRGenFunction::VPtr vptr) override;
98
99 cir::GlobalOp getAddrOfVTable(const CXXRecordDecl *rd,
100 CharUnits vptrOffset) override;
101 CIRGenCallee getVirtualFunctionPointer(CIRGenFunction &cgf,
102 clang::GlobalDecl gd, Address thisAddr,
103 mlir::Type ty,
104 SourceLocation loc) override;
105 mlir::Value emitVirtualDestructorCall(CIRGenFunction &cgf,
106 const CXXDestructorDecl *dtor,
107 CXXDtorType dtorType, Address thisAddr,
108 DeleteOrMemberCallExpr e) override;
109
110 bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const override;
111 bool canSpeculativelyEmitVTableAsBaseClass(const CXXRecordDecl *RD) const;
112
113 mlir::Value getVTableAddressPoint(BaseSubobject base,
114 const CXXRecordDecl *vtableClass) override;
115 mlir::Value getVTableAddressPointInStructorWithVTT(
116 CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,
117 const CXXRecordDecl *nearestVBase);
118
119 mlir::Value getVTableAddressPointInStructor(
120 CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
121 clang::BaseSubobject base,
122 const clang::CXXRecordDecl *nearestVBase) override;
123 void emitVTableDefinitions(CIRGenVTables &cgvt,
124 const CXXRecordDecl *rd) override;
125 void emitVirtualInheritanceTables(const CXXRecordDecl *rd) override;
126
127 void setThunkLinkage(cir::FuncOp thunk, bool forVTable, GlobalDecl gd,
128 bool returnAdjustment) override {
129 if (forVTable && !thunk.hasLocalLinkage())
130 thunk.setLinkage(cir::GlobalLinkageKind::AvailableExternallyLinkage);
131 const auto *nd = cast<NamedDecl>(gd.getDecl());
132 cgm.setGVProperties(thunk, nd);
133 }
134
135 bool exportThunk() override { return true; }
136
137 mlir::Value performThisAdjustment(CIRGenFunction &cgf, Address thisAddr,
138 const CXXRecordDecl *unadjustedClass,
139 const ThunkInfo &ti) override;
140
141 mlir::Value performReturnAdjustment(CIRGenFunction &cgf, Address ret,
142 const CXXRecordDecl *unadjustedClass,
143 const ReturnAdjustment &ra) override;
144
145 bool shouldTypeidBeNullChecked(QualType srcTy) override;
146 mlir::Value emitTypeid(CIRGenFunction &cgf, QualType SrcRecordTy,
147 Address thisPtr, mlir::Type StdTypeInfoPtrTy) override;
148 void emitBadTypeidCall(CIRGenFunction &cgf, mlir::Location loc) override;
149
150 mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
151 QualType ty) override;
152
153 StringRef getPureVirtualCallName() override { return "__cxa_pure_virtual"; }
154 StringRef getDeletedVirtualCallName() override {
155 return "__cxa_deleted_virtual";
156 }
157
158 CatchTypeInfo
159 getAddrOfCXXCatchHandlerType(mlir::Location loc, QualType ty,
160 QualType catchHandlerType) override {
161 auto rtti = dyn_cast<cir::GlobalViewAttr>(getAddrOfRTTIDescriptor(loc, ty));
162 assert(rtti && "expected GlobalViewAttr");
163 return CatchTypeInfo{rtti, 0};
164 }
165
166 bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
167 return true;
168 }
169
170 size_t getSrcArgforCopyCtor(const CXXConstructorDecl *,
171 FunctionArgList &args) const override {
172 assert(!args.empty() && "expected the arglist to not be empty!");
173 return args.size() - 1;
174 }
175
176 void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) override;
177
178 mlir::Value
179 getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf,
180 Address thisAddr, const CXXRecordDecl *classDecl,
181 const CXXRecordDecl *baseClassDecl) override;
182
183 // The traditional clang CodeGen emits calls to `__dynamic_cast` directly into
184 // LLVM in the `emitDynamicCastCall` function. In CIR, `dynamic_cast`
185 // expressions are lowered to `cir.dyn_cast` ops instead of calls to runtime
186 // functions. So during CIRGen we don't need the `emitDynamicCastCall`
187 // function that clang CodeGen has.
188 mlir::Value emitDynamicCast(CIRGenFunction &cgf, mlir::Location loc,
189 QualType srcRecordTy, QualType destRecordTy,
190 cir::PointerType destCIRTy, bool isRefCast,
191 Address src) override;
192
193 cir::MethodAttr buildVirtualMethodAttr(cir::MethodType methodTy,
194 const CXXMethodDecl *md) override;
195
196 Address initializeArrayCookie(CIRGenFunction &cgf, Address newPtr,
197 mlir::Value numElements, const CXXNewExpr *e,
198 QualType elementType) override;
199
200 bool isZeroInitializable(const MemberPointerType *MPT) override;
201
202protected:
203 CharUnits getArrayCookieSizeImpl(QualType elementType) override;
204
205 /**************************** RTTI Uniqueness ******************************/
206 /// Returns true if the ABI requires RTTI type_info objects to be unique
207 /// across a program.
208 virtual bool shouldRTTIBeUnique() const { return true; }
209
210public:
211 /// What sort of unique-RTTI behavior should we use?
212 enum RTTIUniquenessKind {
213 /// We are guaranteeing, or need to guarantee, that the RTTI string
214 /// is unique.
215 RUK_Unique,
216
217 /// We are not guaranteeing uniqueness for the RTTI string, so we
218 /// can demote to hidden visibility but must use string comparisons.
219 RUK_NonUniqueHidden,
220
221 /// We are not guaranteeing uniqueness for the RTTI string, so we
222 /// have to use string comparisons, but we also have to emit it with
223 /// non-hidden visibility.
224 RUK_NonUniqueVisible
225 };
226
227 /// Return the required visibility status for the given type and linkage in
228 /// the current ABI.
229 RTTIUniquenessKind
230 classifyRTTIUniqueness(QualType canTy, cir::GlobalLinkageKind linkage) const;
231
232private:
233 bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *rd) const;
234 bool isVTableHidden(const CXXRecordDecl *rd) const;
235};
236
237} // namespace
238
239void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc,
240 CIRGenFunction &cgf) {
241 // Naked functions have no prolog.
242 if (cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<NakedAttr>()) {
244 "emitInstanceFunctionProlog: Naked");
245 }
246
247 /// Initialize the 'this' slot. In the Itanium C++ ABI, no prologue
248 /// adjustments are required, because they are all handled by thunks.
249 setCXXABIThisValue(cgf, loadIncomingCXXThis(cgf));
250
251 /// Initialize the 'vtt' slot if needed.
252 if (getStructorImplicitParamDecl(cgf)) {
253 cir::LoadOp val = cgf.getBuilder().createLoad(
254 cgf.getLoc(loc),
255 cgf.getAddrOfLocalVar(getStructorImplicitParamDecl(cgf)));
256 setStructorImplicitParamValue(cgf, val);
257 }
258
259 /// If this is a function that the ABI specifies returns 'this', initialize
260 /// the return slot to this' at the start of the function.
261 ///
262 /// Unlike the setting of return types, this is done within the ABI
263 /// implementation instead of by clients of CIRGenCXXBI because:
264 /// 1) getThisValue is currently protected
265 /// 2) in theory, an ABI could implement 'this' returns some other way;
266 /// HasThisReturn only specifies a contract, not the implementation
267 if (hasThisReturn(cgf.curGD)) {
269 "emitInstanceFunctionProlog: hasThisReturn");
270 }
271}
272
273CIRGenCXXABI::AddedStructorArgCounts
274CIRGenItaniumCXXABI::buildStructorSignature(
275 GlobalDecl gd, llvm::SmallVectorImpl<CanQualType> &argTys) {
276 clang::ASTContext &astContext = cgm.getASTContext();
277
278 // All parameters are already in place except VTT, which goes after 'this'.
279 // These are clang types, so we don't need to worry about sret yet.
280
281 // Check if we need to add a VTT parameter (which has type void **).
283 : gd.getDtorType() == Dtor_Base) &&
284 cast<CXXMethodDecl>(gd.getDecl())->getParent()->getNumVBases() != 0) {
286 argTys.insert(argTys.begin() + 1,
287 astContext.getPointerType(
289 return AddedStructorArgCounts::withPrefix(1);
290 }
291
292 return AddedStructorArgCounts{};
293}
294
295// Find out how to cirgen the complete destructor and constructor
296namespace {
297enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT };
298}
299
300static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm,
301 const CXXMethodDecl *md) {
302 if (!cgm.getCodeGenOpts().CXXCtorDtorAliases)
303 return StructorCIRGen::Emit;
304
305 // The complete and base structors are not equivalent if there are any virtual
306 // bases, so emit separate functions.
307 if (md->getParent()->getNumVBases())
308 return StructorCIRGen::Emit;
309
310 GlobalDecl aliasDecl;
311 if (const auto *dd = dyn_cast<CXXDestructorDecl>(md)) {
312 aliasDecl = GlobalDecl(dd, Dtor_Complete);
313 } else {
314 const auto *cd = cast<CXXConstructorDecl>(md);
315 aliasDecl = GlobalDecl(cd, Ctor_Complete);
316 }
317
318 cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);
319
320 if (cir::isDiscardableIfUnused(linkage))
321 return StructorCIRGen::RAUW;
322
323 // FIXME: Should we allow available_externally aliases?
324 if (!cir::isValidLinkage(linkage))
325 return StructorCIRGen::RAUW;
326
327 if (cir::isWeakForLinker(linkage)) {
328 // Only ELF and wasm support COMDATs with arbitrary names (C5/D5).
329 if (cgm.getTarget().getTriple().isOSBinFormatELF() ||
330 cgm.getTarget().getTriple().isOSBinFormatWasm())
331 return StructorCIRGen::COMDAT;
332 return StructorCIRGen::Emit;
333 }
334
335 return StructorCIRGen::Alias;
336}
337
339 GlobalDecl aliasDecl,
340 GlobalDecl targetDecl) {
341 cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);
342
343 // Does this function alias already exists?
344 StringRef mangledName = cgm.getMangledName(aliasDecl);
345 auto globalValue = dyn_cast_or_null<cir::CIRGlobalValueInterface>(
346 cgm.getGlobalValue(mangledName));
347 if (globalValue && !globalValue.isDeclaration())
348 return;
349
350 auto entry = cast_or_null<cir::FuncOp>(cgm.getGlobalValue(mangledName));
351
352 // Retrieve aliasee info.
353 auto aliasee = cast<cir::FuncOp>(cgm.getAddrOfGlobal(targetDecl));
354
355 // Populate actual alias.
356 cgm.emitAliasForGlobal(mangledName, entry, aliasDecl, aliasee, linkage);
357}
358
359void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) {
360 auto *md = cast<CXXMethodDecl>(gd.getDecl());
361 StructorCIRGen cirGenType = getCIRGenToUse(cgm, md);
362 const auto *cd = dyn_cast<CXXConstructorDecl>(md);
363
364 if (cd ? gd.getCtorType() == Ctor_Complete
365 : gd.getDtorType() == Dtor_Complete) {
366 GlobalDecl baseDecl =
368 ;
369
370 if (cirGenType == StructorCIRGen::Alias ||
371 cirGenType == StructorCIRGen::COMDAT) {
372 emitConstructorDestructorAlias(cgm, gd, baseDecl);
373 return;
374 }
375
376 if (cirGenType == StructorCIRGen::RAUW) {
377 StringRef mangledName = cgm.getMangledName(gd);
378 mlir::Operation *aliasee = cgm.getAddrOfGlobal(baseDecl);
379 cgm.addReplacement(mangledName, aliasee);
380 return;
381 }
382 }
383
384 auto fn = cgm.codegenCXXStructor(gd);
385
386 cgm.maybeSetTrivialComdat(*md, fn);
387}
388
389void CIRGenItaniumCXXABI::addImplicitStructorParams(CIRGenFunction &cgf,
390 QualType &resTy,
391 FunctionArgList &params) {
392 const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());
394
395 // Check if we need a VTT parameter as well.
396 if (needsVTTParameter(cgf.curGD)) {
397 ASTContext &astContext = cgm.getASTContext();
398
399 // FIXME: avoid the fake decl
401 QualType t = astContext.getPointerType(astContext.VoidPtrTy);
402 auto *vttDecl = ImplicitParamDecl::Create(
403 astContext, /*DC=*/nullptr, md->getLocation(),
404 &astContext.Idents.get("vtt"), t, ImplicitParamKind::CXXVTT);
405 params.insert(params.begin() + 1, vttDecl);
406 getStructorImplicitParamDecl(cgf) = vttDecl;
407 }
408}
409
410void CIRGenItaniumCXXABI::emitCXXConstructors(const CXXConstructorDecl *d) {
411 // Just make sure we're in sync with TargetCXXABI.
413
414 // The constructor used for constructing this as a base class;
415 // ignores virtual bases.
416 cgm.emitGlobal(GlobalDecl(d, Ctor_Base));
417
418 // The constructor used for constructing this as a complete class;
419 // constructs the virtual bases, then calls the base constructor.
420 if (!d->getParent()->isAbstract()) {
421 // We don't need to emit the complete ctro if the class is abstract.
422 cgm.emitGlobal(GlobalDecl(d, Ctor_Complete));
423 }
424}
425
426void CIRGenItaniumCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) {
427 // The destructor used for destructing this as a base class; ignores
428 // virtual bases.
429 cgm.emitGlobal(GlobalDecl(d, Dtor_Base));
430
431 // The destructor used for destructing this as a most-derived class;
432 // call the base destructor and then destructs any virtual bases.
433 cgm.emitGlobal(GlobalDecl(d, Dtor_Complete));
434
435 // The destructor in a virtual table is always a 'deleting'
436 // destructor, which calls the complete destructor and then uses the
437 // appropriate operator delete.
438 if (d->isVirtual())
439 cgm.emitGlobal(GlobalDecl(d, Dtor_Deleting));
440}
441
442CIRGenCXXABI::AddedStructorArgs CIRGenItaniumCXXABI::getImplicitConstructorArgs(
443 CIRGenFunction &cgf, const CXXConstructorDecl *d, CXXCtorType type,
444 bool forVirtualBase, bool delegating) {
445 if (!needsVTTParameter(GlobalDecl(d, type)))
446 return AddedStructorArgs{};
447
448 // Insert the implicit 'vtt' argument as the second argument. Make sure to
449 // correctly reflect its address space, which can differ from generic on
450 // some targets.
451 mlir::Value vtt =
452 cgf.getVTTParameter(GlobalDecl(d, type), forVirtualBase, delegating);
453 QualType vttTy =
456 return AddedStructorArgs::withPrefix({{vtt, vttTy}});
457}
458
459/// Return whether the given global decl needs a VTT (virtual table table)
460/// parameter, which it does if it's a base constructor or destructor with
461/// virtual bases.
462bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) {
463 auto *md = cast<CXXMethodDecl>(gd.getDecl());
464
465 // We don't have any virtual bases, just return early.
466 if (!md->getParent()->getNumVBases())
467 return false;
468
469 // Check if we have a base constructor.
471 return true;
472
473 // Check if we have a base destructor.
475 return true;
476
477 return false;
478}
479
480void CIRGenItaniumCXXABI::emitVTableDefinitions(CIRGenVTables &cgvt,
481 const CXXRecordDecl *rd) {
482 cir::GlobalOp vtable = getAddrOfVTable(rd, CharUnits());
483 if (vtable.hasInitializer())
484 return;
485
486 ItaniumVTableContext &vtContext = cgm.getItaniumVTableContext();
487 const VTableLayout &vtLayout = vtContext.getVTableLayout(rd);
488 cir::GlobalLinkageKind linkage = cgm.getVTableLinkage(rd);
489 mlir::Attribute rtti =
492
493 // Classic codegen uses ConstantInitBuilder here, which is a very general
494 // and feature-rich class to generate initializers for global values.
495 // For now, this is using a simpler approach to create the initializer in CIR.
496 cgvt.createVTableInitializer(vtable, vtLayout, rtti,
497 cir::isLocalLinkage(linkage));
498
499 // Set the correct linkage.
500 vtable.setLinkage(linkage);
501
502 if (cgm.supportsCOMDAT() && cir::isWeakForLinker(linkage))
503 vtable.setComdat(true);
504
505 // Set the right visibility.
506 cgm.setGVProperties(vtable, rd);
507
508 // If this is the magic class __cxxabiv1::__fundamental_type_info,
509 // we will emit the typeinfo for the fundamental types. This is the
510 // same behaviour as GCC.
511 const DeclContext *DC = rd->getDeclContext();
512 if (rd->getIdentifier() &&
513 rd->getIdentifier()->isStr("__fundamental_type_info") &&
514 isa<NamespaceDecl>(DC) && cast<NamespaceDecl>(DC)->getIdentifier() &&
515 cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
516 DC->getParent()->isTranslationUnit()) {
517 cgm.errorNYI(rd->getSourceRange(),
518 "emitVTableDefinitions: __fundamental_type_info");
519 }
520
521 [[maybe_unused]] auto vtableAsGlobalValue =
522 dyn_cast<cir::CIRGlobalValueInterface>(*vtable);
523 assert(vtableAsGlobalValue && "VTable must support CIRGlobalValueInterface");
524 // Always emit type metadata on non-available_externally definitions, and on
525 // available_externally definitions if we are performing whole program
526 // devirtualization. For WPD we need the type metadata on all vtable
527 // definitions to ensure we associate derived classes with base classes
528 // defined in headers but with a strong definition only in a shared
529 // library.
531 if (cgm.getCodeGenOpts().WholeProgramVTables) {
532 cgm.errorNYI(rd->getSourceRange(),
533 "emitVTableDefinitions: WholeProgramVTables");
534 }
535
537 if (cgm.getLangOpts().RelativeCXXABIVTables) {
538 cgm.errorNYI(rd->getSourceRange(), "vtableRelativeLayout");
539 }
540}
541
542mlir::Value CIRGenItaniumCXXABI::emitVirtualDestructorCall(
543 CIRGenFunction &cgf, const CXXDestructorDecl *dtor, CXXDtorType dtorType,
544 Address thisAddr, DeleteOrMemberCallExpr expr) {
545 auto *callExpr = dyn_cast<const CXXMemberCallExpr *>(expr);
546 auto *delExpr = dyn_cast<const CXXDeleteExpr *>(expr);
547 assert((callExpr != nullptr) ^ (delExpr != nullptr));
548 assert(callExpr == nullptr || callExpr->arg_begin() == callExpr->arg_end());
549 assert(dtorType == Dtor_Deleting || dtorType == Dtor_Complete);
550
551 GlobalDecl globalDecl(dtor, dtorType);
552 const CIRGenFunctionInfo *fnInfo =
553 &cgm.getTypes().arrangeCXXStructorDeclaration(globalDecl);
554 const cir::FuncType &fnTy = cgm.getTypes().getFunctionType(*fnInfo);
555 auto callee = CIRGenCallee::forVirtual(callExpr, globalDecl, thisAddr, fnTy);
556
557 QualType thisTy =
558 callExpr ? callExpr->getObjectType() : delExpr->getDestroyedType();
559
560 cgf.emitCXXDestructorCall(globalDecl, callee, thisAddr.emitRawPointer(),
561 thisTy, nullptr, QualType(), nullptr);
562 return nullptr;
563}
564
565void CIRGenItaniumCXXABI::emitVirtualInheritanceTables(
566 const CXXRecordDecl *rd) {
567 CIRGenVTables &vtables = cgm.getVTables();
568 cir::GlobalOp vtt = vtables.getAddrOfVTT(rd);
569 vtables.emitVTTDefinition(vtt, cgm.getVTableLinkage(rd), rd);
570}
571
572namespace {
573class CIRGenItaniumRTTIBuilder {
574 CIRGenModule &cgm; // Per-module state.
575 const CIRGenItaniumCXXABI &cxxABI; // Per-module state.
576
577 /// The fields of the RTTI descriptor currently being built.
578 SmallVector<mlir::Attribute, 16> fields;
579
580 // Returns the mangled type name of the given type.
581 cir::GlobalOp getAddrOfTypeName(mlir::Location loc, QualType ty,
582 cir::GlobalLinkageKind linkage);
583
584 /// descriptor of the given type.
585 mlir::Attribute getAddrOfExternalRTTIDescriptor(mlir::Location loc,
586 QualType ty);
587
588 /// Build the vtable pointer for the given type.
589 void buildVTablePointer(mlir::Location loc, const Type *ty);
590
591 /// Build an abi::__si_class_type_info, used for single inheritance, according
592 /// to the Itanium C++ ABI, 2.9.5p6b.
593 void buildSIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
594
595 /// Build an abi::__vmi_class_type_info, used for
596 /// classes with bases that do not satisfy the abi::__si_class_type_info
597 /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
598 void buildVMIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
599
600 /// Build an abi::__pointer_type_info, used for pointer types, according
601 /// to the Itanium C++ ABI, 2.9.4p7.
602 void buildPointerTypeInfo(mlir::Location loc, QualType ty);
603
604 /// Build an abi::__pointer_to_member_type_info, used for pointer to member
605 /// types, according to the Itanium C++ ABI, 2.9.4p9.
606
607 /// Build an abi::__pointer_to_member_type_info
608 /// struct, used for member pointer types.
609 void buildPointerToMemberTypeInfo(mlir::Location loc,
610 const MemberPointerType *ty);
611
612public:
613 CIRGenItaniumRTTIBuilder(const CIRGenItaniumCXXABI &abi, CIRGenModule &cgm)
614 : cgm(cgm), cxxABI(abi) {}
615
616 /// Build the RTTI type info struct for the given type, or
617 /// link to an existing RTTI descriptor if one already exists.
618 mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty);
619
620 /// Build the RTTI type info struct for the given type.
621 mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty,
622 cir::GlobalLinkageKind linkage,
623 mlir::SymbolTable::Visibility visibility);
624};
625} // namespace
626
627// TODO(cir): Will be removed after sharing them with the classical codegen
628namespace {
629
630// Pointer type info flags.
631enum {
632 /// PTI_Const - Type has const qualifier.
633 PTI_Const = 0x1,
634
635 /// PTI_Volatile - Type has volatile qualifier.
636 PTI_Volatile = 0x2,
637
638 /// PTI_Restrict - Type has restrict qualifier.
639 PTI_Restrict = 0x4,
640
641 /// PTI_Incomplete - Type is incomplete.
642 PTI_Incomplete = 0x8,
643
644 /// PTI_ContainingClassIncomplete - Containing class is incomplete.
645 /// (in pointer to member).
646 PTI_ContainingClassIncomplete = 0x10,
647
648 /// PTI_TransactionSafe - Pointee is transaction_safe function (C++ TM TS).
649 // PTI_TransactionSafe = 0x20,
650
651 /// PTI_Noexcept - Pointee is noexcept function (C++1z).
652 PTI_Noexcept = 0x40,
653};
654
655// VMI type info flags.
656enum {
657 /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.
658 VMI_NonDiamondRepeat = 0x1,
659
660 /// VMI_DiamondShaped - Class is diamond shaped.
661 VMI_DiamondShaped = 0x2
662};
663
664// Base class type info flags.
665enum {
666 /// BCTI_Virtual - Base class is virtual.
667 BCTI_Virtual = 0x1,
668
669 /// BCTI_Public - Base class is public.
670 BCTI_Public = 0x2
671};
672
673/// Given a builtin type, returns whether the type
674/// info for that type is defined in the standard library.
675/// TODO(cir): this can unified with LLVM codegen
676static bool typeInfoIsInStandardLibrary(const BuiltinType *ty) {
677 // Itanium C++ ABI 2.9.2:
678 // Basic type information (e.g. for "int", "bool", etc.) will be kept in
679 // the run-time support library. Specifically, the run-time support
680 // library should contain type_info objects for the types X, X* and
681 // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char,
682 // unsigned char, signed char, short, unsigned short, int, unsigned int,
683 // long, unsigned long, long long, unsigned long long, float, double,
684 // long double, char16_t, char32_t, and the IEEE 754r decimal and
685 // half-precision floating point types.
686 //
687 // GCC also emits RTTI for __int128.
688 // FIXME: We do not emit RTTI information for decimal types here.
689
690 // Types added here must also be added to emitFundamentalRTTIDescriptors.
691 switch (ty->getKind()) {
692 case BuiltinType::WasmExternRef:
693 case BuiltinType::HLSLResource:
694 llvm_unreachable("NYI");
695 case BuiltinType::Void:
696 case BuiltinType::NullPtr:
697 case BuiltinType::Bool:
698 case BuiltinType::WChar_S:
699 case BuiltinType::WChar_U:
700 case BuiltinType::Char_U:
701 case BuiltinType::Char_S:
702 case BuiltinType::UChar:
703 case BuiltinType::SChar:
704 case BuiltinType::Short:
705 case BuiltinType::UShort:
706 case BuiltinType::Int:
707 case BuiltinType::UInt:
708 case BuiltinType::Long:
709 case BuiltinType::ULong:
710 case BuiltinType::LongLong:
711 case BuiltinType::ULongLong:
712 case BuiltinType::Half:
713 case BuiltinType::Float:
714 case BuiltinType::Double:
715 case BuiltinType::LongDouble:
716 case BuiltinType::Float16:
717 case BuiltinType::Float128:
718 case BuiltinType::Ibm128:
719 case BuiltinType::Char8:
720 case BuiltinType::Char16:
721 case BuiltinType::Char32:
722 case BuiltinType::Int128:
723 case BuiltinType::UInt128:
724 return true;
725
726#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
727 case BuiltinType::Id:
728#include "clang/Basic/OpenCLImageTypes.def"
729#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
730#include "clang/Basic/OpenCLExtensionTypes.def"
731 case BuiltinType::OCLSampler:
732 case BuiltinType::OCLEvent:
733 case BuiltinType::OCLClkEvent:
734 case BuiltinType::OCLQueue:
735 case BuiltinType::OCLReserveID:
736#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
737#include "clang/Basic/AArch64ACLETypes.def"
738#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
739#include "clang/Basic/PPCTypes.def"
740#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
741#include "clang/Basic/RISCVVTypes.def"
742#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
743#include "clang/Basic/AMDGPUTypes.def"
744 case BuiltinType::ShortAccum:
745 case BuiltinType::Accum:
746 case BuiltinType::LongAccum:
747 case BuiltinType::UShortAccum:
748 case BuiltinType::UAccum:
749 case BuiltinType::ULongAccum:
750 case BuiltinType::ShortFract:
751 case BuiltinType::Fract:
752 case BuiltinType::LongFract:
753 case BuiltinType::UShortFract:
754 case BuiltinType::UFract:
755 case BuiltinType::ULongFract:
756 case BuiltinType::SatShortAccum:
757 case BuiltinType::SatAccum:
758 case BuiltinType::SatLongAccum:
759 case BuiltinType::SatUShortAccum:
760 case BuiltinType::SatUAccum:
761 case BuiltinType::SatULongAccum:
762 case BuiltinType::SatShortFract:
763 case BuiltinType::SatFract:
764 case BuiltinType::SatLongFract:
765 case BuiltinType::SatUShortFract:
766 case BuiltinType::SatUFract:
767 case BuiltinType::SatULongFract:
768 case BuiltinType::BFloat16:
769 return false;
770
771 case BuiltinType::Dependent:
772#define BUILTIN_TYPE(Id, SingletonId)
773#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
774#include "clang/AST/BuiltinTypes.def"
775 llvm_unreachable("asking for RRTI for a placeholder type!");
776
777 case BuiltinType::ObjCId:
778 case BuiltinType::ObjCClass:
779 case BuiltinType::ObjCSel:
780 llvm_unreachable("FIXME: Objective-C types are unsupported!");
781 }
782
783 llvm_unreachable("Invalid BuiltinType Kind!");
784}
785
786static bool typeInfoIsInStandardLibrary(const PointerType *pointerTy) {
787 QualType pointeeTy = pointerTy->getPointeeType();
788 const auto *builtinTy = dyn_cast<BuiltinType>(pointeeTy);
789 if (!builtinTy)
790 return false;
791
792 // Check the qualifiers.
793 Qualifiers quals = pointeeTy.getQualifiers();
794 quals.removeConst();
795
796 if (!quals.empty())
797 return false;
798
799 return typeInfoIsInStandardLibrary(builtinTy);
800}
801
802/// IsStandardLibraryRTTIDescriptor - Returns whether the type
803/// information for the given type exists in the standard library.
804static bool isStandardLibraryRttiDescriptor(QualType ty) {
805 // Type info for builtin types is defined in the standard library.
806 if (const auto *builtinTy = dyn_cast<BuiltinType>(ty))
807 return typeInfoIsInStandardLibrary(builtinTy);
808
809 // Type info for some pointer types to builtin types is defined in the
810 // standard library.
811 if (const auto *pointerTy = dyn_cast<PointerType>(ty))
812 return typeInfoIsInStandardLibrary(pointerTy);
813
814 return false;
815}
816
817/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
818/// the given type exists somewhere else, and that we should not emit the type
819/// information in this translation unit. Assumes that it is not a
820/// standard-library type.
821static bool shouldUseExternalRttiDescriptor(CIRGenModule &cgm, QualType ty) {
822 ASTContext &context = cgm.getASTContext();
823
824 // If RTTI is disabled, assume it might be disabled in the
825 // translation unit that defines any potential key function, too.
826 if (!context.getLangOpts().RTTI)
827 return false;
828
829 if (const auto *recordTy = dyn_cast<RecordType>(ty)) {
830 const auto *rd =
831 cast<CXXRecordDecl>(recordTy->getDecl())->getDefinitionOrSelf();
832 if (!rd->hasDefinition())
833 return false;
834
835 if (!rd->isDynamicClass())
836 return false;
837
838 // FIXME: this may need to be reconsidered if the key function
839 // changes.
840 // N.B. We must always emit the RTTI data ourselves if there exists a key
841 // function.
842 bool isDLLImport = rd->hasAttr<DLLImportAttr>();
843
844 // Don't import the RTTI but emit it locally.
845 if (cgm.getTriple().isOSCygMing())
846 return false;
847
848 if (cgm.getVTables().isVTableExternal(rd)) {
850 return true;
851
852 return !isDLLImport || cgm.getTriple().isWindowsItaniumEnvironment();
853 }
854
855 if (isDLLImport)
856 return true;
857 }
858
859 return false;
860}
861
862/// Contains virtual and non-virtual bases seen when traversing a class
863/// hierarchy.
864struct SeenBases {
865 llvm::SmallPtrSet<const CXXRecordDecl *, 16> nonVirtualBases;
866 llvm::SmallPtrSet<const CXXRecordDecl *, 16> virtualBases;
867};
868
869/// Compute the value of the flags member in abi::__vmi_class_type_info.
870///
871static unsigned computeVmiClassTypeInfoFlags(const CXXBaseSpecifier *base,
872 SeenBases &bases) {
873
874 unsigned flags = 0;
875 auto *baseDecl = base->getType()->castAsCXXRecordDecl();
876
877 if (base->isVirtual()) {
878 // Mark the virtual base as seen.
879 if (!bases.virtualBases.insert(baseDecl).second) {
880 // If this virtual base has been seen before, then the class is diamond
881 // shaped.
882 flags |= VMI_DiamondShaped;
883 } else {
884 if (bases.nonVirtualBases.count(baseDecl))
885 flags |= VMI_NonDiamondRepeat;
886 }
887 } else {
888 // Mark the non-virtual base as seen.
889 if (!bases.nonVirtualBases.insert(baseDecl).second) {
890 // If this non-virtual base has been seen before, then the class has non-
891 // diamond shaped repeated inheritance.
892 flags |= VMI_NonDiamondRepeat;
893 } else {
894 if (bases.virtualBases.count(baseDecl))
895 flags |= VMI_NonDiamondRepeat;
896 }
897 }
898
899 // Walk all bases.
900 for (const auto &bs : baseDecl->bases())
901 flags |= computeVmiClassTypeInfoFlags(&bs, bases);
902
903 return flags;
904}
905
906static unsigned computeVmiClassTypeInfoFlags(const CXXRecordDecl *rd) {
907 unsigned flags = 0;
908 SeenBases bases;
909
910 // Walk all bases.
911 for (const auto &bs : rd->bases())
912 flags |= computeVmiClassTypeInfoFlags(&bs, bases);
913
914 return flags;
915}
916
917// Return whether the given record decl has a "single,
918// public, non-virtual base at offset zero (i.e. the derived class is dynamic
919// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
920// TODO(cir): this can unified with LLVM codegen
921static bool canUseSingleInheritance(const CXXRecordDecl *rd) {
922 // Check the number of bases.
923 if (rd->getNumBases() != 1)
924 return false;
925
926 // Get the base.
928
929 // Check that the base is not virtual.
930 if (base->isVirtual())
931 return false;
932
933 // Check that the base is public.
934 if (base->getAccessSpecifier() != AS_public)
935 return false;
936
937 // Check that the class is dynamic iff the base is.
938 auto *baseDecl = base->getType()->castAsCXXRecordDecl();
939 return baseDecl->isEmpty() ||
940 baseDecl->isDynamicClass() == rd->isDynamicClass();
941}
942
943/// IsIncompleteClassType - Returns whether the given record type is incomplete.
944static bool isIncompleteClassType(const RecordType *recordTy) {
945 return !recordTy->getDecl()->getDefinitionOrSelf()->isCompleteDefinition();
946}
947
948/// Returns whether the given type contains an
949/// incomplete class type. This is true if
950///
951/// * The given type is an incomplete class type.
952/// * The given type is a pointer type whose pointee type contains an
953/// incomplete class type.
954/// * The given type is a member pointer type whose class is an incomplete
955/// class type.
956/// * The given type is a member pointer type whoise pointee type contains an
957/// incomplete class type.
958/// is an indirect or direct pointer to an incomplete class type.
959static bool containsIncompleteClassType(QualType ty) {
960 if (const auto *recordTy = dyn_cast<RecordType>(ty)) {
961 if (isIncompleteClassType(recordTy))
962 return true;
963 }
964
965 if (const auto *pointerTy = dyn_cast<PointerType>(ty))
966 return containsIncompleteClassType(pointerTy->getPointeeType());
967
968 if (const auto *memberPointerTy = dyn_cast<MemberPointerType>(ty)) {
969 // Check if the class type is incomplete.
970 if (!memberPointerTy->getMostRecentCXXRecordDecl()->hasDefinition())
971 return true;
972
973 return containsIncompleteClassType(memberPointerTy->getPointeeType());
974 }
975
976 return false;
977}
978
979static unsigned extractPBaseFlags(const ASTContext &ctx, QualType &ty) {
980 unsigned flags = 0;
981
982 if (ty.isConstQualified())
983 flags |= PTI_Const;
984 if (ty.isVolatileQualified())
985 flags |= PTI_Volatile;
986 if (ty.isRestrictQualified())
987 flags |= PTI_Restrict;
988
989 ty = ty.getUnqualifiedType();
990
991 if (containsIncompleteClassType(ty))
992 flags |= PTI_Incomplete;
993
994 if (const auto *proto = ty->getAs<FunctionProtoType>()) {
995 if (proto->isNothrow()) {
996 flags |= PTI_Noexcept;
998 }
999 }
1000
1001 return flags;
1002}
1003
1004const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
1005 // abi::__class_type_info.
1006 static const char *const classTypeInfo =
1007 "_ZTVN10__cxxabiv117__class_type_infoE";
1008 // abi::__si_class_type_info.
1009 static const char *const siClassTypeInfo =
1010 "_ZTVN10__cxxabiv120__si_class_type_infoE";
1011 // abi::__vmi_class_type_info.
1012 static const char *const vmiClassTypeInfo =
1013 "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
1014
1015 switch (ty->getTypeClass()) {
1016#define TYPE(Class, Base)
1017#define ABSTRACT_TYPE(Class, Base)
1018#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
1019#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
1020#define DEPENDENT_TYPE(Class, Base) case Type::Class:
1021#include "clang/AST/TypeNodes.inc"
1022 llvm_unreachable("Non-canonical and dependent types shouldn't get here");
1023
1024 case Type::LValueReference:
1025 case Type::RValueReference:
1026 llvm_unreachable("References shouldn't get here");
1027
1028 case Type::Auto:
1029 case Type::DeducedTemplateSpecialization:
1030 llvm_unreachable("Undeduced type shouldn't get here");
1031
1032 case Type::Pipe:
1033 llvm_unreachable("Pipe types shouldn't get here");
1034
1035 case Type::ArrayParameter:
1036 llvm_unreachable("Array Parameter types should not get here.");
1037
1038 case Type::Builtin:
1039 case Type::BitInt:
1040 case Type::OverflowBehavior:
1041 // GCC treats vector and complex types as fundamental types.
1042 case Type::Vector:
1043 case Type::ExtVector:
1044 case Type::ConstantMatrix:
1045 case Type::Complex:
1046 case Type::Atomic:
1047 // FIXME: GCC treats block pointers as fundamental types?!
1048 case Type::BlockPointer:
1049 return "_ZTVN10__cxxabiv123__fundamental_type_infoE";
1050 case Type::ConstantArray:
1051 case Type::IncompleteArray:
1052 case Type::VariableArray:
1053 // abi::__array_type_info.
1054 return "_ZTVN10__cxxabiv117__array_type_infoE";
1055
1056 case Type::FunctionNoProto:
1057 case Type::FunctionProto:
1058 // abi::__function_type_info.
1059 return "_ZTVN10__cxxabiv120__function_type_infoE";
1060
1061 case Type::Enum:
1062 return "_ZTVN10__cxxabiv116__enum_type_infoE";
1063
1064 case Type::Record: {
1065 const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl())
1066 ->getDefinitionOrSelf();
1067
1068 if (!rd->hasDefinition() || !rd->getNumBases()) {
1069 return classTypeInfo;
1070 }
1071
1072 if (canUseSingleInheritance(rd)) {
1073 return siClassTypeInfo;
1074 }
1075
1076 return vmiClassTypeInfo;
1077 }
1078
1079 case Type::ObjCObject:
1080 cgm.errorNYI("VTableClassNameForType: ObjCObject");
1081 break;
1082
1083 case Type::ObjCInterface:
1084 cgm.errorNYI("VTableClassNameForType: ObjCInterface");
1085 break;
1086
1087 case Type::ObjCObjectPointer:
1088 case Type::Pointer:
1089 // abi::__pointer_type_info.
1090 return "_ZTVN10__cxxabiv119__pointer_type_infoE";
1091
1092 case Type::MemberPointer:
1093 // abi::__pointer_to_member_type_info.
1094 return "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
1095
1096 case Type::HLSLAttributedResource:
1097 case Type::HLSLInlineSpirv:
1098 llvm_unreachable("HLSL doesn't support virtual functions");
1099 }
1100
1101 return nullptr;
1102}
1103} // namespace
1104
1105/// Return the linkage that the type info and type info name constants
1106/// should have for the given type.
1107static cir::GlobalLinkageKind getTypeInfoLinkage(CIRGenModule &cgm,
1108 QualType ty) {
1109 // In addition, it and all of the intermediate abi::__pointer_type_info
1110 // structs in the chain down to the abi::__class_type_info for the
1111 // incomplete class type must be prevented from resolving to the
1112 // corresponding type_info structs for the complete class type, possibly
1113 // by making them local static objects. Finally, a dummy class RTTI is
1114 // generated for the incomplete type that will not resolve to the final
1115 // complete class RTTI (because the latter need not exist), possibly by
1116 // making it a local static object.
1117 if (containsIncompleteClassType(ty))
1118 return cir::GlobalLinkageKind::InternalLinkage;
1119
1120 switch (ty->getLinkage()) {
1121 case Linkage::Invalid:
1122 llvm_unreachable("Linkage hasn't been computed!");
1123
1124 case Linkage::None:
1125 case Linkage::Internal:
1127 return cir::GlobalLinkageKind::InternalLinkage;
1128
1130 case Linkage::Module:
1131 case Linkage::External:
1132 // RTTI is not enabled, which means that this type info struct is going
1133 // to be used for exception handling. Give it linkonce_odr linkage.
1134 if (!cgm.getLangOpts().RTTI)
1135 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
1136
1137 if (const RecordType *record = dyn_cast<RecordType>(ty)) {
1138 const auto *rd =
1139 cast<CXXRecordDecl>(record->getDecl())->getDefinitionOrSelf();
1140 if (rd->hasAttr<WeakAttr>())
1141 return cir::GlobalLinkageKind::WeakODRLinkage;
1142
1143 if (cgm.getTriple().isWindowsItaniumEnvironment())
1144 if (rd->hasAttr<DLLImportAttr>() &&
1145 shouldUseExternalRttiDescriptor(cgm, ty))
1146 return cir::GlobalLinkageKind::ExternalLinkage;
1147
1148 // MinGW always uses LinkOnceODRLinkage for type info.
1149 if (rd->isDynamicClass() && !cgm.getASTContext()
1150 .getTargetInfo()
1151 .getTriple()
1152 .isWindowsGNUEnvironment())
1153 return cgm.getVTableLinkage(rd);
1154 }
1155
1156 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
1157 }
1158
1159 llvm_unreachable("Invalid linkage!");
1160}
1161
1162cir::GlobalOp
1163CIRGenItaniumRTTIBuilder::getAddrOfTypeName(mlir::Location loc, QualType ty,
1164 cir::GlobalLinkageKind linkage) {
1165 CIRGenBuilderTy &builder = cgm.getBuilder();
1166 SmallString<256> name;
1167 llvm::raw_svector_ostream out(name);
1169
1170 // We know that the mangled name of the type starts at index 4 of the
1171 // mangled name of the typename, so we can just index into it in order to
1172 // get the mangled name of the type.
1173 mlir::Attribute init = builder.getString(
1174 name.substr(4), cgm.convertType(cgm.getASTContext().CharTy),
1175 std::nullopt);
1176
1177 CharUnits align =
1179
1180 // builder.getString can return a #cir.zero if the string given to it only
1181 // contains null bytes. However, type names cannot be full of null bytes.
1182 // So cast Init to a ConstArrayAttr should be safe.
1183 auto initStr = cast<cir::ConstArrayAttr>(init);
1184
1185 cir::GlobalOp gv = cgm.createOrReplaceCXXRuntimeVariable(
1186 loc, name, initStr.getType(), linkage, align);
1188 return gv;
1189}
1190
1191mlir::Attribute
1192CIRGenItaniumRTTIBuilder::getAddrOfExternalRTTIDescriptor(mlir::Location loc,
1193 QualType ty) {
1194 // Mangle the RTTI name.
1195 SmallString<256> name;
1196 llvm::raw_svector_ostream out(name);
1198 CIRGenBuilderTy &builder = cgm.getBuilder();
1199
1200 // Look for an existing global.
1201 cir::GlobalOp gv = dyn_cast_or_null<cir::GlobalOp>(
1202 mlir::SymbolTable::lookupSymbolIn(cgm.getModule(), name));
1203
1204 if (!gv) {
1205 // Create a new global variable.
1206 // From LLVM codegen => Note for the future: If we would ever like to do
1207 // deferred emission of RTTI, check if emitting vtables opportunistically
1208 // need any adjustment.
1209 gv = CIRGenModule::createGlobalOp(cgm, loc, name, builder.getUInt8PtrTy(),
1210 /*isConstant=*/true);
1211 const CXXRecordDecl *rd = ty->getAsCXXRecordDecl();
1212 cgm.setGVProperties(gv, rd);
1213
1214 // Import the typeinfo symbol when all non-inline virtual methods are
1215 // imported.
1216 if (cgm.getTarget().hasPS4DLLImportExport()) {
1217 cgm.errorNYI("getAddrOfExternalRTTIDescriptor: hasPS4DLLImportExport");
1218 }
1219 }
1220
1221 return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv);
1222}
1223
1224void CIRGenItaniumRTTIBuilder::buildVTablePointer(mlir::Location loc,
1225 const Type *ty) {
1226 CIRGenBuilderTy &builder = cgm.getBuilder();
1227 const char *vTableName = vTableClassNameForType(cgm, ty);
1228
1229 // Check if the alias exists. If it doesn't, then get or create the global.
1230 if (cgm.getLangOpts().RelativeCXXABIVTables) {
1231 cgm.errorNYI("buildVTablePointer: isRelativeLayout");
1232 return;
1233 }
1234
1235 mlir::Type vtableGlobalTy = builder.getPointerTo(builder.getUInt8PtrTy());
1236 llvm::Align align = cgm.getDataLayout().getABITypeAlign(vtableGlobalTy);
1237 cir::GlobalOp vTable = cgm.createOrReplaceCXXRuntimeVariable(
1238 loc, vTableName, vtableGlobalTy, cir::GlobalLinkageKind::ExternalLinkage,
1240
1241 // The vtable address point is 2.
1242 mlir::Attribute field{};
1243 if (cgm.getLangOpts().RelativeCXXABIVTables) {
1244 cgm.errorNYI("buildVTablePointer: isRelativeLayout");
1245 } else {
1246 SmallVector<mlir::Attribute, 4> offsets{
1247 cgm.getBuilder().getI32IntegerAttr(2)};
1248 auto indices = mlir::ArrayAttr::get(builder.getContext(), offsets);
1250 vTable, indices);
1251 }
1252
1253 assert(field && "expected attribute");
1254 fields.push_back(field);
1255}
1256
1257/// Build an abi::__si_class_type_info, used for single inheritance, according
1258/// to the Itanium C++ ABI, 2.95p6b.
1259void CIRGenItaniumRTTIBuilder::buildSIClassTypeInfo(mlir::Location loc,
1260 const CXXRecordDecl *rd) {
1261 // Itanium C++ ABI 2.9.5p6b:
1262 // It adds to abi::__class_type_info a single member pointing to the
1263 // type_info structure for the base type,
1264 mlir::Attribute baseTypeInfo =
1265 CIRGenItaniumRTTIBuilder(cxxABI, cgm)
1266 .buildTypeInfo(loc, rd->bases_begin()->getType());
1267 fields.push_back(baseTypeInfo);
1268}
1269
1270/// Build an abi::__vmi_class_type_info, used for
1271/// classes with bases that do not satisfy the abi::__si_class_type_info
1272/// constraints, according to the Itanium C++ ABI, 2.9.5p5c.
1273void CIRGenItaniumRTTIBuilder::buildVMIClassTypeInfo(mlir::Location loc,
1274 const CXXRecordDecl *rd) {
1275 mlir::Type unsignedIntLTy =
1277
1278 // Itanium C++ ABI 2.9.5p6c:
1279 // __flags is a word with flags describing details about the class
1280 // structure, which may be referenced by using the __flags_masks
1281 // enumeration. These flags refer to both direct and indirect bases.
1282 unsigned flags = computeVmiClassTypeInfoFlags(rd);
1283 fields.push_back(cir::IntAttr::get(unsignedIntLTy, flags));
1284
1285 // Itanium C++ ABI 2.9.5p6c:
1286 // __base_count is a word with the number of direct proper base class
1287 // descriptions that follow.
1288 fields.push_back(cir::IntAttr::get(unsignedIntLTy, rd->getNumBases()));
1289
1290 if (!rd->getNumBases())
1291 return;
1292
1293 // Now add the base class descriptions.
1294
1295 // Itanium C++ ABI 2.9.5p6c:
1296 // __base_info[] is an array of base class descriptions -- one for every
1297 // direct proper base. Each description is of the type:
1298 //
1299 // struct abi::__base_class_type_info {
1300 // public:
1301 // const __class_type_info *__base_type;
1302 // long __offset_flags;
1303 //
1304 // enum __offset_flags_masks {
1305 // __virtual_mask = 0x1,
1306 // __public_mask = 0x2,
1307 // __offset_shift = 8
1308 // };
1309 // };
1310
1311 // If we're in mingw and 'long' isn't wide enough for a pointer, use 'long
1312 // long' instead of 'long' for __offset_flags. libstdc++abi uses long long on
1313 // LLP64 platforms.
1314 // FIXME: Consider updating libc++abi to match, and extend this logic to all
1315 // LLP64 platforms.
1316 QualType offsetFlagsTy = cgm.getASTContext().LongTy;
1317 const TargetInfo &ti = cgm.getASTContext().getTargetInfo();
1318 if (ti.getTriple().isOSCygMing() &&
1319 ti.getPointerWidth(LangAS::Default) > ti.getLongWidth())
1320 offsetFlagsTy = cgm.getASTContext().LongLongTy;
1321 mlir::Type offsetFlagsLTy = cgm.convertType(offsetFlagsTy);
1322
1323 for (const CXXBaseSpecifier &base : rd->bases()) {
1324 // The __base_type member points to the RTTI for the base type.
1325 fields.push_back(CIRGenItaniumRTTIBuilder(cxxABI, cgm)
1326 .buildTypeInfo(loc, base.getType()));
1327
1328 CXXRecordDecl *baseDecl = base.getType()->castAsCXXRecordDecl();
1329 int64_t offsetFlags = 0;
1330
1331 // All but the lower 8 bits of __offset_flags are a signed offset.
1332 // For a non-virtual base, this is the offset in the object of the base
1333 // subobject. For a virtual base, this is the offset in the virtual table of
1334 // the virtual base offset for the virtual base referenced (negative).
1335 CharUnits offset;
1336 if (base.isVirtual())
1338 rd, baseDecl);
1339 else {
1340 const ASTRecordLayout &layout =
1342 offset = layout.getBaseClassOffset(baseDecl);
1343 }
1344 offsetFlags = uint64_t(offset.getQuantity()) << 8;
1345
1346 // The low-order byte of __offset_flags contains flags, as given by the
1347 // masks from the enumeration __offset_flags_masks.
1348 if (base.isVirtual())
1349 offsetFlags |= BCTI_Virtual;
1350 if (base.getAccessSpecifier() == AS_public)
1351 offsetFlags |= BCTI_Public;
1352
1353 fields.push_back(cir::IntAttr::get(offsetFlagsLTy, offsetFlags));
1354 }
1355}
1356
1357void CIRGenItaniumRTTIBuilder::buildPointerTypeInfo(mlir::Location loc,
1358 QualType ty) {
1359 // Itanium C++ ABI 2.9.4p7:
1360 // abi::__pbase_type_info is a base for both pointer types and
1361 // pointer-to-member types. It adds two data members:
1362 //
1363 // class __pbase_type_info : public std::type_info {
1364 // public:
1365 // unsigned int __flags;
1366 // const std::type_info *__pointee;
1367 //
1368 // enum __masks {
1369 // __const_mask = 0x1,
1370 // __volatile_mask = 0x2,
1371 // __restrict_mask = 0x4,
1372 // __incomplete_mask = 0x8,
1373 // __incomplete_class_mask = 0x10,
1374 // __transaction_safe_mask = 0x20
1375 // __noexcept_mask = 0x40
1376 // };
1377 // };
1378 const unsigned int flags = extractPBaseFlags(cgm.getASTContext(), ty);
1379
1380 mlir::Type unsignedIntTy = cgm.convertType(cgm.getASTContext().UnsignedIntTy);
1381 mlir::Attribute flagsAttr = cir::IntAttr::get(unsignedIntTy, flags);
1382 fields.push_back(flagsAttr);
1383
1384 mlir::Attribute pointeeTypeInfo =
1385 CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, ty);
1386 fields.push_back(pointeeTypeInfo);
1387}
1388
1389void CIRGenItaniumRTTIBuilder::buildPointerToMemberTypeInfo(
1390 mlir::Location loc, const MemberPointerType *ty) {
1391
1392 // The abi::__pointer_to_member_type_info type adds one field to
1393 // abi::__pbase_type_info:
1394 //
1395 // class __pointer_to_member_type_info : public __pbase_type_info {
1396 // public:
1397 // const abi::__class_type_info *__context;
1398 // };
1399 QualType pointeeTy = ty->getPointeeType();
1400
1401 unsigned flags = extractPBaseFlags(cgm.getASTContext(), pointeeTy);
1402
1403 const auto *rd = ty->getMostRecentCXXRecordDecl();
1404 if (!rd->hasDefinition())
1405 flags |= PTI_ContainingClassIncomplete;
1406
1407 mlir::Type unsignedIntTy = cgm.convertType(cgm.getASTContext().UnsignedIntTy);
1408 mlir::Attribute flagsAttr = cir::IntAttr::get(unsignedIntTy, flags);
1409 fields.push_back(flagsAttr);
1410
1411 mlir::Attribute pointeeTypeInfo =
1412 CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, pointeeTy);
1413 fields.push_back(pointeeTypeInfo);
1414
1415 CanQualType contextTy = cgm.getASTContext().getCanonicalTagType(rd);
1416 mlir::Attribute classTypeInfo =
1417 CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, contextTy);
1418 fields.push_back(classTypeInfo);
1419}
1420
1421mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(mlir::Location loc,
1422 QualType ty) {
1423 // We want to operate on the canonical type.
1424 ty = ty.getCanonicalType();
1425
1426 // Check if we've already emitted an RTTI descriptor for this type.
1427 SmallString<256> name;
1428 llvm::raw_svector_ostream out(name);
1430
1431 auto oldGV = dyn_cast_or_null<cir::GlobalOp>(
1432 mlir::SymbolTable::lookupSymbolIn(cgm.getModule(), name));
1433
1434 if (oldGV && !oldGV.isDeclaration()) {
1435 assert(!oldGV.hasAvailableExternallyLinkage() &&
1436 "available_externally typeinfos not yet implemented");
1438 oldGV);
1439 }
1440
1441 // Check if there is already an external RTTI descriptor for this type.
1442 if (isStandardLibraryRttiDescriptor(ty) ||
1443 shouldUseExternalRttiDescriptor(cgm, ty))
1444 return getAddrOfExternalRTTIDescriptor(loc, ty);
1445
1446 // Emit the standard library with external linkage.
1447 cir::GlobalLinkageKind linkage = getTypeInfoLinkage(cgm, ty);
1448
1449 // Give the type_info object and name the formal visibility of the
1450 // type itself.
1453
1454 mlir::SymbolTable::Visibility symVisibility;
1455 if (cir::isLocalLinkage(linkage))
1456 // If the linkage is local, only default visibility makes sense.
1457 symVisibility = mlir::SymbolTable::Visibility::Public;
1458 else if (cxxABI.classifyRTTIUniqueness(ty, linkage) ==
1459 CIRGenItaniumCXXABI::RUK_NonUniqueHidden) {
1460 cgm.errorNYI(
1461 "buildTypeInfo: classifyRTTIUniqueness == RUK_NonUniqueHidden");
1462 symVisibility = CIRGenModule::getMLIRVisibility(ty->getVisibility());
1463 } else
1464 symVisibility = CIRGenModule::getMLIRVisibility(ty->getVisibility());
1465
1466 return buildTypeInfo(loc, ty, linkage, symVisibility);
1467}
1468
1469mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(
1470 mlir::Location loc, QualType ty, cir::GlobalLinkageKind linkage,
1471 mlir::SymbolTable::Visibility visibility) {
1472 CIRGenBuilderTy &builder = cgm.getBuilder();
1473
1475
1476 // Add the vtable pointer.
1477 buildVTablePointer(loc, cast<Type>(ty));
1478
1479 // And the name.
1480 cir::GlobalOp typeName = getAddrOfTypeName(loc, ty, linkage);
1481 mlir::Attribute typeNameField;
1482
1483 // If we're supposed to demote the visibility, be sure to set a flag
1484 // to use a string comparison for type_info comparisons.
1485 CIRGenItaniumCXXABI::RTTIUniquenessKind rttiUniqueness =
1486 cxxABI.classifyRTTIUniqueness(ty, linkage);
1487 if (rttiUniqueness != CIRGenItaniumCXXABI::RUK_Unique) {
1488 // The flag is the sign bit, which on ARM64 is defined to be clear
1489 // for global pointers. This is very ARM64-specific.
1490 cgm.errorNYI(
1491 "buildTypeInfo: rttiUniqueness != CIRGenItaniumCXXABI::RUK_Unique");
1492 } else {
1493 typeNameField =
1494 builder.getGlobalViewAttr(builder.getUInt8PtrTy(), typeName);
1495 }
1496
1497 fields.push_back(typeNameField);
1498
1499 switch (ty->getTypeClass()) {
1500#define TYPE(Class, Base)
1501#define ABSTRACT_TYPE(Class, Base)
1502#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
1503#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
1504#define DEPENDENT_TYPE(Class, Base) case Type::Class:
1505#include "clang/AST/TypeNodes.inc"
1506 llvm_unreachable("Non-canonical and dependent types shouldn't get here");
1507
1508 // GCC treats vector types as fundamental types.
1509 case Type::Builtin:
1510 case Type::Vector:
1511 case Type::ExtVector:
1512 case Type::ConstantMatrix:
1513 case Type::Complex:
1514 case Type::BlockPointer:
1515 // Itanium C++ ABI 2.9.5p4:
1516 // abi::__fundamental_type_info adds no data members to std::type_info.
1517 break;
1518
1519 case Type::LValueReference:
1520 case Type::RValueReference:
1521 llvm_unreachable("References shouldn't get here");
1522
1523 case Type::Auto:
1524 case Type::DeducedTemplateSpecialization:
1525 llvm_unreachable("Undeduced type shouldn't get here");
1526
1527 case Type::Pipe:
1528 break;
1529
1530 case Type::BitInt:
1531 break;
1532
1533 case Type::OverflowBehavior:
1534 break;
1535
1536 case Type::ConstantArray:
1537 case Type::IncompleteArray:
1538 case Type::VariableArray:
1539 case Type::ArrayParameter:
1540 // Itanium C++ ABI 2.9.5p5:
1541 // abi::__array_type_info adds no data members to std::type_info.
1542 break;
1543
1544 case Type::FunctionNoProto:
1545 case Type::FunctionProto:
1546 // Itanium C++ ABI 2.9.5p5:
1547 // abi::__function_type_info adds no data members to std::type_info.
1548 break;
1549
1550 case Type::Enum:
1551 // Itanium C++ ABI 2.9.5p5:
1552 // abi::__enum_type_info adds no data members to std::type_info.
1553 break;
1554
1555 case Type::Record: {
1556 const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl())
1557 ->getDefinitionOrSelf();
1558 if (!rd->hasDefinition() || !rd->getNumBases()) {
1559 // We don't need to emit any fields.
1560 break;
1561 }
1562
1563 if (canUseSingleInheritance(rd)) {
1564 buildSIClassTypeInfo(loc, rd);
1565 } else {
1566 buildVMIClassTypeInfo(loc, rd);
1567 }
1568
1569 break;
1570 }
1571
1572 case Type::ObjCObject:
1573 case Type::ObjCInterface:
1574 cgm.errorNYI("buildTypeInfo: ObjCObject & ObjCInterface");
1575 break;
1576
1577 case Type::ObjCObjectPointer:
1578 cgm.errorNYI("buildTypeInfo: ObjCObjectPointer");
1579 break;
1580
1581 case Type::Pointer:
1582 // We need to get the type info for the pointee type.
1583 buildPointerTypeInfo(loc, cast<PointerType>(ty)->getPointeeType());
1584 break;
1585
1586 case Type::MemberPointer:
1587 buildPointerToMemberTypeInfo(loc, cast<MemberPointerType>(ty));
1588 break;
1589
1590 case Type::Atomic:
1591 // No fields, at least for the moment.
1592 break;
1593
1594 case Type::HLSLAttributedResource:
1595 case Type::HLSLInlineSpirv:
1596 llvm_unreachable("HLSL doesn't support RTTI");
1597 }
1598
1600 cir::TypeInfoAttr init = builder.getTypeInfo(builder.getArrayAttr(fields));
1601
1602 SmallString<256> name;
1603 llvm::raw_svector_ostream out(name);
1605
1606 // Create new global and search for an existing global.
1607 auto oldGV = dyn_cast_or_null<cir::GlobalOp>(
1608 mlir::SymbolTable::lookupSymbolIn(cgm.getModule(), name));
1609
1610 cir::GlobalOp gv =
1611 CIRGenModule::createGlobalOp(cgm, loc, name, init.getType(),
1612 /*isConstant=*/true);
1613 gv.setLinkage(linkage);
1614
1615 // Export the typeinfo in the same circumstances as the vtable is
1616 // exported.
1617 if (cgm.getTarget().hasPS4DLLImportExport()) {
1618 cgm.errorNYI("buildTypeInfo: target hasPS4DLLImportExport");
1619 return {};
1620 }
1621
1622 // If there's already an old global variable, replace it with the new one.
1623 if (oldGV) {
1624 // Replace occurrences of the old variable if needed.
1625 gv.setName(oldGV.getName());
1626 if (!oldGV->use_empty()) {
1627 cgm.errorNYI("buildTypeInfo: old GV !use_empty");
1628 return {};
1629 }
1630 oldGV->erase();
1631 }
1632
1633 if (cgm.supportsCOMDAT() && cir::isWeakForLinker(linkage))
1634 gv.setComdat(true);
1635
1636 CharUnits align = cgm.getASTContext().toCharUnitsFromBits(
1637 cgm.getTarget().getPointerAlign(LangAS::Default));
1638 gv.setAlignmentAttr(cgm.getSize(align));
1639
1640 // The Itanium ABI specifies that type_info objects must be globally
1641 // unique, with one exception: if the type is an incomplete class
1642 // type or a (possibly indirect) pointer to one. That exception
1643 // affects the general case of comparing type_info objects produced
1644 // by the typeid operator, which is why the comparison operators on
1645 // std::type_info generally use the type_info name pointers instead
1646 // of the object addresses. However, the language's built-in uses
1647 // of RTTI generally require class types to be complete, even when
1648 // manipulating pointers to those class types. This allows the
1649 // implementation of dynamic_cast to rely on address equality tests,
1650 // which is much faster.
1651
1652 // All of this is to say that it's important that both the type_info
1653 // object and the type_info name be uniqued when weakly emitted.
1654
1655 mlir::SymbolTable::setSymbolVisibility(typeName, visibility);
1659
1660 mlir::SymbolTable::setSymbolVisibility(gv, visibility);
1664
1666 return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv);
1667}
1668
1669bool CIRGenItaniumCXXABI::shouldTypeidBeNullChecked(QualType srcTy) {
1670 return true;
1671}
1672
1673void CIRGenItaniumCXXABI::emitBadTypeidCall(CIRGenFunction &cgf,
1674 mlir::Location loc) {
1675 // void __cxa_bad_typeid();
1676 cir::FuncType fnTy =
1677 cgf.getBuilder().getFuncType({}, cgf.getBuilder().getVoidTy());
1678 mlir::NamedAttrList attrs;
1679 attrs.set(cir::CIRDialect::getNoReturnAttrName(),
1680 mlir::UnitAttr::get(&cgf.cgm.getMLIRContext()));
1681
1682 cgf.emitRuntimeCall(
1683 loc, cgf.cgm.createRuntimeFunction(fnTy, "__cxa_bad_typeid", attrs), {},
1684 attrs);
1685 cir::UnreachableOp::create(cgf.getBuilder(), loc);
1686}
1687
1688mlir::Value CIRGenItaniumCXXABI::emitTypeid(CIRGenFunction &cgf, QualType srcTy,
1689 Address thisPtr,
1690 mlir::Type typeInfoPtrTy) {
1691 auto *classDecl = srcTy->castAsCXXRecordDecl();
1692 mlir::Location loc = cgm.getLoc(classDecl->getSourceRange());
1693 mlir::Value vptr = cgf.getVTablePtr(loc, thisPtr, classDecl);
1694 mlir::Value vtbl;
1695
1696 // TODO(cir): In classic codegen relative layouts cause us to do a
1697 // 'load_relative' of -4 here. We probably don't want to reprensent this in
1698 // CIR at all, but we should have the NYI here since this could be
1699 // meaningful/notable for implementation of relative layout in the future.
1700 if (cgm.getLangOpts().RelativeCXXABIVTables)
1701 cgm.errorNYI("buildVTablePointer: isRelativeLayout");
1702 else
1703 vtbl = cir::VTableGetTypeInfoOp::create(
1704 cgf.getBuilder(), loc, cgf.getBuilder().getPointerTo(typeInfoPtrTy),
1705 vptr);
1706
1707 return cgf.getBuilder().createAlignedLoad(loc, typeInfoPtrTy, vtbl,
1708 cgf.getPointerAlign());
1709}
1710
1711mlir::Attribute CIRGenItaniumCXXABI::getAddrOfRTTIDescriptor(mlir::Location loc,
1712 QualType ty) {
1713 return CIRGenItaniumRTTIBuilder(*this, cgm).buildTypeInfo(loc, ty);
1714}
1715
1716/// What sort of uniqueness rules should we use for the RTTI for the
1717/// given type?
1718CIRGenItaniumCXXABI::RTTIUniquenessKind
1719CIRGenItaniumCXXABI::classifyRTTIUniqueness(
1720 QualType canTy, cir::GlobalLinkageKind linkage) const {
1721 if (shouldRTTIBeUnique())
1722 return RUK_Unique;
1723
1724 // It's only necessary for linkonce_odr or weak_odr linkage.
1725 if (linkage != cir::GlobalLinkageKind::LinkOnceODRLinkage &&
1726 linkage != cir::GlobalLinkageKind::WeakODRLinkage)
1727 return RUK_Unique;
1728
1729 // It's only necessary with default visibility.
1730 if (canTy->getVisibility() != DefaultVisibility)
1731 return RUK_Unique;
1732
1733 // If we're not required to publish this symbol, hide it.
1734 if (linkage == cir::GlobalLinkageKind::LinkOnceODRLinkage)
1735 return RUK_NonUniqueHidden;
1736
1737 // If we're required to publish this symbol, as we might be under an
1738 // explicit instantiation, leave it with default visibility but
1739 // enable string-comparisons.
1740 assert(linkage == cir::GlobalLinkageKind::WeakODRLinkage);
1741 return RUK_NonUniqueVisible;
1742}
1743
1744void CIRGenItaniumCXXABI::emitDestructorCall(
1745 CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
1746 bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy) {
1747 GlobalDecl gd(dd, type);
1748 mlir::Value vtt =
1749 getCXXDestructorImplicitParam(cgf, dd, type, forVirtualBase, delegating);
1750 ASTContext &astContext = cgm.getASTContext();
1751 QualType vttTy = astContext.getPointerType(astContext.VoidPtrTy);
1753 CIRGenCallee callee =
1755
1756 cgf.emitCXXDestructorCall(gd, callee, thisAddr.getPointer(), thisTy, vtt,
1757 vttTy, nullptr);
1758}
1759
1760void CIRGenItaniumCXXABI::registerGlobalDtor(const VarDecl *vd,
1761 cir::FuncOp dtor,
1762 mlir::Value addr) {
1763 if (vd->isNoDestroy(cgm.getASTContext()))
1764 return;
1765
1766 if (vd->getTLSKind()) {
1767 cgm.errorNYI(vd->getSourceRange(), "registerGlobalDtor: TLS");
1768 return;
1769 }
1770
1771 // HLSL doesn't support atexit.
1772 if (cgm.getLangOpts().HLSL) {
1773 cgm.errorNYI(vd->getSourceRange(), "registerGlobalDtor: HLSL");
1774 return;
1775 }
1776
1777 // The default behavior is to use atexit. This is handled in lowering
1778 // prepare. Nothing to be done for CIR here.
1779}
1780
1781mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam(
1782 CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
1783 bool forVirtualBase, bool delegating) {
1784 GlobalDecl gd(dd, type);
1785 return cgf.getVTTParameter(gd, forVirtualBase, delegating);
1786}
1787
1788// The idea here is creating a separate block for the throw with an
1789// `UnreachableOp` as the terminator. So, we branch from the current block
1790// to the throw block and create a block for the remaining operations.
1791static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc,
1792 mlir::Value exceptionPtr = {},
1793 mlir::FlatSymbolRefAttr typeInfo = {},
1794 mlir::FlatSymbolRefAttr dtor = {}) {
1795 mlir::Block *currentBlock = builder.getInsertionBlock();
1796 mlir::Region *region = currentBlock->getParent();
1797
1798 if (currentBlock->empty()) {
1799 cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
1800 cir::UnreachableOp::create(builder, loc);
1801 } else {
1802 mlir::Block *throwBlock = builder.createBlock(region);
1803
1804 cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
1805 cir::UnreachableOp::create(builder, loc);
1806
1807 builder.setInsertionPointToEnd(currentBlock);
1808 cir::BrOp::create(builder, loc, throwBlock);
1809 }
1810
1811 (void)builder.createBlock(region);
1812}
1813
1814void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) {
1815 // void __cxa_rethrow();
1816 if (isNoReturn) {
1817 CIRGenBuilderTy &builder = cgf.getBuilder();
1818 assert(cgf.currSrcLoc && "expected source location");
1819 mlir::Location loc = *cgf.currSrcLoc;
1820 insertThrowAndSplit(builder, loc);
1821 } else {
1822 cgm.errorNYI("emitRethrow with isNoReturn false");
1823 }
1824}
1825
1826void CIRGenItaniumCXXABI::emitThrow(CIRGenFunction &cgf,
1827 const CXXThrowExpr *e) {
1828 // This differs a bit from LLVM codegen, CIR has native operations for some
1829 // cxa functions, and defers allocation size computation, always pass the dtor
1830 // symbol, etc. CIRGen also does not use getAllocateExceptionFn / getThrowFn.
1831
1832 // Now allocate the exception object.
1833 CIRGenBuilderTy &builder = cgf.getBuilder();
1834 QualType clangThrowType = e->getSubExpr()->getType();
1835 cir::PointerType throwTy =
1836 builder.getPointerTo(cgf.convertType(clangThrowType));
1837 uint64_t typeSize =
1838 cgf.getContext().getTypeSizeInChars(clangThrowType).getQuantity();
1839 mlir::Location subExprLoc = cgf.getLoc(e->getSubExpr()->getSourceRange());
1840
1841 // Defer computing allocation size to some later lowering pass.
1842 mlir::TypedValue<cir::PointerType> exceptionPtr =
1843 cir::AllocExceptionOp::create(builder, subExprLoc, throwTy,
1844 builder.getI64IntegerAttr(typeSize))
1845 .getAddr();
1846
1847 // Build expression and store its result into exceptionPtr.
1848 CharUnits exnAlign = cgf.getContext().getExnObjectAlignment();
1849 cgf.emitAnyExprToExn(e->getSubExpr(), Address(exceptionPtr, exnAlign));
1850
1851 // Get the RTTI symbol address.
1852 auto typeInfo = mlir::cast<cir::GlobalViewAttr>(
1853 cgm.getAddrOfRTTIDescriptor(subExprLoc, clangThrowType,
1854 /*forEH=*/true));
1855 assert(!typeInfo.getIndices() && "expected no indirection");
1856
1857 // The address of the destructor.
1858 //
1859 // Note: LLVM codegen already optimizes out the dtor if the
1860 // type is a record with trivial dtor (by passing down a
1861 // null dtor). In CIR, we forward this info and allow for
1862 // Lowering pass to skip passing the trivial function.
1863 //
1864 const auto *cxxrd = clangThrowType->getAsCXXRecordDecl();
1865 mlir::FlatSymbolRefAttr dtor{};
1866 if (cxxrd && !cxxrd->hasTrivialDestructor()) {
1867 // __cxa_throw is declared to take its destructor as void (*)(void *). We
1868 // must match that if function pointers can be authenticated with a
1869 // discriminator based on their type.
1871 CXXDestructorDecl *dtorD = cxxrd->getDestructor();
1872 dtor = mlir::FlatSymbolRefAttr::get(
1873 cgm.getAddrOfCXXStructor(GlobalDecl(dtorD, Dtor_Complete))
1874 .getSymNameAttr());
1875 }
1876
1877 // Now throw the exception.
1878 mlir::Location loc = cgf.getLoc(e->getSourceRange());
1879 insertThrowAndSplit(builder, loc, exceptionPtr, typeInfo.getSymbol(), dtor);
1880}
1881
1883 switch (cgm.getASTContext().getCXXABIKind()) {
1884 case TargetCXXABI::GenericItanium:
1885 case TargetCXXABI::GenericAArch64:
1886 return new CIRGenItaniumCXXABI(cgm);
1887
1888 case TargetCXXABI::AppleARM64:
1889 // The general Itanium ABI will do until we implement something that
1890 // requires special handling.
1892 return new CIRGenItaniumCXXABI(cgm);
1893
1894 default:
1895 llvm_unreachable("bad or NYI ABI kind");
1896 }
1897}
1898
1899cir::GlobalOp CIRGenItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *rd,
1900 CharUnits vptrOffset) {
1901 assert(vptrOffset.isZero() && "Itanium ABI only supports zero vptr offsets");
1902 cir::GlobalOp &vtable = vtables[rd];
1903 if (vtable)
1904 return vtable;
1905
1906 // Queue up this vtable for possible deferred emission.
1907 cgm.addDeferredVTable(rd);
1908
1909 SmallString<256> name;
1910 llvm::raw_svector_ostream out(name);
1911 getMangleContext().mangleCXXVTable(rd, out);
1912
1913 const VTableLayout &vtLayout =
1915 mlir::Type vtableType = cgm.getVTables().getVTableType(vtLayout);
1916
1917 // Use pointer alignment for the vtable. Otherwise we would align them based
1918 // on the size of the initializer which doesn't make sense as only single
1919 // values are read.
1920 unsigned ptrAlign = cgm.getLangOpts().RelativeCXXABIVTables
1921 ? 32
1923
1925 cgm.getLoc(rd->getSourceRange()), name, vtableType,
1926 cir::GlobalLinkageKind::ExternalLinkage,
1927 cgm.getASTContext().toCharUnitsFromBits(ptrAlign));
1928 // LLVM codegen handles unnamedAddr
1930
1931 // In MS C++ if you have a class with virtual functions in which you are using
1932 // selective member import/export, then all virtual functions must be exported
1933 // unless they are inline, otherwise a link error will result. To match this
1934 // behavior, for such classes, we dllimport the vtable if it is defined
1935 // externally and all the non-inline virtual methods are marked dllimport, and
1936 // we dllexport the vtable if it is defined in this TU and all the non-inline
1937 // virtual methods are marked dllexport.
1938 if (cgm.getTarget().hasPS4DLLImportExport())
1939 cgm.errorNYI(rd->getSourceRange(),
1940 "getAddrOfVTable: PS4 DLL import/export");
1941
1942 cgm.setGVProperties(vtable, rd);
1943 return vtable;
1944}
1945
1946CIRGenCallee CIRGenItaniumCXXABI::getVirtualFunctionPointer(
1947 CIRGenFunction &cgf, clang::GlobalDecl gd, Address thisAddr, mlir::Type ty,
1948 SourceLocation srcLoc) {
1949 CIRGenBuilderTy &builder = cgm.getBuilder();
1950 mlir::Location loc = cgf.getLoc(srcLoc);
1951 cir::PointerType tyPtr = builder.getPointerTo(ty);
1952 auto *methodDecl = cast<CXXMethodDecl>(gd.getDecl());
1953 mlir::Value vtable = cgf.getVTablePtr(loc, thisAddr, methodDecl->getParent());
1954
1955 uint64_t vtableIndex = cgm.getItaniumVTableContext().getMethodVTableIndex(gd);
1956 mlir::Value vfunc{};
1957 if (cgf.shouldEmitVTableTypeCheckedLoad(methodDecl->getParent())) {
1958 cgm.errorNYI(loc, "getVirtualFunctionPointer: emitVTableTypeCheckedLoad");
1959 } else {
1961
1962 mlir::Value vfuncLoad;
1963 if (cgm.getLangOpts().RelativeCXXABIVTables) {
1965 cgm.errorNYI(loc, "getVirtualFunctionPointer: isRelativeLayout");
1966 } else {
1967 auto vtableSlotPtr = cir::VTableGetVirtualFnAddrOp::create(
1968 builder, loc, builder.getPointerTo(tyPtr), vtable, vtableIndex);
1969 vfuncLoad = builder.createAlignedLoad(loc, tyPtr, vtableSlotPtr,
1970 cgf.getPointerAlign());
1971 }
1972
1973 // Add !invariant.load md to virtual function load to indicate that
1974 // function didn't change inside vtable.
1975 // It's safe to add it without -fstrict-vtable-pointers, but it would not
1976 // help in devirtualization because it will only matter if we will have 2
1977 // the same virtual function loads from the same vtable load, which won't
1978 // happen without enabled devirtualization with -fstrict-vtable-pointers.
1979 if (cgm.getCodeGenOpts().OptimizationLevel > 0 &&
1980 cgm.getCodeGenOpts().StrictVTablePointers) {
1981 cgm.errorNYI(loc, "getVirtualFunctionPointer: strictVTablePointers");
1982 }
1983 vfunc = vfuncLoad;
1984 }
1985
1986 CIRGenCallee callee(gd, vfunc.getDefiningOp());
1987 return callee;
1988}
1989
1990mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructorWithVTT(
1991 CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,
1992 const CXXRecordDecl *nearestVBase) {
1993 assert((base.getBase()->getNumVBases() || nearestVBase != nullptr) &&
1994 needsVTTParameter(cgf.curGD) && "This class doesn't have VTT");
1995
1996 // Get the secondary vpointer index.
1997 uint64_t virtualPointerIndex =
1998 cgm.getVTables().getSecondaryVirtualPointerIndex(vtableClass, base);
1999
2000 /// Load the VTT.
2001 mlir::Value vttPtr = cgf.loadCXXVTT();
2002 mlir::Location loc = cgf.getLoc(vtableClass->getSourceRange());
2003 // Calculate the address point from the VTT, and the offset may be zero.
2004 vttPtr = cgf.getBuilder().createVTTAddrPoint(loc, vttPtr.getType(), vttPtr,
2005 virtualPointerIndex);
2006 // And load the address point from the VTT.
2007 auto vptrType = cir::VPtrType::get(cgf.getBuilder().getContext());
2008 return cgf.getBuilder().createAlignedLoad(loc, vptrType, vttPtr,
2009 cgf.getPointerAlign());
2010}
2011
2012mlir::Value
2013CIRGenItaniumCXXABI::getVTableAddressPoint(BaseSubobject base,
2014 const CXXRecordDecl *vtableClass) {
2015 cir::GlobalOp vtable = getAddrOfVTable(vtableClass, CharUnits());
2016
2017 // Find the appropriate vtable within the vtable group, and the address point
2018 // within that vtable.
2019 VTableLayout::AddressPointLocation addressPoint =
2021 .getVTableLayout(vtableClass)
2022 .getAddressPoint(base);
2023
2024 mlir::OpBuilder &builder = cgm.getBuilder();
2025 auto vtablePtrTy = cir::VPtrType::get(builder.getContext());
2026
2027 return cir::VTableAddrPointOp::create(
2028 builder, cgm.getLoc(vtableClass->getSourceRange()), vtablePtrTy,
2029 mlir::FlatSymbolRefAttr::get(vtable.getSymNameAttr()),
2030 cir::AddressPointAttr::get(cgm.getBuilder().getContext(),
2031 addressPoint.VTableIndex,
2032 addressPoint.AddressPointIndex));
2033}
2034
2035mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructor(
2036 CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
2037 clang::BaseSubobject base, const clang::CXXRecordDecl *nearestVBase) {
2038
2039 if ((base.getBase()->getNumVBases() || nearestVBase != nullptr) &&
2040 needsVTTParameter(cgf.curGD)) {
2041 return getVTableAddressPointInStructorWithVTT(cgf, vtableClass, base,
2042 nearestVBase);
2043 }
2044 return getVTableAddressPoint(base, vtableClass);
2045}
2046
2047bool CIRGenItaniumCXXABI::isVirtualOffsetNeededForVTableField(
2048 CIRGenFunction &cgf, CIRGenFunction::VPtr vptr) {
2049 if (vptr.nearestVBase == nullptr)
2050 return false;
2051 return needsVTTParameter(cgf.curGD);
2052}
2053
2054mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset(
2055 mlir::Location loc, CIRGenFunction &cgf, Address thisAddr,
2056 const CXXRecordDecl *classDecl, const CXXRecordDecl *baseClassDecl) {
2057 CIRGenBuilderTy &builder = cgf.getBuilder();
2058 mlir::Value vtablePtr = cgf.getVTablePtr(loc, thisAddr, classDecl);
2059 mlir::Value vtableBytePtr = builder.createBitcast(vtablePtr, cgm.uInt8PtrTy);
2060 CharUnits vbaseOffsetOffset =
2062 baseClassDecl);
2063 mlir::Value offsetVal =
2064 builder.getSInt64(vbaseOffsetOffset.getQuantity(), loc);
2065 auto vbaseOffsetPtr = cir::PtrStrideOp::create(builder, loc, cgm.uInt8PtrTy,
2066 vtableBytePtr, offsetVal);
2067
2068 mlir::Value vbaseOffset;
2069 if (cgm.getLangOpts().RelativeCXXABIVTables) {
2071 cgm.errorNYI(loc, "getVirtualBaseClassOffset: relative layout");
2072 } else {
2073 mlir::Value offsetPtr = builder.createBitcast(
2074 vbaseOffsetPtr, builder.getPointerTo(cgm.ptrDiffTy));
2075 vbaseOffset = builder.createLoad(
2076 loc, Address(offsetPtr, cgm.ptrDiffTy, cgf.getPointerAlign()));
2077 }
2078 return vbaseOffset;
2079}
2080
2081static cir::FuncOp getBadCastFn(CIRGenFunction &cgf) {
2082 // Prototype: void __cxa_bad_cast();
2083
2084 // TODO(cir): set the calling convention of the runtime function.
2086
2087 cir::FuncType fnTy =
2088 cgf.getBuilder().getFuncType({}, cgf.getBuilder().getVoidTy());
2089 return cgf.cgm.createRuntimeFunction(fnTy, "__cxa_bad_cast");
2090}
2091
2092static void emitCallToBadCast(CIRGenFunction &cgf, mlir::Location loc) {
2093 // TODO(cir): set the calling convention to the runtime function.
2095
2096 cgf.emitRuntimeCall(loc, getBadCastFn(cgf));
2097 cir::UnreachableOp::create(cgf.getBuilder(), loc);
2098 cgf.getBuilder().clearInsertionPoint();
2099}
2100
2101void CIRGenItaniumCXXABI::emitBadCastCall(CIRGenFunction &cgf,
2102 mlir::Location loc) {
2103 emitCallToBadCast(cgf, loc);
2104}
2105
2106// TODO(cir): This could be shared with classic codegen.
2108 const CXXRecordDecl *src,
2109 const CXXRecordDecl *dst) {
2110 CXXBasePaths paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
2111 /*DetectVirtual=*/false);
2112
2113 // If Dst is not derived from Src we can skip the whole computation below and
2114 // return that Src is not a public base of Dst. Record all inheritance paths.
2115 if (!dst->isDerivedFrom(src, paths))
2116 return CharUnits::fromQuantity(-2);
2117
2118 unsigned numPublicPaths = 0;
2119 CharUnits offset;
2120
2121 // Now walk all possible inheritance paths.
2122 for (const CXXBasePath &path : paths) {
2123 if (path.Access != AS_public) // Ignore non-public inheritance.
2124 continue;
2125
2126 ++numPublicPaths;
2127
2128 for (const CXXBasePathElement &pathElement : path) {
2129 // If the path contains a virtual base class we can't give any hint.
2130 // -1: no hint.
2131 if (pathElement.Base->isVirtual())
2132 return CharUnits::fromQuantity(-1);
2133
2134 if (numPublicPaths > 1) // Won't use offsets, skip computation.
2135 continue;
2136
2137 // Accumulate the base class offsets.
2138 const ASTRecordLayout &L =
2139 astContext.getASTRecordLayout(pathElement.Class);
2140 offset += L.getBaseClassOffset(
2141 pathElement.Base->getType()->getAsCXXRecordDecl());
2142 }
2143 }
2144
2145 // -2: Src is not a public base of Dst.
2146 if (numPublicPaths == 0)
2147 return CharUnits::fromQuantity(-2);
2148
2149 // -3: Src is a multiple public base type but never a virtual base type.
2150 if (numPublicPaths > 1)
2151 return CharUnits::fromQuantity(-3);
2152
2153 // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
2154 // Return the offset of Src from the origin of Dst.
2155 return offset;
2156}
2157
2158static cir::FuncOp getItaniumDynamicCastFn(CIRGenFunction &cgf) {
2159 // Prototype:
2160 // void *__dynamic_cast(const void *sub,
2161 // global_as const abi::__class_type_info *src,
2162 // global_as const abi::__class_type_info *dst,
2163 // std::ptrdiff_t src2dst_offset);
2164
2165 mlir::Type voidPtrTy = cgf.getBuilder().getVoidPtrTy();
2166 mlir::Type rttiPtrTy = cgf.getBuilder().getUInt8PtrTy();
2167 mlir::Type ptrDiffTy = cgf.convertType(cgf.getContext().getPointerDiffType());
2168
2169 // TODO(cir): mark the function as willreturn readonly.
2172
2173 // TODO(cir): set the calling convention of the runtime function.
2175
2176 cir::FuncType FTy = cgf.getBuilder().getFuncType(
2177 {voidPtrTy, rttiPtrTy, rttiPtrTy, ptrDiffTy}, voidPtrTy);
2178 cir::FuncOp fn = cgf.cgm.createRuntimeFunction(FTy, "__dynamic_cast");
2179 fn->setAttr(cir::CIRDialect::getNoThrowAttrName(),
2180 mlir::UnitAttr::get(cgf.getBuilder().getContext()));
2181 return fn;
2182}
2183
2184static Address emitDynamicCastToVoid(CIRGenFunction &cgf, mlir::Location loc,
2185 QualType srcRecordTy, Address src) {
2186 bool vtableUsesRelativeLayout = cgf.cgm.getLangOpts().RelativeCXXABIVTables;
2187 mlir::Value ptr = cgf.getBuilder().createDynCastToVoid(
2188 loc, src.getPointer(), vtableUsesRelativeLayout);
2189 return Address{ptr, src.getAlignment()};
2190}
2191
2192static mlir::Value emitExactDynamicCast(CIRGenItaniumCXXABI &abi,
2193 CIRGenFunction &cgf, mlir::Location loc,
2194 QualType srcRecordTy,
2195 QualType destRecordTy,
2196 cir::PointerType destCIRTy,
2197 bool isRefCast, Address src) {
2198 // Find all the inheritance paths from SrcRecordTy to DestRecordTy.
2199 const CXXRecordDecl *srcDecl = srcRecordTy->getAsCXXRecordDecl();
2200 const CXXRecordDecl *destDecl = destRecordTy->getAsCXXRecordDecl();
2201 CXXBasePaths paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
2202 /*DetectVirtual=*/false);
2203 (void)destDecl->isDerivedFrom(srcDecl, paths);
2204
2205 // Find an offset within `destDecl` where a `srcDecl` instance and its vptr
2206 // might appear.
2207 std::optional<CharUnits> offset;
2208 for (const CXXBasePath &path : paths) {
2209 // dynamic_cast only finds public inheritance paths.
2210 if (path.Access != AS_public)
2211 continue;
2212
2213 CharUnits pathOffset;
2214 for (const CXXBasePathElement &pathElement : path) {
2215 // Find the offset along this inheritance step.
2216 const CXXRecordDecl *base =
2217 pathElement.Base->getType()->getAsCXXRecordDecl();
2218 if (pathElement.Base->isVirtual()) {
2219 // For a virtual base class, we know that the derived class is exactly
2220 // destDecl, so we can use the vbase offset from its layout.
2221 const ASTRecordLayout &layout =
2222 cgf.getContext().getASTRecordLayout(destDecl);
2223 pathOffset = layout.getVBaseClassOffset(base);
2224 } else {
2225 const ASTRecordLayout &layout =
2226 cgf.getContext().getASTRecordLayout(pathElement.Class);
2227 pathOffset += layout.getBaseClassOffset(base);
2228 }
2229 }
2230
2231 if (!offset) {
2232 offset = pathOffset;
2233 } else if (offset != pathOffset) {
2234 // base appears in at least two different places. Find the most-derived
2235 // object and see if it's a DestDecl. Note that the most-derived object
2236 // must be at least as aligned as this base class subobject, and must
2237 // have a vptr at offset 0.
2238 src = emitDynamicCastToVoid(cgf, loc, srcRecordTy, src);
2239 srcDecl = destDecl;
2240 offset = CharUnits::Zero();
2241 break;
2242 }
2243 }
2244
2245 CIRGenBuilderTy &builder = cgf.getBuilder();
2246
2247 if (!offset) {
2248 // If there are no public inheritance paths, the cast always fails.
2249 mlir::Value nullPtrValue = builder.getNullPtr(destCIRTy, loc);
2250 if (isRefCast) {
2251 mlir::Region *currentRegion = builder.getBlock()->getParent();
2252 emitCallToBadCast(cgf, loc);
2253
2254 // The call to bad_cast will terminate the block. Create a new block to
2255 // hold any follow up code.
2256 builder.createBlock(currentRegion, currentRegion->end());
2257 }
2258
2259 return nullPtrValue;
2260 }
2261
2262 // Compare the vptr against the expected vptr for the destination type at
2263 // this offset. Note that we do not know what type src points to in the case
2264 // where the derived class multiply inherits from the base class so we can't
2265 // use getVTablePtr, so we load the vptr directly instead.
2266
2267 mlir::Value expectedVPtr =
2268 abi.getVTableAddressPoint(BaseSubobject(srcDecl, *offset), destDecl);
2269
2270 // TODO(cir): handle address space here.
2272 mlir::Type vptrTy = expectedVPtr.getType();
2273 mlir::Type vptrPtrTy = builder.getPointerTo(vptrTy);
2274 Address srcVPtrPtr(builder.createBitcast(src.getPointer(), vptrPtrTy),
2275 src.getAlignment());
2276 mlir::Value srcVPtr = builder.createLoad(loc, srcVPtrPtr);
2277
2278 // TODO(cir): decorate SrcVPtr with TBAA info.
2280
2281 mlir::Value success =
2282 builder.createCompare(loc, cir::CmpOpKind::eq, srcVPtr, expectedVPtr);
2283
2284 auto emitCastResult = [&] {
2285 if (offset->isZero())
2286 return builder.createBitcast(src.getPointer(), destCIRTy);
2287
2288 // TODO(cir): handle address space here.
2290 mlir::Type u8PtrTy = builder.getUInt8PtrTy();
2291
2292 mlir::Value strideToApply =
2293 builder.getConstInt(loc, builder.getUInt64Ty(), -offset->getQuantity());
2294 mlir::Value srcU8Ptr = builder.createBitcast(src.getPointer(), u8PtrTy);
2295 mlir::Value resultU8Ptr = cir::PtrStrideOp::create(builder, loc, u8PtrTy,
2296 srcU8Ptr, strideToApply);
2297 return builder.createBitcast(resultU8Ptr, destCIRTy);
2298 };
2299
2300 if (isRefCast) {
2301 mlir::Value failed = builder.createNot(success);
2302 cir::IfOp::create(builder, loc, failed, /*withElseRegion=*/false,
2303 [&](mlir::OpBuilder &, mlir::Location) {
2304 emitCallToBadCast(cgf, loc);
2305 });
2306 return emitCastResult();
2307 }
2308
2309 return cir::TernaryOp::create(
2310 builder, loc, success,
2311 [&](mlir::OpBuilder &, mlir::Location) {
2312 auto result = emitCastResult();
2313 builder.createYield(loc, result);
2314 },
2315 [&](mlir::OpBuilder &, mlir::Location) {
2316 mlir::Value nullPtrValue = builder.getNullPtr(destCIRTy, loc);
2317 builder.createYield(loc, nullPtrValue);
2318 })
2319 .getResult();
2320}
2321
2322static cir::DynamicCastInfoAttr emitDynamicCastInfo(CIRGenFunction &cgf,
2323 mlir::Location loc,
2324 QualType srcRecordTy,
2325 QualType destRecordTy) {
2326 auto srcRtti = mlir::cast<cir::GlobalViewAttr>(
2327 cgf.cgm.getAddrOfRTTIDescriptor(loc, srcRecordTy));
2328 auto destRtti = mlir::cast<cir::GlobalViewAttr>(
2329 cgf.cgm.getAddrOfRTTIDescriptor(loc, destRecordTy));
2330
2331 cir::FuncOp runtimeFuncOp = getItaniumDynamicCastFn(cgf);
2332 cir::FuncOp badCastFuncOp = getBadCastFn(cgf);
2333 auto runtimeFuncRef = mlir::FlatSymbolRefAttr::get(runtimeFuncOp);
2334 auto badCastFuncRef = mlir::FlatSymbolRefAttr::get(badCastFuncOp);
2335
2336 const CXXRecordDecl *srcDecl = srcRecordTy->getAsCXXRecordDecl();
2337 const CXXRecordDecl *destDecl = destRecordTy->getAsCXXRecordDecl();
2338 CharUnits offsetHint = computeOffsetHint(cgf.getContext(), srcDecl, destDecl);
2339
2340 mlir::Type ptrdiffTy = cgf.convertType(cgf.getContext().getPointerDiffType());
2341 auto offsetHintAttr = cir::IntAttr::get(ptrdiffTy, offsetHint.getQuantity());
2342
2343 return cir::DynamicCastInfoAttr::get(srcRtti, destRtti, runtimeFuncRef,
2344 badCastFuncRef, offsetHintAttr);
2345}
2346
2347mlir::Value CIRGenItaniumCXXABI::emitDynamicCast(CIRGenFunction &cgf,
2348 mlir::Location loc,
2349 QualType srcRecordTy,
2350 QualType destRecordTy,
2351 cir::PointerType destCIRTy,
2352 bool isRefCast, Address src) {
2353 bool isCastToVoid = destRecordTy.isNull();
2354 assert((!isCastToVoid || !isRefCast) && "cannot cast to void reference");
2355
2356 if (isCastToVoid)
2357 return emitDynamicCastToVoid(cgf, loc, srcRecordTy, src).getPointer();
2358
2359 // If the destination is effectively final, the cast succeeds if and only
2360 // if the dynamic type of the pointer is exactly the destination type.
2361 if (destRecordTy->getAsCXXRecordDecl()->isEffectivelyFinal() &&
2362 cgf.cgm.getCodeGenOpts().OptimizationLevel > 0) {
2363 CIRGenBuilderTy &builder = cgf.getBuilder();
2364 // If this isn't a reference cast, check the pointer to see if it's null.
2365 if (!isRefCast) {
2366 mlir::Value srcPtrIsNull = builder.createPtrIsNull(src.getPointer());
2367 return cir::TernaryOp::create(
2368 builder, loc, srcPtrIsNull,
2369 [&](mlir::OpBuilder, mlir::Location) {
2370 builder.createYield(
2371 loc, builder.getNullPtr(destCIRTy, loc).getResult());
2372 },
2373 [&](mlir::OpBuilder &, mlir::Location) {
2374 mlir::Value exactCast = emitExactDynamicCast(
2375 *this, cgf, loc, srcRecordTy, destRecordTy, destCIRTy,
2376 isRefCast, src);
2377 builder.createYield(loc, exactCast);
2378 })
2379 .getResult();
2380 }
2381
2382 return emitExactDynamicCast(*this, cgf, loc, srcRecordTy, destRecordTy,
2383 destCIRTy, isRefCast, src);
2384 }
2385
2386 cir::DynamicCastInfoAttr castInfo =
2387 emitDynamicCastInfo(cgf, loc, srcRecordTy, destRecordTy);
2388 return cgf.getBuilder().createDynCast(loc, src.getPointer(), destCIRTy,
2389 isRefCast, castInfo);
2390}
2391
2392cir::MethodAttr
2393CIRGenItaniumCXXABI::buildVirtualMethodAttr(cir::MethodType methodTy,
2394 const CXXMethodDecl *md) {
2395 assert(md->isVirtual() && "only deal with virtual member functions");
2396
2398 uint64_t vtableOffset;
2399 if (cgm.getLangOpts().RelativeCXXABIVTables) {
2400 // Multiply by 4-byte relative offsets.
2401 vtableOffset = index * 4;
2402 } else {
2403 const ASTContext &astContext = cgm.getASTContext();
2404 CharUnits pointerWidth = astContext.toCharUnitsFromBits(
2405 astContext.getTargetInfo().getPointerWidth(LangAS::Default));
2406 vtableOffset = index * pointerWidth.getQuantity();
2407 }
2408
2409 return cir::MethodAttr::get(methodTy, vtableOffset);
2410}
2411/// The Itanium ABI always places an offset to the complete object
2412/// at entry -2 in the vtable.
2413void CIRGenItaniumCXXABI::emitVirtualObjectDelete(
2414 CIRGenFunction &cgf, const CXXDeleteExpr *delExpr, Address ptr,
2415 QualType elementType, const CXXDestructorDecl *dtor) {
2416 bool useGlobalDelete = delExpr->isGlobalDelete();
2417 if (useGlobalDelete) {
2418 cgf.cgm.errorNYI(delExpr->getSourceRange(),
2419 "emitVirtualObjectDelete: global delete");
2420 }
2421
2422 CXXDtorType dtorType = useGlobalDelete ? Dtor_Complete : Dtor_Deleting;
2423 emitVirtualDestructorCall(cgf, dtor, dtorType, ptr, delExpr);
2424}
2425
2426/************************** Array allocation cookies **************************/
2427
2428CharUnits CIRGenItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {
2429 // The array cookie is a size_t; pad that up to the element alignment.
2430 // The cookie is actually right-justified in that space.
2431 return std::max(
2432 cgm.getSizeSize(),
2433 cgm.getASTContext().getPreferredTypeAlignInChars(elementType));
2434}
2435
2436Address CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
2437 Address newPtr,
2438 mlir::Value numElements,
2439 const CXXNewExpr *e,
2440 QualType elementType) {
2441 assert(requiresArrayCookie(e));
2442
2443 // TODO: When sanitizer support is implemented, we'll need to
2444 // get the address space from `newPtr`.
2447
2448 ASTContext &ctx = cgm.getASTContext();
2449 CharUnits sizeSize = cgf.getSizeSize();
2450 mlir::Location loc = cgf.getLoc(e->getSourceRange());
2451
2452 // The size of the cookie.
2453 CharUnits cookieSize =
2454 std::max(sizeSize, ctx.getPreferredTypeAlignInChars(elementType));
2455 assert(cookieSize == getArrayCookieSizeImpl(elementType));
2456
2457 cir::PointerType u8PtrTy = cgf.getBuilder().getUInt8PtrTy();
2458 mlir::Value baseBytePtr =
2459 cgf.getBuilder().createPtrBitcast(newPtr.getPointer(), u8PtrTy);
2460
2461 // Compute an offset to the cookie.
2462 CharUnits cookieOffset = cookieSize - sizeSize;
2463 mlir::Value cookiePtrValue = baseBytePtr;
2464 if (!cookieOffset.isZero()) {
2465 mlir::Value offsetOp = cgf.getBuilder().getSignedInt(
2466 loc, cookieOffset.getQuantity(), /*width=*/32);
2467 cookiePtrValue =
2468 cgf.getBuilder().createPtrStride(loc, cookiePtrValue, offsetOp);
2469 }
2470
2471 CharUnits baseAlignment = newPtr.getAlignment();
2472 CharUnits cookiePtrAlignment = baseAlignment.alignmentAtOffset(cookieOffset);
2473 Address cookiePtr(cookiePtrValue, u8PtrTy, cookiePtrAlignment);
2474
2475 // Write the number of elements into the appropriate slot.
2476 Address numElementsPtr =
2477 cookiePtr.withElementType(cgf.getBuilder(), cgf.sizeTy);
2478 cgf.getBuilder().createStore(loc, numElements, numElementsPtr);
2479
2480 // Finally, compute a pointer to the actual data buffer by skipping
2481 // over the cookie completely.
2482 mlir::Value dataOffset =
2483 cgf.getBuilder().getSignedInt(loc, cookieSize.getQuantity(),
2484 /*width=*/32);
2485 mlir::Value dataPtr =
2486 cgf.getBuilder().createPtrStride(loc, baseBytePtr, dataOffset);
2487 mlir::Value finalPtr =
2488 cgf.getBuilder().createPtrBitcast(dataPtr, newPtr.getElementType());
2489 CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
2490 return Address(finalPtr, newPtr.getElementType(), finalAlignment);
2491}
2492
2493namespace {
2494/// From traditional LLVM, useful info for LLVM lowering support:
2495/// A cleanup to call __cxa_end_catch. In many cases, the caught
2496/// exception type lets us state definitively that the thrown exception
2497/// type does not have a destructor. In particular:
2498/// - Catch-alls tell us nothing, so we have to conservatively
2499/// assume that the thrown exception might have a destructor.
2500/// - Catches by reference behave according to their base types.
2501/// - Catches of non-record types will only trigger for exceptions
2502/// of non-record types, which never have destructors.
2503/// - Catches of record types can trigger for arbitrary subclasses
2504/// of the caught type, so we have to assume the actual thrown
2505/// exception type might have a throwing destructor, even if the
2506/// caught type's destructor is trivial or nothrow.
2507struct CallEndCatch final : EHScopeStack::Cleanup {
2508 CallEndCatch(bool mightThrow, mlir::Value catchToken)
2509 : mightThrow(mightThrow), catchToken(catchToken) {}
2510 bool mightThrow;
2511 mlir::Value catchToken;
2512
2513 void emit(CIRGenFunction &cgf, Flags flags) override {
2514 // Traditional LLVM codegen would emit a call to __cxa_end_catch
2515 // here. For CIR, just let it pass since the cleanup is going
2516 // to be emitted on a later pass when lowering the catch region.
2517 // CGF.EmitRuntimeCallOrTryCall(getEndCatchFn(CGF.CGM));
2518 cir::EndCatchOp::create(cgf.getBuilder(), *cgf.currSrcLoc, catchToken);
2519 cir::YieldOp::create(cgf.getBuilder(), *cgf.currSrcLoc);
2520 }
2521};
2522} // namespace
2523
2524static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken,
2525 mlir::Type exnPtrTy, bool endMightThrow) {
2526 auto catchTokenTy = cir::CatchTokenType::get(cgf.getBuilder().getContext());
2527 auto beginCatch = cir::BeginCatchOp::create(cgf.getBuilder(),
2528 cgf.getBuilder().getUnknownLoc(),
2529 catchTokenTy, exnPtrTy, ehToken);
2530
2531 cgf.ehStack.pushCleanup<CallEndCatch>(
2533 endMightThrow && !cgf.cgm.getLangOpts().AssumeNothrowExceptionDtor,
2534 beginCatch.getCatchToken());
2535
2536 return beginCatch.getExnPtr();
2537}
2538
2539/// A "special initializer" callback for initializing a catch
2540/// parameter during catch initialization.
2541static void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken,
2542 const VarDecl &catchParam, Address paramAddr,
2543 SourceLocation loc) {
2544 CanQualType catchType =
2545 cgf.cgm.getASTContext().getCanonicalType(catchParam.getType());
2546 mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType);
2547
2548 // If we're catching by reference, we can just cast the object
2549 // pointer to the appropriate pointer.
2550 if (isa<ReferenceType>(catchType)) {
2551 QualType caughtType = cast<ReferenceType>(catchType)->getPointeeType();
2552 bool endCatchMightThrow = caughtType->isRecordType();
2553
2554 mlir::Value adjustedExn =
2555 callBeginCatch(cgf, ehToken, cirCatchTy, endCatchMightThrow);
2556
2557 // We have no way to tell the personality function that we're
2558 // catching by reference, so if we're catching a pointer,
2559 // __cxa_begin_catch will actually return that pointer by value.
2560 if (const PointerType *pt = dyn_cast<PointerType>(caughtType)) {
2561 QualType pointeeType = pt->getPointeeType();
2562 // When catching by reference, generally we should just ignore
2563 // this by-value pointer and use the exception object instead.
2564 if (!pointeeType->isRecordType()) {
2565 cgf.cgm.errorNYI(loc,
2566 "initCatchParam: catching a pointer of non-record");
2567 } else {
2568 // Pull the pointer for the reference type off.
2569 mlir::Type ptrTy = cgf.convertTypeForMem(caughtType);
2570
2571 // Create the temporary and write the adjusted pointer into it.
2572 Address exnPtrTmp = cgf.createTempAlloca(
2573 ptrTy, cgf.getPointerAlign(), cgf.getLoc(loc), "exn.byref.tmp");
2574 mlir::Value casted = cgf.getBuilder().createBitcast(adjustedExn, ptrTy);
2575 cgf.getBuilder().createStore(cgf.getLoc(loc), casted, exnPtrTmp);
2576
2577 // Bind the reference to the temporary.
2578 adjustedExn = exnPtrTmp.emitRawPointer();
2579 }
2580 }
2581
2582 mlir::Value exnCast =
2583 cgf.getBuilder().createBitcast(adjustedExn, cirCatchTy);
2584 cgf.getBuilder().createStore(cgf.getLoc(loc), exnCast, paramAddr);
2585 return;
2586 }
2587
2588 // Scalars and complexes.
2589 cir::TypeEvaluationKind tek = cgf.getEvaluationKind(catchType);
2590 if (tek != cir::TEK_Aggregate) {
2591 // Notes for LLVM lowering:
2592 // If the catch type is a pointer type, __cxa_begin_catch returns
2593 // the pointer by value.
2594 if (catchType->hasPointerRepresentation()) {
2595 mlir::Value catchParam =
2596 callBeginCatch(cgf, ehToken, cirCatchTy, /*endMightThrow=*/false);
2597 switch (catchType.getQualifiers().getObjCLifetime()) {
2599 cgf.cgm.errorNYI(loc,
2600 "initCatchParam: PointerRepresentation OCL_Strong");
2601 return;
2602
2605 cgf.cgm.errorNYI(loc, "initCatchParam: PointerRepresentation "
2606 "OCL_ExplicitNone & OCL_Autoreleasing");
2607 return;
2608
2610 cgf.getBuilder().createStore(cgf.getLoc(loc), catchParam, paramAddr);
2611 return;
2612
2614 cgf.cgm.errorNYI(loc, "initCatchParam: PointerRepresentation OCL_Weak");
2615 return;
2616 }
2617
2618 llvm_unreachable("bad ownership qualifier!");
2619 }
2620
2621 // Otherwise, it returns a pointer into the exception object.
2622 mlir::Type cirCatchTy = cgf.convertTypeForMem(catchType);
2623 mlir::Value catchParam =
2624 callBeginCatch(cgf, ehToken, cgf.getBuilder().getPointerTo(cirCatchTy),
2625 /*endMightThrow=*/false);
2626 LValue srcLV = cgf.makeNaturalAlignAddrLValue(catchParam, catchType);
2627 LValue destLV = cgf.makeAddrLValue(paramAddr, catchType);
2628 switch (tek) {
2629 case cir::TEK_Complex: {
2630 mlir::Value load = cgf.emitLoadOfComplex(srcLV, loc);
2631 cgf.emitStoreOfComplex(cgf.getLoc(loc), load, destLV, /*isInit=*/true);
2632 return;
2633 }
2634 case cir::TEK_Scalar: {
2635 mlir::Value exnLoad = cgf.emitLoadOfScalar(srcLV, loc);
2636 cgf.emitStoreOfScalar(exnLoad, destLV, /*isInit=*/true);
2637 return;
2638 }
2639 case cir::TEK_Aggregate:
2640 llvm_unreachable("evaluation kind filtered out!");
2641 }
2642
2643 llvm_unreachable("bad evaluation kind");
2644 }
2645
2646 assert(isa<RecordType>(catchType) && "unexpected catch type!");
2647 auto *catchRD = catchType->getAsCXXRecordDecl();
2648 CharUnits caughtExnAlignment = cgf.cgm.getClassPointerAlignment(catchRD);
2649
2650 // Check for a copy expression. If we don't have a copy expression,
2651 // that means a trivial copy is okay.
2652 const Expr *copyExpr = catchParam.getInit();
2653 if (!copyExpr) {
2654 mlir::Type cirCatchPtrTy = cgf.getBuilder().getPointerTo(cirCatchTy);
2655 mlir::Value rawAdjustedExn =
2656 callBeginCatch(cgf, ehToken, cirCatchPtrTy, /*endMightThrow=*/true);
2657 Address adjustedExn(rawAdjustedExn, cirCatchTy, caughtExnAlignment);
2658 LValue dest = cgf.makeAddrLValue(paramAddr, catchType);
2659 LValue src = cgf.makeAddrLValue(adjustedExn, catchType);
2660 cgf.emitAggregateCopy(dest, src, catchType, AggValueSlot::DoesNotOverlap);
2661 return;
2662 }
2663
2664 cgf.cgm.errorNYI(loc, "initCatchParam: cir::TEK_Aggregate non-trivial copy");
2665}
2666
2667/// Begins a catch statement by initializing the catch variable and
2668/// calling __cxa_begin_catch.
2669void CIRGenItaniumCXXABI::emitBeginCatch(CIRGenFunction &cgf,
2670 const CXXCatchStmt *catchStmt,
2671 mlir::Value ehToken) {
2672 // We have to be very careful with the ordering of cleanups here:
2673 // C++ [except.throw]p4:
2674 // The destruction [of the exception temporary] occurs
2675 // immediately after the destruction of the object declared in
2676 // the exception-declaration in the handler.
2677 //
2678 // So the precise ordering is:
2679 // 1. Construct catch variable.
2680 // 2. __cxa_begin_catch
2681 // 3. Enter __cxa_end_catch cleanup
2682 // 4. Enter dtor cleanup
2683 //
2684 // We do this by using a slightly abnormal initialization process.
2685 // Delegation sequence:
2686 // - ExitCXXTryStmt opens a RunCleanupsScope
2687 // - EmitAutoVarAlloca creates the variable and debug info
2688 // - InitCatchParam initializes the variable from the exception
2689 // - CallBeginCatch calls __cxa_begin_catch
2690 // - CallBeginCatch enters the __cxa_end_catch cleanup
2691 // - EmitAutoVarCleanups enters the variable destructor cleanup
2692 // - EmitCXXTryStmt emits the code for the catch body
2693 // - EmitCXXTryStmt close the RunCleanupsScope
2694
2695 VarDecl *catchParam = catchStmt->getExceptionDecl();
2696 if (!catchParam) {
2697 callBeginCatch(cgf, ehToken, cgf.getBuilder().getVoidPtrTy(),
2698 /*endMightThrow=*/true);
2699 return;
2700 }
2701
2702 auto getCatchParamAllocaIP = [&]() {
2703 cir::CIRBaseBuilderTy::InsertPoint currIns =
2704 cgf.getBuilder().saveInsertionPoint();
2705 mlir::Operation *currParent = currIns.getBlock()->getParentOp();
2706
2707 mlir::Block *insertBlock = nullptr;
2708 if (auto scopeOp = currParent->getParentOfType<cir::ScopeOp>()) {
2709 insertBlock = &scopeOp.getScopeRegion().getBlocks().back();
2710 } else if (auto fnOp = currParent->getParentOfType<cir::FuncOp>()) {
2711 insertBlock = &fnOp.getRegion().getBlocks().back();
2712 } else {
2713 llvm_unreachable("unknown outermost scope-like parent");
2714 }
2715 return cgf.getBuilder().getBestAllocaInsertPoint(insertBlock);
2716 };
2717
2718 // Emit the local. Make sure the alloca's superseed the current scope, since
2719 // these are going to be consumed by `cir.catch`, which is not within the
2720 // current scope.
2721
2722 CIRGenFunction::AutoVarEmission var =
2723 cgf.emitAutoVarAlloca(*catchParam, getCatchParamAllocaIP());
2724 initCatchParam(cgf, ehToken, *catchParam, var.getObjectAddress(cgf),
2725 catchStmt->getBeginLoc());
2726 cgf.emitAutoVarCleanups(var);
2727}
2728
2729bool CIRGenItaniumCXXABI::hasAnyUnusedVirtualInlineFunction(
2730 const CXXRecordDecl *rd) const {
2731 const auto &vtableLayout = cgm.getItaniumVTableContext().getVTableLayout(rd);
2732
2733 for (const auto &vtableComponent : vtableLayout.vtable_components()) {
2734 // Skip empty slot.
2735 if (!vtableComponent.isUsedFunctionPointerKind())
2736 continue;
2737
2738 const CXXMethodDecl *method = vtableComponent.getFunctionDecl();
2739 const FunctionDecl *fd = method->getDefinition();
2740 const bool isInlined =
2741 method->getCanonicalDecl()->isInlined() || (fd && fd->isInlined());
2742 if (!isInlined)
2743 continue;
2744
2745 StringRef name = cgm.getMangledName(
2746 vtableComponent.getGlobalDecl(/*HasVectorDeletingDtors=*/false));
2747 auto entry = dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue(name));
2748 // This checks if virtual inline function has already been emitted.
2749 // Note that it is possible that this inline function would be emitted
2750 // after trying to emit vtable speculatively. Because of this we do
2751 // an extra pass after emitting all deferred vtables to find and emit
2752 // these vtables opportunistically.
2753 if (!entry || entry.isDeclaration())
2754 return true;
2755 }
2756 return false;
2757}
2758
2759bool CIRGenItaniumCXXABI::isVTableHidden(const CXXRecordDecl *rd) const {
2760 const auto &vtableLayout = cgm.getItaniumVTableContext().getVTableLayout(rd);
2761
2762 for (const auto &vtableComponent : vtableLayout.vtable_components()) {
2763 if (vtableComponent.isRTTIKind()) {
2764 const CXXRecordDecl *rttiDecl = vtableComponent.getRTTIDecl();
2765 if (rttiDecl->getVisibility() == Visibility::HiddenVisibility)
2766 return true;
2767 } else if (vtableComponent.isUsedFunctionPointerKind()) {
2768 const CXXMethodDecl *method = vtableComponent.getFunctionDecl();
2769 if (method->getVisibility() == Visibility::HiddenVisibility &&
2770 !method->isDefined())
2771 return true;
2772 }
2773 }
2774 return false;
2775}
2776
2777bool CIRGenItaniumCXXABI::canSpeculativelyEmitVTableAsBaseClass(
2778 const CXXRecordDecl *rd) const {
2779 // We don't emit available_externally vtables if we are in -fapple-kext mode
2780 // because kext mode does not permit devirtualization.
2781 if (cgm.getLangOpts().AppleKext)
2782 return false;
2783
2784 // If the vtable is hidden then it is not safe to emit an available_externally
2785 // copy of vtable.
2786 if (isVTableHidden(rd))
2787 return false;
2788
2789 if (cgm.getCodeGenOpts().ForceEmitVTables)
2790 return true;
2791
2792 // A speculative vtable can only be generated if all virtual inline functions
2793 // defined by this class are emitted. The vtable in the final program contains
2794 // for each virtual inline function not used in the current TU a function that
2795 // is equivalent to the unused function. The function in the actual vtable
2796 // does not have to be declared under the same symbol (e.g., a virtual
2797 // destructor that can be substituted with its base class's destructor). Since
2798 // inline functions are emitted lazily and this emissions does not account for
2799 // speculative emission of a vtable, we might generate a speculative vtable
2800 // with references to inline functions that are not emitted under that name.
2801 // This can lead to problems when devirtualizing a call to such a function,
2802 // that result in linking errors. Hence, if there are any unused virtual
2803 // inline function, we cannot emit the speculative vtable.
2804 // FIXME we can still emit a copy of the vtable if we
2805 // can emit definition of the inline functions.
2806 if (hasAnyUnusedVirtualInlineFunction(rd))
2807 return false;
2808
2809 // For a class with virtual bases, we must also be able to speculatively
2810 // emit the VTT, because CodeGen doesn't have separate notions of "can emit
2811 // the vtable" and "can emit the VTT". For a base subobject, this means we
2812 // need to be able to emit non-virtual base vtables.
2813 if (rd->getNumVBases()) {
2814 for (const auto &b : rd->bases()) {
2815 auto *brd = b.getType()->getAsCXXRecordDecl();
2816 assert(brd && "no class for base specifier");
2817 if (b.isVirtual() || !brd->isDynamicClass())
2818 continue;
2819 if (!canSpeculativelyEmitVTableAsBaseClass(brd))
2820 return false;
2821 }
2822 }
2823
2824 return true;
2825}
2826
2827bool CIRGenItaniumCXXABI::canSpeculativelyEmitVTable(
2828 const CXXRecordDecl *rd) const {
2829 if (!canSpeculativelyEmitVTableAsBaseClass(rd))
2830 return false;
2831
2833 return false;
2834
2835 // For a complete-object vtable (or more specifically, for the VTT), we need
2836 // to be able to speculatively emit the vtables of all dynamic virtual bases.
2837 for (const auto &b : rd->vbases()) {
2838 auto *brd = b.getType()->getAsCXXRecordDecl();
2839 assert(brd && "no class for base specifier");
2840 if (!brd->isDynamicClass())
2841 continue;
2842 if (!canSpeculativelyEmitVTableAsBaseClass(brd))
2843 return false;
2844 }
2845
2846 return true;
2847}
2848
2850 Address initialPtr,
2851 const CXXRecordDecl *unadjustedClass,
2852 int64_t nonVirtualAdjustment,
2853 int64_t virtualAdjustment,
2854 bool isReturnAdjustment) {
2855 if (!nonVirtualAdjustment && !virtualAdjustment)
2856 return initialPtr.getPointer();
2857
2858 CIRGenBuilderTy &builder = cgf.getBuilder();
2859 mlir::Location loc = builder.getUnknownLoc();
2860 cir::PointerType i8PtrTy = builder.getUInt8PtrTy();
2861 mlir::Value v = builder.createBitcast(initialPtr.getPointer(), i8PtrTy);
2862
2863 // In a base-to-derived cast, the non-virtual adjustment is applied first.
2864 if (nonVirtualAdjustment && !isReturnAdjustment) {
2865 cir::ConstantOp offsetConst = builder.getSInt64(nonVirtualAdjustment, loc);
2866 v = cir::PtrStrideOp::create(builder, loc, i8PtrTy, v, offsetConst);
2867 }
2868
2869 // Perform the virtual adjustment if we have one.
2870 mlir::Value resultPtr;
2871 if (virtualAdjustment) {
2872 mlir::Value vtablePtr = cgf.getVTablePtr(
2873 loc, Address(v, clang::CharUnits::One()), unadjustedClass);
2874 vtablePtr = builder.createBitcast(vtablePtr, i8PtrTy);
2875
2876 mlir::Value offset;
2877 mlir::Value offsetPtr =
2878 cir::PtrStrideOp::create(builder, loc, i8PtrTy, vtablePtr,
2879 builder.getSInt64(virtualAdjustment, loc));
2880 if (cgf.cgm.getLangOpts().RelativeCXXABIVTables) {
2882 cgf.cgm.errorNYI("virtual adjustment for relative layout vtables");
2883 } else {
2884 offset = builder.createAlignedLoad(loc, cgf.ptrDiffTy, offsetPtr,
2885 cgf.getPointerAlign());
2886 }
2887
2888 resultPtr = cir::PtrStrideOp::create(builder, loc, i8PtrTy, v, offset);
2889 } else {
2890 resultPtr = v;
2891 }
2892
2893 // In a derived-to-base conversion, the non-virtual adjustment is
2894 // applied second.
2895 if (nonVirtualAdjustment && isReturnAdjustment) {
2896 cir::ConstantOp offsetConst = builder.getSInt64(nonVirtualAdjustment, loc);
2897 resultPtr =
2898 cir::PtrStrideOp::create(builder, loc, i8PtrTy, resultPtr, offsetConst);
2899 }
2900
2901 // Cast back to original pointer type.
2902 return builder.createBitcast(resultPtr, initialPtr.getType());
2903}
2904
2905mlir::Value CIRGenItaniumCXXABI::performThisAdjustment(
2906 CIRGenFunction &cgf, Address thisAddr, const CXXRecordDecl *unadjustedClass,
2907 const ThunkInfo &ti) {
2908 return performTypeAdjustment(cgf, thisAddr, unadjustedClass,
2909 ti.This.NonVirtual,
2911 /*isReturnAdjustment=*/false);
2912}
2913
2914mlir::Value CIRGenItaniumCXXABI::performReturnAdjustment(
2915 CIRGenFunction &cgf, Address ret, const CXXRecordDecl *unadjustedClass,
2916 const ReturnAdjustment &ra) {
2917 return performTypeAdjustment(cgf, ret, unadjustedClass, ra.NonVirtual,
2919 /*isReturnAdjustment=*/true);
2920}
2921
2922bool CIRGenItaniumCXXABI::isZeroInitializable(const MemberPointerType *mpt) {
2923 return mpt->isMemberFunctionPointer();
2924}
static void emit(Program &P, llvm::SmallVectorImpl< std::byte > &Code, const T &Val, bool &Success)
Helper to write bytecode and bail out if 32-bit offsets become invalid.
static void emitConstructorDestructorAlias(CIRGenModule &cgm, GlobalDecl aliasDecl, GlobalDecl targetDecl)
static CharUnits computeOffsetHint(ASTContext &astContext, const CXXRecordDecl *src, const CXXRecordDecl *dst)
static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc, mlir::Value exceptionPtr={}, mlir::FlatSymbolRefAttr typeInfo={}, mlir::FlatSymbolRefAttr dtor={})
static mlir::Value callBeginCatch(CIRGenFunction &cgf, mlir::Value ehToken, mlir::Type exnPtrTy, bool endMightThrow)
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 void initCatchParam(CIRGenFunction &cgf, mlir::Value ehToken, const VarDecl &catchParam, Address paramAddr, SourceLocation loc)
A "special initializer" callback for initializing a catch parameter during catch initialization.
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)
static unsigned extractPBaseFlags(ASTContext &Ctx, QualType &Type)
Compute the flags for a __pbase_type_info, and remove the corresponding pieces from Type.
Defines the clang::Expr interface and subclasses for C++ expressions.
static QualType getPointeeType(const MemRegion *R)
C Language Family Type Representation.
__device__ __2f16 b
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)
static OpBuilder::InsertPoint getBestAllocaInsertPoint(mlir::Block *block)
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
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:226
CharUnits getTypeAlignInChars(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in characters.
CanQualType LongTy
static CanQualType getCanonicalType(QualType T)
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
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:798
const LangOptions & getLangOpts() const
Definition ASTContext.h:952
QualType getFunctionTypeWithExceptionSpec(QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) const
Get a function type and produce the equivalent function type with the specified exception specificati...
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:917
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.
Kind getKind() const
Definition TypeBase.h:3262
mlir::Value getPointer() const
Definition Address.h:96
mlir::Type getElementType() const
Definition Address.h:123
clang::CharUnits getAlignment() const
Definition Address.h:136
mlir::Type getType() const
Definition Address.h:115
mlir::Value emitRawPointer() const
Return the pointer contained in this class after authenticating it and adding offset to it if necessa...
Definition Address.h:110
cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr)
cir::ConstantOp getSInt64(uint64_t c, mlir::Location loc)
cir::PointerType getUInt8PtrTy()
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)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
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)
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false)
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)
static cir::TypeEvaluationKind getEvaluationKind(clang::QualType type)
Return the cir::TypeEvaluationKind of QualType type.
clang::GlobalDecl curGD
The GlobalDecl for the current function being compiled or the global variable currently being initial...
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d, mlir::OpBuilder::InsertPoint ip={})
cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc, const Twine &name="tmp", mlir::Value arraySize=nullptr, bool insertIntoFnEntryBlock=false)
This creates an alloca and inserts it into the entry block if ArraySize is nullptr,...
const clang::Decl * curFuncDecl
Address getAddrOfLocalVar(const clang::VarDecl *vd)
Return the address of a local variable.
void emitAnyExprToExn(const Expr *e, Address addr)
void emitAggregateCopy(LValue dest, LValue src, QualType eltTy, AggValueSlot::Overlap_t mayOverlap, bool isVolatile=false)
Emit an aggregate copy.
LValue makeNaturalAlignAddrLValue(mlir::Value val, QualType ty)
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.
EHScopeStack ehStack
Tracks function scope overall cleanup handling.
mlir::Type convertTypeForMem(QualType t)
mlir::Value emitLoadOfComplex(LValue src, SourceLocation loc)
Load a complex number from the specified l-value.
void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile, clang::QualType ty, LValueBaseInfo baseInfo, bool isInit=false, bool isNontemporal=false)
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.
void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, bool isInit)
EmitStoreOfComplex - Store a complex number into the specified l-value.
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={})
mlir::Value emitLoadOfScalar(LValue lvalue, SourceLocation loc)
EmitLoadOfScalar - Load a scalar value from an address, taking care to appropriately convert from the...
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
void emitCXXDestructorCall(const CXXDestructorDecl *dd, CXXDtorType type, bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy)
std::optional< mlir::Location > currSrcLoc
Use to track source locations across nested visitor traversals.
clang::ASTContext & getContext() const
void emitAutoVarCleanups(const AutoVarEmission &emission)
This class organizes the cross-function state that is used while generating CIR code.
static cir::GlobalOp createGlobalOp(CIRGenModule &cgm, mlir::Location loc, llvm::StringRef name, mlir::Type t, bool isConstant=false, mlir::ptr::MemorySpaceAttrInterface addrSpace={}, mlir::Operation *insertPoint=nullptr)
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.
clang::CharUnits getClassPointerAlignment(const clang::CXXRecordDecl *rd)
Return the best known alignment for an unknown pointer to a particular class.
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)
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)
const cir::CIRDataLayout getDataLayout() const
static void setInitializer(cir::GlobalOp &op, mlir::Attribute value)
cir::GlobalLinkageKind getFunctionLinkage(GlobalDecl gd)
const clang::CodeGenOptions & getCodeGenOpts() const
const clang::LangOptions & getLangOpts() const
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::ModuleOp getModule() const
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...
bool isVirtual() const
Determines whether the base class is a virtual base class (or not).
Definition DeclCXX.h:203
QualType getType() const
Retrieves the type of the base class.
Definition DeclCXX.h:249
AccessSpecifier getAccessSpecifier() const
Returns the access specifier for this base specifier.
Definition DeclCXX.h:230
SourceLocation getBeginLoc() const LLVM_READONLY
Definition StmtCXX.h:43
VarDecl * getExceptionDecl() const
Definition StmtCXX.h:49
bool isGlobalDelete() const
Definition ExprCXX.h:2655
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2136
bool isVirtual() const
Definition DeclCXX.h:2191
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2275
CXXMethodDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition DeclCXX.h:2245
SourceRange getSourceRange() const
Definition ExprCXX.h:2614
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:2343
base_class_range bases()
Definition DeclCXX.h:608
unsigned getNumBases() const
Retrieves the number of base classes of this class.
Definition DeclCXX.h:602
base_class_iterator bases_begin()
Definition DeclCXX.h:615
const CXXBaseSpecifier * base_class_const_iterator
Iterator that traverses the base classes of a class.
Definition DeclCXX.h:520
base_class_range vbases()
Definition DeclCXX.h:625
bool isAbstract() const
Determine whether this class has a pure virtual function.
Definition DeclCXX.h:1221
bool isDynamicClass() const
Definition DeclCXX.h:574
bool hasDefinition() const
Definition DeclCXX.h:561
unsigned getNumVBases() const
Retrieves the number of virtual base classes of this class.
Definition DeclCXX.h:623
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
const Expr * getSubExpr() const
Definition ExprCXX.h:1232
static CanQual< Type > CreateUnsafe(QualType Other)
Qualifiers getQualifiers() const
Retrieve all qualifiers.
CharUnits - 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:207
bool isZero() const
isZero - Test whether the quantity equals zero.
Definition CharUnits.h:122
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
static CharUnits One()
One - Construct a CharUnits quantity of one.
Definition CharUnits.h:58
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition CharUnits.h:53
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2122
bool isTranslationUnit() const
Definition DeclBase.h:2198
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.
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
bool isInlined() const
Determine whether this function should be inlined, because it is either marked "inline" or "constexpr...
Definition Decl.h:2936
FunctionDecl * getDefinition()
Get the definition for this declaration.
Definition Decl.h:2297
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:3248
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:57
GlobalDecl getWithCtorType(CXXCtorType Type)
Definition GlobalDecl.h:178
CXXCtorType getCtorType() const
Definition GlobalDecl.h:108
GlobalDecl getWithDtorType(CXXDtorType Type)
Definition GlobalDecl.h:185
CXXDtorType getDtorType() const
Definition GlobalDecl.h:113
const Decl * getDecl() const
Definition GlobalDecl.h:106
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, IdentifierInfo *Id, QualType T, ImplicitParamKind ParamKind)
Create implicit parameter.
Definition Decl.cpp:5604
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:5535
QualType getPointeeType() const
Definition TypeBase.h:3721
bool isMemberFunctionPointer() const
Returns true if the member type (i.e.
Definition TypeBase.h:3725
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:295
Visibility getVisibility() const
Determines the visibility of this entity.
Definition Decl.h:444
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3378
QualType getPointeeType() const
Definition TypeBase.h:3388
A (possibly-)qualified type.
Definition TypeBase.h:937
bool isVolatileQualified() const
Determine whether this type is volatile-qualified.
Definition TypeBase.h:8515
bool isRestrictQualified() const
Determine whether this type is restrict-qualified.
Definition TypeBase.h:8509
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8471
QualType getCanonicalType() const
Definition TypeBase.h:8483
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8525
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition TypeBase.h:8504
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
Definition TypeBase.h:361
@ OCL_ExplicitNone
This object can be modified without requiring retains or releases.
Definition TypeBase.h:354
@ OCL_None
There is no lifetime qualification on this type.
Definition TypeBase.h:350
@ OCL_Weak
Reading or writing from this object requires a barrier call.
Definition TypeBase.h:364
@ OCL_Autoreleasing
Assigning into this object requires a lifetime extension.
Definition TypeBase.h:367
ObjCLifetime getObjCLifetime() const
Definition TypeBase.h:545
bool empty() const
Definition TypeBase.h:647
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:4895
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:490
virtual bool hasPS4DLLImportExport() const
uint64_t getPointerAlign(LangAS AddrSpace) const
Definition TargetInfo.h:494
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:536
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h:3562
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
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:754
Visibility getVisibility() const
Determine the visibility of this type.
Definition TypeBase.h:3115
Linkage getLinkage() const
Determine the linkage of this type.
Definition Type.cpp:4974
TypeClass getTypeClass() const
Definition TypeBase.h:2433
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9261
bool isRecordType() const
Definition TypeBase.h:8795
AddressPointLocation getAddressPoint(BaseSubobject Base) const
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:926
TLSKind getTLSKind() const
Definition Decl.cpp:2181
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2203
bool isNoDestroy(const ASTContext &) const
Is destruction of this variable entirely suppressed?
Definition Decl.cpp:2849
const Expr * getInit() const
Definition Decl.h:1383
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.
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 Variable var(Literal L)
Returns the variable of L.
Definition CNFFormula.h:64
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition PrimType.h:201
@ 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...
The JSON file list parser is used to communicate input to InstallAPI.
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:125
@ 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
@ Type
The name was classified as a type.
Definition Sema.h:564
U cast(CodeGen::Address addr)
Definition Address.h:327
@ EST_None
no exception specification
@ 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