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