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