clang 24.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#define SPIRV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
742#include "clang/Basic/SPIRVTypes.def"
743 case BuiltinType::ShortAccum:
744 case BuiltinType::Accum:
745 case BuiltinType::LongAccum:
746 case BuiltinType::UShortAccum:
747 case BuiltinType::UAccum:
748 case BuiltinType::ULongAccum:
749 case BuiltinType::ShortFract:
750 case BuiltinType::Fract:
751 case BuiltinType::LongFract:
752 case BuiltinType::UShortFract:
753 case BuiltinType::UFract:
754 case BuiltinType::ULongFract:
755 case BuiltinType::SatShortAccum:
756 case BuiltinType::SatAccum:
757 case BuiltinType::SatLongAccum:
758 case BuiltinType::SatUShortAccum:
759 case BuiltinType::SatUAccum:
760 case BuiltinType::SatULongAccum:
761 case BuiltinType::SatShortFract:
762 case BuiltinType::SatFract:
763 case BuiltinType::SatLongFract:
764 case BuiltinType::SatUShortFract:
765 case BuiltinType::SatUFract:
766 case BuiltinType::SatULongFract:
767 case BuiltinType::BFloat16:
768 return false;
769
770 case BuiltinType::Dependent:
771#define BUILTIN_TYPE(Id, SingletonId)
772#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
773#include "clang/AST/BuiltinTypes.def"
774 llvm_unreachable("asking for RRTI for a placeholder type!");
775
776 case BuiltinType::ObjCId:
777 case BuiltinType::ObjCClass:
778 case BuiltinType::ObjCSel:
779 llvm_unreachable("FIXME: Objective-C types are unsupported!");
780 }
781
782 llvm_unreachable("Invalid BuiltinType Kind!");
783}
784
785static bool typeInfoIsInStandardLibrary(const PointerType *pointerTy) {
786 QualType pointeeTy = pointerTy->getPointeeType();
787 const auto *builtinTy = dyn_cast<BuiltinType>(pointeeTy);
788 if (!builtinTy)
789 return false;
790
791 // Check the qualifiers.
792 Qualifiers quals = pointeeTy.getQualifiers();
793 quals.removeConst();
794
795 if (!quals.empty())
796 return false;
797
798 return typeInfoIsInStandardLibrary(builtinTy);
799}
800
801/// IsStandardLibraryRTTIDescriptor - Returns whether the type
802/// information for the given type exists in the standard library.
803static bool isStandardLibraryRttiDescriptor(QualType ty) {
804 // Type info for builtin types is defined in the standard library.
805 if (const auto *builtinTy = dyn_cast<BuiltinType>(ty))
806 return typeInfoIsInStandardLibrary(builtinTy);
807
808 // Type info for some pointer types to builtin types is defined in the
809 // standard library.
810 if (const auto *pointerTy = dyn_cast<PointerType>(ty))
811 return typeInfoIsInStandardLibrary(pointerTy);
812
813 return false;
814}
815
816/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
817/// the given type exists somewhere else, and that we should not emit the type
818/// information in this translation unit. Assumes that it is not a
819/// standard-library type.
820static bool shouldUseExternalRttiDescriptor(CIRGenModule &cgm, QualType ty) {
821 ASTContext &context = cgm.getASTContext();
822
823 // If RTTI is disabled, assume it might be disabled in the
824 // translation unit that defines any potential key function, too.
825 if (!context.getLangOpts().RTTI)
826 return false;
827
828 if (const auto *recordTy = dyn_cast<RecordType>(ty)) {
829 const auto *rd =
830 cast<CXXRecordDecl>(recordTy->getDecl())->getDefinitionOrSelf();
831 if (!rd->hasDefinition())
832 return false;
833
834 if (!rd->isDynamicClass())
835 return false;
836
837 // FIXME: this may need to be reconsidered if the key function
838 // changes.
839 // N.B. We must always emit the RTTI data ourselves if there exists a key
840 // function.
841 bool isDLLImport = rd->hasAttr<DLLImportAttr>();
842
843 // Don't import the RTTI but emit it locally.
844 if (cgm.getTriple().isOSCygMing())
845 return false;
846
847 if (cgm.getVTables().isVTableExternal(rd)) {
849 return true;
850
851 return !isDLLImport || cgm.getTriple().isWindowsItaniumEnvironment();
852 }
853
854 if (isDLLImport)
855 return true;
856 }
857
858 return false;
859}
860
861/// Contains virtual and non-virtual bases seen when traversing a class
862/// hierarchy.
863struct SeenBases {
864 llvm::SmallPtrSet<const CXXRecordDecl *, 16> nonVirtualBases;
865 llvm::SmallPtrSet<const CXXRecordDecl *, 16> virtualBases;
866};
867
868/// Compute the value of the flags member in abi::__vmi_class_type_info.
869///
870static unsigned computeVmiClassTypeInfoFlags(const CXXBaseSpecifier *base,
871 SeenBases &bases) {
872
873 unsigned flags = 0;
874 auto *baseDecl = base->getType()->castAsCXXRecordDecl();
875
876 if (base->isVirtual()) {
877 // Mark the virtual base as seen.
878 if (!bases.virtualBases.insert(baseDecl).second) {
879 // If this virtual base has been seen before, then the class is diamond
880 // shaped.
881 flags |= VMI_DiamondShaped;
882 } else {
883 if (bases.nonVirtualBases.count(baseDecl))
884 flags |= VMI_NonDiamondRepeat;
885 }
886 } else {
887 // Mark the non-virtual base as seen.
888 if (!bases.nonVirtualBases.insert(baseDecl).second) {
889 // If this non-virtual base has been seen before, then the class has non-
890 // diamond shaped repeated inheritance.
891 flags |= VMI_NonDiamondRepeat;
892 } else {
893 if (bases.virtualBases.count(baseDecl))
894 flags |= VMI_NonDiamondRepeat;
895 }
896 }
897
898 // Walk all bases.
899 for (const auto &bs : baseDecl->bases())
900 flags |= computeVmiClassTypeInfoFlags(&bs, bases);
901
902 return flags;
903}
904
905static unsigned computeVmiClassTypeInfoFlags(const CXXRecordDecl *rd) {
906 unsigned flags = 0;
907 SeenBases bases;
908
909 // Walk all bases.
910 for (const auto &bs : rd->bases())
911 flags |= computeVmiClassTypeInfoFlags(&bs, bases);
912
913 return flags;
914}
915
916// Return whether the given record decl has a "single,
917// public, non-virtual base at offset zero (i.e. the derived class is dynamic
918// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
919// TODO(cir): this can unified with LLVM codegen
920static bool canUseSingleInheritance(const CXXRecordDecl *rd) {
921 // Check the number of bases.
922 if (rd->getNumBases() != 1)
923 return false;
924
925 // Get the base.
927
928 // Check that the base is not virtual.
929 if (base->isVirtual())
930 return false;
931
932 // Check that the base is public.
933 if (base->getAccessSpecifier() != AS_public)
934 return false;
935
936 // Check that the class is dynamic iff the base is.
937 auto *baseDecl = base->getType()->castAsCXXRecordDecl();
938 return baseDecl->isEmpty() ||
939 baseDecl->isDynamicClass() == rd->isDynamicClass();
940}
941
942/// IsIncompleteClassType - Returns whether the given record type is incomplete.
943static bool isIncompleteClassType(const RecordType *recordTy) {
944 return !recordTy->getDecl()->getDefinitionOrSelf()->isCompleteDefinition();
945}
946
947/// Returns whether the given type contains an
948/// incomplete class type. This is true if
949///
950/// * The given type is an incomplete class type.
951/// * The given type is a pointer type whose pointee type contains an
952/// incomplete class type.
953/// * The given type is a member pointer type whose class is an incomplete
954/// class type.
955/// * The given type is a member pointer type whoise pointee type contains an
956/// incomplete class type.
957/// is an indirect or direct pointer to an incomplete class type.
958static bool containsIncompleteClassType(QualType ty) {
959 if (const auto *recordTy = dyn_cast<RecordType>(ty)) {
960 if (isIncompleteClassType(recordTy))
961 return true;
962 }
963
964 if (const auto *pointerTy = dyn_cast<PointerType>(ty))
965 return containsIncompleteClassType(pointerTy->getPointeeType());
966
967 if (const auto *memberPointerTy = dyn_cast<MemberPointerType>(ty)) {
968 // Check if the class type is incomplete.
969 if (!memberPointerTy->getMostRecentCXXRecordDecl()->hasDefinition())
970 return true;
971
972 return containsIncompleteClassType(memberPointerTy->getPointeeType());
973 }
974
975 return false;
976}
977
978static unsigned extractPBaseFlags(const ASTContext &ctx, QualType &ty) {
979 unsigned flags = 0;
980
981 if (ty.isConstQualified())
982 flags |= PTI_Const;
983 if (ty.isVolatileQualified())
984 flags |= PTI_Volatile;
985 if (ty.isRestrictQualified())
986 flags |= PTI_Restrict;
987
988 ty = ty.getUnqualifiedType();
989
990 if (containsIncompleteClassType(ty))
991 flags |= PTI_Incomplete;
992
993 if (const auto *proto = ty->getAs<FunctionProtoType>()) {
994 if (proto->isNothrow()) {
995 flags |= PTI_Noexcept;
997 }
998 }
999
1000 return flags;
1001}
1002
1003const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) {
1004 // abi::__class_type_info.
1005 static const char *const classTypeInfo =
1006 "_ZTVN10__cxxabiv117__class_type_infoE";
1007 // abi::__si_class_type_info.
1008 static const char *const siClassTypeInfo =
1009 "_ZTVN10__cxxabiv120__si_class_type_infoE";
1010 // abi::__vmi_class_type_info.
1011 static const char *const vmiClassTypeInfo =
1012 "_ZTVN10__cxxabiv121__vmi_class_type_infoE";
1013
1014 switch (ty->getTypeClass()) {
1015#define TYPE(Class, Base)
1016#define ABSTRACT_TYPE(Class, Base)
1017#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
1018#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
1019#define DEPENDENT_TYPE(Class, Base) case Type::Class:
1020#include "clang/AST/TypeNodes.inc"
1021 llvm_unreachable("Non-canonical and dependent types shouldn't get here");
1022
1023 case Type::LValueReference:
1024 case Type::RValueReference:
1025 llvm_unreachable("References shouldn't get here");
1026
1027 case Type::Auto:
1028 case Type::DeducedTemplateSpecialization:
1029 llvm_unreachable("Undeduced type shouldn't get here");
1030
1031 case Type::Pipe:
1032 llvm_unreachable("Pipe types shouldn't get here");
1033
1034 case Type::ArrayParameter:
1035 llvm_unreachable("Array Parameter types should not get here.");
1036
1037 case Type::Builtin:
1038 case Type::BitInt:
1039 case Type::OverflowBehavior:
1040 // GCC treats vector and complex types as fundamental types.
1041 case Type::Vector:
1042 case Type::ExtVector:
1043 case Type::ConstantMatrix:
1044 case Type::Complex:
1045 case Type::Atomic:
1046 // FIXME: GCC treats block pointers as fundamental types?!
1047 case Type::BlockPointer:
1048 return "_ZTVN10__cxxabiv123__fundamental_type_infoE";
1049 case Type::ConstantArray:
1050 case Type::IncompleteArray:
1051 case Type::VariableArray:
1052 // abi::__array_type_info.
1053 return "_ZTVN10__cxxabiv117__array_type_infoE";
1054
1055 case Type::FunctionNoProto:
1056 case Type::FunctionProto:
1057 // abi::__function_type_info.
1058 return "_ZTVN10__cxxabiv120__function_type_infoE";
1059
1060 case Type::Enum:
1061 return "_ZTVN10__cxxabiv116__enum_type_infoE";
1062
1063 case Type::Record: {
1064 const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl())
1065 ->getDefinitionOrSelf();
1066
1067 if (!rd->hasDefinition() || !rd->getNumBases()) {
1068 return classTypeInfo;
1069 }
1070
1071 if (canUseSingleInheritance(rd)) {
1072 return siClassTypeInfo;
1073 }
1074
1075 return vmiClassTypeInfo;
1076 }
1077
1078 case Type::ObjCObject:
1079 cgm.errorNYI("VTableClassNameForType: ObjCObject");
1080 break;
1081
1082 case Type::ObjCInterface:
1083 cgm.errorNYI("VTableClassNameForType: ObjCInterface");
1084 break;
1085
1086 case Type::ObjCObjectPointer:
1087 case Type::Pointer:
1088 // abi::__pointer_type_info.
1089 return "_ZTVN10__cxxabiv119__pointer_type_infoE";
1090
1091 case Type::MemberPointer:
1092 // abi::__pointer_to_member_type_info.
1093 return "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
1094
1095 case Type::HLSLAttributedResource:
1096 case Type::HLSLInlineSpirv:
1097 llvm_unreachable("HLSL doesn't support virtual functions");
1098 }
1099
1100 return nullptr;
1101}
1102} // namespace
1103
1104/// Return the linkage that the type info and type info name constants
1105/// should have for the given type.
1106static cir::GlobalLinkageKind getTypeInfoLinkage(CIRGenModule &cgm,
1107 QualType ty) {
1108 // In addition, it and all of the intermediate abi::__pointer_type_info
1109 // structs in the chain down to the abi::__class_type_info for the
1110 // incomplete class type must be prevented from resolving to the
1111 // corresponding type_info structs for the complete class type, possibly
1112 // by making them local static objects. Finally, a dummy class RTTI is
1113 // generated for the incomplete type that will not resolve to the final
1114 // complete class RTTI (because the latter need not exist), possibly by
1115 // making it a local static object.
1116 if (containsIncompleteClassType(ty))
1117 return cir::GlobalLinkageKind::InternalLinkage;
1118
1119 switch (ty->getLinkage()) {
1120 case Linkage::Invalid:
1121 llvm_unreachable("Linkage hasn't been computed!");
1122
1123 case Linkage::None:
1124 case Linkage::Internal:
1126 return cir::GlobalLinkageKind::InternalLinkage;
1127
1129 case Linkage::Module:
1130 case Linkage::External:
1131 // RTTI is not enabled, which means that this type info struct is going
1132 // to be used for exception handling. Give it linkonce_odr linkage.
1133 if (!cgm.getLangOpts().RTTI)
1134 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
1135
1136 if (const RecordType *record = dyn_cast<RecordType>(ty)) {
1137 const auto *rd =
1138 cast<CXXRecordDecl>(record->getDecl())->getDefinitionOrSelf();
1139 if (rd->hasAttr<WeakAttr>())
1140 return cir::GlobalLinkageKind::WeakODRLinkage;
1141
1142 if (cgm.getTriple().isWindowsItaniumEnvironment())
1143 if (rd->hasAttr<DLLImportAttr>() &&
1144 shouldUseExternalRttiDescriptor(cgm, ty))
1145 return cir::GlobalLinkageKind::ExternalLinkage;
1146
1147 // MinGW always uses LinkOnceODRLinkage for type info.
1148 if (rd->isDynamicClass() && !cgm.getASTContext()
1149 .getTargetInfo()
1150 .getTriple()
1151 .isWindowsGNUEnvironment())
1152 return cgm.getVTableLinkage(rd);
1153 }
1154
1155 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
1156 }
1157
1158 llvm_unreachable("Invalid linkage!");
1159}
1160
1161cir::GlobalOp
1162CIRGenItaniumRTTIBuilder::getAddrOfTypeName(mlir::Location loc, QualType ty,
1163 cir::GlobalLinkageKind linkage) {
1164 CIRGenBuilderTy &builder = cgm.getBuilder();
1165 SmallString<256> name;
1166 llvm::raw_svector_ostream out(name);
1168
1169 // We know that the mangled name of the type starts at index 4 of the
1170 // mangled name of the typename, so we can just index into it in order to
1171 // get the mangled name of the type.
1172 mlir::Attribute init = builder.getString(
1173 name.substr(4), cgm.convertType(cgm.getASTContext().CharTy),
1174 std::nullopt);
1175
1176 CharUnits align =
1178
1179 // builder.getString can return a #cir.zero if the string given to it only
1180 // contains null bytes. However, type names cannot be full of null bytes.
1181 // So cast Init to a ConstArrayAttr should be safe.
1182 auto initStr = cast<cir::ConstArrayAttr>(init);
1183
1184 cir::GlobalOp gv = cgm.createOrReplaceCXXRuntimeVariable(
1185 loc, name, initStr.getType(), linkage, align);
1187 return gv;
1188}
1189
1190mlir::Attribute
1191CIRGenItaniumRTTIBuilder::getAddrOfExternalRTTIDescriptor(mlir::Location loc,
1192 QualType ty) {
1193 // Mangle the RTTI name.
1194 SmallString<256> name;
1195 llvm::raw_svector_ostream out(name);
1197 CIRGenBuilderTy &builder = cgm.getBuilder();
1198
1199 // Look for an existing global.
1200 cir::GlobalOp gv = dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue(name));
1201
1202 if (!gv) {
1203 // Create a new global variable.
1204 // From LLVM codegen => Note for the future: If we would ever like to do
1205 // deferred emission of RTTI, check if emitting vtables opportunistically
1206 // need any adjustment.
1207 gv = cgm.createGlobalOp(loc, name, builder.getUInt8PtrTy(),
1208 /*isConstant=*/true);
1209 const CXXRecordDecl *rd = ty->getAsCXXRecordDecl();
1210 cgm.setGVProperties(gv, rd);
1211
1212 // Import the typeinfo symbol when all non-inline virtual methods are
1213 // imported.
1214 if (cgm.getTarget().hasPS4DLLImportExport()) {
1215 cgm.errorNYI("getAddrOfExternalRTTIDescriptor: hasPS4DLLImportExport");
1216 }
1217 }
1218
1219 return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv);
1220}
1221
1222void CIRGenItaniumRTTIBuilder::buildVTablePointer(mlir::Location loc,
1223 const Type *ty) {
1224 CIRGenBuilderTy &builder = cgm.getBuilder();
1225 const char *vTableName = vTableClassNameForType(cgm, ty);
1226
1227 // Check if the alias exists. If it doesn't, then get or create the global.
1228 if (cgm.getLangOpts().RelativeCXXABIVTables) {
1229 cgm.errorNYI("buildVTablePointer: isRelativeLayout");
1230 return;
1231 }
1232
1233 mlir::Type vtableGlobalTy = builder.getPointerTo(builder.getUInt8PtrTy());
1234 llvm::Align align = cgm.getDataLayout().getABITypeAlign(vtableGlobalTy);
1235 cir::GlobalOp vTable = cgm.createOrReplaceCXXRuntimeVariable(
1236 loc, vTableName, vtableGlobalTy, cir::GlobalLinkageKind::ExternalLinkage,
1238 // Note: createOrReplaceCXXRuntimeVariable isn't exactly what classic-codegen
1239 // does here: it just does a getOrInsertGlobal at the module level. However,
1240 // the above function does MOST of what we want, except it sets the global as
1241 // constant, when we don't want that. So set it here instead.
1242 vTable.setConstant(false);
1243
1244 // The vtable address point is 2.
1245 mlir::Attribute field{};
1246 if (cgm.getLangOpts().RelativeCXXABIVTables) {
1247 cgm.errorNYI("buildVTablePointer: isRelativeLayout");
1248 } else {
1249 SmallVector<mlir::Attribute, 4> offsets{
1250 cgm.getBuilder().getI32IntegerAttr(2)};
1251 auto indices = mlir::ArrayAttr::get(builder.getContext(), offsets);
1253 vTable, indices);
1254 }
1255
1256 assert(field && "expected attribute");
1257 fields.push_back(field);
1258}
1259
1260/// Build an abi::__si_class_type_info, used for single inheritance, according
1261/// to the Itanium C++ ABI, 2.95p6b.
1262void CIRGenItaniumRTTIBuilder::buildSIClassTypeInfo(mlir::Location loc,
1263 const CXXRecordDecl *rd) {
1264 // Itanium C++ ABI 2.9.5p6b:
1265 // It adds to abi::__class_type_info a single member pointing to the
1266 // type_info structure for the base type,
1267 mlir::Attribute baseTypeInfo =
1268 CIRGenItaniumRTTIBuilder(cxxABI, cgm)
1269 .buildTypeInfo(loc, rd->bases_begin()->getType());
1270 fields.push_back(baseTypeInfo);
1271}
1272
1273/// Build an abi::__vmi_class_type_info, used for
1274/// classes with bases that do not satisfy the abi::__si_class_type_info
1275/// constraints, according to the Itanium C++ ABI, 2.9.5p5c.
1276void CIRGenItaniumRTTIBuilder::buildVMIClassTypeInfo(mlir::Location loc,
1277 const CXXRecordDecl *rd) {
1278 mlir::Type unsignedIntLTy =
1280
1281 // Itanium C++ ABI 2.9.5p6c:
1282 // __flags is a word with flags describing details about the class
1283 // structure, which may be referenced by using the __flags_masks
1284 // enumeration. These flags refer to both direct and indirect bases.
1285 unsigned flags = computeVmiClassTypeInfoFlags(rd);
1286 fields.push_back(cir::IntAttr::get(unsignedIntLTy, flags));
1287
1288 // Itanium C++ ABI 2.9.5p6c:
1289 // __base_count is a word with the number of direct proper base class
1290 // descriptions that follow.
1291 fields.push_back(cir::IntAttr::get(unsignedIntLTy, rd->getNumBases()));
1292
1293 if (!rd->getNumBases())
1294 return;
1295
1296 // Now add the base class descriptions.
1297
1298 // Itanium C++ ABI 2.9.5p6c:
1299 // __base_info[] is an array of base class descriptions -- one for every
1300 // direct proper base. Each description is of the type:
1301 //
1302 // struct abi::__base_class_type_info {
1303 // public:
1304 // const __class_type_info *__base_type;
1305 // long __offset_flags;
1306 //
1307 // enum __offset_flags_masks {
1308 // __virtual_mask = 0x1,
1309 // __public_mask = 0x2,
1310 // __offset_shift = 8
1311 // };
1312 // };
1313
1314 // If we're in mingw and 'long' isn't wide enough for a pointer, use 'long
1315 // long' instead of 'long' for __offset_flags. libstdc++abi uses long long on
1316 // LLP64 platforms.
1317 // FIXME: Consider updating libc++abi to match, and extend this logic to all
1318 // LLP64 platforms.
1319 QualType offsetFlagsTy = cgm.getASTContext().LongTy;
1320 const TargetInfo &ti = cgm.getASTContext().getTargetInfo();
1321 if (ti.getTriple().isOSCygMing() &&
1322 ti.getPointerWidth(LangAS::Default) > ti.getLongWidth())
1323 offsetFlagsTy = cgm.getASTContext().LongLongTy;
1324 mlir::Type offsetFlagsLTy = cgm.convertType(offsetFlagsTy);
1325
1326 for (const CXXBaseSpecifier &base : rd->bases()) {
1327 // The __base_type member points to the RTTI for the base type.
1328 fields.push_back(CIRGenItaniumRTTIBuilder(cxxABI, cgm)
1329 .buildTypeInfo(loc, base.getType()));
1330
1331 CXXRecordDecl *baseDecl = base.getType()->castAsCXXRecordDecl();
1332 int64_t offsetFlags = 0;
1333
1334 // All but the lower 8 bits of __offset_flags are a signed offset.
1335 // For a non-virtual base, this is the offset in the object of the base
1336 // subobject. For a virtual base, this is the offset in the virtual table of
1337 // the virtual base offset for the virtual base referenced (negative).
1338 CharUnits offset;
1339 if (base.isVirtual())
1341 rd, baseDecl);
1342 else {
1343 const ASTRecordLayout &layout =
1345 offset = layout.getBaseClassOffset(baseDecl);
1346 }
1347 offsetFlags = uint64_t(offset.getQuantity()) << 8;
1348
1349 // The low-order byte of __offset_flags contains flags, as given by the
1350 // masks from the enumeration __offset_flags_masks.
1351 if (base.isVirtual())
1352 offsetFlags |= BCTI_Virtual;
1353 if (base.getAccessSpecifier() == AS_public)
1354 offsetFlags |= BCTI_Public;
1355
1356 fields.push_back(cir::IntAttr::get(offsetFlagsLTy, offsetFlags));
1357 }
1358}
1359
1360void CIRGenItaniumRTTIBuilder::buildPointerTypeInfo(mlir::Location loc,
1361 QualType ty) {
1362 // Itanium C++ ABI 2.9.4p7:
1363 // abi::__pbase_type_info is a base for both pointer types and
1364 // pointer-to-member types. It adds two data members:
1365 //
1366 // class __pbase_type_info : public std::type_info {
1367 // public:
1368 // unsigned int __flags;
1369 // const std::type_info *__pointee;
1370 //
1371 // enum __masks {
1372 // __const_mask = 0x1,
1373 // __volatile_mask = 0x2,
1374 // __restrict_mask = 0x4,
1375 // __incomplete_mask = 0x8,
1376 // __incomplete_class_mask = 0x10,
1377 // __transaction_safe_mask = 0x20
1378 // __noexcept_mask = 0x40
1379 // };
1380 // };
1381 const unsigned int flags = extractPBaseFlags(cgm.getASTContext(), ty);
1382
1383 mlir::Type unsignedIntTy = cgm.convertType(cgm.getASTContext().UnsignedIntTy);
1384 mlir::Attribute flagsAttr = cir::IntAttr::get(unsignedIntTy, flags);
1385 fields.push_back(flagsAttr);
1386
1387 mlir::Attribute pointeeTypeInfo =
1388 CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, ty);
1389 fields.push_back(pointeeTypeInfo);
1390}
1391
1392void CIRGenItaniumRTTIBuilder::buildPointerToMemberTypeInfo(
1393 mlir::Location loc, const MemberPointerType *ty) {
1394
1395 // The abi::__pointer_to_member_type_info type adds one field to
1396 // abi::__pbase_type_info:
1397 //
1398 // class __pointer_to_member_type_info : public __pbase_type_info {
1399 // public:
1400 // const abi::__class_type_info *__context;
1401 // };
1402 QualType pointeeTy = ty->getPointeeType();
1403
1404 unsigned flags = extractPBaseFlags(cgm.getASTContext(), pointeeTy);
1405
1406 const auto *rd = ty->getMostRecentCXXRecordDecl();
1407 if (!rd->hasDefinition())
1408 flags |= PTI_ContainingClassIncomplete;
1409
1410 mlir::Type unsignedIntTy = cgm.convertType(cgm.getASTContext().UnsignedIntTy);
1411 mlir::Attribute flagsAttr = cir::IntAttr::get(unsignedIntTy, flags);
1412 fields.push_back(flagsAttr);
1413
1414 mlir::Attribute pointeeTypeInfo =
1415 CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, pointeeTy);
1416 fields.push_back(pointeeTypeInfo);
1417
1418 CanQualType contextTy = cgm.getASTContext().getCanonicalTagType(rd);
1419 mlir::Attribute classTypeInfo =
1420 CIRGenItaniumRTTIBuilder(cxxABI, cgm).buildTypeInfo(loc, contextTy);
1421 fields.push_back(classTypeInfo);
1422}
1423
1424mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(mlir::Location loc,
1425 QualType ty) {
1426 // We want to operate on the canonical type.
1427 ty = ty.getCanonicalType();
1428
1429 // Check if we've already emitted an RTTI descriptor for this type.
1430 SmallString<256> name;
1431 llvm::raw_svector_ostream out(name);
1433
1434 auto oldGV = dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue(name));
1435
1436 if (oldGV && !oldGV.isDeclaration()) {
1437 assert(!oldGV.hasAvailableExternallyLinkage() &&
1438 "available_externally typeinfos not yet implemented");
1440 oldGV);
1441 }
1442
1443 // Check if there is already an external RTTI descriptor for this type.
1444 if (isStandardLibraryRttiDescriptor(ty) ||
1445 shouldUseExternalRttiDescriptor(cgm, ty))
1446 return getAddrOfExternalRTTIDescriptor(loc, ty);
1447
1448 // Emit the standard library with external linkage.
1449 cir::GlobalLinkageKind linkage = getTypeInfoLinkage(cgm, ty);
1450
1451 // Give the type_info object and name the formal visibility of the
1452 // type itself.
1455
1456 mlir::SymbolTable::Visibility symVisibility;
1457 if (cir::isLocalLinkage(linkage))
1458 // If the linkage is local, only default visibility makes sense.
1459 symVisibility = mlir::SymbolTable::Visibility::Public;
1460 else if (cxxABI.classifyRTTIUniqueness(ty, linkage) ==
1461 CIRGenItaniumCXXABI::RUK_NonUniqueHidden) {
1462 cgm.errorNYI(
1463 "buildTypeInfo: classifyRTTIUniqueness == RUK_NonUniqueHidden");
1464 symVisibility = CIRGenModule::getMLIRVisibility(ty->getVisibility());
1465 } else
1466 symVisibility = CIRGenModule::getMLIRVisibility(ty->getVisibility());
1467
1468 return buildTypeInfo(loc, ty, linkage, symVisibility);
1469}
1470
1471mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo(
1472 mlir::Location loc, QualType ty, cir::GlobalLinkageKind linkage,
1473 mlir::SymbolTable::Visibility visibility) {
1474 CIRGenBuilderTy &builder = cgm.getBuilder();
1475
1477
1478 // Add the vtable pointer.
1479 buildVTablePointer(loc, cast<Type>(ty));
1480
1481 // And the name.
1482 cir::GlobalOp typeName = getAddrOfTypeName(loc, ty, linkage);
1483 mlir::Attribute typeNameField;
1484
1485 // If we're supposed to demote the visibility, be sure to set a flag
1486 // to use a string comparison for type_info comparisons.
1487 CIRGenItaniumCXXABI::RTTIUniquenessKind rttiUniqueness =
1488 cxxABI.classifyRTTIUniqueness(ty, linkage);
1489 if (rttiUniqueness != CIRGenItaniumCXXABI::RUK_Unique) {
1490 // The flag is the sign bit, which on ARM64 is defined to be clear
1491 // for global pointers. This is very ARM64-specific.
1492 cgm.errorNYI(
1493 "buildTypeInfo: rttiUniqueness != CIRGenItaniumCXXABI::RUK_Unique");
1494 } else {
1495 typeNameField =
1496 builder.getGlobalViewAttr(builder.getUInt8PtrTy(), typeName);
1497 }
1498
1499 fields.push_back(typeNameField);
1500
1501 switch (ty->getTypeClass()) {
1502#define TYPE(Class, Base)
1503#define ABSTRACT_TYPE(Class, Base)
1504#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
1505#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
1506#define DEPENDENT_TYPE(Class, Base) case Type::Class:
1507#include "clang/AST/TypeNodes.inc"
1508 llvm_unreachable("Non-canonical and dependent types shouldn't get here");
1509
1510 // GCC treats vector types as fundamental types.
1511 case Type::Builtin:
1512 case Type::Vector:
1513 case Type::ExtVector:
1514 case Type::ConstantMatrix:
1515 case Type::Complex:
1516 case Type::BlockPointer:
1517 // Itanium C++ ABI 2.9.5p4:
1518 // abi::__fundamental_type_info adds no data members to std::type_info.
1519 break;
1520
1521 case Type::LValueReference:
1522 case Type::RValueReference:
1523 llvm_unreachable("References shouldn't get here");
1524
1525 case Type::Auto:
1526 case Type::DeducedTemplateSpecialization:
1527 llvm_unreachable("Undeduced type shouldn't get here");
1528
1529 case Type::Pipe:
1530 break;
1531
1532 case Type::BitInt:
1533 break;
1534
1535 case Type::OverflowBehavior:
1536 break;
1537
1538 case Type::ConstantArray:
1539 case Type::IncompleteArray:
1540 case Type::VariableArray:
1541 case Type::ArrayParameter:
1542 // Itanium C++ ABI 2.9.5p5:
1543 // abi::__array_type_info adds no data members to std::type_info.
1544 break;
1545
1546 case Type::FunctionNoProto:
1547 case Type::FunctionProto:
1548 // Itanium C++ ABI 2.9.5p5:
1549 // abi::__function_type_info adds no data members to std::type_info.
1550 break;
1551
1552 case Type::Enum:
1553 // Itanium C++ ABI 2.9.5p5:
1554 // abi::__enum_type_info adds no data members to std::type_info.
1555 break;
1556
1557 case Type::Record: {
1558 const auto *rd = cast<CXXRecordDecl>(cast<RecordType>(ty)->getDecl())
1559 ->getDefinitionOrSelf();
1560 if (!rd->hasDefinition() || !rd->getNumBases()) {
1561 // We don't need to emit any fields.
1562 break;
1563 }
1564
1565 if (canUseSingleInheritance(rd)) {
1566 buildSIClassTypeInfo(loc, rd);
1567 } else {
1568 buildVMIClassTypeInfo(loc, rd);
1569 }
1570
1571 break;
1572 }
1573
1574 case Type::ObjCObject:
1575 case Type::ObjCInterface:
1576 cgm.errorNYI("buildTypeInfo: ObjCObject & ObjCInterface");
1577 break;
1578
1579 case Type::ObjCObjectPointer:
1580 cgm.errorNYI("buildTypeInfo: ObjCObjectPointer");
1581 break;
1582
1583 case Type::Pointer:
1584 // We need to get the type info for the pointee type.
1585 buildPointerTypeInfo(loc, cast<PointerType>(ty)->getPointeeType());
1586 break;
1587
1588 case Type::MemberPointer:
1589 buildPointerToMemberTypeInfo(loc, cast<MemberPointerType>(ty));
1590 break;
1591
1592 case Type::Atomic:
1593 // No fields, at least for the moment.
1594 break;
1595
1596 case Type::HLSLAttributedResource:
1597 case Type::HLSLInlineSpirv:
1598 llvm_unreachable("HLSL doesn't support RTTI");
1599 }
1600
1602 cir::TypeInfoAttr init = builder.getTypeInfo(builder.getArrayAttr(fields));
1603
1604 SmallString<256> name;
1605 llvm::raw_svector_ostream out(name);
1607
1608 // Create new global and search for an existing global.
1609 auto oldGV = dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue(name));
1610
1611 cir::GlobalOp gv = cgm.createGlobalOp(loc, name, init.getType(),
1612 /*isConstant=*/true);
1613 gv.setLinkage(linkage);
1614
1615 // Export the typeinfo in the same circumstances as the vtable is
1616 // exported.
1617 if (cgm.getTarget().hasPS4DLLImportExport()) {
1618 cgm.errorNYI("buildTypeInfo: target hasPS4DLLImportExport");
1619 return {};
1620 }
1621
1622 // If there's already an old global variable, replace it with the new one.
1623 if (oldGV) {
1624 // Replace occurrences of the old variable if needed.
1625 gv.setName(oldGV.getName());
1626 if (!oldGV->use_empty()) {
1627 cgm.errorNYI("buildTypeInfo: old GV !use_empty");
1628 return {};
1629 }
1630 cgm.eraseGlobalSymbol(oldGV);
1631 oldGV->erase();
1632 }
1633
1634 if (cgm.supportsCOMDAT() && cir::isWeakForLinker(linkage))
1635 gv.setComdat(true);
1636
1637 CharUnits align = cgm.getASTContext().toCharUnitsFromBits(
1638 cgm.getTarget().getPointerAlign(LangAS::Default));
1639 gv.setAlignmentAttr(cgm.getSize(align));
1640
1641 // The Itanium ABI specifies that type_info objects must be globally
1642 // unique, with one exception: if the type is an incomplete class
1643 // type or a (possibly indirect) pointer to one. That exception
1644 // affects the general case of comparing type_info objects produced
1645 // by the typeid operator, which is why the comparison operators on
1646 // std::type_info generally use the type_info name pointers instead
1647 // of the object addresses. However, the language's built-in uses
1648 // of RTTI generally require class types to be complete, even when
1649 // manipulating pointers to those class types. This allows the
1650 // implementation of dynamic_cast to rely on address equality tests,
1651 // which is much faster.
1652
1653 // All of this is to say that it's important that both the type_info
1654 // object and the type_info name be uniqued when weakly emitted.
1655
1656 mlir::SymbolTable::setSymbolVisibility(typeName, visibility);
1660
1661 mlir::SymbolTable::setSymbolVisibility(gv, visibility);
1665
1667 return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv);
1668}
1669
1670bool CIRGenItaniumCXXABI::shouldTypeidBeNullChecked(QualType srcTy) {
1671 return true;
1672}
1673
1674void CIRGenItaniumCXXABI::emitBadTypeidCall(CIRGenFunction &cgf,
1675 mlir::Location loc) {
1676 // void __cxa_bad_typeid();
1677 cir::FuncType fnTy =
1678 cgf.getBuilder().getFuncType({}, cgf.getBuilder().getVoidTy());
1679 mlir::NamedAttrList attrs;
1680 attrs.set(cir::CIRDialect::getNoReturnAttrName(),
1681 mlir::UnitAttr::get(&cgf.cgm.getMLIRContext()));
1682
1683 cgf.emitRuntimeCall(
1684 loc, cgf.cgm.createRuntimeFunction(fnTy, "__cxa_bad_typeid", attrs), {},
1685 attrs);
1686 cir::UnreachableOp::create(cgf.getBuilder(), loc);
1687}
1688
1689mlir::Value CIRGenItaniumCXXABI::emitTypeid(CIRGenFunction &cgf, QualType srcTy,
1690 Address thisPtr,
1691 mlir::Type typeInfoPtrTy) {
1692 auto *classDecl = srcTy->castAsCXXRecordDecl();
1693 mlir::Location loc = cgm.getLoc(classDecl->getSourceRange());
1694 mlir::Value vptr = cgf.getVTablePtr(loc, thisPtr, classDecl);
1695 mlir::Value vtbl;
1696
1697 // TODO(cir): In classic codegen relative layouts cause us to do a
1698 // 'load_relative' of -4 here. We probably don't want to reprensent this in
1699 // CIR at all, but we should have the NYI here since this could be
1700 // meaningful/notable for implementation of relative layout in the future.
1701 if (cgm.getLangOpts().RelativeCXXABIVTables)
1702 cgm.errorNYI("buildVTablePointer: isRelativeLayout");
1703 else
1704 vtbl = cir::VTableGetTypeInfoOp::create(
1705 cgf.getBuilder(), loc, cgf.getBuilder().getPointerTo(typeInfoPtrTy),
1706 vptr);
1707
1708 return cgf.getBuilder().createAlignedLoad(loc, typeInfoPtrTy, vtbl,
1709 cgf.getPointerAlign());
1710}
1711
1712mlir::Attribute CIRGenItaniumCXXABI::getAddrOfRTTIDescriptor(mlir::Location loc,
1713 QualType ty) {
1714 return CIRGenItaniumRTTIBuilder(*this, cgm).buildTypeInfo(loc, ty);
1715}
1716
1717/// What sort of uniqueness rules should we use for the RTTI for the
1718/// given type?
1719CIRGenItaniumCXXABI::RTTIUniquenessKind
1720CIRGenItaniumCXXABI::classifyRTTIUniqueness(
1721 QualType canTy, cir::GlobalLinkageKind linkage) const {
1722 if (shouldRTTIBeUnique())
1723 return RUK_Unique;
1724
1725 // It's only necessary for linkonce_odr or weak_odr linkage.
1726 if (linkage != cir::GlobalLinkageKind::LinkOnceODRLinkage &&
1727 linkage != cir::GlobalLinkageKind::WeakODRLinkage)
1728 return RUK_Unique;
1729
1730 // It's only necessary with default visibility.
1731 if (canTy->getVisibility() != DefaultVisibility)
1732 return RUK_Unique;
1733
1734 // If we're not required to publish this symbol, hide it.
1735 if (linkage == cir::GlobalLinkageKind::LinkOnceODRLinkage)
1736 return RUK_NonUniqueHidden;
1737
1738 // If we're required to publish this symbol, as we might be under an
1739 // explicit instantiation, leave it with default visibility but
1740 // enable string-comparisons.
1741 assert(linkage == cir::GlobalLinkageKind::WeakODRLinkage);
1742 return RUK_NonUniqueVisible;
1743}
1744
1745void CIRGenItaniumCXXABI::emitDestructorCall(
1746 CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
1747 bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy) {
1748 GlobalDecl gd(dd, type);
1749 mlir::Value vtt =
1750 getCXXDestructorImplicitParam(cgf, dd, type, forVirtualBase, delegating);
1751 ASTContext &astContext = cgm.getASTContext();
1752 QualType vttTy = astContext.getPointerType(astContext.VoidPtrTy);
1754 CIRGenCallee callee =
1756
1757 cgf.emitCXXDestructorCall(gd, callee, thisAddr.getPointer(), thisTy, vtt,
1758 vttTy, nullptr);
1759}
1760
1761void CIRGenItaniumCXXABI::registerGlobalDtor(const VarDecl *vd,
1762 cir::FuncOp dtor,
1763 mlir::Value addr) {
1764 if (vd->isNoDestroy(cgm.getASTContext()))
1765 return;
1766
1767 // HLSL doesn't support atexit.
1768 if (cgm.getLangOpts().HLSL) {
1769 cgm.errorNYI(vd->getSourceRange(), "registerGlobalDtor: HLSL");
1770 return;
1771 }
1772
1773 // The default behavior is to use atexit. This is handled in lowering
1774 // prepare. Nothing to be done for CIR here.
1775}
1776
1777mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam(
1778 CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
1779 bool forVirtualBase, bool delegating) {
1780 GlobalDecl gd(dd, type);
1781 return cgf.getVTTParameter(gd, forVirtualBase, delegating);
1782}
1783
1784// The idea here is creating a separate block for the throw with an
1785// `UnreachableOp` as the terminator. So, we branch from the current block
1786// to the throw block and create a block for the remaining operations.
1787static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc,
1788 mlir::Value exceptionPtr = {},
1789 mlir::FlatSymbolRefAttr typeInfo = {},
1790 mlir::FlatSymbolRefAttr dtor = {}) {
1791 mlir::Block *currentBlock = builder.getInsertionBlock();
1792 mlir::Region *region = currentBlock->getParent();
1793
1794 if (currentBlock->empty()) {
1795 cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
1796 cir::UnreachableOp::create(builder, loc);
1797 } else {
1798 mlir::Block *throwBlock = builder.createBlock(region);
1799
1800 cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
1801 cir::UnreachableOp::create(builder, loc);
1802
1803 builder.setInsertionPointToEnd(currentBlock);
1804 cir::BrOp::create(builder, loc, throwBlock);
1805 }
1806
1807 (void)builder.createBlock(region);
1808}
1809
1810void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) {
1811 // void __cxa_rethrow();
1812 if (isNoReturn) {
1813 CIRGenBuilderTy &builder = cgf.getBuilder();
1814 assert(cgf.currSrcLoc && "expected source location");
1815 mlir::Location loc = *cgf.currSrcLoc;
1816 insertThrowAndSplit(builder, loc);
1817 } else {
1818 cgm.errorNYI("emitRethrow with isNoReturn false");
1819 }
1820}
1821
1822void CIRGenItaniumCXXABI::emitThrow(CIRGenFunction &cgf,
1823 const CXXThrowExpr *e) {
1824 // This differs a bit from LLVM codegen, CIR has native operations for some
1825 // cxa functions, and defers allocation size computation, always pass the dtor
1826 // symbol, etc. CIRGen also does not use getAllocateExceptionFn / getThrowFn.
1827
1828 // Now allocate the exception object.
1829 CIRGenBuilderTy &builder = cgf.getBuilder();
1830 QualType clangThrowType = e->getSubExpr()->getType();
1831 cir::PointerType throwTy =
1832 builder.getPointerTo(cgf.convertType(clangThrowType));
1833 uint64_t typeSize =
1834 cgf.getContext().getTypeSizeInChars(clangThrowType).getQuantity();
1835 mlir::Location subExprLoc = cgf.getLoc(e->getSubExpr()->getSourceRange());
1836
1837 // Defer computing allocation size to some later lowering pass.
1838 mlir::TypedValue<cir::PointerType> exceptionPtr =
1839 cir::AllocExceptionOp::create(builder, subExprLoc, throwTy,
1840 builder.getI64IntegerAttr(typeSize))
1841 .getAddr();
1842
1843 // Build expression and store its result into exceptionPtr.
1844 CharUnits exnAlign = cgf.getContext().getExnObjectAlignment();
1845 cgf.emitAnyExprToExn(e->getSubExpr(), Address(exceptionPtr, exnAlign));
1846
1847 // Get the RTTI symbol address.
1848 auto typeInfo = mlir::cast<cir::GlobalViewAttr>(
1849 cgm.getAddrOfRTTIDescriptor(subExprLoc, clangThrowType,
1850 /*forEH=*/true));
1851 assert(!typeInfo.getIndices() && "expected no indirection");
1852
1853 // The address of the destructor.
1854 //
1855 // Note: LLVM codegen already optimizes out the dtor if the
1856 // type is a record with trivial dtor (by passing down a
1857 // null dtor). In CIR, we forward this info and allow for
1858 // Lowering pass to skip passing the trivial function.
1859 //
1860 const auto *cxxrd = clangThrowType->getAsCXXRecordDecl();
1861 mlir::FlatSymbolRefAttr dtor{};
1862 if (cxxrd && !cxxrd->hasTrivialDestructor()) {
1863 // __cxa_throw is declared to take its destructor as void (*)(void *). We
1864 // must match that if function pointers can be authenticated with a
1865 // discriminator based on their type.
1867 CXXDestructorDecl *dtorD = cxxrd->getDestructor();
1868 dtor = mlir::FlatSymbolRefAttr::get(
1869 cgm.getAddrOfCXXStructor(GlobalDecl(dtorD, Dtor_Complete))
1870 .getSymNameAttr());
1871 }
1872
1873 // Now throw the exception.
1874 mlir::Location loc = cgf.getLoc(e->getSourceRange());
1875 insertThrowAndSplit(builder, loc, exceptionPtr, typeInfo.getSymbol(), dtor);
1876}
1877
1879 switch (cgm.getASTContext().getCXXABIKind()) {
1880 case TargetCXXABI::GenericItanium:
1881 case TargetCXXABI::GenericAArch64:
1882 case TargetCXXABI::GenericARM:
1883 return new CIRGenItaniumCXXABI(cgm);
1884
1885 case TargetCXXABI::AppleARM64:
1886 // The general Itanium ABI will do until we implement something that
1887 // requires special handling.
1889 return new CIRGenItaniumCXXABI(cgm);
1890
1891 default:
1892 llvm_unreachable("bad or NYI ABI kind");
1893 }
1894}
1895
1896cir::GlobalOp CIRGenItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *rd,
1897 CharUnits vptrOffset) {
1898 assert(vptrOffset.isZero() && "Itanium ABI only supports zero vptr offsets");
1899 cir::GlobalOp &vtable = vtables[rd];
1900 if (vtable)
1901 return vtable;
1902
1903 // Queue up this vtable for possible deferred emission.
1904 cgm.addDeferredVTable(rd);
1905
1906 SmallString<256> name;
1907 llvm::raw_svector_ostream out(name);
1908 getMangleContext().mangleCXXVTable(rd, out);
1909
1910 const VTableLayout &vtLayout =
1912 mlir::Type vtableType = cgm.getVTables().getVTableType(vtLayout);
1913
1914 // Use pointer alignment for the vtable. Otherwise we would align them based
1915 // on the size of the initializer which doesn't make sense as only single
1916 // values are read.
1917 unsigned ptrAlign = cgm.getLangOpts().RelativeCXXABIVTables
1918 ? 32
1920
1922 cgm.getLoc(rd->getSourceRange()), name, vtableType,
1923 cir::GlobalLinkageKind::ExternalLinkage,
1924 cgm.getASTContext().toCharUnitsFromBits(ptrAlign));
1925 // LLVM codegen handles unnamedAddr
1927
1928 // In MS C++ if you have a class with virtual functions in which you are using
1929 // selective member import/export, then all virtual functions must be exported
1930 // unless they are inline, otherwise a link error will result. To match this
1931 // behavior, for such classes, we dllimport the vtable if it is defined
1932 // externally and all the non-inline virtual methods are marked dllimport, and
1933 // we dllexport the vtable if it is defined in this TU and all the non-inline
1934 // virtual methods are marked dllexport.
1935 if (cgm.getTarget().hasPS4DLLImportExport())
1936 cgm.errorNYI(rd->getSourceRange(),
1937 "getAddrOfVTable: PS4 DLL import/export");
1938
1939 cgm.setGVProperties(vtable, rd);
1940 return vtable;
1941}
1942
1943CIRGenCallee CIRGenItaniumCXXABI::getVirtualFunctionPointer(
1944 CIRGenFunction &cgf, clang::GlobalDecl gd, Address thisAddr, mlir::Type ty,
1945 SourceLocation srcLoc) {
1946 CIRGenBuilderTy &builder = cgm.getBuilder();
1947 mlir::Location loc = cgf.getLoc(srcLoc);
1948 cir::PointerType tyPtr = builder.getPointerTo(ty);
1949 auto *methodDecl = cast<CXXMethodDecl>(gd.getDecl());
1950 mlir::Value vtable = cgf.getVTablePtr(loc, thisAddr, methodDecl->getParent());
1951
1952 uint64_t vtableIndex = cgm.getItaniumVTableContext().getMethodVTableIndex(gd);
1953 mlir::Value vfunc{};
1954 if (cgf.shouldEmitVTableTypeCheckedLoad(methodDecl->getParent())) {
1955 cgm.errorNYI(loc, "getVirtualFunctionPointer: emitVTableTypeCheckedLoad");
1956 } else {
1958
1959 mlir::Value vfuncLoad;
1960 if (cgm.getLangOpts().RelativeCXXABIVTables) {
1962 cgm.errorNYI(loc, "getVirtualFunctionPointer: isRelativeLayout");
1963 } else {
1964 auto vtableSlotPtr = cir::VTableGetVirtualFnAddrOp::create(
1965 builder, loc, builder.getPointerTo(tyPtr), vtable, vtableIndex);
1966 vfuncLoad = builder.createAlignedLoad(loc, tyPtr, vtableSlotPtr,
1967 cgf.getPointerAlign());
1968 }
1969
1970 // Set invariant on the cir.load of virtual function pointer to indicate
1971 // that function didn't change inside vtable.
1972 // It's safe to add it without -fstrict-vtable-pointers, but it would not
1973 // help in devirtualization because it will only matter if we will have 2
1974 // the same virtual function loads from the same vtable load, which won't
1975 // happen without enabled devirtualization with -fstrict-vtable-pointers.
1976 if (cgm.getCodeGenOpts().OptimizationLevel > 0 &&
1977 cgm.getCodeGenOpts().StrictVTablePointers)
1978 if (auto loadOp = vfuncLoad.getDefiningOp<cir::LoadOp>())
1979 loadOp.setInvariant(true);
1980
1981 vfunc = vfuncLoad;
1982 }
1983
1984 CIRGenCallee callee(gd, vfunc.getDefiningOp());
1985 return callee;
1986}
1987
1988mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructorWithVTT(
1989 CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,
1990 const CXXRecordDecl *nearestVBase) {
1991 assert((base.getBase()->getNumVBases() || nearestVBase != nullptr) &&
1992 needsVTTParameter(cgf.curGD) && "This class doesn't have VTT");
1993
1994 // Get the secondary vpointer index.
1995 uint64_t virtualPointerIndex =
1996 cgm.getVTables().getSecondaryVirtualPointerIndex(vtableClass, base);
1997
1998 /// Load the VTT.
1999 mlir::Value vttPtr = cgf.loadCXXVTT();
2000 mlir::Location loc = cgf.getLoc(vtableClass->getSourceRange());
2001 // Calculate the address point from the VTT, and the offset may be zero.
2002 vttPtr = cgf.getBuilder().createVTTAddrPoint(loc, vttPtr.getType(), vttPtr,
2003 virtualPointerIndex);
2004 // And load the address point from the VTT.
2005 auto vptrType = cir::VPtrType::get(cgf.getBuilder().getContext());
2006 return cgf.getBuilder().createAlignedLoad(loc, vptrType, vttPtr,
2007 cgf.getPointerAlign());
2008}
2009
2010mlir::Value
2011CIRGenItaniumCXXABI::getVTableAddressPoint(BaseSubobject base,
2012 const CXXRecordDecl *vtableClass) {
2013 cir::GlobalOp vtable = getAddrOfVTable(vtableClass, CharUnits());
2014
2015 // Find the appropriate vtable within the vtable group, and the address point
2016 // within that vtable.
2017 VTableLayout::AddressPointLocation addressPoint =
2019 .getVTableLayout(vtableClass)
2020 .getAddressPoint(base);
2021
2022 mlir::OpBuilder &builder = cgm.getBuilder();
2023 auto vtablePtrTy = cir::VPtrType::get(builder.getContext());
2024
2025 return cir::VTableAddrPointOp::create(
2026 builder, cgm.getLoc(vtableClass->getSourceRange()), vtablePtrTy,
2027 mlir::FlatSymbolRefAttr::get(vtable.getSymNameAttr()),
2028 cir::AddressPointAttr::get(cgm.getBuilder().getContext(),
2029 addressPoint.VTableIndex,
2030 addressPoint.AddressPointIndex));
2031}
2032
2033mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructor(
2034 CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
2035 clang::BaseSubobject base, const clang::CXXRecordDecl *nearestVBase) {
2036
2037 if ((base.getBase()->getNumVBases() || nearestVBase != nullptr) &&
2038 needsVTTParameter(cgf.curGD)) {
2039 return getVTableAddressPointInStructorWithVTT(cgf, vtableClass, base,
2040 nearestVBase);
2041 }
2042 return getVTableAddressPoint(base, vtableClass);
2043}
2044
2045bool CIRGenItaniumCXXABI::isVirtualOffsetNeededForVTableField(
2046 CIRGenFunction &cgf, CIRGenFunction::VPtr vptr) {
2047 if (vptr.nearestVBase == nullptr)
2048 return false;
2049 return needsVTTParameter(cgf.curGD);
2050}
2051
2052mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset(
2053 mlir::Location loc, CIRGenFunction &cgf, Address thisAddr,
2054 const CXXRecordDecl *classDecl, const CXXRecordDecl *baseClassDecl) {
2055 CIRGenBuilderTy &builder = cgf.getBuilder();
2056 mlir::Value vtablePtr = cgf.getVTablePtr(loc, thisAddr, classDecl);
2057 mlir::Value vtableBytePtr = builder.createBitcast(vtablePtr, cgm.uInt8PtrTy);
2058 CharUnits vbaseOffsetOffset =
2060 baseClassDecl);
2061 mlir::Value offsetVal =
2062 builder.getSInt64(vbaseOffsetOffset.getQuantity(), loc);
2063 auto vbaseOffsetPtr = cir::PtrStrideOp::create(builder, loc, cgm.uInt8PtrTy,
2064 vtableBytePtr, offsetVal);
2065
2066 mlir::Value vbaseOffset;
2067 if (cgm.getLangOpts().RelativeCXXABIVTables) {
2069 cgm.errorNYI(loc, "getVirtualBaseClassOffset: relative layout");
2070 } else {
2071 mlir::Value offsetPtr = builder.createBitcast(
2072 vbaseOffsetPtr, builder.getPointerTo(cgm.ptrDiffTy));
2073 vbaseOffset = builder.createLoad(
2074 loc, Address(offsetPtr, cgm.ptrDiffTy, cgf.getPointerAlign()));
2075 }
2076 return vbaseOffset;
2077}
2078
2079static cir::FuncOp getBadCastFn(CIRGenFunction &cgf) {
2080 // Prototype: void __cxa_bad_cast();
2081
2082 // TODO(cir): set the calling convention of the runtime function.
2084
2085 cir::FuncType fnTy =
2086 cgf.getBuilder().getFuncType({}, cgf.getBuilder().getVoidTy());
2087 return cgf.cgm.createRuntimeFunction(fnTy, "__cxa_bad_cast");
2088}
2089
2090static void emitCallToBadCast(CIRGenFunction &cgf, mlir::Location loc) {
2091 // TODO(cir): set the calling convention to the runtime function.
2093
2094 mlir::NamedAttrList attrs;
2095 attrs.set(cir::CIRDialect::getNoReturnAttrName(),
2096 mlir::UnitAttr::get(&cgf.cgm.getMLIRContext()));
2097
2098 cgf.emitRuntimeCall(loc, getBadCastFn(cgf), {}, attrs);
2099 cir::UnreachableOp::create(cgf.getBuilder(), loc);
2100 cgf.getBuilder().clearInsertionPoint();
2101}
2102
2103void CIRGenItaniumCXXABI::emitBadCastCall(CIRGenFunction &cgf,
2104 mlir::Location loc) {
2105 emitCallToBadCast(cgf, loc);
2106}
2107
2108// TODO(cir): This could be shared with classic codegen.
2110 const CXXRecordDecl *src,
2111 const CXXRecordDecl *dst) {
2112 CXXBasePaths paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
2113 /*DetectVirtual=*/false);
2114
2115 // If Dst is not derived from Src we can skip the whole computation below and
2116 // return that Src is not a public base of Dst. Record all inheritance paths.
2117 if (!dst->isDerivedFrom(src, paths))
2118 return CharUnits::fromQuantity(-2);
2119
2120 unsigned numPublicPaths = 0;
2121 CharUnits offset;
2122
2123 // Now walk all possible inheritance paths.
2124 for (const CXXBasePath &path : paths) {
2125 if (path.Access != AS_public) // Ignore non-public inheritance.
2126 continue;
2127
2128 ++numPublicPaths;
2129
2130 for (const CXXBasePathElement &pathElement : path) {
2131 // If the path contains a virtual base class we can't give any hint.
2132 // -1: no hint.
2133 if (pathElement.Base->isVirtual())
2134 return CharUnits::fromQuantity(-1);
2135
2136 if (numPublicPaths > 1) // Won't use offsets, skip computation.
2137 continue;
2138
2139 // Accumulate the base class offsets.
2140 const ASTRecordLayout &L =
2141 astContext.getASTRecordLayout(pathElement.Class);
2142 offset += L.getBaseClassOffset(
2143 pathElement.Base->getType()->getAsCXXRecordDecl());
2144 }
2145 }
2146
2147 // -2: Src is not a public base of Dst.
2148 if (numPublicPaths == 0)
2149 return CharUnits::fromQuantity(-2);
2150
2151 // -3: Src is a multiple public base type but never a virtual base type.
2152 if (numPublicPaths > 1)
2153 return CharUnits::fromQuantity(-3);
2154
2155 // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
2156 // Return the offset of Src from the origin of Dst.
2157 return offset;
2158}
2159
2160static cir::FuncOp getItaniumDynamicCastFn(CIRGenFunction &cgf) {
2161 // Prototype:
2162 // void *__dynamic_cast(const void *sub,
2163 // global_as const abi::__class_type_info *src,
2164 // global_as const abi::__class_type_info *dst,
2165 // std::ptrdiff_t src2dst_offset);
2166
2167 mlir::Type voidPtrTy = cgf.getBuilder().getVoidPtrTy();
2168 mlir::Type rttiPtrTy = cgf.getBuilder().getUInt8PtrTy();
2169 mlir::Type ptrDiffTy = cgf.convertType(cgf.getContext().getPointerDiffType());
2170
2171 // TODO(cir): mark the function as willreturn readonly.
2174
2175 // TODO(cir): set the calling convention of the runtime function.
2177
2178 cir::FuncType FTy = cgf.getBuilder().getFuncType(
2179 {voidPtrTy, rttiPtrTy, rttiPtrTy, ptrDiffTy}, voidPtrTy);
2180 cir::FuncOp fn = cgf.cgm.createRuntimeFunction(FTy, "__dynamic_cast");
2181 fn->setAttr(cir::CIRDialect::getNoThrowAttrName(),
2182 mlir::UnitAttr::get(cgf.getBuilder().getContext()));
2183 return fn;
2184}
2185
2186static Address emitDynamicCastToVoid(CIRGenFunction &cgf, mlir::Location loc,
2187 QualType srcRecordTy, Address src) {
2188 bool vtableUsesRelativeLayout = cgf.cgm.getLangOpts().RelativeCXXABIVTables;
2189 mlir::Value ptr = cgf.getBuilder().createDynCastToVoid(
2190 loc, src.getPointer(), vtableUsesRelativeLayout);
2191 return Address{ptr, src.getAlignment()};
2192}
2193
2194static mlir::Value emitExactDynamicCast(CIRGenItaniumCXXABI &abi,
2195 CIRGenFunction &cgf, mlir::Location loc,
2196 QualType srcRecordTy,
2197 QualType destRecordTy,
2198 cir::PointerType destCIRTy,
2199 bool isRefCast, Address src) {
2200 // Find all the inheritance paths from SrcRecordTy to DestRecordTy.
2201 const CXXRecordDecl *srcDecl = srcRecordTy->getAsCXXRecordDecl();
2202 const CXXRecordDecl *destDecl = destRecordTy->getAsCXXRecordDecl();
2203 CXXBasePaths paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
2204 /*DetectVirtual=*/false);
2205 (void)destDecl->isDerivedFrom(srcDecl, paths);
2206
2207 // Find an offset within `destDecl` where a `srcDecl` instance and its vptr
2208 // might appear.
2209 std::optional<CharUnits> offset;
2210 for (const CXXBasePath &path : paths) {
2211 // dynamic_cast only finds public inheritance paths.
2212 if (path.Access != AS_public)
2213 continue;
2214
2215 CharUnits pathOffset;
2216 for (const CXXBasePathElement &pathElement : path) {
2217 // Find the offset along this inheritance step.
2218 const CXXRecordDecl *base =
2219 pathElement.Base->getType()->getAsCXXRecordDecl();
2220 if (pathElement.Base->isVirtual()) {
2221 // For a virtual base class, we know that the derived class is exactly
2222 // destDecl, so we can use the vbase offset from its layout.
2223 const ASTRecordLayout &layout =
2224 cgf.getContext().getASTRecordLayout(destDecl);
2225 pathOffset = layout.getVBaseClassOffset(base);
2226 } else {
2227 const ASTRecordLayout &layout =
2228 cgf.getContext().getASTRecordLayout(pathElement.Class);
2229 pathOffset += layout.getBaseClassOffset(base);
2230 }
2231 }
2232
2233 if (!offset) {
2234 offset = pathOffset;
2235 } else if (offset != pathOffset) {
2236 // base appears in at least two different places. Find the most-derived
2237 // object and see if it's a DestDecl. Note that the most-derived object
2238 // must be at least as aligned as this base class subobject, and must
2239 // have a vptr at offset 0.
2240 src = emitDynamicCastToVoid(cgf, loc, srcRecordTy, src);
2241 srcDecl = destDecl;
2242 offset = CharUnits::Zero();
2243 break;
2244 }
2245 }
2246
2247 CIRGenBuilderTy &builder = cgf.getBuilder();
2248
2249 if (!offset) {
2250 // If there are no public inheritance paths, the cast always fails.
2251 mlir::Value nullPtrValue = builder.getNullPtr(destCIRTy, loc);
2252 if (isRefCast) {
2253 mlir::Region *currentRegion = builder.getBlock()->getParent();
2254 emitCallToBadCast(cgf, loc);
2255
2256 // The call to bad_cast will terminate the block. Create a new block to
2257 // hold any follow up code.
2258 builder.createBlock(currentRegion, currentRegion->end());
2259 }
2260
2261 return nullPtrValue;
2262 }
2263
2264 // Compare the vptr against the expected vptr for the destination type at
2265 // this offset. Note that we do not know what type src points to in the case
2266 // where the derived class multiply inherits from the base class so we can't
2267 // use getVTablePtr, so we load the vptr directly instead.
2268
2269 mlir::Value expectedVPtr =
2270 abi.getVTableAddressPoint(BaseSubobject(srcDecl, *offset), destDecl);
2271
2272 // TODO(cir): handle address space here.
2274 mlir::Type vptrTy = expectedVPtr.getType();
2275 mlir::Type vptrPtrTy = builder.getPointerTo(vptrTy);
2276 Address srcVPtrPtr(builder.createBitcast(src.getPointer(), vptrPtrTy),
2277 src.getAlignment());
2278 mlir::Value srcVPtr = builder.createLoad(loc, srcVPtrPtr);
2279
2280 // TODO(cir): decorate SrcVPtr with TBAA info.
2282
2283 mlir::Value success =
2284 builder.createCompare(loc, cir::CmpOpKind::eq, srcVPtr, expectedVPtr);
2285
2286 auto emitCastResult = [&] {
2287 if (offset->isZero())
2288 return builder.createBitcast(src.getPointer(), destCIRTy);
2289
2290 // TODO(cir): handle address space here.
2292 mlir::Type u8PtrTy = builder.getUInt8PtrTy();
2293
2294 mlir::Value strideToApply =
2295 builder.getConstInt(loc, builder.getUInt64Ty(), -offset->getQuantity());
2296 mlir::Value srcU8Ptr = builder.createBitcast(src.getPointer(), u8PtrTy);
2297 mlir::Value resultU8Ptr = cir::PtrStrideOp::create(builder, loc, u8PtrTy,
2298 srcU8Ptr, strideToApply);
2299 return builder.createBitcast(resultU8Ptr, destCIRTy);
2300 };
2301
2302 if (isRefCast) {
2303 mlir::Value failed = builder.createNot(success);
2304 cir::IfOp::create(builder, loc, failed, /*withElseRegion=*/false,
2305 [&](mlir::OpBuilder &, mlir::Location) {
2306 emitCallToBadCast(cgf, loc);
2307 });
2308 return emitCastResult();
2309 }
2310
2311 return cir::TernaryOp::create(
2312 builder, loc, success,
2313 [&](mlir::OpBuilder &, mlir::Location) {
2314 auto result = emitCastResult();
2315 builder.createYield(loc, result);
2316 },
2317 [&](mlir::OpBuilder &, mlir::Location) {
2318 mlir::Value nullPtrValue = builder.getNullPtr(destCIRTy, loc);
2319 builder.createYield(loc, nullPtrValue);
2320 })
2321 .getResult();
2322}
2323
2324static cir::DynamicCastInfoAttr emitDynamicCastInfo(CIRGenFunction &cgf,
2325 mlir::Location loc,
2326 QualType srcRecordTy,
2327 QualType destRecordTy) {
2328 auto srcRtti = mlir::cast<cir::GlobalViewAttr>(
2329 cgf.cgm.getAddrOfRTTIDescriptor(loc, srcRecordTy.getUnqualifiedType()));
2330 auto destRtti = mlir::cast<cir::GlobalViewAttr>(
2331 cgf.cgm.getAddrOfRTTIDescriptor(loc, destRecordTy.getUnqualifiedType()));
2332
2333 cir::FuncOp runtimeFuncOp = getItaniumDynamicCastFn(cgf);
2334 cir::FuncOp badCastFuncOp = getBadCastFn(cgf);
2335 auto runtimeFuncRef = mlir::FlatSymbolRefAttr::get(runtimeFuncOp);
2336 auto badCastFuncRef = mlir::FlatSymbolRefAttr::get(badCastFuncOp);
2337
2338 const CXXRecordDecl *srcDecl = srcRecordTy->getAsCXXRecordDecl();
2339 const CXXRecordDecl *destDecl = destRecordTy->getAsCXXRecordDecl();
2340 CharUnits offsetHint = computeOffsetHint(cgf.getContext(), srcDecl, destDecl);
2341
2342 mlir::Type ptrdiffTy = cgf.convertType(cgf.getContext().getPointerDiffType());
2343 auto offsetHintAttr = cir::IntAttr::get(ptrdiffTy, offsetHint.getQuantity());
2344
2345 return cir::DynamicCastInfoAttr::get(srcRtti, destRtti, runtimeFuncRef,
2346 badCastFuncRef, offsetHintAttr);
2347}
2348
2349mlir::Value CIRGenItaniumCXXABI::emitDynamicCast(CIRGenFunction &cgf,
2350 mlir::Location loc,
2351 QualType srcRecordTy,
2352 QualType destRecordTy,
2353 cir::PointerType destCIRTy,
2354 bool isRefCast, Address src) {
2355 bool isCastToVoid = destRecordTy.isNull();
2356 assert((!isCastToVoid || !isRefCast) && "cannot cast to void reference");
2357
2358 if (isCastToVoid)
2359 return emitDynamicCastToVoid(cgf, loc, srcRecordTy, src).getPointer();
2360
2361 // If the destination is effectively final, the cast succeeds if and only
2362 // if the dynamic type of the pointer is exactly the destination type.
2363 if (destRecordTy->getAsCXXRecordDecl()->isEffectivelyFinal() &&
2364 cgf.cgm.getCodeGenOpts().OptimizationLevel > 0) {
2365 CIRGenBuilderTy &builder = cgf.getBuilder();
2366 // If this isn't a reference cast, check the pointer to see if it's null.
2367 if (!isRefCast) {
2368 mlir::Value srcPtrIsNull = builder.createPtrIsNull(src.getPointer());
2369 return cir::TernaryOp::create(
2370 builder, loc, srcPtrIsNull,
2371 [&](mlir::OpBuilder, mlir::Location) {
2372 builder.createYield(
2373 loc, builder.getNullPtr(destCIRTy, loc).getResult());
2374 },
2375 [&](mlir::OpBuilder &, mlir::Location) {
2376 mlir::Value exactCast = emitExactDynamicCast(
2377 *this, cgf, loc, srcRecordTy, destRecordTy, destCIRTy,
2378 isRefCast, src);
2379 builder.createYield(loc, exactCast);
2380 })
2381 .getResult();
2382 }
2383
2384 return emitExactDynamicCast(*this, cgf, loc, srcRecordTy, destRecordTy,
2385 destCIRTy, isRefCast, src);
2386 }
2387
2388 cir::DynamicCastInfoAttr castInfo =
2389 emitDynamicCastInfo(cgf, loc, srcRecordTy, destRecordTy);
2390 return cgf.getBuilder().createDynCast(loc, src.getPointer(), destCIRTy,
2391 isRefCast, castInfo);
2392}
2393
2394cir::MethodAttr
2395CIRGenItaniumCXXABI::buildVirtualMethodAttr(cir::MethodType methodTy,
2396 const CXXMethodDecl *md) {
2397 assert(md->isVirtual() && "only deal with virtual member functions");
2398
2400 uint64_t vtableOffset;
2401 if (cgm.getLangOpts().RelativeCXXABIVTables) {
2402 // Multiply by 4-byte relative offsets.
2403 vtableOffset = index * 4;
2404 } else {
2405 const ASTContext &astContext = cgm.getASTContext();
2406 CharUnits pointerWidth = astContext.toCharUnitsFromBits(
2407 astContext.getTargetInfo().getPointerWidth(LangAS::Default));
2408 vtableOffset = index * pointerWidth.getQuantity();
2409 }
2410
2411 return cir::MethodAttr::get(methodTy, vtableOffset);
2412}
2413/// The Itanium ABI always places an offset to the complete object
2414/// at entry -2 in the vtable.
2415void CIRGenItaniumCXXABI::emitVirtualObjectDelete(
2416 CIRGenFunction &cgf, const CXXDeleteExpr *delExpr, Address ptr,
2417 QualType elementType, const CXXDestructorDecl *dtor) {
2418 bool useGlobalDelete = delExpr->isGlobalDelete();
2419 if (useGlobalDelete) {
2420 cgf.cgm.errorNYI(delExpr->getSourceRange(),
2421 "emitVirtualObjectDelete: global delete");
2422 }
2423
2424 CXXDtorType dtorType = useGlobalDelete ? Dtor_Complete : Dtor_Deleting;
2425 emitVirtualDestructorCall(cgf, dtor, dtorType, ptr, delExpr);
2426}
2427
2428/************************** Array allocation cookies **************************/
2429
2430CharUnits CIRGenItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {
2431 // The array cookie is a size_t; pad that up to the element alignment.
2432 // The cookie is actually right-justified in that space.
2433 return std::max(
2434 cgm.getSizeSize(),
2435 cgm.getASTContext().getPreferredTypeAlignInChars(elementType));
2436}
2437
2438Address CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
2439 Address newPtr,
2440 mlir::Value numElements,
2441 const CXXNewExpr *e,
2442 QualType elementType) {
2443 assert(requiresArrayCookie(e));
2444
2445 // TODO: When sanitizer support is implemented, we'll need to
2446 // get the address space from `newPtr`.
2449
2450 ASTContext &ctx = cgm.getASTContext();
2451 CharUnits sizeSize = cgf.getSizeSize();
2452 mlir::Location loc = cgf.getLoc(e->getSourceRange());
2453
2454 // The size of the cookie.
2455 CharUnits cookieSize =
2456 std::max(sizeSize, ctx.getPreferredTypeAlignInChars(elementType));
2457 assert(cookieSize == getArrayCookieSizeImpl(elementType));
2458
2459 mlir::Type u8Ty = cgf.getBuilder().getUInt8Ty();
2460 cir::PointerType u8PtrTy = cgf.getBuilder().getUInt8PtrTy();
2461 mlir::Value baseBytePtr =
2462 cgf.getBuilder().createBitcast(newPtr.getPointer(), u8PtrTy);
2463
2464 // Compute an offset to the cookie.
2465 CharUnits cookieOffset = cookieSize - sizeSize;
2466 mlir::Value cookiePtrValue = baseBytePtr;
2467 if (!cookieOffset.isZero()) {
2468 mlir::Value offsetOp = cgf.getBuilder().getSignedInt(
2469 loc, cookieOffset.getQuantity(), /*width=*/32);
2470 cookiePtrValue =
2471 cgf.getBuilder().createPtrStride(loc, cookiePtrValue, offsetOp);
2472 }
2473
2474 CharUnits baseAlignment = newPtr.getAlignment();
2475 CharUnits cookiePtrAlignment = baseAlignment.alignmentAtOffset(cookieOffset);
2476 Address cookiePtr(cookiePtrValue, u8Ty, cookiePtrAlignment);
2477
2478 // Write the number of elements into the appropriate slot.
2479 Address numElementsPtr =
2480 cookiePtr.withElementType(cgf.getBuilder(), cgf.sizeTy);
2481 cgf.getBuilder().createStore(loc, numElements, numElementsPtr);
2482
2483 // Finally, compute a pointer to the actual data buffer by skipping
2484 // over the cookie completely.
2485 mlir::Value dataOffset =
2486 cgf.getBuilder().getSignedInt(loc, cookieSize.getQuantity(),
2487 /*width=*/32);
2488 mlir::Value dataPtr =
2489 cgf.getBuilder().createPtrStride(loc, baseBytePtr, dataOffset);
2490 mlir::Value finalPtr =
2491 cgf.getBuilder().createPtrBitcast(dataPtr, newPtr.getElementType());
2492 CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
2493 return Address(finalPtr, newPtr.getElementType(), finalAlignment);
2494}
2495
2496bool CIRGenItaniumCXXABI::hasAnyUnusedVirtualInlineFunction(
2497 const CXXRecordDecl *rd) const {
2498 const auto &vtableLayout = cgm.getItaniumVTableContext().getVTableLayout(rd);
2499
2500 for (const auto &vtableComponent : vtableLayout.vtable_components()) {
2501 // Skip empty slot.
2502 if (!vtableComponent.isUsedFunctionPointerKind())
2503 continue;
2504
2505 const CXXMethodDecl *method = vtableComponent.getFunctionDecl();
2506 const FunctionDecl *fd = method->getDefinition();
2507 const bool isInlined =
2508 method->getCanonicalDecl()->isInlined() || (fd && fd->isInlined());
2509 if (!isInlined)
2510 continue;
2511
2512 StringRef name = cgm.getMangledName(
2513 vtableComponent.getGlobalDecl(/*HasVectorDeletingDtors=*/false));
2514 auto entry = dyn_cast_or_null<cir::GlobalOp>(cgm.getGlobalValue(name));
2515 // This checks if virtual inline function has already been emitted.
2516 // Note that it is possible that this inline function would be emitted
2517 // after trying to emit vtable speculatively. Because of this we do
2518 // an extra pass after emitting all deferred vtables to find and emit
2519 // these vtables opportunistically.
2520 if (!entry || entry.isDeclaration())
2521 return true;
2522 }
2523 return false;
2524}
2525
2526bool CIRGenItaniumCXXABI::isVTableHidden(const CXXRecordDecl *rd) const {
2527 const auto &vtableLayout = cgm.getItaniumVTableContext().getVTableLayout(rd);
2528
2529 for (const auto &vtableComponent : vtableLayout.vtable_components()) {
2530 if (vtableComponent.isRTTIKind()) {
2531 const CXXRecordDecl *rttiDecl = vtableComponent.getRTTIDecl();
2532 if (rttiDecl->getVisibility() == Visibility::HiddenVisibility)
2533 return true;
2534 } else if (vtableComponent.isUsedFunctionPointerKind()) {
2535 const CXXMethodDecl *method = vtableComponent.getFunctionDecl();
2536 if (method->getVisibility() == Visibility::HiddenVisibility &&
2537 !method->isDefined())
2538 return true;
2539 }
2540 }
2541 return false;
2542}
2543
2544bool CIRGenItaniumCXXABI::canSpeculativelyEmitVTableAsBaseClass(
2545 const CXXRecordDecl *rd) const {
2546 // We don't emit available_externally vtables if we are in -fapple-kext mode
2547 // because kext mode does not permit devirtualization.
2548 if (cgm.getLangOpts().AppleKext)
2549 return false;
2550
2551 // If the vtable is hidden then it is not safe to emit an available_externally
2552 // copy of vtable.
2553 if (isVTableHidden(rd))
2554 return false;
2555
2556 if (cgm.getCodeGenOpts().ForceEmitVTables)
2557 return true;
2558
2559 // A speculative vtable can only be generated if all virtual inline functions
2560 // defined by this class are emitted. The vtable in the final program contains
2561 // for each virtual inline function not used in the current TU a function that
2562 // is equivalent to the unused function. The function in the actual vtable
2563 // does not have to be declared under the same symbol (e.g., a virtual
2564 // destructor that can be substituted with its base class's destructor). Since
2565 // inline functions are emitted lazily and this emissions does not account for
2566 // speculative emission of a vtable, we might generate a speculative vtable
2567 // with references to inline functions that are not emitted under that name.
2568 // This can lead to problems when devirtualizing a call to such a function,
2569 // that result in linking errors. Hence, if there are any unused virtual
2570 // inline function, we cannot emit the speculative vtable.
2571 // FIXME we can still emit a copy of the vtable if we
2572 // can emit definition of the inline functions.
2573 if (hasAnyUnusedVirtualInlineFunction(rd))
2574 return false;
2575
2576 // For a class with virtual bases, we must also be able to speculatively
2577 // emit the VTT, because CodeGen doesn't have separate notions of "can emit
2578 // the vtable" and "can emit the VTT". For a base subobject, this means we
2579 // need to be able to emit non-virtual base vtables.
2580 if (rd->getNumVBases()) {
2581 for (const auto &b : rd->bases()) {
2582 auto *brd = b.getType()->getAsCXXRecordDecl();
2583 assert(brd && "no class for base specifier");
2584 if (b.isVirtual() || !brd->isDynamicClass())
2585 continue;
2586 if (!canSpeculativelyEmitVTableAsBaseClass(brd))
2587 return false;
2588 }
2589 }
2590
2591 return true;
2592}
2593
2594bool CIRGenItaniumCXXABI::canSpeculativelyEmitVTable(
2595 const CXXRecordDecl *rd) const {
2596 if (!canSpeculativelyEmitVTableAsBaseClass(rd))
2597 return false;
2598
2600 return false;
2601
2602 // For a complete-object vtable (or more specifically, for the VTT), we need
2603 // to be able to speculatively emit the vtables of all dynamic virtual bases.
2604 for (const auto &b : rd->vbases()) {
2605 auto *brd = b.getType()->getAsCXXRecordDecl();
2606 assert(brd && "no class for base specifier");
2607 if (!brd->isDynamicClass())
2608 continue;
2609 if (!canSpeculativelyEmitVTableAsBaseClass(brd))
2610 return false;
2611 }
2612
2613 return true;
2614}
2615
2617 Address initialPtr,
2618 const CXXRecordDecl *unadjustedClass,
2619 int64_t nonVirtualAdjustment,
2620 int64_t virtualAdjustment,
2621 bool isReturnAdjustment) {
2622 if (!nonVirtualAdjustment && !virtualAdjustment)
2623 return initialPtr.getPointer();
2624
2625 CIRGenBuilderTy &builder = cgf.getBuilder();
2626 mlir::Location loc = builder.getUnknownLoc();
2627 cir::PointerType i8PtrTy = builder.getUInt8PtrTy();
2628 mlir::Value v = builder.createBitcast(initialPtr.getPointer(), i8PtrTy);
2629
2630 // In a base-to-derived cast, the non-virtual adjustment is applied first.
2631 if (nonVirtualAdjustment && !isReturnAdjustment) {
2632 cir::ConstantOp offsetConst = builder.getSInt64(nonVirtualAdjustment, loc);
2633 v = cir::PtrStrideOp::create(builder, loc, i8PtrTy, v, offsetConst);
2634 }
2635
2636 // Perform the virtual adjustment if we have one.
2637 mlir::Value resultPtr;
2638 if (virtualAdjustment) {
2639 mlir::Value vtablePtr = cgf.getVTablePtr(
2640 loc, Address(v, clang::CharUnits::One()), unadjustedClass);
2641 vtablePtr = builder.createBitcast(vtablePtr, i8PtrTy);
2642
2643 mlir::Value offset;
2644 mlir::Value offsetPtr =
2645 cir::PtrStrideOp::create(builder, loc, i8PtrTy, vtablePtr,
2646 builder.getSInt64(virtualAdjustment, loc));
2647 if (cgf.cgm.getLangOpts().RelativeCXXABIVTables) {
2649 cgf.cgm.errorNYI("virtual adjustment for relative layout vtables");
2650 } else {
2651 offset = builder.createAlignedLoad(loc, cgf.ptrDiffTy, offsetPtr,
2652 cgf.getPointerAlign());
2653 }
2654
2655 resultPtr = cir::PtrStrideOp::create(builder, loc, i8PtrTy, v, offset);
2656 } else {
2657 resultPtr = v;
2658 }
2659
2660 // In a derived-to-base conversion, the non-virtual adjustment is
2661 // applied second.
2662 if (nonVirtualAdjustment && isReturnAdjustment) {
2663 cir::ConstantOp offsetConst = builder.getSInt64(nonVirtualAdjustment, loc);
2664 resultPtr =
2665 cir::PtrStrideOp::create(builder, loc, i8PtrTy, resultPtr, offsetConst);
2666 }
2667
2668 // Cast back to original pointer type.
2669 return builder.createBitcast(resultPtr, initialPtr.getType());
2670}
2671
2672mlir::Value CIRGenItaniumCXXABI::performThisAdjustment(
2673 CIRGenFunction &cgf, Address thisAddr, const CXXRecordDecl *unadjustedClass,
2674 const ThunkInfo &ti) {
2675 return performTypeAdjustment(cgf, thisAddr, unadjustedClass,
2676 ti.This.NonVirtual,
2678 /*isReturnAdjustment=*/false);
2679}
2680
2681mlir::Value CIRGenItaniumCXXABI::performReturnAdjustment(
2682 CIRGenFunction &cgf, Address ret, const CXXRecordDecl *unadjustedClass,
2683 const ReturnAdjustment &ra) {
2684 return performTypeAdjustment(cgf, ret, unadjustedClass, ra.NonVirtual,
2686 /*isReturnAdjustment=*/true);
2687}
2688
2689bool CIRGenItaniumCXXABI::isZeroInitializable(const MemberPointerType *mpt) {
2690 return mpt->isMemberFunctionPointer();
2691}
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.
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:223
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:823
const LangOptions & getLangOpts() const
Definition ASTContext.h:980
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:942
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:3292
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 createLoad(mlir::Location loc, Address addr, bool isVolatile=false, bool isNontemporal=false)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, bool isNontemporal=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
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)
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)
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:2654
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2145
bool isVirtual() const
Definition DeclCXX.h:2200
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2288
CXXMethodDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition DeclCXX.h:2258
SourceRange getSourceRange() const
Definition ExprCXX.h:2613
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:2341
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:1226
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:1231
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:2126
bool isTranslationUnit() const
Definition DeclBase.h:2202
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:3051
FunctionDecl * getDefinition()
Get the definition for this declaration.
Definition Decl.h:2395
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:3234
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:5665
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:5703
QualType getPointeeType() const
Definition TypeBase.h:3785
bool isMemberFunctionPointer() const
Returns true if the member type (i.e.
Definition TypeBase.h:3789
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:3418
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isVolatileQualified() const
Determine whether this type is volatile-qualified.
Definition TypeBase.h:8588
bool isRestrictQualified() const
Determine whether this type is restrict-qualified.
Definition TypeBase.h:8582
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8544
QualType getCanonicalType() const
Definition TypeBase.h:8556
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8598
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition TypeBase.h:8577
bool empty() const
Definition TypeBase.h:648
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:4956
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:496
virtual bool hasPS4DLLImportExport() const
uint64_t getPointerAlign(LangAS AddrSpace) const
Definition TargetInfo.h:500
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:542
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h:3681
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:3142
Linkage getLinkage() const
Determine the linkage of this type.
Definition Type.cpp:5060
TypeClass getTypeClass() const
Definition TypeBase.h:2449
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9340
AddressPointLocation getAddressPoint(BaseSubobject Base) const
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:2171
bool isNoDestroy(const ASTContext &) const
Is destruction of this variable entirely suppressed?
Definition Decl.cpp:2807
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...
Top level wrappers for InstallAPI frontend operations.
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:559
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