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
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 L: DiagnosticsEngine::Error, FormatString: "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 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>(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.
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(RD: 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 Inheritance: 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 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// };
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 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
299CXXABI::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
330CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {
331 return new MicrosoftCXXABI(Ctx);
332}
333

source code of clang/lib/AST/MicrosoftCXXABI.cpp