[AST] Pack CXXDependentScopeMemberExpr

Use the newly available space in the bit-fields of Stmt. Additionally store
FirstQualifierFoundInScope as a trailing object since it is most of the time
null (non-null for 2 of the 35446 CXXDependentScopeMemberExpr when parsing
all of Boost).

It would be possible to move the data for the nested-name-specifier to a
trailing object too to save another 2 pointers, however doing so did actually
regress the time taken to parse all of Boost slightly.

This saves 8 bytes + 1 pointer per CXXDependentScopeMemberExpr in the vast
majority of cases.

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

Reviewed By: rjmccall

llvm-svn: 350625
This commit is contained in:
Bruno Ricci 2019-01-08 14:17:00 +00:00
parent efb5ad1c58
commit 2e6dc538be
5 changed files with 189 additions and 128 deletions

View File

@ -3306,7 +3306,11 @@ class CXXDependentScopeMemberExpr final
: public Expr,
private llvm::TrailingObjects<CXXDependentScopeMemberExpr,
ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc> {
TemplateArgumentLoc, NamedDecl *> {
friend class ASTStmtReader;
friend class ASTStmtWriter;
friend TrailingObjects;
/// The expression for the base pointer or class reference,
/// e.g., the \c x in x.f. Can be null in implicit accesses.
Stmt *Base;
@ -3315,40 +3319,53 @@ class CXXDependentScopeMemberExpr final
/// implicit accesses.
QualType BaseType;
/// Whether this member expression used the '->' operator or
/// the '.' operator.
bool IsArrow : 1;
/// Whether this member expression has info for explicit template
/// keyword and arguments.
bool HasTemplateKWAndArgsInfo : 1;
/// The location of the '->' or '.' operator.
SourceLocation OperatorLoc;
/// The nested-name-specifier that precedes the member name, if any.
/// FIXME: This could be in principle store as a trailing object.
/// However the performance impact of doing so should be investigated first.
NestedNameSpecifierLoc QualifierLoc;
/// In a qualified member access expression such as t->Base::f, this
/// member stores the resolves of name lookup in the context of the member
/// access expression, to be used at instantiation time.
///
/// FIXME: This member, along with the QualifierLoc, could
/// be stuck into a structure that is optionally allocated at the end of
/// the CXXDependentScopeMemberExpr, to save space in the common case.
NamedDecl *FirstQualifierFoundInScope;
/// The member to which this member expression refers, which
/// can be name, overloaded operator, or destructor.
///
/// FIXME: could also be a template-id
DeclarationNameInfo MemberNameInfo;
size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
return HasTemplateKWAndArgsInfo ? 1 : 0;
// CXXDependentScopeMemberExpr is followed by several trailing objects,
// some of which optional. They are in order:
//
// * An optional ASTTemplateKWAndArgsInfo for the explicitly specified
// template keyword and arguments. Present if and only if
// hasTemplateKWAndArgsInfo().
//
// * An array of getNumTemplateArgs() TemplateArgumentLoc containing location
// information for the explicitly specified template arguments.
//
// * An optional NamedDecl *. In a qualified member access expression such
// as t->Base::f, this member stores the resolves of name lookup in the
// context of the member access expression, to be used at instantiation
// time. Present if and only if hasFirstQualifierFoundInScope().
bool hasTemplateKWAndArgsInfo() const {
return CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo;
}
CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base,
bool hasFirstQualifierFoundInScope() const {
return CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope;
}
unsigned numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
return hasTemplateKWAndArgsInfo();
}
unsigned numTrailingObjects(OverloadToken<TemplateArgumentLoc>) const {
return getNumTemplateArgs();
}
unsigned numTrailingObjects(OverloadToken<NamedDecl *>) const {
return hasFirstQualifierFoundInScope();
}
CXXDependentScopeMemberExpr(const ASTContext &Ctx, Expr *Base,
QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
@ -3357,33 +3374,29 @@ class CXXDependentScopeMemberExpr final
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
CXXDependentScopeMemberExpr(EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
bool HasFirstQualifierFoundInScope);
public:
friend class ASTStmtReader;
friend class ASTStmtWriter;
friend TrailingObjects;
CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base,
QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo);
static CXXDependentScopeMemberExpr *
Create(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow,
Create(const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs);
static CXXDependentScopeMemberExpr *
CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs);
CreateEmpty(const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope);
/// True if this is an implicit access, i.e. one in which the
/// member being accessed was not written in the source. The source
/// location of the operator is invalid in this case.
bool isImplicitAccess() const;
bool isImplicitAccess() const {
if (!Base)
return true;
return cast<Expr>(Base)->isImplicitCXXThis();
}
/// Retrieve the base object of this member expressions,
/// e.g., the \c x in \c x.m.
@ -3396,13 +3409,14 @@ public:
/// Determine whether this member expression used the '->'
/// operator; otherwise, it used the '.' operator.
bool isArrow() const { return IsArrow; }
bool isArrow() const { return CXXDependentScopeMemberExprBits.IsArrow; }
/// Retrieve the location of the '->' or '.' operator.
SourceLocation getOperatorLoc() const { return OperatorLoc; }
SourceLocation getOperatorLoc() const {
return CXXDependentScopeMemberExprBits.OperatorLoc;
}
/// Retrieve the nested-name-specifier that qualifies the member
/// name.
/// Retrieve the nested-name-specifier that qualifies the member name.
NestedNameSpecifier *getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
@ -3423,17 +3437,17 @@ public:
/// combined with the results of name lookup into the type of the object
/// expression itself (the class type of x).
NamedDecl *getFirstQualifierFoundInScope() const {
return FirstQualifierFoundInScope;
if (!hasFirstQualifierFoundInScope())
return nullptr;
return *getTrailingObjects<NamedDecl *>();
}
/// Retrieve the name of the member that this expression
/// refers to.
/// Retrieve the name of the member that this expression refers to.
const DeclarationNameInfo &getMemberNameInfo() const {
return MemberNameInfo;
}
/// Retrieve the name of the member that this expression
/// refers to.
/// Retrieve the name of the member that this expression refers to.
DeclarationName getMember() const { return MemberNameInfo.getName(); }
// Retrieve the location of the name of the member that this
@ -3443,21 +3457,24 @@ public:
/// Retrieve the location of the template keyword preceding the
/// member name, if any.
SourceLocation getTemplateKeywordLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
if (!hasTemplateKWAndArgsInfo())
return SourceLocation();
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->TemplateKWLoc;
}
/// Retrieve the location of the left angle bracket starting the
/// explicit template argument list following the member name, if any.
SourceLocation getLAngleLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
if (!hasTemplateKWAndArgsInfo())
return SourceLocation();
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->LAngleLoc;
}
/// Retrieve the location of the right angle bracket ending the
/// explicit template argument list following the member name, if any.
SourceLocation getRAngleLoc() const {
if (!HasTemplateKWAndArgsInfo) return SourceLocation();
if (!hasTemplateKWAndArgsInfo())
return SourceLocation();
return getTrailingObjects<ASTTemplateKWAndArgsInfo>()->RAngleLoc;
}

