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