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