#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/iterator.h"
using namespace clang;
namespace {
static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) {
const RecordType *RT = VD.getType()->getAs<RecordType>();
assert(RT && "type of VarDecl is expected to be RecordType.");
assert(RT->getDecl()->isUnion() && "RecordType is expected to be a union.");
if (const FieldDecl *FD = RT->getDecl()->findFirstNamedDataMember()) {
return FD->getIdentifier();
}
return nullptr;
}
struct DecompositionDeclName {
using BindingArray = ArrayRef<const BindingDecl*>;
BindingArray Bindings;
struct Iterator
: llvm::iterator_adaptor_base<Iterator, BindingArray::const_iterator,
std::random_access_iterator_tag,
const IdentifierInfo *> {
Iterator(BindingArray::const_iterator It) : iterator_adaptor_base(It) {}
const IdentifierInfo *operator*() const {
return (*this->I)->getIdentifier();
}
};
Iterator begin() const { return Iterator(Bindings.begin()); }
Iterator end() const { return Iterator(Bindings.end()); }
};
}
namespace llvm {
template<typename T> bool isDenseMapKeyEmpty(T V) {
return llvm::DenseMapInfo<T>::isEqual(
V, llvm::DenseMapInfo<T>::getEmptyKey());
}
template<typename T> bool isDenseMapKeyTombstone(T V) {
return llvm::DenseMapInfo<T>::isEqual(
V, llvm::DenseMapInfo<T>::getTombstoneKey());
}
template<typename T>
Optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {
bool LHSEmpty = isDenseMapKeyEmpty(LHS);
bool RHSEmpty = isDenseMapKeyEmpty(RHS);
if (LHSEmpty || RHSEmpty)
return LHSEmpty && RHSEmpty;
bool LHSTombstone = isDenseMapKeyTombstone(LHS);
bool RHSTombstone = isDenseMapKeyTombstone(RHS);
if (LHSTombstone || RHSTombstone)
return LHSTombstone && RHSTombstone;
return None;
}
template<>
struct DenseMapInfo<DecompositionDeclName> {
using ArrayInfo = llvm::DenseMapInfo<ArrayRef<const BindingDecl*>>;
static DecompositionDeclName getEmptyKey() {
return {ArrayInfo::getEmptyKey()};
}
static DecompositionDeclName getTombstoneKey() {
return {ArrayInfo::getTombstoneKey()};
}
static unsigned getHashValue(DecompositionDeclName Key) {
assert(!isEqual(Key, getEmptyKey()) && !isEqual(Key, getTombstoneKey()));
return llvm::hash_combine_range(Key.begin(), Key.end());
}
static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) {
if (Optional<bool> Result = areDenseMapKeysEqualSpecialValues(
LHS.Bindings, RHS.Bindings))
return *Result;
return LHS.Bindings.size() == RHS.Bindings.size() &&
std::equal(LHS.begin(), LHS.end(), RHS.begin());
}
};
}
namespace {
class ItaniumNumberingContext : public MangleNumberingContext {
ItaniumMangleContext *Mangler;
llvm::StringMap<unsigned> LambdaManglingNumbers;
unsigned BlockManglingNumber = 0;
llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers;
llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers;
llvm::DenseMap<DecompositionDeclName, unsigned>
DecompsitionDeclManglingNumbers;
public:
ItaniumNumberingContext(ItaniumMangleContext *Mangler) : Mangler(Mangler) {}
unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
const CXXRecordDecl *Lambda = CallOperator->getParent();
assert(Lambda->isLambda());
llvm::SmallString<128> LambdaSig;
llvm::raw_svector_ostream Out(LambdaSig);
Mangler->mangleLambdaSig(Lambda, Out);
return ++LambdaManglingNumbers[LambdaSig];
}
unsigned getManglingNumber(const BlockDecl *BD) override {
return ++BlockManglingNumber;
}
unsigned getStaticLocalNumber(const VarDecl *VD) override {
return 0;
}
unsigned getManglingNumber(const VarDecl *VD, unsigned) override {
if (auto *DD = dyn_cast<DecompositionDecl>(VD)) {
DecompositionDeclName Name{DD->bindings()};
return ++DecompsitionDeclManglingNumbers[Name];
}
const IdentifierInfo *Identifier = VD->getIdentifier();
if (!Identifier) {
Identifier = findAnonymousUnionVarDeclName(*VD);
}
return ++VarManglingNumbers[Identifier];
}
unsigned getManglingNumber(const TagDecl *TD, unsigned) override {
return ++TagManglingNumbers[TD->getIdentifier()];
}
};
class ItaniumSYCLNumberingContext : public ItaniumNumberingContext {
llvm::DenseMap<const CXXMethodDecl *, unsigned> ManglingNumbers;
using ManglingItr = decltype(ManglingNumbers)::iterator;
public:
ItaniumSYCLNumberingContext(ItaniumMangleContext *Mangler)
: ItaniumNumberingContext(Mangler) {}
unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
unsigned Number = ItaniumNumberingContext::getManglingNumber(CallOperator);
std::pair<ManglingItr, bool> emplace_result =
ManglingNumbers.try_emplace(CallOperator, Number);
(void)emplace_result;
assert(emplace_result.second && "Lambda number set multiple times?");
return Number;
}
using ItaniumNumberingContext::getManglingNumber;
unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override {
ManglingItr Itr = ManglingNumbers.find(CallOperator);
assert(Itr != ManglingNumbers.end() && "Lambda not yet mangled?");
return Itr->second;
}
};
class ItaniumCXXABI : public CXXABI {
private:
std::unique_ptr<MangleContext> Mangler;
protected:
ASTContext &Context;
public:
ItaniumCXXABI(ASTContext &Ctx)
: Mangler(Ctx.createMangleContext()), Context(Ctx) {}
MemberPointerInfo
getMemberPointerInfo(const MemberPointerType *MPT) const override {
const TargetInfo &Target = Context.getTargetInfo();
TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0);
MemberPointerInfo MPI;
MPI.Width = Target.getTypeWidth(PtrDiff);
MPI.Align = Target.getTypeAlign(PtrDiff);
MPI.HasPadding = false;
if (MPT->isMemberFunctionPointer())
MPI.Width *= 2;
return MPI;
}
CallingConv getDefaultMethodCallConv(bool isVariadic) const override {
const llvm::Triple &T = Context.getTargetInfo().getTriple();
if (!isVariadic && T.isWindowsGNUEnvironment() &&
T.getArch() == llvm::Triple::x86)
return CC_X86ThisCall;
return Context.getTargetInfo().getDefaultCallingConv();
}
bool isNearlyEmpty(const CXXRecordDecl *RD) const override {
if (!RD->isDynamicClass())
return false;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
CharUnits PointerSize =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
return Layout.getNonVirtualSize() == PointerSize;
}
const CXXConstructorDecl *
getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {
return nullptr;
}
void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
CXXConstructorDecl *CD) override {}
void addTypedefNameForUnnamedTagDecl(TagDecl *TD,
TypedefNameDecl *DD) override {}
TypedefNameDecl *getTypedefNameForUnnamedTagDecl(const TagDecl *TD) override {
return nullptr;
}
void addDeclaratorForUnnamedTagDecl(TagDecl *TD,
DeclaratorDecl *DD) override {}
DeclaratorDecl *getDeclaratorForUnnamedTagDecl(const TagDecl *TD) override {
return nullptr;
}
std::unique_ptr<MangleNumberingContext>
createMangleNumberingContext() const override {
if (Context.getLangOpts().isSYCL())
return std::make_unique<ItaniumSYCLNumberingContext>(
cast<ItaniumMangleContext>(Mangler.get()));
return std::make_unique<ItaniumNumberingContext>(
cast<ItaniumMangleContext>(Mangler.get()));
}
};
}
CXXABI *clang::CreateItaniumCXXABI(ASTContext &Ctx) {
return new ItaniumCXXABI(Ctx);
}
std::unique_ptr<MangleNumberingContext>
clang::createItaniumNumberingContext(MangleContext *Mangler) {
return std::make_unique<ItaniumNumberingContext>(
cast<ItaniumMangleContext>(Mangler));
}