[AST] Only store the needed data in WhileStmt

Don't store the data for the condition variable if not needed.
This cuts the size of WhileStmt by up to a pointer.
The order of the children is kept the same.

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

Reviewed By: rjmccall

llvm-svn: 345597
This commit is contained in:
Bruno Ricci 2018-10-30 13:42:41 +00:00
parent af8e036c29
commit bacf751add
8 changed files with 161 additions and 44 deletions

View File

@ -193,10 +193,14 @@ protected:
};
class WhileStmtBitfields {
friend class ASTStmtReader;
friend class WhileStmt;
unsigned : NumStmtBits;
/// True if the WhileStmt has storage for a condition variable.
unsigned HasVar : 1;
/// The location of the "while".
SourceLocation WhileLoc;
};
@ -1615,16 +1619,75 @@ public:
};
/// WhileStmt - This represents a 'while' stmt.
class WhileStmt : public Stmt {
enum { VAR, COND, BODY, END_EXPR };
Stmt* SubExprs[END_EXPR];
class WhileStmt final : public Stmt,
private llvm::TrailingObjects<WhileStmt, Stmt *> {
friend TrailingObjects;
public:
WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
// WhileStmt is followed by several trailing objects,
// some of which optional. Note that it would be more
// convenient to put the optional trailing object at the end
// but this would affect children().
// The trailing objects are in order:
//
// * A "Stmt *" for the condition variable.
// Present if and only if hasVarStorage(). This is in fact a "DeclStmt *".
//
// * A "Stmt *" for the condition.
// Always present. This is in fact an "Expr *".
//
// * A "Stmt *" for the body.
// Always present.
//
enum { VarOffset = 0, BodyOffsetFromCond = 1 };
enum { NumMandatoryStmtPtr = 2 };
unsigned varOffset() const { return VarOffset; }
unsigned condOffset() const { return VarOffset + hasVarStorage(); }
unsigned bodyOffset() const { return condOffset() + BodyOffsetFromCond; }
unsigned numTrailingObjects(OverloadToken<Stmt *>) const {
return NumMandatoryStmtPtr + hasVarStorage();
}
/// Build a while statement.
WhileStmt(const ASTContext &Ctx, VarDecl *Var, Expr *Cond, Stmt *Body,
SourceLocation WL);
/// Build an empty while statement.
explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) {}
explicit WhileStmt(EmptyShell Empty, bool HasVar);
public:
/// Create a while statement.
static WhileStmt *Create(const ASTContext &Ctx, VarDecl *Var, Expr *Cond,
Stmt *Body, SourceLocation WL);
/// Create an empty while statement optionally with storage for
/// a condition variable.
static WhileStmt *CreateEmpty(const ASTContext &Ctx, bool HasVar);
/// True if this WhileStmt has storage for a condition variable.
bool hasVarStorage() const { return WhileStmtBits.HasVar; }
Expr *getCond() {
return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
}
const Expr *getCond() const {
return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
}
void setCond(Expr *Cond) {
getTrailingObjects<Stmt *>()[condOffset()] = reinterpret_cast<Stmt *>(Cond);
}
Stmt *getBody() { return getTrailingObjects<Stmt *>()[bodyOffset()]; }
const Stmt *getBody() const {
return getTrailingObjects<Stmt *>()[bodyOffset()];
}
void setBody(Stmt *Body) {
getTrailingObjects<Stmt *>()[bodyOffset()] = Body;
}
/// Retrieve the variable declared in this "while" statement, if any.
///
@ -1634,28 +1697,36 @@ public:
/// // ...
/// }
/// \endcode
VarDecl *getConditionVariable() const;
void setConditionVariable(const ASTContext &C, VarDecl *V);
VarDecl *getConditionVariable();
const VarDecl *getConditionVariable() const {
return const_cast<WhileStmt *>(this)->getConditionVariable();
}
/// Set the condition variable of this while statement.
/// The while statement must have storage for it.
void setConditionVariable(const ASTContext &Ctx, VarDecl *V);
/// If this WhileStmt has a condition variable, return the faux DeclStmt
/// associated with the creation of that condition variable.
const DeclStmt *getConditionVariableDeclStmt() const {
return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
DeclStmt *getConditionVariableDeclStmt() {
return hasVarStorage() ? static_cast<DeclStmt *>(
getTrailingObjects<Stmt *>()[varOffset()])
: nullptr;
}
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
Stmt *getBody() { return SubExprs[BODY]; }
const Stmt *getBody() const { return SubExprs[BODY]; }
void setBody(Stmt *S) { SubExprs[BODY] = S; }
const DeclStmt *getConditionVariableDeclStmt() const {
return hasVarStorage() ? static_cast<DeclStmt *>(
getTrailingObjects<Stmt *>()[varOffset()])
: nullptr;
}
SourceLocation getWhileLoc() const { return WhileStmtBits.WhileLoc; }
void setWhileLoc(SourceLocation L) { WhileStmtBits.WhileLoc = L; }
SourceLocation getBeginLoc() const { return getWhileLoc(); }
SourceLocation getEndLoc() const { return getBody()->getEndLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY {
return getBody()->getEndLoc();
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == WhileStmtClass;
@ -1663,7 +1734,9 @@ public:
// Iterators
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
return child_range(getTrailingObjects<Stmt *>(),
getTrailingObjects<Stmt *>() +
numTrailingObjects(OverloadToken<Stmt *>()));
}
};

View File

@ -513,6 +513,7 @@ namespace {
void VisitAttributedStmt(const AttributedStmt *Node);
void VisitIfStmt(const IfStmt *Node);
void VisitSwitchStmt(const SwitchStmt *Node);
void VisitWhileStmt(const WhileStmt *Node);
void VisitLabelStmt(const LabelStmt *Node);
void VisitGotoStmt(const GotoStmt *Node);
void VisitCXXCatchStmt(const CXXCatchStmt *Node);
@ -2041,6 +2042,12 @@ void ASTDumper::VisitSwitchStmt(const SwitchStmt *Node) {
OS << " has_var";
}
void ASTDumper::VisitWhileStmt(const WhileStmt *Node) {
VisitStmt(Node);
if (Node->hasVarStorage())
OS << " has_var";
}
void ASTDumper::VisitLabelStmt(const LabelStmt *Node) {
VisitStmt(Node);
OS << " '" << Node->getName() << "'";

View File

@ -5864,9 +5864,8 @@ ExpectedStmt ASTNodeImporter::VisitWhileStmt(WhileStmt *S) {
SourceLocation ToWhileLoc;
std::tie(ToConditionVariable, ToCond, ToBody, ToWhileLoc) = *Imp;
return new (Importer.getToContext()) WhileStmt(
Importer.getToContext(),
ToConditionVariable, ToCond, ToBody, ToWhileLoc);
return WhileStmt::Create(Importer.getToContext(), ToConditionVariable, ToCond,
ToBody, ToWhileLoc);
}
ExpectedStmt ASTNodeImporter::VisitDoStmt(DoStmt *S) {

View File

@ -978,32 +978,60 @@ void SwitchStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) {
DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd());
}
WhileStmt::WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
SourceLocation WL)
: Stmt(WhileStmtClass) {
setConditionVariable(C, Var);
SubExprs[COND] = cond;
SubExprs[BODY] = body;
WhileStmtBits.WhileLoc = WL;
WhileStmt::WhileStmt(const ASTContext &Ctx, VarDecl *Var, Expr *Cond,
Stmt *Body, SourceLocation WL)
: Stmt(WhileStmtClass) {
bool HasVar = Var != nullptr;
WhileStmtBits.HasVar = HasVar;
setCond(Cond);
setBody(Body);
if (HasVar)
setConditionVariable(Ctx, Var);
setWhileLoc(WL);
}
VarDecl *WhileStmt::getConditionVariable() const {
if (!SubExprs[VAR])
return nullptr;
WhileStmt::WhileStmt(EmptyShell Empty, bool HasVar)
: Stmt(WhileStmtClass, Empty) {
WhileStmtBits.HasVar = HasVar;
}
auto *DS = cast<DeclStmt>(SubExprs[VAR]);
WhileStmt *WhileStmt::Create(const ASTContext &Ctx, VarDecl *Var, Expr *Cond,
Stmt *Body, SourceLocation WL) {
bool HasVar = Var != nullptr;
void *Mem =
Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasVar),
alignof(WhileStmt));
return new (Mem) WhileStmt(Ctx, Var, Cond, Body, WL);
}
WhileStmt *WhileStmt::CreateEmpty(const ASTContext &Ctx, bool HasVar) {
void *Mem =
Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasVar),
alignof(WhileStmt));
return new (Mem) WhileStmt(EmptyShell(), HasVar);
}
VarDecl *WhileStmt::getConditionVariable() {
auto *DS = getConditionVariableDeclStmt();
if (!DS)
return nullptr;
return cast<VarDecl>(DS->getSingleDecl());
}
void WhileStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
void WhileStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) {
assert(hasVarStorage() &&
"This while statement has no storage for a condition variable!");
if (!V) {
SubExprs[VAR] = nullptr;
getTrailingObjects<Stmt *>()[varOffset()] = nullptr;
return;
}
SourceRange VarRange = V->getSourceRange();
SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(),
VarRange.getEnd());
getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx)
DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd());
}
// IndirectGotoStmt

