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