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