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