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(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>(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 | |