clang 22.0.0git
CIRGenItaniumCXXABI.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This provides C++ code generation targeting the Itanium C++ ABI. The class
10// in this file generates structures that follow the Itanium C++ ABI, which is
11// documented at:
12// https://itanium-cxx-abi.github.io/cxx-abi/abi.html
13// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
14//
15// It also supports the closely-related ARM ABI, documented at:
16// https://developer.arm.com/documentation/ihi0041/g/
17//
18//===----------------------------------------------------------------------===//
19
20#include "CIRGenCXXABI.h"
21#include "CIRGenFunction.h"
22
23#include "clang/AST/ExprCXX.h"
27#include "llvm/Support/ErrorHandling.h"
28
29using namespace clang;
30using namespace clang::CIRGen;
31
32namespace {
33
34class CIRGenItaniumCXXABI : public CIRGenCXXABI {
35protected:
36 /// All the vtables which have been defined.
37 llvm::DenseMap<const CXXRecordDecl *, cir::GlobalOp> vtables;
38
39public:
40 CIRGenItaniumCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) {
43 }
44
45 AddedStructorArgs getImplicitConstructorArgs(CIRGenFunction &cgf,
46 const CXXConstructorDecl *d,
48 bool forVirtualBase,
49 bool delegating) override;
50
51 bool needsVTTParameter(clang::GlobalDecl gd) override;
52
53 AddedStructorArgCounts
54 buildStructorSignature(GlobalDecl gd,
55 llvm::SmallVectorImpl<CanQualType> &argTys) override;
56
57 void emitInstanceFunctionProlog(SourceLocation loc,
58 CIRGenFunction &cgf) override;
59
60 void addImplicitStructorParams(CIRGenFunction &cgf, QualType &resTy,
61 FunctionArgList &params) override;
62
63 void emitCXXConstructors(const clang::CXXConstructorDecl *d) override;
64 void emitCXXDestructors(const clang::CXXDestructorDecl *d) override;
65 void emitCXXStructor(clang::GlobalDecl gd) override;
66
67 void emitDestructorCall(CIRGenFunction &cgf, const CXXDestructorDecl *dd,
68 CXXDtorType type, bool forVirtualBase,
69 bool delegating, Address thisAddr,
70 QualType thisTy) override;
71
72 void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) override;
73
74 bool useThunkForDtorVariant(const CXXDestructorDecl *dtor,
75 CXXDtorType dt) const override {
76 // Itanium does not emit any destructor variant as an inline thunk.
77 // Delegating may occur as an optimization, but all variants are either
78 // emitted with external linkage or as linkonce if they are inline and used.
79 return false;
80 }
81
82 bool isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf,
83 CIRGenFunction::VPtr vptr) override;
84
85 cir::GlobalOp getAddrOfVTable(const CXXRecordDecl *rd,
86 CharUnits vptrOffset) override;
87 CIRGenCallee getVirtualFunctionPointer(CIRGenFunction &cgf,
88 clang::GlobalDecl gd, Address thisAddr,
89 mlir::Type ty,
90 SourceLocation loc) override;
91
92 mlir::Value getVTableAddressPoint(BaseSubobject base,
93 const CXXRecordDecl *vtableClass) override;
94 mlir::Value getVTableAddressPointInStructorWithVTT(
95 CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,
96 const CXXRecordDecl *nearestVBase);
97
98 mlir::Value getVTableAddressPointInStructor(
99 CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
100 clang::BaseSubobject base,
101 const clang::CXXRecordDecl *nearestVBase) override;
102 void emitVTableDefinitions(CIRGenVTables &cgvt,
103 const CXXRecordDecl *rd) override;
104 void emitVirtualInheritanceTables(const CXXRecordDecl *rd) override;
105
106 bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
107 return true;
108 }
109
110 mlir::Value
111 getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf,
112 Address thisAddr, const CXXRecordDecl *classDecl,
113 const CXXRecordDecl *baseClassDecl) override;
114};
115
116} // namespace
117
118void CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc,
119 CIRGenFunction &cgf) {
120 // Naked functions have no prolog.
121 if (cgf.curFuncDecl && cgf.curFuncDecl->hasAttr<NakedAttr>()) {
123 "emitInstanceFunctionProlog: Naked");
124 }
125
126 /// Initialize the 'this' slot. In the Itanium C++ ABI, no prologue
127 /// adjustments are required, because they are all handled by thunks.
128 setCXXABIThisValue(cgf, loadIncomingCXXThis(cgf));
129
130 /// Initialize the 'vtt' slot if needed.
131 if (getStructorImplicitParamDecl(cgf)) {
132 cir::LoadOp val = cgf.getBuilder().createLoad(
133 cgf.getLoc(loc),
134 cgf.getAddrOfLocalVar(getStructorImplicitParamDecl(cgf)));
135 setStructorImplicitParamValue(cgf, val);
136 }
137
138 /// If this is a function that the ABI specifies returns 'this', initialize
139 /// the return slot to this' at the start of the function.
140 ///
141 /// Unlike the setting of return types, this is done within the ABI
142 /// implementation instead of by clients of CIRGenCXXBI because:
143 /// 1) getThisValue is currently protected
144 /// 2) in theory, an ABI could implement 'this' returns some other way;
145 /// HasThisReturn only specifies a contract, not the implementation
146 if (hasThisReturn(cgf.curGD)) {
148 "emitInstanceFunctionProlog: hasThisReturn");
149 }
150}
151
152CIRGenCXXABI::AddedStructorArgCounts
153CIRGenItaniumCXXABI::buildStructorSignature(
154 GlobalDecl gd, llvm::SmallVectorImpl<CanQualType> &argTys) {
155 clang::ASTContext &astContext = cgm.getASTContext();
156
157 // All parameters are already in place except VTT, which goes after 'this'.
158 // These are clang types, so we don't need to worry about sret yet.
159
160 // Check if we need to add a VTT parameter (which has type void **).
162 : gd.getDtorType() == Dtor_Base) &&
163 cast<CXXMethodDecl>(gd.getDecl())->getParent()->getNumVBases() != 0) {
165 argTys.insert(argTys.begin() + 1,
166 astContext.getPointerType(
168 return AddedStructorArgCounts::withPrefix(1);
169 }
170
171 return AddedStructorArgCounts{};
172}
173
174// Find out how to cirgen the complete destructor and constructor
175namespace {
176enum class StructorCIRGen { Emit, RAUW, Alias, COMDAT };
177}
178
179static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm,
180 const CXXMethodDecl *md) {
181 if (!cgm.getCodeGenOpts().CXXCtorDtorAliases)
182 return StructorCIRGen::Emit;
183
184 // The complete and base structors are not equivalent if there are any virtual
185 // bases, so emit separate functions.
186 if (md->getParent()->getNumVBases())
187 return StructorCIRGen::Emit;
188
189 GlobalDecl aliasDecl;
190 if (const auto *dd = dyn_cast<CXXDestructorDecl>(md)) {
191 aliasDecl = GlobalDecl(dd, Dtor_Complete);
192 } else {
193 const auto *cd = cast<CXXConstructorDecl>(md);
194 aliasDecl = GlobalDecl(cd, Ctor_Complete);
195 }
196
197 cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);
198
199 if (cir::isDiscardableIfUnused(linkage))
200 return StructorCIRGen::RAUW;
201
202 // FIXME: Should we allow available_externally aliases?
203 if (!cir::isValidLinkage(linkage))
204 return StructorCIRGen::RAUW;
205
206 if (cir::isWeakForLinker(linkage)) {
207 // Only ELF and wasm support COMDATs with arbitrary names (C5/D5).
208 if (cgm.getTarget().getTriple().isOSBinFormatELF() ||
209 cgm.getTarget().getTriple().isOSBinFormatWasm())
210 return StructorCIRGen::COMDAT;
211 return StructorCIRGen::Emit;
212 }
213
214 return StructorCIRGen::Alias;
215}
216
218 GlobalDecl aliasDecl,
219 GlobalDecl targetDecl) {
220 cir::GlobalLinkageKind linkage = cgm.getFunctionLinkage(aliasDecl);
221
222 // Does this function alias already exists?
223 StringRef mangledName = cgm.getMangledName(aliasDecl);
224 auto globalValue = dyn_cast_or_null<cir::CIRGlobalValueInterface>(
225 cgm.getGlobalValue(mangledName));
226 if (globalValue && !globalValue.isDeclaration())
227 return;
228
229 auto entry = cast_or_null<cir::FuncOp>(cgm.getGlobalValue(mangledName));
230
231 // Retrieve aliasee info.
232 auto aliasee = cast<cir::FuncOp>(cgm.getAddrOfGlobal(targetDecl));
233
234 // Populate actual alias.
235 cgm.emitAliasForGlobal(mangledName, entry, aliasDecl, aliasee, linkage);
236}
237
238void CIRGenItaniumCXXABI::emitCXXStructor(GlobalDecl gd) {
239 auto *md = cast<CXXMethodDecl>(gd.getDecl());
240 StructorCIRGen cirGenType = getCIRGenToUse(cgm, md);
241 const auto *cd = dyn_cast<CXXConstructorDecl>(md);
242
243 if (cd ? gd.getCtorType() == Ctor_Complete
244 : gd.getDtorType() == Dtor_Complete) {
245 GlobalDecl baseDecl =
247 ;
248
249 if (cirGenType == StructorCIRGen::Alias ||
250 cirGenType == StructorCIRGen::COMDAT) {
251 emitConstructorDestructorAlias(cgm, gd, baseDecl);
252 return;
253 }
254
255 if (cirGenType == StructorCIRGen::RAUW) {
256 StringRef mangledName = cgm.getMangledName(gd);
257 mlir::Operation *aliasee = cgm.getAddrOfGlobal(baseDecl);
258 cgm.addReplacement(mangledName, aliasee);
259 return;
260 }
261 }
262
263 auto fn = cgm.codegenCXXStructor(gd);
264
265 cgm.maybeSetTrivialComdat(*md, fn);
266}
267
268void CIRGenItaniumCXXABI::addImplicitStructorParams(CIRGenFunction &cgf,
269 QualType &resTy,
270 FunctionArgList &params) {
271 const auto *md = cast<CXXMethodDecl>(cgf.curGD.getDecl());
273
274 // Check if we need a VTT parameter as well.
275 if (needsVTTParameter(cgf.curGD)) {
276 ASTContext &astContext = cgm.getASTContext();
277
278 // FIXME: avoid the fake decl
280 QualType t = astContext.getPointerType(astContext.VoidPtrTy);
281 auto *vttDecl = ImplicitParamDecl::Create(
282 astContext, /*DC=*/nullptr, md->getLocation(),
283 &astContext.Idents.get("vtt"), t, ImplicitParamKind::CXXVTT);
284 params.insert(params.begin() + 1, vttDecl);
285 getStructorImplicitParamDecl(cgf) = vttDecl;
286 }
287}
288
289void CIRGenItaniumCXXABI::emitCXXConstructors(const CXXConstructorDecl *d) {
290 // Just make sure we're in sync with TargetCXXABI.
291 assert(cgm.getTarget().getCXXABI().hasConstructorVariants());
292
293 // The constructor used for constructing this as a base class;
294 // ignores virtual bases.
295 cgm.emitGlobal(GlobalDecl(d, Ctor_Base));
296
297 // The constructor used for constructing this as a complete class;
298 // constructs the virtual bases, then calls the base constructor.
299 if (!d->getParent()->isAbstract()) {
300 // We don't need to emit the complete ctro if the class is abstract.
301 cgm.emitGlobal(GlobalDecl(d, Ctor_Complete));
302 }
303}
304
305void CIRGenItaniumCXXABI::emitCXXDestructors(const CXXDestructorDecl *d) {
306 // The destructor used for destructing this as a base class; ignores
307 // virtual bases.
308 cgm.emitGlobal(GlobalDecl(d, Dtor_Base));
309
310 // The destructor used for destructing this as a most-derived class;
311 // call the base destructor and then destructs any virtual bases.
312 cgm.emitGlobal(GlobalDecl(d, Dtor_Complete));
313
314 // The destructor in a virtual table is always a 'deleting'
315 // destructor, which calls the complete destructor and then uses the
316 // appropriate operator delete.
317 if (d->isVirtual())
318 cgm.emitGlobal(GlobalDecl(d, Dtor_Deleting));
319}
320
321CIRGenCXXABI::AddedStructorArgs CIRGenItaniumCXXABI::getImplicitConstructorArgs(
322 CIRGenFunction &cgf, const CXXConstructorDecl *d, CXXCtorType type,
323 bool forVirtualBase, bool delegating) {
324 if (!needsVTTParameter(GlobalDecl(d, type)))
325 return AddedStructorArgs{};
326
327 // Insert the implicit 'vtt' argument as the second argument. Make sure to
328 // correctly reflect its address space, which can differ from generic on
329 // some targets.
330 mlir::Value vtt =
331 cgf.getVTTParameter(GlobalDecl(d, type), forVirtualBase, delegating);
332 QualType vttTy =
333 cgm.getASTContext().getPointerType(cgm.getASTContext().VoidPtrTy);
335 return AddedStructorArgs::withPrefix({{vtt, vttTy}});
336}
337
338/// Return whether the given global decl needs a VTT (virtual table table)
339/// parameter, which it does if it's a base constructor or destructor with
340/// virtual bases.
341bool CIRGenItaniumCXXABI::needsVTTParameter(GlobalDecl gd) {
342 auto *md = cast<CXXMethodDecl>(gd.getDecl());
343
344 // We don't have any virtual bases, just return early.
345 if (!md->getParent()->getNumVBases())
346 return false;
347
348 // Check if we have a base constructor.
350 return true;
351
352 // Check if we have a base destructor.
354 return true;
355
356 return false;
357}
358
359void CIRGenItaniumCXXABI::emitVTableDefinitions(CIRGenVTables &cgvt,
360 const CXXRecordDecl *rd) {
361 cir::GlobalOp vtable = getAddrOfVTable(rd, CharUnits());
362 if (vtable.hasInitializer())
363 return;
364
365 ItaniumVTableContext &vtContext = cgm.getItaniumVTableContext();
366 const VTableLayout &vtLayout = vtContext.getVTableLayout(rd);
367 cir::GlobalLinkageKind linkage = cgm.getVTableLinkage(rd);
368 mlir::Attribute rtti =
369 cgm.getAddrOfRTTIDescriptor(cgm.getLoc(rd->getBeginLoc()),
370 cgm.getASTContext().getCanonicalTagType(rd));
371
372 // Classic codegen uses ConstantInitBuilder here, which is a very general
373 // and feature-rich class to generate initializers for global values.
374 // For now, this is using a simpler approach to create the initializer in CIR.
375 cgvt.createVTableInitializer(vtable, vtLayout, rtti,
376 cir::isLocalLinkage(linkage));
377
378 // Set the correct linkage.
379 vtable.setLinkage(linkage);
380
381 if (cgm.supportsCOMDAT() && cir::isWeakForLinker(linkage))
382 vtable.setComdat(true);
383
384 // Set the right visibility.
385 cgm.setGVProperties(vtable, rd);
386
387 // If this is the magic class __cxxabiv1::__fundamental_type_info,
388 // we will emit the typeinfo for the fundamental types. This is the
389 // same behaviour as GCC.
390 const DeclContext *DC = rd->getDeclContext();
391 if (rd->getIdentifier() &&
392 rd->getIdentifier()->isStr("__fundamental_type_info") &&
393 isa<NamespaceDecl>(DC) && cast<NamespaceDecl>(DC)->getIdentifier() &&
394 cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") &&
395 DC->getParent()->isTranslationUnit()) {
396 cgm.errorNYI(rd->getSourceRange(),
397 "emitVTableDefinitions: __fundamental_type_info");
398 }
399
400 auto vtableAsGlobalValue = dyn_cast<cir::CIRGlobalValueInterface>(*vtable);
401 assert(vtableAsGlobalValue && "VTable must support CIRGlobalValueInterface");
402 // Always emit type metadata on non-available_externally definitions, and on
403 // available_externally definitions if we are performing whole program
404 // devirtualization. For WPD we need the type metadata on all vtable
405 // definitions to ensure we associate derived classes with base classes
406 // defined in headers but with a strong definition only in a shared
407 // library.
409 if (cgm.getCodeGenOpts().WholeProgramVTables) {
410 cgm.errorNYI(rd->getSourceRange(),
411 "emitVTableDefinitions: WholeProgramVTables");
412 }
413
415 if (vtContext.isRelativeLayout()) {
416 cgm.errorNYI(rd->getSourceRange(), "vtableRelativeLayout");
417 }
418}
419
420void CIRGenItaniumCXXABI::emitVirtualInheritanceTables(
421 const CXXRecordDecl *rd) {
422 CIRGenVTables &vtables = cgm.getVTables();
423 cir::GlobalOp vtt = vtables.getAddrOfVTT(rd);
424 vtables.emitVTTDefinition(vtt, cgm.getVTableLinkage(rd), rd);
425}
426
427void CIRGenItaniumCXXABI::emitDestructorCall(
428 CIRGenFunction &cgf, const CXXDestructorDecl *dd, CXXDtorType type,
429 bool forVirtualBase, bool delegating, Address thisAddr, QualType thisTy) {
430 GlobalDecl gd(dd, type);
431 if (needsVTTParameter(gd)) {
432 cgm.errorNYI(dd->getSourceRange(), "emitDestructorCall: VTT");
433 }
434
435 mlir::Value vtt = nullptr;
436 ASTContext &astContext = cgm.getASTContext();
437 QualType vttTy = astContext.getPointerType(astContext.VoidPtrTy);
439 CIRGenCallee callee =
440 CIRGenCallee::forDirect(cgm.getAddrOfCXXStructor(gd), gd);
441
442 cgf.emitCXXDestructorCall(gd, callee, thisAddr.getPointer(), thisTy, vtt,
443 vttTy, nullptr);
444}
445
446// The idea here is creating a separate block for the throw with an
447// `UnreachableOp` as the terminator. So, we branch from the current block
448// to the throw block and create a block for the remaining operations.
449static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc,
450 mlir::Value exceptionPtr = {},
451 mlir::FlatSymbolRefAttr typeInfo = {},
452 mlir::FlatSymbolRefAttr dtor = {}) {
453 mlir::Block *currentBlock = builder.getInsertionBlock();
454 mlir::Region *region = currentBlock->getParent();
455
456 if (currentBlock->empty()) {
457 cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
458 cir::UnreachableOp::create(builder, loc);
459 } else {
460 mlir::Block *throwBlock = builder.createBlock(region);
461
462 cir::ThrowOp::create(builder, loc, exceptionPtr, typeInfo, dtor);
463 cir::UnreachableOp::create(builder, loc);
464
465 builder.setInsertionPointToEnd(currentBlock);
466 cir::BrOp::create(builder, loc, throwBlock);
467 }
468
469 (void)builder.createBlock(region);
470}
471
472void CIRGenItaniumCXXABI::emitRethrow(CIRGenFunction &cgf, bool isNoReturn) {
473 // void __cxa_rethrow();
474 if (isNoReturn) {
475 CIRGenBuilderTy &builder = cgf.getBuilder();
476 assert(cgf.currSrcLoc && "expected source location");
477 mlir::Location loc = *cgf.currSrcLoc;
478 insertThrowAndSplit(builder, loc);
479 } else {
480 cgm.errorNYI("emitRethrow with isNoReturn false");
481 }
482}
483
485 switch (cgm.getASTContext().getCXXABIKind()) {
486 case TargetCXXABI::GenericItanium:
487 case TargetCXXABI::GenericAArch64:
488 return new CIRGenItaniumCXXABI(cgm);
489
490 case TargetCXXABI::AppleARM64:
491 // The general Itanium ABI will do until we implement something that
492 // requires special handling.
494 return new CIRGenItaniumCXXABI(cgm);
495
496 default:
497 llvm_unreachable("bad or NYI ABI kind");
498 }
499}
500
501cir::GlobalOp CIRGenItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *rd,
502 CharUnits vptrOffset) {
503 assert(vptrOffset.isZero() && "Itanium ABI only supports zero vptr offsets");
504 cir::GlobalOp &vtable = vtables[rd];
505 if (vtable)
506 return vtable;
507
508 // Queue up this vtable for possible deferred emission.
510
511 SmallString<256> name;
512 llvm::raw_svector_ostream out(name);
513 getMangleContext().mangleCXXVTable(rd, out);
514
515 const VTableLayout &vtLayout =
516 cgm.getItaniumVTableContext().getVTableLayout(rd);
517 mlir::Type vtableType = cgm.getVTables().getVTableType(vtLayout);
518
519 // Use pointer alignment for the vtable. Otherwise we would align them based
520 // on the size of the initializer which doesn't make sense as only single
521 // values are read.
522 unsigned ptrAlign = cgm.getItaniumVTableContext().isRelativeLayout()
523 ? 32
524 : cgm.getTarget().getPointerAlign(LangAS::Default);
525
526 vtable = cgm.createOrReplaceCXXRuntimeVariable(
527 cgm.getLoc(rd->getSourceRange()), name, vtableType,
528 cir::GlobalLinkageKind::ExternalLinkage,
529 cgm.getASTContext().toCharUnitsFromBits(ptrAlign));
530 // LLVM codegen handles unnamedAddr
532
533 // In MS C++ if you have a class with virtual functions in which you are using
534 // selective member import/export, then all virtual functions must be exported
535 // unless they are inline, otherwise a link error will result. To match this
536 // behavior, for such classes, we dllimport the vtable if it is defined
537 // externally and all the non-inline virtual methods are marked dllimport, and
538 // we dllexport the vtable if it is defined in this TU and all the non-inline
539 // virtual methods are marked dllexport.
540 if (cgm.getTarget().hasPS4DLLImportExport())
541 cgm.errorNYI(rd->getSourceRange(),
542 "getAddrOfVTable: PS4 DLL import/export");
543
544 cgm.setGVProperties(vtable, rd);
545 return vtable;
546}
547
548CIRGenCallee CIRGenItaniumCXXABI::getVirtualFunctionPointer(
549 CIRGenFunction &cgf, clang::GlobalDecl gd, Address thisAddr, mlir::Type ty,
550 SourceLocation srcLoc) {
551 CIRGenBuilderTy &builder = cgm.getBuilder();
552 mlir::Location loc = cgf.getLoc(srcLoc);
553 cir::PointerType tyPtr = builder.getPointerTo(ty);
554 auto *methodDecl = cast<CXXMethodDecl>(gd.getDecl());
555 mlir::Value vtable = cgf.getVTablePtr(loc, thisAddr, methodDecl->getParent());
556
557 uint64_t vtableIndex = cgm.getItaniumVTableContext().getMethodVTableIndex(gd);
558 mlir::Value vfunc{};
559 if (cgf.shouldEmitVTableTypeCheckedLoad(methodDecl->getParent())) {
560 cgm.errorNYI(loc, "getVirtualFunctionPointer: emitVTableTypeCheckedLoad");
561 } else {
563
564 mlir::Value vfuncLoad;
565 if (cgm.getItaniumVTableContext().isRelativeLayout()) {
567 cgm.errorNYI(loc, "getVirtualFunctionPointer: isRelativeLayout");
568 } else {
569 auto vtableSlotPtr = cir::VTableGetVirtualFnAddrOp::create(
570 builder, loc, builder.getPointerTo(tyPtr), vtable, vtableIndex);
571 vfuncLoad = builder.createAlignedLoad(loc, tyPtr, vtableSlotPtr,
572 cgf.getPointerAlign());
573 }
574
575 // Add !invariant.load md to virtual function load to indicate that
576 // function didn't change inside vtable.
577 // It's safe to add it without -fstrict-vtable-pointers, but it would not
578 // help in devirtualization because it will only matter if we will have 2
579 // the same virtual function loads from the same vtable load, which won't
580 // happen without enabled devirtualization with -fstrict-vtable-pointers.
581 if (cgm.getCodeGenOpts().OptimizationLevel > 0 &&
582 cgm.getCodeGenOpts().StrictVTablePointers) {
583 cgm.errorNYI(loc, "getVirtualFunctionPointer: strictVTablePointers");
584 }
585 vfunc = vfuncLoad;
586 }
587
588 CIRGenCallee callee(gd, vfunc.getDefiningOp());
589 return callee;
590}
591
592mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructorWithVTT(
593 CIRGenFunction &cgf, const CXXRecordDecl *vtableClass, BaseSubobject base,
594 const CXXRecordDecl *nearestVBase) {
595 assert((base.getBase()->getNumVBases() || nearestVBase != nullptr) &&
596 needsVTTParameter(cgf.curGD) && "This class doesn't have VTT");
597
598 // Get the secondary vpointer index.
599 uint64_t virtualPointerIndex =
600 cgm.getVTables().getSecondaryVirtualPointerIndex(vtableClass, base);
601
602 /// Load the VTT.
603 mlir::Value vttPtr = cgf.loadCXXVTT();
604 mlir::Location loc = cgf.getLoc(vtableClass->getSourceRange());
605 // Calculate the address point from the VTT, and the offset may be zero.
606 vttPtr = cgf.getBuilder().createVTTAddrPoint(loc, vttPtr.getType(), vttPtr,
607 virtualPointerIndex);
608 // And load the address point from the VTT.
609 auto vptrType = cir::VPtrType::get(cgf.getBuilder().getContext());
610 return cgf.getBuilder().createAlignedLoad(loc, vptrType, vttPtr,
611 cgf.getPointerAlign());
612}
613
614mlir::Value
615CIRGenItaniumCXXABI::getVTableAddressPoint(BaseSubobject base,
616 const CXXRecordDecl *vtableClass) {
617 cir::GlobalOp vtable = getAddrOfVTable(vtableClass, CharUnits());
618
619 // Find the appropriate vtable within the vtable group, and the address point
620 // within that vtable.
621 VTableLayout::AddressPointLocation addressPoint =
622 cgm.getItaniumVTableContext()
623 .getVTableLayout(vtableClass)
624 .getAddressPoint(base);
625
626 mlir::OpBuilder &builder = cgm.getBuilder();
627 auto vtablePtrTy = cir::VPtrType::get(builder.getContext());
628
629 return builder.create<cir::VTableAddrPointOp>(
630 cgm.getLoc(vtableClass->getSourceRange()), vtablePtrTy,
631 mlir::FlatSymbolRefAttr::get(vtable.getSymNameAttr()),
632 cir::AddressPointAttr::get(cgm.getBuilder().getContext(),
633 addressPoint.VTableIndex,
634 addressPoint.AddressPointIndex));
635}
636
637mlir::Value CIRGenItaniumCXXABI::getVTableAddressPointInStructor(
638 CIRGenFunction &cgf, const clang::CXXRecordDecl *vtableClass,
639 clang::BaseSubobject base, const clang::CXXRecordDecl *nearestVBase) {
640
641 if ((base.getBase()->getNumVBases() || nearestVBase != nullptr) &&
642 needsVTTParameter(cgf.curGD)) {
643 return getVTableAddressPointInStructorWithVTT(cgf, vtableClass, base,
644 nearestVBase);
645 }
646 return getVTableAddressPoint(base, vtableClass);
647}
648
649bool CIRGenItaniumCXXABI::isVirtualOffsetNeededForVTableField(
650 CIRGenFunction &cgf, CIRGenFunction::VPtr vptr) {
651 if (vptr.nearestVBase == nullptr)
652 return false;
653 return needsVTTParameter(cgf.curGD);
654}
655
656mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset(
657 mlir::Location loc, CIRGenFunction &cgf, Address thisAddr,
658 const CXXRecordDecl *classDecl, const CXXRecordDecl *baseClassDecl) {
659 CIRGenBuilderTy &builder = cgf.getBuilder();
660 mlir::Value vtablePtr = cgf.getVTablePtr(loc, thisAddr, classDecl);
661 mlir::Value vtableBytePtr = builder.createBitcast(vtablePtr, cgm.UInt8PtrTy);
662 CharUnits vbaseOffsetOffset =
663 cgm.getItaniumVTableContext().getVirtualBaseOffsetOffset(classDecl,
664 baseClassDecl);
665 mlir::Value offsetVal =
666 builder.getSInt64(vbaseOffsetOffset.getQuantity(), loc);
667 auto vbaseOffsetPtr = cir::PtrStrideOp::create(builder, loc, cgm.UInt8PtrTy,
668 vtableBytePtr, offsetVal);
669
670 mlir::Value vbaseOffset;
671 if (cgm.getItaniumVTableContext().isRelativeLayout()) {
673 cgm.errorNYI(loc, "getVirtualBaseClassOffset: relative layout");
674 } else {
675 mlir::Value offsetPtr = builder.createBitcast(
676 vbaseOffsetPtr, builder.getPointerTo(cgm.PtrDiffTy));
677 vbaseOffset = builder.createLoad(
678 loc, Address(offsetPtr, cgm.PtrDiffTy, cgf.getPointerAlign()));
679 }
680 return vbaseOffset;
681}
static void emitConstructorDestructorAlias(CIRGenModule &cgm, GlobalDecl aliasDecl, GlobalDecl targetDecl)
static void insertThrowAndSplit(mlir::OpBuilder &builder, mlir::Location loc, mlir::Value exceptionPtr={}, mlir::FlatSymbolRefAttr typeInfo={}, mlir::FlatSymbolRefAttr dtor={})
static StructorCIRGen getCIRGenToUse(CIRGenModule &cgm, const CXXMethodDecl *md)
Defines the clang::Expr interface and subclasses for C++ expressions.
cir::PointerType getPointerTo(mlir::Type ty)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
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:737
TargetCXXABI::Kind getCXXABIKind() const
Return the C++ ABI kind that should be used.
const CXXRecordDecl * getBase() const
getBase - Returns the base class declaration.
mlir::Value getPointer() const
Definition Address.h:81
cir::ConstantOp getSInt64(uint64_t c, mlir::Location loc)
cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr, llvm::MaybeAlign align)
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.
static CIRGenCallee forDirect(mlir::Operation *funcPtr, const CIRGenCalleeInfo &abstractInfo=CIRGenCalleeInfo())
Definition CIRGenCall.h:90
clang::GlobalDecl curGD
The GlobalDecl for the current function being compiled or the global variable currently being initial...
const clang::Decl * curFuncDecl
Address getAddrOfLocalVar(const clang::VarDecl *vd)
Return the address of a local variable.
mlir::Value getVTTParameter(GlobalDecl gd, bool forVirtualBase, bool delegating)
Return the VTT parameter that should be passed to a base constructor/destructor with virtual bases.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
mlir::Value loadCXXVTT()
Load the VTT parameter to base constructors/destructors have virtual bases.
mlir::Value getVTablePtr(mlir::Location loc, Address thisAddr, const clang::CXXRecordDecl *vtableClass)
Return the Value of the vtable pointer member pointed to by thisAddr.
bool shouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *rd)
Returns whether we should perform a type checked load when loading a virtual function for virtual cal...
CIRGenBuilderTy & getBuilder()
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.
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
const clang::TargetInfo & getTarget() const
void emitAliasForGlobal(llvm::StringRef mangledName, mlir::Operation *op, GlobalDecl aliasGD, cir::FuncOp aliasee, cir::GlobalLinkageKind linkage)
cir::GlobalLinkageKind getFunctionLinkage(GlobalDecl gd)
const clang::CodeGenOptions & getCodeGenOpts() const
mlir::Operation * getGlobalValue(llvm::StringRef ref)
mlir::Operation * getAddrOfGlobal(clang::GlobalDecl gd, ForDefinition_t isForDefinition=NotForDefinition)
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.
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2129
bool isVirtual() const
Definition DeclCXX.h:2184
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2255
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool isAbstract() const
Determine whether this class has a pure virtual function.
Definition DeclCXX.h:1221
unsigned getNumVBases() const
Retrieves the number of virtual base classes of this class.
Definition DeclCXX.h:623
static CanQual< Type > CreateUnsafe(QualType Other)
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
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
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
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:4490
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:5470
const VTableLayout & getVTableLayout(const CXXRecordDecl *RD)
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:294
Encodes a location in the source.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:4834
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h:3544
static bool isLocalLinkage(GlobalLinkageKind linkage)
Definition CIROpsEnums.h:51
static LLVM_ATTRIBUTE_UNUSED 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:93
static LLVM_ATTRIBUTE_UNUSED bool isValidLinkage(GlobalLinkageKind gl)
static LLVM_ATTRIBUTE_UNUSED bool isWeakForLinker(GlobalLinkageKind linkage)
Whether the definition of this global may be replaced at link time.
CIRGenCXXABI * CreateCIRGenItaniumCXXABI(CIRGenModule &cgm)
Creates and Itanium-family ABI.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
The JSON file list parser is used to communicate input to InstallAPI.
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
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
U cast(CodeGen::Address addr)
Definition Address.h:327
unsigned long uint64_t
static bool addressSpace()
static bool opGlobalUnnamedAddr()
static bool vtableEmitMetadata()
static bool emitTypeMetadataCodeForVCall()
static bool cxxabiAppleARM64CXXABI()
static bool deferredVtables()
static bool cxxabiUseARMGuardVarABI()
static bool cxxabiUseARMMethodPtrABI()
static bool vtableRelativeLayout()
const clang::CXXRecordDecl * nearestVBase
clang::CharUnits getPointerAlign() const