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