10b57cec5SDimitry Andric //===--- CGNonTrivialStruct.cpp - Emit Special Functions for C Structs ----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines functions to generate various special functions for C 100b57cec5SDimitry Andric // structs. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "CodeGenFunction.h" 150b57cec5SDimitry Andric #include "CodeGenModule.h" 160b57cec5SDimitry Andric #include "clang/AST/NonTrivialTypeVisitor.h" 170b57cec5SDimitry Andric #include "clang/CodeGen/CodeGenABITypes.h" 180b57cec5SDimitry Andric #include "llvm/Support/ScopedPrinter.h" 190b57cec5SDimitry Andric #include <array> 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace clang; 220b57cec5SDimitry Andric using namespace CodeGen; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric // Return the size of a field in number of bits. 250b57cec5SDimitry Andric static uint64_t getFieldSize(const FieldDecl *FD, QualType FT, 260b57cec5SDimitry Andric ASTContext &Ctx) { 270b57cec5SDimitry Andric if (FD && FD->isBitField()) 280b57cec5SDimitry Andric return FD->getBitWidthValue(Ctx); 290b57cec5SDimitry Andric return Ctx.getTypeSize(FT); 300b57cec5SDimitry Andric } 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric namespace { 330b57cec5SDimitry Andric enum { DstIdx = 0, SrcIdx = 1 }; 340b57cec5SDimitry Andric const char *ValNameStr[2] = {"dst", "src"}; 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric template <class Derived> struct StructVisitor { 370b57cec5SDimitry Andric StructVisitor(ASTContext &Ctx) : Ctx(Ctx) {} 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric template <class... Ts> 400b57cec5SDimitry Andric void visitStructFields(QualType QT, CharUnits CurStructOffset, Ts... Args) { 410b57cec5SDimitry Andric const RecordDecl *RD = QT->castAs<RecordType>()->getDecl(); 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric // Iterate over the fields of the struct. 440b57cec5SDimitry Andric for (const FieldDecl *FD : RD->fields()) { 450b57cec5SDimitry Andric QualType FT = FD->getType(); 460b57cec5SDimitry Andric FT = QT.isVolatileQualified() ? FT.withVolatile() : FT; 470b57cec5SDimitry Andric asDerived().visit(FT, FD, CurStructOffset, Args...); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric asDerived().flushTrivialFields(Args...); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric template <class... Ts> void visitTrivial(Ts... Args) {} 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric template <class... Ts> void visitCXXDestructor(Ts... Args) { 560b57cec5SDimitry Andric llvm_unreachable("field of a C++ struct type is not expected"); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric template <class... Ts> void flushTrivialFields(Ts... Args) {} 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric uint64_t getFieldOffsetInBits(const FieldDecl *FD) { 620b57cec5SDimitry Andric return FD ? Ctx.getASTRecordLayout(FD->getParent()) 630b57cec5SDimitry Andric .getFieldOffset(FD->getFieldIndex()) 640b57cec5SDimitry Andric : 0; 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric CharUnits getFieldOffset(const FieldDecl *FD) { 680b57cec5SDimitry Andric return Ctx.toCharUnitsFromBits(getFieldOffsetInBits(FD)); 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric Derived &asDerived() { return static_cast<Derived &>(*this); } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric ASTContext &getContext() { return Ctx; } 740b57cec5SDimitry Andric ASTContext &Ctx; 750b57cec5SDimitry Andric }; 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric template <class Derived, bool IsMove> 780b57cec5SDimitry Andric struct CopyStructVisitor : StructVisitor<Derived>, 790b57cec5SDimitry Andric CopiedTypeVisitor<Derived, IsMove> { 800b57cec5SDimitry Andric using StructVisitor<Derived>::asDerived; 810b57cec5SDimitry Andric using Super = CopiedTypeVisitor<Derived, IsMove>; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric CopyStructVisitor(ASTContext &Ctx) : StructVisitor<Derived>(Ctx) {} 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric template <class... Ts> 860b57cec5SDimitry Andric void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT, 870b57cec5SDimitry Andric const FieldDecl *FD, CharUnits CurStructOffset, Ts &&... Args) { 880b57cec5SDimitry Andric if (PCK) 890b57cec5SDimitry Andric asDerived().flushTrivialFields(std::forward<Ts>(Args)...); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric template <class... Ts> 930b57cec5SDimitry Andric void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT, 940b57cec5SDimitry Andric const FieldDecl *FD, CharUnits CurStructOffset, 950b57cec5SDimitry Andric Ts &&... Args) { 960b57cec5SDimitry Andric if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) { 970b57cec5SDimitry Andric asDerived().visitArray(PCK, AT, FT.isVolatileQualified(), FD, 980b57cec5SDimitry Andric CurStructOffset, std::forward<Ts>(Args)...); 990b57cec5SDimitry Andric return; 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric Super::visitWithKind(PCK, FT, FD, CurStructOffset, 1030b57cec5SDimitry Andric std::forward<Ts>(Args)...); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric template <class... Ts> 1070b57cec5SDimitry Andric void visitTrivial(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset, 1080b57cec5SDimitry Andric Ts... Args) { 1090b57cec5SDimitry Andric assert(!FT.isVolatileQualified() && "volatile field not expected"); 1100b57cec5SDimitry Andric ASTContext &Ctx = asDerived().getContext(); 1110b57cec5SDimitry Andric uint64_t FieldSize = getFieldSize(FD, FT, Ctx); 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric // Ignore zero-sized fields. 1140b57cec5SDimitry Andric if (FieldSize == 0) 1150b57cec5SDimitry Andric return; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric uint64_t FStartInBits = asDerived().getFieldOffsetInBits(FD); 1180b57cec5SDimitry Andric uint64_t FEndInBits = FStartInBits + FieldSize; 1190b57cec5SDimitry Andric uint64_t RoundedFEnd = llvm::alignTo(FEndInBits, Ctx.getCharWidth()); 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric // Set Start if this is the first field of a sequence of trivial fields. 1220b57cec5SDimitry Andric if (Start == End) 1230b57cec5SDimitry Andric Start = CurStructOffset + Ctx.toCharUnitsFromBits(FStartInBits); 1240b57cec5SDimitry Andric End = CurStructOffset + Ctx.toCharUnitsFromBits(RoundedFEnd); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric CharUnits Start = CharUnits::Zero(), End = CharUnits::Zero(); 1280b57cec5SDimitry Andric }; 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric // This function creates the mangled name of a special function of a non-trivial 1310b57cec5SDimitry Andric // C struct. Since there is no ODR in C, the function is mangled based on the 1320b57cec5SDimitry Andric // struct contents and not the name. The mangled name has the following 1330b57cec5SDimitry Andric // structure: 1340b57cec5SDimitry Andric // 1350b57cec5SDimitry Andric // <function-name> ::= <prefix> <alignment-info> "_" <struct-field-info> 1360b57cec5SDimitry Andric // <prefix> ::= "__destructor_" | "__default_constructor_" | 1370b57cec5SDimitry Andric // "__copy_constructor_" | "__move_constructor_" | 1380b57cec5SDimitry Andric // "__copy_assignment_" | "__move_assignment_" 1390b57cec5SDimitry Andric // <alignment-info> ::= <dst-alignment> ["_" <src-alignment>] 1400b57cec5SDimitry Andric // <struct-field-info> ::= <field-info>+ 1410b57cec5SDimitry Andric // <field-info> ::= <struct-or-scalar-field-info> | <array-field-info> 1420b57cec5SDimitry Andric // <struct-or-scalar-field-info> ::= "_S" <struct-field-info> | 1430b57cec5SDimitry Andric // <strong-field-info> | <trivial-field-info> 1440b57cec5SDimitry Andric // <array-field-info> ::= "_AB" <array-offset> "s" <element-size> "n" 1450b57cec5SDimitry Andric // <num-elements> <innermost-element-info> "_AE" 1460b57cec5SDimitry Andric // <innermost-element-info> ::= <struct-or-scalar-field-info> 1470b57cec5SDimitry Andric // <strong-field-info> ::= "_s" ["b"] ["v"] <field-offset> 1480b57cec5SDimitry Andric // <trivial-field-info> ::= "_t" ["v"] <field-offset> "_" <field-size> 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric template <class Derived> struct GenFuncNameBase { 1510b57cec5SDimitry Andric std::string getVolatileOffsetStr(bool IsVolatile, CharUnits Offset) { 1520b57cec5SDimitry Andric std::string S; 1530b57cec5SDimitry Andric if (IsVolatile) 1540b57cec5SDimitry Andric S = "v"; 1550b57cec5SDimitry Andric S += llvm::to_string(Offset.getQuantity()); 1560b57cec5SDimitry Andric return S; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric void visitARCStrong(QualType FT, const FieldDecl *FD, 1600b57cec5SDimitry Andric CharUnits CurStructOffset) { 1610b57cec5SDimitry Andric appendStr("_s"); 1620b57cec5SDimitry Andric if (FT->isBlockPointerType()) 1630b57cec5SDimitry Andric appendStr("b"); 1640b57cec5SDimitry Andric CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); 1650b57cec5SDimitry Andric appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset)); 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric void visitARCWeak(QualType FT, const FieldDecl *FD, 1690b57cec5SDimitry Andric CharUnits CurStructOffset) { 1700b57cec5SDimitry Andric appendStr("_w"); 1710b57cec5SDimitry Andric CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); 1720b57cec5SDimitry Andric appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset)); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric void visitStruct(QualType QT, const FieldDecl *FD, 1760b57cec5SDimitry Andric CharUnits CurStructOffset) { 1770b57cec5SDimitry Andric CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); 1780b57cec5SDimitry Andric appendStr("_S"); 1790b57cec5SDimitry Andric asDerived().visitStructFields(QT, FieldOffset); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric template <class FieldKind> 1830b57cec5SDimitry Andric void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile, 1840b57cec5SDimitry Andric const FieldDecl *FD, CharUnits CurStructOffset) { 1850b57cec5SDimitry Andric // String for non-volatile trivial fields is emitted when 1860b57cec5SDimitry Andric // flushTrivialFields is called. 1870b57cec5SDimitry Andric if (!FK) 1880b57cec5SDimitry Andric return asDerived().visitTrivial(QualType(AT, 0), FD, CurStructOffset); 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric asDerived().flushTrivialFields(); 1910b57cec5SDimitry Andric CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); 1920b57cec5SDimitry Andric ASTContext &Ctx = asDerived().getContext(); 1930b57cec5SDimitry Andric const ConstantArrayType *CAT = cast<ConstantArrayType>(AT); 1940b57cec5SDimitry Andric unsigned NumElts = Ctx.getConstantArrayElementCount(CAT); 1950b57cec5SDimitry Andric QualType EltTy = Ctx.getBaseElementType(CAT); 1960b57cec5SDimitry Andric CharUnits EltSize = Ctx.getTypeSizeInChars(EltTy); 1970b57cec5SDimitry Andric appendStr("_AB" + llvm::to_string(FieldOffset.getQuantity()) + "s" + 1980b57cec5SDimitry Andric llvm::to_string(EltSize.getQuantity()) + "n" + 1990b57cec5SDimitry Andric llvm::to_string(NumElts)); 2000b57cec5SDimitry Andric EltTy = IsVolatile ? EltTy.withVolatile() : EltTy; 2010b57cec5SDimitry Andric asDerived().visitWithKind(FK, EltTy, nullptr, FieldOffset); 2020b57cec5SDimitry Andric appendStr("_AE"); 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric void appendStr(StringRef Str) { Name += Str; } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric std::string getName(QualType QT, bool IsVolatile) { 2080b57cec5SDimitry Andric QT = IsVolatile ? QT.withVolatile() : QT; 2090b57cec5SDimitry Andric asDerived().visitStructFields(QT, CharUnits::Zero()); 2100b57cec5SDimitry Andric return Name; 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric Derived &asDerived() { return static_cast<Derived &>(*this); } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric std::string Name; 2160b57cec5SDimitry Andric }; 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric template <class Derived> 2190b57cec5SDimitry Andric struct GenUnaryFuncName : StructVisitor<Derived>, GenFuncNameBase<Derived> { 2200b57cec5SDimitry Andric GenUnaryFuncName(StringRef Prefix, CharUnits DstAlignment, ASTContext &Ctx) 2210b57cec5SDimitry Andric : StructVisitor<Derived>(Ctx) { 2220b57cec5SDimitry Andric this->appendStr(Prefix); 2230b57cec5SDimitry Andric this->appendStr(llvm::to_string(DstAlignment.getQuantity())); 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric }; 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric // Helper function to create a null constant. 2280b57cec5SDimitry Andric static llvm::Constant *getNullForVariable(Address Addr) { 2290b57cec5SDimitry Andric llvm::Type *Ty = Addr.getElementType(); 2300b57cec5SDimitry Andric return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(Ty)); 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric template <bool IsMove> 2340b57cec5SDimitry Andric struct GenBinaryFuncName : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>, 2350b57cec5SDimitry Andric GenFuncNameBase<GenBinaryFuncName<IsMove>> { 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric GenBinaryFuncName(StringRef Prefix, CharUnits DstAlignment, 2380b57cec5SDimitry Andric CharUnits SrcAlignment, ASTContext &Ctx) 2390b57cec5SDimitry Andric : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>(Ctx) { 2400b57cec5SDimitry Andric this->appendStr(Prefix); 2410b57cec5SDimitry Andric this->appendStr(llvm::to_string(DstAlignment.getQuantity())); 2420b57cec5SDimitry Andric this->appendStr("_" + llvm::to_string(SrcAlignment.getQuantity())); 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric void flushTrivialFields() { 2460b57cec5SDimitry Andric if (this->Start == this->End) 2470b57cec5SDimitry Andric return; 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric this->appendStr("_t" + llvm::to_string(this->Start.getQuantity()) + "w" + 2500b57cec5SDimitry Andric llvm::to_string((this->End - this->Start).getQuantity())); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric this->Start = this->End = CharUnits::Zero(); 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric void visitVolatileTrivial(QualType FT, const FieldDecl *FD, 2560b57cec5SDimitry Andric CharUnits CurStructOffset) { 2575ffd83dbSDimitry Andric // Zero-length bit-fields don't need to be copied/assigned. 2585ffd83dbSDimitry Andric if (FD && FD->isZeroLengthBitField(this->Ctx)) 2595ffd83dbSDimitry Andric return; 2605ffd83dbSDimitry Andric 2610b57cec5SDimitry Andric // Because volatile fields can be bit-fields and are individually copied, 2620b57cec5SDimitry Andric // their offset and width are in bits. 2630b57cec5SDimitry Andric uint64_t OffsetInBits = 2640b57cec5SDimitry Andric this->Ctx.toBits(CurStructOffset) + this->getFieldOffsetInBits(FD); 2650b57cec5SDimitry Andric this->appendStr("_tv" + llvm::to_string(OffsetInBits) + "w" + 2660b57cec5SDimitry Andric llvm::to_string(getFieldSize(FD, FT, this->Ctx))); 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric }; 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric struct GenDefaultInitializeFuncName 2710b57cec5SDimitry Andric : GenUnaryFuncName<GenDefaultInitializeFuncName>, 2720b57cec5SDimitry Andric DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName> { 2730b57cec5SDimitry Andric using Super = DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName>; 2740b57cec5SDimitry Andric GenDefaultInitializeFuncName(CharUnits DstAlignment, ASTContext &Ctx) 2750b57cec5SDimitry Andric : GenUnaryFuncName<GenDefaultInitializeFuncName>("__default_constructor_", 2760b57cec5SDimitry Andric DstAlignment, Ctx) {} 2770b57cec5SDimitry Andric void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT, 2780b57cec5SDimitry Andric const FieldDecl *FD, CharUnits CurStructOffset) { 2790b57cec5SDimitry Andric if (const auto *AT = getContext().getAsArrayType(FT)) { 2800b57cec5SDimitry Andric visitArray(PDIK, AT, FT.isVolatileQualified(), FD, CurStructOffset); 2810b57cec5SDimitry Andric return; 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric Super::visitWithKind(PDIK, FT, FD, CurStructOffset); 2850b57cec5SDimitry Andric } 2860b57cec5SDimitry Andric }; 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric struct GenDestructorFuncName : GenUnaryFuncName<GenDestructorFuncName>, 2890b57cec5SDimitry Andric DestructedTypeVisitor<GenDestructorFuncName> { 2900b57cec5SDimitry Andric using Super = DestructedTypeVisitor<GenDestructorFuncName>; 2910b57cec5SDimitry Andric GenDestructorFuncName(const char *Prefix, CharUnits DstAlignment, 2920b57cec5SDimitry Andric ASTContext &Ctx) 2930b57cec5SDimitry Andric : GenUnaryFuncName<GenDestructorFuncName>(Prefix, DstAlignment, Ctx) {} 2940b57cec5SDimitry Andric void visitWithKind(QualType::DestructionKind DK, QualType FT, 2950b57cec5SDimitry Andric const FieldDecl *FD, CharUnits CurStructOffset) { 2960b57cec5SDimitry Andric if (const auto *AT = getContext().getAsArrayType(FT)) { 2970b57cec5SDimitry Andric visitArray(DK, AT, FT.isVolatileQualified(), FD, CurStructOffset); 2980b57cec5SDimitry Andric return; 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric Super::visitWithKind(DK, FT, FD, CurStructOffset); 3020b57cec5SDimitry Andric } 3030b57cec5SDimitry Andric }; 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric // Helper function that creates CGFunctionInfo for an N-ary special function. 3060b57cec5SDimitry Andric template <size_t N> 3070b57cec5SDimitry Andric static const CGFunctionInfo &getFunctionInfo(CodeGenModule &CGM, 3080b57cec5SDimitry Andric FunctionArgList &Args) { 3090b57cec5SDimitry Andric ASTContext &Ctx = CGM.getContext(); 3100b57cec5SDimitry Andric llvm::SmallVector<ImplicitParamDecl *, N> Params; 3110b57cec5SDimitry Andric QualType ParamTy = Ctx.getPointerType(Ctx.VoidPtrTy); 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric for (unsigned I = 0; I < N; ++I) 3140b57cec5SDimitry Andric Params.push_back(ImplicitParamDecl::Create( 3150b57cec5SDimitry Andric Ctx, nullptr, SourceLocation(), &Ctx.Idents.get(ValNameStr[I]), ParamTy, 3165f757f3fSDimitry Andric ImplicitParamKind::Other)); 3170b57cec5SDimitry Andric 31881ad6265SDimitry Andric llvm::append_range(Args, Params); 3190b57cec5SDimitry Andric 3200b57cec5SDimitry Andric return CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args); 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric 3235ffd83dbSDimitry Andric template <size_t N, size_t... Ints> 3245ffd83dbSDimitry Andric static std::array<Address, N> getParamAddrs(std::index_sequence<Ints...> IntSeq, 3255ffd83dbSDimitry Andric std::array<CharUnits, N> Alignments, 32606c3fb27SDimitry Andric const FunctionArgList &Args, 3275ffd83dbSDimitry Andric CodeGenFunction *CGF) { 32881ad6265SDimitry Andric return std::array<Address, N>{ 32981ad6265SDimitry Andric {Address(CGF->Builder.CreateLoad(CGF->GetAddrOfLocalVar(Args[Ints])), 33006c3fb27SDimitry Andric CGF->VoidPtrTy, Alignments[Ints], KnownNonNull)...}}; 3315ffd83dbSDimitry Andric } 3325ffd83dbSDimitry Andric 3330b57cec5SDimitry Andric // Template classes that are used as bases for classes that emit special 3340b57cec5SDimitry Andric // functions. 3350b57cec5SDimitry Andric template <class Derived> struct GenFuncBase { 3360b57cec5SDimitry Andric template <size_t N> 3370b57cec5SDimitry Andric void visitStruct(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset, 3380b57cec5SDimitry Andric std::array<Address, N> Addrs) { 3390b57cec5SDimitry Andric this->asDerived().callSpecialFunction( 3400b57cec5SDimitry Andric FT, CurStructOffset + asDerived().getFieldOffset(FD), Addrs); 3410b57cec5SDimitry Andric } 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric template <class FieldKind, size_t N> 3440b57cec5SDimitry Andric void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile, 3450b57cec5SDimitry Andric const FieldDecl *FD, CharUnits CurStructOffset, 3460b57cec5SDimitry Andric std::array<Address, N> Addrs) { 3470b57cec5SDimitry Andric // Non-volatile trivial fields are copied when flushTrivialFields is called. 3480b57cec5SDimitry Andric if (!FK) 3490b57cec5SDimitry Andric return asDerived().visitTrivial(QualType(AT, 0), FD, CurStructOffset, 3500b57cec5SDimitry Andric Addrs); 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric asDerived().flushTrivialFields(Addrs); 3530b57cec5SDimitry Andric CodeGenFunction &CGF = *this->CGF; 3540b57cec5SDimitry Andric ASTContext &Ctx = CGF.getContext(); 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric // Compute the end address. 3570b57cec5SDimitry Andric QualType BaseEltQT; 3580b57cec5SDimitry Andric std::array<Address, N> StartAddrs = Addrs; 3590b57cec5SDimitry Andric for (unsigned I = 0; I < N; ++I) 3600b57cec5SDimitry Andric StartAddrs[I] = getAddrWithOffset(Addrs[I], CurStructOffset, FD); 3610b57cec5SDimitry Andric Address DstAddr = StartAddrs[DstIdx]; 3620b57cec5SDimitry Andric llvm::Value *NumElts = CGF.emitArrayLength(AT, BaseEltQT, DstAddr); 3630b57cec5SDimitry Andric unsigned BaseEltSize = Ctx.getTypeSizeInChars(BaseEltQT).getQuantity(); 3640b57cec5SDimitry Andric llvm::Value *BaseEltSizeVal = 3650b57cec5SDimitry Andric llvm::ConstantInt::get(NumElts->getType(), BaseEltSize); 3660b57cec5SDimitry Andric llvm::Value *SizeInBytes = 3670b57cec5SDimitry Andric CGF.Builder.CreateNUWMul(BaseEltSizeVal, NumElts); 36806c3fb27SDimitry Andric llvm::Value *DstArrayEnd = CGF.Builder.CreateInBoundsGEP( 369*0fca6ea1SDimitry Andric CGF.Int8Ty, DstAddr.emitRawPointer(CGF), SizeInBytes); 3700b57cec5SDimitry Andric llvm::BasicBlock *PreheaderBB = CGF.Builder.GetInsertBlock(); 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric // Create the header block and insert the phi instructions. 3730b57cec5SDimitry Andric llvm::BasicBlock *HeaderBB = CGF.createBasicBlock("loop.header"); 3740b57cec5SDimitry Andric CGF.EmitBlock(HeaderBB); 3750b57cec5SDimitry Andric llvm::PHINode *PHIs[N]; 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric for (unsigned I = 0; I < N; ++I) { 3780b57cec5SDimitry Andric PHIs[I] = CGF.Builder.CreatePHI(CGF.CGM.Int8PtrPtrTy, 2, "addr.cur"); 379*0fca6ea1SDimitry Andric PHIs[I]->addIncoming(StartAddrs[I].emitRawPointer(CGF), PreheaderBB); 3800b57cec5SDimitry Andric } 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric // Create the exit and loop body blocks. 3830b57cec5SDimitry Andric llvm::BasicBlock *ExitBB = CGF.createBasicBlock("loop.exit"); 3840b57cec5SDimitry Andric llvm::BasicBlock *LoopBB = CGF.createBasicBlock("loop.body"); 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric // Emit the comparison and conditional branch instruction that jumps to 3870b57cec5SDimitry Andric // either the exit or the loop body. 3880b57cec5SDimitry Andric llvm::Value *Done = 3890b57cec5SDimitry Andric CGF.Builder.CreateICmpEQ(PHIs[DstIdx], DstArrayEnd, "done"); 3900b57cec5SDimitry Andric CGF.Builder.CreateCondBr(Done, ExitBB, LoopBB); 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric // Visit the element of the array in the loop body. 3930b57cec5SDimitry Andric CGF.EmitBlock(LoopBB); 3940b57cec5SDimitry Andric QualType EltQT = AT->getElementType(); 3950b57cec5SDimitry Andric CharUnits EltSize = Ctx.getTypeSizeInChars(EltQT); 3960b57cec5SDimitry Andric std::array<Address, N> NewAddrs = Addrs; 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric for (unsigned I = 0; I < N; ++I) 39981ad6265SDimitry Andric NewAddrs[I] = 40081ad6265SDimitry Andric Address(PHIs[I], CGF.Int8PtrTy, 40181ad6265SDimitry Andric StartAddrs[I].getAlignment().alignmentAtOffset(EltSize)); 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric EltQT = IsVolatile ? EltQT.withVolatile() : EltQT; 4040b57cec5SDimitry Andric this->asDerived().visitWithKind(FK, EltQT, nullptr, CharUnits::Zero(), 4050b57cec5SDimitry Andric NewAddrs); 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric LoopBB = CGF.Builder.GetInsertBlock(); 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric for (unsigned I = 0; I < N; ++I) { 4100b57cec5SDimitry Andric // Instrs to update the destination and source addresses. 4110b57cec5SDimitry Andric // Update phi instructions. 4120b57cec5SDimitry Andric NewAddrs[I] = getAddrWithOffset(NewAddrs[I], EltSize); 413*0fca6ea1SDimitry Andric PHIs[I]->addIncoming(NewAddrs[I].emitRawPointer(CGF), LoopBB); 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric // Insert an unconditional branch to the header block. 4170b57cec5SDimitry Andric CGF.Builder.CreateBr(HeaderBB); 4180b57cec5SDimitry Andric CGF.EmitBlock(ExitBB); 4190b57cec5SDimitry Andric } 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric /// Return an address with the specified offset from the passed address. 4220b57cec5SDimitry Andric Address getAddrWithOffset(Address Addr, CharUnits Offset) { 4230b57cec5SDimitry Andric assert(Addr.isValid() && "invalid address"); 4240b57cec5SDimitry Andric if (Offset.getQuantity() == 0) 4250b57cec5SDimitry Andric return Addr; 42606c3fb27SDimitry Andric Addr = Addr.withElementType(CGF->CGM.Int8Ty); 4270b57cec5SDimitry Andric Addr = CGF->Builder.CreateConstInBoundsGEP(Addr, Offset.getQuantity()); 42806c3fb27SDimitry Andric return Addr.withElementType(CGF->CGM.Int8PtrTy); 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric Address getAddrWithOffset(Address Addr, CharUnits StructFieldOffset, 4320b57cec5SDimitry Andric const FieldDecl *FD) { 4330b57cec5SDimitry Andric return getAddrWithOffset(Addr, StructFieldOffset + 4340b57cec5SDimitry Andric asDerived().getFieldOffset(FD)); 4350b57cec5SDimitry Andric } 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric template <size_t N> 4385ffd83dbSDimitry Andric llvm::Function *getFunction(StringRef FuncName, QualType QT, 4395ffd83dbSDimitry Andric std::array<CharUnits, N> Alignments, 4405ffd83dbSDimitry Andric CodeGenModule &CGM) { 4410b57cec5SDimitry Andric // If the special function already exists in the module, return it. 4420b57cec5SDimitry Andric if (llvm::Function *F = CGM.getModule().getFunction(FuncName)) { 4430b57cec5SDimitry Andric bool WrongType = false; 4440b57cec5SDimitry Andric if (!F->getReturnType()->isVoidTy()) 4450b57cec5SDimitry Andric WrongType = true; 4460b57cec5SDimitry Andric else { 4470b57cec5SDimitry Andric for (const llvm::Argument &Arg : F->args()) 4480b57cec5SDimitry Andric if (Arg.getType() != CGM.Int8PtrPtrTy) 4490b57cec5SDimitry Andric WrongType = true; 4500b57cec5SDimitry Andric } 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric if (WrongType) { 4535ffd83dbSDimitry Andric std::string FuncName = std::string(F->getName()); 4540b57cec5SDimitry Andric SourceLocation Loc = QT->castAs<RecordType>()->getDecl()->getLocation(); 4550b57cec5SDimitry Andric CGM.Error(Loc, "special function " + FuncName + 4560b57cec5SDimitry Andric " for non-trivial C struct has incorrect type"); 4570b57cec5SDimitry Andric return nullptr; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric return F; 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric ASTContext &Ctx = CGM.getContext(); 4630b57cec5SDimitry Andric FunctionArgList Args; 4640b57cec5SDimitry Andric const CGFunctionInfo &FI = getFunctionInfo<N>(CGM, Args); 4650b57cec5SDimitry Andric llvm::FunctionType *FuncTy = CGM.getTypes().GetFunctionType(FI); 4660b57cec5SDimitry Andric llvm::Function *F = 4670b57cec5SDimitry Andric llvm::Function::Create(FuncTy, llvm::GlobalValue::LinkOnceODRLinkage, 4680b57cec5SDimitry Andric FuncName, &CGM.getModule()); 4690b57cec5SDimitry Andric F->setVisibility(llvm::GlobalValue::HiddenVisibility); 470fe6060f1SDimitry Andric CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, F, /*IsThunk=*/false); 4710b57cec5SDimitry Andric CGM.SetLLVMFunctionAttributesForDefinition(nullptr, F); 4720b57cec5SDimitry Andric CodeGenFunction NewCGF(CGM); 4730b57cec5SDimitry Andric setCGF(&NewCGF); 474fe6060f1SDimitry Andric CGF->StartFunction(GlobalDecl(), Ctx.VoidTy, F, FI, Args); 475fe6060f1SDimitry Andric auto AL = ApplyDebugLocation::CreateArtificial(*CGF); 4765ffd83dbSDimitry Andric std::array<Address, N> Addrs = 4775ffd83dbSDimitry Andric getParamAddrs<N>(std::make_index_sequence<N>{}, Alignments, Args, CGF); 4780b57cec5SDimitry Andric asDerived().visitStructFields(QT, CharUnits::Zero(), Addrs); 4790b57cec5SDimitry Andric CGF->FinishFunction(); 4800b57cec5SDimitry Andric return F; 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric template <size_t N> 4840b57cec5SDimitry Andric void callFunc(StringRef FuncName, QualType QT, std::array<Address, N> Addrs, 4850b57cec5SDimitry Andric CodeGenFunction &CallerCGF) { 4860b57cec5SDimitry Andric std::array<CharUnits, N> Alignments; 4870b57cec5SDimitry Andric llvm::Value *Ptrs[N]; 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric for (unsigned I = 0; I < N; ++I) { 4900b57cec5SDimitry Andric Alignments[I] = Addrs[I].getAlignment(); 491*0fca6ea1SDimitry Andric Ptrs[I] = Addrs[I].emitRawPointer(CallerCGF); 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric if (llvm::Function *F = 4955ffd83dbSDimitry Andric getFunction(FuncName, QT, Alignments, CallerCGF.CGM)) 4960b57cec5SDimitry Andric CallerCGF.EmitNounwindRuntimeCall(F, Ptrs); 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric Derived &asDerived() { return static_cast<Derived &>(*this); } 5000b57cec5SDimitry Andric 5010b57cec5SDimitry Andric void setCGF(CodeGenFunction *F) { CGF = F; } 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric CodeGenFunction *CGF = nullptr; 5040b57cec5SDimitry Andric }; 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric template <class Derived, bool IsMove> 5070b57cec5SDimitry Andric struct GenBinaryFunc : CopyStructVisitor<Derived, IsMove>, 5080b57cec5SDimitry Andric GenFuncBase<Derived> { 5090b57cec5SDimitry Andric GenBinaryFunc(ASTContext &Ctx) : CopyStructVisitor<Derived, IsMove>(Ctx) {} 5100b57cec5SDimitry Andric 5110b57cec5SDimitry Andric void flushTrivialFields(std::array<Address, 2> Addrs) { 5120b57cec5SDimitry Andric CharUnits Size = this->End - this->Start; 5130b57cec5SDimitry Andric 5140b57cec5SDimitry Andric if (Size.getQuantity() == 0) 5150b57cec5SDimitry Andric return; 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], this->Start); 5180b57cec5SDimitry Andric Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], this->Start); 5190b57cec5SDimitry Andric 5200b57cec5SDimitry Andric // Emit memcpy. 52106c3fb27SDimitry Andric if (Size.getQuantity() >= 16 || 52206c3fb27SDimitry Andric !llvm::has_single_bit<uint32_t>(Size.getQuantity())) { 5230b57cec5SDimitry Andric llvm::Value *SizeVal = 5240b57cec5SDimitry Andric llvm::ConstantInt::get(this->CGF->SizeTy, Size.getQuantity()); 52506c3fb27SDimitry Andric DstAddr = DstAddr.withElementType(this->CGF->Int8Ty); 52606c3fb27SDimitry Andric SrcAddr = SrcAddr.withElementType(this->CGF->Int8Ty); 5270b57cec5SDimitry Andric this->CGF->Builder.CreateMemCpy(DstAddr, SrcAddr, SizeVal, false); 5280b57cec5SDimitry Andric } else { 5290b57cec5SDimitry Andric llvm::Type *Ty = llvm::Type::getIntNTy( 5300b57cec5SDimitry Andric this->CGF->getLLVMContext(), 5310b57cec5SDimitry Andric Size.getQuantity() * this->CGF->getContext().getCharWidth()); 53206c3fb27SDimitry Andric DstAddr = DstAddr.withElementType(Ty); 53306c3fb27SDimitry Andric SrcAddr = SrcAddr.withElementType(Ty); 5340b57cec5SDimitry Andric llvm::Value *SrcVal = this->CGF->Builder.CreateLoad(SrcAddr, false); 5350b57cec5SDimitry Andric this->CGF->Builder.CreateStore(SrcVal, DstAddr, false); 5360b57cec5SDimitry Andric } 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andric this->Start = this->End = CharUnits::Zero(); 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric template <class... Ts> 5420b57cec5SDimitry Andric void visitVolatileTrivial(QualType FT, const FieldDecl *FD, CharUnits Offset, 5430b57cec5SDimitry Andric std::array<Address, 2> Addrs) { 5440b57cec5SDimitry Andric LValue DstLV, SrcLV; 5450b57cec5SDimitry Andric if (FD) { 5465ffd83dbSDimitry Andric // No need to copy zero-length bit-fields. 5475ffd83dbSDimitry Andric if (FD->isZeroLengthBitField(this->CGF->getContext())) 5485ffd83dbSDimitry Andric return; 5495ffd83dbSDimitry Andric 5500b57cec5SDimitry Andric QualType RT = QualType(FD->getParent()->getTypeForDecl(), 0); 5510eae32dcSDimitry Andric llvm::Type *Ty = this->CGF->ConvertType(RT); 5520b57cec5SDimitry Andric Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], Offset); 55306c3fb27SDimitry Andric LValue DstBase = 55406c3fb27SDimitry Andric this->CGF->MakeAddrLValue(DstAddr.withElementType(Ty), FT); 5550b57cec5SDimitry Andric DstLV = this->CGF->EmitLValueForField(DstBase, FD); 5560b57cec5SDimitry Andric Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], Offset); 55706c3fb27SDimitry Andric LValue SrcBase = 55806c3fb27SDimitry Andric this->CGF->MakeAddrLValue(SrcAddr.withElementType(Ty), FT); 5590b57cec5SDimitry Andric SrcLV = this->CGF->EmitLValueForField(SrcBase, FD); 5600b57cec5SDimitry Andric } else { 5610eae32dcSDimitry Andric llvm::Type *Ty = this->CGF->ConvertTypeForMem(FT); 56206c3fb27SDimitry Andric Address DstAddr = Addrs[DstIdx].withElementType(Ty); 56306c3fb27SDimitry Andric Address SrcAddr = Addrs[SrcIdx].withElementType(Ty); 5640b57cec5SDimitry Andric DstLV = this->CGF->MakeAddrLValue(DstAddr, FT); 5650b57cec5SDimitry Andric SrcLV = this->CGF->MakeAddrLValue(SrcAddr, FT); 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric RValue SrcVal = this->CGF->EmitLoadOfLValue(SrcLV, SourceLocation()); 5680b57cec5SDimitry Andric this->CGF->EmitStoreThroughLValue(SrcVal, DstLV); 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric }; 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric // These classes that emit the special functions for a non-trivial struct. 5730b57cec5SDimitry Andric struct GenDestructor : StructVisitor<GenDestructor>, 5740b57cec5SDimitry Andric GenFuncBase<GenDestructor>, 5750b57cec5SDimitry Andric DestructedTypeVisitor<GenDestructor> { 5760b57cec5SDimitry Andric using Super = DestructedTypeVisitor<GenDestructor>; 5770b57cec5SDimitry Andric GenDestructor(ASTContext &Ctx) : StructVisitor<GenDestructor>(Ctx) {} 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric void visitWithKind(QualType::DestructionKind DK, QualType FT, 5800b57cec5SDimitry Andric const FieldDecl *FD, CharUnits CurStructOffset, 5810b57cec5SDimitry Andric std::array<Address, 1> Addrs) { 5820b57cec5SDimitry Andric if (const auto *AT = getContext().getAsArrayType(FT)) { 5830b57cec5SDimitry Andric visitArray(DK, AT, FT.isVolatileQualified(), FD, CurStructOffset, Addrs); 5840b57cec5SDimitry Andric return; 5850b57cec5SDimitry Andric } 5860b57cec5SDimitry Andric 5870b57cec5SDimitry Andric Super::visitWithKind(DK, FT, FD, CurStructOffset, Addrs); 5880b57cec5SDimitry Andric } 5890b57cec5SDimitry Andric 5900b57cec5SDimitry Andric void visitARCStrong(QualType QT, const FieldDecl *FD, 5910b57cec5SDimitry Andric CharUnits CurStructOffset, std::array<Address, 1> Addrs) { 5920b57cec5SDimitry Andric CGF->destroyARCStrongImprecise( 5930b57cec5SDimitry Andric *CGF, getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT); 5940b57cec5SDimitry Andric } 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, 5970b57cec5SDimitry Andric std::array<Address, 1> Addrs) { 5980b57cec5SDimitry Andric CGF->destroyARCWeak( 5990b57cec5SDimitry Andric *CGF, getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT); 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric 6020b57cec5SDimitry Andric void callSpecialFunction(QualType FT, CharUnits Offset, 6030b57cec5SDimitry Andric std::array<Address, 1> Addrs) { 6040b57cec5SDimitry Andric CGF->callCStructDestructor( 6050b57cec5SDimitry Andric CGF->MakeAddrLValue(getAddrWithOffset(Addrs[DstIdx], Offset), FT)); 6060b57cec5SDimitry Andric } 6070b57cec5SDimitry Andric }; 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric struct GenDefaultInitialize 6100b57cec5SDimitry Andric : StructVisitor<GenDefaultInitialize>, 6110b57cec5SDimitry Andric GenFuncBase<GenDefaultInitialize>, 6120b57cec5SDimitry Andric DefaultInitializedTypeVisitor<GenDefaultInitialize> { 6130b57cec5SDimitry Andric using Super = DefaultInitializedTypeVisitor<GenDefaultInitialize>; 6140b57cec5SDimitry Andric typedef GenFuncBase<GenDefaultInitialize> GenFuncBaseTy; 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric GenDefaultInitialize(ASTContext &Ctx) 6170b57cec5SDimitry Andric : StructVisitor<GenDefaultInitialize>(Ctx) {} 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT, 6200b57cec5SDimitry Andric const FieldDecl *FD, CharUnits CurStructOffset, 6210b57cec5SDimitry Andric std::array<Address, 1> Addrs) { 6220b57cec5SDimitry Andric if (const auto *AT = getContext().getAsArrayType(FT)) { 6230b57cec5SDimitry Andric visitArray(PDIK, AT, FT.isVolatileQualified(), FD, CurStructOffset, 6240b57cec5SDimitry Andric Addrs); 6250b57cec5SDimitry Andric return; 6260b57cec5SDimitry Andric } 6270b57cec5SDimitry Andric 6280b57cec5SDimitry Andric Super::visitWithKind(PDIK, FT, FD, CurStructOffset, Addrs); 6290b57cec5SDimitry Andric } 6300b57cec5SDimitry Andric 6310b57cec5SDimitry Andric void visitARCStrong(QualType QT, const FieldDecl *FD, 6320b57cec5SDimitry Andric CharUnits CurStructOffset, std::array<Address, 1> Addrs) { 6330b57cec5SDimitry Andric CGF->EmitNullInitialization( 6340b57cec5SDimitry Andric getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT); 6350b57cec5SDimitry Andric } 6360b57cec5SDimitry Andric 6370b57cec5SDimitry Andric void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, 6380b57cec5SDimitry Andric std::array<Address, 1> Addrs) { 6390b57cec5SDimitry Andric CGF->EmitNullInitialization( 6400b57cec5SDimitry Andric getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT); 6410b57cec5SDimitry Andric } 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric template <class FieldKind, size_t... Is> 6440b57cec5SDimitry Andric void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile, 6450b57cec5SDimitry Andric const FieldDecl *FD, CharUnits CurStructOffset, 6460b57cec5SDimitry Andric std::array<Address, 1> Addrs) { 6470b57cec5SDimitry Andric if (!FK) 6480b57cec5SDimitry Andric return visitTrivial(QualType(AT, 0), FD, CurStructOffset, Addrs); 6490b57cec5SDimitry Andric 6500b57cec5SDimitry Andric ASTContext &Ctx = getContext(); 6510b57cec5SDimitry Andric CharUnits Size = Ctx.getTypeSizeInChars(QualType(AT, 0)); 6520b57cec5SDimitry Andric QualType EltTy = Ctx.getBaseElementType(QualType(AT, 0)); 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric if (Size < CharUnits::fromQuantity(16) || EltTy->getAs<RecordType>()) { 6550b57cec5SDimitry Andric GenFuncBaseTy::visitArray(FK, AT, IsVolatile, FD, CurStructOffset, Addrs); 6560b57cec5SDimitry Andric return; 6570b57cec5SDimitry Andric } 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric llvm::Constant *SizeVal = CGF->Builder.getInt64(Size.getQuantity()); 6600b57cec5SDimitry Andric Address DstAddr = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD); 66106c3fb27SDimitry Andric Address Loc = DstAddr.withElementType(CGF->Int8Ty); 6620b57cec5SDimitry Andric CGF->Builder.CreateMemSet(Loc, CGF->Builder.getInt8(0), SizeVal, 6630b57cec5SDimitry Andric IsVolatile); 6640b57cec5SDimitry Andric } 6650b57cec5SDimitry Andric 6660b57cec5SDimitry Andric void callSpecialFunction(QualType FT, CharUnits Offset, 6670b57cec5SDimitry Andric std::array<Address, 1> Addrs) { 6680b57cec5SDimitry Andric CGF->callCStructDefaultConstructor( 6690b57cec5SDimitry Andric CGF->MakeAddrLValue(getAddrWithOffset(Addrs[DstIdx], Offset), FT)); 6700b57cec5SDimitry Andric } 6710b57cec5SDimitry Andric }; 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric struct GenCopyConstructor : GenBinaryFunc<GenCopyConstructor, false> { 6740b57cec5SDimitry Andric GenCopyConstructor(ASTContext &Ctx) 6750b57cec5SDimitry Andric : GenBinaryFunc<GenCopyConstructor, false>(Ctx) {} 6760b57cec5SDimitry Andric 6770b57cec5SDimitry Andric void visitARCStrong(QualType QT, const FieldDecl *FD, 6780b57cec5SDimitry Andric CharUnits CurStructOffset, std::array<Address, 2> Addrs) { 6790b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD); 6800b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD); 6810b57cec5SDimitry Andric llvm::Value *SrcVal = CGF->EmitLoadOfScalar( 6820b57cec5SDimitry Andric Addrs[SrcIdx], QT.isVolatileQualified(), QT, SourceLocation()); 6830b57cec5SDimitry Andric llvm::Value *Val = CGF->EmitARCRetain(QT, SrcVal); 6840b57cec5SDimitry Andric CGF->EmitStoreOfScalar(Val, CGF->MakeAddrLValue(Addrs[DstIdx], QT), true); 6850b57cec5SDimitry Andric } 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, 6880b57cec5SDimitry Andric std::array<Address, 2> Addrs) { 6890b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD); 6900b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD); 6910b57cec5SDimitry Andric CGF->EmitARCCopyWeak(Addrs[DstIdx], Addrs[SrcIdx]); 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric void callSpecialFunction(QualType FT, CharUnits Offset, 6950b57cec5SDimitry Andric std::array<Address, 2> Addrs) { 6960b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset); 6970b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset); 6980b57cec5SDimitry Andric CGF->callCStructCopyConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT), 6990b57cec5SDimitry Andric CGF->MakeAddrLValue(Addrs[SrcIdx], FT)); 7000b57cec5SDimitry Andric } 7010b57cec5SDimitry Andric }; 7020b57cec5SDimitry Andric 7030b57cec5SDimitry Andric struct GenMoveConstructor : GenBinaryFunc<GenMoveConstructor, true> { 7040b57cec5SDimitry Andric GenMoveConstructor(ASTContext &Ctx) 7050b57cec5SDimitry Andric : GenBinaryFunc<GenMoveConstructor, true>(Ctx) {} 7060b57cec5SDimitry Andric 7070b57cec5SDimitry Andric void visitARCStrong(QualType QT, const FieldDecl *FD, 7080b57cec5SDimitry Andric CharUnits CurStructOffset, std::array<Address, 2> Addrs) { 7090b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD); 7100b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD); 7110b57cec5SDimitry Andric LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT); 7120b57cec5SDimitry Andric llvm::Value *SrcVal = 7130b57cec5SDimitry Andric CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal(); 714*0fca6ea1SDimitry Andric CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV); 7150b57cec5SDimitry Andric CGF->EmitStoreOfScalar(SrcVal, CGF->MakeAddrLValue(Addrs[DstIdx], QT), 7160b57cec5SDimitry Andric /* isInitialization */ true); 7170b57cec5SDimitry Andric } 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, 7200b57cec5SDimitry Andric std::array<Address, 2> Addrs) { 7210b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD); 7220b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD); 7230b57cec5SDimitry Andric CGF->EmitARCMoveWeak(Addrs[DstIdx], Addrs[SrcIdx]); 7240b57cec5SDimitry Andric } 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric void callSpecialFunction(QualType FT, CharUnits Offset, 7270b57cec5SDimitry Andric std::array<Address, 2> Addrs) { 7280b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset); 7290b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset); 7300b57cec5SDimitry Andric CGF->callCStructMoveConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT), 7310b57cec5SDimitry Andric CGF->MakeAddrLValue(Addrs[SrcIdx], FT)); 7320b57cec5SDimitry Andric } 7330b57cec5SDimitry Andric }; 7340b57cec5SDimitry Andric 7350b57cec5SDimitry Andric struct GenCopyAssignment : GenBinaryFunc<GenCopyAssignment, false> { 7360b57cec5SDimitry Andric GenCopyAssignment(ASTContext &Ctx) 7370b57cec5SDimitry Andric : GenBinaryFunc<GenCopyAssignment, false>(Ctx) {} 7380b57cec5SDimitry Andric 7390b57cec5SDimitry Andric void visitARCStrong(QualType QT, const FieldDecl *FD, 7400b57cec5SDimitry Andric CharUnits CurStructOffset, std::array<Address, 2> Addrs) { 7410b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD); 7420b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD); 7430b57cec5SDimitry Andric llvm::Value *SrcVal = CGF->EmitLoadOfScalar( 7440b57cec5SDimitry Andric Addrs[SrcIdx], QT.isVolatileQualified(), QT, SourceLocation()); 7450b57cec5SDimitry Andric CGF->EmitARCStoreStrong(CGF->MakeAddrLValue(Addrs[DstIdx], QT), SrcVal, 7460b57cec5SDimitry Andric false); 7470b57cec5SDimitry Andric } 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, 7500b57cec5SDimitry Andric std::array<Address, 2> Addrs) { 7510b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD); 7520b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD); 7530b57cec5SDimitry Andric CGF->emitARCCopyAssignWeak(QT, Addrs[DstIdx], Addrs[SrcIdx]); 7540b57cec5SDimitry Andric } 7550b57cec5SDimitry Andric 7560b57cec5SDimitry Andric void callSpecialFunction(QualType FT, CharUnits Offset, 7570b57cec5SDimitry Andric std::array<Address, 2> Addrs) { 7580b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset); 7590b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset); 7600b57cec5SDimitry Andric CGF->callCStructCopyAssignmentOperator( 7610b57cec5SDimitry Andric CGF->MakeAddrLValue(Addrs[DstIdx], FT), 7620b57cec5SDimitry Andric CGF->MakeAddrLValue(Addrs[SrcIdx], FT)); 7630b57cec5SDimitry Andric } 7640b57cec5SDimitry Andric }; 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric struct GenMoveAssignment : GenBinaryFunc<GenMoveAssignment, true> { 7670b57cec5SDimitry Andric GenMoveAssignment(ASTContext &Ctx) 7680b57cec5SDimitry Andric : GenBinaryFunc<GenMoveAssignment, true>(Ctx) {} 7690b57cec5SDimitry Andric 7700b57cec5SDimitry Andric void visitARCStrong(QualType QT, const FieldDecl *FD, 7710b57cec5SDimitry Andric CharUnits CurStructOffset, std::array<Address, 2> Addrs) { 7720b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD); 7730b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD); 7740b57cec5SDimitry Andric LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT); 7750b57cec5SDimitry Andric llvm::Value *SrcVal = 7760b57cec5SDimitry Andric CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal(); 777*0fca6ea1SDimitry Andric CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV); 7780b57cec5SDimitry Andric LValue DstLV = CGF->MakeAddrLValue(Addrs[DstIdx], QT); 7790b57cec5SDimitry Andric llvm::Value *DstVal = 7800b57cec5SDimitry Andric CGF->EmitLoadOfLValue(DstLV, SourceLocation()).getScalarVal(); 7810b57cec5SDimitry Andric CGF->EmitStoreOfScalar(SrcVal, DstLV); 7820b57cec5SDimitry Andric CGF->EmitARCRelease(DstVal, ARCImpreciseLifetime); 7830b57cec5SDimitry Andric } 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset, 7860b57cec5SDimitry Andric std::array<Address, 2> Addrs) { 7870b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD); 7880b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD); 7890b57cec5SDimitry Andric CGF->emitARCMoveAssignWeak(QT, Addrs[DstIdx], Addrs[SrcIdx]); 7900b57cec5SDimitry Andric } 7910b57cec5SDimitry Andric 7920b57cec5SDimitry Andric void callSpecialFunction(QualType FT, CharUnits Offset, 7930b57cec5SDimitry Andric std::array<Address, 2> Addrs) { 7940b57cec5SDimitry Andric Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset); 7950b57cec5SDimitry Andric Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset); 7960b57cec5SDimitry Andric CGF->callCStructMoveAssignmentOperator( 7970b57cec5SDimitry Andric CGF->MakeAddrLValue(Addrs[DstIdx], FT), 7980b57cec5SDimitry Andric CGF->MakeAddrLValue(Addrs[SrcIdx], FT)); 7990b57cec5SDimitry Andric } 8000b57cec5SDimitry Andric }; 8010b57cec5SDimitry Andric 8020b57cec5SDimitry Andric } // namespace 8030b57cec5SDimitry Andric 8040b57cec5SDimitry Andric void CodeGenFunction::destroyNonTrivialCStruct(CodeGenFunction &CGF, 8050b57cec5SDimitry Andric Address Addr, QualType Type) { 8060b57cec5SDimitry Andric CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Type)); 8070b57cec5SDimitry Andric } 8080b57cec5SDimitry Andric 8090b57cec5SDimitry Andric // Default-initialize a variable that is a non-trivial struct or an array of 8100b57cec5SDimitry Andric // such structure. 8110b57cec5SDimitry Andric void CodeGenFunction::defaultInitNonTrivialCStructVar(LValue Dst) { 8120b57cec5SDimitry Andric GenDefaultInitialize Gen(getContext()); 813*0fca6ea1SDimitry Andric Address DstPtr = Dst.getAddress().withElementType(CGM.Int8PtrTy); 8140b57cec5SDimitry Andric Gen.setCGF(this); 8150b57cec5SDimitry Andric QualType QT = Dst.getType(); 8160b57cec5SDimitry Andric QT = Dst.isVolatile() ? QT.withVolatile() : QT; 8170b57cec5SDimitry Andric Gen.visit(QT, nullptr, CharUnits::Zero(), std::array<Address, 1>({{DstPtr}})); 8180b57cec5SDimitry Andric } 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric template <class G, size_t N> 8210b57cec5SDimitry Andric static void callSpecialFunction(G &&Gen, StringRef FuncName, QualType QT, 8220b57cec5SDimitry Andric bool IsVolatile, CodeGenFunction &CGF, 8230b57cec5SDimitry Andric std::array<Address, N> Addrs) { 824480093f4SDimitry Andric auto SetArtificialLoc = ApplyDebugLocation::CreateArtificial(CGF); 8250b57cec5SDimitry Andric for (unsigned I = 0; I < N; ++I) 82606c3fb27SDimitry Andric Addrs[I] = Addrs[I].withElementType(CGF.CGM.Int8PtrTy); 8270b57cec5SDimitry Andric QT = IsVolatile ? QT.withVolatile() : QT; 8280b57cec5SDimitry Andric Gen.callFunc(FuncName, QT, Addrs, CGF); 8290b57cec5SDimitry Andric } 8300b57cec5SDimitry Andric 8310b57cec5SDimitry Andric template <class G, size_t N> 8320b57cec5SDimitry Andric static llvm::Function * 8330b57cec5SDimitry Andric getSpecialFunction(G &&Gen, StringRef FuncName, QualType QT, bool IsVolatile, 8340b57cec5SDimitry Andric std::array<CharUnits, N> Alignments, CodeGenModule &CGM) { 8350b57cec5SDimitry Andric QT = IsVolatile ? QT.withVolatile() : QT; 8360b57cec5SDimitry Andric // The following call requires an array of addresses as arguments, but doesn't 8370b57cec5SDimitry Andric // actually use them (it overwrites them with the addresses of the arguments 8380b57cec5SDimitry Andric // of the created function). 8395ffd83dbSDimitry Andric return Gen.getFunction(FuncName, QT, Alignments, CGM); 8400b57cec5SDimitry Andric } 8410b57cec5SDimitry Andric 8420b57cec5SDimitry Andric // Functions to emit calls to the special functions of a non-trivial C struct. 8430b57cec5SDimitry Andric void CodeGenFunction::callCStructDefaultConstructor(LValue Dst) { 8440b57cec5SDimitry Andric bool IsVolatile = Dst.isVolatile(); 845*0fca6ea1SDimitry Andric Address DstPtr = Dst.getAddress(); 8460b57cec5SDimitry Andric QualType QT = Dst.getType(); 8470b57cec5SDimitry Andric GenDefaultInitializeFuncName GenName(DstPtr.getAlignment(), getContext()); 8480b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 8490b57cec5SDimitry Andric callSpecialFunction(GenDefaultInitialize(getContext()), FuncName, QT, 8500b57cec5SDimitry Andric IsVolatile, *this, std::array<Address, 1>({{DstPtr}})); 8510b57cec5SDimitry Andric } 8520b57cec5SDimitry Andric 8530b57cec5SDimitry Andric std::string CodeGenFunction::getNonTrivialCopyConstructorStr( 8540b57cec5SDimitry Andric QualType QT, CharUnits Alignment, bool IsVolatile, ASTContext &Ctx) { 8550b57cec5SDimitry Andric GenBinaryFuncName<false> GenName("", Alignment, Alignment, Ctx); 8560b57cec5SDimitry Andric return GenName.getName(QT, IsVolatile); 8570b57cec5SDimitry Andric } 8580b57cec5SDimitry Andric 8590b57cec5SDimitry Andric std::string CodeGenFunction::getNonTrivialDestructorStr(QualType QT, 8600b57cec5SDimitry Andric CharUnits Alignment, 8610b57cec5SDimitry Andric bool IsVolatile, 8620b57cec5SDimitry Andric ASTContext &Ctx) { 8630b57cec5SDimitry Andric GenDestructorFuncName GenName("", Alignment, Ctx); 8640b57cec5SDimitry Andric return GenName.getName(QT, IsVolatile); 8650b57cec5SDimitry Andric } 8660b57cec5SDimitry Andric 8670b57cec5SDimitry Andric void CodeGenFunction::callCStructDestructor(LValue Dst) { 8680b57cec5SDimitry Andric bool IsVolatile = Dst.isVolatile(); 869*0fca6ea1SDimitry Andric Address DstPtr = Dst.getAddress(); 8700b57cec5SDimitry Andric QualType QT = Dst.getType(); 8710b57cec5SDimitry Andric GenDestructorFuncName GenName("__destructor_", DstPtr.getAlignment(), 8720b57cec5SDimitry Andric getContext()); 8730b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 8740b57cec5SDimitry Andric callSpecialFunction(GenDestructor(getContext()), FuncName, QT, IsVolatile, 8750b57cec5SDimitry Andric *this, std::array<Address, 1>({{DstPtr}})); 8760b57cec5SDimitry Andric } 8770b57cec5SDimitry Andric 8780b57cec5SDimitry Andric void CodeGenFunction::callCStructCopyConstructor(LValue Dst, LValue Src) { 8790b57cec5SDimitry Andric bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); 880*0fca6ea1SDimitry Andric Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); 8810b57cec5SDimitry Andric QualType QT = Dst.getType(); 8820b57cec5SDimitry Andric GenBinaryFuncName<false> GenName("__copy_constructor_", DstPtr.getAlignment(), 8830b57cec5SDimitry Andric SrcPtr.getAlignment(), getContext()); 8840b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 8850b57cec5SDimitry Andric callSpecialFunction(GenCopyConstructor(getContext()), FuncName, QT, 8860b57cec5SDimitry Andric IsVolatile, *this, 8870b57cec5SDimitry Andric std::array<Address, 2>({{DstPtr, SrcPtr}})); 8880b57cec5SDimitry Andric } 8890b57cec5SDimitry Andric 8900b57cec5SDimitry Andric void CodeGenFunction::callCStructCopyAssignmentOperator(LValue Dst, LValue Src 8910b57cec5SDimitry Andric 8920b57cec5SDimitry Andric ) { 8930b57cec5SDimitry Andric bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); 894*0fca6ea1SDimitry Andric Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); 8950b57cec5SDimitry Andric QualType QT = Dst.getType(); 8960b57cec5SDimitry Andric GenBinaryFuncName<false> GenName("__copy_assignment_", DstPtr.getAlignment(), 8970b57cec5SDimitry Andric SrcPtr.getAlignment(), getContext()); 8980b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 8990b57cec5SDimitry Andric callSpecialFunction(GenCopyAssignment(getContext()), FuncName, QT, IsVolatile, 9000b57cec5SDimitry Andric *this, std::array<Address, 2>({{DstPtr, SrcPtr}})); 9010b57cec5SDimitry Andric } 9020b57cec5SDimitry Andric 9030b57cec5SDimitry Andric void CodeGenFunction::callCStructMoveConstructor(LValue Dst, LValue Src) { 9040b57cec5SDimitry Andric bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); 905*0fca6ea1SDimitry Andric Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); 9060b57cec5SDimitry Andric QualType QT = Dst.getType(); 9070b57cec5SDimitry Andric GenBinaryFuncName<true> GenName("__move_constructor_", DstPtr.getAlignment(), 9080b57cec5SDimitry Andric SrcPtr.getAlignment(), getContext()); 9090b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 9100b57cec5SDimitry Andric callSpecialFunction(GenMoveConstructor(getContext()), FuncName, QT, 9110b57cec5SDimitry Andric IsVolatile, *this, 9120b57cec5SDimitry Andric std::array<Address, 2>({{DstPtr, SrcPtr}})); 9130b57cec5SDimitry Andric } 9140b57cec5SDimitry Andric 9150b57cec5SDimitry Andric void CodeGenFunction::callCStructMoveAssignmentOperator(LValue Dst, LValue Src 9160b57cec5SDimitry Andric 9170b57cec5SDimitry Andric ) { 9180b57cec5SDimitry Andric bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); 919*0fca6ea1SDimitry Andric Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); 9200b57cec5SDimitry Andric QualType QT = Dst.getType(); 9210b57cec5SDimitry Andric GenBinaryFuncName<true> GenName("__move_assignment_", DstPtr.getAlignment(), 9220b57cec5SDimitry Andric SrcPtr.getAlignment(), getContext()); 9230b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 9240b57cec5SDimitry Andric callSpecialFunction(GenMoveAssignment(getContext()), FuncName, QT, IsVolatile, 9250b57cec5SDimitry Andric *this, std::array<Address, 2>({{DstPtr, SrcPtr}})); 9260b57cec5SDimitry Andric } 9270b57cec5SDimitry Andric 9280b57cec5SDimitry Andric llvm::Function *clang::CodeGen::getNonTrivialCStructDefaultConstructor( 9290b57cec5SDimitry Andric CodeGenModule &CGM, CharUnits DstAlignment, bool IsVolatile, QualType QT) { 9300b57cec5SDimitry Andric ASTContext &Ctx = CGM.getContext(); 9310b57cec5SDimitry Andric GenDefaultInitializeFuncName GenName(DstAlignment, Ctx); 9320b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 9330b57cec5SDimitry Andric return getSpecialFunction(GenDefaultInitialize(Ctx), FuncName, QT, IsVolatile, 9340b57cec5SDimitry Andric std::array<CharUnits, 1>({{DstAlignment}}), CGM); 9350b57cec5SDimitry Andric } 9360b57cec5SDimitry Andric 9370b57cec5SDimitry Andric llvm::Function *clang::CodeGen::getNonTrivialCStructCopyConstructor( 9380b57cec5SDimitry Andric CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment, 9390b57cec5SDimitry Andric bool IsVolatile, QualType QT) { 9400b57cec5SDimitry Andric ASTContext &Ctx = CGM.getContext(); 9410b57cec5SDimitry Andric GenBinaryFuncName<false> GenName("__copy_constructor_", DstAlignment, 9420b57cec5SDimitry Andric SrcAlignment, Ctx); 9430b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 9440b57cec5SDimitry Andric return getSpecialFunction( 9450b57cec5SDimitry Andric GenCopyConstructor(Ctx), FuncName, QT, IsVolatile, 9460b57cec5SDimitry Andric std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM); 9470b57cec5SDimitry Andric } 9480b57cec5SDimitry Andric 9490b57cec5SDimitry Andric llvm::Function *clang::CodeGen::getNonTrivialCStructMoveConstructor( 9500b57cec5SDimitry Andric CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment, 9510b57cec5SDimitry Andric bool IsVolatile, QualType QT) { 9520b57cec5SDimitry Andric ASTContext &Ctx = CGM.getContext(); 9530b57cec5SDimitry Andric GenBinaryFuncName<true> GenName("__move_constructor_", DstAlignment, 9540b57cec5SDimitry Andric SrcAlignment, Ctx); 9550b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 9560b57cec5SDimitry Andric return getSpecialFunction( 9570b57cec5SDimitry Andric GenMoveConstructor(Ctx), FuncName, QT, IsVolatile, 9580b57cec5SDimitry Andric std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM); 9590b57cec5SDimitry Andric } 9600b57cec5SDimitry Andric 9610b57cec5SDimitry Andric llvm::Function *clang::CodeGen::getNonTrivialCStructCopyAssignmentOperator( 9620b57cec5SDimitry Andric CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment, 9630b57cec5SDimitry Andric bool IsVolatile, QualType QT) { 9640b57cec5SDimitry Andric ASTContext &Ctx = CGM.getContext(); 9650b57cec5SDimitry Andric GenBinaryFuncName<false> GenName("__copy_assignment_", DstAlignment, 9660b57cec5SDimitry Andric SrcAlignment, Ctx); 9670b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 9680b57cec5SDimitry Andric return getSpecialFunction( 9690b57cec5SDimitry Andric GenCopyAssignment(Ctx), FuncName, QT, IsVolatile, 9700b57cec5SDimitry Andric std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM); 9710b57cec5SDimitry Andric } 9720b57cec5SDimitry Andric 9730b57cec5SDimitry Andric llvm::Function *clang::CodeGen::getNonTrivialCStructMoveAssignmentOperator( 9740b57cec5SDimitry Andric CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment, 9750b57cec5SDimitry Andric bool IsVolatile, QualType QT) { 9760b57cec5SDimitry Andric ASTContext &Ctx = CGM.getContext(); 9770b57cec5SDimitry Andric GenBinaryFuncName<true> GenName("__move_assignment_", DstAlignment, 9780b57cec5SDimitry Andric SrcAlignment, Ctx); 9790b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 9800b57cec5SDimitry Andric return getSpecialFunction( 9810b57cec5SDimitry Andric GenMoveAssignment(Ctx), FuncName, QT, IsVolatile, 9820b57cec5SDimitry Andric std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM); 9830b57cec5SDimitry Andric } 9840b57cec5SDimitry Andric 9850b57cec5SDimitry Andric llvm::Function *clang::CodeGen::getNonTrivialCStructDestructor( 9860b57cec5SDimitry Andric CodeGenModule &CGM, CharUnits DstAlignment, bool IsVolatile, QualType QT) { 9870b57cec5SDimitry Andric ASTContext &Ctx = CGM.getContext(); 9880b57cec5SDimitry Andric GenDestructorFuncName GenName("__destructor_", DstAlignment, Ctx); 9890b57cec5SDimitry Andric std::string FuncName = GenName.getName(QT, IsVolatile); 9900b57cec5SDimitry Andric return getSpecialFunction(GenDestructor(Ctx), FuncName, QT, IsVolatile, 9910b57cec5SDimitry Andric std::array<CharUnits, 1>({{DstAlignment}}), CGM); 9920b57cec5SDimitry Andric } 993