is because GNU-style Statement-expressions cause the last statement in the
statement-expression to act like an expression.
We now have two notions: block-level statements and block-level expressions.
The former are all Stmt* that appear in the list of statements in CFGBlocks. The
latter is the subset of the former; these block-level statements are used as
subexpressions somewhere in the AST. CFG::isBlockExpr() returns true for the
latter, not the former (previously isBlockExpr() always returned true for
non-Expr Stmt*).
Modified the LiveVariables analysis to also track liveness state for block-level
expressions (using the updated definition of block-level expressions).
Modified the dataflow solver so that when it records values for block-level
statements, it records the dataflow value *before* the transfer function for a
Stmt* is evaluated (not after). This is more in sync in what clients will want.
Modified CFGStmtVisitor to record the current block-level statement.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46143
91177308-0d34-0410-b5e6-
96231b3b80d8
//===----------------------------------------------------------------------===//
namespace {
- typedef llvm::DenseMap<const Expr*,unsigned> BlkExprMapTy;
+ typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
}
static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
if (const Expr* E = dyn_cast<Expr>(*BI)) {
unsigned x = M->size();
(*M)[E] = x;
+
+ // Special handling for statement expressions. The last statement
+ // in the statement expression is also a block-level expr.
+ if (const StmtExpr* S = dyn_cast<StmtExpr>(E)) {
+ const CompoundStmt* C = S->getSubStmt();
+ if (!C->body_empty()) {
+ x = M->size();
+ (*M)[C->body_back()] = x;
+ }
+ }
}
-
- return M;
-}
-bool CFG::isBlkExpr(const Stmt* S) {
- assert (S != NULL);
- if (const Expr* E = dyn_cast<Expr>(S)) return getBlkExprNum(E);
- else return true; // Statements are by default "block-level expressions."
+ return M;
}
-CFG::BlkExprNumTy CFG::getBlkExprNum(const Expr* E) {
- assert(E != NULL);
+CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) {
+ assert(S != NULL);
if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); }
BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap);
- BlkExprMapTy::iterator I = M->find(E);
+ BlkExprMapTy::iterator I = M->find(S);
if (I == M->end()) return CFG::BlkExprNumTy();
else return CFG::BlkExprNumTy(I->second);
if (AD.Observer)
AD.Observer->ObserveStmt(S,AD,LiveState);
- static_cast<CFGStmtVisitor<TransferFuncs>*>(this)->Visit(S);
+
+ if (S == getCurrentBlkStmt()) {
+ StmtVisitor<TransferFuncs,void>::Visit(S);
+ if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead;
+ }
+ else if (!getCFG().isBlkExpr(S))
+ StmtVisitor<TransferFuncs,void>::Visit(S);
+ else
+ // For block-level expressions, mark that they are live.
+ LiveState(S,AD) = Alive;
}
void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
return Live(D,getAnalysisData());
}
+bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const {
+ return getStmtData(Loc)(StmtVal,getAnalysisData());
+}
+
//===----------------------------------------------------------------------===//
// printing liveness state for debugging
//
operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
};
- bool isBlkExpr(const Stmt* S);
- bool isBlkExpr(const Expr* E) { return getBlkExprNum(E); }
- BlkExprNumTy getBlkExprNum(const Expr* E);
+ bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
+ BlkExprNumTy getBlkExprNum(const Stmt* S);
unsigned getNumBlkExprs();
unsigned getNumBlockIDs() const { return NumBlockIDs; }
// We need to keep track of both declarations and CFGBlock-level expressions,
- // (so that we don't explore such expressions twice), but we only need
- // liveness information for declarations (hence
- // ValTy = DeclBitVector_Types::ValTy instead of
- // ValTy = ExprDeclBitVector_Types::ValTy).
-
+ // (so that we don't explore such expressions twice). We also want
+ // to compute liveness information for block-level expressions, since these
+ // act as "temporary" values.
+
struct AnalysisDataTy : public ExprDeclBitVector_Types::AnalysisDataTy {
ObserverTy* Observer;
};
// We only keep actual dataflow state for declarations.
- typedef DeclBitVector_Types::ValTy ValTy;
+ typedef ExprDeclBitVector_Types::ValTy ValTy;
//===-----------------------------------------------------===//
// ObserverTy - Observer for uninitialized values queries.
/// has been recorded at the statement level (see runOnAllBlocks), and
/// only returns liveness information for block-level expressions.
bool isLive(const Stmt* S, const VarDecl* D) const;
+
+ /// IsLive - Returns true the block-level expression "value" is live
+ /// before the given block-level expression (see runOnAllBlocks).
+ bool isLive(const Stmt* Loc, const Stmt* StmtVal) const;
/// IsLive - Return true if a variable is live according to the
/// provided livness bitvector.
/// ProcessBlock - Process the transfer functions for a given block.
void ProcessBlock(const CFGBlock* B, bool recordStmtValues) {
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
- TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
if (recordStmtValues) D.getStmtDataMap()[*I] = TF.getVal();
+ TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
}
}
/// getStmtData - Retrieves the dataflow values associated with a
/// specified Stmt. If the dataflow analysis is a forward analysis,
- /// this data corresponds to the point immediately after a Stmt.
+ /// this data corresponds to the point immediately before a Stmt.
/// If the analysis is a backwards analysis, it is associated with
- /// the point before a Stmt. This data is only computed for block-level
+ /// the point after a Stmt. This data is only computed for block-level
/// expressions, and only when requested when the analysis is executed.
ValTy& getStmtData(const Stmt* S) {
assert (StmtDataMap && "Dataflow values were not computed for statements.");
void setCFG(CFG* c) { cfg = c; }
CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; }
- bool isTracked(const Expr* E) { return cfg->isBlkExpr(E); }
+ bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); }
using DeclBitVector_Types::AnalysisDataTy::isTracked;
- unsigned getIdx(const Expr* E) const {
- CFG::BlkExprNumTy I = cfg->getBlkExprNum(E);
+ unsigned getIdx(const Stmt* S) const {
+ CFG::BlkExprNumTy I = cfg->getBlkExprNum(S);
assert(I && "expression not tracked for bitvector.");
return I;
}
}
llvm::BitVector::reference
- operator()(const Expr* E, const AnalysisDataTy& AD) {
- return ExprBV[AD.getIdx(E)];
+ operator()(const Stmt* S, const AnalysisDataTy& AD) {
+ return ExprBV[AD.getIdx(S)];
}
const llvm::BitVector::reference
- operator()(const Expr* E, const AnalysisDataTy& AD) const {
- return const_cast<ValTy&>(*this)(E,AD);
+ operator()(const Stmt* S, const AnalysisDataTy& AD) const {
+ return const_cast<ValTy&>(*this)(S,AD);
}
using DeclBitVector_Types::ValTy::operator();
template <typename ImplClass, typename RetTy=void>
class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
- Stmt* CurrentBlkExpr;
+ Stmt* CurrentBlkStmt;
struct NullifyStmt {
Stmt*& S;
~NullifyStmt() { S = NULL; }
};
-public:
- CFGStmtVisitor() : CurrentBlkExpr(NULL) {}
+public:
+ CFGStmtVisitor() : CurrentBlkStmt(NULL) {}
+
+ Stmt* getCurrentBlkStmt() const { return CurrentBlkStmt; }
RetTy Visit(Stmt* S) {
- if (S == CurrentBlkExpr ||
+ if (S == CurrentBlkStmt ||
!static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S))
return StmtVisitor<ImplClass,RetTy>::Visit(S);
else
/// is no implementation provided for a BlockStmt_XXX method, we default
/// to using StmtVisitor's Visit method.
RetTy BlockStmt_Visit(Stmt* S) {
- CurrentBlkExpr = S;
- NullifyStmt cleanup(CurrentBlkExpr);
+ CurrentBlkStmt = S;
+ NullifyStmt cleanup(CurrentBlkStmt);
switch (S->getStmtClass()) {
DISPATCH_CASE(CallExpr)