Modified the notion of "Block-level expressions" in CFGs to include Stmt*. This
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. llvm-svn: 46143
This commit is contained in:
parent
e4d3e3c0e7
commit
85be7cf8ca
@ -988,7 +988,7 @@ void CFGBlock::reverseStmts() { std::reverse(Stmts.begin(),Stmts.end()); }
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
typedef llvm::DenseMap<const Expr*,unsigned> BlkExprMapTy;
|
||||
typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
|
||||
}
|
||||
|
||||
static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
|
||||
@ -999,23 +999,27 @@ 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."
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -77,7 +77,16 @@ void TransferFuncs::Visit(Stmt *S) {
|
||||
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) {
|
||||
@ -186,6 +195,10 @@ bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const {
|
||||
return Live(D,getAnalysisData());
|
||||
}
|
||||
|
||||
bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const {
|
||||
return getStmtData(Loc)(StmtVal,getAnalysisData());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// printing liveness state for debugging
|
||||
//
|
||||
|
||||
@ -255,9 +255,8 @@ public:
|
||||
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; }
|
||||
|
||||
@ -30,11 +30,10 @@ struct LiveVariables_ValueTypes {
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
@ -42,7 +41,7 @@ struct LiveVariables_ValueTypes {
|
||||
};
|
||||
|
||||
// We only keep actual dataflow state for declarations.
|
||||
typedef DeclBitVector_Types::ValTy ValTy;
|
||||
typedef ExprDeclBitVector_Types::ValTy ValTy;
|
||||
|
||||
//===-----------------------------------------------------===//
|
||||
// ObserverTy - Observer for uninitialized values queries.
|
||||
@ -76,6 +75,10 @@ public:
|
||||
/// 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.
|
||||
|
||||
@ -236,8 +236,8 @@ private:
|
||||
/// 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -110,9 +110,9 @@ public:
|
||||
|
||||
/// 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.");
|
||||
|
||||
@ -139,11 +139,11 @@ struct ExprDeclBitVector_Types {
|
||||
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;
|
||||
}
|
||||
@ -187,12 +187,12 @@ struct ExprDeclBitVector_Types {
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
@ -33,7 +33,7 @@ static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
|
||||
|
||||
template <typename ImplClass, typename RetTy=void>
|
||||
class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
Stmt* CurrentBlkExpr;
|
||||
Stmt* CurrentBlkStmt;
|
||||
|
||||
struct NullifyStmt {
|
||||
Stmt*& S;
|
||||
@ -42,11 +42,13 @@ class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
~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
|
||||
@ -59,8 +61,8 @@ public:
|
||||
/// 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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user