View File

@ -738,6 +738,28 @@ protected:
unsigned NumArgs;
};
class CXXDependentScopeMemberExprBitfields {
friend class ASTStmtReader;
friend class CXXDependentScopeMemberExpr;
unsigned : NumExprBits;
/// Whether this member expression used the '->' operator or
/// the '.' operator.
unsigned IsArrow : 1;
/// Whether this member expression has info for explicit template
/// keyword and arguments.
unsigned HasTemplateKWAndArgsInfo : 1;
/// See getFirstQualifierFoundInScope() and the comment listing
/// the trailing objects.
unsigned HasFirstQualifierFoundInScope : 1;
/// The location of the '->' or '.' operator.
SourceLocation OperatorLoc;
};
//===--- C++ Coroutines TS bitfields classes ---===//
class CoawaitExprBitfields {
@ -825,6 +847,7 @@ protected:
CXXConstructExprBitfields CXXConstructExprBits;
ExprWithCleanupsBitfields ExprWithCleanupsBits;
CXXUnresolvedConstructExprBitfields CXXUnresolvedConstructExprBits;
CXXDependentScopeMemberExprBitfields CXXDependentScopeMemberExprBits;
// C++ Coroutines TS expressions
CoawaitExprBitfields CoawaitBits;

View File

@ -1301,24 +1301,26 @@ SourceLocation CXXUnresolvedConstructExpr::getBeginLoc() const {
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow,
const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs)
: Expr(CXXDependentScopeMemberExprClass, C.DependentTy, VK_LValue,
: Expr(CXXDependentScopeMemberExprClass, Ctx.DependentTy, VK_LValue,
OK_Ordinary, true, true, true,
((Base && Base->containsUnexpandedParameterPack()) ||
(QualifierLoc &&
QualifierLoc.getNestedNameSpecifier()
->containsUnexpandedParameterPack()) ||
(QualifierLoc && QualifierLoc.getNestedNameSpecifier()
->containsUnexpandedParameterPack()) ||
MemberNameInfo.containsUnexpandedParameterPack())),
Base(Base), BaseType(BaseType), IsArrow(IsArrow),
HasTemplateKWAndArgsInfo(TemplateArgs != nullptr ||
TemplateKWLoc.isValid()),
OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
Base(Base), BaseType(BaseType), QualifierLoc(QualifierLoc),
MemberNameInfo(MemberNameInfo) {
CXXDependentScopeMemberExprBits.IsArrow = IsArrow;
CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
(TemplateArgs != nullptr) || TemplateKWLoc.isValid();
CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope =
FirstQualifierFoundInScope != nullptr;
CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc;
if (TemplateArgs) {
bool Dependent = true;
bool InstantiationDependent = true;
@ -1332,56 +1334,54 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
}
if (hasFirstQualifierFoundInScope())
*getTrailingObjects<NamedDecl *>() = FirstQualifierFoundInScope;
}
CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::Create(const ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid();
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(
EmptyShell Empty, bool HasTemplateKWAndArgsInfo,
bool HasFirstQualifierFoundInScope)
: Expr(CXXDependentScopeMemberExprClass, Empty) {
CXXDependentScopeMemberExprBits.HasTemplateKWAndArgsInfo =
HasTemplateKWAndArgsInfo;
CXXDependentScopeMemberExprBits.HasFirstQualifierFoundInScope =
HasFirstQualifierFoundInScope;
}
CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::Create(
const ASTContext &Ctx, Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
bool HasTemplateKWAndArgsInfo =
(TemplateArgs != nullptr) || TemplateKWLoc.isValid();
unsigned NumTemplateArgs = TemplateArgs ? TemplateArgs->size() : 0;
std::size_t Size =
totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
HasTemplateKWAndArgsInfo, NumTemplateArgs);
bool HasFirstQualifierFoundInScope = FirstQualifierFoundInScope != nullptr;
void *Mem = C.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType,
IsArrow, OperatorLoc,
QualifierLoc,
TemplateKWLoc,
FirstQualifierFoundInScope,
MemberNameInfo, TemplateArgs);
unsigned Size = totalSizeToAlloc<ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc, NamedDecl *>(
HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope);
void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
return new (Mem) CXXDependentScopeMemberExpr(
Ctx, Base, BaseType, IsArrow, OperatorLoc, QualifierLoc, TemplateKWLoc,
FirstQualifierFoundInScope, MemberNameInfo, TemplateArgs);
}
CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
CXXDependentScopeMemberExpr *CXXDependentScopeMemberExpr::CreateEmpty(
const ASTContext &Ctx, bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs, bool HasFirstQualifierFoundInScope) {
assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo);
std::size_t Size =
totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
HasTemplateKWAndArgsInfo, NumTemplateArgs);
void *Mem = C.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
auto *E =
new (Mem) CXXDependentScopeMemberExpr(C, nullptr, QualType(),
false, SourceLocation(),
NestedNameSpecifierLoc(),
SourceLocation(), nullptr,
DeclarationNameInfo(), nullptr);
E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo;
return E;
}
bool CXXDependentScopeMemberExpr::isImplicitAccess() const {
if (!Base)
return true;
unsigned Size = totalSizeToAlloc<ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc, NamedDecl *>(
HasTemplateKWAndArgsInfo, NumTemplateArgs, HasFirstQualifierFoundInScope);
return cast<Expr>(Base)->isImplicitCXXThis();
void *Mem = Ctx.Allocate(Size, alignof(CXXDependentScopeMemberExpr));
return new (Mem) CXXDependentScopeMemberExpr(
EmptyShell(), HasTemplateKWAndArgsInfo, HasFirstQualifierFoundInScope);
}
static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin,

