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