
This is a major change on how we represent nested name qualifications in the AST. * The nested name specifier itself and how it's stored is changed. The prefixes for types are handled within the type hierarchy, which makes canonicalization for them super cheap, no memory allocation required. Also translating a type into nested name specifier form becomes a no-op. An identifier is stored as a DependentNameType. The nested name specifier gains a lightweight handle class, to be used instead of passing around pointers, which is similar to what is implemented for TemplateName. There is still one free bit available, and this handle can be used within a PointerUnion and PointerIntPair, which should keep bit-packing aficionados happy. * The ElaboratedType node is removed, all type nodes in which it could previously apply to can now store the elaborated keyword and name qualifier, tail allocating when present. * TagTypes can now point to the exact declaration found when producing these, as opposed to the previous situation of there only existing one TagType per entity. This increases the amount of type sugar retained, and can have several applications, for example in tracking module ownership, and other tools which care about source file origins, such as IWYU. These TagTypes are lazily allocated, in order to limit the increase in AST size. This patch offers a great performance benefit. It greatly improves compilation time for [stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for `test_on2.cpp` in that project, which is the slowest compiling test, this patch improves `-c` compilation time by about 7.2%, with the `-fsyntax-only` improvement being at ~12%. This has great results on compile-time-tracker as well:  This patch also further enables other optimziations in the future, and will reduce the performance impact of template specialization resugaring when that lands. It has some other miscelaneous drive-by fixes. About the review: Yes the patch is huge, sorry about that. Part of the reason is that I started by the nested name specifier part, before the ElaboratedType part, but that had a huge performance downside, as ElaboratedType is a big performance hog. I didn't have the steam to go back and change the patch after the fact. There is also a lot of internal API changes, and it made sense to remove ElaboratedType in one go, versus removing it from one type at a time, as that would present much more churn to the users. Also, the nested name specifier having a different API avoids missing changes related to how prefixes work now, which could make existing code compile but not work. How to review: The important changes are all in `clang/include/clang/AST` and `clang/lib/AST`, with also important changes in `clang/lib/Sema/TreeTransform.h`. The rest and bulk of the changes are mostly consequences of the changes in API. PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just for easier to rebasing. I plan to rename it back after this lands. Fixes #136624 Fixes https://github.com/llvm/llvm-project/issues/43179 Fixes https://github.com/llvm/llvm-project/issues/68670 Fixes https://github.com/llvm/llvm-project/issues/92757
1016 lines
42 KiB
C++
1016 lines
42 KiB
C++
//===--- CGNonTrivialStruct.cpp - Emit Special Functions for C Structs ----===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines functions to generate various special functions for C
|
|
// structs.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CGDebugInfo.h"
|
|
#include "CodeGenFunction.h"
|
|
#include "CodeGenModule.h"
|
|
#include "clang/AST/NonTrivialTypeVisitor.h"
|
|
#include "clang/CodeGen/CodeGenABITypes.h"
|
|
#include "llvm/Support/ScopedPrinter.h"
|
|
#include <array>
|
|
|
|
using namespace clang;
|
|
using namespace CodeGen;
|
|
|
|
// Return the size of a field in number of bits.
|
|
static uint64_t getFieldSize(const FieldDecl *FD, QualType FT,
|
|
ASTContext &Ctx) {
|
|
if (FD && FD->isBitField())
|
|
return FD->getBitWidthValue();
|
|
return Ctx.getTypeSize(FT);
|
|
}
|
|
|
|
namespace {
|
|
enum { DstIdx = 0, SrcIdx = 1 };
|
|
const char *ValNameStr[2] = {"dst", "src"};
|
|
|
|
template <class Derived> struct StructVisitor {
|
|
StructVisitor(ASTContext &Ctx) : Ctx(Ctx) {}
|
|
|
|
template <class... Ts>
|
|
void visitStructFields(QualType QT, CharUnits CurStructOffset, Ts... Args) {
|
|
const RecordDecl *RD =
|
|
QT->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
|
|
|
|
// Iterate over the fields of the struct.
|
|
for (const FieldDecl *FD : RD->fields()) {
|
|
QualType FT = FD->getType();
|
|
FT = QT.isVolatileQualified() ? FT.withVolatile() : FT;
|
|
asDerived().visit(FT, FD, CurStructOffset, Args...);
|
|
}
|
|
|
|
asDerived().flushTrivialFields(Args...);
|
|
}
|
|
|
|
template <class... Ts> void visitTrivial(Ts... Args) {}
|
|
|
|
template <class... Ts> void visitCXXDestructor(Ts... Args) {
|
|
llvm_unreachable("field of a C++ struct type is not expected");
|
|
}
|
|
|
|
template <class... Ts> void flushTrivialFields(Ts... Args) {}
|
|
|
|
uint64_t getFieldOffsetInBits(const FieldDecl *FD) {
|
|
return FD ? Ctx.getASTRecordLayout(FD->getParent())
|
|
.getFieldOffset(FD->getFieldIndex())
|
|
: 0;
|
|
}
|
|
|
|
CharUnits getFieldOffset(const FieldDecl *FD) {
|
|
return Ctx.toCharUnitsFromBits(getFieldOffsetInBits(FD));
|
|
}
|
|
|
|
Derived &asDerived() { return static_cast<Derived &>(*this); }
|
|
|
|
ASTContext &getContext() { return Ctx; }
|
|
ASTContext &Ctx;
|
|
};
|
|
|
|
template <class Derived, bool IsMove>
|
|
struct CopyStructVisitor : StructVisitor<Derived>,
|
|
CopiedTypeVisitor<Derived, IsMove> {
|
|
using StructVisitor<Derived>::asDerived;
|
|
using Super = CopiedTypeVisitor<Derived, IsMove>;
|
|
|
|
CopyStructVisitor(ASTContext &Ctx) : StructVisitor<Derived>(Ctx) {}
|
|
|
|
template <class... Ts>
|
|
void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT,
|
|
const FieldDecl *FD, CharUnits CurStructOffset, Ts &&... Args) {
|
|
if (PCK)
|
|
asDerived().flushTrivialFields(std::forward<Ts>(Args)...);
|
|
}
|
|
|
|
template <class... Ts>
|
|
void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT,
|
|
const FieldDecl *FD, CharUnits CurStructOffset,
|
|
Ts &&... Args) {
|
|
if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) {
|
|
asDerived().visitArray(PCK, AT, FT.isVolatileQualified(), FD,
|
|
CurStructOffset, std::forward<Ts>(Args)...);
|
|
return;
|
|
}
|
|
|
|
Super::visitWithKind(PCK, FT, FD, CurStructOffset,
|
|
std::forward<Ts>(Args)...);
|
|
}
|
|
|
|
template <class... Ts>
|
|
void visitTrivial(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset,
|
|
Ts... Args) {
|
|
assert(!FT.isVolatileQualified() && "volatile field not expected");
|
|
ASTContext &Ctx = asDerived().getContext();
|
|
uint64_t FieldSize = getFieldSize(FD, FT, Ctx);
|
|
|
|
// Ignore zero-sized fields.
|
|
if (FieldSize == 0)
|
|
return;
|
|
|
|
uint64_t FStartInBits = asDerived().getFieldOffsetInBits(FD);
|
|
uint64_t FEndInBits = FStartInBits + FieldSize;
|
|
uint64_t RoundedFEnd = llvm::alignTo(FEndInBits, Ctx.getCharWidth());
|
|
|
|
// Set Start if this is the first field of a sequence of trivial fields.
|
|
if (Start == End)
|
|
Start = CurStructOffset + Ctx.toCharUnitsFromBits(FStartInBits);
|
|
End = CurStructOffset + Ctx.toCharUnitsFromBits(RoundedFEnd);
|
|
}
|
|
|
|
CharUnits Start = CharUnits::Zero(), End = CharUnits::Zero();
|
|
};
|
|
|
|
// This function creates the mangled name of a special function of a non-trivial
|
|
// C struct. Since there is no ODR in C, the function is mangled based on the
|
|
// struct contents and not the name. The mangled name has the following
|
|
// structure:
|
|
//
|
|
// <function-name> ::= <prefix> <alignment-info> "_" <struct-field-info>
|
|
// <prefix> ::= "__destructor_" | "__default_constructor_" |
|
|
// "__copy_constructor_" | "__move_constructor_" |
|
|
// "__copy_assignment_" | "__move_assignment_"
|
|
// <alignment-info> ::= <dst-alignment> ["_" <src-alignment>]
|
|
// <struct-field-info> ::= <field-info>+
|
|
// <field-info> ::= <struct-or-scalar-field-info> | <array-field-info>
|
|
// <struct-or-scalar-field-info> ::= "_S" <struct-field-info> |
|
|
// <strong-field-info> | <trivial-field-info>
|
|
// <array-field-info> ::= "_AB" <array-offset> "s" <element-size> "n"
|
|
// <num-elements> <innermost-element-info> "_AE"
|
|
// <innermost-element-info> ::= <struct-or-scalar-field-info>
|
|
// <strong-field-info> ::= "_s" ["b"] ["v"] <field-offset>
|
|
// <trivial-field-info> ::= "_t" ["v"] <field-offset> "_" <field-size>
|
|
|
|
template <class Derived> struct GenFuncNameBase {
|
|
std::string getVolatileOffsetStr(bool IsVolatile, CharUnits Offset) {
|
|
std::string S;
|
|
if (IsVolatile)
|
|
S = "v";
|
|
S += llvm::to_string(Offset.getQuantity());
|
|
return S;
|
|
}
|
|
|
|
void visitARCStrong(QualType FT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset) {
|
|
appendStr("_s");
|
|
if (FT->isBlockPointerType())
|
|
appendStr("b");
|
|
CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
|
|
appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset));
|
|
}
|
|
|
|
void visitARCWeak(QualType FT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset) {
|
|
appendStr("_w");
|
|
CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
|
|
appendStr(getVolatileOffsetStr(FT.isVolatileQualified(), FieldOffset));
|
|
}
|
|
|
|
void visitStruct(QualType QT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset) {
|
|
CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
|
|
appendStr("_S");
|
|
asDerived().visitStructFields(QT, FieldOffset);
|
|
}
|
|
|
|
template <class FieldKind>
|
|
void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile,
|
|
const FieldDecl *FD, CharUnits CurStructOffset) {
|
|
// String for non-volatile trivial fields is emitted when
|
|
// flushTrivialFields is called.
|
|
if (!FK)
|
|
return asDerived().visitTrivial(QualType(AT, 0), FD, CurStructOffset);
|
|
|
|
asDerived().flushTrivialFields();
|
|
CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD);
|
|
ASTContext &Ctx = asDerived().getContext();
|
|
const ConstantArrayType *CAT = cast<ConstantArrayType>(AT);
|
|
unsigned NumElts = Ctx.getConstantArrayElementCount(CAT);
|
|
QualType EltTy = Ctx.getBaseElementType(CAT);
|
|
CharUnits EltSize = Ctx.getTypeSizeInChars(EltTy);
|
|
appendStr("_AB" + llvm::to_string(FieldOffset.getQuantity()) + "s" +
|
|
llvm::to_string(EltSize.getQuantity()) + "n" +
|
|
llvm::to_string(NumElts));
|
|
EltTy = IsVolatile ? EltTy.withVolatile() : EltTy;
|
|
asDerived().visitWithKind(FK, EltTy, nullptr, FieldOffset);
|
|
appendStr("_AE");
|
|
}
|
|
|
|
void appendStr(StringRef Str) { Name += Str; }
|
|
|
|
std::string getName(QualType QT, bool IsVolatile) {
|
|
QT = IsVolatile ? QT.withVolatile() : QT;
|
|
asDerived().visitStructFields(QT, CharUnits::Zero());
|
|
return Name;
|
|
}
|
|
|
|
Derived &asDerived() { return static_cast<Derived &>(*this); }
|
|
|
|
std::string Name;
|
|
};
|
|
|
|
template <class Derived>
|
|
struct GenUnaryFuncName : StructVisitor<Derived>, GenFuncNameBase<Derived> {
|
|
GenUnaryFuncName(StringRef Prefix, CharUnits DstAlignment, ASTContext &Ctx)
|
|
: StructVisitor<Derived>(Ctx) {
|
|
this->appendStr(Prefix);
|
|
this->appendStr(llvm::to_string(DstAlignment.getQuantity()));
|
|
}
|
|
};
|
|
|
|
// Helper function to create a null constant.
|
|
static llvm::Constant *getNullForVariable(Address Addr) {
|
|
llvm::Type *Ty = Addr.getElementType();
|
|
return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(Ty));
|
|
}
|
|
|
|
template <bool IsMove>
|
|
struct GenBinaryFuncName : CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>,
|
|
GenFuncNameBase<GenBinaryFuncName<IsMove>> {
|
|
|
|
GenBinaryFuncName(StringRef Prefix, CharUnits DstAlignment,
|
|
CharUnits SrcAlignment, ASTContext &Ctx)
|
|
: CopyStructVisitor<GenBinaryFuncName<IsMove>, IsMove>(Ctx) {
|
|
this->appendStr(Prefix);
|
|
this->appendStr(llvm::to_string(DstAlignment.getQuantity()));
|
|
this->appendStr("_" + llvm::to_string(SrcAlignment.getQuantity()));
|
|
}
|
|
|
|
void flushTrivialFields() {
|
|
if (this->Start == this->End)
|
|
return;
|
|
|
|
this->appendStr("_t" + llvm::to_string(this->Start.getQuantity()) + "w" +
|
|
llvm::to_string((this->End - this->Start).getQuantity()));
|
|
|
|
this->Start = this->End = CharUnits::Zero();
|
|
}
|
|
|
|
void visitVolatileTrivial(QualType FT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset) {
|
|
// Zero-length bit-fields don't need to be copied/assigned.
|
|
if (FD && FD->isZeroLengthBitField())
|
|
return;
|
|
|
|
// Because volatile fields can be bit-fields and are individually copied,
|
|
// their offset and width are in bits.
|
|
uint64_t OffsetInBits =
|
|
this->Ctx.toBits(CurStructOffset) + this->getFieldOffsetInBits(FD);
|
|
this->appendStr("_tv" + llvm::to_string(OffsetInBits) + "w" +
|
|
llvm::to_string(getFieldSize(FD, FT, this->Ctx)));
|
|
}
|
|
|
|
void visitPtrAuth(QualType FT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset) {
|
|
this->appendStr("_pa");
|
|
PointerAuthQualifier PtrAuth = FT.getPointerAuth().withoutKeyNone();
|
|
this->appendStr(llvm::to_string(PtrAuth.getKey()) + "_");
|
|
this->appendStr(llvm::to_string(PtrAuth.getExtraDiscriminator()) + "_");
|
|
if (PtrAuth.authenticatesNullValues())
|
|
this->appendStr("anv_");
|
|
CharUnits FieldOffset = CurStructOffset + this->getFieldOffset(FD);
|
|
this->appendStr(llvm::to_string(FieldOffset.getQuantity()));
|
|
}
|
|
};
|
|
|
|
struct GenDefaultInitializeFuncName
|
|
: GenUnaryFuncName<GenDefaultInitializeFuncName>,
|
|
DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName> {
|
|
using Super = DefaultInitializedTypeVisitor<GenDefaultInitializeFuncName>;
|
|
GenDefaultInitializeFuncName(CharUnits DstAlignment, ASTContext &Ctx)
|
|
: GenUnaryFuncName<GenDefaultInitializeFuncName>("__default_constructor_",
|
|
DstAlignment, Ctx) {}
|
|
void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT,
|
|
const FieldDecl *FD, CharUnits CurStructOffset) {
|
|
if (const auto *AT = getContext().getAsArrayType(FT)) {
|
|
visitArray(PDIK, AT, FT.isVolatileQualified(), FD, CurStructOffset);
|
|
return;
|
|
}
|
|
|
|
Super::visitWithKind(PDIK, FT, FD, CurStructOffset);
|
|
}
|
|
};
|
|
|
|
struct GenDestructorFuncName : GenUnaryFuncName<GenDestructorFuncName>,
|
|
DestructedTypeVisitor<GenDestructorFuncName> {
|
|
using Super = DestructedTypeVisitor<GenDestructorFuncName>;
|
|
GenDestructorFuncName(const char *Prefix, CharUnits DstAlignment,
|
|
ASTContext &Ctx)
|
|
: GenUnaryFuncName<GenDestructorFuncName>(Prefix, DstAlignment, Ctx) {}
|
|
void visitWithKind(QualType::DestructionKind DK, QualType FT,
|
|
const FieldDecl *FD, CharUnits CurStructOffset) {
|
|
if (const auto *AT = getContext().getAsArrayType(FT)) {
|
|
visitArray(DK, AT, FT.isVolatileQualified(), FD, CurStructOffset);
|
|
return;
|
|
}
|
|
|
|
Super::visitWithKind(DK, FT, FD, CurStructOffset);
|
|
}
|
|
};
|
|
|
|
// Helper function that creates CGFunctionInfo for an N-ary special function.
|
|
template <size_t N>
|
|
static const CGFunctionInfo &getFunctionInfo(CodeGenModule &CGM,
|
|
FunctionArgList &Args) {
|
|
ASTContext &Ctx = CGM.getContext();
|
|
llvm::SmallVector<ImplicitParamDecl *, N> Params;
|
|
QualType ParamTy = Ctx.getPointerType(Ctx.VoidPtrTy);
|
|
|
|
for (unsigned I = 0; I < N; ++I)
|
|
Params.push_back(ImplicitParamDecl::Create(
|
|
Ctx, nullptr, SourceLocation(), &Ctx.Idents.get(ValNameStr[I]), ParamTy,
|
|
ImplicitParamKind::Other));
|
|
|
|
llvm::append_range(Args, Params);
|
|
|
|
return CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args);
|
|
}
|
|
|
|
template <size_t N, size_t... Ints>
|
|
static std::array<Address, N> getParamAddrs(std::index_sequence<Ints...> IntSeq,
|
|
std::array<CharUnits, N> Alignments,
|
|
const FunctionArgList &Args,
|
|
CodeGenFunction *CGF) {
|
|
return std::array<Address, N>{
|
|
{Address(CGF->Builder.CreateLoad(CGF->GetAddrOfLocalVar(Args[Ints])),
|
|
CGF->VoidPtrTy, Alignments[Ints], KnownNonNull)...}};
|
|
}
|
|
|
|
// Template classes that are used as bases for classes that emit special
|
|
// functions.
|
|
template <class Derived> struct GenFuncBase {
|
|
template <size_t N>
|
|
void visitStruct(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, N> Addrs) {
|
|
this->asDerived().callSpecialFunction(
|
|
FT, CurStructOffset + asDerived().getFieldOffset(FD), Addrs);
|
|
}
|
|
|
|
template <class FieldKind, size_t N>
|
|
void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile,
|
|
const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, N> Addrs) {
|
|
// Non-volatile trivial fields are copied when flushTrivialFields is called.
|
|
if (!FK)
|
|
return asDerived().visitTrivial(QualType(AT, 0), FD, CurStructOffset,
|
|
Addrs);
|
|
|
|
asDerived().flushTrivialFields(Addrs);
|
|
CodeGenFunction &CGF = *this->CGF;
|
|
ASTContext &Ctx = CGF.getContext();
|
|
|
|
// Compute the end address.
|
|
QualType BaseEltQT;
|
|
std::array<Address, N> StartAddrs = Addrs;
|
|
for (unsigned I = 0; I < N; ++I)
|
|
StartAddrs[I] = getAddrWithOffset(Addrs[I], CurStructOffset, FD);
|
|
Address DstAddr = StartAddrs[DstIdx];
|
|
llvm::Value *NumElts = CGF.emitArrayLength(AT, BaseEltQT, DstAddr);
|
|
unsigned BaseEltSize = Ctx.getTypeSizeInChars(BaseEltQT).getQuantity();
|
|
llvm::Value *BaseEltSizeVal =
|
|
llvm::ConstantInt::get(NumElts->getType(), BaseEltSize);
|
|
llvm::Value *SizeInBytes =
|
|
CGF.Builder.CreateNUWMul(BaseEltSizeVal, NumElts);
|
|
llvm::Value *DstArrayEnd = CGF.Builder.CreateInBoundsGEP(
|
|
CGF.Int8Ty, DstAddr.emitRawPointer(CGF), SizeInBytes);
|
|
llvm::BasicBlock *PreheaderBB = CGF.Builder.GetInsertBlock();
|
|
|
|
// Create the header block and insert the phi instructions.
|
|
llvm::BasicBlock *HeaderBB = CGF.createBasicBlock("loop.header");
|
|
CGF.EmitBlock(HeaderBB);
|
|
llvm::PHINode *PHIs[N];
|
|
|
|
for (unsigned I = 0; I < N; ++I) {
|
|
PHIs[I] = CGF.Builder.CreatePHI(CGF.CGM.Int8PtrPtrTy, 2, "addr.cur");
|
|
PHIs[I]->addIncoming(StartAddrs[I].emitRawPointer(CGF), PreheaderBB);
|
|
}
|
|
|
|
// Create the exit and loop body blocks.
|
|
llvm::BasicBlock *ExitBB = CGF.createBasicBlock("loop.exit");
|
|
llvm::BasicBlock *LoopBB = CGF.createBasicBlock("loop.body");
|
|
|
|
// Emit the comparison and conditional branch instruction that jumps to
|
|
// either the exit or the loop body.
|
|
llvm::Value *Done =
|
|
CGF.Builder.CreateICmpEQ(PHIs[DstIdx], DstArrayEnd, "done");
|
|
CGF.Builder.CreateCondBr(Done, ExitBB, LoopBB);
|
|
|
|
// Visit the element of the array in the loop body.
|
|
CGF.EmitBlock(LoopBB);
|
|
QualType EltQT = AT->getElementType();
|
|
CharUnits EltSize = Ctx.getTypeSizeInChars(EltQT);
|
|
std::array<Address, N> NewAddrs = Addrs;
|
|
|
|
for (unsigned I = 0; I < N; ++I)
|
|
NewAddrs[I] =
|
|
Address(PHIs[I], CGF.Int8PtrTy,
|
|
StartAddrs[I].getAlignment().alignmentAtOffset(EltSize));
|
|
|
|
EltQT = IsVolatile ? EltQT.withVolatile() : EltQT;
|
|
this->asDerived().visitWithKind(FK, EltQT, nullptr, CharUnits::Zero(),
|
|
NewAddrs);
|
|
|
|
LoopBB = CGF.Builder.GetInsertBlock();
|
|
|
|
for (unsigned I = 0; I < N; ++I) {
|
|
// Instrs to update the destination and source addresses.
|
|
// Update phi instructions.
|
|
NewAddrs[I] = getAddrWithOffset(NewAddrs[I], EltSize);
|
|
PHIs[I]->addIncoming(NewAddrs[I].emitRawPointer(CGF), LoopBB);
|
|
}
|
|
|
|
// Insert an unconditional branch to the header block.
|
|
CGF.Builder.CreateBr(HeaderBB);
|
|
CGF.EmitBlock(ExitBB);
|
|
}
|
|
|
|
/// Return an address with the specified offset from the passed address.
|
|
Address getAddrWithOffset(Address Addr, CharUnits Offset) {
|
|
assert(Addr.isValid() && "invalid address");
|
|
if (Offset.getQuantity() == 0)
|
|
return Addr;
|
|
Addr = Addr.withElementType(CGF->CGM.Int8Ty);
|
|
Addr = CGF->Builder.CreateConstInBoundsGEP(Addr, Offset.getQuantity());
|
|
return Addr.withElementType(CGF->CGM.Int8PtrTy);
|
|
}
|
|
|
|
Address getAddrWithOffset(Address Addr, CharUnits StructFieldOffset,
|
|
const FieldDecl *FD) {
|
|
return getAddrWithOffset(Addr, StructFieldOffset +
|
|
asDerived().getFieldOffset(FD));
|
|
}
|
|
|
|
template <size_t N>
|
|
llvm::Function *getFunction(StringRef FuncName, QualType QT,
|
|
std::array<CharUnits, N> Alignments,
|
|
CodeGenModule &CGM) {
|
|
// If the special function already exists in the module, return it.
|
|
if (llvm::Function *F = CGM.getModule().getFunction(FuncName)) {
|
|
bool WrongType = false;
|
|
if (!F->getReturnType()->isVoidTy())
|
|
WrongType = true;
|
|
else {
|
|
for (const llvm::Argument &Arg : F->args())
|
|
if (Arg.getType() != CGM.Int8PtrPtrTy)
|
|
WrongType = true;
|
|
}
|
|
|
|
if (WrongType) {
|
|
std::string FuncName = std::string(F->getName());
|
|
SourceLocation Loc =
|
|
QT->castAs<RecordType>()->getOriginalDecl()->getLocation();
|
|
CGM.Error(Loc, "special function " + FuncName +
|
|
" for non-trivial C struct has incorrect type");
|
|
return nullptr;
|
|
}
|
|
return F;
|
|
}
|
|
|
|
ASTContext &Ctx = CGM.getContext();
|
|
FunctionArgList Args;
|
|
const CGFunctionInfo &FI = getFunctionInfo<N>(CGM, Args);
|
|
llvm::FunctionType *FuncTy = CGM.getTypes().GetFunctionType(FI);
|
|
llvm::Function *F =
|
|
llvm::Function::Create(FuncTy, llvm::GlobalValue::LinkOnceODRLinkage,
|
|
FuncName, &CGM.getModule());
|
|
F->setVisibility(llvm::GlobalValue::HiddenVisibility);
|
|
CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, F, /*IsThunk=*/false);
|
|
CGM.SetLLVMFunctionAttributesForDefinition(nullptr, F);
|
|
CodeGenFunction NewCGF(CGM);
|
|
setCGF(&NewCGF);
|
|
CGF->StartFunction(GlobalDecl(), Ctx.VoidTy, F, FI, Args);
|
|
auto AL = ApplyDebugLocation::CreateArtificial(*CGF);
|
|
std::array<Address, N> Addrs =
|
|
getParamAddrs<N>(std::make_index_sequence<N>{}, Alignments, Args, CGF);
|
|
asDerived().visitStructFields(QT, CharUnits::Zero(), Addrs);
|
|
CGF->FinishFunction();
|
|
return F;
|
|
}
|
|
|
|
template <size_t N>
|
|
void callFunc(StringRef FuncName, QualType QT, std::array<Address, N> Addrs,
|
|
CodeGenFunction &CallerCGF) {
|
|
std::array<CharUnits, N> Alignments;
|
|
llvm::Value *Ptrs[N];
|
|
|
|
for (unsigned I = 0; I < N; ++I) {
|
|
Alignments[I] = Addrs[I].getAlignment();
|
|
Ptrs[I] = Addrs[I].emitRawPointer(CallerCGF);
|
|
}
|
|
|
|
if (llvm::Function *F =
|
|
getFunction(FuncName, QT, Alignments, CallerCGF.CGM))
|
|
CallerCGF.EmitNounwindRuntimeCall(F, Ptrs);
|
|
}
|
|
|
|
Derived &asDerived() { return static_cast<Derived &>(*this); }
|
|
|
|
void setCGF(CodeGenFunction *F) { CGF = F; }
|
|
|
|
CodeGenFunction *CGF = nullptr;
|
|
};
|
|
|
|
template <class Derived, bool IsMove>
|
|
struct GenBinaryFunc : CopyStructVisitor<Derived, IsMove>,
|
|
GenFuncBase<Derived> {
|
|
GenBinaryFunc(ASTContext &Ctx) : CopyStructVisitor<Derived, IsMove>(Ctx) {}
|
|
|
|
void flushTrivialFields(std::array<Address, 2> Addrs) {
|
|
CharUnits Size = this->End - this->Start;
|
|
|
|
if (Size.getQuantity() == 0)
|
|
return;
|
|
|
|
Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], this->Start);
|
|
Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], this->Start);
|
|
|
|
// Emit memcpy.
|
|
if (Size.getQuantity() >= 16 ||
|
|
!llvm::has_single_bit<uint32_t>(Size.getQuantity())) {
|
|
llvm::Value *SizeVal =
|
|
llvm::ConstantInt::get(this->CGF->SizeTy, Size.getQuantity());
|
|
DstAddr = DstAddr.withElementType(this->CGF->Int8Ty);
|
|
SrcAddr = SrcAddr.withElementType(this->CGF->Int8Ty);
|
|
this->CGF->Builder.CreateMemCpy(DstAddr, SrcAddr, SizeVal, false);
|
|
} else {
|
|
llvm::Type *Ty = llvm::Type::getIntNTy(
|
|
this->CGF->getLLVMContext(),
|
|
Size.getQuantity() * this->CGF->getContext().getCharWidth());
|
|
DstAddr = DstAddr.withElementType(Ty);
|
|
SrcAddr = SrcAddr.withElementType(Ty);
|
|
llvm::Value *SrcVal = this->CGF->Builder.CreateLoad(SrcAddr, false);
|
|
this->CGF->Builder.CreateStore(SrcVal, DstAddr, false);
|
|
}
|
|
|
|
this->Start = this->End = CharUnits::Zero();
|
|
}
|
|
|
|
template <class... Ts>
|
|
void visitVolatileTrivial(QualType FT, const FieldDecl *FD, CharUnits Offset,
|
|
std::array<Address, 2> Addrs) {
|
|
LValue DstLV, SrcLV;
|
|
if (FD) {
|
|
// No need to copy zero-length bit-fields.
|
|
if (FD->isZeroLengthBitField())
|
|
return;
|
|
|
|
CanQualType RT =
|
|
this->CGF->getContext().getCanonicalTagType(FD->getParent());
|
|
llvm::Type *Ty = this->CGF->ConvertType(RT);
|
|
Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], Offset);
|
|
LValue DstBase =
|
|
this->CGF->MakeAddrLValue(DstAddr.withElementType(Ty), FT);
|
|
DstLV = this->CGF->EmitLValueForField(DstBase, FD);
|
|
Address SrcAddr = this->getAddrWithOffset(Addrs[SrcIdx], Offset);
|
|
LValue SrcBase =
|
|
this->CGF->MakeAddrLValue(SrcAddr.withElementType(Ty), FT);
|
|
SrcLV = this->CGF->EmitLValueForField(SrcBase, FD);
|
|
} else {
|
|
llvm::Type *Ty = this->CGF->ConvertTypeForMem(FT);
|
|
Address DstAddr = Addrs[DstIdx].withElementType(Ty);
|
|
Address SrcAddr = Addrs[SrcIdx].withElementType(Ty);
|
|
DstLV = this->CGF->MakeAddrLValue(DstAddr, FT);
|
|
SrcLV = this->CGF->MakeAddrLValue(SrcAddr, FT);
|
|
}
|
|
RValue SrcVal = this->CGF->EmitLoadOfLValue(SrcLV, SourceLocation());
|
|
this->CGF->EmitStoreThroughLValue(SrcVal, DstLV);
|
|
}
|
|
void visitPtrAuth(QualType FT, const FieldDecl *FD, CharUnits CurStackOffset,
|
|
std::array<Address, 2> Addrs) {
|
|
PointerAuthQualifier PtrAuth = FT.getPointerAuth().withoutKeyNone();
|
|
Addrs[DstIdx] = this->getAddrWithOffset(Addrs[DstIdx], CurStackOffset, FD);
|
|
Addrs[SrcIdx] = this->getAddrWithOffset(Addrs[SrcIdx], CurStackOffset, FD);
|
|
this->CGF->EmitPointerAuthCopy(PtrAuth, FT, Addrs[DstIdx], Addrs[SrcIdx]);
|
|
}
|
|
};
|
|
|
|
// These classes that emit the special functions for a non-trivial struct.
|
|
struct GenDestructor : StructVisitor<GenDestructor>,
|
|
GenFuncBase<GenDestructor>,
|
|
DestructedTypeVisitor<GenDestructor> {
|
|
using Super = DestructedTypeVisitor<GenDestructor>;
|
|
GenDestructor(ASTContext &Ctx) : StructVisitor<GenDestructor>(Ctx) {}
|
|
|
|
void visitWithKind(QualType::DestructionKind DK, QualType FT,
|
|
const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, 1> Addrs) {
|
|
if (const auto *AT = getContext().getAsArrayType(FT)) {
|
|
visitArray(DK, AT, FT.isVolatileQualified(), FD, CurStructOffset, Addrs);
|
|
return;
|
|
}
|
|
|
|
Super::visitWithKind(DK, FT, FD, CurStructOffset, Addrs);
|
|
}
|
|
|
|
void visitARCStrong(QualType QT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset, std::array<Address, 1> Addrs) {
|
|
CGF->destroyARCStrongImprecise(
|
|
*CGF, getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT);
|
|
}
|
|
|
|
void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, 1> Addrs) {
|
|
CGF->destroyARCWeak(
|
|
*CGF, getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT);
|
|
}
|
|
|
|
void callSpecialFunction(QualType FT, CharUnits Offset,
|
|
std::array<Address, 1> Addrs) {
|
|
CGF->callCStructDestructor(
|
|
CGF->MakeAddrLValue(getAddrWithOffset(Addrs[DstIdx], Offset), FT));
|
|
}
|
|
};
|
|
|
|
struct GenDefaultInitialize
|
|
: StructVisitor<GenDefaultInitialize>,
|
|
GenFuncBase<GenDefaultInitialize>,
|
|
DefaultInitializedTypeVisitor<GenDefaultInitialize> {
|
|
using Super = DefaultInitializedTypeVisitor<GenDefaultInitialize>;
|
|
typedef GenFuncBase<GenDefaultInitialize> GenFuncBaseTy;
|
|
|
|
GenDefaultInitialize(ASTContext &Ctx)
|
|
: StructVisitor<GenDefaultInitialize>(Ctx) {}
|
|
|
|
void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT,
|
|
const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, 1> Addrs) {
|
|
if (const auto *AT = getContext().getAsArrayType(FT)) {
|
|
visitArray(PDIK, AT, FT.isVolatileQualified(), FD, CurStructOffset,
|
|
Addrs);
|
|
return;
|
|
}
|
|
|
|
Super::visitWithKind(PDIK, FT, FD, CurStructOffset, Addrs);
|
|
}
|
|
|
|
void visitARCStrong(QualType QT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset, std::array<Address, 1> Addrs) {
|
|
CGF->EmitNullInitialization(
|
|
getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT);
|
|
}
|
|
|
|
void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, 1> Addrs) {
|
|
CGF->EmitNullInitialization(
|
|
getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD), QT);
|
|
}
|
|
|
|
template <class FieldKind, size_t... Is>
|
|
void visitArray(FieldKind FK, const ArrayType *AT, bool IsVolatile,
|
|
const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, 1> Addrs) {
|
|
if (!FK)
|
|
return visitTrivial(QualType(AT, 0), FD, CurStructOffset, Addrs);
|
|
|
|
ASTContext &Ctx = getContext();
|
|
CharUnits Size = Ctx.getTypeSizeInChars(QualType(AT, 0));
|
|
QualType EltTy = Ctx.getBaseElementType(QualType(AT, 0));
|
|
|
|
if (Size < CharUnits::fromQuantity(16) || EltTy->getAs<RecordType>()) {
|
|
GenFuncBaseTy::visitArray(FK, AT, IsVolatile, FD, CurStructOffset, Addrs);
|
|
return;
|
|
}
|
|
|
|
llvm::Constant *SizeVal = CGF->Builder.getInt64(Size.getQuantity());
|
|
Address DstAddr = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);
|
|
Address Loc = DstAddr.withElementType(CGF->Int8Ty);
|
|
CGF->Builder.CreateMemSet(Loc, CGF->Builder.getInt8(0), SizeVal,
|
|
IsVolatile);
|
|
}
|
|
|
|
void callSpecialFunction(QualType FT, CharUnits Offset,
|
|
std::array<Address, 1> Addrs) {
|
|
CGF->callCStructDefaultConstructor(
|
|
CGF->MakeAddrLValue(getAddrWithOffset(Addrs[DstIdx], Offset), FT));
|
|
}
|
|
};
|
|
|
|
struct GenCopyConstructor : GenBinaryFunc<GenCopyConstructor, false> {
|
|
GenCopyConstructor(ASTContext &Ctx)
|
|
: GenBinaryFunc<GenCopyConstructor, false>(Ctx) {}
|
|
|
|
void visitARCStrong(QualType QT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset, std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);
|
|
llvm::Value *SrcVal = CGF->EmitLoadOfScalar(
|
|
Addrs[SrcIdx], QT.isVolatileQualified(), QT, SourceLocation());
|
|
llvm::Value *Val = CGF->EmitARCRetain(QT, SrcVal);
|
|
CGF->EmitStoreOfScalar(Val, CGF->MakeAddrLValue(Addrs[DstIdx], QT), true);
|
|
}
|
|
|
|
void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);
|
|
CGF->EmitARCCopyWeak(Addrs[DstIdx], Addrs[SrcIdx]);
|
|
}
|
|
|
|
void callSpecialFunction(QualType FT, CharUnits Offset,
|
|
std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset);
|
|
CGF->callCStructCopyConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT),
|
|
CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
|
|
}
|
|
};
|
|
|
|
struct GenMoveConstructor : GenBinaryFunc<GenMoveConstructor, true> {
|
|
GenMoveConstructor(ASTContext &Ctx)
|
|
: GenBinaryFunc<GenMoveConstructor, true>(Ctx) {}
|
|
|
|
void visitARCStrong(QualType QT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset, std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);
|
|
LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT);
|
|
llvm::Value *SrcVal =
|
|
CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();
|
|
CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);
|
|
CGF->EmitStoreOfScalar(SrcVal, CGF->MakeAddrLValue(Addrs[DstIdx], QT),
|
|
/* isInitialization */ true);
|
|
}
|
|
|
|
void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);
|
|
CGF->EmitARCMoveWeak(Addrs[DstIdx], Addrs[SrcIdx]);
|
|
}
|
|
|
|
void callSpecialFunction(QualType FT, CharUnits Offset,
|
|
std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset);
|
|
CGF->callCStructMoveConstructor(CGF->MakeAddrLValue(Addrs[DstIdx], FT),
|
|
CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
|
|
}
|
|
};
|
|
|
|
struct GenCopyAssignment : GenBinaryFunc<GenCopyAssignment, false> {
|
|
GenCopyAssignment(ASTContext &Ctx)
|
|
: GenBinaryFunc<GenCopyAssignment, false>(Ctx) {}
|
|
|
|
void visitARCStrong(QualType QT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset, std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);
|
|
llvm::Value *SrcVal = CGF->EmitLoadOfScalar(
|
|
Addrs[SrcIdx], QT.isVolatileQualified(), QT, SourceLocation());
|
|
CGF->EmitARCStoreStrong(CGF->MakeAddrLValue(Addrs[DstIdx], QT), SrcVal,
|
|
false);
|
|
}
|
|
|
|
void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);
|
|
CGF->emitARCCopyAssignWeak(QT, Addrs[DstIdx], Addrs[SrcIdx]);
|
|
}
|
|
|
|
void callSpecialFunction(QualType FT, CharUnits Offset,
|
|
std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset);
|
|
CGF->callCStructCopyAssignmentOperator(
|
|
CGF->MakeAddrLValue(Addrs[DstIdx], FT),
|
|
CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
|
|
}
|
|
};
|
|
|
|
struct GenMoveAssignment : GenBinaryFunc<GenMoveAssignment, true> {
|
|
GenMoveAssignment(ASTContext &Ctx)
|
|
: GenBinaryFunc<GenMoveAssignment, true>(Ctx) {}
|
|
|
|
void visitARCStrong(QualType QT, const FieldDecl *FD,
|
|
CharUnits CurStructOffset, std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);
|
|
LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT);
|
|
llvm::Value *SrcVal =
|
|
CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal();
|
|
CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV);
|
|
LValue DstLV = CGF->MakeAddrLValue(Addrs[DstIdx], QT);
|
|
llvm::Value *DstVal =
|
|
CGF->EmitLoadOfLValue(DstLV, SourceLocation()).getScalarVal();
|
|
CGF->EmitStoreOfScalar(SrcVal, DstLV);
|
|
CGF->EmitARCRelease(DstVal, ARCImpreciseLifetime);
|
|
}
|
|
|
|
void visitARCWeak(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset,
|
|
std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], CurStructOffset, FD);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], CurStructOffset, FD);
|
|
CGF->emitARCMoveAssignWeak(QT, Addrs[DstIdx], Addrs[SrcIdx]);
|
|
}
|
|
|
|
void callSpecialFunction(QualType FT, CharUnits Offset,
|
|
std::array<Address, 2> Addrs) {
|
|
Addrs[DstIdx] = getAddrWithOffset(Addrs[DstIdx], Offset);
|
|
Addrs[SrcIdx] = getAddrWithOffset(Addrs[SrcIdx], Offset);
|
|
CGF->callCStructMoveAssignmentOperator(
|
|
CGF->MakeAddrLValue(Addrs[DstIdx], FT),
|
|
CGF->MakeAddrLValue(Addrs[SrcIdx], FT));
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
void CodeGenFunction::destroyNonTrivialCStruct(CodeGenFunction &CGF,
|
|
Address Addr, QualType Type) {
|
|
CGF.callCStructDestructor(CGF.MakeAddrLValue(Addr, Type));
|
|
}
|
|
|
|
// Default-initialize a variable that is a non-trivial struct or an array of
|
|
// such structure.
|
|
void CodeGenFunction::defaultInitNonTrivialCStructVar(LValue Dst) {
|
|
GenDefaultInitialize Gen(getContext());
|
|
Address DstPtr = Dst.getAddress().withElementType(CGM.Int8PtrTy);
|
|
Gen.setCGF(this);
|
|
QualType QT = Dst.getType();
|
|
QT = Dst.isVolatile() ? QT.withVolatile() : QT;
|
|
Gen.visit(QT, nullptr, CharUnits::Zero(), std::array<Address, 1>({{DstPtr}}));
|
|
}
|
|
|
|
template <class G, size_t N>
|
|
static void callSpecialFunction(G &&Gen, StringRef FuncName, QualType QT,
|
|
bool IsVolatile, CodeGenFunction &CGF,
|
|
std::array<Address, N> Addrs) {
|
|
auto SetArtificialLoc = ApplyDebugLocation::CreateArtificial(CGF);
|
|
for (unsigned I = 0; I < N; ++I)
|
|
Addrs[I] = Addrs[I].withElementType(CGF.CGM.Int8PtrTy);
|
|
QT = IsVolatile ? QT.withVolatile() : QT;
|
|
Gen.callFunc(FuncName, QT, Addrs, CGF);
|
|
}
|
|
|
|
template <class G, size_t N>
|
|
static llvm::Function *
|
|
getSpecialFunction(G &&Gen, StringRef FuncName, QualType QT, bool IsVolatile,
|
|
std::array<CharUnits, N> Alignments, CodeGenModule &CGM) {
|
|
QT = IsVolatile ? QT.withVolatile() : QT;
|
|
// The following call requires an array of addresses as arguments, but doesn't
|
|
// actually use them (it overwrites them with the addresses of the arguments
|
|
// of the created function).
|
|
return Gen.getFunction(FuncName, QT, Alignments, CGM);
|
|
}
|
|
|
|
// Functions to emit calls to the special functions of a non-trivial C struct.
|
|
void CodeGenFunction::callCStructDefaultConstructor(LValue Dst) {
|
|
bool IsVolatile = Dst.isVolatile();
|
|
Address DstPtr = Dst.getAddress();
|
|
QualType QT = Dst.getType();
|
|
GenDefaultInitializeFuncName GenName(DstPtr.getAlignment(), getContext());
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
callSpecialFunction(GenDefaultInitialize(getContext()), FuncName, QT,
|
|
IsVolatile, *this, std::array<Address, 1>({{DstPtr}}));
|
|
}
|
|
|
|
std::string CodeGenFunction::getNonTrivialCopyConstructorStr(
|
|
QualType QT, CharUnits Alignment, bool IsVolatile, ASTContext &Ctx) {
|
|
GenBinaryFuncName<false> GenName("", Alignment, Alignment, Ctx);
|
|
return GenName.getName(QT, IsVolatile);
|
|
}
|
|
|
|
std::string CodeGenFunction::getNonTrivialDestructorStr(QualType QT,
|
|
CharUnits Alignment,
|
|
bool IsVolatile,
|
|
ASTContext &Ctx) {
|
|
GenDestructorFuncName GenName("", Alignment, Ctx);
|
|
return GenName.getName(QT, IsVolatile);
|
|
}
|
|
|
|
void CodeGenFunction::callCStructDestructor(LValue Dst) {
|
|
bool IsVolatile = Dst.isVolatile();
|
|
Address DstPtr = Dst.getAddress();
|
|
QualType QT = Dst.getType();
|
|
GenDestructorFuncName GenName("__destructor_", DstPtr.getAlignment(),
|
|
getContext());
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
callSpecialFunction(GenDestructor(getContext()), FuncName, QT, IsVolatile,
|
|
*this, std::array<Address, 1>({{DstPtr}}));
|
|
}
|
|
|
|
void CodeGenFunction::callCStructCopyConstructor(LValue Dst, LValue Src) {
|
|
bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
|
|
Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
|
|
QualType QT = Dst.getType();
|
|
GenBinaryFuncName<false> GenName("__copy_constructor_", DstPtr.getAlignment(),
|
|
SrcPtr.getAlignment(), getContext());
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
callSpecialFunction(GenCopyConstructor(getContext()), FuncName, QT,
|
|
IsVolatile, *this,
|
|
std::array<Address, 2>({{DstPtr, SrcPtr}}));
|
|
}
|
|
|
|
void CodeGenFunction::callCStructCopyAssignmentOperator(LValue Dst, LValue Src
|
|
|
|
) {
|
|
bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
|
|
Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
|
|
QualType QT = Dst.getType();
|
|
GenBinaryFuncName<false> GenName("__copy_assignment_", DstPtr.getAlignment(),
|
|
SrcPtr.getAlignment(), getContext());
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
callSpecialFunction(GenCopyAssignment(getContext()), FuncName, QT, IsVolatile,
|
|
*this, std::array<Address, 2>({{DstPtr, SrcPtr}}));
|
|
}
|
|
|
|
void CodeGenFunction::callCStructMoveConstructor(LValue Dst, LValue Src) {
|
|
bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
|
|
Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
|
|
QualType QT = Dst.getType();
|
|
GenBinaryFuncName<true> GenName("__move_constructor_", DstPtr.getAlignment(),
|
|
SrcPtr.getAlignment(), getContext());
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
callSpecialFunction(GenMoveConstructor(getContext()), FuncName, QT,
|
|
IsVolatile, *this,
|
|
std::array<Address, 2>({{DstPtr, SrcPtr}}));
|
|
}
|
|
|
|
void CodeGenFunction::callCStructMoveAssignmentOperator(LValue Dst, LValue Src
|
|
|
|
) {
|
|
bool IsVolatile = Dst.isVolatile() || Src.isVolatile();
|
|
Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress();
|
|
QualType QT = Dst.getType();
|
|
GenBinaryFuncName<true> GenName("__move_assignment_", DstPtr.getAlignment(),
|
|
SrcPtr.getAlignment(), getContext());
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
callSpecialFunction(GenMoveAssignment(getContext()), FuncName, QT, IsVolatile,
|
|
*this, std::array<Address, 2>({{DstPtr, SrcPtr}}));
|
|
}
|
|
|
|
llvm::Function *clang::CodeGen::getNonTrivialCStructDefaultConstructor(
|
|
CodeGenModule &CGM, CharUnits DstAlignment, bool IsVolatile, QualType QT) {
|
|
ASTContext &Ctx = CGM.getContext();
|
|
GenDefaultInitializeFuncName GenName(DstAlignment, Ctx);
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
return getSpecialFunction(GenDefaultInitialize(Ctx), FuncName, QT, IsVolatile,
|
|
std::array<CharUnits, 1>({{DstAlignment}}), CGM);
|
|
}
|
|
|
|
llvm::Function *clang::CodeGen::getNonTrivialCStructCopyConstructor(
|
|
CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment,
|
|
bool IsVolatile, QualType QT) {
|
|
ASTContext &Ctx = CGM.getContext();
|
|
GenBinaryFuncName<false> GenName("__copy_constructor_", DstAlignment,
|
|
SrcAlignment, Ctx);
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
return getSpecialFunction(
|
|
GenCopyConstructor(Ctx), FuncName, QT, IsVolatile,
|
|
std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM);
|
|
}
|
|
|
|
llvm::Function *clang::CodeGen::getNonTrivialCStructMoveConstructor(
|
|
CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment,
|
|
bool IsVolatile, QualType QT) {
|
|
ASTContext &Ctx = CGM.getContext();
|
|
GenBinaryFuncName<true> GenName("__move_constructor_", DstAlignment,
|
|
SrcAlignment, Ctx);
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
return getSpecialFunction(
|
|
GenMoveConstructor(Ctx), FuncName, QT, IsVolatile,
|
|
std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM);
|
|
}
|
|
|
|
llvm::Function *clang::CodeGen::getNonTrivialCStructCopyAssignmentOperator(
|
|
CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment,
|
|
bool IsVolatile, QualType QT) {
|
|
ASTContext &Ctx = CGM.getContext();
|
|
GenBinaryFuncName<false> GenName("__copy_assignment_", DstAlignment,
|
|
SrcAlignment, Ctx);
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
return getSpecialFunction(
|
|
GenCopyAssignment(Ctx), FuncName, QT, IsVolatile,
|
|
std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM);
|
|
}
|
|
|
|
llvm::Function *clang::CodeGen::getNonTrivialCStructMoveAssignmentOperator(
|
|
CodeGenModule &CGM, CharUnits DstAlignment, CharUnits SrcAlignment,
|
|
bool IsVolatile, QualType QT) {
|
|
ASTContext &Ctx = CGM.getContext();
|
|
GenBinaryFuncName<true> GenName("__move_assignment_", DstAlignment,
|
|
SrcAlignment, Ctx);
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
return getSpecialFunction(
|
|
GenMoveAssignment(Ctx), FuncName, QT, IsVolatile,
|
|
std::array<CharUnits, 2>({{DstAlignment, SrcAlignment}}), CGM);
|
|
}
|
|
|
|
llvm::Function *clang::CodeGen::getNonTrivialCStructDestructor(
|
|
CodeGenModule &CGM, CharUnits DstAlignment, bool IsVolatile, QualType QT) {
|
|
ASTContext &Ctx = CGM.getContext();
|
|
GenDestructorFuncName GenName("__destructor_", DstAlignment, Ctx);
|
|
std::string FuncName = GenName.getName(QT, IsVolatile);
|
|
return getSpecialFunction(GenDestructor(Ctx), FuncName, QT, IsVolatile,
|
|
std::array<CharUnits, 1>({{DstAlignment}}), CGM);
|
|
}
|