View File

@ -1306,8 +1306,8 @@ StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond,
if (isa<NullStmt>(Body))
getCurCompoundScope().setHasEmptyLoopBodies();
return new (Context)
WhileStmt(Context, CondVal.first, CondVal.second, Body, WhileLoc);
return WhileStmt::Create(Context, CondVal.first, CondVal.second, Body,
WhileLoc);
}
StmtResult

View File

@ -270,10 +270,14 @@ void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
void ASTStmtReader::VisitWhileStmt(WhileStmt *S) {
VisitStmt(S);
S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>());
bool HasVar = Record.readInt();
S->setCond(Record.readSubExpr());
S->setBody(Record.readSubStmt());
if (HasVar)
S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>());
S->setWhileLoc(ReadSourceLocation());
}
@ -2325,7 +2329,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case STMT_WHILE:
S = new (Context) WhileStmt(Empty);
S = WhileStmt::CreateEmpty(
Context,
/* HasVar=*/Record[ASTStmtReader::NumStmtFields + 0]);
break;
case STMT_DO:

View File

@ -183,9 +183,15 @@ void ASTStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
void ASTStmtWriter::VisitWhileStmt(WhileStmt *S) {
VisitStmt(S);
Record.AddDeclRef(S->getConditionVariable());
bool HasVar = S->getConditionVariableDeclStmt() != nullptr;
Record.push_back(HasVar);
Record.AddStmt(S->getCond());
Record.AddStmt(S->getBody());
if (HasVar)
Record.AddDeclRef(S->getConditionVariable());
Record.AddSourceLocation(S->getWhileLoc());
Code = serialization::STMT_WHILE;
}

View File

@ -1,12 +1,10 @@
// RUN: clang-import-test -dump-ast -import %S/Inputs/F.cpp -expression %s | FileCheck %s
// CHECK: WhileStmt
// CHECK-NEXT: <<NULL>>
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: NullStmt
// CHECK: WhileStmt
// CHECK-NEXT: <<NULL>>
// CHECK-NEXT: CXXBoolLiteralExpr
// CHECK-NEXT: CompoundStmt