Further reduce "-fsyntax-only -Wuninitialized" time on sqlite3.c by another 2.5% using intelligent pruning of blocks during the final reporting pass.

llvm-svn: 168257
This commit is contained in:
Ted Kremenek 2012-11-17 07:18:30 +00:00
parent 15443ee70f
commit 778a6ed358
1 changed files with 52 additions and 12 deletions

View File

@ -426,13 +426,13 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {
AnalysisDeclContext &ac; AnalysisDeclContext &ac;
const ClassifyRefs &classification; const ClassifyRefs &classification;
ObjCNoReturn objCNoRet; ObjCNoReturn objCNoRet;
UninitVariablesHandler *handler; UninitVariablesHandler &handler;
public: public:
TransferFunctions(CFGBlockValues &vals, const CFG &cfg, TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
const CFGBlock *block, AnalysisDeclContext &ac, const CFGBlock *block, AnalysisDeclContext &ac,
const ClassifyRefs &classification, const ClassifyRefs &classification,
UninitVariablesHandler *handler) UninitVariablesHandler &handler)
: vals(vals), cfg(cfg), block(block), ac(ac), : vals(vals), cfg(cfg), block(block), ac(ac),
classification(classification), objCNoRet(ac.getASTContext()), classification(classification), objCNoRet(ac.getASTContext()),
handler(handler) {} handler(handler) {}
@ -589,11 +589,9 @@ public:
} }
void TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd) { void TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd) {
if (!handler)
return;
Value v = vals[vd]; Value v = vals[vd];
if (isUninitialized(v)) if (isUninitialized(v))
handler->handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v)); handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
} }
void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) { void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
@ -654,8 +652,7 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
vals[cast<VarDecl>(dr->getDecl())] = Initialized; vals[cast<VarDecl>(dr->getDecl())] = Initialized;
break; break;
case ClassifyRefs::SelfInit: case ClassifyRefs::SelfInit:
if (handler) handler.handleSelfInit(cast<VarDecl>(dr->getDecl()));
handler->handleSelfInit(cast<VarDecl>(dr->getDecl()));
break; break;
} }
} }
@ -721,7 +718,7 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
AnalysisDeclContext &ac, CFGBlockValues &vals, AnalysisDeclContext &ac, CFGBlockValues &vals,
const ClassifyRefs &classification, const ClassifyRefs &classification,
llvm::BitVector &wasAnalyzed, llvm::BitVector &wasAnalyzed,
UninitVariablesHandler *handler = 0) { UninitVariablesHandler &handler) {
wasAnalyzed[block->getBlockID()] = true; wasAnalyzed[block->getBlockID()] = true;
vals.resetScratch(); vals.resetScratch();
// Merge in values of predecessor blocks. // Merge in values of predecessor blocks.
@ -745,6 +742,43 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
return vals.updateValueVectorWithScratch(block); return vals.updateValueVectorWithScratch(block);
} }
/// PruneBlocksHandler is a special UninitVariablesHandler that is used
/// to detect when a CFGBlock has any *potential* use of an uninitialized
/// variable. It is mainly used to prune out work during the final
/// reporting pass.
namespace {
struct PruneBlocksHandler : public UninitVariablesHandler {
PruneBlocksHandler(unsigned numBlocks)
: hadUse(numBlocks, false), hadAnyUse(false),
currentBlock(0) {}
virtual ~PruneBlocksHandler() {}
/// Records if a CFGBlock had a potential use of an uninitialized variable.
llvm::BitVector hadUse;
/// Records if any CFGBlock had a potential use of an uninitialized variable.
bool hadAnyUse;
/// The current block to scribble use information.
unsigned currentBlock;
virtual void handleUseOfUninitVariable(const VarDecl *vd,
const UninitUse &use) {
hadUse[currentBlock] = true;
hadAnyUse = true;
}
/// Called when the uninitialized variable analysis detects the
/// idiom 'int x = x'. All other uses of 'x' within the initializer
/// are handled by handleUseOfUninitVariable.
virtual void handleSelfInit(const VarDecl *vd) {
hadUse[currentBlock] = true;
hadAnyUse = true;
}
};
}
void clang::runUninitializedVariablesAnalysis( void clang::runUninitializedVariablesAnalysis(
const DeclContext &dc, const DeclContext &dc,
const CFG &cfg, const CFG &cfg,
@ -776,22 +810,28 @@ void clang::runUninitializedVariablesAnalysis(
worklist.enqueueSuccessors(&cfg.getEntry()); worklist.enqueueSuccessors(&cfg.getEntry());
llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false); llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
wasAnalyzed[cfg.getEntry().getBlockID()] = true; wasAnalyzed[cfg.getEntry().getBlockID()] = true;
PruneBlocksHandler PBH(cfg.getNumBlockIDs());
while (const CFGBlock *block = worklist.dequeue()) { while (const CFGBlock *block = worklist.dequeue()) {
PBH.currentBlock = block->getBlockID();
// Did the block change? // Did the block change?
bool changed = runOnBlock(block, cfg, ac, vals, bool changed = runOnBlock(block, cfg, ac, vals,
classification, wasAnalyzed); classification, wasAnalyzed, PBH);
++stats.NumBlockVisits; ++stats.NumBlockVisits;
if (changed || !previouslyVisited[block->getBlockID()]) if (changed || !previouslyVisited[block->getBlockID()])
worklist.enqueueSuccessors(block); worklist.enqueueSuccessors(block);
previouslyVisited[block->getBlockID()] = true; previouslyVisited[block->getBlockID()] = true;
} }
if (!PBH.hadAnyUse)
return;
// Run through the blocks one more time, and report uninitialized variabes. // Run through the blocks one more time, and report uninitialized variabes.
for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
const CFGBlock *block = *BI; const CFGBlock *block = *BI;
if (wasAnalyzed[block->getBlockID()]) { if (PBH.hadUse[block->getBlockID()]) {
runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, &handler); runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
++stats.NumBlockVisits; ++stats.NumBlockVisits;
} }
} }