clang 24.0.0git
CIRGenVTables.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 contains code dealing with C++ code generation of virtual tables.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenVTables.h"
14
15#include "CIRGenCXXABI.h"
16#include "CIRGenModule.h"
17#include "mlir/IR/Types.h"
20#include "llvm/ADT/SmallVector.h"
21
22using namespace llvm;
23using namespace clang;
24using namespace clang::CIRGen;
25
27 : cgm(cgm), vtContext(cgm.getASTContext().getVTableContext()) {}
28
29cir::FuncOp CIRGenModule::getAddrOfThunk(StringRef name, mlir::Type fnTy,
30 GlobalDecl gd) {
31 return getOrCreateCIRFunction(name, fnTy, gd, /*forVTable=*/true,
32 /*dontDefer=*/true, /*isThunk=*/true);
33}
34
35static void setThunkProperties(CIRGenModule &cgm, const ThunkInfo &thunk,
36 cir::FuncOp thunkFn, bool forVTable,
37 GlobalDecl gd) {
38 cgm.setFunctionLinkage(gd, thunkFn);
39 cgm.getCXXABI().setThunkLinkage(thunkFn, forVTable, gd,
40 !thunk.Return.isEmpty());
41
42 // Set the right visibility.
43 cgm.setGVProperties(thunkFn, cast<NamedDecl>(gd.getDecl()));
44
45 if (!cgm.getCXXABI().exportThunk()) {
47 cgm.setDSOLocal(static_cast<mlir::Operation *>(thunkFn));
48 }
49
50 if (cgm.supportsCOMDAT() && thunkFn.isWeakForLinker())
51 thunkFn.setComdat(true);
52}
53
55 mlir::Type ptrTy = builder.getUInt8PtrTy();
57 return ptrTy;
58}
59
60mlir::Type CIRGenVTables::getVTableComponentType() {
61 return cgm.getVTableComponentType();
62}
63
66 mlir::Type componentType = getVTableComponentType();
67 for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i)
68 tys.push_back(cir::ArrayType::get(componentType, layout.getVTableSize(i)));
69
70 // FIXME(cir): should VTableLayout be encoded like we do for some
71 // AST nodes?
72 return cgm.getBuilder().getAnonRecordTy(
73 tys, /*packed=*/false, cir::RecordType::getAllDataKinds(tys));
74}
75
76/// At this point in the translation unit, does it appear that can we
77/// rely on the vtable being defined elsewhere in the program?
78///
79/// The response is really only definitive when called at the end of
80/// the translation unit.
81///
82/// The only semantic restriction here is that the object file should
83/// not contain a vtable definition when that vtable is defined
84/// strongly elsewhere. Otherwise, we'd just like to avoid emitting
85/// vtables when unnecessary.
86/// TODO(cir): this should be merged into common AST helper for codegen.
88 assert(rd->isDynamicClass() && "Non-dynamic classes have no VTable.");
89
90 // We always synthesize vtables if they are needed in the MS ABI. MSVC doesn't
91 // emit them even if there is an explicit template instantiation.
92 if (cgm.getTarget().getCXXABI().isMicrosoft())
93 return false;
94
95 // If we have an explicit instantiation declaration (and not a
96 // definition), the vtable is defined elsewhere.
99 return true;
100
101 // Otherwise, if the class is an instantiated template, the
102 // vtable must be defined here.
103 if (tsk == TSK_ImplicitInstantiation ||
105 return false;
106
107 // Otherwise, if the class doesn't have a key function (possibly
108 // anymore), the vtable must be defined here.
109 const CXXMethodDecl *keyFunction =
111 if (!keyFunction)
112 return false;
113
114 // Otherwise, if we don't have a definition of the key function, the
115 // vtable must be defined somewhere else.
116 return !keyFunction->hasBody();
117}
118
119/// This is a callback from Sema to tell us that a particular vtable is
120/// required to be emitted in this translation unit.
121///
122/// This is only called for vtables that _must_ be emitted (mainly due to key
123/// functions). For weak vtables, CodeGen tracks when they are needed and
124/// emits them as-needed.
126 vtables.generateClassData(rd);
127}
128
131
132 if (rd->getNumVBases())
133 cgm.getCXXABI().emitVirtualInheritanceTables(rd);
134
135 cgm.getCXXABI().emitVTableDefinitions(*this, rd);
136}
137
138mlir::Attribute CIRGenVTables::getVTableComponent(
139 const VTableLayout &layout, unsigned componentIndex, mlir::Attribute rtti,
140 unsigned &nextVTableThunkIndex, unsigned vtableAddressPoint,
141 bool vtableHasLocalLinkage) {
142 const VTableComponent &component = layout.vtable_components()[componentIndex];
143
144 CIRGenBuilderTy builder = cgm.getBuilder();
145
147
148 switch (component.getKind()) {
150 return builder.getConstNullPtrAttr(builder.getUInt8PtrTy());
151
153 return builder.getConstPtrAttr(builder.getUInt8PtrTy(),
154 component.getVCallOffset().getQuantity());
155
157 return builder.getConstPtrAttr(builder.getUInt8PtrTy(),
158 component.getVBaseOffset().getQuantity());
159
161 return builder.getConstPtrAttr(builder.getUInt8PtrTy(),
162 component.getOffsetToTop().getQuantity());
163
165 assert((mlir::isa<cir::GlobalViewAttr>(rtti) ||
166 mlir::isa<cir::ConstPtrAttr>(rtti)) &&
167 "expected GlobalViewAttr or ConstPtrAttr");
168 return rtti;
169
173 GlobalDecl gd = component.getGlobalDecl(
175 cgm.getASTContext().getLangOpts()));
176
178
179 auto getSpecialVirtFn = [&](StringRef name) -> cir::FuncOp {
181
182 if (cgm.getLangOpts().OpenMP && cgm.getLangOpts().OpenMPIsTargetDevice &&
183 cgm.getTriple().isNVPTX())
184 cgm.errorNYI(gd.getDecl()->getSourceRange(),
185 "getVTableComponent for OMP Device NVPTX");
186
187 cir::FuncType fnTy =
188 cgm.getBuilder().getFuncType({}, cgm.getBuilder().getVoidTy());
189 cir::FuncOp fnPtr = cgm.createRuntimeFunction(fnTy, name);
190
192 return fnPtr;
193 };
194
195 cir::FuncOp fnPtr;
196 if (cast<CXXMethodDecl>(gd.getDecl())->isPureVirtual()) {
197 if (!pureVirtualFn)
198 pureVirtualFn =
199 getSpecialVirtFn(cgm.getCXXABI().getPureVirtualCallName());
200 fnPtr = pureVirtualFn;
201 } else if (cast<CXXMethodDecl>(gd.getDecl())->isDeleted()) {
202 if (!deletedVirtualFn)
203 deletedVirtualFn =
204 getSpecialVirtFn(cgm.getCXXABI().getDeletedVirtualCallName());
205 fnPtr = deletedVirtualFn;
206 } else if (nextVTableThunkIndex < layout.vtable_thunks().size() &&
207 layout.vtable_thunks()[nextVTableThunkIndex].first ==
208 componentIndex) {
209 const ThunkInfo &thunkInfo =
210 layout.vtable_thunks()[nextVTableThunkIndex].second;
211 nextVTableThunkIndex++;
212 fnPtr = maybeEmitThunk(gd, thunkInfo, /*forVTable=*/true);
214 } else {
215 // Otherwise we can use the method definition directly.
216 cir::FuncType fnTy = cgm.getTypes().getFunctionType(gd);
217 fnPtr = cgm.getAddrOfFunction(gd, fnTy, /*ForVTable=*/true);
218 }
219
220 return cir::GlobalViewAttr::get(
221 builder.getUInt8PtrTy(),
222 mlir::FlatSymbolRefAttr::get(fnPtr.getSymNameAttr()));
223 }
224 }
225
226 llvm_unreachable("Unexpected vtable component kind");
227}
228
229void CIRGenVTables::createVTableInitializer(cir::GlobalOp &vtableOp,
230 const clang::VTableLayout &layout,
231 mlir::Attribute rtti,
232 bool vtableHasLocalLinkage) {
233 mlir::Type componentType = getVTableComponentType();
234
235 const llvm::SmallVectorImpl<unsigned> &addressPoints =
236 layout.getAddressPointIndices();
237 unsigned nextVTableThunkIndex = 0;
238
239 mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();
240
242 for (auto [vtableIndex, addressPoint] : llvm::enumerate(addressPoints)) {
243 // Build a ConstArrayAttr of the vtable components.
244 size_t vtableStart = layout.getVTableOffset(vtableIndex);
245 size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex);
247 components.reserve(vtableEnd - vtableStart);
248 for (size_t componentIndex : llvm::seq(vtableStart, vtableEnd))
249 components.push_back(
250 getVTableComponent(layout, componentIndex, rtti, nextVTableThunkIndex,
251 addressPoint, vtableHasLocalLinkage));
252 // Create a ConstArrayAttr to hold the components.
253 auto arr = cir::ConstArrayAttr::get(
254 cir::ArrayType::get(componentType, components.size()),
255 mlir::ArrayAttr::get(mlirContext, components));
256 vtables.push_back(arr);
257 }
258
259 // Create a ConstRecordAttr to hold the component array.
260 const auto members = mlir::ArrayAttr::get(mlirContext, vtables);
261 cir::ConstRecordAttr record = cgm.getBuilder().getAnonConstRecord(members);
262
263 // Create a VTableAttr
264 auto vtableAttr = cir::VTableAttr::get(record.getType(), record.getMembers());
265
266 // Add the vtable initializer to the vtable global op.
267 cgm.setInitializer(vtableOp, vtableAttr);
268}
269
271 const CXXRecordDecl *rd, const BaseSubobject &base, bool baseIsVirtual,
272 cir::GlobalLinkageKind linkage, VTableAddressPointsMapTy &addressPoints) {
274
275 std::unique_ptr<VTableLayout> vtLayout(
276 getItaniumVTableContext().createConstructionVTableLayout(
277 base.getBase(), base.getBaseOffset(), baseIsVirtual, rd));
278
279 // Add the address points.
280 addressPoints = vtLayout->getAddressPoints();
281
282 // Get the mangled construction vtable name.
283 SmallString<256> outName;
284 llvm::raw_svector_ostream out(outName);
285 cast<ItaniumMangleContext>(cgm.getCXXABI().getMangleContext())
286 .mangleCXXCtorVTable(rd, base.getBaseOffset().getQuantity(),
287 base.getBase(), out);
288 SmallString<256> name(outName);
289
291
292 cir::RecordType vtType = getVTableType(*vtLayout);
293
294 // Construction vtable symbols are not part of the Itanium ABI, so we cannot
295 // guarantee that they actually will be available externally. Instead, when
296 // emitting an available_externally VTT, we provide references to an internal
297 // linkage construction vtable. The ABI only requires complete-object vtables
298 // to be the same for all instances of a type, not construction vtables.
299 if (linkage == cir::GlobalLinkageKind::AvailableExternallyLinkage)
300 linkage = cir::GlobalLinkageKind::InternalLinkage;
301
302 llvm::Align align = cgm.getDataLayout().getABITypeAlign(vtType);
303 mlir::Location loc = cgm.getLoc(rd->getSourceRange());
304
305 // Create the variable that will hold the construction vtable.
306 cir::GlobalOp vtable = cgm.createOrReplaceCXXRuntimeVariable(
307 loc, name, vtType, linkage, CharUnits::fromQuantity(align));
308
309 // V-tables are always unnamed_addr.
311
312 mlir::Attribute rtti = cgm.getAddrOfRTTIDescriptor(
313 loc, cgm.getASTContext().getCanonicalTagType(base.getBase()));
314
315 // Create and set the initializer.
316 createVTableInitializer(vtable, *vtLayout, rtti,
317 cir::isLocalLinkage(vtable.getLinkage()));
318
319 // Set properties only after the initializer has been set to ensure that the
320 // GV is treated as definition and not declaration.
321 assert(!vtable.isDeclaration() && "Shouldn't set properties on declaration");
322 cgm.setGVProperties(vtable, rd);
323
326
327 return vtable;
328}
329
331 const CXXRecordDecl *rd);
332
333/// Compute the required linkage of the vtable for the given class.
334///
335/// Note that we only call this at the end of the translation unit.
336cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) {
337 if (!rd->isExternallyVisible())
338 return cir::GlobalLinkageKind::InternalLinkage;
339
340 // We're at the end of the translation unit, so the current key
341 // function is fully correct.
342 const CXXMethodDecl *keyFunction = astContext.getCurrentKeyFunction(rd);
343 if (keyFunction && !rd->hasAttr<DLLImportAttr>()) {
344 // If this class has a key function, use that to determine the
345 // linkage of the vtable.
346 const FunctionDecl *def = nullptr;
347 if (keyFunction->hasBody(def))
348 keyFunction = cast<CXXMethodDecl>(def);
349
350 // All of the cases below do something different with AppleKext enabled.
352 switch (keyFunction->getTemplateSpecializationKind()) {
353 case TSK_Undeclared:
355 assert(
356 (def || codeGenOpts.OptimizationLevel > 0 ||
357 codeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo) &&
358 "Shouldn't query vtable linkage without key function, "
359 "optimizations, or debug info");
360 if (!def && codeGenOpts.OptimizationLevel > 0)
361 return cir::GlobalLinkageKind::AvailableExternallyLinkage;
362
363 if (keyFunction->isInlined())
364 return !astContext.getLangOpts().AppleKext
365 ? cir::GlobalLinkageKind::LinkOnceODRLinkage
366 : cir::GlobalLinkageKind::InternalLinkage;
367 return cir::GlobalLinkageKind::ExternalLinkage;
368
370 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
371
373 return cir::GlobalLinkageKind::WeakODRLinkage;
374
376 return !def ? cir::GlobalLinkageKind::AvailableExternallyLinkage
377 : cir::GlobalLinkageKind::ExternalLinkage;
378 }
379 }
380 // -fapple-kext mode does not support weak linkage, so we must use
381 // internal linkage.
382 if (astContext.getLangOpts().AppleKext)
383 return cir::GlobalLinkageKind::InternalLinkage;
384
385 auto discardableODRLinkage = cir::GlobalLinkageKind::LinkOnceODRLinkage;
386 auto nonDiscardableODRLinkage = cir::GlobalLinkageKind::WeakODRLinkage;
387 if (rd->hasAttr<DLLExportAttr>()) {
388 // Cannot discard exported vtables.
389 discardableODRLinkage = nonDiscardableODRLinkage;
390 } else if (rd->hasAttr<DLLImportAttr>()) {
391 // Imported vtables are available externally.
392 discardableODRLinkage = cir::GlobalLinkageKind::AvailableExternallyLinkage;
393 nonDiscardableODRLinkage =
394 cir::GlobalLinkageKind::AvailableExternallyLinkage;
395 }
396
397 switch (rd->getTemplateSpecializationKind()) {
398 case TSK_Undeclared:
401 return discardableODRLinkage;
402
404 // Explicit instantiations in MSVC do not provide vtables, so we must emit
405 // our own.
406 if (getTarget().getCXXABI().isMicrosoft())
407 return discardableODRLinkage;
409 ? cir::GlobalLinkageKind::AvailableExternallyLinkage
410 : cir::GlobalLinkageKind::ExternalLinkage;
411
413 return nonDiscardableODRLinkage;
414 }
415
416 llvm_unreachable("Invalid TemplateSpecializationKind!");
417}
418
420 assert(rd->getNumVBases() && "Only classes with virtual bases need a VTT");
421
422 SmallString<256> outName;
423 llvm::raw_svector_ostream out(outName);
424 cast<ItaniumMangleContext>(cgm.getCXXABI().getMangleContext())
425 .mangleCXXVTT(rd, out);
426 StringRef name = outName.str();
427
428 // This will also defer the definition of the VTT.
429 (void)cgm.getCXXABI().getAddrOfVTable(rd, CharUnits());
430
431 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);
432
433 auto arrayType = cir::ArrayType::get(cgm.getBuilder().getUInt8PtrTy(),
434 builder.getVTTComponents().size());
435 llvm::Align align =
436 cgm.getDataLayout().getABITypeAlign(cgm.getBuilder().getUInt8PtrTy());
437 cir::GlobalOp vtt = cgm.createOrReplaceCXXRuntimeVariable(
438 cgm.getLoc(rd->getSourceRange()), name, arrayType,
439 cir::GlobalLinkageKind::ExternalLinkage, CharUnits::fromQuantity(align));
440 cgm.setGVProperties(vtt, rd);
441 return vtt;
442}
443
444static cir::GlobalOp
446 const CXXRecordDecl *mostDerivedClass,
447 const VTTVTable &vtable, cir::GlobalLinkageKind linkage,
448 VTableLayout::AddressPointsMapTy &addressPoints) {
449 if (vtable.getBase() == mostDerivedClass) {
450 assert(vtable.getBaseOffset().isZero() &&
451 "Most derived class vtable must have a zero offset!");
452 // This is a regular vtable.
453 return cgm.getCXXABI().getAddrOfVTable(mostDerivedClass, CharUnits());
454 }
455 return cgvt.generateConstructionVTable(
456 mostDerivedClass, vtable.getBaseSubobject(), vtable.isVirtual(), linkage,
457 addressPoints);
458}
459
460/// Emit the definition of the given vtable.
461void CIRGenVTables::emitVTTDefinition(cir::GlobalOp vttOp,
462 cir::GlobalLinkageKind linkage,
463 const CXXRecordDecl *rd) {
464 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/true);
465
466 mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();
467
468 auto arrayType = cir::ArrayType::get(cgm.getBuilder().getUInt8PtrTy(),
469 builder.getVTTComponents().size());
470
472 SmallVector<VTableAddressPointsMapTy> vtableAddressPoints;
473 for (const VTTVTable &vtt : builder.getVTTVTables()) {
474 vtableAddressPoints.push_back(VTableAddressPointsMapTy());
475 vtables.push_back(getAddrOfVTTVTable(*this, cgm, rd, vtt, linkage,
476 vtableAddressPoints.back()));
477 }
478
479 SmallVector<mlir::Attribute> vttComponents;
480 for (const VTTComponent &vttComponent : builder.getVTTComponents()) {
481 const VTTVTable &vttVT = builder.getVTTVTables()[vttComponent.VTableIndex];
482 cir::GlobalOp vtable = vtables[vttComponent.VTableIndex];
484 if (vttVT.getBase() == rd) {
485 // Just get the address point for the regular vtable.
486 addressPoint =
488 vttComponent.VTableBase);
489 } else {
490 addressPoint = vtableAddressPoints[vttComponent.VTableIndex].lookup(
491 vttComponent.VTableBase);
492 assert(addressPoint.AddressPointIndex != 0 &&
493 "Did not find ctor vtable address point!");
494 }
495
496 mlir::Attribute indices[2] = {
497 cgm.getBuilder().getI32IntegerAttr(addressPoint.VTableIndex),
498 cgm.getBuilder().getI32IntegerAttr(addressPoint.AddressPointIndex),
499 };
500
501 auto indicesAttr = mlir::ArrayAttr::get(mlirContext, indices);
502 cir::GlobalViewAttr init = cgm.getBuilder().getGlobalViewAttr(
503 cgm.getBuilder().getUInt8PtrTy(), vtable, indicesAttr);
504
505 vttComponents.push_back(init);
506 }
507
508 auto init = cir::ConstArrayAttr::get(
509 arrayType, mlir::ArrayAttr::get(mlirContext, vttComponents));
510
511 vttOp.setInitialValueAttr(init);
512
513 // Set the correct linkage.
514 vttOp.setLinkage(linkage);
515 mlir::SymbolTable::setSymbolVisibility(
516 vttOp, CIRGenModule::getMLIRVisibility(vttOp));
517
518 if (cgm.supportsCOMDAT() && vttOp.isWeakForLinker())
519 vttOp.setComdat(true);
520}
521
523 BaseSubobject base) {
524 BaseSubobjectPairTy classSubobjectPair(rd, base);
525
526 SubVTTIndiciesMapTy::iterator it = subVTTIndicies.find(classSubobjectPair);
527 if (it != subVTTIndicies.end())
528 return it->second;
529
530 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);
531
532 for (const auto &entry : builder.getSubVTTIndices()) {
533 // Insert all indices.
534 BaseSubobjectPairTy subclassSubobjectPair(rd, entry.first);
535
536 subVTTIndicies.insert(std::make_pair(subclassSubobjectPair, entry.second));
537 }
538
539 it = subVTTIndicies.find(classSubobjectPair);
540 assert(it != subVTTIndicies.end() && "Did not find index!");
541
542 return it->second;
543}
544
546 BaseSubobject base) {
547 auto it = secondaryVirtualPointerIndices.find(std::make_pair(rd, base));
548
549 if (it != secondaryVirtualPointerIndices.end())
550 return it->second;
551
552 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);
553
554 // Insert all secondary vpointer indices.
555 for (const auto &entry : builder.getSecondaryVirtualPointerIndices()) {
556 std::pair<const CXXRecordDecl *, BaseSubobject> pair =
557 std::make_pair(rd, entry.first);
558
559 secondaryVirtualPointerIndices.insert(std::make_pair(pair, entry.second));
560 }
561
562 it = secondaryVirtualPointerIndices.find(std::make_pair(rd, base));
563 assert(it != secondaryVirtualPointerIndices.end() && "Did not find index!");
564
565 return it->second;
566}
567
569 RValue rv, const ThunkInfo &thunk) {
570 // Emit the return adjustment. For non-reference pointer returns, match
571 // classic codegen: skip the adjustment when the returned pointer is null.
572 bool nullCheckValue = !resultType->isReferenceType();
573 mlir::Value returnValue = rv.getValue();
574
575 const CXXRecordDecl *classDecl =
576 resultType->getPointeeType()->getAsCXXRecordDecl();
577 CharUnits classAlign = cgf.cgm.getClassPointerAlignment(classDecl);
578 mlir::Type pointeeType = cgf.convertTypeForMem(resultType->getPointeeType());
579 CIRGenBuilderTy &builder = cgf.getBuilder();
580 mlir::Location loc = returnValue.getLoc();
581
582 if (!nullCheckValue) {
583 returnValue = cgf.cgm.getCXXABI().performReturnAdjustment(
584 cgf, Address(returnValue, pointeeType, classAlign), classDecl,
585 thunk.Return);
586 return RValue::get(returnValue);
587 }
588
589 mlir::Value isNotNull = builder.createPtrIsNotNull(returnValue);
590 returnValue =
591 cir::TernaryOp::create(
592 builder, loc, isNotNull,
593 [&](mlir::OpBuilder &, mlir::Location) {
594 mlir::Value adjusted = cgf.cgm.getCXXABI().performReturnAdjustment(
595 cgf, Address(returnValue, pointeeType, classAlign), classDecl,
596 thunk.Return);
597 builder.createYield(loc, adjusted);
598 },
599 [&](mlir::OpBuilder &, mlir::Location) {
600 mlir::Value nullVal =
601 builder.getNullPtr(returnValue.getType(), loc).getResult();
602 builder.createYield(loc, nullVal);
603 })
604 .getResult();
605
606 return RValue::get(returnValue);
607}
608
610 const CIRGenFunctionInfo &fnInfo,
611 bool isUnprototyped) {
612 assert(!curGD.getDecl() && "curGD was already set!");
613 curGD = gd;
614 curFuncIsThunk = true;
615
616 // Build FunctionArgs.
617 const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl());
618 QualType thisType = md->getThisType();
619 QualType resultType;
620 if (isUnprototyped)
621 resultType = cgm.getASTContext().VoidTy;
622 else if (cgm.getCXXABI().hasThisReturn(gd))
623 resultType = thisType;
624 else if (cgm.getCXXABI().hasMostDerivedReturn(gd))
625 resultType = cgm.getASTContext().VoidPtrTy;
626 else
627 resultType = md->getType()->castAs<FunctionProtoType>()->getReturnType();
628 FunctionArgList functionArgs;
629
630 // Create the implicit 'this' parameter declaration.
631 cgm.getCXXABI().buildThisParam(*this, functionArgs);
632
633 // Add the rest of the parameters, if we have a prototype to work with.
634 if (!isUnprototyped) {
635 functionArgs.append(md->param_begin(), md->param_end());
636
638 cgm.getCXXABI().addImplicitStructorParams(*this, resultType,
639 functionArgs);
640 }
641
643
644 // Start defining the function.
645 cir::FuncType funcType = cgm.getTypes().getFunctionType(fnInfo);
646 startFunction(GlobalDecl(), resultType, fn, funcType, functionArgs,
647 md->getLocation(), md->getLocation());
648 // TODO(cir): Move this into startFunction.
649 curFnInfo = &fnInfo;
651
652 // Since we didn't pass a GlobalDecl to startFunction, do this ourselves.
653 cgm.getCXXABI().emitInstanceFunctionProlog(md->getLocation(), *this);
655 curCodeDecl = md;
656 curFuncDecl = md;
657}
658
660 // Clear these to restore the invariants expected by
661 // startFunction/finishFunction.
662 curCodeDecl = nullptr;
663 curFuncDecl = nullptr;
664
666}
667
669 SourceRange fnLoc,
670 const ThunkInfo *thunk,
671 bool isUnprototyped) {
672 assert(isa<CXXMethodDecl>(curGD.getDecl()) &&
673 "Please use a new CGF for this thunk");
674 const CXXMethodDecl *md = cast<CXXMethodDecl>(curGD.getDecl());
675
676 // Determine the this pointer class (may differ from md's class for thunks).
677 const CXXRecordDecl *thisValueClass =
679 if (thunk)
680 thisValueClass = thunk->ThisType->getPointeeCXXRecordDecl();
681
682 mlir::Value adjustedThisPtr =
683 thunk ? cgm.getCXXABI().performThisAdjustment(*this, loadCXXThisAddress(),
684 thisValueClass, *thunk)
685 : loadCXXThis();
686
687 // If perfect forwarding is required a variadic method, a method using
688 // inalloca, or an unprototyped thunk, use musttail. Emit an error if this
689 // thunk requires a return adjustment, since that is impossible with musttail.
691 if ((curFnInfo && curFnInfo->isVariadic()) || isUnprototyped) {
692 // Error if return adjustment is needed (can't do with musttail).
693 if (thunk && !thunk->Return.isEmpty()) {
694 if (isUnprototyped)
695 cgm.errorUnsupported(
696 md, "return-adjusting thunk with incomplete parameter type");
697 else if (curFnInfo && curFnInfo->isVariadic())
698 llvm_unreachable("shouldn't try to emit musttail return-adjusting "
699 "thunks for variadic functions");
700 else
701 cgm.errorUnsupported(
702 md, "non-trivial argument copy for return-adjusting thunk");
703 }
704 emitMustTailThunk(curGD, adjustedThisPtr, callee);
705 return;
706 }
707
708 // Build the call argument list.
709 CallArgList callArgs;
710 QualType thisType = md->getThisType();
711 callArgs.add(RValue::get(adjustedThisPtr), thisType);
712
714 cgm.getCXXABI().adjustCallArgsForDestructorThunk(*this, curGD, callArgs);
715
716#ifndef NDEBUG
717 unsigned prefixArgs = callArgs.size() - 1;
718#endif
719
720 // Add the rest of the method parameters.
721 for (const ParmVarDecl *pd : md->parameters())
722 emitDelegateCallArg(callArgs, pd, SourceLocation());
723
724 const FunctionProtoType *fpt = md->getType()->castAs<FunctionProtoType>();
725
726#ifndef NDEBUG
727 const CIRGenFunctionInfo &callFnInfo = cgm.getTypes().arrangeCXXMethodCall(
728 callArgs, fpt, RequiredArgs::getFromProtoWithExtraSlots(fpt, 1),
729 prefixArgs);
730 assert(callFnInfo.argTypeSize() == curFnInfo->argTypeSize());
731#endif
732
733 // Determine whether we have a return value slot to use.
734 QualType resultType = cgm.getCXXABI().hasThisReturn(curGD) ? thisType
735 : cgm.getCXXABI().hasMostDerivedReturn(curGD)
736 ? cgm.getASTContext().VoidPtrTy
737 : fpt->getReturnType();
738
739 ReturnValueSlot slot;
740 // This should also be tracking volatile, unused, and externally destructed.
742 if (!resultType->isVoidType() && hasAggregateEvaluationKind(resultType))
744
745 // Now emit our call.
746 CIRGenCallee cirCallee = CIRGenCallee::forDirect(callee, curGD);
747 mlir::Location loc = builder.getUnknownLoc();
748 RValue rv = emitCall(*curFnInfo, cirCallee, slot, callArgs,
749 /*callOrTryCall=*/nullptr, /*isMustTail=*/false, fnLoc);
750
751 // Consider return adjustment if we have ThunkInfo.
752 if (thunk && !thunk->Return.isEmpty())
753 rv = performReturnAdjustment(*this, resultType, rv, *thunk);
754 else
756
757 // Emit return. For aggregate returns the call has already written the
758 // result through the slot bound to returnValue above; emit the
759 // corresponding load+return here rather than leaving the function to
760 // fall off the end and have LexicalScope::emitImplicitReturn drop a
761 // `cir.trap` / `cir.unreachable` in its place (which would silently
762 // discard the result we just stored).
763 if (!resultType->isVoidType()) {
764 if (slot.isNull())
765 cgm.getCXXABI().emitReturnFromThunk(*this, rv, resultType);
766 else
767 emitReturnOfRValue(loc, rv, resultType);
768 }
769
770 // Disable final ARC autorelease.
772
773 finishThunk();
774}
775
777 mlir::Value adjustedThisPtr,
778 cir::FuncOp callee) {
779 // Forward all function arguments, replacing 'this' with the adjusted pointer.
780 // The call is marked musttail so varargs are forwarded correctly.
781 mlir::Block *entryBlock = getCurFunctionEntryBlock();
783 for (mlir::BlockArgument arg : entryBlock->getArguments())
784 args.push_back(arg);
785
786 // Replace the 'this' argument (first arg) with the adjusted pointer.
787 assert(!args.empty() && "thunk must have at least 'this' argument");
788 if (adjustedThisPtr.getType() != args[0].getType())
789 adjustedThisPtr = builder.createBitcast(adjustedThisPtr, args[0].getType());
790 args[0] = adjustedThisPtr;
791
792 mlir::Location loc = curFn->getLoc();
793 cir::FuncType calleeTy = callee.getFunctionType();
794 mlir::Type retTy = calleeTy.getReturnType();
795
796 cir::CallOp call = builder.createCallOp(loc, callee, args);
797 call->setAttr(cir::CIRDialect::getMustTailAttrName(),
798 mlir::UnitAttr::get(builder.getContext()));
799
800 if (isa<cir::VoidType>(retTy))
801 cir::ReturnOp::create(builder, loc);
802 else
803 cir::ReturnOp::create(builder, loc, call->getResult(0));
804
805 finishThunk();
806}
807
809 const CIRGenFunctionInfo &fnInfo,
810 GlobalDecl gd, const ThunkInfo &thunk,
811 bool isUnprototyped) {
812 // Create entry block and set up the builder's insertion point.
813 // This must be done before calling startThunk() which calls startFunction().
814 assert(fn.isDeclaration() && "Function already has body?");
815 mlir::Block *entryBb = fn.addEntryBlock();
816 builder.setInsertionPointToStart(entryBb);
817
818 // Create a scope in the symbol table to hold variable declarations.
819 // This is required before startFunction processes parameters, as it will
820 // insert them into the symbolTable (ScopedHashTable) which requires an
821 // active scope.
823
824 // Create lexical scope - must stay alive for entire thunk generation.
825 // startFunction() requires currLexScope to be set.
826 SourceLocRAIIObject locRAII(*this, fnLoc);
827 LexicalScope lexScope{*this, fn.getLoc(), entryBb};
828
829 startThunk(fn, gd, fnInfo, isUnprototyped);
831
832 // Get our callee. Use a placeholder type if this method is unprototyped so
833 // that CIRGenModule doesn't try to set attributes.
834 mlir::Type ty;
835 if (isUnprototyped)
836 cgm.errorNYI("unprototyped thunk placeholder type");
837 else
838 ty = cgm.getTypes().getFunctionType(fnInfo);
839
840 cir::FuncOp calleeOp = cgm.getAddrOfFunction(gd, ty, /*forVTable=*/true);
841
842 // Make the call and return the result.
843 emitCallAndReturnForThunk(calleeOp, fnLoc, &thunk, isUnprototyped);
844}
845
847 bool isUnprototyped, bool forVTable) {
848 // Always emit thunks in the MS C++ ABI. We cannot rely on other TUs to
849 // provide thunks for us.
850 if (cgm.getTarget().getCXXABI().isMicrosoft())
851 return true;
852
853 // In the Itanium C++ ABI, vtable thunks are provided by TUs that provide
854 // definitions of the main method. Therefore, emitting thunks with the vtable
855 // is purely an optimization. Emit the thunk if optimizations are enabled and
856 // all of the parameter types are complete.
857 if (forVTable)
858 return cgm.getCodeGenOpts().OptimizationLevel && !isUnprototyped;
859
860 // Always emit thunks along with the method definition.
861 return true;
862}
863
865 const ThunkInfo &thunkAdjustments,
866 bool forVTable) {
867 const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl());
868 SmallString<256> name;
869 MangleContext &mCtx = cgm.getCXXABI().getMangleContext();
870
871 llvm::raw_svector_ostream out(name);
872 if (const CXXDestructorDecl *dd = dyn_cast<CXXDestructorDecl>(md)) {
873 mCtx.mangleCXXDtorThunk(dd, gd.getDtorType(), thunkAdjustments,
874 /*elideOverrideInfo=*/false, out);
875 } else {
876 mCtx.mangleThunk(md, thunkAdjustments, /*elideOverrideInfo=*/false, out);
877 }
878
879 if (cgm.getASTContext().useAbbreviatedThunkName(gd, name.str())) {
880 name = "";
881 if (const CXXDestructorDecl *dd = dyn_cast<CXXDestructorDecl>(md))
882 mCtx.mangleCXXDtorThunk(dd, gd.getDtorType(), thunkAdjustments,
883 /*elideOverrideInfo=*/true, out);
884 else
885 mCtx.mangleThunk(md, thunkAdjustments, /*elideOverrideInfo=*/true, out);
886 }
887
888 cir::FuncType thunkVTableTy = cgm.getTypes().getFunctionType(gd);
889 cir::FuncOp thunk = cgm.getAddrOfThunk(name, thunkVTableTy, gd);
890
891 // If we don't need to emit a definition, return this declaration as is.
892 bool isUnprototyped = !cgm.getTypes().isFuncTypeConvertible(
893 md->getType()->castAs<FunctionType>());
894 if (!shouldEmitVTableThunk(cgm, md, isUnprototyped, forVTable))
895 return thunk;
896
897 // Arrange a function prototype appropriate for a function definition. In some
898 // cases in the MS ABI, we may need to build an unprototyped musttail thunk.
899 const CIRGenFunctionInfo &fnInfo =
900 isUnprototyped ? (cgm.errorNYI("unprototyped must-tail thunk"),
901 cgm.getTypes().arrangeGlobalDeclaration(gd))
902 : cgm.getTypes().arrangeGlobalDeclaration(gd);
903 cir::FuncType thunkFnTy = cgm.getTypes().getFunctionType(fnInfo);
904
905 // This is to replace OG's casting to a function, keeping it here to
906 // streamline the 1-to-1 mapping from OG starting below.
907 cir::FuncOp thunkFn = thunk;
908 if (thunk.getFunctionType() != thunkFnTy) {
909 cir::FuncOp oldThunkFn = thunkFn;
910
911 assert(oldThunkFn.isDeclaration() && "Shouldn't replace non-declaration");
912
913 // Remove the name from the old thunk function and get a new thunk.
914 cgm.eraseGlobalSymbol(oldThunkFn);
915 oldThunkFn.setName(StringRef());
916 thunkFn =
917 cir::FuncOp::create(cgm.getBuilder(), thunk->getLoc(), name.str(),
918 thunkFnTy, cir::GlobalLinkageKind::ExternalLinkage);
919 cgm.insertGlobalSymbol(thunkFn);
920 cgm.setCIRFunctionAttributes(md, fnInfo, thunkFn, /*isThunk=*/false);
921
922 if (!oldThunkFn->use_empty())
923 oldThunkFn->replaceAllUsesWith(thunkFn);
924
925 // Remove the old thunk.
926 oldThunkFn->erase();
927 }
928
929 bool abiHasKeyFunctions = cgm.getTarget().getCXXABI().hasKeyFunctions();
930 bool useAvailableExternallyLinkage = forVTable && abiHasKeyFunctions;
931
932 // If the type of the underlying GlobalValue is wrong, we'll have to replace
933 // it. It should be a declaration.
934 if (!thunkFn.isDeclaration()) {
935 if (!abiHasKeyFunctions || useAvailableExternallyLinkage) {
936 // There is already a thunk emitted for this function, do nothing.
937 return thunkFn;
938 }
939
940 setThunkProperties(cgm, thunkAdjustments, thunkFn, forVTable, gd);
941 return thunkFn;
942 }
943
944 // TODO(cir): Add "thunk" attribute if unprototyped.
945
946 cgm.setCIRFunctionAttributesForDefinition(cast<FunctionDecl>(gd.getDecl()),
947 thunkFn);
948
949 // Thunks for variadic methods are special because in general variadic
950 // arguments cannot be perfectly forwarded. In the general case, clang
951 // implements such thunks by cloning the original function body. However, for
952 // thunks with no return adjustment on targets that support musttail, we can
953 // use musttail to perfectly forward the variadic arguments.
954 bool shouldCloneVarArgs = false;
955 if (!isUnprototyped && thunkFn.getFunctionType().isVarArg()) {
956 shouldCloneVarArgs = true;
957 if (thunkAdjustments.Return.isEmpty()) {
958 switch (cgm.getTriple().getArch()) {
959 case llvm::Triple::x86_64:
960 case llvm::Triple::x86:
961 case llvm::Triple::aarch64:
962 shouldCloneVarArgs = false;
963 break;
964 default:
965 break;
966 }
967 }
968 }
969
970 if (shouldCloneVarArgs) {
971 if (useAvailableExternallyLinkage)
972 return thunkFn;
973 cgm.errorNYI("varargs thunk cloning");
974 } else {
975 // Normal thunk body generation.
976 mlir::OpBuilder::InsertionGuard guard(cgm.getBuilder());
977 CIRGenFunction cgf(cgm, cgm.getBuilder());
978 cgf.generateThunk(thunkFn, md->getSourceRange(), fnInfo, gd,
979 thunkAdjustments, isUnprototyped);
980 }
981
982 setThunkProperties(cgm, thunkAdjustments, thunkFn, forVTable, gd);
983 return thunkFn;
984}
985
987 const CXXMethodDecl *md =
988 cast<CXXMethodDecl>(gd.getDecl())->getCanonicalDecl();
989
990 // We don't need to generate thunks for the base destructor.
992 return;
993
994 const VTableContextBase::ThunkInfoVectorTy *thunkInfoVector =
995 vtContext->getThunkInfo(gd);
996
997 if (!thunkInfoVector)
998 return;
999
1000 for (const ThunkInfo &thunk : *thunkInfoVector)
1001 maybeEmitThunk(gd, thunk, /*forVTable=*/false);
1002}
1003
1005 const CXXRecordDecl *rd) {
1006 return cgm.getCodeGenOpts().OptimizationLevel > 0 &&
1008}
1009
1010/// Given that we're currently at the end of the translation unit, and
1011/// we've emitted a reference to the vtable for this class, should
1012/// we define that vtable?
1014 const CXXRecordDecl *rd) {
1015 // If vtable is internal then it has to be done.
1016 if (!cgm.getVTables().isVTableExternal(rd))
1017 return true;
1018
1019 // If it's external then maybe we will need it as available_externally.
1021}
1022
1023/// Given that at some point we emitted a reference to one or more
1024/// vtables, and that we are now at the end of the translation unit,
1025/// decide whether we should emit them.
1027#ifndef NDEBUG
1028 // Remember the size of DeferredVTables, because we're going to assume
1029 // that this entire operation doesn't modify it.
1030 size_t savedSize = deferredVTables.size();
1031#endif
1032 for (const CXXRecordDecl *rd : deferredVTables) {
1034 vtables.generateClassData(rd);
1036 opportunisticVTables.push_back(rd);
1037 }
1038
1039 assert(savedSize == deferredVTables.size() &&
1040 "deferred extra vtables during vtable emission?");
1041 deferredVTables.clear();
1042}
1043
1045 // Try to emit external vtables as available_externally if they have emitted
1046 // all inlined virtual functions. It runs after EmitDeferred() and therefore
1047 // is not allowed to create new references to things that need to be emitted
1048 // lazily. Note that it also uses fact that we eagerly emitting RTTI.
1049
1050 assert(
1051 (opportunisticVTables.empty() || shouldOpportunisticallyEmitVTables()) &&
1052 "Only emit opportunistic vtables with optimizations");
1053
1054 for (const CXXRecordDecl *rd : opportunisticVTables) {
1055 assert(getVTables().isVTableExternal(rd) &&
1056 "This queue should only contain external vtables");
1057 if (getCXXABI().canSpeculativelyEmitVTable(rd))
1058 vtables.generateClassData(rd);
1059 }
1060 opportunisticVTables.clear();
1061}
1062
1064 return codeGenOpts.OptimizationLevel > 0;
1065}
static RValue performReturnAdjustment(CIRGenFunction &cgf, QualType resultType, RValue rv, const ThunkInfo &thunk)
static cir::GlobalOp getAddrOfVTTVTable(CIRGenVTables &cgvt, CIRGenModule &cgm, const CXXRecordDecl *mostDerivedClass, const VTTVTable &vtable, cir::GlobalLinkageKind linkage, VTableLayout::AddressPointsMapTy &addressPoints)
static bool shouldEmitAvailableExternallyVTable(const CIRGenModule &cgm, const CXXRecordDecl *rd)
static bool shouldEmitVTableAtEndOfTranslationUnit(CIRGenModule &cgm, const CXXRecordDecl *rd)
Given that we're currently at the end of the translation unit, and we've emitted a reference to the v...
static void setThunkProperties(CIRGenModule &cgm, const ThunkInfo &thunk, cir::FuncOp thunkFn, bool forVTable, GlobalDecl gd)
static bool shouldEmitVTableThunk(CIRGenModule &cgm, const CXXMethodDecl *md, bool isUnprototyped, bool forVTable)
TokenType getType() const
Returns the token's type, e.g.
mlir::TypedAttr getConstNullPtrAttr(mlir::Type t)
cir::ConstantOp getNullPtr(mlir::Type ty, mlir::Location loc)
mlir::Value createPtrIsNotNull(mlir::Value ptr)
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value)
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
C++ view class that accepts both !cir.struct and !cir.union types.
Definition CIRTypes.h:149
static llvm::SmallVector< RecordMemberKind > getAllDataKinds(llvm::ArrayRef< mlir::Type > members)
One Data kind per member.
Definition CIRTypes.cpp:162
const CXXMethodDecl * getCurrentKeyFunction(const CXXRecordDecl *RD)
Get our current best idea for the key function of the given record decl, or nullptr if there isn't on...
const LangOptions & getLangOpts() const
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:965
const CXXRecordDecl * getBase() const
getBase - Returns the base class declaration.
CharUnits getBaseOffset() const
getBaseOffset - Returns the base class offset.
cir::PointerType getUInt8PtrTy()
cir::FuncType getFuncType(llvm::ArrayRef< mlir::Type > params, mlir::Type retTy, bool isVarArg=false)
virtual bool exportThunk()=0
Returns true if the thunk should be exported.
virtual bool canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const =0
Determine whether it's possible to emit a vtable for RD, even though we do not know that the vtable h...
virtual cir::GlobalOp getAddrOfVTable(const CXXRecordDecl *rd, CharUnits vptrOffset)=0
Get the address of the vtable for the given record decl which should be used for the vptr at the give...
virtual void setThunkLinkage(cir::FuncOp thunk, bool forVTable, GlobalDecl gd, bool returnAdjustment)=0
Set the linkage and visibility of a thunk function.
virtual mlir::Value performReturnAdjustment(CIRGenFunction &cgf, Address ret, const CXXRecordDecl *unadjustedClass, const ReturnAdjustment &ra)=0
Perform adjustment on a return pointer for a thunk (covariant returns).
virtual llvm::StringRef getPureVirtualCallName()=0
static CIRGenCallee forDirect(mlir::Operation *funcPtr, const CIRGenCalleeInfo &abstractInfo=CIRGenCalleeInfo())
Definition CIRGenCall.h:92
clang::GlobalDecl curGD
The GlobalDecl for the current function being compiled or the global variable currently being initial...
bool curFuncIsThunk
In C++, whether we are code generating a thunk.
mlir::Block * getCurFunctionEntryBlock()
mlir::Value loadCXXThis()
Load the value for 'this'.
const clang::Decl * curFuncDecl
void emitMustTailThunk(GlobalDecl gd, mlir::Value adjustedThisPtr, cir::FuncOp callee)
Emit a musttail call for a thunk with a potentially different ABI.
llvm::ScopedHashTableScope< const clang::Decl *, mlir::Value > SymTableScopeTy
mlir::Operation * curFn
The current function or global initializer that is generated code for.
void startThunk(cir::FuncOp fn, GlobalDecl gd, const CIRGenFunctionInfo &fnInfo, bool isUnprototyped)
Start generating a thunk function.
mlir::Type convertTypeForMem(QualType t)
Address returnValue
The temporary alloca to hold the return value.
static bool hasAggregateEvaluationKind(clang::QualType type)
void finishFunction(SourceLocation endLoc)
void emitCallAndReturnForThunk(cir::FuncOp callee, SourceRange fnLoc, const ThunkInfo *thunk, bool isUnprototyped)
Emit the call and return for a thunk function.
void emitReturnOfRValue(mlir::Location loc, RValue rv, QualType ty)
const clang::Decl * curCodeDecl
This is the inner-most code context, which includes blocks.
CIRGenBuilderTy & getBuilder()
void startFunction(clang::GlobalDecl gd, clang::QualType returnType, cir::FuncOp fn, cir::FuncType funcType, FunctionArgList args, clang::SourceLocation loc, clang::SourceLocation startLoc)
Emit code for the start of a function.
RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, bool isMustTail, SourceRange clangLoc)
void emitDelegateCallArg(CallArgList &args, const clang::VarDecl *param, clang::SourceLocation loc)
We are performing a delegate call; that is, the current function is delegating to another one.
const CIRGenFunctionInfo * curFnInfo
void generateThunk(cir::FuncOp fn, SourceRange fnLoc, const CIRGenFunctionInfo &fnInfo, GlobalDecl gd, const ThunkInfo &thunk, bool isUnprototyped)
Generate code for a thunk function.
void finishThunk()
Finish generating a thunk function.
This class organizes the cross-function state that is used while generating CIR code.
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
clang::ASTContext & getASTContext() const
CIRGenBuilderTy & getBuilder()
void setDSOLocal(mlir::Operation *op) const
void setGVProperties(mlir::Operation *op, const NamedDecl *d) const
Set visibility, dllimport/dllexport and dso_local.
clang::CharUnits getClassPointerAlignment(const clang::CXXRecordDecl *rd)
Return the best known alignment for an unknown pointer to a particular class.
const clang::TargetInfo & getTarget() const
const llvm::Triple & getTriple() const
static mlir::SymbolTable::Visibility getMLIRVisibility(Visibility v)
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, mlir::NamedAttrList extraAttrs={}, bool isLocal=false, bool assumeConvergent=false)
cir::FuncOp getAddrOfThunk(StringRef name, mlir::Type fnTy, GlobalDecl gd)
Get or create a thunk function with the given name and type.
const clang::CodeGenOptions & getCodeGenOpts() const
void emitDeferredVTables()
Emit any vtables which we deferred and still have a use for.
const clang::LangOptions & getLangOpts() const
cir::FuncOp getOrCreateCIRFunction(llvm::StringRef mangledName, mlir::Type funcType, clang::GlobalDecl gd, bool forVTable, bool dontDefer=false, bool isThunk=false, ForDefinition_t isForDefinition=NotForDefinition, mlir::NamedAttrList extraAttrs={})
void emitVTablesOpportunistically()
Try to emit external vtables as available_externally if they have emitted all inlined virtual functio...
CIRGenCXXABI & getCXXABI() const
CIRGenVTables & getVTables()
void setFunctionLinkage(GlobalDecl gd, cir::FuncOp f)
void emitVTable(const CXXRecordDecl *rd)
This is a callback from Sema to tell us that a particular vtable is required to be emitted in this tr...
cir::GlobalLinkageKind getVTableLinkage(const CXXRecordDecl *rd)
Return the appropriate linkage for the vtable, VTT, and type information of the given class.
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.
cir::GlobalOp generateConstructionVTable(const CXXRecordDecl *rd, const BaseSubobject &base, bool baseIsVirtual, cir::GlobalLinkageKind linkage, VTableAddressPointsMapTy &addressPoints)
Generate a construction vtable for the given base subobject.
uint64_t getSubVTTIndex(const CXXRecordDecl *rd, BaseSubobject base)
Return the index of the sub-VTT for the base class of the given record decl.
void emitThunks(GlobalDecl gd)
Emit the associated thunks for the given global decl.
void emitVTTDefinition(cir::GlobalOp vttOp, cir::GlobalLinkageKind linkage, const CXXRecordDecl *rd)
Emit the definition of the given vtable.
CIRGenVTables(CIRGenModule &cgm)
cir::FuncOp maybeEmitThunk(GlobalDecl gd, const ThunkInfo &thunkAdjustments, bool forVTable)
Emit a thunk for the given global decl if needed, or return an existing thunk.
void generateClassData(const CXXRecordDecl *rd)
Generate all the class data required to be generated upon definition of a KeyFunction.
cir::GlobalOp getAddrOfVTT(const CXXRecordDecl *rd)
Get the address of the VTT for the given record decl.
clang::ItaniumVTableContext & getItaniumVTableContext()
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.
Type for representing both the decl and type of parameters to a function.
Definition CIRGenCall.h:193
This trivial value class is used to represent the result of an expression that is evaluated.
Definition CIRGenValue.h:33
static RValue get(mlir::Value v)
Definition CIRGenValue.h:83
mlir::Value getValue() const
Return the value of this scalar value.
Definition CIRGenValue.h:57
static RequiredArgs getFromProtoWithExtraSlots(const clang::FunctionProtoType *prototype, unsigned additional)
Compute the arguments required by the given formal prototype, given that there may be some additional...
Contains the address where the return value of a function can be stored, and whether the address is v...
Definition CIRGenCall.h:260
Represents a C++ destructor within a class.
Definition DeclCXX.h:2907
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2150
QualType getThisType() const
Return the type of the this pointer.
Definition DeclCXX.cpp:2859
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
TemplateSpecializationKind getTemplateSpecializationKind() const
Determine whether this particular class is a specialization or instantiation of a class template or m...
Definition DeclCXX.cpp:2062
bool isDynamicClass() const
Definition DeclCXX.h:575
unsigned getNumVBases() const
Retrieves the number of virtual base classes of this class.
Definition DeclCXX.h:624
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
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
SourceLocation getLocation() const
Definition DeclBase.h:447
bool hasAttr() const
Definition DeclBase.h:585
virtual SourceRange getSourceRange() const LLVM_READONLY
Source range that this declaration covers.
Definition DeclBase.h:435
Represents a function declaration or definition.
Definition Decl.h:2059
param_iterator param_end()
Definition Decl.h:2918
bool isInlined() const
Determine whether this function should be inlined, because it is either marked "inline" or "constexpr...
Definition Decl.h:3052
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2905
param_iterator param_begin()
Definition Decl.h:2917
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:4608
TemplateSpecializationKind getTemplateSpecializationKind() const
Determine what kind of template instantiation this function represents.
Definition Decl.cpp:4456
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition Decl.cpp:3186
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5398
FunctionType - C99 6.7.5.3 - Function Declarators.
Definition TypeBase.h:4594
QualType getReturnType() const
Definition TypeBase.h:4934
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:60
CXXDtorType getDtorType() const
Definition GlobalDecl.h:122
const Decl * getDecl() const
Definition GlobalDecl.h:115
const VTableLayout & getVTableLayout(const CXXRecordDecl *RD)
MangleContext - Context for tracking state which persists across multiple calls to the C++ name mangl...
Definition Mangle.h:56
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, const ThunkInfo &Thunk, bool ElideOverrideInfo, raw_ostream &)=0
virtual void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, bool ElideOverrideInfo, raw_ostream &)=0
bool isExternallyVisible() const
Definition Decl.h:434
Represents a parameter to a function.
Definition Decl.h:1820
A (possibly-)qualified type.
Definition TypeBase.h:938
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:4958
bool isMicrosoft() const
Is this ABI an MSVC-compatible ABI?
virtual bool emitVectorDeletingDtors(const LangOptions &) const
Controls whether to emit MSVC vector deleting destructors.
TargetCXXABI getCXXABI() const
Get the C++ ABI currently in use.
bool isVoidType() const
Definition TypeBase.h:9037
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9331
bool isReferenceType() const
Definition TypeBase.h:8689
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Definition Type.cpp:2076
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:881
Class for building VTT layout information.
Definition VTTBuilder.h:71
const llvm::DenseMap< BaseSubobject, uint64_t > & getSecondaryVirtualPointerIndices() const
Returns a reference to the secondary virtual pointer indices.
Definition VTTBuilder.h:157
const llvm::DenseMap< BaseSubobject, uint64_t > & getSubVTTIndices() const
Returns a reference to the sub-VTT indices.
Definition VTTBuilder.h:151
const VTTComponentsVectorTy & getVTTComponents() const
Definition VTTBuilder.h:141
const VTTVTablesVectorTy & getVTTVTables() const
Definition VTTBuilder.h:146
CharUnits getBaseOffset() const
Definition VTTBuilder.h:48
bool isVirtual() const
Definition VTTBuilder.h:52
const CXXRecordDecl * getBase() const
Definition VTTBuilder.h:44
BaseSubobject getBaseSubobject() const
Definition VTTBuilder.h:56
Represents a single component in a vtable.
CharUnits getVBaseOffset() const
Kind getKind() const
Get the kind of this vtable component.
@ CK_DeletingDtorPointer
A pointer to the deleting destructor.
@ CK_UnusedFunctionPointer
An entry that is never used.
@ CK_CompleteDtorPointer
A pointer to the complete destructor.
CharUnits getOffsetToTop() const
GlobalDecl getGlobalDecl(bool HasVectorDeletingDtors) const
CharUnits getVCallOffset() const
SmallVector< ThunkInfo, 1 > ThunkInfoVectorTy
const AddressPointsIndexMapTy & getAddressPointIndices() const
size_t getVTableOffset(size_t i) const
llvm::DenseMap< BaseSubobject, AddressPointLocation > AddressPointsMapTy
AddressPointLocation getAddressPoint(BaseSubobject Base) const
ArrayRef< VTableComponent > vtable_components() const
size_t getNumVTables() const
ArrayRef< VTableThunkTy > vtable_thunks() const
size_t getVTableSize(size_t i) const
QualType getType() const
Definition Decl.h:724
static bool isLocalLinkage(GlobalLinkageKind linkage)
Definition CIROpsEnums.h:51
const AstTypeMatcher< ArrayType > arrayType
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
QualType pointeeType(QualType T)
@ Dtor_Base
Base object dtor.
Definition ABI.h:37
TemplateSpecializationKind
Describes the kind of template specialization that a particular template specialization declaration r...
Definition Specifiers.h:189
@ TSK_ExplicitInstantiationDefinition
This template specialization was instantiated from a template due to an explicit instantiation defini...
Definition Specifiers.h:207
@ TSK_ExplicitInstantiationDeclaration
This template specialization was instantiated from a template due to an explicit instantiation declar...
Definition Specifiers.h:203
@ TSK_ExplicitSpecialization
This template specialization was declared or defined by an explicit specialization (C++ [temp....
Definition Specifiers.h:199
@ TSK_ImplicitInstantiation
This template specialization was implicitly instantiated from a template.
Definition Specifiers.h:195
@ TSK_Undeclared
This template specialization was formed from a template-id but has not yet been declared,...
Definition Specifiers.h:192
U cast(CodeGen::Address addr)
Definition Address.h:327
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
static bool objCLifetime()
static bool opGlobalUnnamedAddr()
static bool vtableEmitMetadata()
static bool opCallThunkTailHint()
static bool setDLLStorageClass()
static bool opCallInAlloca()
static bool pointerAuthentication()
static bool returnValueSlotFeatures()
static bool cudaSupport()
static bool generateDebugInfo()
static bool vtableRelativeLayout()
Represents a scope, including function bodies, compound statements, and the substatements of if/while...
bool isEmpty() const
Definition Thunk.h:70
The this pointer adjustment as well as an optional return adjustment for a thunk.
Definition Thunk.h:157
ReturnAdjustment Return
The return adjustment.
Definition Thunk.h:162
const Type * ThisType
Definition Thunk.h:173