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