View File

@ -1584,22 +1584,37 @@ void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) {
E->SubExpr = Record.readSubExpr();
}
void
ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
CXXDependentScopeMemberExpr *E) {
VisitExpr(E);
if (Record.readInt()) // HasTemplateKWAndArgsInfo
bool HasTemplateKWAndArgsInfo = Record.readInt();
unsigned NumTemplateArgs = Record.readInt();
bool HasFirstQualifierFoundInScope = Record.readInt();
assert((HasTemplateKWAndArgsInfo == E->hasTemplateKWAndArgsInfo()) &&
"Wrong HasTemplateKWAndArgsInfo!");
assert(
(HasFirstQualifierFoundInScope == E->hasFirstQualifierFoundInScope()) &&
"Wrong HasFirstQualifierFoundInScope!");
if (HasTemplateKWAndArgsInfo)
ReadTemplateKWAndArgsInfo(
*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
E->getTrailingObjects<TemplateArgumentLoc>(),
/*NumTemplateArgs=*/Record.readInt());
E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
E->Base = Record.readSubExpr();
assert((NumTemplateArgs == E->getNumTemplateArgs()) &&
"Wrong NumTemplateArgs!");
E->CXXDependentScopeMemberExprBits.IsArrow = Record.readInt();
E->CXXDependentScopeMemberExprBits.OperatorLoc = ReadSourceLocation();
E->BaseType = Record.readType();
E->IsArrow = Record.readInt();
E->OperatorLoc = ReadSourceLocation();
E->QualifierLoc = Record.readNestedNameSpecifierLoc();
E->FirstQualifierFoundInScope = ReadDeclAs<NamedDecl>();
E->Base = Record.readSubExpr();
if (HasFirstQualifierFoundInScope)
*E->getTrailingObjects<NamedDecl *>() = ReadDeclAs<NamedDecl>();
ReadDeclarationNameInfo(E->MemberNameInfo);
}
@ -3224,11 +3239,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_CXX_DEPENDENT_SCOPE_MEMBER:
S = CXXDependentScopeMemberExpr::CreateEmpty(Context,
/*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
? Record[ASTStmtReader::NumExprFields + 1]
: 0);
S = CXXDependentScopeMemberExpr::CreateEmpty(
Context,
/*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1],
/*HasFirstQualifierFoundInScope=*/
Record[ASTStmtReader::NumExprFields + 2]);
break;
case EXPR_CXX_DEPENDENT_SCOPE_DECL_REF:

