r345597 - [AST] Only store the needed data in WhileStmt
Bruno Ricci via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 30 06:42:41 PDT 2018
Author: brunoricci
Date: Tue Oct 30 06:42:41 2018
New Revision: 345597
URL: http://llvm.org/viewvc/llvm-project?rev=345597&view=rev
Log:
[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
Modified:
cfe/trunk/include/clang/AST/Stmt.h
cfe/trunk/lib/AST/ASTDumper.cpp
cfe/trunk/lib/AST/ASTImporter.cpp
cfe/trunk/lib/AST/Stmt.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
cfe/trunk/test/Import/while-stmt/test.cpp
Modified: cfe/trunk/include/clang/AST/Stmt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=345597&r1=345596&r2=345597&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Stmt.h (original)
+++ cfe/trunk/include/clang/AST/Stmt.h Tue Oct 30 06:42:41 2018
@@ -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 *>()));
}
};
Modified: cfe/trunk/lib/AST/ASTDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=345597&r1=345596&r2=345597&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTDumper.cpp (original)
+++ cfe/trunk/lib/AST/ASTDumper.cpp Tue Oct 30 06:42:41 2018
@@ -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);
@@ -2040,6 +2041,12 @@ void ASTDumper::VisitSwitchStmt(const Sw
if (Node->hasVarStorage())
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);
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=345597&r1=345596&r2=345597&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Oct 30 06:42:41 2018
@@ -5864,9 +5864,8 @@ ExpectedStmt ASTNodeImporter::VisitWhile
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) {
Modified: cfe/trunk/lib/AST/Stmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=345597&r1=345596&r2=345597&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Stmt.cpp (original)
+++ cfe/trunk/lib/AST/Stmt.cpp Tue Oct 30 06:42:41 2018
@@ -978,32 +978,60 @@ void SwitchStmt::setConditionVariable(co
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;
+}
+
+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);
+}
- auto *DS = cast<DeclStmt>(SubExprs[VAR]);
+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
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=345597&r1=345596&r2=345597&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Oct 30 06:42:41 2018
@@ -1306,8 +1306,8 @@ StmtResult Sema::ActOnWhileStmt(SourceLo
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
Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=345597&r1=345596&r2=345597&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Tue Oct 30 06:42:41 2018
@@ -270,10 +270,14 @@ void ASTStmtReader::VisitSwitchStmt(Swit
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(Modu
break;
case STMT_WHILE:
- S = new (Context) WhileStmt(Empty);
+ S = WhileStmt::CreateEmpty(
+ Context,
+ /* HasVar=*/Record[ASTStmtReader::NumStmtFields + 0]);
break;
case STMT_DO:
Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=345597&r1=345596&r2=345597&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Tue Oct 30 06:42:41 2018
@@ -183,9 +183,15 @@ void ASTStmtWriter::VisitSwitchStmt(Swit
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;
}
Modified: cfe/trunk/test/Import/while-stmt/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/while-stmt/test.cpp?rev=345597&r1=345596&r2=345597&view=diff
==============================================================================
--- cfe/trunk/test/Import/while-stmt/test.cpp (original)
+++ cfe/trunk/test/Import/while-stmt/test.cpp Tue Oct 30 06:42:41 2018
@@ -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
More information about the cfe-commits
mailing list