teak-llvm/clang/lib/AST/DeclarationName.cpp
Bruno Ricci 366ba73018 [AST] Various optimizations + refactoring in DeclarationName(Table)
Introduce the following optimizations in DeclarationName(Table):

 1. Store common kinds inline in DeclarationName instead of
    DeclarationNameExtra. Currently the kind of C++ constructor, destructor,
    conversion function and overloaded operator names is stored in
    DeclarationNameExtra. Instead store it inline in DeclarationName.
    To do this align IdentifierInfo, CXXSpecialName, DeclarationNameExtra
    and CXXOperatorIdName to 8 bytes so that we can use the lower 3 bits of
    DeclarationName::Ptr. This is already the case on 64 bits archs anyway.
    This also allow us to remove DeclarationNameExtra from CXXSpecialName
    and CXXOperatorIdName, which shave off a pointer from CXXSpecialName. 

 2. Synchronize the enumerations DeclarationName::NameKind,
    DeclarationName::StoredNameKind and Selector::IdentifierInfoFlag.
    This makes DeclarationName::getNameKind much more efficient since we can
    replace the switch table by a single comparison and an addition.

 3. Put the overloaded operator names inline in DeclarationNameTable to remove
    an indirection. This increase the size of DeclarationNameTable a little
    bit but this is not important since it is only used in ASTContext, and
    never copied nor moved from. This also get rid of the last dynamic
    allocation in DeclarationNameTable.

Altogether these optimizations cut the run time of parsing all of Boost by
about 0.8%. While we are at it, do the following NFC modifications:

 1. Put the internal classes CXXSpecialName, CXXDeductionGuideNameExtra,
    CXXOperatorIdName, CXXLiteralOperatorIdName and DeclarationNameExtra
    in a namespace detail since these classes are only meant to be used by
    DeclarationName and DeclarationNameTable. Make this more explicit by making
    the members of these classes private and friending DeclarationName(Table).

 2. Make DeclarationName::getFETokenInfo a non-template since every users are
    using it to get a void *. It was supposed to be used with a type to avoid
    a subsequent static_cast.

 3. Change the internal functions DeclarationName::getAs* to castAs* since when
    we use them we already know the correct kind. This has no external impact
    since all of these are private.

Reviewed By: erichkeane, rjmccall

Differential Revision: https://reviews.llvm.org/D52267

llvm-svn: 342729
2018-09-21 12:53:22 +00:00

528 lines
17 KiB
C++

