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