forked from OSchip/llvm-project
[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:
parent
af8e036c29
commit
bacf751add
|
@ -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 *>()));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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() << "'";
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue