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.setSelfComdat();
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
177 const bool isThunk =
178 nextVTableThunkIndex < layout.vtable_thunks().size() &&
179 layout.vtable_thunks()[nextVTableThunkIndex].first == componentIndex;
180
181 if (cgm.getLangOpts().CUDA) {
182 // Emit NULL for methods we can't codegen on this
183 // side. Otherwise we'd end up with vtable with unresolved
184 // references.
185 const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl());
186 // OK on device side: functions w/ __device__ attribute
187 // OK on host side: anything except __device__-only functions.
188 bool canEmitMethod =
189 cgm.getLangOpts().CUDAIsDevice
190 ? md->hasAttr<CUDADeviceAttr>()
191 : (md->hasAttr<CUDAHostAttr>() || !md->hasAttr<CUDADeviceAttr>());
192 if (!canEmitMethod) {
193 if (isThunk)
194 nextVTableThunkIndex++;
195 return builder.getConstNullPtrAttr(builder.getUInt8PtrTy());
196 }
197 // Method is acceptable, continue processing as usual.
198 }
199
200 auto getSpecialVirtFn = [&](StringRef name) -> cir::FuncOp {
202
203 if (cgm.getLangOpts().OpenMP && cgm.getLangOpts().OpenMPIsTargetDevice &&
204 cgm.getTriple().isNVPTX())
205 cgm.errorNYI(gd.getDecl()->getSourceRange(),
206 "getVTableComponent for OMP Device NVPTX");
207
208 cir::FuncType fnTy =
209 cgm.getBuilder().getFuncType({}, cgm.getBuilder().getVoidTy());
210 cir::FuncOp fnPtr = cgm.createRuntimeFunction(fnTy, name);
211
213
214 // The Microsoft ABI uses the same function name for pure and deleted
215 // virtual functions.
216 if (!fnPtr.isDeclaration())
217 return fnPtr;
218
219 // For device compilation, provide a weak definition that traps,
220 // otherwise linking ends up with unresolved references.
221 if (cgm.getLangOpts().isTargetDevice()) {
222 fnPtr.setLinkage(cir::GlobalLinkageKind::WeakAnyLinkage);
223 mlir::SymbolTable::setSymbolVisibility(
224 fnPtr, cgm.getMLIRVisibilityFromCIRLinkage(fnPtr.getLinkage()));
225 mlir::OpBuilder::InsertionGuard guard(builder);
226 builder.setInsertionPointToStart(fnPtr.addEntryBlock());
227 cir::TrapOp::create(builder, fnPtr.getLoc());
228 }
229
230 return fnPtr;
231 };
232
233 cir::FuncOp fnPtr;
234 if (cast<CXXMethodDecl>(gd.getDecl())->isPureVirtual()) {
235 if (!pureVirtualFn)
236 pureVirtualFn =
237 getSpecialVirtFn(cgm.getCXXABI().getPureVirtualCallName());
238 fnPtr = pureVirtualFn;
239 } else if (cast<CXXMethodDecl>(gd.getDecl())->isDeleted()) {
240 if (!deletedVirtualFn)
241 deletedVirtualFn =
242 getSpecialVirtFn(cgm.getCXXABI().getDeletedVirtualCallName());
243 fnPtr = deletedVirtualFn;
244 } else if (isThunk) {
245 const ThunkInfo &thunkInfo =
246 layout.vtable_thunks()[nextVTableThunkIndex].second;
247 nextVTableThunkIndex++;
248 fnPtr = maybeEmitThunk(gd, thunkInfo, /*forVTable=*/true);
250 } else {
251 // Otherwise we can use the method definition directly.
252 cir::FuncType fnTy = cgm.getTypes().getFunctionType(gd);
253 fnPtr = cgm.getAddrOfFunction(gd, fnTy, /*ForVTable=*/true);
254 }
255
256 return cir::GlobalViewAttr::get(
257 builder.getUInt8PtrTy(),
258 mlir::FlatSymbolRefAttr::get(fnPtr.getSymNameAttr()));
259 }
260 }
261
262 llvm_unreachable("Unexpected vtable component kind");
263}
264
265void CIRGenVTables::createVTableInitializer(cir::GlobalOp &vtableOp,
266 const clang::VTableLayout &layout,
267 mlir::Attribute rtti,
268 bool vtableHasLocalLinkage) {
269 mlir::Type componentType = getVTableComponentType();
270
271 const llvm::SmallVectorImpl<unsigned> &addressPoints =
272 layout.getAddressPointIndices();
273 unsigned nextVTableThunkIndex = 0;
274
275 mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();
276
278 for (auto [vtableIndex, addressPoint] : llvm::enumerate(addressPoints)) {
279 // Build a ConstArrayAttr of the vtable components.
280 size_t vtableStart = layout.getVTableOffset(vtableIndex);
281 size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex);
283 components.reserve(vtableEnd - vtableStart);
284 for (size_t componentIndex : llvm::seq(vtableStart, vtableEnd))
285 components.push_back(
286 getVTableComponent(layout, componentIndex, rtti, nextVTableThunkIndex,
287 addressPoint, vtableHasLocalLinkage));
288 // Create a ConstArrayAttr to hold the components.
289 auto arr = cir::ConstArrayAttr::get(
290 cir::ArrayType::get(componentType, components.size()),
291 mlir::ArrayAttr::get(mlirContext, components));
292 vtables.push_back(arr);
293 }
294
295 // Create a ConstRecordAttr to hold the component array.
296 const auto members = mlir::ArrayAttr::get(mlirContext, vtables);
297 cir::ConstRecordAttr record = cgm.getBuilder().getAnonConstRecord(members);
298
299 // Create a VTableAttr
300 auto vtableAttr = cir::VTableAttr::get(record.getType(), record.getMembers());
301
302 // Add the vtable initializer to the vtable global op.
303 cgm.setInitializer(vtableOp, vtableAttr);
304}
305
307 const CXXRecordDecl *rd, const BaseSubobject &base, bool baseIsVirtual,
308 cir::GlobalLinkageKind linkage, VTableAddressPointsMapTy &addressPoints) {
310
311 std::unique_ptr<VTableLayout> vtLayout(
312 getItaniumVTableContext().createConstructionVTableLayout(
313 base.getBase(), base.getBaseOffset(), baseIsVirtual, rd));
314
315 // Add the address points.
316 addressPoints = vtLayout->getAddressPoints();
317
318 // Get the mangled construction vtable name.
319 SmallString<256> outName;
320 llvm::raw_svector_ostream out(outName);
321 cast<ItaniumMangleContext>(cgm.getCXXABI().getMangleContext())
322 .mangleCXXCtorVTable(rd, base.getBaseOffset().getQuantity(),
323 base.getBase(), out);
324 SmallString<256> name(outName);
325
327
328 cir::RecordType vtType = getVTableType(*vtLayout);
329
330 // Construction vtable symbols are not part of the Itanium ABI, so we cannot
331 // guarantee that they actually will be available externally. Instead, when
332 // emitting an available_externally VTT, we provide references to an internal
333 // linkage construction vtable. The ABI only requires complete-object vtables
334 // to be the same for all instances of a type, not construction vtables.
335 if (linkage == cir::GlobalLinkageKind::AvailableExternallyLinkage)
336 linkage = cir::GlobalLinkageKind::InternalLinkage;
337
338 llvm::Align align = cgm.getDataLayout().getABITypeAlign(vtType);
339 mlir::Location loc = cgm.getLoc(rd->getSourceRange());
340
341 // Create the variable that will hold the construction vtable.
342 cir::GlobalOp vtable = cgm.createOrReplaceCXXRuntimeVariable(
343 loc, name, vtType, linkage, CharUnits::fromQuantity(align));
344
345 // V-tables are always unnamed_addr.
347
348 mlir::Attribute rtti = cgm.getAddrOfRTTIDescriptor(
349 loc, cgm.getASTContext().getCanonicalTagType(base.getBase()));
350
351 // Create and set the initializer.
352 createVTableInitializer(vtable, *vtLayout, rtti,
353 cir::isLocalLinkage(vtable.getLinkage()));
354
355 // Set properties only after the initializer has been set to ensure that the
356 // GV is treated as definition and not declaration.
357 assert(!vtable.isDeclaration() && "Shouldn't set properties on declaration");
358 cgm.setGVProperties(vtable, rd);
359
362
363 return vtable;
364}
365
367 const CXXRecordDecl *rd);
368
369/// Compute the required linkage of the vtable for the given class.
370///
371/// Note that we only call this at the end of the translation unit.
372cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) {
373 if (!rd->isExternallyVisible())
374 return cir::GlobalLinkageKind::InternalLinkage;
375
376 // We're at the end of the translation unit, so the current key
377 // function is fully correct.
378 const CXXMethodDecl *keyFunction = astContext.getCurrentKeyFunction(rd);
379 if (keyFunction && !rd->hasAttr<DLLImportAttr>()) {
380 // If this class has a key function, use that to determine the
381 // linkage of the vtable.
382 const FunctionDecl *def = nullptr;
383 if (keyFunction->hasBody(def))
384 keyFunction = cast<CXXMethodDecl>(def);
385
386 // All of the cases below do something different with AppleKext enabled.
388 switch (keyFunction->getTemplateSpecializationKind()) {
389 case TSK_Undeclared:
391 assert(
392 (def || codeGenOpts.OptimizationLevel > 0 ||
393 codeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo) &&
394 "Shouldn't query vtable linkage without key function, "
395 "optimizations, or debug info");
396 if (!def && codeGenOpts.OptimizationLevel > 0)
397 return cir::GlobalLinkageKind::AvailableExternallyLinkage;
398
399 if (keyFunction->isInlined())
400 return !astContext.getLangOpts().AppleKext
401 ? cir::GlobalLinkageKind::LinkOnceODRLinkage
402 : cir::GlobalLinkageKind::InternalLinkage;
403 return cir::GlobalLinkageKind::ExternalLinkage;
404
406 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
407
409 return cir::GlobalLinkageKind::WeakODRLinkage;
410
412 return !def ? cir::GlobalLinkageKind::AvailableExternallyLinkage
413 : cir::GlobalLinkageKind::ExternalLinkage;
414 }
415 }
416 // -fapple-kext mode does not support weak linkage, so we must use
417 // internal linkage.
418 if (astContext.getLangOpts().AppleKext)
419 return cir::GlobalLinkageKind::InternalLinkage;
420
421 auto discardableODRLinkage = cir::GlobalLinkageKind::LinkOnceODRLinkage;
422 auto nonDiscardableODRLinkage = cir::GlobalLinkageKind::WeakODRLinkage;
423 if (rd->hasAttr<DLLExportAttr>()) {
424 // Cannot discard exported vtables.
425 discardableODRLinkage = nonDiscardableODRLinkage;
426 } else if (rd->hasAttr<DLLImportAttr>()) {
427 // Imported vtables are available externally.
428 discardableODRLinkage = cir::GlobalLinkageKind::AvailableExternallyLinkage;
429 nonDiscardableODRLinkage =
430 cir::GlobalLinkageKind::AvailableExternallyLinkage;
431 }
432
433 switch (rd->getTemplateSpecializationKind()) {
434 case TSK_Undeclared:
437 return discardableODRLinkage;
438
440 // Explicit instantiations in MSVC do not provide vtables, so we must emit
441 // our own.
442 if (getTarget().getCXXABI().isMicrosoft())
443 return discardableODRLinkage;
445 ? cir::GlobalLinkageKind::AvailableExternallyLinkage
446 : cir::GlobalLinkageKind::ExternalLinkage;
447
449 return nonDiscardableODRLinkage;
450 }
451
452 llvm_unreachable("Invalid TemplateSpecializationKind!");
453}
454
456 assert(rd->getNumVBases() && "Only classes with virtual bases need a VTT");
457
458 SmallString<256> outName;
459 llvm::raw_svector_ostream out(outName);
460 cast<ItaniumMangleContext>(cgm.getCXXABI().getMangleContext())
461 .mangleCXXVTT(rd, out);
462 StringRef name = outName.str();
463
464 // This will also defer the definition of the VTT.
465 (void)cgm.getCXXABI().getAddrOfVTable(rd, CharUnits());
466
467 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);
468
469 auto arrayType = cir::ArrayType::get(cgm.getBuilder().getUInt8PtrTy(),
470 builder.getVTTComponents().size());
471 llvm::Align align =
472 cgm.getDataLayout().getABITypeAlign(cgm.getBuilder().getUInt8PtrTy());
473 cir::GlobalOp vtt = cgm.createOrReplaceCXXRuntimeVariable(
474 cgm.getLoc(rd->getSourceRange()), name, arrayType,
475 cir::GlobalLinkageKind::ExternalLinkage, CharUnits::fromQuantity(align));
476 cgm.setGVProperties(vtt, rd);
477 return vtt;
478}
479
480static cir::GlobalOp
482 const CXXRecordDecl *mostDerivedClass,
483 const VTTVTable &vtable, cir::GlobalLinkageKind linkage,
484 VTableLayout::AddressPointsMapTy &addressPoints) {
485 if (vtable.getBase() == mostDerivedClass) {
486 assert(vtable.getBaseOffset().isZero() &&
487 "Most derived class vtable must have a zero offset!");
488 // This is a regular vtable.
489 return cgm.getCXXABI().getAddrOfVTable(mostDerivedClass, CharUnits());
490 }
491 return cgvt.generateConstructionVTable(
492 mostDerivedClass, vtable.getBaseSubobject(), vtable.isVirtual(), linkage,
493 addressPoints);
494}
495
496/// Emit the definition of the given vtable.
497void CIRGenVTables::emitVTTDefinition(cir::GlobalOp vttOp,
498 cir::GlobalLinkageKind linkage,
499 const CXXRecordDecl *rd) {
500 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/true);
501
502 mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();
503
504 auto arrayType = cir::ArrayType::get(cgm.getBuilder().getUInt8PtrTy(),
505 builder.getVTTComponents().size());
506
508 SmallVector<VTableAddressPointsMapTy> vtableAddressPoints;
509 for (const VTTVTable &vtt : builder.getVTTVTables()) {
510 vtableAddressPoints.push_back(VTableAddressPointsMapTy());
511 vtables.push_back(getAddrOfVTTVTable(*this, cgm, rd, vtt, linkage,
512 vtableAddressPoints.back()));
513 }
514
515 SmallVector<mlir::Attribute> vttComponents;
516 for (const VTTComponent &vttComponent : builder.getVTTComponents()) {
517 const VTTVTable &vttVT = builder.getVTTVTables()[vttComponent.VTableIndex];
518 cir::GlobalOp vtable = vtables[vttComponent.VTableIndex];
520 if (vttVT.getBase() == rd) {
521 // Just get the address point for the regular vtable.
522 addressPoint =
524 vttComponent.VTableBase);
525 } else {
526 addressPoint = vtableAddressPoints[vttComponent.VTableIndex].lookup(
527 vttComponent.VTableBase);
528 assert(addressPoint.AddressPointIndex != 0 &&
529 "Did not find ctor vtable address point!");
530 }
531
532 mlir::Attribute indices[2] = {
533 cgm.getBuilder().getI32IntegerAttr(addressPoint.VTableIndex),
534 cgm.getBuilder().getI32IntegerAttr(addressPoint.AddressPointIndex),
535 };
536
537 auto indicesAttr = mlir::ArrayAttr::get(mlirContext, indices);
538 CIRGenBuilderTy &bld = cgm.getBuilder();
539 auto init = bld.getGlobalViewAttr(bld.getUInt8PtrTy(), vtable, indicesAttr,
540 /*addressPoint=*/true);
541
542 vttComponents.push_back(init);
543 }
544
545 auto init = cir::ConstArrayAttr::get(
546 arrayType, mlir::ArrayAttr::get(mlirContext, vttComponents));
547
548 vttOp.setInitialValueAttr(init);
549
550 // Set the correct linkage.
551 vttOp.setLinkage(linkage);
552 mlir::SymbolTable::setSymbolVisibility(
553 vttOp, CIRGenModule::getMLIRVisibility(vttOp));
554
555 if (cgm.supportsCOMDAT() && vttOp.isWeakForLinker())
556 vttOp.setSelfComdat();
557}
558
560 BaseSubobject base) {
561 BaseSubobjectPairTy classSubobjectPair(rd, base);
562
563 SubVTTIndiciesMapTy::iterator it = subVTTIndicies.find(classSubobjectPair);
564 if (it != subVTTIndicies.end())
565 return it->second;
566
567 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);
568
569 for (const auto &entry : builder.getSubVTTIndices()) {
570 // Insert all indices.
571 BaseSubobjectPairTy subclassSubobjectPair(rd, entry.first);
572
573 subVTTIndicies.insert(std::make_pair(subclassSubobjectPair, entry.second));
574 }
575
576 it = subVTTIndicies.find(classSubobjectPair);
577 assert(it != subVTTIndicies.end() && "Did not find index!");
578
579 return it->second;
580}
581
583 BaseSubobject base) {
584 auto it = secondaryVirtualPointerIndices.find(std::make_pair(rd, base));
585
586 if (it != secondaryVirtualPointerIndices.end())
587 return it->second;
588
589 VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);
590
591 // Insert all secondary vpointer indices.
592 for (const auto &entry : builder.getSecondaryVirtualPointerIndices()) {
593 std::pair<const CXXRecordDecl *, BaseSubobject> pair =
594 std::make_pair(rd, entry.first);
595
596 secondaryVirtualPointerIndices.insert(std::make_pair(pair, entry.second));
597 }
598
599 it = secondaryVirtualPointerIndices.find(std::make_pair(rd, base));
600 assert(it != secondaryVirtualPointerIndices.end() && "Did not find index!");
601
602 return it->second;
603}
604
606 RValue rv, const ThunkInfo &thunk) {
607 // Emit the return adjustment. For non-reference pointer returns, match
608 // classic codegen: skip the adjustment when the returned pointer is null.
609 bool nullCheckValue = !resultType->isReferenceType();
610 mlir::Value returnValue = rv.getValue();
611
612 const CXXRecordDecl *classDecl =
613 resultType->getPointeeType()->getAsCXXRecordDecl();
614 CharUnits classAlign = cgf.cgm.getClassPointerAlignment(classDecl);
615 mlir::Type pointeeType = cgf.convertTypeForMem(resultType->getPointeeType());
616 CIRGenBuilderTy &builder = cgf.getBuilder();
617 mlir::Location loc = returnValue.getLoc();
618
619 if (!nullCheckValue) {
620 returnValue = cgf.cgm.getCXXABI().performReturnAdjustment(
621 cgf, Address(returnValue, pointeeType, classAlign), classDecl,
622 thunk.Return);
623 return RValue::get(returnValue);
624 }
625
626 mlir::Value isNotNull = builder.createPtrIsNotNull(returnValue);
627 returnValue =
628 cir::TernaryOp::create(
629 builder, loc, isNotNull,
630 [&](mlir::OpBuilder &, mlir::Location) {
631 mlir::Value adjusted = cgf.cgm.getCXXABI().performReturnAdjustment(
632 cgf, Address(returnValue, pointeeType, classAlign), classDecl,
633 thunk.Return);
634 builder.createYield(loc, adjusted);
635 },
636 [&](mlir::OpBuilder &, mlir::Location) {
637 mlir::Value nullVal =
638 builder.getNullPtr(returnValue.getType(), loc).getResult();
639 builder.createYield(loc, nullVal);
640 })
641 .getResult();
642
643 return RValue::get(returnValue);
644}
645
647 const CIRGenFunctionInfo &fnInfo,
648 bool isUnprototyped) {
649 assert(!curGD.getDecl() && "curGD was already set!");
650 curGD = gd;
651 curFuncIsThunk = true;
652
653 // Build FunctionArgs.
654 const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl());
655 QualType thisType = md->getThisType();
656 QualType resultType;
657 if (isUnprototyped)
658 resultType = cgm.getASTContext().VoidTy;
659 else if (cgm.getCXXABI().hasThisReturn(gd))
660 resultType = thisType;
661 else if (cgm.getCXXABI().hasMostDerivedReturn(gd))
662 resultType = cgm.getASTContext().VoidPtrTy;
663 else
664 resultType = md->getType()->castAs<FunctionProtoType>()->getReturnType();
665 FunctionArgList functionArgs;
666
667 // Create the implicit 'this' parameter declaration.
668 cgm.getCXXABI().buildThisParam(*this, functionArgs);
669
670 // Add the rest of the parameters, if we have a prototype to work with.
671 if (!isUnprototyped) {
672 functionArgs.append(md->param_begin(), md->param_end());
673
675 cgm.getCXXABI().addImplicitStructorParams(*this, resultType,
676 functionArgs);
677 }
678
680
681 // Start defining the function.
682 cir::FuncType funcType = cgm.getTypes().getFunctionType(fnInfo);
683 startFunction(GlobalDecl(), resultType, fn, funcType, functionArgs,
684 md->getLocation(), md->getLocation());
685 // TODO(cir): Move this into startFunction.
686 curFnInfo = &fnInfo;
688
689 // Since we didn't pass a GlobalDecl to startFunction, do this ourselves.
690 cgm.getCXXABI().emitInstanceFunctionProlog(md->getLocation(), *this);
692 curCodeDecl = md;
693 curFuncDecl = md;
694}
695
697 // Clear these to restore the invariants expected by
698 // startFunction/finishFunction.
699 curCodeDecl = nullptr;
700 curFuncDecl = nullptr;
701
703}
704
706 SourceRange fnLoc,
707 const ThunkInfo *thunk,
708 bool isUnprototyped) {
709 assert(isa<CXXMethodDecl>(curGD.getDecl()) &&
710 "Please use a new CGF for this thunk");
711 const CXXMethodDecl *md = cast<CXXMethodDecl>(curGD.getDecl());
712
713 // Determine the this pointer class (may differ from md's class for thunks).
714 const CXXRecordDecl *thisValueClass =
716 if (thunk)
717 thisValueClass = thunk->ThisType->getPointeeCXXRecordDecl();
718
719 mlir::Value adjustedThisPtr =
720 thunk ? cgm.getCXXABI().performThisAdjustment(*this, loadCXXThisAddress(),
721 thisValueClass, *thunk)
722 : loadCXXThis();
723
724 // If perfect forwarding is required a variadic method, a method using
725 // inalloca, or an unprototyped thunk, use musttail. Emit an error if this
726 // thunk requires a return adjustment, since that is impossible with musttail.
728 if ((curFnInfo && curFnInfo->isVariadic()) || isUnprototyped) {
729 // Error if return adjustment is needed (can't do with musttail).
730 if (thunk && !thunk->Return.isEmpty()) {
731 if (isUnprototyped)
732 cgm.errorUnsupported(
733 md, "return-adjusting thunk with incomplete parameter type");
734 else if (curFnInfo && curFnInfo->isVariadic())
735 llvm_unreachable("shouldn't try to emit musttail return-adjusting "
736 "thunks for variadic functions");
737 else
738 cgm.errorUnsupported(
739 md, "non-trivial argument copy for return-adjusting thunk");
740 }
741 emitMustTailThunk(curGD, adjustedThisPtr, callee);
742 return;
743 }
744
745 // Build the call argument list.
746 CallArgList callArgs;
747 QualType thisType = md->getThisType();
748 callArgs.add(RValue::get(adjustedThisPtr), thisType);
749
751 cgm.getCXXABI().adjustCallArgsForDestructorThunk(*this, curGD, callArgs);
752
753#ifndef NDEBUG
754 unsigned prefixArgs = callArgs.size() - 1;
755#endif
756
757 // Add the rest of the method parameters.
758 for (const ParmVarDecl *pd : md->parameters())
759 emitDelegateCallArg(callArgs, pd, SourceLocation());
760
761 const FunctionProtoType *fpt = md->getType()->castAs<FunctionProtoType>();
762
763#ifndef NDEBUG
764 const CIRGenFunctionInfo &callFnInfo = cgm.getTypes().arrangeCXXMethodCall(
765 callArgs, fpt, RequiredArgs::getFromProtoWithExtraSlots(fpt, 1),
766 prefixArgs);
767 assert(callFnInfo.argTypeSize() == curFnInfo->argTypeSize());
768#endif
769
770 // Determine whether we have a return value slot to use.
771 QualType resultType = cgm.getCXXABI().hasThisReturn(curGD) ? thisType
772 : cgm.getCXXABI().hasMostDerivedReturn(curGD)
773 ? cgm.getASTContext().VoidPtrTy
774 : fpt->getReturnType();
775
776 ReturnValueSlot slot;
777 // This should also be tracking volatile, unused, and externally destructed.
779 if (!resultType->isVoidType() && hasAggregateEvaluationKind(resultType))
781
782 // Now emit our call.
783 CIRGenCallee cirCallee = CIRGenCallee::forDirect(callee, curGD);
784 mlir::Location loc = builder.getUnknownLoc();
785 RValue rv = emitCall(*curFnInfo, cirCallee, slot, callArgs,
786 /*callOrTryCall=*/nullptr, /*isMustTail=*/false, fnLoc);
787
788 // Consider return adjustment if we have ThunkInfo.
789 if (thunk && !thunk->Return.isEmpty())
790 rv = performReturnAdjustment(*this, resultType, rv, *thunk);
791 else
793
794 // Emit return. For aggregate returns the call has already written the
795 // result through the slot bound to returnValue above; emit the
796 // corresponding load+return here rather than leaving the function to
797 // fall off the end and have LexicalScope::emitImplicitReturn drop a
798 // `cir.trap` / `cir.unreachable` in its place (which would silently
799 // discard the result we just stored).
800 if (!resultType->isVoidType()) {
801 if (slot.isNull())
802 cgm.getCXXABI().emitReturnFromThunk(*this, rv, resultType);
803 else
804 emitReturnOfRValue(loc, rv, resultType);
805 }
806
807 // Disable final ARC autorelease.
809
810 finishThunk();
811}
812
814 mlir::Value adjustedThisPtr,
815 cir::FuncOp callee) {
816 // Forward all function arguments, replacing 'this' with the adjusted pointer.
817 // The call is marked musttail so varargs are forwarded correctly.
818 mlir::Block *entryBlock = getCurFunctionEntryBlock();
820 for (mlir::BlockArgument arg : entryBlock->getArguments())
821 args.push_back(arg);
822
823 // Replace the 'this' argument (first arg) with the adjusted pointer.
824 assert(!args.empty() && "thunk must have at least 'this' argument");
825 if (adjustedThisPtr.getType() != args[0].getType())
826 adjustedThisPtr = builder.createBitcast(adjustedThisPtr, args[0].getType());
827 args[0] = adjustedThisPtr;
828
829 mlir::Location loc = curFn->getLoc();
830 cir::FuncType calleeTy = callee.getFunctionType();
831 mlir::Type retTy = calleeTy.getReturnType();
832
834 cir::CallOp call =
835 builder.createCallOp(loc, callee, args, /*attrs=*/{}, /*argAttrs=*/{},
836 /*resAttrs=*/{}, curFnInfo->getCallingConvention());
837 call->setAttr(cir::CIRDialect::getMustTailAttrName(),
838 mlir::UnitAttr::get(builder.getContext()));
839
840 if (isa<cir::VoidType>(retTy))
841 cir::ReturnOp::create(builder, loc);
842 else
843 cir::ReturnOp::create(builder, loc, call->getResult(0));
844
845 finishThunk();
846}
847
849 const CIRGenFunctionInfo &fnInfo,
850 GlobalDecl gd, const ThunkInfo &thunk,
851 bool isUnprototyped) {
852 // Create entry block and set up the builder's insertion point.
853 // This must be done before calling startThunk() which calls startFunction().
854 assert(fn.isDeclaration() && "Function already has body?");
855 mlir::Block *entryBb = fn.addEntryBlock();
856 builder.setInsertionPointToStart(entryBb);
857
858 // Create a scope in the symbol table to hold variable declarations.
859 // This is required before startFunction processes parameters, as it will
860 // insert them into the symbolTable (ScopedHashTable) which requires an
861 // active scope.
863
864 // Create lexical scope - must stay alive for entire thunk generation.
865 // startFunction() requires currLexScope to be set.
866 SourceLocRAIIObject locRAII(*this, fnLoc);
867 LexicalScope lexScope{*this, fn.getLoc(), entryBb};
868
869 startThunk(fn, gd, fnInfo, isUnprototyped);
871
872 // Get our callee. Use a placeholder type if this method is unprototyped so
873 // that CIRGenModule doesn't try to set attributes.
874 mlir::Type ty;
875 if (isUnprototyped)
876 cgm.errorNYI("unprototyped thunk placeholder type");
877 else
878 ty = cgm.getTypes().getFunctionType(fnInfo);
879
880 cir::FuncOp calleeOp = cgm.getAddrOfFunction(gd, ty, /*forVTable=*/true);
881
882 // Make the call and return the result.
883 emitCallAndReturnForThunk(calleeOp, fnLoc, &thunk, isUnprototyped);
884}
885
887 bool isUnprototyped, bool forVTable) {
888 // Always emit thunks in the MS C++ ABI. We cannot rely on other TUs to
889 // provide thunks for us.
890 if (cgm.getTarget().getCXXABI().isMicrosoft())
891 return true;
892
893 // In the Itanium C++ ABI, vtable thunks are provided by TUs that provide
894 // definitions of the main method. Therefore, emitting thunks with the vtable
895 // is purely an optimization. Emit the thunk if optimizations are enabled and
896 // all of the parameter types are complete.
897 if (forVTable)
898 return cgm.getCodeGenOpts().OptimizationLevel && !isUnprototyped;
899
900 // Always emit thunks along with the method definition.
901 return true;
902}
903
905 const ThunkInfo &thunkAdjustments,
906 bool forVTable) {
907 const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl());
908 SmallString<256> name;
909 MangleContext &mCtx = cgm.getCXXABI().getMangleContext();
910
911 llvm::raw_svector_ostream out(name);
912 if (const CXXDestructorDecl *dd = dyn_cast<CXXDestructorDecl>(md)) {
913 mCtx.mangleCXXDtorThunk(dd, gd.getDtorType(), thunkAdjustments,
914 /*elideOverrideInfo=*/false, out);
915 } else {
916 mCtx.mangleThunk(md, thunkAdjustments, /*elideOverrideInfo=*/false, out);
917 }
918
919 if (cgm.getASTContext().useAbbreviatedThunkName(gd, name.str())) {
920 name = "";
921 if (const CXXDestructorDecl *dd = dyn_cast<CXXDestructorDecl>(md))
922 mCtx.mangleCXXDtorThunk(dd, gd.getDtorType(), thunkAdjustments,
923 /*elideOverrideInfo=*/true, out);
924 else
925 mCtx.mangleThunk(md, thunkAdjustments, /*elideOverrideInfo=*/true, out);
926 }
927
928 cir::FuncType thunkVTableTy = cgm.getTypes().getFunctionType(gd);
929 cir::FuncOp thunk = cgm.getAddrOfThunk(name, thunkVTableTy, gd);
930
931 // If we don't need to emit a definition, return this declaration as is.
932 bool isUnprototyped = !cgm.getTypes().isFuncTypeConvertible(
933 md->getType()->castAs<FunctionType>());
934 if (!shouldEmitVTableThunk(cgm, md, isUnprototyped, forVTable))
935 return thunk;
936
937 // Arrange a function prototype appropriate for a function definition. In some
938 // cases in the MS ABI, we may need to build an unprototyped musttail thunk.
939 const CIRGenFunctionInfo &fnInfo =
940 isUnprototyped ? (cgm.errorNYI("unprototyped must-tail thunk"),
941 cgm.getTypes().arrangeGlobalDeclaration(gd))
942 : cgm.getTypes().arrangeGlobalDeclaration(gd);
943 cir::FuncType thunkFnTy = cgm.getTypes().getFunctionType(fnInfo);
944
945 // This is to replace OG's casting to a function, keeping it here to
946 // streamline the 1-to-1 mapping from OG starting below.
947 cir::FuncOp thunkFn = thunk;
948 if (thunk.getFunctionType() != thunkFnTy) {
949 cir::FuncOp oldThunkFn = thunkFn;
950
951 assert(oldThunkFn.isDeclaration() && "Shouldn't replace non-declaration");
952
953 // Remove the name from the old thunk function and get a new thunk.
954 cgm.eraseGlobalSymbol(oldThunkFn);
955 oldThunkFn.setName(StringRef());
956 thunkFn =
957 cir::FuncOp::create(cgm.getBuilder(), thunk->getLoc(), name.str(),
958 thunkFnTy, cir::GlobalLinkageKind::ExternalLinkage);
959 cgm.insertGlobalSymbol(thunkFn);
960 cgm.setCIRFunctionAttributes(md, fnInfo, thunkFn, /*isThunk=*/false);
961
962 if (!oldThunkFn->use_empty())
963 oldThunkFn->replaceAllUsesWith(thunkFn);
964
965 // Remove the old thunk.
966 oldThunkFn->erase();
967 }
968
969 bool abiHasKeyFunctions = cgm.getTarget().getCXXABI().hasKeyFunctions();
970 bool useAvailableExternallyLinkage = forVTable && abiHasKeyFunctions;
971
972 // If the type of the underlying GlobalValue is wrong, we'll have to replace
973 // it. It should be a declaration.
974 if (!thunkFn.isDeclaration()) {
975 if (!abiHasKeyFunctions || useAvailableExternallyLinkage) {
976 // There is already a thunk emitted for this function, do nothing.
977 return thunkFn;
978 }
979
980 setThunkProperties(cgm, thunkAdjustments, thunkFn, forVTable, gd);
981 return thunkFn;
982 }
983
984 // TODO(cir): Add "thunk" attribute if unprototyped.
985
986 cgm.setCIRFunctionAttributesForDefinition(cast<FunctionDecl>(gd.getDecl()),
987 thunkFn);
988
989 // Thunks for variadic methods are special because in general variadic
990 // arguments cannot be perfectly forwarded. In the general case, clang
991 // implements such thunks by cloning the original function body. However, for
992 // thunks with no return adjustment on targets that support musttail, we can
993 // use musttail to perfectly forward the variadic arguments.
994 bool shouldCloneVarArgs = false;
995 if (!isUnprototyped && thunkFn.getFunctionType().isVarArg()) {
996 shouldCloneVarArgs = true;
997 if (thunkAdjustments.Return.isEmpty()) {
998 switch (cgm.getTriple().getArch()) {
999 case llvm::Triple::x86_64:
1000 case llvm::Triple::x86:
1001 case llvm::Triple::aarch64:
1002 shouldCloneVarArgs = false;
1003 break;
1004 default:
1005 break;
1006 }
1007 }
1008 }
1009
1010 if (shouldCloneVarArgs) {
1011 if (useAvailableExternallyLinkage)
1012 return thunkFn;
1013 cgm.errorNYI("varargs thunk cloning");
1014 } else {
1015 // Normal thunk body generation.
1016 mlir::OpBuilder::InsertionGuard guard(cgm.getBuilder());
1017 CIRGenFunction cgf(cgm, cgm.getBuilder());
1018 cgf.generateThunk(thunkFn, md->getSourceRange(), fnInfo, gd,
1019 thunkAdjustments, isUnprototyped);
1020 }
1021
1022 setThunkProperties(cgm, thunkAdjustments, thunkFn, forVTable, gd);
1023 return thunkFn;
1024}
1025
1027 const CXXMethodDecl *md =
1028 cast<CXXMethodDecl>(gd.getDecl())->getCanonicalDecl();
1029
1030 // We don't need to generate thunks for the base destructor.
1031 if (isa<CXXDestructorDecl>(md) && gd.getDtorType() == Dtor_Base)
1032 return;
1033
1034 const VTableContextBase::ThunkInfoVectorTy *thunkInfoVector =
1035 vtContext->getThunkInfo(gd);
1036
1037 if (!thunkInfoVector)
1038 return;
1039
1040 for (const ThunkInfo &thunk : *thunkInfoVector)
1041 maybeEmitThunk(gd, thunk, /*forVTable=*/false);
1042}
1043
1045 const CXXRecordDecl *rd) {
1046 return cgm.getCodeGenOpts().OptimizationLevel > 0 &&
1048}
1049
1050/// Given that we're currently at the end of the translation unit, and
1051/// we've emitted a reference to the vtable for this class, should
1052/// we define that vtable?
1054 const CXXRecordDecl *rd) {
1055 // If vtable is internal then it has to be done.
1056 if (!cgm.getVTables().isVTableExternal(rd))
1057 return true;
1058
1059 // If it's external then maybe we will need it as available_externally.
1061}
1062
1063/// Given that at some point we emitted a reference to one or more
1064/// vtables, and that we are now at the end of the translation unit,
1065/// decide whether we should emit them.
1067#ifndef NDEBUG
1068 // Remember the size of DeferredVTables, because we're going to assume
1069 // that this entire operation doesn't modify it.
1070 size_t savedSize = deferredVTables.size();
1071#endif
1072 for (const CXXRecordDecl *rd : deferredVTables) {
1074 vtables.generateClassData(rd);
1076 opportunisticVTables.push_back(rd);
1077 }
1078
1079 assert(savedSize == deferredVTables.size() &&
1080 "deferred extra vtables during vtable emission?");
1081 deferredVTables.clear();
1082}
1083
1085 // Try to emit external vtables as available_externally if they have emitted
1086 // all inlined virtual functions. It runs after EmitDeferred() and therefore
1087 // is not allowed to create new references to things that need to be emitted
1088 // lazily. Note that it also uses fact that we eagerly emitting RTTI.
1089
1090 assert(
1091 (opportunisticVTables.empty() || shouldOpportunisticallyEmitVTables()) &&
1092 "Only emit opportunistic vtables with optimizations");
1093
1094 for (const CXXRecordDecl *rd : opportunisticVTables) {
1095 assert(getVTables().isVTableExternal(rd) &&
1096 "This queue should only contain external vtables");
1097 if (getCXXABI().canSpeculativelyEmitVTable(rd))
1098 vtables.generateClassData(rd);
1099 }
1100 opportunisticVTables.clear();
1101}
1102
1104 return codeGenOpts.OptimizationLevel > 0;
1105}
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.
static bool hasAttr(const Decl *D, bool IgnoreImplicitAttr)
Definition SemaCUDA.cpp:186
mlir::TypedAttr getConstNullPtrAttr(mlir::Type t)
cir::GlobalViewAttr getGlobalViewAttr(cir::GlobalOp globalOp, mlir::ArrayAttr indices={})
Get constant address of a global variable as an MLIR attribute.
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:975
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).
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 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
This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
bool isZero() const
Test whether the quantity equals zero.
Definition CharUnits.h:101
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
Definition CharUnits.h:155
static CharUnits fromQuantity(QuantityType Quantity)
Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:58
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:3056
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:4618
TemplateSpecializationKind getTemplateSpecializationKind() const
Determine what kind of template instantiation this function represents.
Definition Decl.cpp:4466
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition Decl.cpp:3191
Represents a prototype with parameter type info, e.g.
Definition TypeBase.h:5416
FunctionType - C99 6.7.5.3 - Function Declarators.
Definition TypeBase.h:4612
QualType getReturnType() const
Definition TypeBase.h:4952
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:4974
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:9068
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:9366
bool isReferenceType() const
Definition TypeBase.h:8707
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:2080
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:885
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:192
@ TSK_ExplicitInstantiationDefinition
This template specialization was instantiated from a template due to an explicit instantiation defini...
Definition Specifiers.h:210
@ TSK_ExplicitInstantiationDeclaration
This template specialization was instantiated from a template due to an explicit instantiation declar...
Definition Specifiers.h:206
@ TSK_ExplicitSpecialization
This template specialization was declared or defined by an explicit specialization (C++ [temp....
Definition Specifiers.h:202
@ TSK_ImplicitInstantiation
This template specialization was implicitly instantiated from a template.
Definition Specifiers.h:198
@ TSK_Undeclared
This template specialization was formed from a template-id but has not yet been declared,...
Definition Specifiers.h:195
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 opCallAttrs()
static bool returnValueSlotFeatures()
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