Newer
Older
//=- LiveVariables.cpp - Live Variable Analysis for Source CFGs -*- C++ --*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// details.
//
//===----------------------------------------------------------------------===//
//
// This file implements Live Variables analysis for source-level CFGs.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/AST/Expr.h"
#include "clang/AST/CFG.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "llvm/ADT/SmallPtrSet.h"
Ted Kremenek
committed
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
using namespace clang;
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Useful constants.
//===----------------------------------------------------------------------===//
static const bool Alive = true;
static const bool Dead = false;
//===----------------------------------------------------------------------===//
// Dataflow initialization logic.
//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN RegisterDecls
: public CFGRecStmtDeclVisitor<RegisterDecls> {
LiveVariables::AnalysisDataTy& AD;
Ted Kremenek
committed
typedef llvm::SmallVector<VarDecl*, 20> AlwaysLiveTy;
AlwaysLiveTy AlwaysLive;
public:
Ted Kremenek
committed
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
~RegisterDecls() {
AD.AlwaysLive.resetValues(AD);
for (AlwaysLiveTy::iterator I = AlwaysLive.begin(), E = AlwaysLive.end();
I != E; ++ I)
AD.AlwaysLive(*I, AD) = Alive;
}
void VisitVarDecl(VarDecl* VD) {
// Register the VarDecl for tracking.
AD.Register(VD);
// Does the variable have global storage? If so, it is always live.
if (VD->hasGlobalStorage())
AlwaysLive.push_back(VD);
}
void VisitUnaryOperator(UnaryOperator* U) {
// Check for '&'. Any VarDecl whose value has its address-taken we
// treat as always being live (flow-insensitive).
Expr* E = U->getSubExpr()->IgnoreParenCasts();
if (U->getOpcode() == UnaryOperator::AddrOf)
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
AD.Register(VD);
AlwaysLive.push_back(VD);
return;
}
Visit(E);
}
CFG& getCFG() { return AD.getCFG(); }
} // end anonymous namespace
Ted Kremenek
committed
Ted Kremenek
committed
LiveVariables::LiveVariables(CFG& cfg) {
// Register all referenced VarDecls.
Ted Kremenek
committed
getAnalysisData().setCFG(&cfg);
RegisterDecls R(getAnalysisData());
cfg.VisitBlockStmts(R);
}
//===----------------------------------------------------------------------===//
// Transfer functions.
//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
LiveVariables::AnalysisDataTy& AD;
LiveVariables::ValTy LiveState;
public:
TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
LiveVariables::ValTy& getVal() { return LiveState; }
CFG& getCFG() { return AD.getCFG(); }
Ted Kremenek
committed
void VisitDeclRefExpr(DeclRefExpr* DR);
void VisitBinaryOperator(BinaryOperator* B);
void VisitAssign(BinaryOperator* B);
void VisitDeclStmt(DeclStmt* DS);
void VisitUnaryOperator(UnaryOperator* U);
Ted Kremenek
committed
void Visit(Stmt *S);
void VisitTerminator(Stmt* S);
Ted Kremenek
committed
void SetTopValue(LiveVariables::ValTy& V) {
V = AD.AlwaysLive;
}
void TransferFuncs::Visit(Stmt *S) {
if (AD.Observer)
AD.Observer->ObserveStmt(S,AD,LiveState);
Ted Kremenek
committed
if (S == getCurrentBlkStmt()) {
if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead;
StmtVisitor<TransferFuncs,void>::Visit(S);
Ted Kremenek
committed
}
else if (!getCFG().isBlkExpr(S))
StmtVisitor<TransferFuncs,void>::Visit(S);
else
// For block-level expressions, mark that they are live.
LiveState(S,AD) = Alive;
Ted Kremenek
committed
void TransferFuncs::VisitTerminator(Stmt* S) {
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
Expr* E = NULL;
switch (S->getStmtClass()) {
default:
return;
case Stmt::ForStmtClass:
E = cast<ForStmt>(S)->getCond();
break;
case Stmt::WhileStmtClass:
E = cast<WhileStmt>(S)->getCond();
break;
case Stmt::DoStmtClass:
E = cast<DoStmt>(S)->getCond();
break;
case Stmt::IfStmtClass:
E = cast<IfStmt>(S)->getCond();
break;
case Stmt::ChooseExprClass:
E = cast<ChooseExpr>(S)->getCond();
break;
case Stmt::IndirectGotoStmtClass:
E = cast<IndirectGotoStmt>(S)->getTarget();
break;
case Stmt::SwitchStmtClass:
E = cast<SwitchStmt>(S)->getCond();
break;
case Stmt::ConditionalOperatorClass:
E = cast<ConditionalOperator>(S)->getCond();
break;
case Stmt::BinaryOperatorClass: // '&&' and '||'
E = cast<BinaryOperator>(S)->getLHS();
break;
Ted Kremenek
committed
}
if (!E)
return;
E = E->IgnoreParens();
assert (getCFG().isBlkExpr(E));
LiveState(E, AD) = Alive;
Ted Kremenek
committed
}
void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
LiveState(V,AD) = Alive;
void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
Ted Kremenek
committed
if (B->isAssignmentOp()) VisitAssign(B);
else VisitStmt(B);
void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
Expr *E = U->getSubExpr();
case UnaryOperator::SizeOf: return;
case UnaryOperator::PostInc:
case UnaryOperator::PostDec:
case UnaryOperator::PreInc:
case UnaryOperator::PreDec:
// Walk through the subexpressions, blasting through ParenExprs
// until we either find a DeclRefExpr or some non-DeclRefExpr
// expression.
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParens()))
if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
// Treat the --/++ operator as a kill.
if (AD.Observer) { AD.Observer->ObserverKill(DR); }
LiveState(VD, AD) = Alive;
return VisitDeclRefExpr(DR);
}
// Fall-through.
default:
return Visit(E);
void TransferFuncs::VisitAssign(BinaryOperator* B) {
Expr* LHS = B->getLHS();
// Assigning to a variable?
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParens())) {
Ted Kremenek
committed
// Update liveness inforamtion.
unsigned bit = AD.getIdx(DR->getDecl());
LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
if (AD.Observer) { AD.Observer->ObserverKill(DR); }
// Handle things like +=, etc., which also generate "uses"
// of a variable. Do this just by visiting the subexpression.
if (B->getOpcode() != BinaryOperator::Assign)
VisitDeclRefExpr(DR);
else // Not assigning to a variable. Process LHS as usual.
Visit(B->getRHS());
void TransferFuncs::VisitDeclStmt(DeclStmt* DS) {
// Declarations effectively "kill" a variable since they cannot
// possibly be live before they are declared.
for (ScopedDecl* D = DS->getDecl(); D != NULL; D = D->getNextDeclarator())
if (VarDecl* VD = dyn_cast<VarDecl>(D)) {
Ted Kremenek
committed
// Update liveness information.
unsigned bit = AD.getIdx(VD);
LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
if (Expr* Init = VD->getInit())
Visit(Init);
}
}
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Merge operator: if something is live on any successor block, it is live
// in the current block (a set union).
//===----------------------------------------------------------------------===//
namespace {
struct Merge {
typedef ExprDeclBitVector_Types::ValTy ValTy;
void operator()(ValTy& Dst, const ValTy& Src) {
Dst.OrDeclBits(Src);
Dst.AndExprBits(Src);
}
};
typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver;
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// External interface to run Liveness analysis.
//===----------------------------------------------------------------------===//
void LiveVariables::runOnCFG(CFG& cfg) {
Solver S(*this);
S.runOnCFG(cfg);
}
void LiveVariables::runOnAllBlocks(const CFG& cfg,
LiveVariables::ObserverTy* Obs,
bool recordStmtValues) {
Solver S(*this);
ObserverTy* OldObserver = getAnalysisData().Observer;
getAnalysisData().Observer = Obs;
S.runOnAllBlocks(cfg, recordStmtValues);
getAnalysisData().Observer = OldObserver;
}
//===----------------------------------------------------------------------===//
// liveness queries
//
bool LiveVariables::isLive(const CFGBlock* B, const VarDecl* D) const {
Ted Kremenek
committed
DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D);
return i.isValid() ? getBlockData(B).getBit(i) : false;
bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const {
Ted Kremenek
committed
DeclBitVector_Types::Idx i = getAnalysisData().getIdx(D);
return i.isValid() ? Live.getBit(i) : false;
}
Ted Kremenek
committed
bool LiveVariables::isLive(const Stmt* Loc, const Stmt* StmtVal) const {
return getStmtData(Loc)(StmtVal,getAnalysisData());
}
bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const {
return getStmtData(Loc)(D,getAnalysisData());
}
//===----------------------------------------------------------------------===//
// printing liveness state for debugging
//
void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
const AnalysisDataTy& AD = getAnalysisData();
for (AnalysisDataTy::decl_iterator I = AD.begin_decl(),
E = AD.end_decl(); I!=E; ++I)
if (V.getDeclBit(I->second)) {
SourceLocation PhysLoc = SM.getPhysicalLoc(I->first->getLocation());
fprintf(stderr, " %s <%s:%u:%u>\n",
I->first->getIdentifier()->getName(),
SM.getSourceName(PhysLoc),
SM.getLineNumber(PhysLoc),
SM.getColumnNumber(PhysLoc));
}
}
void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
for (BlockDataMapTy::iterator I = getBlockDataMap().begin(),
E = getBlockDataMap().end(); I!=E; ++I) {
fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n",
I->first->getBlockID());
dumpLiveness(I->second,M);
}
fprintf(stderr,"\n");
}