brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.2 KiB · 36bab62 Raw
527 lines · cpp
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-exception6//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"18#include "clang/AST/VTTBuilder.h"19#include "clang/AST/VTableBuilder.h"20#include "llvm/ADT/SmallVector.h"21 22using namespace llvm;23using namespace clang;24using namespace clang::CIRGen;25 26CIRGenVTables::CIRGenVTables(CIRGenModule &cgm)27    : cgm(cgm), vtContext(cgm.getASTContext().getVTableContext()) {}28 29mlir::Type CIRGenModule::getVTableComponentType() {30  mlir::Type ptrTy = builder.getUInt8PtrTy();31  assert(!cir::MissingFeatures::vtableRelativeLayout());32  return ptrTy;33}34 35mlir::Type CIRGenVTables::getVTableComponentType() {36  return cgm.getVTableComponentType();37}38 39cir::RecordType CIRGenVTables::getVTableType(const VTableLayout &layout) {40  SmallVector<mlir::Type, 4> tys;41  mlir::Type componentType = getVTableComponentType();42  for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i)43    tys.push_back(cir::ArrayType::get(componentType, layout.getVTableSize(i)));44 45  // FIXME(cir): should VTableLayout be encoded like we do for some46  // AST nodes?47  return cgm.getBuilder().getAnonRecordTy(tys, /*incomplete=*/false);48}49 50/// At this point in the translation unit, does it appear that can we51/// rely on the vtable being defined elsewhere in the program?52///53/// The response is really only definitive when called at the end of54/// the translation unit.55///56/// The only semantic restriction here is that the object file should57/// not contain a vtable definition when that vtable is defined58/// strongly elsewhere.  Otherwise, we'd just like to avoid emitting59/// vtables when unnecessary.60/// TODO(cir): this should be merged into common AST helper for codegen.61bool CIRGenVTables::isVTableExternal(const CXXRecordDecl *rd) {62  assert(rd->isDynamicClass() && "Non-dynamic classes have no VTable.");63 64  // We always synthesize vtables if they are needed in the MS ABI. MSVC doesn't65  // emit them even if there is an explicit template instantiation.66  if (cgm.getTarget().getCXXABI().isMicrosoft())67    return false;68 69  // If we have an explicit instantiation declaration (and not a70  // definition), the vtable is defined elsewhere.71  TemplateSpecializationKind tsk = rd->getTemplateSpecializationKind();72  if (tsk == TSK_ExplicitInstantiationDeclaration)73    return true;74 75  // Otherwise, if the class is an instantiated template, the76  // vtable must be defined here.77  if (tsk == TSK_ImplicitInstantiation ||78      tsk == TSK_ExplicitInstantiationDefinition)79    return false;80 81  // Otherwise, if the class doesn't have a key function (possibly82  // anymore), the vtable must be defined here.83  const CXXMethodDecl *keyFunction =84      cgm.getASTContext().getCurrentKeyFunction(rd);85  if (!keyFunction)86    return false;87 88  // Otherwise, if we don't have a definition of the key function, the89  // vtable must be defined somewhere else.90  return !keyFunction->hasBody();91}92 93/// This is a callback from Sema to tell us that a particular vtable is94/// required to be emitted in this translation unit.95///96/// This is only called for vtables that _must_ be emitted (mainly due to key97/// functions).  For weak vtables, CodeGen tracks when they are needed and98/// emits them as-needed.99void CIRGenModule::emitVTable(const CXXRecordDecl *rd) {100  vtables.generateClassData(rd);101}102 103void CIRGenVTables::generateClassData(const CXXRecordDecl *rd) {104  assert(!cir::MissingFeatures::generateDebugInfo());105 106  if (rd->getNumVBases())107    cgm.getCXXABI().emitVirtualInheritanceTables(rd);108 109  cgm.getCXXABI().emitVTableDefinitions(*this, rd);110}111 112mlir::Attribute CIRGenVTables::getVTableComponent(113    const VTableLayout &layout, unsigned componentIndex, mlir::Attribute rtti,114    unsigned &nextVTableThunkIndex, unsigned vtableAddressPoint,115    bool vtableHasLocalLinkage) {116  const VTableComponent &component = layout.vtable_components()[componentIndex];117 118  CIRGenBuilderTy builder = cgm.getBuilder();119 120  assert(!cir::MissingFeatures::vtableRelativeLayout());121 122  switch (component.getKind()) {123  case VTableComponent::CK_UnusedFunctionPointer:124    cgm.errorNYI("getVTableComponent: UnusedFunctionPointer");125    return mlir::Attribute();126 127  case VTableComponent::CK_VCallOffset:128    return builder.getConstPtrAttr(builder.getUInt8PtrTy(),129                                   component.getVCallOffset().getQuantity());130 131  case VTableComponent::CK_VBaseOffset:132    return builder.getConstPtrAttr(builder.getUInt8PtrTy(),133                                   component.getVBaseOffset().getQuantity());134 135  case VTableComponent::CK_OffsetToTop:136    return builder.getConstPtrAttr(builder.getUInt8PtrTy(),137                                   component.getOffsetToTop().getQuantity());138 139  case VTableComponent::CK_RTTI:140    assert((mlir::isa<cir::GlobalViewAttr>(rtti) ||141            mlir::isa<cir::ConstPtrAttr>(rtti)) &&142           "expected GlobalViewAttr or ConstPtrAttr");143    return rtti;144 145  case VTableComponent::CK_FunctionPointer:146  case VTableComponent::CK_CompleteDtorPointer:147  case VTableComponent::CK_DeletingDtorPointer: {148    GlobalDecl gd = component.getGlobalDecl();149 150    assert(!cir::MissingFeatures::cudaSupport());151 152    cir::FuncOp fnPtr;153    if (cast<CXXMethodDecl>(gd.getDecl())->isPureVirtual()) {154      cgm.errorNYI("getVTableComponent: CK_FunctionPointer: pure virtual");155      return mlir::Attribute();156    } else if (cast<CXXMethodDecl>(gd.getDecl())->isDeleted()) {157      cgm.errorNYI("getVTableComponent: CK_FunctionPointer: deleted virtual");158      return mlir::Attribute();159    } else if (nextVTableThunkIndex < layout.vtable_thunks().size() &&160               layout.vtable_thunks()[nextVTableThunkIndex].first ==161                   componentIndex) {162      cgm.errorNYI("getVTableComponent: CK_FunctionPointer: thunk");163      return mlir::Attribute();164    } else {165      // Otherwise we can use the method definition directly.166      cir::FuncType fnTy = cgm.getTypes().getFunctionTypeForVTable(gd);167      fnPtr = cgm.getAddrOfFunction(gd, fnTy, /*ForVTable=*/true);168    }169 170    return cir::GlobalViewAttr::get(171        builder.getUInt8PtrTy(),172        mlir::FlatSymbolRefAttr::get(fnPtr.getSymNameAttr()));173  }174  }175 176  llvm_unreachable("Unexpected vtable component kind");177}178 179void CIRGenVTables::createVTableInitializer(cir::GlobalOp &vtableOp,180                                            const clang::VTableLayout &layout,181                                            mlir::Attribute rtti,182                                            bool vtableHasLocalLinkage) {183  mlir::Type componentType = getVTableComponentType();184 185  const llvm::SmallVectorImpl<unsigned> &addressPoints =186      layout.getAddressPointIndices();187  unsigned nextVTableThunkIndex = 0;188 189  mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();190 191  SmallVector<mlir::Attribute> vtables;192  for (auto [vtableIndex, addressPoint] : llvm::enumerate(addressPoints)) {193    // Build a ConstArrayAttr of the vtable components.194    size_t vtableStart = layout.getVTableOffset(vtableIndex);195    size_t vtableEnd = vtableStart + layout.getVTableSize(vtableIndex);196    llvm::SmallVector<mlir::Attribute> components;197    components.reserve(vtableEnd - vtableStart);198    for (size_t componentIndex : llvm::seq(vtableStart, vtableEnd))199      components.push_back(200          getVTableComponent(layout, componentIndex, rtti, nextVTableThunkIndex,201                             addressPoint, vtableHasLocalLinkage));202    // Create a ConstArrayAttr to hold the components.203    auto arr = cir::ConstArrayAttr::get(204        cir::ArrayType::get(componentType, components.size()),205        mlir::ArrayAttr::get(mlirContext, components));206    vtables.push_back(arr);207  }208 209  // Create a ConstRecordAttr to hold the component array.210  const auto members = mlir::ArrayAttr::get(mlirContext, vtables);211  cir::ConstRecordAttr record = cgm.getBuilder().getAnonConstRecord(members);212 213  // Create a VTableAttr214  auto vtableAttr = cir::VTableAttr::get(record.getType(), record.getMembers());215 216  // Add the vtable initializer to the vtable global op.217  cgm.setInitializer(vtableOp, vtableAttr);218}219 220cir::GlobalOp CIRGenVTables::generateConstructionVTable(221    const CXXRecordDecl *rd, const BaseSubobject &base, bool baseIsVirtual,222    cir::GlobalLinkageKind linkage, VTableAddressPointsMapTy &addressPoints) {223  assert(!cir::MissingFeatures::generateDebugInfo());224 225  std::unique_ptr<VTableLayout> vtLayout(226      getItaniumVTableContext().createConstructionVTableLayout(227          base.getBase(), base.getBaseOffset(), baseIsVirtual, rd));228 229  // Add the address points.230  addressPoints = vtLayout->getAddressPoints();231 232  // Get the mangled construction vtable name.233  SmallString<256> outName;234  llvm::raw_svector_ostream out(outName);235  cast<ItaniumMangleContext>(cgm.getCXXABI().getMangleContext())236      .mangleCXXCtorVTable(rd, base.getBaseOffset().getQuantity(),237                           base.getBase(), out);238  SmallString<256> name(outName);239 240  assert(!cir::MissingFeatures::vtableRelativeLayout());241 242  cir::RecordType vtType = getVTableType(*vtLayout);243 244  // Construction vtable symbols are not part of the Itanium ABI, so we cannot245  // guarantee that they actually will be available externally. Instead, when246  // emitting an available_externally VTT, we provide references to an internal247  // linkage construction vtable. The ABI only requires complete-object vtables248  // to be the same for all instances of a type, not construction vtables.249  if (linkage == cir::GlobalLinkageKind::AvailableExternallyLinkage)250    linkage = cir::GlobalLinkageKind::InternalLinkage;251 252  llvm::Align align = cgm.getDataLayout().getABITypeAlign(vtType);253  mlir::Location loc = cgm.getLoc(rd->getSourceRange());254 255  // Create the variable that will hold the construction vtable.256  cir::GlobalOp vtable = cgm.createOrReplaceCXXRuntimeVariable(257      loc, name, vtType, linkage, CharUnits::fromQuantity(align));258 259  // V-tables are always unnamed_addr.260  assert(!cir::MissingFeatures::opGlobalUnnamedAddr());261 262  mlir::Attribute rtti = cgm.getAddrOfRTTIDescriptor(263      loc, cgm.getASTContext().getCanonicalTagType(base.getBase()));264 265  // Create and set the initializer.266  createVTableInitializer(vtable, *vtLayout, rtti,267                          cir::isLocalLinkage(vtable.getLinkage()));268 269  // Set properties only after the initializer has been set to ensure that the270  // GV is treated as definition and not declaration.271  assert(!vtable.isDeclaration() && "Shouldn't set properties on declaration");272  cgm.setGVProperties(vtable, rd);273 274  assert(!cir::MissingFeatures::vtableEmitMetadata());275  assert(!cir::MissingFeatures::vtableRelativeLayout());276 277  return vtable;278}279 280/// Compute the required linkage of the vtable for the given class.281///282/// Note that we only call this at the end of the translation unit.283cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) {284  if (!rd->isExternallyVisible())285    return cir::GlobalLinkageKind::InternalLinkage;286 287  // We're at the end of the translation unit, so the current key288  // function is fully correct.289  const CXXMethodDecl *keyFunction = astContext.getCurrentKeyFunction(rd);290  if (keyFunction && !rd->hasAttr<DLLImportAttr>()) {291    // If this class has a key function, use that to determine the292    // linkage of the vtable.293    const FunctionDecl *def = nullptr;294    if (keyFunction->hasBody(def))295      keyFunction = cast<CXXMethodDecl>(def);296 297    // All of the cases below do something different with AppleKext enabled.298    assert(!cir::MissingFeatures::appleKext());299    switch (keyFunction->getTemplateSpecializationKind()) {300    case TSK_Undeclared:301    case TSK_ExplicitSpecialization:302      assert(303          (def || codeGenOpts.OptimizationLevel > 0 ||304           codeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo) &&305          "Shouldn't query vtable linkage without key function, "306          "optimizations, or debug info");307      if (!def && codeGenOpts.OptimizationLevel > 0)308        return cir::GlobalLinkageKind::AvailableExternallyLinkage;309 310      if (keyFunction->isInlined())311        return !astContext.getLangOpts().AppleKext312                   ? cir::GlobalLinkageKind::LinkOnceODRLinkage313                   : cir::GlobalLinkageKind::InternalLinkage;314      return cir::GlobalLinkageKind::ExternalLinkage;315 316    case TSK_ImplicitInstantiation:317      return cir::GlobalLinkageKind::LinkOnceODRLinkage;318 319    case TSK_ExplicitInstantiationDefinition:320      return cir::GlobalLinkageKind::WeakODRLinkage;321 322    case TSK_ExplicitInstantiationDeclaration:323      llvm_unreachable("Should not have been asked to emit this");324    }325  }326  // -fapple-kext mode does not support weak linkage, so we must use327  // internal linkage.328  if (astContext.getLangOpts().AppleKext)329    return cir::GlobalLinkageKind::InternalLinkage;330 331  auto discardableODRLinkage = cir::GlobalLinkageKind::LinkOnceODRLinkage;332  auto nonDiscardableODRLinkage = cir::GlobalLinkageKind::WeakODRLinkage;333  if (rd->hasAttr<DLLExportAttr>()) {334    // Cannot discard exported vtables.335    discardableODRLinkage = nonDiscardableODRLinkage;336  } else if (rd->hasAttr<DLLImportAttr>()) {337    // Imported vtables are available externally.338    discardableODRLinkage = cir::GlobalLinkageKind::AvailableExternallyLinkage;339    nonDiscardableODRLinkage =340        cir::GlobalLinkageKind::AvailableExternallyLinkage;341  }342 343  switch (rd->getTemplateSpecializationKind()) {344  case TSK_Undeclared:345  case TSK_ExplicitSpecialization:346  case TSK_ImplicitInstantiation:347    return discardableODRLinkage;348 349  case TSK_ExplicitInstantiationDeclaration: {350    errorNYI(rd->getSourceRange(),351             "getVTableLinkage: explicit instantiation declaration");352    return cir::GlobalLinkageKind::ExternalLinkage;353  }354 355  case TSK_ExplicitInstantiationDefinition:356    return nonDiscardableODRLinkage;357  }358 359  llvm_unreachable("Invalid TemplateSpecializationKind!");360}361 362cir::GlobalOp CIRGenVTables::getAddrOfVTT(const CXXRecordDecl *rd) {363  assert(rd->getNumVBases() && "Only classes with virtual bases need a VTT");364 365  SmallString<256> outName;366  llvm::raw_svector_ostream out(outName);367  cast<ItaniumMangleContext>(cgm.getCXXABI().getMangleContext())368      .mangleCXXVTT(rd, out);369  StringRef name = outName.str();370 371  // This will also defer the definition of the VTT.372  (void)cgm.getCXXABI().getAddrOfVTable(rd, CharUnits());373 374  VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);375 376  auto arrayType = cir::ArrayType::get(cgm.getBuilder().getUInt8PtrTy(),377                                       builder.getVTTComponents().size());378  llvm::Align align =379      cgm.getDataLayout().getABITypeAlign(cgm.getBuilder().getUInt8PtrTy());380  cir::GlobalOp vtt = cgm.createOrReplaceCXXRuntimeVariable(381      cgm.getLoc(rd->getSourceRange()), name, arrayType,382      cir::GlobalLinkageKind::ExternalLinkage, CharUnits::fromQuantity(align));383  cgm.setGVProperties(vtt, rd);384  return vtt;385}386 387static cir::GlobalOp388getAddrOfVTTVTable(CIRGenVTables &cgvt, CIRGenModule &cgm,389                   const CXXRecordDecl *mostDerivedClass,390                   const VTTVTable &vtable, cir::GlobalLinkageKind linkage,391                   VTableLayout::AddressPointsMapTy &addressPoints) {392  if (vtable.getBase() == mostDerivedClass) {393    assert(vtable.getBaseOffset().isZero() &&394           "Most derived class vtable must have a zero offset!");395    // This is a regular vtable.396    return cgm.getCXXABI().getAddrOfVTable(mostDerivedClass, CharUnits());397  }398  return cgvt.generateConstructionVTable(399      mostDerivedClass, vtable.getBaseSubobject(), vtable.isVirtual(), linkage,400      addressPoints);401}402 403/// Emit the definition of the given vtable.404void CIRGenVTables::emitVTTDefinition(cir::GlobalOp vttOp,405                                      cir::GlobalLinkageKind linkage,406                                      const CXXRecordDecl *rd) {407  VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/true);408 409  mlir::MLIRContext *mlirContext = &cgm.getMLIRContext();410 411  auto arrayType = cir::ArrayType::get(cgm.getBuilder().getUInt8PtrTy(),412                                       builder.getVTTComponents().size());413 414  SmallVector<cir::GlobalOp> vtables;415  SmallVector<VTableAddressPointsMapTy> vtableAddressPoints;416  for (const VTTVTable &vtt : builder.getVTTVTables()) {417    vtableAddressPoints.push_back(VTableAddressPointsMapTy());418    vtables.push_back(getAddrOfVTTVTable(*this, cgm, rd, vtt, linkage,419                                         vtableAddressPoints.back()));420  }421 422  SmallVector<mlir::Attribute> vttComponents;423  for (const VTTComponent &vttComponent : builder.getVTTComponents()) {424    const VTTVTable &vttVT = builder.getVTTVTables()[vttComponent.VTableIndex];425    cir::GlobalOp vtable = vtables[vttComponent.VTableIndex];426    VTableLayout::AddressPointLocation addressPoint;427    if (vttVT.getBase() == rd) {428      // Just get the address point for the regular vtable.429      addressPoint =430          getItaniumVTableContext().getVTableLayout(rd).getAddressPoint(431              vttComponent.VTableBase);432    } else {433      addressPoint = vtableAddressPoints[vttComponent.VTableIndex].lookup(434          vttComponent.VTableBase);435      assert(addressPoint.AddressPointIndex != 0 &&436             "Did not find ctor vtable address point!");437    }438 439    mlir::Attribute indices[2] = {440        cgm.getBuilder().getI32IntegerAttr(addressPoint.VTableIndex),441        cgm.getBuilder().getI32IntegerAttr(addressPoint.AddressPointIndex),442    };443 444    auto indicesAttr = mlir::ArrayAttr::get(mlirContext, indices);445    cir::GlobalViewAttr init = cgm.getBuilder().getGlobalViewAttr(446        cgm.getBuilder().getUInt8PtrTy(), vtable, indicesAttr);447 448    vttComponents.push_back(init);449  }450 451  auto init = cir::ConstArrayAttr::get(452      arrayType, mlir::ArrayAttr::get(mlirContext, vttComponents));453 454  vttOp.setInitialValueAttr(init);455 456  // Set the correct linkage.457  vttOp.setLinkage(linkage);458  mlir::SymbolTable::setSymbolVisibility(459      vttOp, CIRGenModule::getMLIRVisibility(vttOp));460 461  if (cgm.supportsCOMDAT() && vttOp.isWeakForLinker())462    vttOp.setComdat(true);463}464 465uint64_t CIRGenVTables::getSubVTTIndex(const CXXRecordDecl *rd,466                                       BaseSubobject base) {467  BaseSubobjectPairTy classSubobjectPair(rd, base);468 469  SubVTTIndiciesMapTy::iterator it = subVTTIndicies.find(classSubobjectPair);470  if (it != subVTTIndicies.end())471    return it->second;472 473  VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);474 475  for (const auto &entry : builder.getSubVTTIndices()) {476    // Insert all indices.477    BaseSubobjectPairTy subclassSubobjectPair(rd, entry.first);478 479    subVTTIndicies.insert(std::make_pair(subclassSubobjectPair, entry.second));480  }481 482  it = subVTTIndicies.find(classSubobjectPair);483  assert(it != subVTTIndicies.end() && "Did not find index!");484 485  return it->second;486}487 488uint64_t CIRGenVTables::getSecondaryVirtualPointerIndex(const CXXRecordDecl *rd,489                                                        BaseSubobject base) {490  auto it = secondaryVirtualPointerIndices.find(std::make_pair(rd, base));491 492  if (it != secondaryVirtualPointerIndices.end())493    return it->second;494 495  VTTBuilder builder(cgm.getASTContext(), rd, /*GenerateDefinition=*/false);496 497  // Insert all secondary vpointer indices.498  for (const auto &entry : builder.getSecondaryVirtualPointerIndices()) {499    std::pair<const CXXRecordDecl *, BaseSubobject> pair =500        std::make_pair(rd, entry.first);501 502    secondaryVirtualPointerIndices.insert(std::make_pair(pair, entry.second));503  }504 505  it = secondaryVirtualPointerIndices.find(std::make_pair(rd, base));506  assert(it != secondaryVirtualPointerIndices.end() && "Did not find index!");507 508  return it->second;509}510 511void CIRGenVTables::emitThunks(GlobalDecl gd) {512  const CXXMethodDecl *md =513      cast<CXXMethodDecl>(gd.getDecl())->getCanonicalDecl();514 515  // We don't need to generate thunks for the base destructor.516  if (isa<CXXDestructorDecl>(md) && gd.getDtorType() == Dtor_Base)517    return;518 519  const VTableContextBase::ThunkInfoVectorTy *thunkInfoVector =520      vtContext->getThunkInfo(gd);521 522  if (!thunkInfoVector)523    return;524 525  cgm.errorNYI(md->getSourceRange(), "emitThunks");526}527