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