mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-16 00:16:50 +00:00
Convert ProfileVerifier to template so it can be used for different types of ProfileInfo.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@90451 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1640f7e033
commit
8c30abec6d
@ -21,6 +21,7 @@
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include "llvm/Support/InstIterator.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include <set>
|
||||
using namespace llvm;
|
||||
@ -29,44 +30,45 @@ static cl::opt<bool,false>
|
||||
ProfileVerifierDisableAssertions("profile-verifier-noassert",
|
||||
cl::desc("Disable assertions"));
|
||||
|
||||
namespace {
|
||||
class ProfileVerifierPass : public FunctionPass {
|
||||
namespace llvm {
|
||||
template<class FType, class BType>
|
||||
class ProfileVerifierPassT : public FunctionPass {
|
||||
|
||||
struct DetailedBlockInfo {
|
||||
const BasicBlock *BB;
|
||||
double BBWeight;
|
||||
double inWeight;
|
||||
int inCount;
|
||||
double outWeight;
|
||||
int outCount;
|
||||
const BType *BB;
|
||||
double BBWeight;
|
||||
double inWeight;
|
||||
int inCount;
|
||||
double outWeight;
|
||||
int outCount;
|
||||
};
|
||||
|
||||
ProfileInfo *PI;
|
||||
std::set<const BasicBlock*> BBisVisited;
|
||||
std::set<const Function*> FisVisited;
|
||||
ProfileInfoT<FType, BType> *PI;
|
||||
std::set<const BType*> BBisVisited;
|
||||
std::set<const FType*> FisVisited;
|
||||
bool DisableAssertions;
|
||||
|
||||
// When debugging is enabled, the verifier prints a whole slew of debug
|
||||
// information, otherwise its just the assert. These are all the helper
|
||||
// functions.
|
||||
bool PrintedDebugTree;
|
||||
std::set<const BasicBlock*> BBisPrinted;
|
||||
std::set<const BType*> BBisPrinted;
|
||||
void debugEntry(DetailedBlockInfo*);
|
||||
void printDebugInfo(const BasicBlock *BB);
|
||||
void printDebugInfo(const BType *BB);
|
||||
|
||||
public:
|
||||
static char ID; // Class identification, replacement for typeinfo
|
||||
|
||||
explicit ProfileVerifierPass () : FunctionPass(&ID) {
|
||||
explicit ProfileVerifierPassT () : FunctionPass(&ID) {
|
||||
DisableAssertions = ProfileVerifierDisableAssertions;
|
||||
}
|
||||
explicit ProfileVerifierPass (bool da) : FunctionPass(&ID),
|
||||
DisableAssertions(da) {
|
||||
explicit ProfileVerifierPassT (bool da) : FunctionPass(&ID),
|
||||
DisableAssertions(da) {
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<ProfileInfo>();
|
||||
AU.addRequired<ProfileInfoT<FType, BType> >();
|
||||
}
|
||||
|
||||
const char *getPassName() const {
|
||||
@ -74,16 +76,296 @@ namespace {
|
||||
}
|
||||
|
||||
/// run - Verify the profile information.
|
||||
bool runOnFunction(Function &F);
|
||||
void recurseBasicBlock(const BasicBlock*);
|
||||
bool runOnFunction(FType &F);
|
||||
void recurseBasicBlock(const BType*);
|
||||
|
||||
bool exitReachable(const Function*);
|
||||
double ReadOrAssert(ProfileInfo::Edge);
|
||||
bool exitReachable(const FType*);
|
||||
double ReadOrAssert(typename ProfileInfoT<FType, BType>::Edge);
|
||||
void CheckValue(bool, const char*, DetailedBlockInfo*);
|
||||
};
|
||||
} // End of anonymous namespace
|
||||
|
||||
char ProfileVerifierPass::ID = 0;
|
||||
typedef ProfileVerifierPassT<Function, BasicBlock> ProfileVerifierPass;
|
||||
|
||||
template<class FType, class BType>
|
||||
void ProfileVerifierPassT<FType, BType>::printDebugInfo(const BType *BB) {
|
||||
|
||||
if (BBisPrinted.find(BB) != BBisPrinted.end()) return;
|
||||
|
||||
double BBWeight = PI->getExecutionCount(BB);
|
||||
if (BBWeight == ProfileInfoT<FType, BType>::MissingValue) { BBWeight = 0; }
|
||||
double inWeight = 0;
|
||||
int inCount = 0;
|
||||
std::set<const BType*> ProcessedPreds;
|
||||
for ( pred_const_iterator bbi = pred_begin(BB), bbe = pred_end(BB);
|
||||
bbi != bbe; ++bbi ) {
|
||||
if (ProcessedPreds.insert(*bbi).second) {
|
||||
typename ProfileInfoT<FType, BType>::Edge E = PI->getEdge(*bbi,BB);
|
||||
double EdgeWeight = PI->getEdgeWeight(E);
|
||||
if (EdgeWeight == ProfileInfoT<FType, BType>::MissingValue) { EdgeWeight = 0; }
|
||||
errs() << "calculated in-edge " << E << ": "
|
||||
<< format("%20.20g",EdgeWeight) << "\n";
|
||||
inWeight += EdgeWeight;
|
||||
inCount++;
|
||||
}
|
||||
}
|
||||
double outWeight = 0;
|
||||
int outCount = 0;
|
||||
std::set<const BType*> ProcessedSuccs;
|
||||
for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
|
||||
bbi != bbe; ++bbi ) {
|
||||
if (ProcessedSuccs.insert(*bbi).second) {
|
||||
typename ProfileInfoT<FType, BType>::Edge E = PI->getEdge(BB,*bbi);
|
||||
double EdgeWeight = PI->getEdgeWeight(E);
|
||||
if (EdgeWeight == ProfileInfoT<FType, BType>::MissingValue) { EdgeWeight = 0; }
|
||||
errs() << "calculated out-edge " << E << ": "
|
||||
<< format("%20.20g",EdgeWeight) << "\n";
|
||||
outWeight += EdgeWeight;
|
||||
outCount++;
|
||||
}
|
||||
}
|
||||
errs() << "Block " << BB->getNameStr() << " in "
|
||||
<< BB->getParent()->getNameStr() << ":"
|
||||
<< "BBWeight=" << format("%20.20g",BBWeight) << ","
|
||||
<< "inWeight=" << format("%20.20g",inWeight) << ","
|
||||
<< "inCount=" << inCount << ","
|
||||
<< "outWeight=" << format("%20.20g",outWeight) << ","
|
||||
<< "outCount" << outCount << "\n";
|
||||
|
||||
// mark as visited and recurse into subnodes
|
||||
BBisPrinted.insert(BB);
|
||||
for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
|
||||
bbi != bbe; ++bbi ) {
|
||||
printDebugInfo(*bbi);
|
||||
}
|
||||
}
|
||||
|
||||
template<class FType, class BType>
|
||||
void ProfileVerifierPassT<FType, BType>::debugEntry (DetailedBlockInfo *DI) {
|
||||
errs() << "TROUBLE: Block " << DI->BB->getNameStr() << " in "
|
||||
<< DI->BB->getParent()->getNameStr() << ":"
|
||||
<< "BBWeight=" << format("%20.20g",DI->BBWeight) << ","
|
||||
<< "inWeight=" << format("%20.20g",DI->inWeight) << ","
|
||||
<< "inCount=" << DI->inCount << ","
|
||||
<< "outWeight=" << format("%20.20g",DI->outWeight) << ","
|
||||
<< "outCount=" << DI->outCount << "\n";
|
||||
if (!PrintedDebugTree) {
|
||||
PrintedDebugTree = true;
|
||||
printDebugInfo(&(DI->BB->getParent()->getEntryBlock()));
|
||||
}
|
||||
}
|
||||
|
||||
// This compares A and B for equality.
|
||||
static bool Equals(double A, double B) {
|
||||
return A == B;
|
||||
}
|
||||
|
||||
// This checks if the function "exit" is reachable from an given function
|
||||
// via calls, this is necessary to check if a profile is valid despite the
|
||||
// counts not fitting exactly.
|
||||
template<class FType, class BType>
|
||||
bool ProfileVerifierPassT<FType, BType>::exitReachable(const FType *F) {
|
||||
if (!F) return false;
|
||||
|
||||
if (FisVisited.count(F)) return false;
|
||||
|
||||
FType *Exit = F->getParent()->getFunction("exit");
|
||||
if (Exit == F) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FisVisited.insert(F);
|
||||
bool exits = false;
|
||||
for (const_inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
|
||||
if (const CallInst *CI = dyn_cast<CallInst>(&*I)) {
|
||||
FType *F = CI->getCalledFunction();
|
||||
if (F) {
|
||||
exits |= exitReachable(F);
|
||||
} else {
|
||||
// This is a call to a pointer, all bets are off...
|
||||
exits = true;
|
||||
}
|
||||
if (exits) break;
|
||||
}
|
||||
}
|
||||
return exits;
|
||||
}
|
||||
|
||||
#define ASSERTMESSAGE(M) \
|
||||
{ errs() << "ASSERT:" << (M) << "\n"; \
|
||||
if (!DisableAssertions) assert(0 && (M)); }
|
||||
|
||||
template<class FType, class BType>
|
||||
double ProfileVerifierPassT<FType, BType>::ReadOrAssert(typename ProfileInfoT<FType, BType>::Edge E) {
|
||||
double EdgeWeight = PI->getEdgeWeight(E);
|
||||
if (EdgeWeight == ProfileInfoT<FType, BType>::MissingValue) {
|
||||
errs() << "Edge " << E << " in Function "
|
||||
<< ProfileInfoT<FType, BType>::getFunction(E)->getNameStr() << ": ";
|
||||
ASSERTMESSAGE("Edge has missing value");
|
||||
return 0;
|
||||
} else {
|
||||
if (EdgeWeight < 0) {
|
||||
errs() << "Edge " << E << " in Function "
|
||||
<< ProfileInfoT<FType, BType>::getFunction(E)->getNameStr() << ": ";
|
||||
ASSERTMESSAGE("Edge has negative value");
|
||||
}
|
||||
return EdgeWeight;
|
||||
}
|
||||
}
|
||||
|
||||
template<class FType, class BType>
|
||||
void ProfileVerifierPassT<FType, BType>::CheckValue(bool Error,
|
||||
const char *Message,
|
||||
DetailedBlockInfo *DI) {
|
||||
if (Error) {
|
||||
DEBUG(debugEntry(DI));
|
||||
errs() << "Block " << DI->BB->getNameStr() << " in Function "
|
||||
<< DI->BB->getParent()->getNameStr() << ": ";
|
||||
ASSERTMESSAGE(Message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// This calculates the Information for a block and then recurses into the
|
||||
// successors.
|
||||
template<class FType, class BType>
|
||||
void ProfileVerifierPassT<FType, BType>::recurseBasicBlock(const BType *BB) {
|
||||
|
||||
// Break the recursion by remembering all visited blocks.
|
||||
if (BBisVisited.find(BB) != BBisVisited.end()) return;
|
||||
|
||||
// Use a data structure to store all the information, this can then be handed
|
||||
// to debug printers.
|
||||
DetailedBlockInfo DI;
|
||||
DI.BB = BB;
|
||||
DI.outCount = DI.inCount = 0;
|
||||
DI.inWeight = DI.outWeight = 0;
|
||||
|
||||
// Read predecessors.
|
||||
std::set<const BType*> ProcessedPreds;
|
||||
pred_const_iterator bpi = pred_begin(BB), bpe = pred_end(BB);
|
||||
// If there are none, check for (0,BB) edge.
|
||||
if (bpi == bpe) {
|
||||
DI.inWeight += ReadOrAssert(PI->getEdge(0,BB));
|
||||
DI.inCount++;
|
||||
}
|
||||
for (;bpi != bpe; ++bpi) {
|
||||
if (ProcessedPreds.insert(*bpi).second) {
|
||||
DI.inWeight += ReadOrAssert(PI->getEdge(*bpi,BB));
|
||||
DI.inCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Read successors.
|
||||
std::set<const BType*> ProcessedSuccs;
|
||||
succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
|
||||
// If there is an (0,BB) edge, consider it too. (This is done not only when
|
||||
// there are no successors, but every time; not every function contains
|
||||
// return blocks with no successors (think loop latch as return block)).
|
||||
double w = PI->getEdgeWeight(PI->getEdge(BB,0));
|
||||
if (w != ProfileInfoT<FType, BType>::MissingValue) {
|
||||
DI.outWeight += w;
|
||||
DI.outCount++;
|
||||
}
|
||||
for (;bbi != bbe; ++bbi) {
|
||||
if (ProcessedSuccs.insert(*bbi).second) {
|
||||
DI.outWeight += ReadOrAssert(PI->getEdge(BB,*bbi));
|
||||
DI.outCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Read block weight.
|
||||
DI.BBWeight = PI->getExecutionCount(BB);
|
||||
CheckValue(DI.BBWeight == ProfileInfoT<FType, BType>::MissingValue,
|
||||
"BasicBlock has missing value", &DI);
|
||||
CheckValue(DI.BBWeight < 0,
|
||||
"BasicBlock has negative value", &DI);
|
||||
|
||||
// Check if this block is a setjmp target.
|
||||
bool isSetJmpTarget = false;
|
||||
if (DI.outWeight > DI.inWeight) {
|
||||
for (typename BType::const_iterator i = BB->begin(), ie = BB->end();
|
||||
i != ie; ++i) {
|
||||
if (const CallInst *CI = dyn_cast<CallInst>(&*i)) {
|
||||
FType *F = CI->getCalledFunction();
|
||||
if (F && (F->getNameStr() == "_setjmp")) {
|
||||
isSetJmpTarget = true; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if this block is eventually reaching exit.
|
||||
bool isExitReachable = false;
|
||||
if (DI.inWeight > DI.outWeight) {
|
||||
for (typename BType::const_iterator i = BB->begin(), ie = BB->end();
|
||||
i != ie; ++i) {
|
||||
if (const CallInst *CI = dyn_cast<CallInst>(&*i)) {
|
||||
FType *F = CI->getCalledFunction();
|
||||
if (F) {
|
||||
FisVisited.clear();
|
||||
isExitReachable |= exitReachable(F);
|
||||
} else {
|
||||
// This is a call to a pointer, all bets are off...
|
||||
isExitReachable = true;
|
||||
}
|
||||
if (isExitReachable) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DI.inCount > 0 && DI.outCount == 0) {
|
||||
// If this is a block with no successors.
|
||||
if (!isSetJmpTarget) {
|
||||
CheckValue(!Equals(DI.inWeight,DI.BBWeight),
|
||||
"inWeight and BBWeight do not match", &DI);
|
||||
}
|
||||
} else if (DI.inCount == 0 && DI.outCount > 0) {
|
||||
// If this is a block with no predecessors.
|
||||
if (!isExitReachable)
|
||||
CheckValue(!Equals(DI.BBWeight,DI.outWeight),
|
||||
"BBWeight and outWeight do not match", &DI);
|
||||
} else {
|
||||
// If this block has successors and predecessors.
|
||||
if (DI.inWeight > DI.outWeight && !isExitReachable)
|
||||
CheckValue(!Equals(DI.inWeight,DI.outWeight),
|
||||
"inWeight and outWeight do not match", &DI);
|
||||
if (DI.inWeight < DI.outWeight && !isSetJmpTarget)
|
||||
CheckValue(!Equals(DI.inWeight,DI.outWeight),
|
||||
"inWeight and outWeight do not match", &DI);
|
||||
}
|
||||
|
||||
|
||||
// Mark this block as visited, rescurse into successors.
|
||||
BBisVisited.insert(BB);
|
||||
for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
|
||||
bbi != bbe; ++bbi ) {
|
||||
recurseBasicBlock(*bbi);
|
||||
}
|
||||
}
|
||||
|
||||
template<class FType, class BType>
|
||||
bool ProfileVerifierPassT<FType, BType>::runOnFunction(FType &F) {
|
||||
PI = getAnalysisIfAvailable<ProfileInfoT<FType, BType> >();
|
||||
if (!PI)
|
||||
ASSERTMESSAGE("No ProfileInfo available");
|
||||
|
||||
// Prepare global variables.
|
||||
PrintedDebugTree = false;
|
||||
BBisVisited.clear();
|
||||
|
||||
// Fetch entry block and recurse into it.
|
||||
const BType *entry = &F.getEntryBlock();
|
||||
recurseBasicBlock(entry);
|
||||
|
||||
if (PI->getExecutionCount(&F) != PI->getExecutionCount(entry))
|
||||
ASSERTMESSAGE("Function count and entry block count do not match");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class FType, class BType>
|
||||
char ProfileVerifierPassT<FType, BType>::ID = 0;
|
||||
}
|
||||
|
||||
static RegisterPass<ProfileVerifierPass>
|
||||
X("profile-verifier", "Verify profiling information", false, true);
|
||||
|
||||
@ -93,252 +375,3 @@ namespace llvm {
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileVerifierPass::printDebugInfo(const BasicBlock *BB) {
|
||||
|
||||
if (BBisPrinted.find(BB) != BBisPrinted.end()) return;
|
||||
|
||||
double BBWeight = PI->getExecutionCount(BB);
|
||||
if (BBWeight == ProfileInfo::MissingValue) { BBWeight = 0; }
|
||||
double inWeight = 0;
|
||||
int inCount = 0;
|
||||
std::set<const BasicBlock*> ProcessedPreds;
|
||||
for ( pred_const_iterator bbi = pred_begin(BB), bbe = pred_end(BB);
|
||||
bbi != bbe; ++bbi ) {
|
||||
if (ProcessedPreds.insert(*bbi).second) {
|
||||
ProfileInfo::Edge E = PI->getEdge(*bbi,BB);
|
||||
double EdgeWeight = PI->getEdgeWeight(E);
|
||||
if (EdgeWeight == ProfileInfo::MissingValue) { EdgeWeight = 0; }
|
||||
errs() << "calculated in-edge " << E << ": " << EdgeWeight << "\n";
|
||||
inWeight += EdgeWeight;
|
||||
inCount++;
|
||||
}
|
||||
}
|
||||
double outWeight = 0;
|
||||
int outCount = 0;
|
||||
std::set<const BasicBlock*> ProcessedSuccs;
|
||||
for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
|
||||
bbi != bbe; ++bbi ) {
|
||||
if (ProcessedSuccs.insert(*bbi).second) {
|
||||
ProfileInfo::Edge E = PI->getEdge(BB,*bbi);
|
||||
double EdgeWeight = PI->getEdgeWeight(E);
|
||||
if (EdgeWeight == ProfileInfo::MissingValue) { EdgeWeight = 0; }
|
||||
errs() << "calculated out-edge " << E << ": " << EdgeWeight << "\n";
|
||||
outWeight += EdgeWeight;
|
||||
outCount++;
|
||||
}
|
||||
}
|
||||
errs()<<"Block "<<BB->getNameStr()<<" in "<<BB->getParent()->getNameStr()
|
||||
<<",BBWeight="<<BBWeight<<",inWeight="<<inWeight<<",inCount="<<inCount
|
||||
<<",outWeight="<<outWeight<<",outCount"<<outCount<<"\n";
|
||||
|
||||
// mark as visited and recurse into subnodes
|
||||
BBisPrinted.insert(BB);
|
||||
for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
|
||||
bbi != bbe; ++bbi ) {
|
||||
printDebugInfo(*bbi);
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileVerifierPass::debugEntry (DetailedBlockInfo *DI) {
|
||||
errs() << "TROUBLE: Block " << DI->BB->getNameStr() << " in "
|
||||
<< DI->BB->getParent()->getNameStr() << ":";
|
||||
errs() << "BBWeight=" << DI->BBWeight << ",";
|
||||
errs() << "inWeight=" << DI->inWeight << ",";
|
||||
errs() << "inCount=" << DI->inCount << ",";
|
||||
errs() << "outWeight=" << DI->outWeight << ",";
|
||||
errs() << "outCount=" << DI->outCount << "\n";
|
||||
if (!PrintedDebugTree) {
|
||||
PrintedDebugTree = true;
|
||||
printDebugInfo(&(DI->BB->getParent()->getEntryBlock()));
|
||||
}
|
||||
}
|
||||
|
||||
// This compares A and B but considering maybe small differences.
|
||||
static bool Equals(double A, double B) {
|
||||
double maxRelativeError = 0.0000001;
|
||||
if (A == B)
|
||||
return true;
|
||||
double relativeError;
|
||||
if (fabs(B) > fabs(A))
|
||||
relativeError = fabs((A - B) / B);
|
||||
else
|
||||
relativeError = fabs((A - B) / A);
|
||||
if (relativeError <= maxRelativeError) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// This checks if the function "exit" is reachable from an given function
|
||||
// via calls, this is necessary to check if a profile is valid despite the
|
||||
// counts not fitting exactly.
|
||||
bool ProfileVerifierPass::exitReachable(const Function *F) {
|
||||
if (!F) return false;
|
||||
|
||||
if (FisVisited.count(F)) return false;
|
||||
|
||||
Function *Exit = F->getParent()->getFunction("exit");
|
||||
if (Exit == F) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FisVisited.insert(F);
|
||||
bool exits = false;
|
||||
for (const_inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
|
||||
if (const CallInst *CI = dyn_cast<CallInst>(&*I)) {
|
||||
exits |= exitReachable(CI->getCalledFunction());
|
||||
if (exits) break;
|
||||
}
|
||||
}
|
||||
return exits;
|
||||
}
|
||||
|
||||
#define ASSERTMESSAGE(M) \
|
||||
errs() << (M) << "\n"; \
|
||||
if (!DisableAssertions) assert(0 && (M));
|
||||
|
||||
double ProfileVerifierPass::ReadOrAssert(ProfileInfo::Edge E) {
|
||||
double EdgeWeight = PI->getEdgeWeight(E);
|
||||
if (EdgeWeight == ProfileInfo::MissingValue) {
|
||||
errs() << "Edge " << E << " in Function "
|
||||
<< ProfileInfo::getFunction(E)->getNameStr() << ": ";
|
||||
ASSERTMESSAGE("ASSERT:Edge has missing value");
|
||||
return 0;
|
||||
} else {
|
||||
return EdgeWeight;
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileVerifierPass::CheckValue(bool Error, const char *Message,
|
||||
DetailedBlockInfo *DI) {
|
||||
if (Error) {
|
||||
DEBUG(debugEntry(DI));
|
||||
errs() << "Block " << DI->BB->getNameStr() << " in Function "
|
||||
<< DI->BB->getParent()->getNameStr() << ": ";
|
||||
ASSERTMESSAGE(Message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// This calculates the Information for a block and then recurses into the
|
||||
// successors.
|
||||
void ProfileVerifierPass::recurseBasicBlock(const BasicBlock *BB) {
|
||||
|
||||
// Break the recursion by remembering all visited blocks.
|
||||
if (BBisVisited.find(BB) != BBisVisited.end()) return;
|
||||
|
||||
// Use a data structure to store all the information, this can then be handed
|
||||
// to debug printers.
|
||||
DetailedBlockInfo DI;
|
||||
DI.BB = BB;
|
||||
DI.outCount = DI.inCount = 0;
|
||||
DI.inWeight = DI.outWeight = 0.0;
|
||||
|
||||
// Read predecessors.
|
||||
std::set<const BasicBlock*> ProcessedPreds;
|
||||
pred_const_iterator bpi = pred_begin(BB), bpe = pred_end(BB);
|
||||
// If there are none, check for (0,BB) edge.
|
||||
if (bpi == bpe) {
|
||||
DI.inWeight += ReadOrAssert(PI->getEdge(0,BB));
|
||||
DI.inCount++;
|
||||
}
|
||||
for (;bpi != bpe; ++bpi) {
|
||||
if (ProcessedPreds.insert(*bpi).second) {
|
||||
DI.inWeight += ReadOrAssert(PI->getEdge(*bpi,BB));
|
||||
DI.inCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Read successors.
|
||||
std::set<const BasicBlock*> ProcessedSuccs;
|
||||
succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
|
||||
// If there is an (0,BB) edge, consider it too. (This is done not only when
|
||||
// there are no successors, but every time; not every function contains
|
||||
// return blocks with no successors (think loop latch as return block)).
|
||||
double w = PI->getEdgeWeight(PI->getEdge(BB,0));
|
||||
if (w != ProfileInfo::MissingValue) {
|
||||
DI.outWeight += w;
|
||||
DI.outCount++;
|
||||
}
|
||||
for (;bbi != bbe; ++bbi) {
|
||||
if (ProcessedSuccs.insert(*bbi).second) {
|
||||
DI.outWeight += ReadOrAssert(PI->getEdge(BB,*bbi));
|
||||
DI.outCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Read block weight.
|
||||
DI.BBWeight = PI->getExecutionCount(BB);
|
||||
CheckValue(DI.BBWeight == ProfileInfo::MissingValue,
|
||||
"ASSERT:BasicBlock has missing value", &DI);
|
||||
|
||||
// Check if this block is a setjmp target.
|
||||
bool isSetJmpTarget = false;
|
||||
if (DI.outWeight > DI.inWeight) {
|
||||
for (BasicBlock::const_iterator i = BB->begin(), ie = BB->end();
|
||||
i != ie; ++i) {
|
||||
if (const CallInst *CI = dyn_cast<CallInst>(&*i)) {
|
||||
Function *F = CI->getCalledFunction();
|
||||
if (F && (F->getNameStr() == "_setjmp")) {
|
||||
isSetJmpTarget = true; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if this block is eventually reaching exit.
|
||||
bool isExitReachable = false;
|
||||
if (DI.inWeight > DI.outWeight) {
|
||||
for (BasicBlock::const_iterator i = BB->begin(), ie = BB->end();
|
||||
i != ie; ++i) {
|
||||
if (const CallInst *CI = dyn_cast<CallInst>(&*i)) {
|
||||
FisVisited.clear();
|
||||
isExitReachable |= exitReachable(CI->getCalledFunction());
|
||||
if (isExitReachable) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DI.inCount > 0 && DI.outCount == 0) {
|
||||
// If this is a block with no successors.
|
||||
if (!isSetJmpTarget) {
|
||||
CheckValue(!Equals(DI.inWeight,DI.BBWeight),
|
||||
"ASSERT:inWeight and BBWeight do not match", &DI);
|
||||
}
|
||||
} else if (DI.inCount == 0 && DI.outCount > 0) {
|
||||
// If this is a block with no predecessors.
|
||||
if (!isExitReachable)
|
||||
CheckValue(!Equals(DI.BBWeight,DI.outWeight),
|
||||
"ASSERT:BBWeight and outWeight do not match", &DI);
|
||||
} else {
|
||||
// If this block has successors and predecessors.
|
||||
if (DI.inWeight > DI.outWeight && !isExitReachable)
|
||||
CheckValue(!Equals(DI.inWeight,DI.outWeight),
|
||||
"ASSERT:inWeight and outWeight do not match", &DI);
|
||||
if (DI.inWeight < DI.outWeight && !isSetJmpTarget)
|
||||
CheckValue(!Equals(DI.inWeight,DI.outWeight),
|
||||
"ASSERT:inWeight and outWeight do not match", &DI);
|
||||
}
|
||||
|
||||
|
||||
// Mark this block as visited, rescurse into successors.
|
||||
BBisVisited.insert(BB);
|
||||
for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
|
||||
bbi != bbe; ++bbi ) {
|
||||
recurseBasicBlock(*bbi);
|
||||
}
|
||||
}
|
||||
|
||||
bool ProfileVerifierPass::runOnFunction(Function &F) {
|
||||
PI = &getAnalysis<ProfileInfo>();
|
||||
|
||||
// Prepare global variables.
|
||||
PrintedDebugTree = false;
|
||||
BBisVisited.clear();
|
||||
|
||||
// Fetch entry block and recurse into it.
|
||||
const BasicBlock *entry = &F.getEntryBlock();
|
||||
recurseBasicBlock(entry);
|
||||
|
||||
if (!DisableAssertions)
|
||||
assert((PI->getExecutionCount(&F)==PI->getExecutionCount(entry)) &&
|
||||
"Function count and entry block count do not match");
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user