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