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