xref: /openbsd-src/gnu/llvm/clang/lib/CodeGen/CGVTT.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- CGVTT.cpp - Emit LLVM Code for C++ VTTs --------------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This contains code dealing with C++ code generation of VTTs (vtable tables).
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "CodeGenModule.h"
14e5dd7070Spatrick #include "CGCXXABI.h"
15e5dd7070Spatrick #include "clang/AST/RecordLayout.h"
16e5dd7070Spatrick #include "clang/AST/VTTBuilder.h"
17e5dd7070Spatrick using namespace clang;
18e5dd7070Spatrick using namespace CodeGen;
19e5dd7070Spatrick 
20e5dd7070Spatrick static llvm::GlobalVariable *
GetAddrOfVTTVTable(CodeGenVTables & CGVT,CodeGenModule & CGM,const CXXRecordDecl * MostDerivedClass,const VTTVTable & VTable,llvm::GlobalVariable::LinkageTypes Linkage,VTableLayout::AddressPointsMapTy & AddressPoints)21e5dd7070Spatrick GetAddrOfVTTVTable(CodeGenVTables &CGVT, CodeGenModule &CGM,
22e5dd7070Spatrick                    const CXXRecordDecl *MostDerivedClass,
23e5dd7070Spatrick                    const VTTVTable &VTable,
24e5dd7070Spatrick                    llvm::GlobalVariable::LinkageTypes Linkage,
25e5dd7070Spatrick                    VTableLayout::AddressPointsMapTy &AddressPoints) {
26e5dd7070Spatrick   if (VTable.getBase() == MostDerivedClass) {
27e5dd7070Spatrick     assert(VTable.getBaseOffset().isZero() &&
28e5dd7070Spatrick            "Most derived class vtable must have a zero offset!");
29e5dd7070Spatrick     // This is a regular vtable.
30e5dd7070Spatrick     return CGM.getCXXABI().getAddrOfVTable(MostDerivedClass, CharUnits());
31e5dd7070Spatrick   }
32e5dd7070Spatrick 
33e5dd7070Spatrick   return CGVT.GenerateConstructionVTable(MostDerivedClass,
34e5dd7070Spatrick                                          VTable.getBaseSubobject(),
35e5dd7070Spatrick                                          VTable.isVirtual(),
36e5dd7070Spatrick                                          Linkage,
37e5dd7070Spatrick                                          AddressPoints);
38e5dd7070Spatrick }
39e5dd7070Spatrick 
40e5dd7070Spatrick void
EmitVTTDefinition(llvm::GlobalVariable * VTT,llvm::GlobalVariable::LinkageTypes Linkage,const CXXRecordDecl * RD)41e5dd7070Spatrick CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT,
42e5dd7070Spatrick                                   llvm::GlobalVariable::LinkageTypes Linkage,
43e5dd7070Spatrick                                   const CXXRecordDecl *RD) {
44e5dd7070Spatrick   VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/true);
45e5dd7070Spatrick   llvm::ArrayType *ArrayType =
46a9ac8606Spatrick       llvm::ArrayType::get(CGM.Int8PtrTy, Builder.getVTTComponents().size());
47e5dd7070Spatrick 
48e5dd7070Spatrick   SmallVector<llvm::GlobalVariable *, 8> VTables;
49e5dd7070Spatrick   SmallVector<VTableAddressPointsMapTy, 8> VTableAddressPoints;
50e5dd7070Spatrick   for (const VTTVTable *i = Builder.getVTTVTables().begin(),
51e5dd7070Spatrick                        *e = Builder.getVTTVTables().end(); i != e; ++i) {
52e5dd7070Spatrick     VTableAddressPoints.push_back(VTableAddressPointsMapTy());
53e5dd7070Spatrick     VTables.push_back(GetAddrOfVTTVTable(*this, CGM, RD, *i, Linkage,
54e5dd7070Spatrick                                          VTableAddressPoints.back()));
55e5dd7070Spatrick   }
56e5dd7070Spatrick 
57e5dd7070Spatrick   SmallVector<llvm::Constant *, 8> VTTComponents;
58e5dd7070Spatrick   for (const VTTComponent *i = Builder.getVTTComponents().begin(),
59e5dd7070Spatrick                           *e = Builder.getVTTComponents().end(); i != e; ++i) {
60e5dd7070Spatrick     const VTTVTable &VTTVT = Builder.getVTTVTables()[i->VTableIndex];
61e5dd7070Spatrick     llvm::GlobalVariable *VTable = VTables[i->VTableIndex];
62e5dd7070Spatrick     VTableLayout::AddressPointLocation AddressPoint;
63e5dd7070Spatrick     if (VTTVT.getBase() == RD) {
64e5dd7070Spatrick       // Just get the address point for the regular vtable.
65e5dd7070Spatrick       AddressPoint =
66e5dd7070Spatrick           getItaniumVTableContext().getVTableLayout(RD).getAddressPoint(
67e5dd7070Spatrick               i->VTableBase);
68e5dd7070Spatrick     } else {
69e5dd7070Spatrick       AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase);
70e5dd7070Spatrick       assert(AddressPoint.AddressPointIndex != 0 &&
71e5dd7070Spatrick              "Did not find ctor vtable address point!");
72e5dd7070Spatrick     }
73e5dd7070Spatrick 
74e5dd7070Spatrick      llvm::Value *Idxs[] = {
75a9ac8606Spatrick        llvm::ConstantInt::get(CGM.Int32Ty, 0),
76a9ac8606Spatrick        llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.VTableIndex),
77a9ac8606Spatrick        llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.AddressPointIndex),
78e5dd7070Spatrick      };
79e5dd7070Spatrick 
80e5dd7070Spatrick      llvm::Constant *Init = llvm::ConstantExpr::getGetElementPtr(
81e5dd7070Spatrick          VTable->getValueType(), VTable, Idxs, /*InBounds=*/true,
82e5dd7070Spatrick          /*InRangeIndex=*/1);
83e5dd7070Spatrick 
84a9ac8606Spatrick      Init = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(Init,
85a9ac8606Spatrick                                                                  CGM.Int8PtrTy);
86e5dd7070Spatrick 
87e5dd7070Spatrick      VTTComponents.push_back(Init);
88e5dd7070Spatrick   }
89e5dd7070Spatrick 
90e5dd7070Spatrick   llvm::Constant *Init = llvm::ConstantArray::get(ArrayType, VTTComponents);
91e5dd7070Spatrick 
92e5dd7070Spatrick   VTT->setInitializer(Init);
93e5dd7070Spatrick 
94e5dd7070Spatrick   // Set the correct linkage.
95e5dd7070Spatrick   VTT->setLinkage(Linkage);
96e5dd7070Spatrick 
97e5dd7070Spatrick   if (CGM.supportsCOMDAT() && VTT->isWeakForLinker())
98e5dd7070Spatrick     VTT->setComdat(CGM.getModule().getOrInsertComdat(VTT->getName()));
99e5dd7070Spatrick }
100e5dd7070Spatrick 
GetAddrOfVTT(const CXXRecordDecl * RD)101e5dd7070Spatrick llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
102e5dd7070Spatrick   assert(RD->getNumVBases() && "Only classes with virtual bases need a VTT");
103e5dd7070Spatrick 
104e5dd7070Spatrick   SmallString<256> OutName;
105e5dd7070Spatrick   llvm::raw_svector_ostream Out(OutName);
106e5dd7070Spatrick   cast<ItaniumMangleContext>(CGM.getCXXABI().getMangleContext())
107e5dd7070Spatrick       .mangleCXXVTT(RD, Out);
108e5dd7070Spatrick   StringRef Name = OutName.str();
109e5dd7070Spatrick 
110e5dd7070Spatrick   // This will also defer the definition of the VTT.
111e5dd7070Spatrick   (void) CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
112e5dd7070Spatrick 
113e5dd7070Spatrick   VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
114e5dd7070Spatrick 
115e5dd7070Spatrick   llvm::ArrayType *ArrayType =
116e5dd7070Spatrick     llvm::ArrayType::get(CGM.Int8PtrTy, Builder.getVTTComponents().size());
117*12c85518Srobert   llvm::Align Align = CGM.getDataLayout().getABITypeAlign(CGM.Int8PtrTy);
118e5dd7070Spatrick 
119e5dd7070Spatrick   llvm::GlobalVariable *GV = CGM.CreateOrReplaceCXXRuntimeVariable(
120e5dd7070Spatrick       Name, ArrayType, llvm::GlobalValue::ExternalLinkage, Align);
121e5dd7070Spatrick   GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
122*12c85518Srobert   CGM.setGVProperties(GV, RD);
123e5dd7070Spatrick   return GV;
124e5dd7070Spatrick }
125e5dd7070Spatrick 
getSubVTTIndex(const CXXRecordDecl * RD,BaseSubobject Base)126e5dd7070Spatrick uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD,
127e5dd7070Spatrick                                         BaseSubobject Base) {
128e5dd7070Spatrick   BaseSubobjectPairTy ClassSubobjectPair(RD, Base);
129e5dd7070Spatrick 
130e5dd7070Spatrick   SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassSubobjectPair);
131e5dd7070Spatrick   if (I != SubVTTIndicies.end())
132e5dd7070Spatrick     return I->second;
133e5dd7070Spatrick 
134e5dd7070Spatrick   VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
135e5dd7070Spatrick 
136e5dd7070Spatrick   for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
137e5dd7070Spatrick        Builder.getSubVTTIndicies().begin(),
138e5dd7070Spatrick        E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
139e5dd7070Spatrick     // Insert all indices.
140e5dd7070Spatrick     BaseSubobjectPairTy ClassSubobjectPair(RD, I->first);
141e5dd7070Spatrick 
142e5dd7070Spatrick     SubVTTIndicies.insert(std::make_pair(ClassSubobjectPair, I->second));
143e5dd7070Spatrick   }
144e5dd7070Spatrick 
145e5dd7070Spatrick   I = SubVTTIndicies.find(ClassSubobjectPair);
146e5dd7070Spatrick   assert(I != SubVTTIndicies.end() && "Did not find index!");
147e5dd7070Spatrick 
148e5dd7070Spatrick   return I->second;
149e5dd7070Spatrick }
150e5dd7070Spatrick 
151e5dd7070Spatrick uint64_t
getSecondaryVirtualPointerIndex(const CXXRecordDecl * RD,BaseSubobject Base)152e5dd7070Spatrick CodeGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD,
153e5dd7070Spatrick                                                 BaseSubobject Base) {
154e5dd7070Spatrick   SecondaryVirtualPointerIndicesMapTy::iterator I =
155e5dd7070Spatrick     SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base));
156e5dd7070Spatrick 
157e5dd7070Spatrick   if (I != SecondaryVirtualPointerIndices.end())
158e5dd7070Spatrick     return I->second;
159e5dd7070Spatrick 
160e5dd7070Spatrick   VTTBuilder Builder(CGM.getContext(), RD, /*GenerateDefinition=*/false);
161e5dd7070Spatrick 
162e5dd7070Spatrick   // Insert all secondary vpointer indices.
163e5dd7070Spatrick   for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I =
164e5dd7070Spatrick        Builder.getSecondaryVirtualPointerIndices().begin(),
165e5dd7070Spatrick        E = Builder.getSecondaryVirtualPointerIndices().end(); I != E; ++I) {
166e5dd7070Spatrick     std::pair<const CXXRecordDecl *, BaseSubobject> Pair =
167e5dd7070Spatrick       std::make_pair(RD, I->first);
168e5dd7070Spatrick 
169e5dd7070Spatrick     SecondaryVirtualPointerIndices.insert(std::make_pair(Pair, I->second));
170e5dd7070Spatrick   }
171e5dd7070Spatrick 
172e5dd7070Spatrick   I = SecondaryVirtualPointerIndices.find(std::make_pair(RD, Base));
173e5dd7070Spatrick   assert(I != SecondaryVirtualPointerIndices.end() && "Did not find index!");
174e5dd7070Spatrick 
175e5dd7070Spatrick   return I->second;
176e5dd7070Spatrick }
177