Clang Project

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