View File

@ -1554,31 +1554,36 @@ void ASTStmtWriter::VisitExprWithCleanups(ExprWithCleanups *E) {
Code = serialization::EXPR_EXPR_WITH_CLEANUPS;
}
void
ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){
void ASTStmtWriter::VisitCXXDependentScopeMemberExpr(
CXXDependentScopeMemberExpr *E) {
VisitExpr(E);
// Don't emit anything here, HasTemplateKWAndArgsInfo must be
// emitted first.
// Don't emit anything here (or if you do you will have to update
// the corresponding deserialization function).
Record.push_back(E->HasTemplateKWAndArgsInfo);
if (E->HasTemplateKWAndArgsInfo) {
Record.push_back(E->hasTemplateKWAndArgsInfo());
Record.push_back(E->getNumTemplateArgs());
Record.push_back(E->hasFirstQualifierFoundInScope());
if (E->hasTemplateKWAndArgsInfo()) {
const ASTTemplateKWAndArgsInfo &ArgInfo =
*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>();
Record.push_back(ArgInfo.NumTemplateArgs);
AddTemplateKWAndArgsInfo(ArgInfo,
E->getTrailingObjects<TemplateArgumentLoc>());
}
Record.push_back(E->isArrow());
Record.AddSourceLocation(E->getOperatorLoc());
Record.AddTypeRef(E->getBaseType());
Record.AddNestedNameSpecifierLoc(E->getQualifierLoc());
if (!E->isImplicitAccess())
Record.AddStmt(E->getBase());
else
Record.AddStmt(nullptr);
Record.AddTypeRef(E->getBaseType());
Record.push_back(E->isArrow());
Record.AddSourceLocation(E->getOperatorLoc());
Record.AddNestedNameSpecifierLoc(E->getQualifierLoc());
Record.AddDeclRef(E->getFirstQualifierFoundInScope());
if (E->hasFirstQualifierFoundInScope())
Record.AddDeclRef(E->getFirstQualifierFoundInScope());
Record.AddDeclarationNameInfo(E->MemberNameInfo);
Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER;
}