//===- DeclarationName.cpp - Declaration names implementation -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the DeclarationName and DeclarationNameTable
// classes.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <string>
using namespace clang;
static int compareInt(unsigned A, unsigned B) {
return (A < B ? -1 : (A > B ? 1 : 0));
}
int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
if (LHS.getNameKind() != RHS.getNameKind())
return (LHS.getNameKind() < RHS.getNameKind() ? -1 : 1);
switch (LHS.getNameKind()) {
case DeclarationName::Identifier: {
IdentifierInfo *LII = LHS.castAsIdentifierInfo();
IdentifierInfo *RII = RHS.castAsIdentifierInfo();
if (!LII)
return RII ? -1 : 0;
if (!RII)
return 1;
return LII->getName().compare(RII->getName());
}
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector: {
Selector LHSSelector = LHS.getObjCSelector();
Selector RHSSelector = RHS.getObjCSelector();
// getNumArgs for ZeroArgSelector returns 0, but we still need to compare.
if (LHS.getNameKind() == DeclarationName::ObjCZeroArgSelector &&
RHS.getNameKind() == DeclarationName::ObjCZeroArgSelector) {
return LHSSelector.getAsIdentifierInfo()->getName().compare(
RHSSelector.getAsIdentifierInfo()->getName());
}
unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs();
for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) {
switch (LHSSelector.getNameForSlot(I).compare(
RHSSelector.getNameForSlot(I))) {
case -1:
return -1;
case 1:
return 1;
default:
break;
}
}
return compareInt(LN, RN);
}
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
if (QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType()))
return -1;
if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType()))
return 1;
return 0;
case DeclarationName::CXXDeductionGuideName:
// We never want to compare deduction guide names for templates from
// different scopes, so just compare the template-name.
return compare(LHS.getCXXDeductionGuideTemplate()->getDeclName(),
RHS.getCXXDeductionGuideTemplate()->getDeclName());
case DeclarationName::CXXOperatorName:
return compareInt(LHS.getCXXOverloadedOperator(),
RHS.getCXXOverloadedOperator());
case DeclarationName::CXXLiteralOperatorName:
return LHS.getCXXLiteralIdentifier()->getName().compare(
RHS.getCXXLiteralIdentifier()->getName());
case DeclarationName::CXXUsingDirective:
return 0;
}
llvm_unreachable("Invalid DeclarationName Kind!");
}
static void printCXXConstructorDestructorName(QualType ClassType,
raw_ostream &OS,
PrintingPolicy Policy) {
// We know we're printing C++ here. Ensure we print types properly.
Policy.adjustForCPlusPlus();
if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) {
OS << *ClassRec->getDecl();
return;
}
if (Policy.SuppressTemplateArgsInCXXConstructors) {
if (auto *InjTy = ClassType->getAs<InjectedClassNameType>()) {
OS << *InjTy->getDecl();
return;
}
}
ClassType.print(OS, Policy);
}
void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) {
switch (getNameKind()) {
case DeclarationName::Identifier:
if (const IdentifierInfo *II = getAsIdentifierInfo())
OS << II->getName();
return;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
getObjCSelector().print(OS);
return;
case DeclarationName::CXXConstructorName:
return printCXXConstructorDestructorName(getCXXNameType(), OS, Policy);
case DeclarationName::CXXDestructorName:
OS << '~';
return printCXXConstructorDestructorName(getCXXNameType(), OS, Policy);
case DeclarationName::CXXDeductionGuideName:
OS << "<deduction guide for ";
getCXXDeductionGuideTemplate()->getDeclName().print(OS, Policy);
OS << '>';
return;
case DeclarationName::CXXOperatorName: {
static const char *const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
nullptr,
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
Spelling,
#include "clang/Basic/OperatorKinds.def"
};
const char *OpName = OperatorNames[getCXXOverloadedOperator()];
assert(OpName && "not an overloaded operator");
OS << "operator";
if (OpName[0] >= 'a' && OpName[0] <= 'z')
OS << ' ';
OS << OpName;
return;
}
case DeclarationName::CXXLiteralOperatorName:
OS << "operator\"\"" << getCXXLiteralIdentifier()->getName();
return;
case DeclarationName::CXXConversionFunctionName: {
OS << "operator ";
QualType Type = getCXXNameType();
if (const RecordType *Rec = Type->getAs<RecordType>()) {
OS << *Rec->getDecl();
return;
}
// We know we're printing C++ here, ensure we print 'bool' properly.
PrintingPolicy CXXPolicy = Policy;
CXXPolicy.adjustForCPlusPlus();
Type.print(OS, CXXPolicy);
return;
}
case DeclarationName::CXXUsingDirective:
OS << "<using-directive>";
return;
}
llvm_unreachable("Unexpected declaration name kind");
}
namespace clang {
raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) {
LangOptions LO;
N.print(OS, PrintingPolicy(LO));
return OS;
}
} // namespace clang
bool DeclarationName::isDependentName() const {
QualType T = getCXXNameType();
if (!T.isNull() && T->isDependentType())
return true;
// A class-scope deduction guide in a dependent context has a dependent name.
auto *TD = getCXXDeductionGuideTemplate();
if (TD && TD->getDeclContext()->isDependentContext())
return true;
return false;
}
std::string DeclarationName::getAsString() const {
std::string Result;
llvm::raw_string_ostream OS(Result);
OS << *this;
return OS.str();
}
void *DeclarationName::getFETokenInfoSlow() const {
switch (getNameKind()) {
case Identifier:
llvm_unreachable("case Identifier already handled by getFETokenInfo!");
case CXXConstructorName:
case CXXDestructorName:
case CXXConversionFunctionName:
return castAsCXXSpecialNameExtra()->FETokenInfo;
case CXXOperatorName:
return castAsCXXOperatorIdName()->FETokenInfo;
case CXXDeductionGuideName:
return castAsCXXDeductionGuideNameExtra()->FETokenInfo;
case CXXLiteralOperatorName:
return castAsCXXLiteralOperatorIdName()->FETokenInfo;
default:
llvm_unreachable("DeclarationName has no FETokenInfo!");
}
}
void DeclarationName::setFETokenInfoSlow(void *T) {
switch (getNameKind()) {
case Identifier:
llvm_unreachable("case Identifier already handled by setFETokenInfo!");
case CXXConstructorName:
case CXXDestructorName:
case CXXConversionFunctionName:
castAsCXXSpecialNameExtra()->FETokenInfo = T;
break;
case CXXOperatorName:
castAsCXXOperatorIdName()->FETokenInfo = T;
break;
case CXXDeductionGuideName:
castAsCXXDeductionGuideNameExtra()->FETokenInfo = T;
break;
case CXXLiteralOperatorName:
castAsCXXLiteralOperatorIdName()->FETokenInfo = T;
break;
default:
llvm_unreachable("DeclarationName has no FETokenInfo!");
}
}
LLVM_DUMP_METHOD void DeclarationName::dump() const {
llvm::errs() << *this << '\n';
}
DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
// Initialize the overloaded operator names.
for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op)
CXXOperatorNames[Op].Kind = static_cast<OverloadedOperatorKind>(Op);
}
DeclarationName
DeclarationNameTable::getCXXDeductionGuideName(TemplateDecl *Template) {
Template = cast<TemplateDecl>(Template->getCanonicalDecl());
llvm::FoldingSetNodeID ID;
ID.AddPointer(Template);
void *InsertPos = nullptr;
if (auto *Name = CXXDeductionGuideNames.FindNodeOrInsertPos(ID, InsertPos))
return DeclarationName(Name);
auto *Name = new (Ctx) detail::CXXDeductionGuideNameExtra(Template);
CXXDeductionGuideNames.InsertNode(Name, InsertPos);
return DeclarationName(Name);
}
DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) {
// The type of constructors is unqualified.
Ty = Ty.getUnqualifiedType();
// Do we already have this C++ constructor name ?
llvm::FoldingSetNodeID ID;
ID.AddPointer(Ty.getAsOpaquePtr());
void *InsertPos = nullptr;
if (auto *Name = CXXConstructorNames.FindNodeOrInsertPos(ID, InsertPos))
return {Name, DeclarationName::StoredCXXConstructorName};
// We have to create it.
auto *SpecialName = new (Ctx) detail::CXXSpecialNameExtra(Ty);
CXXConstructorNames.InsertNode(SpecialName, InsertPos);
return {SpecialName, DeclarationName::StoredCXXConstructorName};
}
DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) {
// The type of destructors is unqualified.
Ty = Ty.getUnqualifiedType();
// Do we already have this C++ destructor name ?
llvm::FoldingSetNodeID ID;
ID.AddPointer(Ty.getAsOpaquePtr());
void *InsertPos = nullptr;
if (auto *Name = CXXDestructorNames.FindNodeOrInsertPos(ID, InsertPos))
return {Name, DeclarationName::StoredCXXDestructorName};
// We have to create it.
auto *SpecialName = new (Ctx) detail::CXXSpecialNameExtra(Ty);
CXXDestructorNames.InsertNode(SpecialName, InsertPos);
return {SpecialName, DeclarationName::StoredCXXDestructorName};
}
DeclarationName
DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) {
// Do we already have this C++ conversion function name ?
llvm::FoldingSetNodeID ID;
ID.AddPointer(Ty.getAsOpaquePtr());
void *InsertPos = nullptr;
if (auto *Name =
CXXConversionFunctionNames.FindNodeOrInsertPos(ID, InsertPos))
return {Name, DeclarationName::StoredCXXConversionFunctionName};
// We have to create it.
auto *SpecialName = new (Ctx) detail::CXXSpecialNameExtra(Ty);
CXXConversionFunctionNames.InsertNode(SpecialName, InsertPos);
return {SpecialName, DeclarationName::StoredCXXConversionFunctionName};
}
DeclarationName
DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
CanQualType Ty) {
switch (Kind) {
case DeclarationName::CXXConstructorName:
return getCXXConstructorName(Ty);
case DeclarationName::CXXDestructorName:
return getCXXDestructorName(Ty);
case DeclarationName::CXXConversionFunctionName:
return getCXXConversionFunctionName(Ty);
default:
llvm_unreachable("Invalid kind in getCXXSpecialName!");
}
}
DeclarationName
DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
llvm::FoldingSetNodeID ID;
ID.AddPointer(II);
void *InsertPos = nullptr;
if (auto *Name = CXXLiteralOperatorNames.FindNodeOrInsertPos(ID, InsertPos))
return DeclarationName(Name);
auto *LiteralName = new (Ctx) detail::CXXLiteralOperatorIdName(II);
CXXLiteralOperatorNames.InsertNode(LiteralName, InsertPos);
return DeclarationName(LiteralName);
}
DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) {
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
case DeclarationName::CXXDeductionGuideName:
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
NamedType.TInfo = nullptr;
break;
case DeclarationName::CXXOperatorName:
CXXOperatorName.BeginOpNameLoc = SourceLocation().getRawEncoding();
CXXOperatorName.EndOpNameLoc = SourceLocation().getRawEncoding();
break;
case DeclarationName::CXXLiteralOperatorName:
CXXLiteralOperatorName.OpNameLoc = SourceLocation().getRawEncoding();
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
// FIXME: ?
break;
case DeclarationName::CXXUsingDirective:
break;
}
}
bool DeclarationNameInfo::containsUnexpandedParameterPack() const {
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
case DeclarationName::CXXDeductionGuideName:
return false;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo)
return TInfo->getType()->containsUnexpandedParameterPack();
return Name.getCXXNameType()->containsUnexpandedParameterPack();
}
llvm_unreachable("All name kinds handled.");
}
bool DeclarationNameInfo::isInstantiationDependent() const {
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
case DeclarationName::CXXDeductionGuideName:
return false;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo)
return TInfo->getType()->isInstantiationDependentType();
return Name.getCXXNameType()->isInstantiationDependentType();
}
llvm_unreachable("All name kinds handled.");
}
std::string DeclarationNameInfo::getAsString() const {
std::string Result;
llvm::raw_string_ostream OS(Result);
printName(OS);
return OS.str();
}
void DeclarationNameInfo::printName(raw_ostream &OS) const {
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
case DeclarationName::CXXDeductionGuideName:
OS << Name;
return;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) {
if (Name.getNameKind() == DeclarationName::CXXDestructorName)
OS << '~';
else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
OS << "operator ";
LangOptions LO;
LO.CPlusPlus = true;
LO.Bool = true;
PrintingPolicy PP(LO);
PP.SuppressScope = true;
OS << TInfo->getType().getAsString(PP);
} else
OS << Name;
return;
}
llvm_unreachable("Unexpected declaration name kind");
}
SourceLocation DeclarationNameInfo::getEndLocPrivate() const {
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
case DeclarationName::CXXDeductionGuideName:
return NameLoc;
case DeclarationName::CXXOperatorName: {
unsigned raw = LocInfo.CXXOperatorName.EndOpNameLoc;
return SourceLocation::getFromRawEncoding(raw);
}
case DeclarationName::CXXLiteralOperatorName: {
unsigned raw = LocInfo.CXXLiteralOperatorName.OpNameLoc;
return SourceLocation::getFromRawEncoding(raw);
}
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo)
return TInfo->getTypeLoc().getEndLoc();
else
return NameLoc;
// DNInfo work in progress: FIXME.
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXUsingDirective:
return NameLoc;
}
llvm_unreachable("Unexpected declaration name kind");
}