riccibruno created this revision.
riccibruno added a reviewer: rjmccall.
riccibruno added a project: clang.
Herald added a subscriber: cfe-commits.
riccibruno added a dependency: D53716: [AST] Only store data for the NRVO
candidate in ReturnStmt if needed..
Don't store the init statement and condition variable if not needed.
This cuts the size of `ForStmt` by up to 2 pointers, and 1 pointer in
the common case. The condition and increment are stored unconditionally
since for statements without a condition and increment are quite uncommon.
The order of the children is kept the same.
Repository:
rC Clang
https://reviews.llvm.org/D53717
Files:
include/clang/AST/Stmt.h
lib/AST/ASTImporter.cpp
lib/AST/Stmt.cpp
lib/Sema/SemaStmt.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
test/Import/for-stmt/test.cpp
Index: test/Import/for-stmt/test.cpp
===================================================================
--- test/Import/for-stmt/test.cpp
+++ test/Import/for-stmt/test.cpp
@@ -3,21 +3,17 @@
// CHECK: ForStmt
// CHECK-NEXT: <<NULL>>
// CHECK-NEXT: <<NULL>>
-// CHECK-NEXT: <<NULL>>
-// CHECK-NEXT: <<NULL>>
// CHECK-NEXT: NullStmt
// CHECK: ForStmt
// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl
// CHECK-NEXT: IntegerLiteral
// CHECK-NEXT: <<NULL>>
// CHECK-NEXT: <<NULL>>
-// CHECK-NEXT: <<NULL>>
// CHECK-NEXT: ContinueStmt
// CHECK: ForStmt
-// CHECK-NEXT: <<NULL>>
// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl
// CHECK-NEXT: CXXBoolLiteralExpr
@@ -32,7 +28,6 @@
// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl
// CHECK-NEXT: IntegerLiteral
-// CHECK-NEXT: <<NULL>>
// CHECK-NEXT: BinaryOperator
// CHECK-NEXT: ImplicitCastExpr
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -208,11 +208,20 @@
void ASTStmtWriter::VisitForStmt(ForStmt *S) {
VisitStmt(S);
- Record.AddStmt(S->getInit());
+
+ bool HasInit = !!S->getInit();
+ bool HasVar = !!S->getConditionVariableDeclStmt();
+ Record.push_back(HasInit);
+ Record.push_back(HasVar);
+
Record.AddStmt(S->getCond());
- Record.AddDeclRef(S->getConditionVariable());
Record.AddStmt(S->getInc());
Record.AddStmt(S->getBody());
+ if (HasInit)
+ Record.AddStmt(S->getInit());
+ if (HasVar)
+ Record.AddDeclRef(S->getConditionVariable());
+
Record.AddSourceLocation(S->getForLoc());
Record.AddSourceLocation(S->getLParenLoc());
Record.AddSourceLocation(S->getRParenLoc());
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -292,11 +292,18 @@
void ASTStmtReader::VisitForStmt(ForStmt *S) {
VisitStmt(S);
- S->setInit(Record.readSubStmt());
+
+ bool HasInit = Record.readInt();
+ bool HasVar = Record.readInt();
+
S->setCond(Record.readSubExpr());
- S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>());
S->setInc(Record.readSubExpr());
S->setBody(Record.readSubStmt());
+ if (HasInit)
+ S->setInit(Record.readSubStmt());
+ if (HasVar)
+ S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>());
+
S->setForLoc(ReadSourceLocation());
S->setLParenLoc(ReadSourceLocation());
S->setRParenLoc(ReadSourceLocation());
@@ -2342,7 +2349,10 @@
break;
case STMT_FOR:
- S = new (Context) ForStmt(Empty);
+ S = ForStmt::CreateEmpty(
+ Context,
+ /* HasInit=*/Record[ASTStmtReader::NumStmtFields + 0],
+ /* HasVar=*/Record[ASTStmtReader::NumStmtFields + 1]);
break;
case STMT_GOTO:
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -1780,9 +1780,9 @@
if (isa<NullStmt>(Body))
getCurCompoundScope().setHasEmptyLoopBodies();
- return new (Context)
- ForStmt(Context, First, Second.get().second, Second.get().first, Third,
- Body, ForLoc, LParenLoc, RParenLoc);
+ return ForStmt::Create(Context, First, Second.get().second,
+ Second.get().first, Third, Body, ForLoc, LParenLoc,
+ RParenLoc);
}
/// In an Objective C collection iteration statement:
Index: lib/AST/Stmt.cpp
===================================================================
--- lib/AST/Stmt.cpp
+++ lib/AST/Stmt.cpp
@@ -881,36 +881,70 @@
return isa<ObjCAvailabilityCheckExpr>(getCond());
}
-ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
- Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
- SourceLocation RP)
- : Stmt(ForStmtClass), LParenLoc(LP), RParenLoc(RP)
-{
- SubExprs[INIT] = Init;
- setConditionVariable(C, condVar);
- SubExprs[COND] = Cond;
- SubExprs[INC] = Inc;
- SubExprs[BODY] = Body;
- ForStmtBits.ForLoc = FL;
-}
-
-VarDecl *ForStmt::getConditionVariable() const {
- if (!SubExprs[CONDVAR])
- return nullptr;
+ForStmt::ForStmt(const ASTContext &Ctx, Stmt *Init, Expr *Cond,
+ VarDecl *CondVar, Expr *Inc, Stmt *Body, SourceLocation FL,
+ SourceLocation LP, SourceLocation RP)
+ : Stmt(ForStmtClass), LParenLoc(LP), RParenLoc(RP) {
+ bool HasInit = !!Init;
+ bool HasVar = !!CondVar;
+ ForStmtBits.HasInit = HasInit;
+ ForStmtBits.HasVar = HasVar;
+
+ setCond(Cond);
+ setBody(Body);
+ setInc(Inc);
+ if (HasInit)
+ setInit(Init);
+ if (HasVar)
+ setConditionVariable(Ctx, CondVar);
+
+ setForLoc(FL);
+}
+
+ForStmt::ForStmt(EmptyShell Empty, bool HasInit, bool HasVar)
+ : Stmt(ForStmtClass, Empty) {
+ ForStmtBits.HasInit = HasInit;
+ ForStmtBits.HasVar = HasVar;
+}
+
+ForStmt *ForStmt::Create(const ASTContext &Ctx, Stmt *Init, Expr *Cond,
+ VarDecl *CondVar, Expr *Inc, Stmt *Body,
+ SourceLocation FL, SourceLocation LP,
+ SourceLocation RP) {
+ bool HasInit = !!Init;
+ bool HasVar = !!CondVar;
+ void *Mem = Ctx.Allocate(
+ totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasInit + HasVar),
+ alignof(ForStmt));
+ return new (Mem) ForStmt(Ctx, Init, Cond, CondVar, Inc, Body, FL, LP, RP);
+}
+
+ForStmt *ForStmt::CreateEmpty(const ASTContext &Ctx, bool HasInit,
+ bool HasVar) {
+ void *Mem = Ctx.Allocate(
+ totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasInit + HasVar),
+ alignof(ForStmt));
+ return new (Mem) ForStmt(EmptyShell(), HasInit, HasVar);
+}
- auto *DS = cast<DeclStmt>(SubExprs[CONDVAR]);
+VarDecl *ForStmt::getConditionVariable() {
+ auto *DS = getConditionVariableDeclStmt();
+ if (!DS)
+ return nullptr;
return cast<VarDecl>(DS->getSingleDecl());
}
-void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
+void ForStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) {
+ assert(hasVar() && "no storage for the condition variable in this ForStmt!");
+
if (!V) {
- SubExprs[CONDVAR] = nullptr;
+ getTrailingObjects<Stmt *>()[varOffset()] = nullptr;
return;
}
SourceRange VarRange = V->getSourceRange();
- SubExprs[CONDVAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(),
- VarRange.getEnd());
+ getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx)
+ DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd());
}
SwitchStmt::SwitchStmt(const ASTContext &Ctx, Stmt *init, VarDecl *Var,
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -5860,10 +5860,9 @@
ToInit, ToCond, ToConditionVariable, ToInc, ToBody, ToForLoc,
ToLParenLoc, ToRParenLoc) = *Imp;
- return new (Importer.getToContext()) ForStmt(
- Importer.getToContext(),
- ToInit, ToCond, ToConditionVariable, ToInc, ToBody, ToForLoc, ToLParenLoc,
- ToRParenLoc);
+ return ForStmt::Create(Importer.getToContext(), ToInit, ToCond,
+ ToConditionVariable, ToInc, ToBody, ToForLoc,
+ ToLParenLoc, ToRParenLoc);
}
ExpectedStmt ASTNodeImporter::VisitGotoStmt(GotoStmt *S) {
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -219,6 +219,12 @@
unsigned : NumStmtBits;
+ /// True if the ForStmt has storage for an init statement.
+ unsigned HasInit : 1;
+
+ /// True if the ForStmt has storage for a condition variable.
+ unsigned HasVar : 1;
+
/// The location of the "for".
SourceLocation ForLoc;
};
@@ -1784,20 +1790,121 @@
/// ForStmt - This represents a 'for (init;cond;inc)' stmt. Note that any of
/// the init/cond/inc parts of the ForStmt will be null if they were not
/// specified in the source.
-class ForStmt : public Stmt {
- enum { INIT, CONDVAR, COND, INC, BODY, END_EXPR };
- Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt.
+class ForStmt final : public Stmt,
+ private llvm::TrailingObjects<ForStmt, Stmt *> {
+ friend TrailingObjects;
+
+ /// The location of the left and right parentheses.
SourceLocation LParenLoc, RParenLoc;
-public:
- ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
+ // ForStmt is followed by several trailing objects, some of which optional.
+ // Note that it would be more convenient to put the optional trailing objects
+ // at the end but this would affect children(). Note also that even though
+ // it is possible to have a for statement without a condition or increment,
+ // the condition and increment are unconditionally stored since these kind
+ // of for statement are quite uncommon.
+ // The trailing objects are in order:
+ //
+ // * A "Stmt *" for the init statement.
+ // Present if and only if hasInit(). This is in fact either an "Expr *"
+ // or a "DeclStmt *" depending on whether the init statement is an
+ // expression statement or a simple declaration.
+ //
+ // * A "Stmt *" for the condition variable.
+ // Present if and only if hasVar(). This is in fact a "DeclStmt *".
+ //
+ // * A "Stmt *" for the condition.
+ // Always present. This is in fact an "Expr *".
+ //
+ // * A "Stmt *" for the increment.
+ // Always present. This is in fact an "Expr *".
+ //
+ // * A "Stmt *" for the body.
+ // Always present.
+ enum { InitOffset = 0, IncOffsetFromCond = 1, BodyOffsetFromCond = 2 };
+ enum { NumMandatoryStmtPtr = 3 };
+
+ unsigned numTrailingObjects(OverloadToken<Stmt *>) const {
+ return NumMandatoryStmtPtr + hasInit() + hasVar();
+ }
+
+ unsigned initOffset() const { return InitOffset; }
+ unsigned varOffset() const { return InitOffset + hasInit(); }
+ unsigned condOffset() const { return InitOffset + hasInit() + hasVar(); }
+ unsigned incOffset() const { return condOffset() + IncOffsetFromCond; }
+ unsigned bodyOffset() const { return condOffset() + BodyOffsetFromCond; }
+
+ /// True if this ForStmt has storage for an init statement.
+ bool hasInit() const { return ForStmtBits.HasInit; }
+
+ /// True if this ForStmt has storage for a condition variable.
+ bool hasVar() const { return ForStmtBits.HasVar; }
+
+ /// Build a for statement.
+ ForStmt(const ASTContext &Ctx, Stmt *Init, Expr *Cond, VarDecl *CondVar,
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
SourceLocation RP);
/// Build an empty for statement.
- explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) {}
+ explicit ForStmt(EmptyShell Empty, bool HasInit, bool HasVar);
+
+public:
+ /// Create a for statement.
+ static ForStmt *Create(const ASTContext &Ctx, Stmt *Init, Expr *Cond,
+ VarDecl *CondVar, Expr *Inc, Stmt *Body,
+ SourceLocation FL, SourceLocation LP,
+ SourceLocation RP);
+
+ /// Create an empty for statement optionally with storage for an init
+ /// statement and a condition variable.
+ static ForStmt *CreateEmpty(const ASTContext &Ctx, bool HasInit, bool 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);
+ }
+
+ Expr *getInc() {
+ return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[incOffset()]);
+ }
+
+ const Expr *getInc() const {
+ return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[incOffset()]);
+ }
- Stmt *getInit() { return SubExprs[INIT]; }
+ void setInc(Expr *Inc) {
+ getTrailingObjects<Stmt *>()[incOffset()] = reinterpret_cast<Stmt *>(Inc);
+ }
+
+ Stmt *getBody() { return getTrailingObjects<Stmt *>()[bodyOffset()]; }
+ const Stmt *getBody() const {
+ return getTrailingObjects<Stmt *>()[bodyOffset()];
+ }
+
+ void setBody(Stmt *Body) {
+ getTrailingObjects<Stmt *>()[bodyOffset()] = Body;
+ }
+
+ Stmt *getInit() {
+ return hasInit() ? getTrailingObjects<Stmt *>()[initOffset()] : nullptr;
+ }
+
+ const Stmt *getInit() const {
+ return hasInit() ? getTrailingObjects<Stmt *>()[initOffset()] : nullptr;
+ }
+
+ void setInit(Stmt *Init) {
+ assert(hasInit() &&
+ "This for statement has no storage for an init statement!");
+ getTrailingObjects<Stmt *>()[initOffset()] = Init;
+ }
/// Retrieve the variable declared in this "for" statement, if any.
///
@@ -1807,28 +1914,28 @@
/// // ...
/// }
/// \endcode
- VarDecl *getConditionVariable() const;
+ VarDecl *getConditionVariable();
+ const VarDecl *getConditionVariable() const {
+ return const_cast<ForStmt *>(this)->getConditionVariable();
+ }
+
+ /// Set the condition variable declared in this for statement.
+ /// The for statement must have storage for this variable.
void setConditionVariable(const ASTContext &C, VarDecl *V);
/// If this ForStmt 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[CONDVAR]);
+ DeclStmt *getConditionVariableDeclStmt() {
+ return hasVar() ? static_cast<DeclStmt *>(
+ getTrailingObjects<Stmt *>()[varOffset()])
+ : nullptr;
}
- Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
- Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); }
- Stmt *getBody() { return SubExprs[BODY]; }
-
- const Stmt *getInit() const { return SubExprs[INIT]; }
- const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
- const Expr *getInc() const { return reinterpret_cast<Expr*>(SubExprs[INC]); }
- const Stmt *getBody() const { return SubExprs[BODY]; }
-
- void setInit(Stmt *S) { SubExprs[INIT] = S; }
- void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
- void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); }
- void setBody(Stmt *S) { SubExprs[BODY] = S; }
+ const DeclStmt *getConditionVariableDeclStmt() const {
+ return hasVar() ? static_cast<DeclStmt *>(
+ getTrailingObjects<Stmt *>()[varOffset()])
+ : nullptr;
+ }
SourceLocation getForLoc() const { return ForStmtBits.ForLoc; }
void setForLoc(SourceLocation L) { ForStmtBits.ForLoc = L; }
@@ -1838,15 +1945,19 @@
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
SourceLocation getBeginLoc() const { return getForLoc(); }
- SourceLocation getEndLoc() const { return getBody()->getEndLoc(); }
+ SourceLocation getEndLoc() const LLVM_READONLY {
+ return getBody()->getEndLoc();
+ }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ForStmtClass;
}
// Iterators
child_range children() {
- return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
+ return child_range(getTrailingObjects<Stmt *>(),
+ getTrailingObjects<Stmt *>() +
+ numTrailingObjects(OverloadToken<Stmt *>()));
}
};
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits