brintos

brintos / llvm-project-archived public Read only

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