| 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 = 0; |
| 34 | unsigned StaticLocalNumber = 0; |
| 35 | unsigned StaticThreadlocalNumber = 0; |
| 36 | |
| 37 | public: |
| 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 | |
| 66 | class MSHIPNumberingContext : public MicrosoftNumberingContext { |
| 67 | std::unique_ptr<MangleNumberingContext> DeviceCtx; |
| 68 | |
| 69 | public: |
| 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 | L: DiagnosticsEngine::Error, FormatString: "Mangling number exceeds limit (65535)" ); |
| 88 | Diags.Report(Loc: TD->getLocation(), DiagID); |
| 89 | } |
| 90 | return (DeviceN << 16) | HostN; |
| 91 | } |
| 92 | }; |
| 93 | |
| 94 | class MSSYCLNumberingContext : public MicrosoftNumberingContext { |
| 95 | std::unique_ptr<MangleNumberingContext> DeviceCtx; |
| 96 | |
| 97 | public: |
| 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 | |
| 107 | class 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 | |
| 120 | public: |
| 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 | p: Context.createMangleContext(T: Context.getAuxTargetInfo())); |
| 128 | } |
| 129 | else if (Context.getLangOpts().isSYCL()) { |
| 130 | DeviceMangler.reset( |
| 131 | p: ItaniumMangleContext::create(Context, Diags&: Context.getDiagnostics())); |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | MemberPointerInfo |
| 136 | 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 | void |
| 155 | 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 | Val: const_cast<TagDecl *>(TD->getCanonicalDecl())); |
| 174 | } |
| 175 | |
| 176 | void addDeclaratorForUnnamedTagDecl(TagDecl *TD, |
| 177 | DeclaratorDecl *DD) override { |
| 178 | TD = TD->getCanonicalDecl(); |
| 179 | DD = cast<DeclaratorDecl>(Val: 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 | Val: 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>(args: DeviceMangler.get()); |
| 195 | } else if (Context.getLangOpts().isSYCL()) { |
| 196 | assert(DeviceMangler && "Missing device mangler" ); |
| 197 | return std::make_unique<MSSYCLNumberingContext>(args: 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 the |
| 206 | // total. This function tells us if we inherit from anybody that uses MI, or if |
| 207 | // we have a non-primary base class, which uses the multiple inheritance model. |
| 208 | static 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 | |
| 222 | MSInheritanceModel CXXRecordDecl::calculateInheritanceModel() const { |
| 223 | if (!hasDefinition() || isParsingBaseSpecifiers()) |
| 224 | return MSInheritanceModel::Unspecified; |
| 225 | if (getNumVBases() > 0) |
| 226 | return MSInheritanceModel::Virtual; |
| 227 | if (usesMultipleInheritanceModel(RD: this)) |
| 228 | return MSInheritanceModel::Multiple; |
| 229 | return MSInheritanceModel::Single; |
| 230 | } |
| 231 | |
| 232 | MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const { |
| 233 | MSInheritanceAttr *IA = getAttr<MSInheritanceAttr>(); |
| 234 | assert(IA && "Expected MSInheritanceAttr on the CXXRecordDecl!" ); |
| 235 | return IA->getInheritanceModel(); |
| 236 | } |
| 237 | |
| 238 | bool CXXRecordDecl::nullFieldOffsetIsZero() const { |
| 239 | return !inheritanceModelHasOnlyOneField(/*IsMemberFunction=*/false, |
| 240 | Inheritance: getMSInheritanceModel()) || |
| 241 | (hasDefinition() && isPolymorphic()); |
| 242 | } |
| 243 | |
| 244 | MSVtorDispMode 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 member |
| 251 | // pointer in the MS C++ ABI. |
| 252 | // |
| 253 | // Member function pointers have the following general form; however, fields |
| 254 | // are dropped as permitted (under the MSVC interpretation) by the inheritance |
| 255 | // model of the actual class. |
| 256 | // |
| 257 | // struct { |
| 258 | // // A pointer to the member function to call. If the member function is |
| 259 | // // virtual, this will be a thunk that forwards to the appropriate vftable |
| 260 | // // slot. |
| 261 | // void *FunctionPointerOrVirtualThunk; |
| 262 | // |
| 263 | // // An offset to add to the address of the vbtable pointer after |
| 264 | // // (possibly) selecting the virtual base but before resolving and calling |
| 265 | // // the function. |
| 266 | // // Only needed if the class has any virtual bases or bases at a non-zero |
| 267 | // // offset. |
| 268 | // int NonVirtualBaseAdjustment; |
| 269 | // |
| 270 | // // The offset of the vb-table pointer within the object. Only needed for |
| 271 | // // incomplete types. |
| 272 | // int VBPtrOffset; |
| 273 | // |
| 274 | // // An offset within the vb-table that selects the virtual base containing |
| 275 | // // the member. Loading from this offset produces a new offset that is |
| 276 | // // added to the address of the vb-table pointer to produce the base. |
| 277 | // int VirtualBaseAdjustmentOffset; |
| 278 | // }; |
| 279 | static std::pair<unsigned, unsigned> |
| 280 | getMSMemberPointerSlots(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 | else |
| 288 | Ints = 1; |
| 289 | if (inheritanceModelHasNVOffsetField(IsMemberFunction: MPT->isMemberFunctionPointer(), |
| 290 | Inheritance)) |
| 291 | Ints++; |
| 292 | if (inheritanceModelHasVBPtrOffsetField(Inheritance)) |
| 293 | Ints++; |
| 294 | if (inheritanceModelHasVBTableOffsetField(Inheritance)) |
| 295 | Ints++; |
| 296 | return std::make_pair(x&: Ptrs, y&: Ints); |
| 297 | } |
| 298 | |
| 299 | CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo( |
| 300 | const MemberPointerType *MPT) const { |
| 301 | // The nominal struct is laid out with pointers followed by ints and aligned |
| 302 | // to a pointer width if any are present and an int width otherwise. |
| 303 | const TargetInfo &Target = Context.getTargetInfo(); |
| 304 | unsigned PtrSize = Target.getPointerWidth(AddrSpace: LangAS::Default); |
| 305 | unsigned IntSize = Target.getIntWidth(); |
| 306 | |
| 307 | unsigned Ptrs, Ints; |
| 308 | std::tie(args&: Ptrs, args&: 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 to |
| 314 | // 8 bytes. However, __alignof usually returns 4 for data memptrs and 8 for |
| 315 | // function memptrs. |
| 316 | if (Ptrs + Ints > 1 && Target.getTriple().isArch32Bit()) |
| 317 | MPI.Align = 64; |
| 318 | else if (Ptrs) |
| 319 | MPI.Align = Target.getPointerAlign(AddrSpace: LangAS::Default); |
| 320 | else |
| 321 | MPI.Align = Target.getIntAlign(); |
| 322 | |
| 323 | if (Target.getTriple().isArch64Bit()) { |
| 324 | MPI.Width = llvm::alignTo(Value: MPI.Width, Align: MPI.Align); |
| 325 | MPI.HasPadding = MPI.Width != (Ptrs * PtrSize + Ints * IntSize); |
| 326 | } |
| 327 | return MPI; |
| 328 | } |
| 329 | |
| 330 | CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) { |
| 331 | return new MicrosoftCXXABI(Ctx); |
| 332 | } |
| 333 | |