Path: blob/main/contrib/llvm-project/clang/lib/CodeGen/CGNonTrivialStruct.cpp
35233 views
//===--- CGNonTrivialStruct.cpp - Emit Special Functions for C Structs ----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines functions to generate various special functions for C9// structs.10//11//===----------------------------------------------------------------------===//1213#include "CodeGenFunction.h"14#include "CodeGenModule.h"15#include "clang/AST/NonTrivialTypeVisitor.h"16#include "clang/CodeGen/CodeGenABITypes.h"17#include "llvm/Support/ScopedPrinter.h"18#include <array>1920using namespace clang;21using namespace CodeGen;2223// Return the size of a field in number of bits.24static uint64_t getFieldSize(const FieldDecl *FD, QualType FT,25ASTContext &Ctx) {26if (FD && FD->isBitField())27return FD->getBitWidthValue(Ctx);28return Ctx.getTypeSize(FT);29}3031namespace {32enum { DstIdx = 0, SrcIdx = 1 };33const char *ValNameStr[2] = {"dst", "src"};3435template <class Derived> struct StructVisitor {36StructVisitor(ASTContext &Ctx) : Ctx(Ctx) {}3738template <class... Ts>39void visitStructFields(QualType QT, CharUnits CurStructOffset, Ts... Args) {40const RecordDecl *RD = QT->castAs<RecordType>()->getDecl();4142// Iterate over the fields of the struct.43for (const FieldDecl *FD : RD->fields()) {44QualType FT = FD->getType();45FT = QT.isVolatileQualified() ? FT.withVolatile() : FT;46asDerived().visit(FT, FD, CurStructOffset, Args...);47}4849asDerived().flushTrivialFields(Args...);50}5152template <class... Ts> void visitTrivial(Ts... Args) {}5354template <class... Ts> void visitCXXDestructor(Ts... Args) {55llvm_unreachable("field of a C++ struct type is not expected");56}5758template <class... Ts> void flushTrivialFields(Ts... Args) {}5960uint64_t getFieldOffsetInBits(const FieldDecl *FD) {61return FD ? Ctx.getASTRecordLayout(FD->getParent())62.getFieldOffset(FD->getFieldIndex())63: 0;64}6566CharUnits getFieldOffset(const FieldDecl *FD) {67return Ctx.toCharUnitsFromBits(getFieldOffsetInBits(FD));68}6970Derived &asDerived() { return static_cast<Derived &>(*this); }7172ASTContext &getContext() { return Ctx; }73ASTContext &Ctx;74};7576template <class Derived, bool IsMove>77struct CopyStructVisitor : StructVisitor<Derived>,78CopiedTypeVisitor<Derived, IsMove> {79using StructVisitor<Derived>::asDerived;80using Super = CopiedTypeVisitor<Derived, IsMove>;8182CopyStructVisitor(ASTContext &Ctx) : StructVisitor<Derived>(Ctx) {}8384template <class... Ts>85void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT,86const FieldDecl *FD, CharUnits CurStructOffset, Ts &&... Args) {87if (PCK)88asDerived().flushTrivialFields(std::forward<Ts>(Args)...);89}9091template <class... Ts>92void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT,93const FieldDecl *FD, CharUnits CurStructOffset,94Ts &&... Args) {95if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) {96asDerived().visitArray(PCK, AT, FT.isVolatileQualified(), FD,97CurStructOffset, std::forward<Ts>(Args)...);98return;99}100101Super::visitWithKind(PCK, FT, FD, CurStructOffset,102std::forward<Ts>(Args)...);103}104105template <class... Ts>106void visitTrivial(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset,107Ts... Args) {108assert(!FT.isVolatileQualified() && "volatile field not expected");109ASTContext &Ctx = asDerived().getContext();110uint64_t FieldSize = getFieldSize(FD, FT, Ctx);111112// Ignore zero-sized fields.113if (FieldSize == 0)114return;115116uint64_t FStartInBits = asDerived().getFieldOffsetInBits(FD);117uint64_t FEndInBits = FStartInBits + FieldSize;118uint64_t RoundedFEnd = llvm::alignTo(FEndInBits, Ctx.getCharWidth());119120// Set Start if this is the first field of a sequence of trivial fields.121if (Start == End)122Start = CurStructOffset + Ctx.toCharUnitsFromBits(FStartInBits);123End = CurStructOffset + Ctx.toCharUnitsFromBits(RoundedFEnd);124}125126CharUnits Start = CharUnits::Zero(), End = CharUnits::Zero();127};128129// This function creates the mangled name of a special function of a non-trivial130// C struct. Since there is no ODR in C, the function is mangled based on the131// struct contents and not the name. The mangled name has the following132// 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>148149template <class Derived> struct GenFuncNameBase {150std::string getVolatileOffsetStr(bool IsVolatile, CharUnits Offset) {151std::string S;152if (IsVolatile)153S = "v";154S += llvm::to_string(Offset.getQuantity());155return S;156}157158void visitARCStrong(QualType FT, const FieldDecl *FD,159CharUnits CurStructOffset) {160appendStr("_s");161if (FT->isBlockPointerType())162appendStr("b");163CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);164appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset));165}166167void visitARCWeak(QualType FT, const FieldDecl *FD,168CharUnits CurStructOffset) {169appendStr("_w");170CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);171appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset));172}173174void visitStruct(QualType QT, const FieldDecl *FD,175CharUnits CurStructOffset) {176CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);177appendStr("_S");178asDerived().visitStructFields(QT, FieldOffset);179}180181template <class FieldKind>182void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile,183const FieldDecl *FD, CharUnits CurStructOffset) {184// String for non-volatile trivial fields is emitted when185// flushTrivialFields is called.186if (!FK)187return asDerived().visitTrivial(QualType(AT, 0), FD, CurStructOffset);188189asDerived().flushTrivialFields();190CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);191ASTContext &Ctx = asDerived().getContext();192const ConstantArrayType *CAT = cast<ConstantArrayType>(AT);193unsigned NumElts = Ctx.getConstantArrayElementCount(CAT);194QualType EltTy = Ctx.getBaseElementType(CAT);195CharUnits EltSize = Ctx.getTypeSizeInChars(EltTy);196appendStr("_AB" + llvm::to_string(FieldOffset.getQuantity()) + "s" +197llvm::to_string(EltSize.getQuantity()) + "n" +198llvm::to_string(NumElts));199EltTy = IsVolatile ? EltTy.withVolatile() : EltTy;200asDerived().visitWithKind(FK, EltTy, nullptr, FieldOffset);201appendStr("_AE");202}203204void appendStr(StringRef Str) { Name += Str; }205206std::string getName(QualType QT, bool IsVolatile) {207QT = IsVolatile ? QT.withVolatile() : QT;208asDerived().visitStructFields(QT, CharUnits::Zero());209return Name;210}211212Derived &asDerived() { return static_cast<Derived &>(*this); }213214std::string Name;215};216217template <class Derived>218struct GenUnaryFuncName : StructVisitor<Derived>, GenFuncNameBase<Derived> {219GenUnaryFuncName(StringRef Prefix, CharUnits DstAlignment, ASTContext &Ctx)220: StructVisitor<Derived>(Ctx) {221this->appendStr(Prefix);222this->appendStr(llvm::to_string(DstAlignment.getQuantity()));223}224};225226// Helper function to create a null constant.227static llvm::Constant *getNullForVariable(Address Addr) {228llvm::Type *Ty = Addr.getElementType();229return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(Ty));230}231232template <bool IsMove>233struct GenBinaryFuncName : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>,234GenFuncNameBase<GenBinaryFuncName<IsMove>> {235236GenBinaryFuncName(StringRef Prefix, CharUnits DstAlignment,237CharUnits SrcAlignment, ASTContext &Ctx)238: CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>(Ctx) {239this->appendStr(Prefix);240this->appendStr(llvm::to_string(DstAlignment.getQuantity()));241this->appendStr("_" + llvm::to_string(SrcAlignment.getQuantity()));242}243244void flushTrivialFields() {245if (this->Start == this->End)246return;247248this->appendStr("_t" + llvm::to_string(this->Start.getQuantity()) + "w" +249llvm::to_string((this->End - this->Start).getQuantity()));250251this->Start = this->End = CharUnits::Zero();252}253254void visitVolatileTrivial(QualType FT, const FieldDecl *FD,255CharUnits CurStructOffset) {256// Zero-length bit-fields don't need to be copied/assigned.257if (FD && FD->isZeroLengthBitField(this->Ctx))258return;259260// Because volatile fields can be bit-fields and are individually copied,261// their offset and width are in bits.262uint64_t OffsetInBits =263this->Ctx.toBits(CurStructOffset) + this->getFieldOffsetInBits(FD);264this->appendStr("_tv" + llvm::to_string(OffsetInBits) + "w" +265llvm::to_string(getFieldSize(FD, FT, this->Ctx)));266}267};268269struct GenDefaultInitializeFuncName270: GenUnaryFuncName<GenDefaultInitializeFuncName>,271DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName> {272using Super = DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName>;273GenDefaultInitializeFuncName(CharUnits DstAlignment, ASTContext &Ctx)274: GenUnaryFuncName<GenDefaultInitializeFuncName>("__default_constructor_",275DstAlignment, Ctx) {}276void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT,277const FieldDecl *FD, CharUnits CurStructOffset) {278if (const auto *AT = getContext().getAsArrayType(FT)) {279visitArray(PDIK, AT, FT.isVolatileQualified(), FD, CurStructOffset);280return;281}282283Super::visitWithKind(PDIK, FT, FD, CurStructOffset);284}285};286287struct GenDestructorFuncName : GenUnaryFuncName<GenDestructorFuncName>,288DestructedTypeVisitor<GenDestructorFuncName> {289using Super = DestructedTypeVisitor<GenDestructorFuncName>;290GenDestructorFuncName(const char *Prefix, CharUnits DstAlignment,291ASTContext &Ctx)292: GenUnaryFuncName<GenDestructorFuncName>(Prefix, DstAlignment, Ctx) {}293void visitWithKind(QualType::DestructionKind DK, QualType FT,294const FieldDecl *FD, CharUnits CurStructOffset) {295if (const auto *AT = getContext().getAsArrayType(FT)) {296visitArray(DK, AT, FT.isVolatileQualified(), FD, CurStructOffset);297return;298}299300Super::visitWithKind(DK, FT, FD, CurStructOffset);301}302};303304// Helper function that creates CGFunctionInfo for an N-ary special function.305template <size_t N>306static const CGFunctionInfo &getFunctionInfo(CodeGenModule &CGM,307FunctionArgList &Args) {308ASTContext &Ctx = CGM.getContext();309llvm::SmallVector<ImplicitParamDecl *, N> Params;310QualType ParamTy = Ctx.getPointerType(Ctx.VoidPtrTy);311312for (unsigned I = 0; I < N; ++I)313Params.push_back(ImplicitParamDecl::Create(314Ctx, nullptr, SourceLocation(), &Ctx.Idents.get(ValNameStr[I]), ParamTy,315ImplicitParamKind::Other));316317llvm::append_range(Args, Params);318319return CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);320}321322template <size_t N, size_t... Ints>323static std::array<Address, N> getParamAddrs(std::index_sequence<Ints...> IntSeq,324std::array<CharUnits, N> Alignments,325const FunctionArgList &Args,326CodeGenFunction *CGF) {327return std::array<Address, N>{328{Address(CGF->Builder.CreateLoad(CGF->GetAddrOfLocalVar(Args[Ints])),329CGF->VoidPtrTy, Alignments[Ints], KnownNonNull)...}};330}331332// Template classes that are used as bases for classes that emit special333// functions.334template <class Derived> struct GenFuncBase {335template <size_t N>336void visitStruct(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset,337std::array<Address, N> Addrs) {338this->asDerived().callSpecialFunction(339FT, CurStructOffset + asDerived().getFieldOffset(FD), Addrs);340}341342template <class FieldKind, size_t N>343void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile,344const FieldDecl *FD, CharUnits CurStructOffset,345std::array<Address, N> Addrs) {346// Non-volatile trivial fields are copied when flushTrivialFields is called.347if (!FK)348return asDerived().visitTrivial(QualType(AT, 0), FD, CurStructOffset,349Addrs);350351asDerived().flushTrivialFields(Addrs);352CodeGenFunction &CGF = *this->CGF;353ASTContext &Ctx = CGF.getContext();354355// Compute the end address.356QualType BaseEltQT;357std::array<Address, N> StartAddrs = Addrs;358for (unsigned I = 0; I < N; ++I)359StartAddrs[I] = getAddrWithOffset(Addrs[I], CurStructOffset, FD);360Address DstAddr = StartAddrs[DstIdx];361llvm::Value *NumElts = CGF.emitArrayLength(AT, BaseEltQT, DstAddr);362unsigned BaseEltSize = Ctx.getTypeSizeInChars(BaseEltQT).getQuantity();363llvm::Value *BaseEltSizeVal =364llvm::ConstantInt::get(NumElts->getType(), BaseEltSize);365llvm::Value *SizeInBytes =366CGF.Builder.CreateNUWMul(BaseEltSizeVal, NumElts);367llvm::Value *DstArrayEnd = CGF.Builder.CreateInBoundsGEP(368CGF.Int8Ty, DstAddr.emitRawPointer(CGF), SizeInBytes);369llvm::BasicBlock *PreheaderBB = CGF.Builder.GetInsertBlock();370371// Create the header block and insert the phi instructions.372llvm::BasicBlock *HeaderBB = CGF.createBasicBlock("loop.header");373CGF.EmitBlock(HeaderBB);374llvm::PHINode *PHIs[N];375376for (unsigned I = 0; I < N; ++I) {377PHIs[I] = CGF.Builder.CreatePHI(CGF.CGM.Int8PtrPtrTy, 2, "addr.cur");378PHIs[I]->addIncoming(StartAddrs[I].emitRawPointer(CGF), PreheaderBB);379}380381// Create the exit and loop body blocks.382llvm::BasicBlock *ExitBB = CGF.createBasicBlock("loop.exit");383llvm::BasicBlock *LoopBB = CGF.createBasicBlock("loop.body");384385// Emit the comparison and conditional branch instruction that jumps to386// either the exit or the loop body.387llvm::Value *Done =388CGF.Builder.CreateICmpEQ(PHIs[DstIdx], DstArrayEnd, "done");389CGF.Builder.CreateCondBr(Done, ExitBB, LoopBB);390391// Visit the element of the array in the loop body.392CGF.EmitBlock(LoopBB);393QualType EltQT = AT->getElementType();394CharUnits EltSize = Ctx.getTypeSizeInChars(EltQT);395std::array<Address, N> NewAddrs = Addrs;396397for (unsigned I = 0; I < N; ++I)398NewAddrs[I] =399Address(PHIs[I], CGF.Int8PtrTy,400StartAddrs[I].getAlignment().alignmentAtOffset(EltSize));401402EltQT = IsVolatile ? EltQT.withVolatile() : EltQT;403this->asDerived().visitWithKind(FK, EltQT, nullptr, CharUnits::Zero(),404NewAddrs);405406LoopBB = CGF.Builder.GetInsertBlock();407408for (unsigned I = 0; I < N; ++I) {409// Instrs to update the destination and source addresses.410// Update phi instructions.411NewAddrs[I] = getAddrWithOffset(NewAddrs[I], EltSize);412PHIs[I]->addIncoming(NewAddrs[I].emitRawPointer(CGF), LoopBB);413}414415// Insert an unconditional branch to the header block.416CGF.Builder.CreateBr(HeaderBB);417CGF.EmitBlock(ExitBB);418}419420/// Return an address with the specified offset from the passed address.421Address getAddrWithOffset(Address Addr, CharUnits Offset) {422assert(Addr.isValid() && "invalid address");423if (Offset.getQuantity() == 0)424return Addr;425Addr = Addr.withElementType(CGF->CGM.Int8Ty);426Addr = CGF->Builder.CreateConstInBoundsGEP(Addr, Offset.getQuantity());427return Addr.withElementType(CGF->CGM.Int8PtrTy);428}429430Address getAddrWithOffset(Address Addr, CharUnits StructFieldOffset,431const FieldDecl *FD) {432return getAddrWithOffset(Addr, StructFieldOffset +433asDerived().getFieldOffset(FD));434}435436template <size_t N>437llvm::Function *getFunction(StringRef FuncName, QualType QT,438std::array<CharUnits, N> Alignments,439CodeGenModule &CGM) {440// If the special function already exists in the module, return it.441if (llvm::Function *F = CGM.getModule().getFunction(FuncName)) {442bool WrongType = false;443if (!F->getReturnType()->isVoidTy())444WrongType = true;445else {446for (const llvm::Argument &Arg : F->args())447if (Arg.getType() != CGM.Int8PtrPtrTy)448WrongType = true;449}450451if (WrongType) {452std::string FuncName = std::string(F->getName());453SourceLocation Loc = QT->castAs<RecordType>()->getDecl()->getLocation();454CGM.Error(Loc, "special function " + FuncName +455" for non-trivial C struct has incorrect type");456return nullptr;457}458return F;459}460461ASTContext &Ctx = CGM.getContext();462FunctionArgList Args;463const CGFunctionInfo &FI = getFunctionInfo<N>(CGM, Args);464llvm::FunctionType *FuncTy = CGM.getTypes().GetFunctionType(FI);465llvm::Function *F =466llvm::Function::Create(FuncTy, llvm::GlobalValue::LinkOnceODRLinkage,467FuncName, &CGM.getModule());468F->setVisibility(llvm::GlobalValue::HiddenVisibility);469CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, F, /*IsThunk=*/false);470CGM.SetLLVMFunctionAttributesForDefinition(nullptr, F);471CodeGenFunction NewCGF(CGM);472setCGF(&NewCGF);473CGF->StartFunction(GlobalDecl(), Ctx.VoidTy, F, FI, Args);474auto AL = ApplyDebugLocation::CreateArtificial(*CGF);475std::array<Address, N> Addrs =476getParamAddrs<N>(std::make_index_sequence<N>{}, Alignments, Args, CGF);477asDerived().visitStructFields(QT, CharUnits::Zero(), Addrs);478CGF->FinishFunction();479return F;480}481482template <size_t N>483void callFunc(StringRef FuncName, QualType QT, std::array<Address, N> Addrs,484CodeGenFunction &CallerCGF) {485std::array<CharUnits, N> Alignments;486llvm::Value *Ptrs[N];487488for (unsigned I = 0; I < N; ++I) {489Alignments[I] = Addrs[I].getAlignment();490Ptrs[I] = Addrs[I].emitRawPointer(CallerCGF);491}492493if (llvm::Function *F =494getFunction(FuncName, QT, Alignments, CallerCGF.CGM))495CallerCGF.EmitNounwindRuntimeCall(F, Ptrs);496}497498Derived &asDerived() { return static_cast<Derived &>(*this); }499500void setCGF(CodeGenFunction *F) { CGF = F; }501502CodeGenFunction *CGF = nullptr;503};504505template <class Derived, bool IsMove>506struct GenBinaryFunc : CopyStructVisitor<Derived, IsMove>,507GenFuncBase<Derived> {508GenBinaryFunc(ASTContext &Ctx) : CopyStructVisitor<Derived, IsMove>(Ctx) {}509510void flushTrivialFields(std::array<Address, 2> Addrs) {511CharUnits Size = this->End - this->Start;512513if (Size.getQuantity() == 0)514return;515516Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], this->Start);517Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], this->Start);518519// Emit memcpy.520if (Size.getQuantity() >= 16 ||521!llvm::has_single_bit<uint32_t>(Size.getQuantity())) {522llvm::Value *SizeVal =523llvm::ConstantInt::get(this->CGF->SizeTy, Size.getQuantity());524DstAddr = DstAddr.withElementType(this->CGF->Int8Ty);525SrcAddr = SrcAddr.withElementType(this->CGF->Int8Ty);526this->CGF->Builder.CreateMemCpy(DstAddr, SrcAddr, SizeVal, false);527} else {528llvm::Type *Ty = llvm::Type::getIntNTy(529this->CGF->getLLVMContext(),530Size.getQuantity() * this->CGF->getContext().getCharWidth());531DstAddr = DstAddr.withElementType(Ty);532SrcAddr = SrcAddr.withElementType(Ty);533llvm::Value *SrcVal = this->CGF->Builder.CreateLoad(SrcAddr, false);534this->CGF->Builder.CreateStore(SrcVal, DstAddr, false);535}536537this->Start = this->End = CharUnits::Zero();538}539540template <class... Ts>541void visitVolatileTrivial(QualType FT, const FieldDecl *FD, CharUnits Offset,542std::array<Address, 2> Addrs) {543LValue DstLV, SrcLV;544if (FD) {545// No need to copy zero-length bit-fields.546if (FD->isZeroLengthBitField(this->CGF->getContext()))547return;548549QualType RT = QualType(FD->getParent()->getTypeForDecl(), 0);550llvm::Type *Ty = this->CGF->ConvertType(RT);551Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], Offset);552LValue DstBase =553this->CGF->MakeAddrLValue(DstAddr.withElementType(Ty), FT);554DstLV = this->CGF->EmitLValueForField(DstBase, FD);555Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], Offset);556LValue SrcBase =557this->CGF->MakeAddrLValue(SrcAddr.withElementType(Ty), FT);558SrcLV = this->CGF->EmitLValueForField(SrcBase, FD);559} else {560llvm::Type *Ty = this->CGF->ConvertTypeForMem(FT);561Address DstAddr = Addrs[DstIdx].withElementType(Ty);562Address SrcAddr = Addrs[SrcIdx].withElementType(Ty);563DstLV = this->CGF->MakeAddrLValue(DstAddr, FT);564SrcLV = this->CGF->MakeAddrLValue(SrcAddr, FT);565}566RValue SrcVal = this->CGF->EmitLoadOfLValue(SrcLV, SourceLocation());567this->CGF->EmitStoreThroughLValue(SrcVal, DstLV);568}569};570571// These classes that emit the special functions for a non-trivial struct.572struct GenDestructor : StructVisitor<GenDestructor>,573GenFuncBase<GenDestructor>,574DestructedTypeVisitor<GenDestructor> {575using Super = DestructedTypeVisitor<GenDestructor>;576GenDestructor(ASTContext &Ctx) : StructVisitor<GenDestructor>(Ctx) {}577578void visitWithKind(QualType::DestructionKind DK, QualType FT,579const FieldDecl *FD, CharUnits CurStructOffset,580std::array<Address, 1> Addrs) {581if (const auto *AT = getContext().getAsArrayType(FT)) {582visitArray(DK, AT, FT.isVolatileQualified(), FD, CurStructOffset, Addrs);583return;584}585586Super::visitWithKind(DK, FT, FD, CurStructOffset, Addrs);587}588589void visitARCStrong(QualType QT, const FieldDecl *FD,590CharUnits CurStructOffset, std::array<Address, 1> Addrs) {591CGF->destroyARCStrongImprecise(592*CGF, getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT);593}594595void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,596std::array<Address, 1> Addrs) {597CGF->destroyARCWeak(598*CGF, getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT);599}600601void callSpecialFunction(QualType FT, CharUnits Offset,602std::array<Address, 1> Addrs) {603CGF->callCStructDestructor(604CGF->MakeAddrLValue(getAddrWithOffset(Addrs[DstIdx], Offset), FT));605}606};607608struct GenDefaultInitialize609: StructVisitor<GenDefaultInitialize>,610GenFuncBase<GenDefaultInitialize>,611DefaultInitializedTypeVisitor<GenDefaultInitialize> {612using Super = DefaultInitializedTypeVisitor<GenDefaultInitialize>;613typedef GenFuncBase<GenDefaultInitialize> GenFuncBaseTy;614615GenDefaultInitialize(ASTContext &Ctx)616: StructVisitor<GenDefaultInitialize>(Ctx) {}617618void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT,619const FieldDecl *FD, CharUnits CurStructOffset,620std::array<Address, 1> Addrs) {621if (const auto *AT = getContext().getAsArrayType(FT)) {622visitArray(PDIK, AT, FT.isVolatileQualified(), FD, CurStructOffset,623Addrs);624return;625}626627Super::visitWithKind(PDIK, FT, FD, CurStructOffset, Addrs);628}629630void visitARCStrong(QualType QT, const FieldDecl *FD,631CharUnits CurStructOffset, std::array<Address, 1> Addrs) {632CGF->EmitNullInitialization(633getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT);634}635636void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,637std::array<Address, 1> Addrs) {638CGF->EmitNullInitialization(639getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT);640}641642template <class FieldKind, size_t... Is>643void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile,644const FieldDecl *FD, CharUnits CurStructOffset,645std::array<Address, 1> Addrs) {646if (!FK)647return visitTrivial(QualType(AT, 0), FD, CurStructOffset, Addrs);648649ASTContext &Ctx = getContext();650CharUnits Size = Ctx.getTypeSizeInChars(QualType(AT, 0));651QualType EltTy = Ctx.getBaseElementType(QualType(AT, 0));652653if (Size < CharUnits::fromQuantity(16) || EltTy->getAs<RecordType>()) {654GenFuncBaseTy::visitArray(FK, AT, IsVolatile, FD, CurStructOffset, Addrs);655return;656}657658llvm::Constant *SizeVal = CGF->Builder.getInt64(Size.getQuantity());659Address DstAddr = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);660Address Loc = DstAddr.withElementType(CGF->Int8Ty);661CGF->Builder.CreateMemSet(Loc, CGF->Builder.getInt8(0), SizeVal,662IsVolatile);663}664665void callSpecialFunction(QualType FT, CharUnits Offset,666std::array<Address, 1> Addrs) {667CGF->callCStructDefaultConstructor(668CGF->MakeAddrLValue(getAddrWithOffset(Addrs[DstIdx], Offset), FT));669}670};671672struct GenCopyConstructor : GenBinaryFunc<GenCopyConstructor, false> {673GenCopyConstructor(ASTContext &Ctx)674: GenBinaryFunc<GenCopyConstructor, false>(Ctx) {}675676void visitARCStrong(QualType QT, const FieldDecl *FD,677CharUnits CurStructOffset, std::array<Address, 2> Addrs) {678Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);679Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);680llvm::Value *SrcVal = CGF->EmitLoadOfScalar(681Addrs[SrcIdx], QT.isVolatileQualified(), QT, SourceLocation());682llvm::Value *Val = CGF->EmitARCRetain(QT, SrcVal);683CGF->EmitStoreOfScalar(Val, CGF->MakeAddrLValue(Addrs[DstIdx], QT), true);684}685686void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,687std::array<Address, 2> Addrs) {688Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);689Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);690CGF->EmitARCCopyWeak(Addrs[DstIdx], Addrs[SrcIdx]);691}692693void callSpecialFunction(QualType FT, CharUnits Offset,694std::array<Address, 2> Addrs) {695Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset);696Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset);697CGF->callCStructCopyConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT),698CGF->MakeAddrLValue(Addrs[SrcIdx], FT));699}700};701702struct GenMoveConstructor : GenBinaryFunc<GenMoveConstructor, true> {703GenMoveConstructor(ASTContext &Ctx)704: GenBinaryFunc<GenMoveConstructor, true>(Ctx) {}705706void visitARCStrong(QualType QT, const FieldDecl *FD,707CharUnits CurStructOffset, std::array<Address, 2> Addrs) {708Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);709Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);710LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT);711llvm::Value *SrcVal =712CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();713CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);714CGF->EmitStoreOfScalar(SrcVal, CGF->MakeAddrLValue(Addrs[DstIdx], QT),715/* isInitialization */ true);716}717718void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,719std::array<Address, 2> Addrs) {720Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);721Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);722CGF->EmitARCMoveWeak(Addrs[DstIdx], Addrs[SrcIdx]);723}724725void callSpecialFunction(QualType FT, CharUnits Offset,726std::array<Address, 2> Addrs) {727Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset);728Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset);729CGF->callCStructMoveConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT),730CGF->MakeAddrLValue(Addrs[SrcIdx], FT));731}732};733734struct GenCopyAssignment : GenBinaryFunc<GenCopyAssignment, false> {735GenCopyAssignment(ASTContext &Ctx)736: GenBinaryFunc<GenCopyAssignment, false>(Ctx) {}737738void visitARCStrong(QualType QT, const FieldDecl *FD,739CharUnits CurStructOffset, std::array<Address, 2> Addrs) {740Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);741Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);742llvm::Value *SrcVal = CGF->EmitLoadOfScalar(743Addrs[SrcIdx], QT.isVolatileQualified(), QT, SourceLocation());744CGF->EmitARCStoreStrong(CGF->MakeAddrLValue(Addrs[DstIdx], QT), SrcVal,745false);746}747748void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,749std::array<Address, 2> Addrs) {750Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);751Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);752CGF->emitARCCopyAssignWeak(QT, Addrs[DstIdx], Addrs[SrcIdx]);753}754755void callSpecialFunction(QualType FT, CharUnits Offset,756std::array<Address, 2> Addrs) {757Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset);758Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset);759CGF->callCStructCopyAssignmentOperator(760CGF->MakeAddrLValue(Addrs[DstIdx], FT),761CGF->MakeAddrLValue(Addrs[SrcIdx], FT));762}763};764765struct GenMoveAssignment : GenBinaryFunc<GenMoveAssignment, true> {766GenMoveAssignment(ASTContext &Ctx)767: GenBinaryFunc<GenMoveAssignment, true>(Ctx) {}768769void visitARCStrong(QualType QT, const FieldDecl *FD,770CharUnits CurStructOffset, std::array<Address, 2> Addrs) {771Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);772Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);773LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT);774llvm::Value *SrcVal =775CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();776CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);777LValue DstLV = CGF->MakeAddrLValue(Addrs[DstIdx], QT);778llvm::Value *DstVal =779CGF->EmitLoadOfLValue(DstLV, SourceLocation()).getScalarVal();780CGF->EmitStoreOfScalar(SrcVal, DstLV);781CGF->EmitARCRelease(DstVal, ARCImpreciseLifetime);782}783784void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,785std::array<Address, 2> Addrs) {786Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);787Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);788CGF->emitARCMoveAssignWeak(QT, Addrs[DstIdx], Addrs[SrcIdx]);789}790791void callSpecialFunction(QualType FT, CharUnits Offset,792std::array<Address, 2> Addrs) {793Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset);794Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset);795CGF->callCStructMoveAssignmentOperator(796CGF->MakeAddrLValue(Addrs[DstIdx], FT),797CGF->MakeAddrLValue(Addrs[SrcIdx], FT));798}799};800801} // namespace802803void CodeGenFunction::destroyNonTrivialCStruct(CodeGenFunction &CGF,804Address Addr, QualType Type) {805CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Type));806}807808// Default-initialize a variable that is a non-trivial struct or an array of809// such structure.810void CodeGenFunction::defaultInitNonTrivialCStructVar(LValue Dst) {811GenDefaultInitialize Gen(getContext());812Address DstPtr = Dst.getAddress().withElementType(CGM.Int8PtrTy);813Gen.setCGF(this);814QualType QT = Dst.getType();815QT = Dst.isVolatile() ? QT.withVolatile() : QT;816Gen.visit(QT, nullptr, CharUnits::Zero(), std::array<Address, 1>({{DstPtr}}));817}818819template <class G, size_t N>820static void callSpecialFunction(G &&Gen, StringRef FuncName, QualType QT,821bool IsVolatile, CodeGenFunction &CGF,822std::array<Address, N> Addrs) {823auto SetArtificialLoc = ApplyDebugLocation::CreateArtificial(CGF);824for (unsigned I = 0; I < N; ++I)825Addrs[I] = Addrs[I].withElementType(CGF.CGM.Int8PtrTy);826QT = IsVolatile ? QT.withVolatile() : QT;827Gen.callFunc(FuncName, QT, Addrs, CGF);828}829830template <class G, size_t N>831static llvm::Function *832getSpecialFunction(G &&Gen, StringRef FuncName, QualType QT, bool IsVolatile,833std::array<CharUnits, N> Alignments, CodeGenModule &CGM) {834QT = IsVolatile ? QT.withVolatile() : QT;835// The following call requires an array of addresses as arguments, but doesn't836// actually use them (it overwrites them with the addresses of the arguments837// of the created function).838return Gen.getFunction(FuncName, QT, Alignments, CGM);839}840841// Functions to emit calls to the special functions of a non-trivial C struct.842void CodeGenFunction::callCStructDefaultConstructor(LValue Dst) {843bool IsVolatile = Dst.isVolatile();844Address DstPtr = Dst.getAddress();845QualType QT = Dst.getType();846GenDefaultInitializeFuncName GenName(DstPtr.getAlignment(), getContext());847std::string FuncName = GenName.getName(QT, IsVolatile);848callSpecialFunction(GenDefaultInitialize(getContext()), FuncName, QT,849IsVolatile, *this, std::array<Address, 1>({{DstPtr}}));850}851852std::string CodeGenFunction::getNonTrivialCopyConstructorStr(853QualType QT, CharUnits Alignment, bool IsVolatile, ASTContext &Ctx) {854GenBinaryFuncName<false> GenName("", Alignment, Alignment, Ctx);855return GenName.getName(QT, IsVolatile);856}857858std::string CodeGenFunction::getNonTrivialDestructorStr(QualType QT,859CharUnits Alignment,860bool IsVolatile,861ASTContext &Ctx) {862GenDestructorFuncName GenName("", Alignment, Ctx);863return GenName.getName(QT, IsVolatile);864}865866void CodeGenFunction::callCStructDestructor(LValue Dst) {867bool IsVolatile = Dst.isVolatile();868Address DstPtr = Dst.getAddress();869QualType QT = Dst.getType();870GenDestructorFuncName GenName("__destructor_", DstPtr.getAlignment(),871getContext());872std::string FuncName = GenName.getName(QT, IsVolatile);873callSpecialFunction(GenDestructor(getContext()), FuncName, QT, IsVolatile,874*this, std::array<Address, 1>({{DstPtr}}));875}876877void CodeGenFunction::callCStructCopyConstructor(LValue Dst, LValue Src) {878bool IsVolatile = Dst.isVolatile() || Src.isVolatile();879Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();880QualType QT = Dst.getType();881GenBinaryFuncName<false> GenName("__copy_constructor_", DstPtr.getAlignment(),882SrcPtr.getAlignment(), getContext());883std::string FuncName = GenName.getName(QT, IsVolatile);884callSpecialFunction(GenCopyConstructor(getContext()), FuncName, QT,885IsVolatile, *this,886std::array<Address, 2>({{DstPtr, SrcPtr}}));887}888889void CodeGenFunction::callCStructCopyAssignmentOperator(LValue Dst, LValue Src890891) {892bool IsVolatile = Dst.isVolatile() || Src.isVolatile();893Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();894QualType QT = Dst.getType();895GenBinaryFuncName<false> GenName("__copy_assignment_", DstPtr.getAlignment(),896SrcPtr.getAlignment(), getContext());897std::string FuncName = GenName.getName(QT, IsVolatile);898callSpecialFunction(GenCopyAssignment(getContext()), FuncName, QT, IsVolatile,899*this, std::array<Address, 2>({{DstPtr, SrcPtr}}));900}901902void CodeGenFunction::callCStructMoveConstructor(LValue Dst, LValue Src) {903bool IsVolatile = Dst.isVolatile() || Src.isVolatile();904Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();905QualType QT = Dst.getType();906GenBinaryFuncName<true> GenName("__move_constructor_", DstPtr.getAlignment(),907SrcPtr.getAlignment(), getContext());908std::string FuncName = GenName.getName(QT, IsVolatile);909callSpecialFunction(GenMoveConstructor(getContext()), FuncName, QT,910IsVolatile, *this,911std::array<Address, 2>({{DstPtr, SrcPtr}}));912}913914void CodeGenFunction::callCStructMoveAssignmentOperator(LValue Dst, LValue Src915916) {917bool IsVolatile = Dst.isVolatile() || Src.isVolatile();918Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();919QualType QT = Dst.getType();920GenBinaryFuncName<true> GenName("__move_assignment_", DstPtr.getAlignment(),921SrcPtr.getAlignment(), getContext());922std::string FuncName = GenName.getName(QT, IsVolatile);923callSpecialFunction(GenMoveAssignment(getContext()), FuncName, QT, IsVolatile,924*this, std::array<Address, 2>({{DstPtr, SrcPtr}}));925}926927llvm::Function *clang::CodeGen::getNonTrivialCStructDefaultConstructor(928CodeGenModule &CGM, CharUnits DstAlignment, bool IsVolatile, QualType QT) {929ASTContext &Ctx = CGM.getContext();930GenDefaultInitializeFuncName GenName(DstAlignment, Ctx);931std::string FuncName = GenName.getName(QT, IsVolatile);932return getSpecialFunction(GenDefaultInitialize(Ctx), FuncName, QT, IsVolatile,933std::array<CharUnits, 1>({{DstAlignment}}), CGM);934}935936llvm::Function *clang::CodeGen::getNonTrivialCStructCopyConstructor(937CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment,938bool IsVolatile, QualType QT) {939ASTContext &Ctx = CGM.getContext();940GenBinaryFuncName<false> GenName("__copy_constructor_", DstAlignment,941SrcAlignment, Ctx);942std::string FuncName = GenName.getName(QT, IsVolatile);943return getSpecialFunction(944GenCopyConstructor(Ctx), FuncName, QT, IsVolatile,945std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM);946}947948llvm::Function *clang::CodeGen::getNonTrivialCStructMoveConstructor(949CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment,950bool IsVolatile, QualType QT) {951ASTContext &Ctx = CGM.getContext();952GenBinaryFuncName<true> GenName("__move_constructor_", DstAlignment,953SrcAlignment, Ctx);954std::string FuncName = GenName.getName(QT, IsVolatile);955return getSpecialFunction(956GenMoveConstructor(Ctx), FuncName, QT, IsVolatile,957std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM);958}959960llvm::Function *clang::CodeGen::getNonTrivialCStructCopyAssignmentOperator(961CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment,962bool IsVolatile, QualType QT) {963ASTContext &Ctx = CGM.getContext();964GenBinaryFuncName<false> GenName("__copy_assignment_", DstAlignment,965SrcAlignment, Ctx);966std::string FuncName = GenName.getName(QT, IsVolatile);967return getSpecialFunction(968GenCopyAssignment(Ctx), FuncName, QT, IsVolatile,969std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM);970}971972llvm::Function *clang::CodeGen::getNonTrivialCStructMoveAssignmentOperator(973CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment,974bool IsVolatile, QualType QT) {975ASTContext &Ctx = CGM.getContext();976GenBinaryFuncName<true> GenName("__move_assignment_", DstAlignment,977SrcAlignment, Ctx);978std::string FuncName = GenName.getName(QT, IsVolatile);979return getSpecialFunction(980GenMoveAssignment(Ctx), FuncName, QT, IsVolatile,981std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM);982}983984llvm::Function *clang::CodeGen::getNonTrivialCStructDestructor(985CodeGenModule &CGM, CharUnits DstAlignment, bool IsVolatile, QualType QT) {986ASTContext &Ctx = CGM.getContext();987GenDestructorFuncName GenName("__destructor_", DstAlignment, Ctx);988std::string FuncName = GenName.getName(QT, IsVolatile);989return getSpecialFunction(GenDestructor(Ctx), FuncName, QT, IsVolatile,990std::array<CharUnits, 1>({{DstAlignment}}), CGM);991}992993994