clang 23.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
64cir::RecordType CIRGenVTables::getVTableType(const VTableLayout &layout) {
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(tys, /*incomplete=*/false);
73}
74
75/// At this point in the translation unit, does it appear that can we
76/// rely on the vtable being defined elsewhere in the program?
77///
78/// The response is really only definitive when called at the end of
79/// the translation unit.
80///
81/// The only semantic restriction here is that the object file should
82/// not contain a vtable definition when that vtable is defined
83/// strongly elsewhere. Otherwise, we'd just like to avoid emitting
84/// vtables when unnecessary.
85/// TODO(cir): this should be merged into common AST helper for codegen.
87 assert(rd->isDynamicClass() && "Non-dynamic classes have no VTable.");
88
89 // We always synthesize vtables if they are needed in the MS ABI. MSVC doesn't
90 // emit them even if there is an explicit template instantiation.
91 if (cgm.getTarget().getCXXABI().isMicrosoft())
92 return false;
93
94 // If we have an explicit instantiation declaration (and not a
95 // definition), the vtable is defined elsewhere.
98 return true;
99
100 // Otherwise, if the class is an instantiated template, the
101 // vtable must be defined here.
102 if (tsk == TSK_ImplicitInstantiation ||
104 return false;
105
106 // Otherwise, if the class doesn't have a key function (possibly
107 // anymore), the vtable must be defined here.
108 const CXXMethodDecl *keyFunction =
110 if (!keyFunction)
111 return false;
112
113 // Otherwise, if we don't have a definition of the key function, the
114 // vtable must be defined somewhere else.
115 return !keyFunction->hasBody();
116}
117
118/// This is a callback from Sema to tell us that a particular vtable is
119/// required to be emitted in this translation unit.
120///
121/// This is only called for vtables that _must_ be emitted (mainly due to key
122/// functions). For weak vtables, CodeGen tracks when they are needed and
123/// emits them as-needed.
125 vtables.generateClassData(rd);
126}
127
130
131 if (rd->getNumVBases())
132 cgm.getCXXABI().emitVirtualInheritanceTables(rd);
133
134 cgm.getCXXABI().emitVTableDefinitions(*this, rd);
135}
136
137mlir::Attribute CIRGenVTables::getVTableComponent(
138 const VTableLayout &layout, unsigned componentIndex, mlir::Attribute rtti,
139 unsigned &nextVTableThunkIndex, unsigned vtableAddressPoint,
140 bool vtableHasLocalLinkage) {
141 const VTableComponent &component = layout.vtable_components()[componentIndex];
142
143 CIRGenBuilderTy builder = cgm.getBuilder();
144
146
147 switch (component.getKind()) {
149 return builder.getConstNullPtrAttr(builder.getUInt8PtrTy());
150
152 return builder.getConstPtrAttr(builder.getUInt8PtrTy(),
153 component.getVCallOffset().getQuantity());
154
156 return builder.getConstPtrAttr(builder.getUInt8PtrTy(),
157 component.getVBaseOffset().getQuantity());
158
160 return builder.getConstPtrAttr(builder.getUInt8PtrTy(),
161 component.getOffsetToTop().getQuantity());
162
164 assert((mlir::isa<cir::GlobalViewAttr>(rtti) ||
165 mlir::isa<cir::ConstPtrAttr>(rtti)) &&
166 "expected GlobalViewAttr or ConstPtrAttr");
167 return rtti;
168
172 GlobalDecl gd = component.getGlobalDecl(
174 cgm.getASTContext().getLangOpts()));
175
177
178 auto getSpecialVirtFn = [&](StringRef name) -> cir::FuncOp {
180
181 if (cgm.getLangOpts().OpenMP && cgm.getLangOpts().OpenMPIsTargetDevice &&
182 cgm.getTriple().isNVPTX())
183 cgm.errorNYI(gd.getDecl()->getSourceRange(),
184 "getVTableComponent for OMP Device NVPTX");
185
186 cir::FuncType fnTy =
187 cgm.getBuilder().getFuncType({}, cgm.getBuilder().getVoidTy());
188 cir::FuncOp fnPtr = cgm.createRuntimeFunction(fnTy, name);
189
191 return fnPtr;
192 };
193
194 cir::FuncOp fnPtr;
195 if (cast<CXXMethodDecl>(gd.getDecl())->isPureVirtual()) {
196 if (!pureVirtualFn)
197 pureVirtualFn =
198 getSpecialVirtFn(cgm.getCXXABI().getPureVirtualCallName());
199 fnPtr = pureVirtualFn;
200 } else if (cast<CXXMethodDecl>(gd.getDecl())->isDeleted()) {
201 if (!deletedVirtualFn)
202 deletedVirtualFn =
203 getSpecialVirtFn(cgm.getCXXABI().getDeletedVirtualCallName());
204 fnPtr = deletedVirtualFn;
205 } else if (nextVTableThunkIndex < layout.vtable_thunks().size() &&
206 layout.vtable_thunks()[nextVTableThunkIndex].first ==
207 componentIndex) {
208 const ThunkInfo &thunkInfo =
209 layout.vtable_thunks()[nextVTableThunkIndex].second;
210 nextVTableThunkIndex++;
211 fnPtr = maybeEmitThunk(gd, thunkInfo, /*forVTable=*/true);
213 } else {
214 // Otherwise we can use the method definition directly.
215 cir::FuncType fnTy = cgm.getTypes().getFunctionType(gd);
216 fnPtr = cgm.getAddrOfFunction(gd, fnTy, /*ForVTable=*/true);
217 }
218
219 return cir::GlobalViewAttr::get(
220 builder.getUInt8PtrTy(),
221 mlir::FlatSymbolRefAttr::get(fnPtr.getSymNameAttr()));
222 }
223 }
224
225 llvm_unreachable("Unexpected vtable component kind");
226}
227
228void CIRGenVTables::createVTableInitializer(cir::GlobalOp &vtableOp,
229 const clang::VTableLayout &layout,
230 mlir::Attribute rtti,
231 bool vtableHasLocalLinkage) {
232 mlir::Type componentType = getVTableComponentType();
233
234 const llvm::SmallVectorImpl<unsigned> &addressPoints =
235 layout.getAddressPointIndices();
236 unsigned nextVTableThunkIndex = 0;
237
238 mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();
239
241 for (auto [vtableIndex, addressPoint] : llvm::enumerate(addressPoints)) {
242 // Build a ConstArrayAttr of the vtable components.
243 size_t vtableStart = layout.getVTableOffset(vtableIndex);
244 size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex);
246 components.reserve(vtableEnd - vtableStart);
247 for (size_t componentIndex : llvm::seq(vtableStart, vtableEnd))
248 components.push_back(
249 getVTableComponent(layout, componentIndex, rtti, nextVTableThunkIndex,
250 addressPoint, vtableHasLocalLinkage));
251 // Create a ConstArrayAttr to hold the components.
252 auto arr = cir::ConstArrayAttr::get(
253 cir::ArrayType::get(componentType, components.size()),
254 mlir::ArrayAttr::get(mlirContext, components));
255 vtables.push_back(arr);
256 }
257
258 // Create a ConstRecordAttr to hold the component array.
259 const auto members = mlir::ArrayAttr::get(mlirContext, vtables);
260 cir::ConstRecordAttr record = cgm.getBuilder().getAnonConstRecord(members);
261
262 // Create a VTableAttr
263 auto vtableAttr = cir::VTableAttr::get(record.getType(), record.getMembers());
264
265 // Add the vtable initializer to the vtable global op.
266 cgm.setInitializer(vtableOp, vtableAttr);
267}
268
270 const CXXRecordDecl *rd, const BaseSubobject &base, bool baseIsVirtual,
271 cir::GlobalLinkageKind linkage, VTableAddressPointsMapTy &addressPoints) {
273
274 std::unique_ptr<VTableLayout> vtLayout(
275 getItaniumVTableContext().createConstructionVTableLayout(
276 base.getBase(), base.getBaseOffset(), baseIsVirtual, rd));
277
278 // Add the address points.
279 addressPoints = vtLayout->getAddressPoints();
280
281 // Get the mangled construction vtable name.
282 SmallString<256> outName;
283 llvm::raw_svector_ostream out(outName);
284 cast<ItaniumMangleContext>(cgm.getCXXABI().getMangleContext())
285 .mangleCXXCtorVTable(rd, base.getBaseOffset().getQuantity(),
286 base.getBase(), out);
287 SmallString<256> name(outName);
288
290
291 cir::RecordType vtType = getVTableType(*vtLayout);
292
293 // Construction vtable symbols are not part of the Itanium ABI, so we cannot
294 // guarantee that they actually will be available externally. Instead, when
295 // emitting an available_externally VTT, we provide references to an internal
296 // linkage construction vtable. The ABI only requires complete-object vtables
297 // to be the same for all instances of a type, not construction vtables.
298 if (linkage == cir::GlobalLinkageKind::AvailableExternallyLinkage)
299 linkage = cir::GlobalLinkageKind::InternalLinkage;
300
301 llvm::Align align = cgm.getDataLayout().getABITypeAlign(vtType);
302 mlir::Location loc = cgm.getLoc(rd->getSourceRange());
303
304 // Create the variable that will hold the construction vtable.
305 cir::GlobalOp vtable = cgm.createOrReplaceCXXRuntimeVariable(
306 loc, name, vtType, linkage, CharUnits::fromQuantity(align));
307
308 // V-tables are always unnamed_addr.
310
311 mlir::Attribute rtti = cgm.getAddrOfRTTIDescriptor(
312 loc, cgm.getASTContext().getCanonicalTagType(base.getBase()));
313
314 // Create and set the initializer.
315 createVTableInitializer(vtable, *vtLayout, rtti,
316 cir::isLocalLinkage(vtable.getLinkage()));
317
318 // Set properties only after the initializer has been set to ensure that the
319 // GV is treated as definition and not declaration.
320 assert(!vtable.isDeclaration() && "Shouldn't set properties on declaration");
321 cgm.setGVProperties(vtable, rd);
322
325
326 return vtable;
327}
328
330 const CXXRecordDecl *rd);
331
332/// Compute the required linkage of the vtable for the given class.
333///
334/// Note that we only call this at the end of the translation unit.
335cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) {
336 if (!rd->isExternallyVisible())
337 return cir::GlobalLinkageKind::InternalLinkage;
338
339 // We're at the end of the translation unit, so the current key
340 // function is fully correct.
341 const CXXMethodDecl *keyFunction = astContext.getCurrentKeyFunction(rd);
342 if (keyFunction && !rd->hasAttr<DLLImportAttr>()) {
343 // If this class has a key function, use that to determine the
344 // linkage of the vtable.
345 const FunctionDecl *def = nullptr;
346 if (keyFunction->hasBody(def))
347 keyFunction = cast<CXXMethodDecl>(def);
348
349 // All of the cases below do something different with AppleKext enabled.
351 switch (keyFunction->getTemplateSpecializationKind()) {
352 case TSK_Undeclared:
354 assert(
355 (def || codeGenOpts.OptimizationLevel > 0 ||
356 codeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo) &&
357 "Shouldn't query vtable linkage without key function, "
358 "optimizations, or debug info");
359 if (!def && codeGenOpts.OptimizationLevel > 0)
360 return cir::GlobalLinkageKind::AvailableExternallyLinkage;
361
362 if (keyFunction->isInlined())
363 return !astContext.getLangOpts().AppleKext
364 ? cir::GlobalLinkageKind::LinkOnceODRLinkage
365 : cir::GlobalLinkageKind::InternalLinkage;
366 return cir::GlobalLinkageKind::ExternalLinkage;
367
369 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
370
372 return cir::GlobalLinkageKind::WeakODRLinkage;
373
375 return !def ? cir::GlobalLinkageKind::AvailableExternallyLinkage
376 : cir::GlobalLinkageKind::ExternalLinkage;
377 }
378 }
379 // -fapple-kext mode does not support weak linkage, so we must use
380 // internal linkage.
381 if (astContext.getLangOpts().AppleKext)
382 return cir::GlobalLinkageKind::InternalLinkage;
383
384 auto discardableODRLinkage = cir::GlobalLinkageKind::LinkOnceODRLinkage;
385 auto nonDiscardableODRLinkage = cir::GlobalLinkageKind::WeakODRLinkage;
386 if (rd->hasAttr<DLLExportAttr>()) {
387 // Cannot discard exported vtables.
388 discardableODRLinkage = nonDiscardableODRLinkage;
389 } else if (rd->hasAttr<DLLImportAttr>()) {
390 // Imported vtables are available externally.
391 discardableODRLinkage = cir::GlobalLinkageKind::AvailableExternallyLinkage;
392 nonDiscardableODRLinkage =
393 cir::GlobalLinkageKind::AvailableExternallyLinkage;
394 }
395
396 switch (rd->getTemplateSpecializationKind()) {
397 case TSK_Undeclared:
400 return discardableODRLinkage;
401
403 // Explicit instantiations in MSVC do not provide vtables, so we must emit
404 // our own.
405 if (getTarget().getCXXABI().isMicrosoft())
406 return discardableODRLinkage;
408 ? cir::GlobalLinkageKind::AvailableExternallyLinkage
409 : cir::GlobalLinkageKind::ExternalLinkage;
410
412 return nonDiscardableODRLinkage;
413 }
414
415 llvm_unreachable("Invalid TemplateSpecializationKind!");
416}
417
419 assert(rd->getNumVBases() && "Only classes with virtual bases need a VTT");
420
421 SmallString<256> outName;
422 llvm::raw_svector_ostream out(outName);
423 cast<ItaniumMangleContext>(cgm.getCXXABI().getMangleContext())
424 .mangleCXXVTT(rd, out);
425 StringRef name = outName.str();
426
427 // This will also defer the definition of the VTT.
428 (void)cgm.getCXXABI().getAddrOfVTable(rd, CharUnits());
429
430 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);
431
432 auto arrayType = cir::ArrayType::get(cgm.getBuilder().getUInt8PtrTy(),
433 builder.getVTTComponents().size());
434 llvm::Align align =
435 cgm.getDataLayout().getABITypeAlign(cgm.getBuilder().getUInt8PtrTy());
436 cir::GlobalOp vtt = cgm.createOrReplaceCXXRuntimeVariable(
437 cgm.getLoc(rd->getSourceRange()), name, arrayType,
438 cir::GlobalLinkageKind::ExternalLinkage, CharUnits::fromQuantity(align));
439 cgm.setGVProperties(vtt, rd);
440 return vtt;
441}
442
443static cir::GlobalOp
445 const CXXRecordDecl *mostDerivedClass,
446 const VTTVTable &vtable, cir::GlobalLinkageKind linkage,
447 VTableLayout::AddressPointsMapTy &addressPoints) {
448 if (vtable.getBase() == mostDerivedClass) {
449 assert(vtable.getBaseOffset().isZero() &&
450 "Most derived class vtable must have a zero offset!");
451 // This is a regular vtable.
452 return cgm.getCXXABI().getAddrOfVTable(mostDerivedClass, CharUnits());
453 }
454 return cgvt.generateConstructionVTable(
455 mostDerivedClass, vtable.getBaseSubobject(), vtable.isVirtual(), linkage,
456 addressPoints);
457}
458
459/// Emit the definition of the given vtable.
460void CIRGenVTables::emitVTTDefinition(cir::GlobalOp vttOp,
461 cir::GlobalLinkageKind linkage,
462 const CXXRecordDecl *rd) {
463 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/true);
464
465 mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();
466
467 auto arrayType = cir::ArrayType::get(cgm.getBuilder().getUInt8PtrTy(),
468 builder.getVTTComponents().size());
469
471 SmallVector<VTableAddressPointsMapTy> vtableAddressPoints;
472 for (const VTTVTable &vtt : builder.getVTTVTables()) {
473 vtableAddressPoints.push_back(VTableAddressPointsMapTy());
474 vtables.push_back(getAddrOfVTTVTable(*this, cgm, rd, vtt, linkage,
475 vtableAddressPoints.back()));
476 }
477
478 SmallVector<mlir::Attribute> vttComponents;
479 for (const VTTComponent &vttComponent : builder.getVTTComponents()) {
480 const VTTVTable &vttVT = builder.getVTTVTables()[vttComponent.VTableIndex];
481 cir::GlobalOp vtable = vtables[vttComponent.VTableIndex];
483 if (vttVT.getBase() == rd) {
484 // Just get the address point for the regular vtable.
485 addressPoint =
487 vttComponent.VTableBase);
488 } else {
489 addressPoint = vtableAddressPoints[vttComponent.VTableIndex].lookup(
490 vttComponent.VTableBase);
491 assert(addressPoint.AddressPointIndex != 0 &&
492 "Did not find ctor vtable address point!");
493 }
494
495 mlir::Attribute indices[2] = {
496 cgm.getBuilder().getI32IntegerAttr(addressPoint.VTableIndex),
497 cgm.getBuilder().getI32IntegerAttr(addressPoint.AddressPointIndex),
498 };
499
500 auto indicesAttr = mlir::ArrayAttr::get(mlirContext, indices);
501 cir::GlobalViewAttr init = cgm.getBuilder().getGlobalViewAttr(
502 cgm.getBuilder().getUInt8PtrTy(), vtable, indicesAttr);
503
504 vttComponents.push_back(init);
505 }
506
507 auto init = cir::ConstArrayAttr::get(
508 arrayType, mlir::ArrayAttr::get(mlirContext, vttComponents));
509
510 vttOp.setInitialValueAttr(init);
511
512 // Set the correct linkage.
513 vttOp.setLinkage(linkage);
514 mlir::SymbolTable::setSymbolVisibility(
515 vttOp, CIRGenModule::getMLIRVisibility(vttOp));
516
517 if (cgm.supportsCOMDAT() && vttOp.isWeakForLinker())
518 vttOp.setComdat(true);
519}
520
522 BaseSubobject base) {
523 BaseSubobjectPairTy classSubobjectPair(rd, base);
524
525 SubVTTIndiciesMapTy::iterator it = subVTTIndicies.find(classSubobjectPair);
526 if (it != subVTTIndicies.end())
527 return it->second;
528
529 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);
530
531 for (const auto &entry : builder.getSubVTTIndices()) {
532 // Insert all indices.
533 BaseSubobjectPairTy subclassSubobjectPair(rd, entry.first);
534
535 subVTTIndicies.insert(std::make_pair(subclassSubobjectPair, entry.second));
536 }
537
538 it = subVTTIndicies.find(classSubobjectPair);
539 assert(it != subVTTIndicies.end() && "Did not find index!");
540
541 return it->second;
542}
543
545 BaseSubobject base) {
546 auto it = secondaryVirtualPointerIndices.find(std::make_pair(rd, base));
547
548 if (it != secondaryVirtualPointerIndices.end())
549 return it->second;
550
551 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);
552
553 // Insert all secondary vpointer indices.
554 for (const auto &entry : builder.getSecondaryVirtualPointerIndices()) {
555 std::pair<const CXXRecordDecl *, BaseSubobject> pair =
556 std::make_pair(rd, entry.first);
557
558 secondaryVirtualPointerIndices.insert(std::make_pair(pair, entry.second));
559 }
560
561 it = secondaryVirtualPointerIndices.find(std::make_pair(rd, base));
562 assert(it != secondaryVirtualPointerIndices.end() && "Did not find index!");
563
564 return it->second;
565}
566
568 RValue rv, const ThunkInfo &thunk) {
569 // Emit the return adjustment. For non-reference pointer returns, match
570 // classic codegen: skip the adjustment when the returned pointer is null.
571 bool nullCheckValue = !resultType->isReferenceType();
572 mlir::Value returnValue = rv.getValue();
573
574 const CXXRecordDecl *classDecl =
575 resultType->getPointeeType()->getAsCXXRecordDecl();
576 CharUnits classAlign = cgf.cgm.getClassPointerAlignment(classDecl);
577 mlir::Type pointeeType = cgf.convertTypeForMem(resultType->getPointeeType());
578 CIRGenBuilderTy &builder = cgf.getBuilder();
579 mlir::Location loc = returnValue.getLoc();
580
581 if (!nullCheckValue) {
582 returnValue = cgf.cgm.getCXXABI().performReturnAdjustment(
583 cgf, Address(returnValue, pointeeType, classAlign), classDecl,
584 thunk.Return);
585 return RValue::get(returnValue);
586 }
587
588 mlir::Value isNotNull = builder.createPtrIsNotNull(returnValue);
589 returnValue =
590 cir::TernaryOp::create(
591 builder, loc, isNotNull,
592 [&](mlir::OpBuilder &, mlir::Location) {
593 mlir::Value adjusted = cgf.cgm.getCXXABI().performReturnAdjustment(
594 cgf, Address(returnValue, pointeeType, classAlign), classDecl,
595 thunk.Return);
596 builder.createYield(loc, adjusted);
597 },
598 [&](mlir::OpBuilder &, mlir::Location) {
599 mlir::Value nullVal =
600 builder.getNullPtr(returnValue.getType(), loc).getResult();
601 builder.createYield(loc, nullVal);
602 })
603 .getResult();
604
605 return RValue::get(returnValue);
606}
607
609 const CIRGenFunctionInfo &fnInfo,
610 bool isUnprototyped) {
611 assert(!curGD.getDecl() && "curGD was already set!");
612 curGD = gd;
613 curFuncIsThunk = true;
614
615 // Build FunctionArgs.
616 const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl());
617 QualType thisType = md->getThisType();
618 QualType resultType;
619 if (isUnprototyped)
620 resultType = cgm.getASTContext().VoidTy;
621 else if (cgm.getCXXABI().hasThisReturn(gd))
622 resultType = thisType;
623 else if (cgm.getCXXABI().hasMostDerivedReturn(gd))
624 resultType = cgm.getASTContext().VoidPtrTy;
625 else
626 resultType = md->getType()->castAs<FunctionProtoType>()->getReturnType();
627 FunctionArgList functionArgs;
628
629 // Create the implicit 'this' parameter declaration.
630 cgm.getCXXABI().buildThisParam(*this, functionArgs);
631
632 // Add the rest of the parameters, if we have a prototype to work with.
633 if (!isUnprototyped) {
634 functionArgs.append(md->param_begin(), md->param_end());
635
637 cgm.getCXXABI().addImplicitStructorParams(*this, resultType,
638 functionArgs);
639 }
640
642
643 // Start defining the function.
644 cir::FuncType funcType = cgm.getTypes().getFunctionType(fnInfo);
645 startFunction(GlobalDecl(), resultType, fn, funcType, functionArgs,
646 md->getLocation(), md->getLocation());
647 // TODO(cir): Move this into startFunction.
648 curFnInfo = &fnInfo;
650
651 // Since we didn't pass a GlobalDecl to startFunction, do this ourselves.
652 cgm.getCXXABI().emitInstanceFunctionProlog(md->getLocation(), *this);
654 curCodeDecl = md;
655 curFuncDecl = md;
656}
657
659 // Clear these to restore the invariants expected by
660 // startFunction/finishFunction.
661 curCodeDecl = nullptr;
662 curFuncDecl = nullptr;
663
665}
666
668 const ThunkInfo *thunk,
669 bool isUnprototyped) {
670 assert(isa<CXXMethodDecl>(curGD.getDecl()) &&
671 "Please use a new CGF for this thunk");
672 const CXXMethodDecl *md = cast<CXXMethodDecl>(curGD.getDecl());
673
674 // Determine the this pointer class (may differ from md's class for thunks).
675 const CXXRecordDecl *thisValueClass =
677 if (thunk)
678 thisValueClass = thunk->ThisType->getPointeeCXXRecordDecl();
679
680 mlir::Value adjustedThisPtr =
681 thunk ? cgm.getCXXABI().performThisAdjustment(*this, loadCXXThisAddress(),
682 thisValueClass, *thunk)
683 : loadCXXThis();
684
685 // If perfect forwarding is required a variadic method, a method using
686 // inalloca, or an unprototyped thunk, use musttail. Emit an error if this
687 // thunk requires a return adjustment, since that is impossible with musttail.
689 if ((curFnInfo && curFnInfo->isVariadic()) || isUnprototyped) {
690 // Error if return adjustment is needed (can't do with musttail).
691 if (thunk && !thunk->Return.isEmpty()) {
692 if (isUnprototyped)
693 cgm.errorUnsupported(
694 md, "return-adjusting thunk with incomplete parameter type");
695 else if (curFnInfo && curFnInfo->isVariadic())
696 llvm_unreachable("shouldn't try to emit musttail return-adjusting "
697 "thunks for variadic functions");
698 else
699 cgm.errorUnsupported(
700 md, "non-trivial argument copy for return-adjusting thunk");
701 }
702 emitMustTailThunk(curGD, adjustedThisPtr, callee);
703 return;
704 }
705
706 // Build the call argument list.
707 CallArgList callArgs;
708 QualType thisType = md->getThisType();
709 callArgs.add(RValue::get(adjustedThisPtr), thisType);
710
712 cgm.getCXXABI().adjustCallArgsForDestructorThunk(*this, curGD, callArgs);
713
714#ifndef NDEBUG
715 unsigned prefixArgs = callArgs.size() - 1;
716#endif
717
718 // Add the rest of the method parameters.
719 for (const ParmVarDecl *pd : md->parameters())
720 emitDelegateCallArg(callArgs, pd, SourceLocation());
721
722 const FunctionProtoType *fpt = md->getType()->castAs<FunctionProtoType>();
723
724#ifndef NDEBUG
725 const CIRGenFunctionInfo &callFnInfo = cgm.getTypes().arrangeCXXMethodCall(
726 callArgs, fpt, RequiredArgs::getFromProtoWithExtraSlots(fpt, 1),
727 prefixArgs);
728 assert(callFnInfo.argTypeSize() == curFnInfo->argTypeSize());
729#endif
730
731 // Determine whether we have a return value slot to use.
732 QualType resultType = cgm.getCXXABI().hasThisReturn(curGD) ? thisType
733 : cgm.getCXXABI().hasMostDerivedReturn(curGD)
734 ? cgm.getASTContext().VoidPtrTy
735 : fpt->getReturnType();
736
737 ReturnValueSlot slot;
738 // This should also be tracking volatile, unused, and externally destructed.
740 if (!resultType->isVoidType() && hasAggregateEvaluationKind(resultType))
742
743 // Now emit our call.
744 CIRGenCallee cirCallee = CIRGenCallee::forDirect(callee, curGD);
745 mlir::Location loc = builder.getUnknownLoc();
746 RValue rv = emitCall(*curFnInfo, cirCallee, slot, callArgs,
747 /*callOrTryCall=*/nullptr, loc);
748
749 // Consider return adjustment if we have ThunkInfo.
750 if (thunk && !thunk->Return.isEmpty())
751 rv = performReturnAdjustment(*this, resultType, rv, *thunk);
752 else
754
755 // Emit return.
756 if (!resultType->isVoidType() && slot.isNull())
757 cgm.getCXXABI().emitReturnFromThunk(*this, rv, resultType);
758
759 // Disable final ARC autorelease.
761
762 finishThunk();
763}
764
766 mlir::Value adjustedThisPtr,
767 cir::FuncOp callee) {
768 // Forward all function arguments, replacing 'this' with the adjusted pointer.
769 // The call is marked musttail so varargs are forwarded correctly.
770 mlir::Block *entryBlock = getCurFunctionEntryBlock();
772 for (mlir::BlockArgument arg : entryBlock->getArguments())
773 args.push_back(arg);
774
775 // Replace the 'this' argument (first arg) with the adjusted pointer.
776 assert(!args.empty() && "thunk must have at least 'this' argument");
777 if (adjustedThisPtr.getType() != args[0].getType())
778 adjustedThisPtr = builder.createBitcast(adjustedThisPtr, args[0].getType());
779 args[0] = adjustedThisPtr;
780
781 mlir::Location loc = curFn->getLoc();
782 cir::FuncType calleeTy = callee.getFunctionType();
783 mlir::Type retTy = calleeTy.getReturnType();
784
785 cir::CallOp call = builder.createCallOp(loc, callee, args);
786 call->setAttr(cir::CIRDialect::getMustTailAttrName(),
787 mlir::UnitAttr::get(builder.getContext()));
788
789 if (isa<cir::VoidType>(retTy))
790 cir::ReturnOp::create(builder, loc);
791 else
792 cir::ReturnOp::create(builder, loc, call->getResult(0));
793
794 finishThunk();
795}
796
798 const CIRGenFunctionInfo &fnInfo,
799 GlobalDecl gd, const ThunkInfo &thunk,
800 bool isUnprototyped) {
801 // Create entry block and set up the builder's insertion point.
802 // This must be done before calling startThunk() which calls startFunction().
803 assert(fn.isDeclaration() && "Function already has body?");
804 mlir::Block *entryBb = fn.addEntryBlock();
805 builder.setInsertionPointToStart(entryBb);
806
807 // Create a scope in the symbol table to hold variable declarations.
808 // This is required before startFunction processes parameters, as it will
809 // insert them into the symbolTable (ScopedHashTable) which requires an
810 // active scope.
812
813 // Create lexical scope - must stay alive for entire thunk generation.
814 // startFunction() requires currLexScope to be set.
815 SourceLocRAIIObject locRAII(*this, fn.getLoc());
816 LexicalScope lexScope{*this, fn.getLoc(), entryBb};
817
818 startThunk(fn, gd, fnInfo, isUnprototyped);
820
821 // Get our callee. Use a placeholder type if this method is unprototyped so
822 // that CIRGenModule doesn't try to set attributes.
823 mlir::Type ty;
824 if (isUnprototyped)
825 cgm.errorNYI("unprototyped thunk placeholder type");
826 else
827 ty = cgm.getTypes().getFunctionType(fnInfo);
828
829 cir::FuncOp calleeOp = cgm.getAddrOfFunction(gd, ty, /*forVTable=*/true);
830
831 // Make the call and return the result.
832 emitCallAndReturnForThunk(calleeOp, &thunk, isUnprototyped);
833}
834
836 bool isUnprototyped, bool forVTable) {
837 // Always emit thunks in the MS C++ ABI. We cannot rely on other TUs to
838 // provide thunks for us.
839 if (cgm.getTarget().getCXXABI().isMicrosoft())
840 return true;
841
842 // In the Itanium C++ ABI, vtable thunks are provided by TUs that provide
843 // definitions of the main method. Therefore, emitting thunks with the vtable
844 // is purely an optimization. Emit the thunk if optimizations are enabled and
845 // all of the parameter types are complete.
846 if (forVTable)
847 return cgm.getCodeGenOpts().OptimizationLevel && !isUnprototyped;
848
849 // Always emit thunks along with the method definition.
850 return true;
851}
852
854 const ThunkInfo &thunkAdjustments,
855 bool forVTable) {
856 const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl());
857 SmallString<256> name;
858 MangleContext &mCtx = cgm.getCXXABI().getMangleContext();
859
860 llvm::raw_svector_ostream out(name);
861 if (const CXXDestructorDecl *dd = dyn_cast<CXXDestructorDecl>(md)) {
862 mCtx.mangleCXXDtorThunk(dd, gd.getDtorType(), thunkAdjustments,
863 /*elideOverrideInfo=*/false, out);
864 } else {
865 mCtx.mangleThunk(md, thunkAdjustments, /*elideOverrideInfo=*/false, out);
866 }
867
868 if (cgm.getASTContext().useAbbreviatedThunkName(gd, name.str())) {
869 name = "";
870 if (const CXXDestructorDecl *dd = dyn_cast<CXXDestructorDecl>(md))
871 mCtx.mangleCXXDtorThunk(dd, gd.getDtorType(), thunkAdjustments,
872 /*elideOverrideInfo=*/true, out);
873 else
874 mCtx.mangleThunk(md, thunkAdjustments, /*elideOverrideInfo=*/true, out);
875 }
876
877 cir::FuncType thunkVTableTy = cgm.getTypes().getFunctionType(gd);
878 cir::FuncOp thunk = cgm.getAddrOfThunk(name, thunkVTableTy, gd);
879
880 // If we don't need to emit a definition, return this declaration as is.
881 bool isUnprototyped = !cgm.getTypes().isFuncTypeConvertible(
882 md->getType()->castAs<FunctionType>());
883 if (!shouldEmitVTableThunk(cgm, md, isUnprototyped, forVTable))
884 return thunk;
885
886 // Arrange a function prototype appropriate for a function definition. In some
887 // cases in the MS ABI, we may need to build an unprototyped musttail thunk.
888 const CIRGenFunctionInfo &fnInfo =
889 isUnprototyped ? (cgm.errorNYI("unprototyped must-tail thunk"),
890 cgm.getTypes().arrangeGlobalDeclaration(gd))
891 : cgm.getTypes().arrangeGlobalDeclaration(gd);
892 cir::FuncType thunkFnTy = cgm.getTypes().getFunctionType(fnInfo);
893
894 // This is to replace OG's casting to a function, keeping it here to
895 // streamline the 1-to-1 mapping from OG starting below.
896 cir::FuncOp thunkFn = thunk;
897 if (thunk.getFunctionType() != thunkFnTy) {
898 cir::FuncOp oldThunkFn = thunkFn;
899
900 assert(oldThunkFn.isDeclaration() && "Shouldn't replace non-declaration");
901
902 // Remove the name from the old thunk function and get a new thunk.
903 cgm.eraseGlobalSymbol(oldThunkFn);
904 oldThunkFn.setName(StringRef());
905 thunkFn =
906 cir::FuncOp::create(cgm.getBuilder(), thunk->getLoc(), name.str(),
907 thunkFnTy, cir::GlobalLinkageKind::ExternalLinkage);
908 cgm.insertGlobalSymbol(thunkFn);
909 cgm.setCIRFunctionAttributes(md, fnInfo, thunkFn, /*isThunk=*/false);
910
911 if (!oldThunkFn->use_empty())
912 oldThunkFn->replaceAllUsesWith(thunkFn);
913
914 // Remove the old thunk.
915 oldThunkFn->erase();
916 }
917
918 bool abiHasKeyFunctions = cgm.getTarget().getCXXABI().hasKeyFunctions();
919 bool useAvailableExternallyLinkage = forVTable && abiHasKeyFunctions;
920
921 // If the type of the underlying GlobalValue is wrong, we'll have to replace
922 // it. It should be a declaration.
923 if (!thunkFn.isDeclaration()) {
924 if (!abiHasKeyFunctions || useAvailableExternallyLinkage) {
925 // There is already a thunk emitted for this function, do nothing.
926 return thunkFn;
927 }
928
929 setThunkProperties(cgm, thunkAdjustments, thunkFn, forVTable, gd);
930 return thunkFn;
931 }
932
933 // TODO(cir): Add "thunk" attribute if unprototyped.
934
935 cgm.setCIRFunctionAttributesForDefinition(cast<FunctionDecl>(gd.getDecl()),
936 thunkFn);
937
938 // Thunks for variadic methods are special because in general variadic
939 // arguments cannot be perfectly forwarded. In the general case, clang
940 // implements such thunks by cloning the original function body. However, for
941 // thunks with no return adjustment on targets that support musttail, we can
942 // use musttail to perfectly forward the variadic arguments.
943 bool shouldCloneVarArgs = false;
944 if (!isUnprototyped && thunkFn.getFunctionType().isVarArg()) {
945 shouldCloneVarArgs = true;
946 if (thunkAdjustments.Return.isEmpty()) {
947 switch (cgm.getTriple().getArch()) {
948 case llvm::Triple::x86_64:
949 case llvm::Triple::x86:
950 case llvm::Triple::aarch64:
951 shouldCloneVarArgs = false;
952 break;
953 default:
954 break;
955 }
956 }
957 }
958
959 if (shouldCloneVarArgs) {
960 if (useAvailableExternallyLinkage)
961 return thunkFn;
962 cgm.errorNYI("varargs thunk cloning");
963 } else {
964 // Normal thunk body generation.
965 mlir::OpBuilder::InsertionGuard guard(cgm.getBuilder());
966 CIRGenFunction cgf(cgm, cgm.getBuilder());
967 cgf.generateThunk(thunkFn, fnInfo, gd, thunkAdjustments, isUnprototyped);
968 }
969
970 setThunkProperties(cgm, thunkAdjustments, thunkFn, forVTable, gd);
971 return thunkFn;
972}
973
975 const CXXMethodDecl *md =
976 cast<CXXMethodDecl>(gd.getDecl())->getCanonicalDecl();
977
978 // We don't need to generate thunks for the base destructor.
980 return;
981
982 const VTableContextBase::ThunkInfoVectorTy *thunkInfoVector =
983 vtContext->getThunkInfo(gd);
984
985 if (!thunkInfoVector)
986 return;
987
988 for (const ThunkInfo &thunk : *thunkInfoVector)
989 maybeEmitThunk(gd, thunk, /*forVTable=*/false);
990}
991
993 const CXXRecordDecl *rd) {
994 return cgm.getCodeGenOpts().OptimizationLevel > 0 &&
996}
997
998/// Given that we're currently at the end of the translation unit, and
999/// we've emitted a reference to the vtable for this class, should
1000/// we define that vtable?
1002 const CXXRecordDecl *rd) {
1003 // If vtable is internal then it has to be done.
1004 if (!cgm.getVTables().isVTableExternal(rd))
1005 return true;
1006
1007 // If it's external then maybe we will need it as available_externally.
1009}
1010
1011/// Given that at some point we emitted a reference to one or more
1012/// vtables, and that we are now at the end of the translation unit,
1013/// decide whether we should emit them.
1015#ifndef NDEBUG
1016 // Remember the size of DeferredVTables, because we're going to assume
1017 // that this entire operation doesn't modify it.
1018 size_t savedSize = deferredVTables.size();
1019#endif
1020 for (const CXXRecordDecl *rd : deferredVTables) {
1022 vtables.generateClassData(rd);
1024 opportunisticVTables.push_back(rd);
1025 }
1026
1027 assert(savedSize == deferredVTables.size() &&
1028 "deferred extra vtables during vtable emission?");
1029 deferredVTables.clear();
1030}
1031
1033 // Try to emit external vtables as available_externally if they have emitted
1034 // all inlined virtual functions. It runs after EmitDeferred() and therefore
1035 // is not allowed to create new references to things that need to be emitted
1036 // lazily. Note that it also uses fact that we eagerly emitting RTTI.
1037
1038 assert(
1039 (opportunisticVTables.empty() || shouldOpportunisticallyEmitVTables()) &&
1040 "Only emit opportunistic vtables with optimizations");
1041
1042 for (const CXXRecordDecl *rd : opportunisticVTables) {
1043 assert(getVTables().isVTableExternal(rd) &&
1044 "This queue should only contain external vtables");
1045 if (getCXXABI().canSpeculativelyEmitVTable(rd))
1046 vtables.generateClassData(rd);
1047 }
1048 opportunisticVTables.clear();
1049}
1050
1052 return codeGenOpts.OptimizationLevel > 0;
1053}
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.
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
Definition ASTContext.h:959
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:924
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
void generateThunk(cir::FuncOp fn, const CIRGenFunctionInfo &fnInfo, GlobalDecl gd, const ThunkInfo &thunk, bool isUnprototyped)
Generate code for a thunk function.
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.
void emitCallAndReturnForThunk(cir::FuncOp callee, const ThunkInfo *thunk, bool isUnprototyped)
Emit the call and return for a thunk function.
static bool hasAggregateEvaluationKind(clang::QualType type)
void finishFunction(SourceLocation endLoc)
RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, mlir::Location loc)
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.
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 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:2882
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2132
QualType getThisType() const
Return the type of the this pointer.
Definition DeclCXX.cpp:2861
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:2060
bool isDynamicClass() const
Definition DeclCXX.h:574
unsigned getNumVBases() const
Retrieves the number of virtual base classes of this class.
Definition DeclCXX.h:623
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:547
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:2018
param_iterator param_end()
Definition Decl.h:2805
bool isInlined() const
Determine whether this function should be inlined, because it is either marked "inline" or "constexpr...
Definition Decl.h:2939
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2792
param_iterator param_begin()
Definition Decl.h:2804
TemplateSpecializationKind getTemplateSpecializationKind() const
Determine what kind of template instantiation this function represents.
Definition Decl.cpp:4412
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition Decl.cpp:3194
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5362
FunctionType - C99 6.7.5.3 - Function Declarators.
Definition TypeBase.h:4558
QualType getReturnType() const
Definition TypeBase.h:4898
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:57
CXXDtorType getDtorType() const
Definition GlobalDecl.h:113
const Decl * getDecl() const
Definition GlobalDecl.h:106
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:433
Represents a parameter to a function.
Definition Decl.h:1808
A (possibly-)qualified type.
Definition TypeBase.h:937
Encodes a location in the source.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:4888
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:9039
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:9333
bool isReferenceType() const
Definition TypeBase.h:8697
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:1958
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
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:723
static bool isLocalLinkage(GlobalLinkageKind linkage)
Definition CIROpsEnums.h:51
const AstTypeMatcher< ArrayType > arrayType
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ 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 setDLLStorageClass()
static bool opCallInAlloca()
static bool pointerAuthentication()
static bool opCallMustTail()
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