brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.5 KiB · 1c020c3 Raw
333 lines · cpp
1//===------- MicrosoftCXXABI.cpp - AST support for the Microsoft C++ ABI --===//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 provides C++ AST support targeting the Microsoft Visual C++10// ABI.11//12//===----------------------------------------------------------------------===//13 14#include "CXXABI.h"15#include "clang/AST/ASTContext.h"16#include "clang/AST/Attr.h"17#include "clang/AST/CXXInheritance.h"18#include "clang/AST/DeclCXX.h"19#include "clang/AST/Mangle.h"20#include "clang/AST/MangleNumberingContext.h"21#include "clang/AST/RecordLayout.h"22#include "clang/AST/Type.h"23#include "clang/Basic/TargetInfo.h"24 25using namespace clang;26 27namespace {28 29/// Numbers things which need to correspond across multiple TUs.30/// Typically these are things like static locals, lambdas, or blocks.31class MicrosoftNumberingContext : public MangleNumberingContext {32  llvm::DenseMap<const Type *, unsigned> ManglingNumbers;33  unsigned LambdaManglingNumber = 0;34  unsigned StaticLocalNumber = 0;35  unsigned StaticThreadlocalNumber = 0;36 37public:38  MicrosoftNumberingContext() = default;39 40  unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {41    return ++LambdaManglingNumber;42  }43 44  unsigned getManglingNumber(const BlockDecl *BD) override {45    const Type *Ty = nullptr;46    return ++ManglingNumbers[Ty];47  }48 49  unsigned getStaticLocalNumber(const VarDecl *VD) override {50    if (VD->getTLSKind())51      return ++StaticThreadlocalNumber;52    return ++StaticLocalNumber;53  }54 55  unsigned getManglingNumber(const VarDecl *VD,56                             unsigned MSLocalManglingNumber) override {57    return MSLocalManglingNumber;58  }59 60  unsigned getManglingNumber(const TagDecl *TD,61                             unsigned MSLocalManglingNumber) override {62    return MSLocalManglingNumber;63  }64};65 66class MSHIPNumberingContext : public MicrosoftNumberingContext {67  std::unique_ptr<MangleNumberingContext> DeviceCtx;68 69public:70  using MicrosoftNumberingContext::getManglingNumber;71  MSHIPNumberingContext(MangleContext *DeviceMangler) {72    DeviceCtx = createItaniumNumberingContext(DeviceMangler);73  }74 75  unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override {76    return DeviceCtx->getManglingNumber(CallOperator);77  }78 79  unsigned getManglingNumber(const TagDecl *TD,80                             unsigned MSLocalManglingNumber) override {81    unsigned DeviceN = DeviceCtx->getManglingNumber(TD, MSLocalManglingNumber);82    unsigned HostN =83        MicrosoftNumberingContext::getManglingNumber(TD, MSLocalManglingNumber);84    if (DeviceN > 0xFFFF || HostN > 0xFFFF) {85      DiagnosticsEngine &Diags = TD->getASTContext().getDiagnostics();86      unsigned DiagID = Diags.getCustomDiagID(87          DiagnosticsEngine::Error, "Mangling number exceeds limit (65535)");88      Diags.Report(TD->getLocation(), DiagID);89    }90    return (DeviceN << 16) | HostN;91  }92};93 94class MSSYCLNumberingContext : public MicrosoftNumberingContext {95  std::unique_ptr<MangleNumberingContext> DeviceCtx;96 97public:98  MSSYCLNumberingContext(MangleContext *DeviceMangler) {99    DeviceCtx = createItaniumNumberingContext(DeviceMangler);100  }101 102  unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override {103    return DeviceCtx->getManglingNumber(CallOperator);104  }105};106 107class MicrosoftCXXABI : public CXXABI {108  ASTContext &Context;109  llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> RecordToCopyCtor;110 111  llvm::SmallDenseMap<TagDecl *, DeclaratorDecl *>112      UnnamedTagDeclToDeclaratorDecl;113  llvm::SmallDenseMap<TagDecl *, TypedefNameDecl *>114      UnnamedTagDeclToTypedefNameDecl;115 116  // MangleContext for device numbering context, which is based on Itanium C++117  // ABI.118  std::unique_ptr<MangleContext> DeviceMangler;119 120public:121  MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) {122    if (Context.getLangOpts().CUDA && Context.getAuxTargetInfo()) {123      assert(Context.getTargetInfo().getCXXABI().isMicrosoft() &&124             Context.getAuxTargetInfo()->getCXXABI().isItaniumFamily() &&125             "Unexpected combination of C++ ABIs.");126      DeviceMangler.reset(127          Context.createMangleContext(Context.getAuxTargetInfo()));128    }129    else if (Context.getLangOpts().isSYCL()) {130      DeviceMangler.reset(131          ItaniumMangleContext::create(Context, Context.getDiagnostics()));132    }133  }134 135  MemberPointerInfo136  getMemberPointerInfo(const MemberPointerType *MPT) const override;137 138  CallingConv getDefaultMethodCallConv(bool isVariadic) const override {139    if (!isVariadic &&140        Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)141      return CC_X86ThisCall;142    return Context.getTargetInfo().getDefaultCallingConv();143  }144 145  bool isNearlyEmpty(const CXXRecordDecl *RD) const override {146    llvm_unreachable("unapplicable to the MS ABI");147  }148 149  const CXXConstructorDecl *150  getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {151    return RecordToCopyCtor[RD];152  }153 154  void155  addCopyConstructorForExceptionObject(CXXRecordDecl *RD,156                                       CXXConstructorDecl *CD) override {157    assert(CD != nullptr);158    assert(RecordToCopyCtor[RD] == nullptr || RecordToCopyCtor[RD] == CD);159    RecordToCopyCtor[RD] = CD;160  }161 162  void addTypedefNameForUnnamedTagDecl(TagDecl *TD,163                                       TypedefNameDecl *DD) override {164    TD = TD->getCanonicalDecl();165    DD = DD->getCanonicalDecl();166    TypedefNameDecl *&I = UnnamedTagDeclToTypedefNameDecl[TD];167    if (!I)168      I = DD;169  }170 171  TypedefNameDecl *getTypedefNameForUnnamedTagDecl(const TagDecl *TD) override {172    return UnnamedTagDeclToTypedefNameDecl.lookup(173        const_cast<TagDecl *>(TD->getCanonicalDecl()));174  }175 176  void addDeclaratorForUnnamedTagDecl(TagDecl *TD,177                                      DeclaratorDecl *DD) override {178    TD = TD->getCanonicalDecl();179    DD = cast<DeclaratorDecl>(DD->getCanonicalDecl());180    DeclaratorDecl *&I = UnnamedTagDeclToDeclaratorDecl[TD];181    if (!I)182      I = DD;183  }184 185  DeclaratorDecl *getDeclaratorForUnnamedTagDecl(const TagDecl *TD) override {186    return UnnamedTagDeclToDeclaratorDecl.lookup(187        const_cast<TagDecl *>(TD->getCanonicalDecl()));188  }189 190  std::unique_ptr<MangleNumberingContext>191  createMangleNumberingContext() const override {192    if (Context.getLangOpts().CUDA && Context.getAuxTargetInfo()) {193      assert(DeviceMangler && "Missing device mangler");194      return std::make_unique<MSHIPNumberingContext>(DeviceMangler.get());195    } else if (Context.getLangOpts().isSYCL()) {196      assert(DeviceMangler && "Missing device mangler");197      return std::make_unique<MSSYCLNumberingContext>(DeviceMangler.get());198    }199 200    return std::make_unique<MicrosoftNumberingContext>();201  }202};203}204 205// getNumBases() seems to only give us the number of direct bases, and not the206// total.  This function tells us if we inherit from anybody that uses MI, or if207// we have a non-primary base class, which uses the multiple inheritance model.208static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {209  while (RD->getNumBases() > 0) {210    if (RD->getNumBases() > 1)211      return true;212    assert(RD->getNumBases() == 1);213    const CXXRecordDecl *Base =214        RD->bases_begin()->getType()->getAsCXXRecordDecl();215    if (RD->isPolymorphic() && !Base->isPolymorphic())216      return true;217    RD = Base;218  }219  return false;220}221 222MSInheritanceModel CXXRecordDecl::calculateInheritanceModel() const {223  if (!hasDefinition() || isParsingBaseSpecifiers())224    return MSInheritanceModel::Unspecified;225  if (getNumVBases() > 0)226    return MSInheritanceModel::Virtual;227  if (usesMultipleInheritanceModel(this))228    return MSInheritanceModel::Multiple;229  return MSInheritanceModel::Single;230}231 232MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const {233  MSInheritanceAttr *IA = getAttr<MSInheritanceAttr>();234  assert(IA && "Expected MSInheritanceAttr on the CXXRecordDecl!");235  return IA->getInheritanceModel();236}237 238bool CXXRecordDecl::nullFieldOffsetIsZero() const {239  return !inheritanceModelHasOnlyOneField(/*IsMemberFunction=*/false,240                                          getMSInheritanceModel()) ||241         (hasDefinition() && isPolymorphic());242}243 244MSVtorDispMode CXXRecordDecl::getMSVtorDispMode() const {245  if (MSVtorDispAttr *VDA = getAttr<MSVtorDispAttr>())246    return VDA->getVtorDispMode();247  return getASTContext().getLangOpts().getVtorDispMode();248}249 250// Returns the number of pointer and integer slots used to represent a member251// pointer in the MS C++ ABI.252//253// Member function pointers have the following general form;  however, fields254// are dropped as permitted (under the MSVC interpretation) by the inheritance255// model of the actual class.256//257//   struct {258//     // A pointer to the member function to call.  If the member function is259//     // virtual, this will be a thunk that forwards to the appropriate vftable260//     // slot.261//     void *FunctionPointerOrVirtualThunk;262//263//     // An offset to add to the address of the vbtable pointer after264//     // (possibly) selecting the virtual base but before resolving and calling265//     // the function.266//     // Only needed if the class has any virtual bases or bases at a non-zero267//     // offset.268//     int NonVirtualBaseAdjustment;269//270//     // The offset of the vb-table pointer within the object.  Only needed for271//     // incomplete types.272//     int VBPtrOffset;273//274//     // An offset within the vb-table that selects the virtual base containing275//     // the member.  Loading from this offset produces a new offset that is276//     // added to the address of the vb-table pointer to produce the base.277//     int VirtualBaseAdjustmentOffset;278//   };279static std::pair<unsigned, unsigned>280getMSMemberPointerSlots(const MemberPointerType *MPT) {281  const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();282  MSInheritanceModel Inheritance = RD->getMSInheritanceModel();283  unsigned Ptrs = 0;284  unsigned Ints = 0;285  if (MPT->isMemberFunctionPointer())286    Ptrs = 1;287  else288    Ints = 1;289  if (inheritanceModelHasNVOffsetField(MPT->isMemberFunctionPointer(),290                                          Inheritance))291    Ints++;292  if (inheritanceModelHasVBPtrOffsetField(Inheritance))293    Ints++;294  if (inheritanceModelHasVBTableOffsetField(Inheritance))295    Ints++;296  return std::make_pair(Ptrs, Ints);297}298 299CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo(300    const MemberPointerType *MPT) const {301  // The nominal struct is laid out with pointers followed by ints and aligned302  // to a pointer width if any are present and an int width otherwise.303  const TargetInfo &Target = Context.getTargetInfo();304  unsigned PtrSize = Target.getPointerWidth(LangAS::Default);305  unsigned IntSize = Target.getIntWidth();306 307  unsigned Ptrs, Ints;308  std::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT);309  MemberPointerInfo MPI;310  MPI.HasPadding = false;311  MPI.Width = Ptrs * PtrSize + Ints * IntSize;312 313  // When MSVC does x86_32 record layout, it aligns aggregate member pointers to314  // 8 bytes.  However, __alignof usually returns 4 for data memptrs and 8 for315  // function memptrs.316  if (Ptrs + Ints > 1 && Target.getTriple().isArch32Bit())317    MPI.Align = 64;318  else if (Ptrs)319    MPI.Align = Target.getPointerAlign(LangAS::Default);320  else321    MPI.Align = Target.getIntAlign();322 323  if (Target.getTriple().isArch64Bit()) {324    MPI.Width = llvm::alignTo(MPI.Width, MPI.Align);325    MPI.HasPadding = MPI.Width != (Ptrs * PtrSize + Ints * IntSize);326  }327  return MPI;328}329 330CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {331  return new MicrosoftCXXABI(Ctx);332}333