clang 22.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"
19#include "llvm/ADT/SmallVector.h"
20
21using namespace llvm;
22using namespace clang;
23using namespace clang::CIRGen;
24
26 : cgm(cgm), vtContext(cgm.getASTContext().getVTableContext()) {}
27
29 mlir::Type ptrTy = builder.getUInt8PtrTy();
31 return ptrTy;
32}
33
34mlir::Type CIRGenVTables::getVTableComponentType() {
35 return cgm.getVTableComponentType();
36}
37
38cir::RecordType CIRGenVTables::getVTableType(const VTableLayout &layout) {
40 mlir::Type componentType = getVTableComponentType();
41 for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i)
42 tys.push_back(cir::ArrayType::get(componentType, layout.getVTableSize(i)));
43
44 // FIXME(cir): should VTableLayout be encoded like we do for some
45 // AST nodes?
46 return cgm.getBuilder().getAnonRecordTy(tys, /*incomplete=*/false);
47}
48
49/// This is a callback from Sema to tell us that a particular vtable is
50/// required to be emitted in this translation unit.
51///
52/// This is only called for vtables that _must_ be emitted (mainly due to key
53/// functions). For weak vtables, CodeGen tracks when they are needed and
54/// emits them as-needed.
56 vtables.generateClassData(rd);
57}
58
61
62 if (rd->getNumVBases())
63 cgm.errorNYI(rd->getSourceRange(), "emitVirtualInheritanceTables");
64
65 cgm.getCXXABI().emitVTableDefinitions(*this, rd);
66}
67
68mlir::Attribute CIRGenVTables::getVTableComponent(
69 const VTableLayout &layout, unsigned componentIndex, mlir::Attribute rtti,
70 unsigned &nextVTableThunkIndex, unsigned vtableAddressPoint,
71 bool vtableHasLocalLinkage) {
72 const VTableComponent &component = layout.vtable_components()[componentIndex];
73
74 CIRGenBuilderTy builder = cgm.getBuilder();
75
77
78 switch (component.getKind()) {
80 cgm.errorNYI("getVTableComponent: VCallOffset");
81 return mlir::Attribute();
83 cgm.errorNYI("getVTableComponent: VBaseOffset");
84 return mlir::Attribute();
86 cgm.errorNYI("getVTableComponent: CompleteDtorPointer");
87 return mlir::Attribute();
89 cgm.errorNYI("getVTableComponent: DeletingDtorPointer");
90 return mlir::Attribute();
92 cgm.errorNYI("getVTableComponent: UnusedFunctionPointer");
93 return mlir::Attribute();
94
96 return builder.getConstPtrAttr(builder.getUInt8PtrTy(),
97 component.getOffsetToTop().getQuantity());
98
100 assert((mlir::isa<cir::GlobalViewAttr>(rtti) ||
101 mlir::isa<cir::ConstPtrAttr>(rtti)) &&
102 "expected GlobalViewAttr or ConstPtrAttr");
103 return rtti;
104
106 GlobalDecl gd = component.getGlobalDecl();
107
109
110 cir::FuncOp fnPtr;
111 if (cast<CXXMethodDecl>(gd.getDecl())->isPureVirtual()) {
112 cgm.errorNYI("getVTableComponent: CK_FunctionPointer: pure virtual");
113 return mlir::Attribute();
114 } else if (cast<CXXMethodDecl>(gd.getDecl())->isDeleted()) {
115 cgm.errorNYI("getVTableComponent: CK_FunctionPointer: deleted virtual");
116 return mlir::Attribute();
117 } else if (nextVTableThunkIndex < layout.vtable_thunks().size() &&
118 layout.vtable_thunks()[nextVTableThunkIndex].first ==
119 componentIndex) {
120 cgm.errorNYI("getVTableComponent: CK_FunctionPointer: thunk");
121 return mlir::Attribute();
122 } else {
123 // Otherwise we can use the method definition directly.
124 cir::FuncType fnTy = cgm.getTypes().getFunctionTypeForVTable(gd);
125 fnPtr = cgm.getAddrOfFunction(gd, fnTy, /*ForVTable=*/true);
126 }
127
128 return cir::GlobalViewAttr::get(
129 builder.getUInt8PtrTy(),
130 mlir::FlatSymbolRefAttr::get(fnPtr.getSymNameAttr()));
131 }
132 }
133
134 llvm_unreachable("Unexpected vtable component kind");
135}
136
137void CIRGenVTables::createVTableInitializer(cir::GlobalOp &vtableOp,
138 const clang::VTableLayout &layout,
139 mlir::Attribute rtti,
140 bool vtableHasLocalLinkage) {
141 mlir::Type componentType = getVTableComponentType();
142
143 const llvm::SmallVectorImpl<unsigned> &addressPoints =
144 layout.getAddressPointIndices();
145 unsigned nextVTableThunkIndex = 0;
146
147 mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();
148
150 for (auto [vtableIndex, addressPoint] : llvm::enumerate(addressPoints)) {
151 // Build a ConstArrayAttr of the vtable components.
152 size_t vtableStart = layout.getVTableOffset(vtableIndex);
153 size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex);
155 components.reserve(vtableEnd - vtableStart);
156 for (size_t componentIndex : llvm::seq(vtableStart, vtableEnd))
157 components.push_back(
158 getVTableComponent(layout, componentIndex, rtti, nextVTableThunkIndex,
159 addressPoint, vtableHasLocalLinkage));
160 // Create a ConstArrayAttr to hold the components.
161 auto arr = cir::ConstArrayAttr::get(
162 cir::ArrayType::get(componentType, components.size()),
163 mlir::ArrayAttr::get(mlirContext, components));
164 vtables.push_back(arr);
165 }
166
167 // Create a ConstRecordAttr to hold the component array.
168 const auto members = mlir::ArrayAttr::get(mlirContext, vtables);
169 cir::ConstRecordAttr record = cgm.getBuilder().getAnonConstRecord(members);
170
171 // Create a VTableAttr
172 auto vtableAttr = cir::VTableAttr::get(record.getType(), record.getMembers());
173
174 // Add the vtable initializer to the vtable global op.
175 cgm.setInitializer(vtableOp, vtableAttr);
176}
177
178/// Compute the required linkage of the vtable for the given class.
179///
180/// Note that we only call this at the end of the translation unit.
181cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) {
182 if (!rd->isExternallyVisible())
183 return cir::GlobalLinkageKind::InternalLinkage;
184
185 // We're at the end of the translation unit, so the current key
186 // function is fully correct.
187 const CXXMethodDecl *keyFunction = astContext.getCurrentKeyFunction(rd);
188 if (keyFunction && !rd->hasAttr<DLLImportAttr>()) {
189 // If this class has a key function, use that to determine the
190 // linkage of the vtable.
191 const FunctionDecl *def = nullptr;
192 if (keyFunction->hasBody(def))
193 keyFunction = cast<CXXMethodDecl>(def);
194
195 // All of the cases below do something different with AppleKext enabled.
197 switch (keyFunction->getTemplateSpecializationKind()) {
198 case TSK_Undeclared:
200 assert(
201 (def || codeGenOpts.OptimizationLevel > 0 ||
202 codeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo) &&
203 "Shouldn't query vtable linkage without key function, "
204 "optimizations, or debug info");
205 if (!def && codeGenOpts.OptimizationLevel > 0)
206 return cir::GlobalLinkageKind::AvailableExternallyLinkage;
207
208 if (keyFunction->isInlined())
209 return !astContext.getLangOpts().AppleKext
210 ? cir::GlobalLinkageKind::LinkOnceODRLinkage
211 : cir::GlobalLinkageKind::InternalLinkage;
212 return cir::GlobalLinkageKind::ExternalLinkage;
213
215 return cir::GlobalLinkageKind::LinkOnceODRLinkage;
216
218 return cir::GlobalLinkageKind::WeakODRLinkage;
219
221 llvm_unreachable("Should not have been asked to emit this");
222 }
223 }
224
225 errorNYI(rd->getSourceRange(), "getVTableLinkage: no key function");
226 return cir::GlobalLinkageKind::ExternalLinkage;
227}
228
230 const CXXMethodDecl *md =
231 cast<CXXMethodDecl>(gd.getDecl())->getCanonicalDecl();
232
233 // We don't need to generate thunks for the base destructor.
234 if (isa<CXXDestructorDecl>(md) && gd.getDtorType() == Dtor_Base)
235 return;
236
237 const VTableContextBase::ThunkInfoVectorTy *thunkInfoVector =
238 vtContext->getThunkInfo(gd);
239
240 if (!thunkInfoVector)
241 return;
242
243 cgm.errorNYI(md->getSourceRange(), "emitThunks");
244}
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value)
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:894
cir::ConstRecordAttr getAnonConstRecord(mlir::ArrayAttr arrayAttr, bool packed=false, bool padded=false, mlir::Type ty={})
Definition: CIRGenBuilder.h:63
cir::PointerType getUInt8PtrTy()
cir::RecordType getAnonRecordTy(llvm::ArrayRef< mlir::Type > members, bool packed=false, bool padded=false)
Get a CIR anonymous record type.
virtual void emitVTableDefinitions(CIRGenVTables &cgvt, const CXXRecordDecl *rd)=0
Emits the VTable definitions required for the given record type.
This class organizes the cross-function state that is used while generating CIR code.
Definition: CIRGenModule.h:56
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
CIRGenBuilderTy & getBuilder()
Definition: CIRGenModule.h:101
cir::FuncOp getAddrOfFunction(clang::GlobalDecl gd, mlir::Type funcType=nullptr, bool forVTable=false, bool dontDefer=false, ForDefinition_t isForDefinition=NotForDefinition)
Return the address of the given function.
static void setInitializer(cir::GlobalOp &op, mlir::Attribute value)
mlir::MLIRContext & getMLIRContext()
Definition: CIRGenModule.h:110
CIRGenCXXABI & getCXXABI() const
Definition: CIRGenModule.h:109
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::FuncType getFunctionTypeForVTable(clang::GlobalDecl gd)
Get the CIR function type for use in a vtable, given a CXXMethodDecl.
Definition: CIRGenCall.cpp:63
cir::RecordType getVTableType(const clang::VTableLayout &layout)
Returns the type of a vtable with the given layout.
void createVTableInitializer(cir::GlobalOp &vtable, const clang::VTableLayout &layout, mlir::Attribute rtti, bool vtableHasLocalLinkage)
Add vtable components for the given vtable layout to the given global initializer.
void emitThunks(GlobalDecl gd)
Emit the associated thunks for the given global decl.
CIRGenVTables(CIRGenModule &cgm)
void generateClassData(const CXXRecordDecl *rd)
Generate all the class data required to be generated upon definition of a KeyFunction.
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2129
CXXMethodDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Definition: DeclCXX.h:2225
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
unsigned getNumVBases() const
Retrieves the number of virtual base classes of this class.
Definition: DeclCXX.h:623
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition: CharUnits.h:185
bool hasAttr() const
Definition: DeclBase.h:577
Represents a function declaration or definition.
Definition: Decl.h:1999
bool isInlined() const
Determine whether this function should be inlined, because it is either marked "inline" or "constexpr...
Definition: Decl.h:2914
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition: Decl.cpp:4486
TemplateSpecializationKind getTemplateSpecializationKind() const
Determine what kind of template instantiation this function represents.
Definition: Decl.cpp:4354
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition: Decl.cpp:3191
GlobalDecl - represents a global declaration.
Definition: GlobalDecl.h:57
CXXDtorType getDtorType() const
Definition: GlobalDecl.h:113
const Decl * getDecl() const
Definition: GlobalDecl.h:106
bool isExternallyVisible() const
Definition: Decl.h:432
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition: Decl.cpp:4830
Represents a single component in a vtable.
Definition: VTableBuilder.h:30
GlobalDecl getGlobalDecl() const
Kind getKind() const
Get the kind of this vtable component.
Definition: VTableBuilder.h:97
@ CK_DeletingDtorPointer
A pointer to the deleting destructor.
Definition: VTableBuilder.h:43
@ CK_UnusedFunctionPointer
An entry that is never used.
Definition: VTableBuilder.h:50
@ CK_CompleteDtorPointer
A pointer to the complete destructor.
Definition: VTableBuilder.h:40
CharUnits getOffsetToTop() const
virtual const ThunkInfoVectorTy * getThunkInfo(GlobalDecl GD)
const AddressPointsIndexMapTy & getAddressPointIndices() const
size_t getVTableOffset(size_t i) const
ArrayRef< VTableComponent > vtable_components() const
size_t getNumVTables() const
ArrayRef< VTableThunkTy > vtable_thunks() const
size_t getVTableSize(size_t i) const
The JSON file list parser is used to communicate input to InstallAPI.
@ Dtor_Base
Base object dtor.
Definition: ABI.h:36
@ TSK_ExplicitInstantiationDefinition
This template specialization was instantiated from a template due to an explicit instantiation defini...
Definition: Specifiers.h:206
@ TSK_ExplicitInstantiationDeclaration
This template specialization was instantiated from a template due to an explicit instantiation declar...
Definition: Specifiers.h:202
@ TSK_ExplicitSpecialization
This template specialization was declared or defined by an explicit specialization (C++ [temp....
Definition: Specifiers.h:198
@ TSK_ImplicitInstantiation
This template specialization was implicitly instantiated from a template.
Definition: Specifiers.h:194
@ TSK_Undeclared
This template specialization was formed from a template-id but has not yet been declared,...
Definition: Specifiers.h:191
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30
static bool appleKext()
static bool cudaSupport()
static bool generateDebugInfo()
static bool vtableRelativeLayout()