1f768db77SAnders Carlsson //===--- CGVTT.cpp - Emit LLVM Code for C++ VTTs --------------------------===//
2f768db77SAnders Carlsson //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f768db77SAnders Carlsson //
7f768db77SAnders Carlsson //===----------------------------------------------------------------------===//
8f768db77SAnders Carlsson //
9f768db77SAnders Carlsson // This contains code dealing with C++ code generation of VTTs (vtable tables).
10f768db77SAnders Carlsson //
11f768db77SAnders Carlsson //===----------------------------------------------------------------------===//
12f768db77SAnders Carlsson
13f768db77SAnders Carlsson #include "CodeGenModule.h"
145d865c32SJohn McCall #include "CGCXXABI.h"
15f768db77SAnders Carlsson #include "clang/AST/RecordLayout.h"
162d259523SPeter Collingbourne #include "clang/AST/VTTBuilder.h"
17f768db77SAnders Carlsson using namespace clang;
18f768db77SAnders Carlsson using namespace CodeGen;
19f768db77SAnders Carlsson
20e3b172afSDavid Blaikie static llvm::GlobalVariable *
GetAddrOfVTTVTable(CodeGenVTables & CGVT,CodeGenModule & CGM,const CXXRecordDecl * MostDerivedClass,const VTTVTable & VTable,llvm::GlobalVariable::LinkageTypes Linkage,VTableLayout::AddressPointsMapTy & AddressPoints)218b5987ebSTimur Iskhodzhanov GetAddrOfVTTVTable(CodeGenVTables &CGVT, CodeGenModule &CGM,
228b5987ebSTimur Iskhodzhanov const CXXRecordDecl *MostDerivedClass,
23d9eb79caSPeter Collingbourne const VTTVTable &VTable,
24d9eb79caSPeter Collingbourne llvm::GlobalVariable::LinkageTypes Linkage,
252849c4e8SPeter Collingbourne VTableLayout::AddressPointsMapTy &AddressPoints) {
26d9eb79caSPeter Collingbourne if (VTable.getBase() == MostDerivedClass) {
27d9eb79caSPeter Collingbourne assert(VTable.getBaseOffset().isZero() &&
28a208b399SAnders Carlsson "Most derived class vtable must have a zero offset!");
29a208b399SAnders Carlsson // This is a regular vtable.
308b5987ebSTimur Iskhodzhanov return CGM.getCXXABI().getAddrOfVTable(MostDerivedClass, CharUnits());
31a208b399SAnders Carlsson }
32a208b399SAnders Carlsson
33d9eb79caSPeter Collingbourne return CGVT.GenerateConstructionVTable(MostDerivedClass,
34d9eb79caSPeter Collingbourne VTable.getBaseSubobject(),
35d9eb79caSPeter Collingbourne VTable.isVirtual(),
36d9eb79caSPeter Collingbourne Linkage,
37a208b399SAnders Carlsson AddressPoints);
38a208b399SAnders Carlsson }
39a208b399SAnders Carlsson
40883fc72cSAnders Carlsson void
EmitVTTDefinition(llvm::GlobalVariable * VTT,llvm::GlobalVariable::LinkageTypes Linkage,const CXXRecordDecl * RD)41883fc72cSAnders Carlsson CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
42883fc72cSAnders Carlsson llvm::GlobalVariable::LinkageTypes Linkage,
43f768db77SAnders Carlsson const CXXRecordDecl *RD) {
442000e4eaSPeter Collingbourne VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/true);
452192fe50SChris Lattner llvm::ArrayType *ArrayType =
4651e09e1dSAlex Richardson llvm::ArrayType::get(CGM.Int8PtrTy, Builder.getVTTComponents().size());
47883fc72cSAnders Carlsson
48e3b172afSDavid Blaikie SmallVector<llvm::GlobalVariable *, 8> VTables;
49d9eb79caSPeter Collingbourne SmallVector<VTableAddressPointsMapTy, 8> VTableAddressPoints;
50d9eb79caSPeter Collingbourne for (const VTTVTable *i = Builder.getVTTVTables().begin(),
51d9eb79caSPeter Collingbourne *e = Builder.getVTTVTables().end(); i != e; ++i) {
52d9eb79caSPeter Collingbourne VTableAddressPoints.push_back(VTableAddressPointsMapTy());
538b5987ebSTimur Iskhodzhanov VTables.push_back(GetAddrOfVTTVTable(*this, CGM, RD, *i, Linkage,
54d9eb79caSPeter Collingbourne VTableAddressPoints.back()));
55d9eb79caSPeter Collingbourne }
56d9eb79caSPeter Collingbourne
57d9eb79caSPeter Collingbourne SmallVector<llvm::Constant *, 8> VTTComponents;
58d9eb79caSPeter Collingbourne for (const VTTComponent *i = Builder.getVTTComponents().begin(),
59d9eb79caSPeter Collingbourne *e = Builder.getVTTComponents().end(); i != e; ++i) {
60d9eb79caSPeter Collingbourne const VTTVTable &VTTVT = Builder.getVTTVTables()[i->VTableIndex];
61e3b172afSDavid Blaikie llvm::GlobalVariable *VTable = VTables[i->VTableIndex];
622849c4e8SPeter Collingbourne VTableLayout::AddressPointLocation AddressPoint;
63d9eb79caSPeter Collingbourne if (VTTVT.getBase() == RD) {
64d9eb79caSPeter Collingbourne // Just get the address point for the regular vtable.
6558776636STimur Iskhodzhanov AddressPoint =
66b60a3d5bSReid Kleckner getItaniumVTableContext().getVTableLayout(RD).getAddressPoint(
67b60a3d5bSReid Kleckner i->VTableBase);
68d9eb79caSPeter Collingbourne } else {
69d9eb79caSPeter Collingbourne AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase);
702849c4e8SPeter Collingbourne assert(AddressPoint.AddressPointIndex != 0 &&
712849c4e8SPeter Collingbourne "Did not find ctor vtable address point!");
72d9eb79caSPeter Collingbourne }
73d9eb79caSPeter Collingbourne
74d9eb79caSPeter Collingbourne llvm::Value *Idxs[] = {
7551e09e1dSAlex Richardson llvm::ConstantInt::get(CGM.Int32Ty, 0),
7651e09e1dSAlex Richardson llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.VTableIndex),
7751e09e1dSAlex Richardson llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.AddressPointIndex),
78d9eb79caSPeter Collingbourne };
79d9eb79caSPeter Collingbourne
8025a2b70cSPeter Collingbourne llvm::Constant *Init = llvm::ConstantExpr::getGetElementPtr(
8125a2b70cSPeter Collingbourne VTable->getValueType(), VTable, Idxs, /*InBounds=*/true,
8225a2b70cSPeter Collingbourne /*InRangeIndex=*/1);
83d9eb79caSPeter Collingbourne
8451e09e1dSAlex Richardson Init = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(Init,
8551e09e1dSAlex Richardson CGM.Int8PtrTy);
86d9eb79caSPeter Collingbourne
87d9eb79caSPeter Collingbourne VTTComponents.push_back(Init);
88d9eb79caSPeter Collingbourne }
89d9eb79caSPeter Collingbourne
90d9eb79caSPeter Collingbourne llvm::Constant *Init = llvm::ConstantArray::get(ArrayType, VTTComponents);
91883fc72cSAnders Carlsson
92883fc72cSAnders Carlsson VTT->setInitializer(Init);
93883fc72cSAnders Carlsson
94883fc72cSAnders Carlsson // Set the correct linkage.
95883fc72cSAnders Carlsson VTT->setLinkage(Linkage);
965963024fSAnders Carlsson
97c7da6da5SNAKAMURA Takumi if (CGM.supportsCOMDAT() && VTT->isWeakForLinker())
98c7da6da5SNAKAMURA Takumi VTT->setComdat(CGM.getModule().getOrInsertComdat(VTT->getName()));
99883fc72cSAnders Carlsson }
100883fc72cSAnders Carlsson
GetAddrOfVTT(const CXXRecordDecl * RD)101883fc72cSAnders Carlsson llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
102883fc72cSAnders Carlsson assert(RD->getNumVBases() && "Only classes with virtual bases need a VTT");
103f768db77SAnders Carlsson
1042c1dd271SDylan Noblesmith SmallString<256> OutName;
1053968cd0fSRafael Espindola llvm::raw_svector_ostream Out(OutName);
1066745522fSTimur Iskhodzhanov cast<ItaniumMangleContext>(CGM.getCXXABI().getMangleContext())
1076745522fSTimur Iskhodzhanov .mangleCXXVTT(RD, Out);
1080e62c1ccSChris Lattner StringRef Name = OutName.str();
109f768db77SAnders Carlsson
11071c26936SPeter Collingbourne // This will also defer the definition of the VTT.
1118b5987ebSTimur Iskhodzhanov (void) CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
112d6f1518cSAnders Carlsson
1132000e4eaSPeter Collingbourne VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
114f768db77SAnders Carlsson
1152192fe50SChris Lattner llvm::ArrayType *ArrayType =
116ece0409aSChris Lattner llvm::ArrayType::get(CGM.Int8PtrTy, Builder.getVTTComponents().size());
117be0c5b6dSDavid Green unsigned Align = CGM.getDataLayout().getABITypeAlignment(CGM.Int8PtrTy);
1185670d965SAnders Carlsson
119be0c5b6dSDavid Green llvm::GlobalVariable *GV = CGM.CreateOrReplaceCXXRuntimeVariable(
120be0c5b6dSDavid Green Name, ArrayType, llvm::GlobalValue::ExternalLinkage, Align);
121bcf909d7SPeter Collingbourne GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
122*e11bf8deSEli Friedman CGM.setGVProperties(GV, RD);
123f768db77SAnders Carlsson return GV;
124f768db77SAnders Carlsson }
125f768db77SAnders Carlsson
getSubVTTIndex(const CXXRecordDecl * RD,BaseSubobject Base)126a864caffSAnders Carlsson uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD,
127859b3064SAnders Carlsson BaseSubobject Base) {
1288bdbb5beSAnders Carlsson BaseSubobjectPairTy ClassSubobjectPair(RD, Base);
129f768db77SAnders Carlsson
1308bdbb5beSAnders Carlsson SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassSubobjectPair);
131f768db77SAnders Carlsson if (I != SubVTTIndicies.end())
132f768db77SAnders Carlsson return I->second;
133f768db77SAnders Carlsson
1342000e4eaSPeter Collingbourne VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
135f768db77SAnders Carlsson
1368bdbb5beSAnders Carlsson for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
137f768db77SAnders Carlsson Builder.getSubVTTIndicies().begin(),
138f768db77SAnders Carlsson E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
139f768db77SAnders Carlsson // Insert all indices.
1408bdbb5beSAnders Carlsson BaseSubobjectPairTy ClassSubobjectPair(RD, I->first);
141f768db77SAnders Carlsson
1428bdbb5beSAnders Carlsson SubVTTIndicies.insert(std::make_pair(ClassSubobjectPair, I->second));
143f768db77SAnders Carlsson }
144f768db77SAnders Carlsson
1458bdbb5beSAnders Carlsson I = SubVTTIndicies.find(ClassSubobjectPair);
146f768db77SAnders Carlsson assert(I != SubVTTIndicies.end() && "Did not find index!");
147f768db77SAnders Carlsson
148f768db77SAnders Carlsson return I->second;
149f768db77SAnders Carlsson }
150f1a994ceSAnders Carlsson
151f1a994ceSAnders Carlsson uint64_t
getSecondaryVirtualPointerIndex(const CXXRecordDecl * RD,BaseSubobject Base)152f1a994ceSAnders Carlsson CodeGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
153f1a994ceSAnders Carlsson BaseSubobject Base) {
154f1a994ceSAnders Carlsson SecondaryVirtualPointerIndicesMapTy::iterator I =
155f1a994ceSAnders Carlsson SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base));
156f1a994ceSAnders Carlsson
157f1a994ceSAnders Carlsson if (I != SecondaryVirtualPointerIndices.end())
158f1a994ceSAnders Carlsson return I->second;
159f1a994ceSAnders Carlsson
1602000e4eaSPeter Collingbourne VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
161f1a994ceSAnders Carlsson
162f1a994ceSAnders Carlsson // Insert all secondary vpointer indices.
163f1a994ceSAnders Carlsson for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
164f1a994ceSAnders Carlsson Builder.getSecondaryVirtualPointerIndices().begin(),
165f1a994ceSAnders Carlsson E = Builder.getSecondaryVirtualPointerIndices().end(); I != E; ++I) {
166f1a994ceSAnders Carlsson std::pair<const CXXRecordDecl *, BaseSubobject> Pair =
167f1a994ceSAnders Carlsson std::make_pair(RD, I->first);
168f1a994ceSAnders Carlsson
169f1a994ceSAnders Carlsson SecondaryVirtualPointerIndices.insert(std::make_pair(Pair, I->second));
170f1a994ceSAnders Carlsson }
171f1a994ceSAnders Carlsson
172f1a994ceSAnders Carlsson I = SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base));
173f1a994ceSAnders Carlsson assert(I != SecondaryVirtualPointerIndices.end() && "Did not find index!");
174f1a994ceSAnders Carlsson
175f1a994ceSAnders Carlsson return I->second;
176f1a994ceSAnders Carlsson }
177