зеркало из https://github.com/microsoft/clang.git
Added "Dead Stores", a flow-sensitive checker that checks for stores
to variables that are no longer live. This analysis is built on top of CFGs and the LiveVariables analysis. changes to driver: added driver option "-check-dead-stores" to run the analysis git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41754 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
27b07c5fb9
Коммит
055c275fab
|
@ -372,7 +372,7 @@ void LiveVariables::runOnBlock(const CFGBlock* B, LiveVariablesAuditor* Auditor)
|
||||||
// liveness queries
|
// liveness queries
|
||||||
//
|
//
|
||||||
|
|
||||||
bool LiveVariables::IsLive(const CFGBlock* B, const Decl* D) const {
|
bool LiveVariables::isLive(const CFGBlock* B, const Decl* D) const {
|
||||||
BlockLivenessMap::const_iterator I = LiveAtBlockEntryMap.find(B);
|
BlockLivenessMap::const_iterator I = LiveAtBlockEntryMap.find(B);
|
||||||
assert (I != LiveAtBlockEntryMap.end());
|
assert (I != LiveAtBlockEntryMap.end());
|
||||||
|
|
||||||
|
@ -382,6 +382,12 @@ bool LiveVariables::IsLive(const CFGBlock* B, const Decl* D) const {
|
||||||
return I->second[VI->second.Idx];
|
return I->second[VI->second.Idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LiveVariables::isLive(llvm::BitVector& Live, const Decl* D) const {
|
||||||
|
VarInfoMap::const_iterator VI = VarInfos.find(D);
|
||||||
|
assert (VI != VarInfos.end());
|
||||||
|
return Live[VI->second.Idx];
|
||||||
|
}
|
||||||
|
|
||||||
bool LiveVariables::KillsVar(const Stmt* S, const Decl* D) const {
|
bool LiveVariables::KillsVar(const Stmt* S, const Decl* D) const {
|
||||||
VarInfoMap::const_iterator VI = VarInfos.find(D);
|
VarInfoMap::const_iterator VI = VarInfos.find(D);
|
||||||
assert (VI != VarInfos.end());
|
assert (VI != VarInfos.end());
|
||||||
|
@ -404,6 +410,15 @@ const LiveVariables::VarInfo& LiveVariables::getVarInfo(const Decl* D) const {
|
||||||
return const_cast<LiveVariables*>(this)->getVarInfo(D);
|
return const_cast<LiveVariables*>(this)->getVarInfo(D);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Defaults for LiveVariablesAuditor
|
||||||
|
|
||||||
|
void LiveVariablesAuditor::AuditStmt(Stmt* S, LiveVariables& L,
|
||||||
|
llvm::BitVector& V) {}
|
||||||
|
|
||||||
|
void LiveVariablesAuditor::AuditBlockExit(const CFGBlock* B, LiveVariables& L,
|
||||||
|
llvm::BitVector& V) {}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// printing liveness state for debugging
|
// printing liveness state for debugging
|
||||||
//
|
//
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "clang/AST/AST.h"
|
#include "clang/AST/AST.h"
|
||||||
#include "clang/AST/CFG.h"
|
#include "clang/AST/CFG.h"
|
||||||
#include "clang/Analysis/LiveVariables.h"
|
#include "clang/Analysis/LiveVariables.h"
|
||||||
|
#include "clang/Analysis/LocalCheckers.h"
|
||||||
#include "clang/Lex/Preprocessor.h"
|
#include "clang/Lex/Preprocessor.h"
|
||||||
#include "clang/Sema/ASTStreamer.h"
|
#include "clang/Sema/ASTStreamer.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
@ -209,4 +210,30 @@ void clang::AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID)
|
||||||
ASTStreamer_Terminate(Streamer);
|
ASTStreamer_Terminate(Streamer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clang::RunDeadStoresCheck(Preprocessor &PP, unsigned MainFileID,bool Stats)
|
||||||
|
{
|
||||||
|
ASTContext Context(PP.getTargetInfo(), PP.getIdentifierTable());
|
||||||
|
ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID);
|
||||||
|
|
||||||
|
while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) {
|
||||||
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||||
|
if (FD->getBody()) {
|
||||||
|
if (CFG* C = CFG::buildCFG(FD->getBody())) {
|
||||||
|
clang::CheckDeadStores(*C,PP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf(stderr," Error processing CFG.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Stats) {
|
||||||
|
fprintf(stderr, "\nSTATISTICS:\n");
|
||||||
|
ASTStreamer_PrintStats(Streamer);
|
||||||
|
Context.PrintStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTStreamer_Terminate(Streamer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ void DumpCFGs(Preprocessor &PP, unsigned MainFileID,
|
||||||
|
|
||||||
void AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID);
|
void AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID);
|
||||||
|
|
||||||
|
void RunDeadStoresCheck(Preprocessor &PP, unsigned MainFileID, bool Stats);
|
||||||
|
|
||||||
} // end clang namespace
|
} // end clang namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,6 +3,6 @@ CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
|
||||||
CXXFLAGS = -fno-rtti
|
CXXFLAGS = -fno-rtti
|
||||||
|
|
||||||
TOOLNAME = clang
|
TOOLNAME = clang
|
||||||
USEDLIBS = clangCodeGen.a clangSEMA.a clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a
|
USEDLIBS = clangCodeGen.a clangAnalysis.a clangSEMA.a clangAST.a clangParse.a clangLex.a clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.common
|
include $(LEVEL)/Makefile.common
|
||||||
|
|
|
@ -53,8 +53,9 @@ enum ProgActions {
|
||||||
ParseASTCheck, // Parse ASTs and check diagnostics.
|
ParseASTCheck, // Parse ASTs and check diagnostics.
|
||||||
ParseAST, // Parse ASTs.
|
ParseAST, // Parse ASTs.
|
||||||
ParseCFGDump, // Parse ASTS. Build CFGs. Print CFGs.
|
ParseCFGDump, // Parse ASTS. Build CFGs. Print CFGs.
|
||||||
ParseCFGView, // Parse ASTS. Build CFGs. View CFGs (Graphviz).
|
ParseCFGView, // Parse ASTS. Build CFGs. View CFGs.
|
||||||
AnalysisLiveVariables, // Print results of live-variable analysis.
|
AnalysisLiveVariables, // Print results of live-variable analysis.
|
||||||
|
WarnDeadStores, // Run DeadStores checker on parsed ASTs.
|
||||||
ParsePrintCallbacks, // Parse and print each callback.
|
ParsePrintCallbacks, // Parse and print each callback.
|
||||||
ParseSyntaxOnly, // Parse and perform semantic analysis.
|
ParseSyntaxOnly, // Parse and perform semantic analysis.
|
||||||
ParseNoop, // Parse with noop callbacks.
|
ParseNoop, // Parse with noop callbacks.
|
||||||
|
@ -93,6 +94,8 @@ ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
|
||||||
"Run parser, then build and view CFGs with Graphviz."),
|
"Run parser, then build and view CFGs with Graphviz."),
|
||||||
clEnumValN(AnalysisLiveVariables, "dump-live-variables",
|
clEnumValN(AnalysisLiveVariables, "dump-live-variables",
|
||||||
"Print results of live variable analysis."),
|
"Print results of live variable analysis."),
|
||||||
|
clEnumValN(WarnDeadStores, "check-dead-stores",
|
||||||
|
"Flag warnings of stores to dead variables."),
|
||||||
clEnumValN(EmitLLVM, "emit-llvm",
|
clEnumValN(EmitLLVM, "emit-llvm",
|
||||||
"Build ASTs then convert to LLVM, emit .ll file"),
|
"Build ASTs then convert to LLVM, emit .ll file"),
|
||||||
clEnumValEnd));
|
clEnumValEnd));
|
||||||
|
@ -852,6 +855,9 @@ static void ProcessInputFile(Preprocessor &PP, unsigned MainFileID,
|
||||||
case AnalysisLiveVariables:
|
case AnalysisLiveVariables:
|
||||||
AnalyzeLiveVariables(PP, MainFileID);
|
AnalyzeLiveVariables(PP, MainFileID);
|
||||||
break;
|
break;
|
||||||
|
case WarnDeadStores:
|
||||||
|
RunDeadStoresCheck(PP, MainFileID, Stats);
|
||||||
|
break;
|
||||||
case EmitLLVM:
|
case EmitLLVM:
|
||||||
EmitLLVMFromASTs(PP, MainFileID, Stats);
|
EmitLLVMFromASTs(PP, MainFileID, Stats);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; };
|
1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; };
|
||||||
1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; };
|
1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; };
|
||||||
35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */; };
|
35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */; };
|
||||||
|
355CF6840C90A8D400A08AA3 /* DeadStores.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 355CF6830C90A8D400A08AA3 /* DeadStores.cpp */; };
|
||||||
356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */; };
|
356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */; };
|
||||||
84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; };
|
84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; };
|
||||||
84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84D9A88B0C1A581300AC7ABC /* AttributeList.h */; };
|
84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84D9A88B0C1A581300AC7ABC /* AttributeList.h */; };
|
||||||
|
@ -210,6 +211,8 @@
|
||||||
1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; };
|
1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; };
|
||||||
35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = AST/ExprCXX.cpp; sourceTree = "<group>"; };
|
35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = AST/ExprCXX.cpp; sourceTree = "<group>"; };
|
||||||
3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = "<group>"; };
|
3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = "<group>"; };
|
||||||
|
355CF6820C90A8B600A08AA3 /* LocalCheckers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocalCheckers.h; path = clang/Analysis/LocalCheckers.h; sourceTree = "<group>"; };
|
||||||
|
355CF6830C90A8D400A08AA3 /* DeadStores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeadStores.cpp; path = Analysis/DeadStores.cpp; sourceTree = "<group>"; };
|
||||||
356EF9B20C8F7DBA006650F5 /* LiveVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LiveVariables.h; path = clang/Analysis/LiveVariables.h; sourceTree = "<group>"; };
|
356EF9B20C8F7DBA006650F5 /* LiveVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LiveVariables.h; path = clang/Analysis/LiveVariables.h; sourceTree = "<group>"; };
|
||||||
356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = Analysis/LiveVariables.cpp; sourceTree = "<group>"; };
|
356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = Analysis/LiveVariables.cpp; sourceTree = "<group>"; };
|
||||||
84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = "<group>"; };
|
84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = "<group>"; };
|
||||||
|
@ -377,9 +380,18 @@
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
355CF6850C90A8D600A08AA3 /* LocalCheckers */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
355CF6830C90A8D400A08AA3 /* DeadStores.cpp */,
|
||||||
|
);
|
||||||
|
name = LocalCheckers;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
356EF9AF0C8F7DA4006650F5 /* Analysis */ = {
|
356EF9AF0C8F7DA4006650F5 /* Analysis */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
355CF6820C90A8B600A08AA3 /* LocalCheckers.h */,
|
||||||
356EF9B20C8F7DBA006650F5 /* LiveVariables.h */,
|
356EF9B20C8F7DBA006650F5 /* LiveVariables.h */,
|
||||||
);
|
);
|
||||||
name = Analysis;
|
name = Analysis;
|
||||||
|
@ -389,6 +401,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */,
|
356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */,
|
||||||
|
355CF6850C90A8D600A08AA3 /* LocalCheckers */,
|
||||||
);
|
);
|
||||||
name = Analysis;
|
name = Analysis;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -741,6 +754,7 @@
|
||||||
35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */,
|
35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */,
|
||||||
DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */,
|
DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */,
|
||||||
356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */,
|
356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */,
|
||||||
|
355CF6840C90A8D400A08AA3 /* DeadStores.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,14 +30,14 @@ namespace clang {
|
||||||
|
|
||||||
class LiveVariablesAuditor {
|
class LiveVariablesAuditor {
|
||||||
public:
|
public:
|
||||||
virtual ~LiveVariablesAuditor();
|
virtual ~LiveVariablesAuditor() {}
|
||||||
|
|
||||||
/// AuditStmt - A callback invoked right before invoking the liveness
|
/// AuditStmt - A callback invoked right before invoking the liveness
|
||||||
/// transfer function on the given statement. If the liveness information
|
/// transfer function on the given statement. If the liveness information
|
||||||
/// has been previously calculated by running LiveVariables::runOnCFG,
|
/// has been previously calculated by running LiveVariables::runOnCFG,
|
||||||
/// then V contains the liveness information after the execution of
|
/// then V contains the liveness information after the execution of
|
||||||
/// the given statement.
|
/// the given statement.
|
||||||
virtual void AuditStmt(Stmt* S, LiveVariables& L, llvm::BitVector& V) = 0;
|
virtual void AuditStmt(Stmt* S, LiveVariables& L, llvm::BitVector& V);
|
||||||
|
|
||||||
/// AuditBlockExit - A callback invoked right before invoking the liveness
|
/// AuditBlockExit - A callback invoked right before invoking the liveness
|
||||||
/// transfer function on the given block. If the liveness information
|
/// transfer function on the given block. If the liveness information
|
||||||
|
@ -45,7 +45,7 @@ public:
|
||||||
/// then V contains the liveness information after the execution of
|
/// then V contains the liveness information after the execution of
|
||||||
/// the given block.
|
/// the given block.
|
||||||
virtual void AuditBlockExit(const CFGBlock* B, LiveVariables& L,
|
virtual void AuditBlockExit(const CFGBlock* B, LiveVariables& L,
|
||||||
llvm::BitVector& V) = 0;
|
llvm::BitVector& V);
|
||||||
};
|
};
|
||||||
|
|
||||||
class LiveVariables {
|
class LiveVariables {
|
||||||
|
@ -100,7 +100,12 @@ public:
|
||||||
|
|
||||||
/// IsLive - Return true if a variable is live at beginning of a specified
|
/// IsLive - Return true if a variable is live at beginning of a specified
|
||||||
// block.
|
// block.
|
||||||
bool IsLive(const CFGBlock* B, const Decl* D) const;
|
bool isLive(const CFGBlock* B, const Decl* D) const;
|
||||||
|
|
||||||
|
/// IsLive - Return true if a variable is live according to the provided
|
||||||
|
/// livness bitvector. This is typically used by classes that subclass
|
||||||
|
/// LiveVariablesAuditor.
|
||||||
|
bool isLive(llvm::BitVector& V, const Decl* D) const;
|
||||||
|
|
||||||
/// getVarInfo - Return the liveness information associated with a given
|
/// getVarInfo - Return the liveness information associated with a given
|
||||||
/// variable.
|
/// variable.
|
||||||
|
|
|
@ -748,6 +748,9 @@ DIAG(warn_ret_stack_ref, WARNING,
|
||||||
DIAG(warn_floatingpoint_eq, WARNING,
|
DIAG(warn_floatingpoint_eq, WARNING,
|
||||||
"comparing floating point with == or != is unsafe")
|
"comparing floating point with == or != is unsafe")
|
||||||
|
|
||||||
|
// CHECK: stores to variables that are no longer live (dead stores)
|
||||||
|
DIAG(warn_dead_store, WARNING, "value stored to variable is never used")
|
||||||
|
|
||||||
// CFString checking
|
// CFString checking
|
||||||
DIAG(err_cfstring_literal_not_string_constant, ERROR,
|
DIAG(err_cfstring_literal_not_string_constant, ERROR,
|
||||||
"CFString literal is not a string constant")
|
"CFString literal is not a string constant")
|
||||||
|
|
Загрузка…
Ссылка в новой задаче