1 | //===--- CGNonTrivialStruct.cpp - Emit Special Functions for C Structs ----===// |
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 file defines functions to generate various special functions for C |
10 | // structs. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "CGDebugInfo.h" |
15 | #include "CodeGenFunction.h" |
16 | #include "CodeGenModule.h" |
17 | #include "clang/AST/NonTrivialTypeVisitor.h" |
18 | #include "clang/CodeGen/CodeGenABITypes.h" |
19 | #include "llvm/Support/ScopedPrinter.h" |
20 | #include <array> |
21 | |
22 | using namespace clang; |
23 | using namespace CodeGen; |
24 | |
25 | // Return the size of a field in number of bits. |
26 | static uint64_t getFieldSize(const FieldDecl *FD, QualType FT, |
27 | ASTContext &Ctx) { |
28 | if (FD && FD->isBitField()) |
29 | return FD->getBitWidthValue(); |
30 | return Ctx.getTypeSize(T: FT); |
31 | } |
32 | |
33 | namespace { |
34 | enum { DstIdx = 0, SrcIdx = 1 }; |
35 | const char *ValNameStr[2] = {"dst" , "src" }; |
36 | |
37 | template <class Derived> struct StructVisitor { |
38 | StructVisitor(ASTContext &Ctx) : Ctx(Ctx) {} |
39 | |
40 | template <class... Ts> |
41 | void visitStructFields(QualType QT, CharUnits CurStructOffset, Ts... Args) { |
42 | const RecordDecl *RD = QT->castAs<RecordType>()->getDecl(); |
43 | |
44 | // Iterate over the fields of the struct. |
45 | for (const FieldDecl *FD : RD->fields()) { |
46 | QualType FT = FD->getType(); |
47 | FT = QT.isVolatileQualified() ? FT.withVolatile() : FT; |
48 | asDerived().visit(FT, FD, CurStructOffset, Args...); |
49 | } |
50 | |
51 | asDerived().flushTrivialFields(Args...); |
52 | } |
53 | |
54 | template <class... Ts> void visitTrivial(Ts... Args) {} |
55 | |
56 | template <class... Ts> void visitCXXDestructor(Ts... Args) { |
57 | llvm_unreachable("field of a C++ struct type is not expected" ); |
58 | } |
59 | |
60 | template <class... Ts> void flushTrivialFields(Ts... Args) {} |
61 | |
62 | uint64_t getFieldOffsetInBits(const FieldDecl *FD) { |
63 | return FD ? Ctx.getASTRecordLayout(D: FD->getParent()) |
64 | .getFieldOffset(FieldNo: FD->getFieldIndex()) |
65 | : 0; |
66 | } |
67 | |
68 | CharUnits getFieldOffset(const FieldDecl *FD) { |
69 | return Ctx.toCharUnitsFromBits(BitSize: getFieldOffsetInBits(FD)); |
70 | } |
71 | |
72 | Derived &asDerived() { return static_cast<Derived &>(*this); } |
73 | |
74 | ASTContext &getContext() { return Ctx; } |
75 | ASTContext &Ctx; |
76 | }; |
77 | |
78 | template <class Derived, bool IsMove> |
79 | struct CopyStructVisitor : StructVisitor<Derived>, |
80 | CopiedTypeVisitor<Derived, IsMove> { |
81 | using StructVisitor<Derived>::asDerived; |
82 | using Super = CopiedTypeVisitor<Derived, IsMove>; |
83 | |
84 | CopyStructVisitor(ASTContext &Ctx) : StructVisitor<Derived>(Ctx) {} |
85 | |
86 | template <class... Ts> |
87 | void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT, |
88 | const FieldDecl *FD, CharUnits CurStructOffset, Ts &&... Args) { |
89 | if (PCK) |
90 | asDerived().flushTrivialFields(std::forward<Ts>(Args)...); |
91 | } |
92 | |
93 | template <class... Ts> |
94 | void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT, |
95 | const FieldDecl *FD, CharUnits CurStructOffset, |
96 | Ts &&... Args) { |
97 | if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) { |
98 | asDerived().visitArray(PCK, AT, FT.isVolatileQualified(), FD, |
99 | CurStructOffset, std::forward<Ts>(Args)...); |
100 | return; |
101 | } |
102 | |
103 | Super::visitWithKind(PCK, FT, FD, CurStructOffset, |
104 | std::forward<Ts>(Args)...); |
105 | } |
106 | |
107 | template <class... Ts> |
108 | void visitTrivial(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset, |
109 | Ts... Args) { |
110 | assert(!FT.isVolatileQualified() && "volatile field not expected" ); |
111 | ASTContext &Ctx = asDerived().getContext(); |
112 | uint64_t FieldSize = getFieldSize(FD, FT, Ctx); |
113 | |
114 | // Ignore zero-sized fields. |
115 | if (FieldSize == 0) |
116 | return; |
117 | |
118 | uint64_t FStartInBits = asDerived().getFieldOffsetInBits(FD); |
119 | uint64_t FEndInBits = FStartInBits + FieldSize; |
120 | uint64_t RoundedFEnd = llvm::alignTo(Value: FEndInBits, Align: Ctx.getCharWidth()); |
121 | |
122 | // Set Start if this is the first field of a sequence of trivial fields. |
123 | if (Start == End) |
124 | Start = CurStructOffset + Ctx.toCharUnitsFromBits(BitSize: FStartInBits); |
125 | End = CurStructOffset + Ctx.toCharUnitsFromBits(BitSize: RoundedFEnd); |
126 | } |
127 | |
128 | CharUnits Start = CharUnits::Zero(), End = CharUnits::Zero(); |
129 | }; |
130 | |
131 | // This function creates the mangled name of a special function of a non-trivial |
132 | // C struct. Since there is no ODR in C, the function is mangled based on the |
133 | // struct contents and not the name. The mangled name has the following |
134 | // structure: |
135 | // |
136 | // <function-name> ::= <prefix> <alignment-info> "_" <struct-field-info> |
137 | // <prefix> ::= "__destructor_" | "__default_constructor_" | |
138 | // "__copy_constructor_" | "__move_constructor_" | |
139 | // "__copy_assignment_" | "__move_assignment_" |
140 | // <alignment-info> ::= <dst-alignment> ["_" <src-alignment>] |
141 | // <struct-field-info> ::= <field-info>+ |
142 | // <field-info> ::= <struct-or-scalar-field-info> | <array-field-info> |
143 | // <struct-or-scalar-field-info> ::= "_S" <struct-field-info> | |
144 | // <strong-field-info> | <trivial-field-info> |
145 | // <array-field-info> ::= "_AB" <array-offset> "s" <element-size> "n" |
146 | // <num-elements> <innermost-element-info> "_AE" |
147 | // <innermost-element-info> ::= <struct-or-scalar-field-info> |
148 | // <strong-field-info> ::= "_s" ["b"] ["v"] <field-offset> |
149 | // <trivial-field-info> ::= "_t" ["v"] <field-offset> "_" <field-size> |
150 | |
151 | template <class Derived> struct GenFuncNameBase { |
152 | std::string getVolatileOffsetStr(bool IsVolatile, CharUnits Offset) { |
153 | std::string S; |
154 | if (IsVolatile) |
155 | S = "v" ; |
156 | S += llvm::to_string(Value: Offset.getQuantity()); |
157 | return S; |
158 | } |
159 | |
160 | void visitARCStrong(QualType FT, const FieldDecl *FD, |
161 | CharUnits CurStructOffset) { |
162 | appendStr(Str: "_s" ); |
163 | if (FT->isBlockPointerType()) |
164 | appendStr(Str: "b" ); |
165 | CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); |
166 | appendStr(Str: getVolatileOffsetStr(IsVolatile: FT.isVolatileQualified(), Offset: FieldOffset)); |
167 | } |
168 | |
169 | void visitARCWeak(QualType FT, const FieldDecl *FD, |
170 | CharUnits CurStructOffset) { |
171 | appendStr(Str: "_w" ); |
172 | CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); |
173 | appendStr(Str: getVolatileOffsetStr(IsVolatile: FT.isVolatileQualified(), Offset: FieldOffset)); |
174 | } |
175 | |
176 | void visitStruct(QualType QT, const FieldDecl *FD, |
177 | CharUnits CurStructOffset) { |
178 | CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); |
179 | appendStr(Str: "_S" ); |
180 | asDerived().visitStructFields(QT, FieldOffset); |
181 | } |
182 | |
183 | template <class FieldKind> |
184 | void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile, |
185 | const FieldDecl *FD, CharUnits CurStructOffset) { |
186 | // String for non-volatile trivial fields is emitted when |
187 | // flushTrivialFields is called. |
188 | if (!FK) |
189 | return asDerived().visitTrivial(QualType(AT, 0), FD, CurStructOffset); |
190 | |
191 | asDerived().flushTrivialFields(); |
192 | CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); |
193 | ASTContext &Ctx = asDerived().getContext(); |
194 | const ConstantArrayType *CAT = cast<ConstantArrayType>(Val: AT); |
195 | unsigned NumElts = Ctx.getConstantArrayElementCount(CA: CAT); |
196 | QualType EltTy = Ctx.getBaseElementType(VAT: CAT); |
197 | CharUnits EltSize = Ctx.getTypeSizeInChars(T: EltTy); |
198 | appendStr(Str: "_AB" + llvm::to_string(Value: FieldOffset.getQuantity()) + "s" + |
199 | llvm::to_string(Value: EltSize.getQuantity()) + "n" + |
200 | llvm::to_string(Value: NumElts)); |
201 | EltTy = IsVolatile ? EltTy.withVolatile() : EltTy; |
202 | asDerived().visitWithKind(FK, EltTy, nullptr, FieldOffset); |
203 | appendStr(Str: "_AE" ); |
204 | } |
205 | |
206 | void appendStr(StringRef Str) { Name += Str; } |
207 | |
208 | std::string getName(QualType QT, bool IsVolatile) { |
209 | QT = IsVolatile ? QT.withVolatile() : QT; |
210 | asDerived().visitStructFields(QT, CharUnits::Zero()); |
211 | return Name; |
212 | } |
213 | |
214 | Derived &asDerived() { return static_cast<Derived &>(*this); } |
215 | |
216 | std::string Name; |
217 | }; |
218 | |
219 | template <class Derived> |
220 | struct GenUnaryFuncName : StructVisitor<Derived>, GenFuncNameBase<Derived> { |
221 | GenUnaryFuncName(StringRef Prefix, CharUnits DstAlignment, ASTContext &Ctx) |
222 | : StructVisitor<Derived>(Ctx) { |
223 | this->appendStr(Prefix); |
224 | this->appendStr(llvm::to_string(Value: DstAlignment.getQuantity())); |
225 | } |
226 | }; |
227 | |
228 | // Helper function to create a null constant. |
229 | static llvm::Constant *getNullForVariable(Address Addr) { |
230 | llvm::Type *Ty = Addr.getElementType(); |
231 | return llvm::ConstantPointerNull::get(T: cast<llvm::PointerType>(Val: Ty)); |
232 | } |
233 | |
234 | template <bool IsMove> |
235 | struct GenBinaryFuncName : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>, |
236 | GenFuncNameBase<GenBinaryFuncName<IsMove>> { |
237 | |
238 | GenBinaryFuncName(StringRef Prefix, CharUnits DstAlignment, |
239 | CharUnits SrcAlignment, ASTContext &Ctx) |
240 | : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>(Ctx) { |
241 | this->appendStr(Prefix); |
242 | this->appendStr(llvm::to_string(Value: DstAlignment.getQuantity())); |
243 | this->appendStr("_" + llvm::to_string(Value: SrcAlignment.getQuantity())); |
244 | } |
245 | |
246 | void flushTrivialFields() { |
247 | if (this->Start == this->End) |
248 | return; |
249 | |
250 | this->appendStr("_t" + llvm::to_string(this->Start.getQuantity()) + "w" + |
251 | llvm::to_string((this->End - this->Start).getQuantity())); |
252 | |
253 | this->Start = this->End = CharUnits::Zero(); |
254 | } |
255 | |
256 | void visitVolatileTrivial(QualType FT, const FieldDecl *FD, |
257 | CharUnits CurStructOffset) { |
258 | // Zero-length bit-fields don't need to be copied/assigned. |
259 | if (FD && FD->isZeroLengthBitField()) |
260 | return; |
261 | |
262 | // Because volatile fields can be bit-fields and are individually copied, |
263 | // their offset and width are in bits. |
264 | uint64_t OffsetInBits = |
265 | this->Ctx.toBits(CurStructOffset) + this->getFieldOffsetInBits(FD); |
266 | this->appendStr("_tv" + llvm::to_string(Value: OffsetInBits) + "w" + |
267 | llvm::to_string(getFieldSize(FD, FT, this->Ctx))); |
268 | } |
269 | |
270 | void visitPtrAuth(QualType FT, const FieldDecl *FD, |
271 | CharUnits CurStructOffset) { |
272 | this->appendStr("_pa" ); |
273 | PointerAuthQualifier PtrAuth = FT.getPointerAuth().withoutKeyNone(); |
274 | this->appendStr(llvm::to_string(Value: PtrAuth.getKey()) + "_" ); |
275 | this->appendStr(llvm::to_string(Value: PtrAuth.getExtraDiscriminator()) + "_" ); |
276 | if (PtrAuth.authenticatesNullValues()) |
277 | this->appendStr("anv_" ); |
278 | CharUnits FieldOffset = CurStructOffset + this->getFieldOffset(FD); |
279 | this->appendStr(llvm::to_string(Value: FieldOffset.getQuantity())); |
280 | } |
281 | }; |
282 | |
283 | struct GenDefaultInitializeFuncName |
284 | : GenUnaryFuncName<GenDefaultInitializeFuncName>, |
285 | DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName> { |
286 | using Super = DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName>; |
287 | GenDefaultInitializeFuncName(CharUnits DstAlignment, ASTContext &Ctx) |
288 | : GenUnaryFuncName<GenDefaultInitializeFuncName>("__default_constructor_" , |
289 | DstAlignment, Ctx) {} |
290 | void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT, |
291 | const FieldDecl *FD, CharUnits CurStructOffset) { |
292 | if (const auto *AT = getContext().getAsArrayType(T: FT)) { |
293 | visitArray(FK: PDIK, AT, IsVolatile: FT.isVolatileQualified(), FD, CurStructOffset); |
294 | return; |
295 | } |
296 | |
297 | Super::visitWithKind(PDIK, FT, Args&: FD, Args&: CurStructOffset); |
298 | } |
299 | }; |
300 | |
301 | struct GenDestructorFuncName : GenUnaryFuncName<GenDestructorFuncName>, |
302 | DestructedTypeVisitor<GenDestructorFuncName> { |
303 | using Super = DestructedTypeVisitor<GenDestructorFuncName>; |
304 | GenDestructorFuncName(const char *Prefix, CharUnits DstAlignment, |
305 | ASTContext &Ctx) |
306 | : GenUnaryFuncName<GenDestructorFuncName>(Prefix, DstAlignment, Ctx) {} |
307 | void visitWithKind(QualType::DestructionKind DK, QualType FT, |
308 | const FieldDecl *FD, CharUnits CurStructOffset) { |
309 | if (const auto *AT = getContext().getAsArrayType(T: FT)) { |
310 | visitArray(FK: DK, AT, IsVolatile: FT.isVolatileQualified(), FD, CurStructOffset); |
311 | return; |
312 | } |
313 | |
314 | Super::visitWithKind(DK, FT, Args&: FD, Args&: CurStructOffset); |
315 | } |
316 | }; |
317 | |
318 | // Helper function that creates CGFunctionInfo for an N-ary special function. |
319 | template <size_t N> |
320 | static const CGFunctionInfo &getFunctionInfo(CodeGenModule &CGM, |
321 | FunctionArgList &Args) { |
322 | ASTContext &Ctx = CGM.getContext(); |
323 | llvm::SmallVector<ImplicitParamDecl *, N> Params; |
324 | QualType ParamTy = Ctx.getPointerType(T: Ctx.VoidPtrTy); |
325 | |
326 | for (unsigned I = 0; I < N; ++I) |
327 | Params.push_back(ImplicitParamDecl::Create( |
328 | C&: Ctx, DC: nullptr, IdLoc: SourceLocation(), Id: &Ctx.Idents.get(Name: ValNameStr[I]), T: ParamTy, |
329 | ParamKind: ImplicitParamKind::Other)); |
330 | |
331 | llvm::append_range(Args, Params); |
332 | |
333 | return CGM.getTypes().arrangeBuiltinFunctionDeclaration(resultType: Ctx.VoidTy, args: Args); |
334 | } |
335 | |
336 | template <size_t N, size_t... Ints> |
337 | static std::array<Address, N> getParamAddrs(std::index_sequence<Ints...> IntSeq, |
338 | std::array<CharUnits, N> Alignments, |
339 | const FunctionArgList &Args, |
340 | CodeGenFunction *CGF) { |
341 | return std::array<Address, N>{ |
342 | {Address(CGF->Builder.CreateLoad(Addr: CGF->GetAddrOfLocalVar(VD: Args[Ints])), |
343 | CGF->VoidPtrTy, Alignments[Ints], KnownNonNull)...}}; |
344 | } |
345 | |
346 | // Template classes that are used as bases for classes that emit special |
347 | // functions. |
348 | template <class Derived> struct GenFuncBase { |
349 | template <size_t N> |
350 | void visitStruct(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset, |
351 | std::array<Address, N> Addrs) { |
352 | this->asDerived().callSpecialFunction( |
353 | FT, CurStructOffset + asDerived().getFieldOffset(FD), Addrs); |
354 | } |
355 | |
356 | template <class FieldKind, size_t N> |
357 | void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile, |
358 | const FieldDecl *FD, CharUnits CurStructOffset, |
359 | std::array<Address, N> Addrs) { |
360 | // Non-volatile trivial fields are copied when flushTrivialFields is called. |
361 | if (!FK) |
362 | return asDerived().visitTrivial(QualType(AT, 0), FD, CurStructOffset, |
363 | Addrs); |
364 | |
365 | asDerived().flushTrivialFields(Addrs); |
366 | CodeGenFunction &CGF = *this->CGF; |
367 | ASTContext &Ctx = CGF.getContext(); |
368 | |
369 | // Compute the end address. |
370 | QualType BaseEltQT; |
371 | std::array<Address, N> StartAddrs = Addrs; |
372 | for (unsigned I = 0; I < N; ++I) |
373 | StartAddrs[I] = getAddrWithOffset(Addrs[I], CurStructOffset, FD); |
374 | Address DstAddr = StartAddrs[DstIdx]; |
375 | llvm::Value *NumElts = CGF.emitArrayLength(arrayType: AT, baseType&: BaseEltQT, addr&: DstAddr); |
376 | unsigned BaseEltSize = Ctx.getTypeSizeInChars(T: BaseEltQT).getQuantity(); |
377 | llvm::Value *BaseEltSizeVal = |
378 | llvm::ConstantInt::get(Ty: NumElts->getType(), V: BaseEltSize); |
379 | llvm::Value *SizeInBytes = |
380 | CGF.Builder.CreateNUWMul(LHS: BaseEltSizeVal, RHS: NumElts); |
381 | llvm::Value *DstArrayEnd = CGF.Builder.CreateInBoundsGEP( |
382 | Ty: CGF.Int8Ty, Ptr: DstAddr.emitRawPointer(CGF), IdxList: SizeInBytes); |
383 | llvm::BasicBlock * = CGF.Builder.GetInsertBlock(); |
384 | |
385 | // Create the header block and insert the phi instructions. |
386 | llvm::BasicBlock * = CGF.createBasicBlock(name: "loop.header" ); |
387 | CGF.EmitBlock(BB: HeaderBB); |
388 | llvm::PHINode *PHIs[N]; |
389 | |
390 | for (unsigned I = 0; I < N; ++I) { |
391 | PHIs[I] = CGF.Builder.CreatePHI(Ty: CGF.CGM.Int8PtrPtrTy, NumReservedValues: 2, Name: "addr.cur" ); |
392 | PHIs[I]->addIncoming(StartAddrs[I].emitRawPointer(CGF), PreheaderBB); |
393 | } |
394 | |
395 | // Create the exit and loop body blocks. |
396 | llvm::BasicBlock *ExitBB = CGF.createBasicBlock(name: "loop.exit" ); |
397 | llvm::BasicBlock *LoopBB = CGF.createBasicBlock(name: "loop.body" ); |
398 | |
399 | // Emit the comparison and conditional branch instruction that jumps to |
400 | // either the exit or the loop body. |
401 | llvm::Value *Done = |
402 | CGF.Builder.CreateICmpEQ(LHS: PHIs[DstIdx], RHS: DstArrayEnd, Name: "done" ); |
403 | CGF.Builder.CreateCondBr(Cond: Done, True: ExitBB, False: LoopBB); |
404 | |
405 | // Visit the element of the array in the loop body. |
406 | CGF.EmitBlock(BB: LoopBB); |
407 | QualType EltQT = AT->getElementType(); |
408 | CharUnits EltSize = Ctx.getTypeSizeInChars(T: EltQT); |
409 | std::array<Address, N> NewAddrs = Addrs; |
410 | |
411 | for (unsigned I = 0; I < N; ++I) |
412 | NewAddrs[I] = |
413 | Address(PHIs[I], CGF.Int8PtrTy, |
414 | StartAddrs[I].getAlignment().alignmentAtOffset(EltSize)); |
415 | |
416 | EltQT = IsVolatile ? EltQT.withVolatile() : EltQT; |
417 | this->asDerived().visitWithKind(FK, EltQT, nullptr, CharUnits::Zero(), |
418 | NewAddrs); |
419 | |
420 | LoopBB = CGF.Builder.GetInsertBlock(); |
421 | |
422 | for (unsigned I = 0; I < N; ++I) { |
423 | // Instrs to update the destination and source addresses. |
424 | // Update phi instructions. |
425 | NewAddrs[I] = getAddrWithOffset(NewAddrs[I], EltSize); |
426 | PHIs[I]->addIncoming(NewAddrs[I].emitRawPointer(CGF), LoopBB); |
427 | } |
428 | |
429 | // Insert an unconditional branch to the header block. |
430 | CGF.Builder.CreateBr(Dest: HeaderBB); |
431 | CGF.EmitBlock(BB: ExitBB); |
432 | } |
433 | |
434 | /// Return an address with the specified offset from the passed address. |
435 | Address getAddrWithOffset(Address Addr, CharUnits Offset) { |
436 | assert(Addr.isValid() && "invalid address" ); |
437 | if (Offset.getQuantity() == 0) |
438 | return Addr; |
439 | Addr = Addr.withElementType(ElemTy: CGF->CGM.Int8Ty); |
440 | Addr = CGF->Builder.CreateConstInBoundsGEP(Addr, Index: Offset.getQuantity()); |
441 | return Addr.withElementType(ElemTy: CGF->CGM.Int8PtrTy); |
442 | } |
443 | |
444 | Address getAddrWithOffset(Address Addr, CharUnits StructFieldOffset, |
445 | const FieldDecl *FD) { |
446 | return getAddrWithOffset(Addr, StructFieldOffset + |
447 | asDerived().getFieldOffset(FD)); |
448 | } |
449 | |
450 | template <size_t N> |
451 | llvm::Function *getFunction(StringRef FuncName, QualType QT, |
452 | std::array<CharUnits, N> Alignments, |
453 | CodeGenModule &CGM) { |
454 | // If the special function already exists in the module, return it. |
455 | if (llvm::Function *F = CGM.getModule().getFunction(Name: FuncName)) { |
456 | bool WrongType = false; |
457 | if (!F->getReturnType()->isVoidTy()) |
458 | WrongType = true; |
459 | else { |
460 | for (const llvm::Argument &Arg : F->args()) |
461 | if (Arg.getType() != CGM.Int8PtrPtrTy) |
462 | WrongType = true; |
463 | } |
464 | |
465 | if (WrongType) { |
466 | std::string FuncName = std::string(F->getName()); |
467 | SourceLocation Loc = QT->castAs<RecordType>()->getDecl()->getLocation(); |
468 | CGM.Error(loc: Loc, error: "special function " + FuncName + |
469 | " for non-trivial C struct has incorrect type" ); |
470 | return nullptr; |
471 | } |
472 | return F; |
473 | } |
474 | |
475 | ASTContext &Ctx = CGM.getContext(); |
476 | FunctionArgList Args; |
477 | const CGFunctionInfo &FI = getFunctionInfo<N>(CGM, Args); |
478 | llvm::FunctionType *FuncTy = CGM.getTypes().GetFunctionType(Info: FI); |
479 | llvm::Function *F = |
480 | llvm::Function::Create(Ty: FuncTy, Linkage: llvm::GlobalValue::LinkOnceODRLinkage, |
481 | N: FuncName, M: &CGM.getModule()); |
482 | F->setVisibility(llvm::GlobalValue::HiddenVisibility); |
483 | CGM.SetLLVMFunctionAttributes(GD: GlobalDecl(), Info: FI, F, /*IsThunk=*/false); |
484 | CGM.SetLLVMFunctionAttributesForDefinition(D: nullptr, F); |
485 | CodeGenFunction NewCGF(CGM); |
486 | setCGF(&NewCGF); |
487 | CGF->StartFunction(GD: GlobalDecl(), RetTy: Ctx.VoidTy, Fn: F, FnInfo: FI, Args); |
488 | auto AL = ApplyDebugLocation::CreateArtificial(CGF&: *CGF); |
489 | std::array<Address, N> Addrs = |
490 | getParamAddrs<N>(std::make_index_sequence<N>{}, Alignments, Args, CGF); |
491 | asDerived().visitStructFields(QT, CharUnits::Zero(), Addrs); |
492 | CGF->FinishFunction(); |
493 | return F; |
494 | } |
495 | |
496 | template <size_t N> |
497 | void callFunc(StringRef FuncName, QualType QT, std::array<Address, N> Addrs, |
498 | CodeGenFunction &CallerCGF) { |
499 | std::array<CharUnits, N> Alignments; |
500 | llvm::Value *Ptrs[N]; |
501 | |
502 | for (unsigned I = 0; I < N; ++I) { |
503 | Alignments[I] = Addrs[I].getAlignment(); |
504 | Ptrs[I] = Addrs[I].emitRawPointer(CallerCGF); |
505 | } |
506 | |
507 | if (llvm::Function *F = |
508 | getFunction(FuncName, QT, Alignments, CallerCGF.CGM)) |
509 | CallerCGF.EmitNounwindRuntimeCall(F, Ptrs); |
510 | } |
511 | |
512 | Derived &asDerived() { return static_cast<Derived &>(*this); } |
513 | |
514 | void setCGF(CodeGenFunction *F) { CGF = F; } |
515 | |
516 | CodeGenFunction *CGF = nullptr; |
517 | }; |
518 | |
519 | template <class Derived, bool IsMove> |
520 | struct GenBinaryFunc : CopyStructVisitor<Derived, IsMove>, |
521 | GenFuncBase<Derived> { |
522 | GenBinaryFunc(ASTContext &Ctx) : CopyStructVisitor<Derived, IsMove>(Ctx) {} |
523 | |
524 | void flushTrivialFields(std::array<Address, 2> Addrs) { |
525 | CharUnits Size = this->End - this->Start; |
526 | |
527 | if (Size.getQuantity() == 0) |
528 | return; |
529 | |
530 | Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], this->Start); |
531 | Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], this->Start); |
532 | |
533 | // Emit memcpy. |
534 | if (Size.getQuantity() >= 16 || |
535 | !llvm::has_single_bit<uint32_t>(Value: Size.getQuantity())) { |
536 | llvm::Value *SizeVal = |
537 | llvm::ConstantInt::get(this->CGF->SizeTy, Size.getQuantity()); |
538 | DstAddr = DstAddr.withElementType(ElemTy: this->CGF->Int8Ty); |
539 | SrcAddr = SrcAddr.withElementType(ElemTy: this->CGF->Int8Ty); |
540 | this->CGF->Builder.CreateMemCpy(DstAddr, SrcAddr, SizeVal, false); |
541 | } else { |
542 | llvm::Type *Ty = llvm::Type::getIntNTy( |
543 | C&: this->CGF->getLLVMContext(), |
544 | N: Size.getQuantity() * this->CGF->getContext().getCharWidth()); |
545 | DstAddr = DstAddr.withElementType(ElemTy: Ty); |
546 | SrcAddr = SrcAddr.withElementType(ElemTy: Ty); |
547 | llvm::Value *SrcVal = this->CGF->Builder.CreateLoad(SrcAddr, false); |
548 | this->CGF->Builder.CreateStore(SrcVal, DstAddr, false); |
549 | } |
550 | |
551 | this->Start = this->End = CharUnits::Zero(); |
552 | } |
553 | |
554 | template <class... Ts> |
555 | void visitVolatileTrivial(QualType FT, const FieldDecl *FD, CharUnits Offset, |
556 | std::array<Address, 2> Addrs) { |
557 | LValue DstLV, SrcLV; |
558 | if (FD) { |
559 | // No need to copy zero-length bit-fields. |
560 | if (FD->isZeroLengthBitField()) |
561 | return; |
562 | |
563 | QualType RT = QualType(FD->getParent()->getTypeForDecl(), 0); |
564 | llvm::Type *Ty = this->CGF->ConvertType(RT); |
565 | Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], Offset); |
566 | LValue DstBase = |
567 | this->CGF->MakeAddrLValue(DstAddr.withElementType(ElemTy: Ty), FT); |
568 | DstLV = this->CGF->EmitLValueForField(DstBase, FD); |
569 | Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], Offset); |
570 | LValue SrcBase = |
571 | this->CGF->MakeAddrLValue(SrcAddr.withElementType(ElemTy: Ty), FT); |
572 | SrcLV = this->CGF->EmitLValueForField(SrcBase, FD); |
573 | } else { |
574 | llvm::Type *Ty = this->CGF->ConvertTypeForMem(FT); |
575 | Address DstAddr = Addrs[DstIdx].withElementType(ElemTy: Ty); |
576 | Address SrcAddr = Addrs[SrcIdx].withElementType(ElemTy: Ty); |
577 | DstLV = this->CGF->MakeAddrLValue(DstAddr, FT); |
578 | SrcLV = this->CGF->MakeAddrLValue(SrcAddr, FT); |
579 | } |
580 | RValue SrcVal = this->CGF->EmitLoadOfLValue(SrcLV, SourceLocation()); |
581 | this->CGF->EmitStoreThroughLValue(SrcVal, DstLV); |
582 | } |
583 | void visitPtrAuth(QualType FT, const FieldDecl *FD, CharUnits CurStackOffset, |
584 | std::array<Address, 2> Addrs) { |
585 | PointerAuthQualifier PtrAuth = FT.getPointerAuth().withoutKeyNone(); |
586 | Addrs[DstIdx] = this->getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD); |
587 | Addrs[SrcIdx] = this->getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD); |
588 | this->CGF->EmitPointerAuthCopy(PtrAuth, FT, Addrs[DstIdx], Addrs[SrcIdx]); |
589 | } |
590 | }; |
591 | |
592 | // These classes that emit the special functions for a non-trivial struct. |
593 | struct GenDestructor : StructVisitor<GenDestructor>, |
594 | GenFuncBase<GenDestructor>, |
595 | DestructedTypeVisitor<GenDestructor> { |
596 | using Super = DestructedTypeVisitor<GenDestructor>; |
597 | GenDestructor(ASTContext &Ctx) : StructVisitor<GenDestructor>(Ctx) {} |
598 | |
599 | void visitWithKind(QualType::DestructionKind DK, QualType FT, |
600 | const FieldDecl *FD, CharUnits CurStructOffset, |
601 | std::array<Address, 1> Addrs) { |
602 | if (const auto *AT = getContext().getAsArrayType(T: FT)) { |
603 | visitArray(FK: DK, AT, IsVolatile: FT.isVolatileQualified(), FD, CurStructOffset, Addrs); |
604 | return; |
605 | } |
606 | |
607 | Super::visitWithKind(DK, FT, Args&: FD, Args&: CurStructOffset, Args&: Addrs); |
608 | } |
609 | |
610 | void visitARCStrong(QualType QT, const FieldDecl *FD, |
611 | CharUnits CurStructOffset, std::array<Address, 1> Addrs) { |
612 | CGF->destroyARCStrongImprecise( |
613 | *CGF, getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD), QT); |
614 | } |
615 | |
616 | void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, |
617 | std::array<Address, 1> Addrs) { |
618 | CGF->destroyARCWeak( |
619 | *CGF, getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD), QT); |
620 | } |
621 | |
622 | void callSpecialFunction(QualType FT, CharUnits Offset, |
623 | std::array<Address, 1> Addrs) { |
624 | CGF->callCStructDestructor( |
625 | Dst: CGF->MakeAddrLValue(Addr: getAddrWithOffset(Addr: Addrs[DstIdx], Offset), T: FT)); |
626 | } |
627 | }; |
628 | |
629 | struct GenDefaultInitialize |
630 | : StructVisitor<GenDefaultInitialize>, |
631 | GenFuncBase<GenDefaultInitialize>, |
632 | DefaultInitializedTypeVisitor<GenDefaultInitialize> { |
633 | using Super = DefaultInitializedTypeVisitor<GenDefaultInitialize>; |
634 | typedef GenFuncBase<GenDefaultInitialize> GenFuncBaseTy; |
635 | |
636 | GenDefaultInitialize(ASTContext &Ctx) |
637 | : StructVisitor<GenDefaultInitialize>(Ctx) {} |
638 | |
639 | void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT, |
640 | const FieldDecl *FD, CharUnits CurStructOffset, |
641 | std::array<Address, 1> Addrs) { |
642 | if (const auto *AT = getContext().getAsArrayType(T: FT)) { |
643 | visitArray(FK: PDIK, AT, IsVolatile: FT.isVolatileQualified(), FD, CurStructOffset, |
644 | Addrs); |
645 | return; |
646 | } |
647 | |
648 | Super::visitWithKind(PDIK, FT, Args&: FD, Args&: CurStructOffset, Args&: Addrs); |
649 | } |
650 | |
651 | void visitARCStrong(QualType QT, const FieldDecl *FD, |
652 | CharUnits CurStructOffset, std::array<Address, 1> Addrs) { |
653 | CGF->EmitNullInitialization( |
654 | DestPtr: getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD), Ty: QT); |
655 | } |
656 | |
657 | void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, |
658 | std::array<Address, 1> Addrs) { |
659 | CGF->EmitNullInitialization( |
660 | DestPtr: getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD), Ty: QT); |
661 | } |
662 | |
663 | template <class FieldKind, size_t... Is> |
664 | void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile, |
665 | const FieldDecl *FD, CharUnits CurStructOffset, |
666 | std::array<Address, 1> Addrs) { |
667 | if (!FK) |
668 | return visitTrivial(Args: QualType(AT, 0), Args: FD, Args: CurStructOffset, Args: Addrs); |
669 | |
670 | ASTContext &Ctx = getContext(); |
671 | CharUnits Size = Ctx.getTypeSizeInChars(T: QualType(AT, 0)); |
672 | QualType EltTy = Ctx.getBaseElementType(QT: QualType(AT, 0)); |
673 | |
674 | if (Size < CharUnits::fromQuantity(Quantity: 16) || EltTy->getAs<RecordType>()) { |
675 | GenFuncBaseTy::visitArray(FK, AT, IsVolatile, FD, CurStructOffset, Addrs); |
676 | return; |
677 | } |
678 | |
679 | llvm::Constant *SizeVal = CGF->Builder.getInt64(C: Size.getQuantity()); |
680 | Address DstAddr = getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD); |
681 | Address Loc = DstAddr.withElementType(ElemTy: CGF->Int8Ty); |
682 | CGF->Builder.CreateMemSet(Dest: Loc, Value: CGF->Builder.getInt8(C: 0), Size: SizeVal, |
683 | IsVolatile); |
684 | } |
685 | |
686 | void callSpecialFunction(QualType FT, CharUnits Offset, |
687 | std::array<Address, 1> Addrs) { |
688 | CGF->callCStructDefaultConstructor( |
689 | Dst: CGF->MakeAddrLValue(Addr: getAddrWithOffset(Addr: Addrs[DstIdx], Offset), T: FT)); |
690 | } |
691 | }; |
692 | |
693 | struct GenCopyConstructor : GenBinaryFunc<GenCopyConstructor, false> { |
694 | GenCopyConstructor(ASTContext &Ctx) |
695 | : GenBinaryFunc<GenCopyConstructor, false>(Ctx) {} |
696 | |
697 | void visitARCStrong(QualType QT, const FieldDecl *FD, |
698 | CharUnits CurStructOffset, std::array<Address, 2> Addrs) { |
699 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD); |
700 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], StructFieldOffset: CurStructOffset, FD); |
701 | llvm::Value *SrcVal = CGF->EmitLoadOfScalar( |
702 | Addr: Addrs[SrcIdx], Volatile: QT.isVolatileQualified(), Ty: QT, Loc: SourceLocation()); |
703 | llvm::Value *Val = CGF->EmitARCRetain(type: QT, value: SrcVal); |
704 | CGF->EmitStoreOfScalar(value: Val, lvalue: CGF->MakeAddrLValue(Addr: Addrs[DstIdx], T: QT), isInit: true); |
705 | } |
706 | |
707 | void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, |
708 | std::array<Address, 2> Addrs) { |
709 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD); |
710 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], StructFieldOffset: CurStructOffset, FD); |
711 | CGF->EmitARCCopyWeak(dst: Addrs[DstIdx], src: Addrs[SrcIdx]); |
712 | } |
713 | |
714 | void callSpecialFunction(QualType FT, CharUnits Offset, |
715 | std::array<Address, 2> Addrs) { |
716 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], Offset); |
717 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], Offset); |
718 | CGF->callCStructCopyConstructor(Dst: CGF->MakeAddrLValue(Addr: Addrs[DstIdx], T: FT), |
719 | Src: CGF->MakeAddrLValue(Addr: Addrs[SrcIdx], T: FT)); |
720 | } |
721 | }; |
722 | |
723 | struct GenMoveConstructor : GenBinaryFunc<GenMoveConstructor, true> { |
724 | GenMoveConstructor(ASTContext &Ctx) |
725 | : GenBinaryFunc<GenMoveConstructor, true>(Ctx) {} |
726 | |
727 | void visitARCStrong(QualType QT, const FieldDecl *FD, |
728 | CharUnits CurStructOffset, std::array<Address, 2> Addrs) { |
729 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD); |
730 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], StructFieldOffset: CurStructOffset, FD); |
731 | LValue SrcLV = CGF->MakeAddrLValue(Addr: Addrs[SrcIdx], T: QT); |
732 | llvm::Value *SrcVal = |
733 | CGF->EmitLoadOfLValue(V: SrcLV, Loc: SourceLocation()).getScalarVal(); |
734 | CGF->EmitStoreOfScalar(value: getNullForVariable(Addr: SrcLV.getAddress()), lvalue: SrcLV); |
735 | CGF->EmitStoreOfScalar(value: SrcVal, lvalue: CGF->MakeAddrLValue(Addr: Addrs[DstIdx], T: QT), |
736 | /* isInitialization */ isInit: true); |
737 | } |
738 | |
739 | void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, |
740 | std::array<Address, 2> Addrs) { |
741 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD); |
742 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], StructFieldOffset: CurStructOffset, FD); |
743 | CGF->EmitARCMoveWeak(dst: Addrs[DstIdx], src: Addrs[SrcIdx]); |
744 | } |
745 | |
746 | void callSpecialFunction(QualType FT, CharUnits Offset, |
747 | std::array<Address, 2> Addrs) { |
748 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], Offset); |
749 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], Offset); |
750 | CGF->callCStructMoveConstructor(Dst: CGF->MakeAddrLValue(Addr: Addrs[DstIdx], T: FT), |
751 | Src: CGF->MakeAddrLValue(Addr: Addrs[SrcIdx], T: FT)); |
752 | } |
753 | }; |
754 | |
755 | struct GenCopyAssignment : GenBinaryFunc<GenCopyAssignment, false> { |
756 | GenCopyAssignment(ASTContext &Ctx) |
757 | : GenBinaryFunc<GenCopyAssignment, false>(Ctx) {} |
758 | |
759 | void visitARCStrong(QualType QT, const FieldDecl *FD, |
760 | CharUnits CurStructOffset, std::array<Address, 2> Addrs) { |
761 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD); |
762 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], StructFieldOffset: CurStructOffset, FD); |
763 | llvm::Value *SrcVal = CGF->EmitLoadOfScalar( |
764 | Addr: Addrs[SrcIdx], Volatile: QT.isVolatileQualified(), Ty: QT, Loc: SourceLocation()); |
765 | CGF->EmitARCStoreStrong(lvalue: CGF->MakeAddrLValue(Addr: Addrs[DstIdx], T: QT), value: SrcVal, |
766 | resultIgnored: false); |
767 | } |
768 | |
769 | void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, |
770 | std::array<Address, 2> Addrs) { |
771 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD); |
772 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], StructFieldOffset: CurStructOffset, FD); |
773 | CGF->emitARCCopyAssignWeak(Ty: QT, DstAddr: Addrs[DstIdx], SrcAddr: Addrs[SrcIdx]); |
774 | } |
775 | |
776 | void callSpecialFunction(QualType FT, CharUnits Offset, |
777 | std::array<Address, 2> Addrs) { |
778 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], Offset); |
779 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], Offset); |
780 | CGF->callCStructCopyAssignmentOperator( |
781 | Dst: CGF->MakeAddrLValue(Addr: Addrs[DstIdx], T: FT), |
782 | Src: CGF->MakeAddrLValue(Addr: Addrs[SrcIdx], T: FT)); |
783 | } |
784 | }; |
785 | |
786 | struct GenMoveAssignment : GenBinaryFunc<GenMoveAssignment, true> { |
787 | GenMoveAssignment(ASTContext &Ctx) |
788 | : GenBinaryFunc<GenMoveAssignment, true>(Ctx) {} |
789 | |
790 | void visitARCStrong(QualType QT, const FieldDecl *FD, |
791 | CharUnits CurStructOffset, std::array<Address, 2> Addrs) { |
792 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD); |
793 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], StructFieldOffset: CurStructOffset, FD); |
794 | LValue SrcLV = CGF->MakeAddrLValue(Addr: Addrs[SrcIdx], T: QT); |
795 | llvm::Value *SrcVal = |
796 | CGF->EmitLoadOfLValue(V: SrcLV, Loc: SourceLocation()).getScalarVal(); |
797 | CGF->EmitStoreOfScalar(value: getNullForVariable(Addr: SrcLV.getAddress()), lvalue: SrcLV); |
798 | LValue DstLV = CGF->MakeAddrLValue(Addr: Addrs[DstIdx], T: QT); |
799 | llvm::Value *DstVal = |
800 | CGF->EmitLoadOfLValue(V: DstLV, Loc: SourceLocation()).getScalarVal(); |
801 | CGF->EmitStoreOfScalar(value: SrcVal, lvalue: DstLV); |
802 | CGF->EmitARCRelease(value: DstVal, precise: ARCImpreciseLifetime); |
803 | } |
804 | |
805 | void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, |
806 | std::array<Address, 2> Addrs) { |
807 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], StructFieldOffset: CurStructOffset, FD); |
808 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], StructFieldOffset: CurStructOffset, FD); |
809 | CGF->emitARCMoveAssignWeak(Ty: QT, DstAddr: Addrs[DstIdx], SrcAddr: Addrs[SrcIdx]); |
810 | } |
811 | |
812 | void callSpecialFunction(QualType FT, CharUnits Offset, |
813 | std::array<Address, 2> Addrs) { |
814 | Addrs[DstIdx] = getAddrWithOffset(Addr: Addrs[DstIdx], Offset); |
815 | Addrs[SrcIdx] = getAddrWithOffset(Addr: Addrs[SrcIdx], Offset); |
816 | CGF->callCStructMoveAssignmentOperator( |
817 | Dst: CGF->MakeAddrLValue(Addr: Addrs[DstIdx], T: FT), |
818 | Src: CGF->MakeAddrLValue(Addr: Addrs[SrcIdx], T: FT)); |
819 | } |
820 | }; |
821 | |
822 | } // namespace |
823 | |
824 | void CodeGenFunction::destroyNonTrivialCStruct(CodeGenFunction &CGF, |
825 | Address Addr, QualType Type) { |
826 | CGF.callCStructDestructor(Dst: CGF.MakeAddrLValue(Addr, T: Type)); |
827 | } |
828 | |
829 | // Default-initialize a variable that is a non-trivial struct or an array of |
830 | // such structure. |
831 | void CodeGenFunction::defaultInitNonTrivialCStructVar(LValue Dst) { |
832 | GenDefaultInitialize Gen(getContext()); |
833 | Address DstPtr = Dst.getAddress().withElementType(ElemTy: CGM.Int8PtrTy); |
834 | Gen.setCGF(this); |
835 | QualType QT = Dst.getType(); |
836 | QT = Dst.isVolatile() ? QT.withVolatile() : QT; |
837 | Gen.visit(FT: QT, Args: nullptr, Args: CharUnits::Zero(), Args: std::array<Address, 1>({._M_elems: {DstPtr}})); |
838 | } |
839 | |
840 | template <class G, size_t N> |
841 | static void callSpecialFunction(G &&Gen, StringRef FuncName, QualType QT, |
842 | bool IsVolatile, CodeGenFunction &CGF, |
843 | std::array<Address, N> Addrs) { |
844 | auto SetArtificialLoc = ApplyDebugLocation::CreateArtificial(CGF); |
845 | for (unsigned I = 0; I < N; ++I) |
846 | Addrs[I] = Addrs[I].withElementType(CGF.CGM.Int8PtrTy); |
847 | QT = IsVolatile ? QT.withVolatile() : QT; |
848 | Gen.callFunc(FuncName, QT, Addrs, CGF); |
849 | } |
850 | |
851 | template <class G, size_t N> |
852 | static llvm::Function * |
853 | getSpecialFunction(G &&Gen, StringRef FuncName, QualType QT, bool IsVolatile, |
854 | std::array<CharUnits, N> Alignments, CodeGenModule &CGM) { |
855 | QT = IsVolatile ? QT.withVolatile() : QT; |
856 | // The following call requires an array of addresses as arguments, but doesn't |
857 | // actually use them (it overwrites them with the addresses of the arguments |
858 | // of the created function). |
859 | return Gen.getFunction(FuncName, QT, Alignments, CGM); |
860 | } |
861 | |
862 | // Functions to emit calls to the special functions of a non-trivial C struct. |
863 | void CodeGenFunction::callCStructDefaultConstructor(LValue Dst) { |
864 | bool IsVolatile = Dst.isVolatile(); |
865 | Address DstPtr = Dst.getAddress(); |
866 | QualType QT = Dst.getType(); |
867 | GenDefaultInitializeFuncName GenName(DstPtr.getAlignment(), getContext()); |
868 | std::string FuncName = GenName.getName(QT, IsVolatile); |
869 | callSpecialFunction(Gen: GenDefaultInitialize(getContext()), FuncName, QT, |
870 | IsVolatile, CGF&: *this, Addrs: std::array<Address, 1>({._M_elems: {DstPtr}})); |
871 | } |
872 | |
873 | std::string CodeGenFunction::getNonTrivialCopyConstructorStr( |
874 | QualType QT, CharUnits Alignment, bool IsVolatile, ASTContext &Ctx) { |
875 | GenBinaryFuncName<false> GenName("" , Alignment, Alignment, Ctx); |
876 | return GenName.getName(QT, IsVolatile); |
877 | } |
878 | |
879 | std::string CodeGenFunction::getNonTrivialDestructorStr(QualType QT, |
880 | CharUnits Alignment, |
881 | bool IsVolatile, |
882 | ASTContext &Ctx) { |
883 | GenDestructorFuncName GenName("" , Alignment, Ctx); |
884 | return GenName.getName(QT, IsVolatile); |
885 | } |
886 | |
887 | void CodeGenFunction::callCStructDestructor(LValue Dst) { |
888 | bool IsVolatile = Dst.isVolatile(); |
889 | Address DstPtr = Dst.getAddress(); |
890 | QualType QT = Dst.getType(); |
891 | GenDestructorFuncName GenName("__destructor_" , DstPtr.getAlignment(), |
892 | getContext()); |
893 | std::string FuncName = GenName.getName(QT, IsVolatile); |
894 | callSpecialFunction(Gen: GenDestructor(getContext()), FuncName, QT, IsVolatile, |
895 | CGF&: *this, Addrs: std::array<Address, 1>({._M_elems: {DstPtr}})); |
896 | } |
897 | |
898 | void CodeGenFunction::callCStructCopyConstructor(LValue Dst, LValue Src) { |
899 | bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); |
900 | Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); |
901 | QualType QT = Dst.getType(); |
902 | GenBinaryFuncName<false> GenName("__copy_constructor_" , DstPtr.getAlignment(), |
903 | SrcPtr.getAlignment(), getContext()); |
904 | std::string FuncName = GenName.getName(QT, IsVolatile); |
905 | callSpecialFunction(Gen: GenCopyConstructor(getContext()), FuncName, QT, |
906 | IsVolatile, CGF&: *this, |
907 | Addrs: std::array<Address, 2>({._M_elems: {DstPtr, SrcPtr}})); |
908 | } |
909 | |
910 | void CodeGenFunction::callCStructCopyAssignmentOperator(LValue Dst, LValue Src |
911 | |
912 | ) { |
913 | bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); |
914 | Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); |
915 | QualType QT = Dst.getType(); |
916 | GenBinaryFuncName<false> GenName("__copy_assignment_" , DstPtr.getAlignment(), |
917 | SrcPtr.getAlignment(), getContext()); |
918 | std::string FuncName = GenName.getName(QT, IsVolatile); |
919 | callSpecialFunction(Gen: GenCopyAssignment(getContext()), FuncName, QT, IsVolatile, |
920 | CGF&: *this, Addrs: std::array<Address, 2>({._M_elems: {DstPtr, SrcPtr}})); |
921 | } |
922 | |
923 | void CodeGenFunction::callCStructMoveConstructor(LValue Dst, LValue Src) { |
924 | bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); |
925 | Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); |
926 | QualType QT = Dst.getType(); |
927 | GenBinaryFuncName<true> GenName("__move_constructor_" , DstPtr.getAlignment(), |
928 | SrcPtr.getAlignment(), getContext()); |
929 | std::string FuncName = GenName.getName(QT, IsVolatile); |
930 | callSpecialFunction(Gen: GenMoveConstructor(getContext()), FuncName, QT, |
931 | IsVolatile, CGF&: *this, |
932 | Addrs: std::array<Address, 2>({._M_elems: {DstPtr, SrcPtr}})); |
933 | } |
934 | |
935 | void CodeGenFunction::callCStructMoveAssignmentOperator(LValue Dst, LValue Src |
936 | |
937 | ) { |
938 | bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); |
939 | Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); |
940 | QualType QT = Dst.getType(); |
941 | GenBinaryFuncName<true> GenName("__move_assignment_" , DstPtr.getAlignment(), |
942 | SrcPtr.getAlignment(), getContext()); |
943 | std::string FuncName = GenName.getName(QT, IsVolatile); |
944 | callSpecialFunction(Gen: GenMoveAssignment(getContext()), FuncName, QT, IsVolatile, |
945 | CGF&: *this, Addrs: std::array<Address, 2>({._M_elems: {DstPtr, SrcPtr}})); |
946 | } |
947 | |
948 | llvm::Function *clang::CodeGen::getNonTrivialCStructDefaultConstructor( |
949 | CodeGenModule &CGM, CharUnits DstAlignment, bool IsVolatile, QualType QT) { |
950 | ASTContext &Ctx = CGM.getContext(); |
951 | GenDefaultInitializeFuncName GenName(DstAlignment, Ctx); |
952 | std::string FuncName = GenName.getName(QT, IsVolatile); |
953 | return getSpecialFunction(Gen: GenDefaultInitialize(Ctx), FuncName, QT, IsVolatile, |
954 | Alignments: std::array<CharUnits, 1>({._M_elems: {DstAlignment}}), CGM); |
955 | } |
956 | |
957 | llvm::Function *clang::CodeGen::getNonTrivialCStructCopyConstructor( |
958 | CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment, |
959 | bool IsVolatile, QualType QT) { |
960 | ASTContext &Ctx = CGM.getContext(); |
961 | GenBinaryFuncName<false> GenName("__copy_constructor_" , DstAlignment, |
962 | SrcAlignment, Ctx); |
963 | std::string FuncName = GenName.getName(QT, IsVolatile); |
964 | return getSpecialFunction( |
965 | Gen: GenCopyConstructor(Ctx), FuncName, QT, IsVolatile, |
966 | Alignments: std::array<CharUnits, 2>({._M_elems: {DstAlignment, SrcAlignment}}), CGM); |
967 | } |
968 | |
969 | llvm::Function *clang::CodeGen::getNonTrivialCStructMoveConstructor( |
970 | CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment, |
971 | bool IsVolatile, QualType QT) { |
972 | ASTContext &Ctx = CGM.getContext(); |
973 | GenBinaryFuncName<true> GenName("__move_constructor_" , DstAlignment, |
974 | SrcAlignment, Ctx); |
975 | std::string FuncName = GenName.getName(QT, IsVolatile); |
976 | return getSpecialFunction( |
977 | Gen: GenMoveConstructor(Ctx), FuncName, QT, IsVolatile, |
978 | Alignments: std::array<CharUnits, 2>({._M_elems: {DstAlignment, SrcAlignment}}), CGM); |
979 | } |
980 | |
981 | llvm::Function *clang::CodeGen::getNonTrivialCStructCopyAssignmentOperator( |
982 | CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment, |
983 | bool IsVolatile, QualType QT) { |
984 | ASTContext &Ctx = CGM.getContext(); |
985 | GenBinaryFuncName<false> GenName("__copy_assignment_" , DstAlignment, |
986 | SrcAlignment, Ctx); |
987 | std::string FuncName = GenName.getName(QT, IsVolatile); |
988 | return getSpecialFunction( |
989 | Gen: GenCopyAssignment(Ctx), FuncName, QT, IsVolatile, |
990 | Alignments: std::array<CharUnits, 2>({._M_elems: {DstAlignment, SrcAlignment}}), CGM); |
991 | } |
992 | |
993 | llvm::Function *clang::CodeGen::getNonTrivialCStructMoveAssignmentOperator( |
994 | CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment, |
995 | bool IsVolatile, QualType QT) { |
996 | ASTContext &Ctx = CGM.getContext(); |
997 | GenBinaryFuncName<true> GenName("__move_assignment_" , DstAlignment, |
998 | SrcAlignment, Ctx); |
999 | std::string FuncName = GenName.getName(QT, IsVolatile); |
1000 | return getSpecialFunction( |
1001 | Gen: GenMoveAssignment(Ctx), FuncName, QT, IsVolatile, |
1002 | Alignments: std::array<CharUnits, 2>({._M_elems: {DstAlignment, SrcAlignment}}), CGM); |
1003 | } |
1004 | |
1005 | llvm::Function *clang::CodeGen::getNonTrivialCStructDestructor( |
1006 | CodeGenModule &CGM, CharUnits DstAlignment, bool IsVolatile, QualType QT) { |
1007 | ASTContext &Ctx = CGM.getContext(); |
1008 | GenDestructorFuncName GenName("__destructor_" , DstAlignment, Ctx); |
1009 | std::string FuncName = GenName.getName(QT, IsVolatile); |
1010 | return getSpecialFunction(Gen: GenDestructor(Ctx), FuncName, QT, IsVolatile, |
1011 | Alignments: std::array<CharUnits, 1>({._M_elems: {DstAlignment}}), CGM); |
1012 | } |
1013 | |