Cleanup GlobalsModRef a bit. When analysing the

callgraph, when one member of a SCC calls another
then the analysis would drop to mod-ref because
there is (usually) no function info for the callee
yet; fix this.  Teach the analysis about function
attributes, in particular the readonly attribute
(which requires being careful about globals).

llvm-svn: 55696
This commit is contained in:
Duncan Sands 2008-09-03 12:55:42 +00:00
parent 823cf841d1
commit 0283a6c991
4 changed files with 146 additions and 104 deletions

View File

@ -70,6 +70,10 @@ namespace {
/// taken.
std::set<GlobalValue*> NonAddressTakenGlobals;
/// ReadGlobals - The globals without addresses taken that are read by
/// some function.
std::set<GlobalValue*> ReadGlobals;
/// IndirectGlobals - The memory pointed to by this global is known to be
/// 'owned' by the global.
std::set<GlobalValue*> IndirectGlobals;
@ -129,8 +133,7 @@ namespace {
private:
/// getFunctionInfo - Return the function info for the function, or null if
/// the function calls an external function (in which case we don't have
/// anything useful to say about it).
/// we don't have anything useful to say about it.
FunctionRecord *getFunctionInfo(Function *F) {
std::map<Function*, FunctionRecord>::iterator I = FunctionInfo.find(F);
if (I != FunctionInfo.end())
@ -140,7 +143,6 @@ namespace {
void AnalyzeGlobals(Module &M);
void AnalyzeCallGraph(CallGraph &CG, Module &M);
void AnalyzeSCC(std::vector<CallGraphNode *> &SCC);
bool AnalyzeUsesOfPointer(Value *V, std::vector<Function*> &Readers,
std::vector<Function*> &Writers,
GlobalValue *OkayStoreDest = 0);
@ -174,12 +176,12 @@ static Value *getUnderlyingObject(Value *V) {
return getUnderlyingObject(CE->getOperand(0));
}
// Othewise, we don't know what this is, return it as the base pointer.
// Otherwise, we don't know what this is, return it as the base pointer.
return V;
}
/// AnalyzeGlobals - Scan through the users of all of the internal
/// GlobalValue's in the program. If none of them have their "Address taken"
/// GlobalValue's in the program. If none of them have their "address taken"
/// (really, their address passed to something nontrivial), record this fact,
/// and record the functions that they are used directly in.
void GlobalsModRef::AnalyzeGlobals(Module &M) {
@ -200,6 +202,11 @@ void GlobalsModRef::AnalyzeGlobals(Module &M) {
if (!AnalyzeUsesOfPointer(I, Readers, Writers)) {
// Remember that we are tracking this global, and the mod/ref fns
NonAddressTakenGlobals.insert(I);
if (!Readers.empty())
// Some function read this global - remember that.
ReadGlobals.insert(I);
for (unsigned i = 0, e = Readers.size(); i != e; ++i)
FunctionInfo[Readers[i]].GlobalInfo[I] |= Ref;
@ -344,40 +351,45 @@ bool GlobalsModRef::AnalyzeIndirectGlobalMemory(GlobalValue *GV) {
void GlobalsModRef::AnalyzeCallGraph(CallGraph &CG, Module &M) {
// We do a bottom-up SCC traversal of the call graph. In other words, we
// visit all callees before callers (leaf-first).
for (scc_iterator<CallGraph*> I = scc_begin(&CG), E = scc_end(&CG); I!=E; ++I)
if ((*I).size() != 1) {
AnalyzeSCC(*I);
} else if (Function *F = (*I)[0]->getFunction()) {
if (!F->isDeclaration()) {
// Nonexternal function.
AnalyzeSCC(*I);
} else {
// Otherwise external function. Handle intrinsics and other special
// cases here.
if (getAnalysis<AliasAnalysis>().doesNotAccessMemory(F))
// If it does not access memory, process the function, causing us to
// realize it doesn't do anything (the body is empty).
AnalyzeSCC(*I);
else {
// Otherwise, don't process it. This will cause us to conservatively
// assume the worst.
}
}
} else {
// Do not process the external node, assume the worst.
}
}
void GlobalsModRef::AnalyzeSCC(std::vector<CallGraphNode *> &SCC) {
for (scc_iterator<CallGraph*> I = scc_begin(&CG), E = scc_end(&CG); I != E;
++I) {
std::vector<CallGraphNode *> &SCC = *I;
assert(!SCC.empty() && "SCC with no functions?");
if (!SCC[0]->getFunction())
// Do not process the external node, assume the worst.
continue;
FunctionRecord &FR = FunctionInfo[SCC[0]->getFunction()];
bool CallsExternal = false;
bool KnowNothing = false;
unsigned FunctionEffect = 0;
// Collect the mod/ref properties due to called functions. We only compute
// one mod-ref set
for (unsigned i = 0, e = SCC.size(); i != e && !CallsExternal; ++i)
// one mod-ref set.
for (unsigned i = 0, e = SCC.size(); i != e && !KnowNothing; ++i) {
Function *F = SCC[i]->getFunction();
if (!F) {
KnowNothing = true;
break;
}
if (F->isDeclaration()) {
// Try to get mod/ref behaviour from function attributes.
if (F->onlyReadsMemory()) {
FunctionEffect |= Ref;
// This function might call back into the module and read a global, so
// mark all globals read somewhere as being read by this function.
for (std::set<GlobalValue*>::iterator GI = ReadGlobals.begin(),
E = ReadGlobals.end(); GI != E; ++GI)
FR.GlobalInfo[*GI] |= Ref;
} else if (!F->doesNotAccessMemory()) {
// Can't say anything useful.
KnowNothing = true;
}
continue;
}
for (CallGraphNode::iterator CI = SCC[i]->begin(), E = SCC[i]->end();
CI != E; ++CI)
if (Function *Callee = CI->second->getFunction()) {
@ -390,35 +402,27 @@ void GlobalsModRef::AnalyzeSCC(std::vector<CallGraphNode *> &SCC) {
CalleeFR->GlobalInfo.begin(), E = CalleeFR->GlobalInfo.end();
GI != E; ++GI)
FR.GlobalInfo[GI->first] |= GI->second;
} else {
// Okay, if we can't say anything about it, maybe some other alias
// analysis can.
ModRefBehavior MRB =
AliasAnalysis::getModRefBehavior(Callee);
if (MRB != DoesNotAccessMemory) {
// FIXME: could make this more aggressive for functions that just
// read memory. We should just say they read all globals.
CallsExternal = true;
break;
}
// Can't say anything about it. However, if it is inside our SCC,
// then nothing needs to be done.
CallGraphNode *CalleeNode = CG[Callee];
if (std::find(SCC.begin(), SCC.end(), CalleeNode) == SCC.end())
KnowNothing = true;
}
} else {
CallsExternal = true;
break;
KnowNothing = true;
}
}
// If this SCC calls an external function, we can't say anything about it, so
// remove all SCC functions from the FunctionInfo map.
if (CallsExternal) {
// If we can't say anything useful about this SCC, remove all SCC functions
// from the FunctionInfo map.
if (KnowNothing) {
for (unsigned i = 0, e = SCC.size(); i != e; ++i)
FunctionInfo.erase(SCC[i]->getFunction());
return;
}
// Otherwise, unless we already know that this function mod/refs memory, scan
// the function bodies to see if there are any explicit loads or stores.
if (FunctionEffect != ModRef) {
// Scan the function bodies for explicit loads or stores.
for (unsigned i = 0, e = SCC.size(); i != e && FunctionEffect != ModRef;++i)
for (inst_iterator II = inst_begin(SCC[i]->getFunction()),
E = inst_end(SCC[i]->getFunction());
@ -429,7 +433,6 @@ void GlobalsModRef::AnalyzeSCC(std::vector<CallGraphNode *> &SCC) {
FunctionEffect |= Mod;
else if (isa<MallocInst>(*II) || isa<FreeInst>(*II))
FunctionEffect |= ModRef;
}
if ((FunctionEffect & Mod) == 0)
++NumReadMemFunctions;
@ -441,6 +444,7 @@ void GlobalsModRef::AnalyzeSCC(std::vector<CallGraphNode *> &SCC) {
// information to each function in the SCC.
for (unsigned i = 1, e = SCC.size(); i != e; ++i)
FunctionInfo[SCC[i]->getFunction()] = FR;
}
}

View File

@ -0,0 +1,11 @@
; RUN: llvm-as < %s | opt -globalsmodref-aa -markmodref | llvm-dis | grep readnone
define i32 @a() {
%tmp = call i32 @b( ) ; <i32> [#uses=1]
ret i32 %tmp
}
define i32 @b() {
%tmp = call i32 @a( ) ; <i32> [#uses=1]
ret i32 %tmp
}

View File

@ -0,0 +1,18 @@
; RUN: llvm-as < %s | opt -globalsmodref-aa -gvn | llvm-dis | grep call | count 2
@g = internal global i32 0 ; <i32*> [#uses=2]
define i32 @r() {
%tmp = load i32* @g ; <i32> [#uses=1]
ret i32 %tmp
}
define i32 @f() {
entry:
%tmp = call i32 @e( ) ; <i32> [#uses=1]
store i32 %tmp, i32* @g
%tmp2 = call i32 @e( ) ; <i32> [#uses=1]
ret i32 %tmp2
}
declare i32 @e() readonly ; might call @r

View File

@ -0,0 +1,9 @@
; RUN: llvm-as < %s | opt -globalsmodref-aa -markmodref | llvm-dis | grep readonly | count 2
define i32 @f() {
entry:
%tmp = call i32 @e( ) ; <i32> [#uses=1]
ret i32 %tmp
}
declare i32 @e() readonly