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