forked from OSchip/llvm-project
[FunctionAttrs] Extract a helper function for the core logic used to
evaluate whether 'readonly' or 'readnone' apply to a given function. This both reduces indentation and will make it easy to share the logic with a new pass manager implementation. llvm-svn: 248181
This commit is contained in:
parent
126caeb043
commit
7542d37688
|
@ -89,6 +89,115 @@ INITIALIZE_PASS_END(FunctionAttrs, "functionattrs",
|
|||
|
||||
Pass *llvm::createFunctionAttrsPass() { return new FunctionAttrs(); }
|
||||
|
||||
namespace {
|
||||
/// The three kinds of memory access relevant to 'readonly' and
|
||||
/// 'readnone' attributes.
|
||||
enum MemoryAccessKind {
|
||||
MAK_ReadNone = 0,
|
||||
MAK_ReadOnly = 1,
|
||||
MAK_MayWrite = 2
|
||||
};
|
||||
}
|
||||
|
||||
static MemoryAccessKind
|
||||
checkFunctionMemoryAccess(Function &F, AAResults &AAR,
|
||||
const SmallPtrSetImpl<Function *> &SCCNodes) {
|
||||
FunctionModRefBehavior MRB = AAR.getModRefBehavior(&F);
|
||||
if (MRB == FMRB_DoesNotAccessMemory)
|
||||
// Already perfect!
|
||||
return MAK_ReadNone;
|
||||
|
||||
// Definitions with weak linkage may be overridden at linktime with
|
||||
// something that writes memory, so treat them like declarations.
|
||||
if (F.isDeclaration() || F.mayBeOverridden()) {
|
||||
if (AliasAnalysis::onlyReadsMemory(MRB))
|
||||
return MAK_ReadOnly;
|
||||
|
||||
// Conservatively assume it writes to memory.
|
||||
return MAK_MayWrite;
|
||||
}
|
||||
|
||||
// Scan the function body for instructions that may read or write memory.
|
||||
bool ReadsMemory = false;
|
||||
for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) {
|
||||
Instruction *I = &*II;
|
||||
|
||||
// Some instructions can be ignored even if they read or write memory.
|
||||
// Detect these now, skipping to the next instruction if one is found.
|
||||
CallSite CS(cast<Value>(I));
|
||||
if (CS) {
|
||||
// Ignore calls to functions in the same SCC.
|
||||
if (CS.getCalledFunction() && SCCNodes.count(CS.getCalledFunction()))
|
||||
continue;
|
||||
FunctionModRefBehavior MRB = AAR.getModRefBehavior(CS);
|
||||
// If the call doesn't access arbitrary memory, we may be able to
|
||||
// figure out something.
|
||||
if (AliasAnalysis::onlyAccessesArgPointees(MRB)) {
|
||||
// If the call does access argument pointees, check each argument.
|
||||
if (AliasAnalysis::doesAccessArgPointees(MRB))
|
||||
// Check whether all pointer arguments point to local memory, and
|
||||
// ignore calls that only access local memory.
|
||||
for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
|
||||
CI != CE; ++CI) {
|
||||
Value *Arg = *CI;
|
||||
if (Arg->getType()->isPointerTy()) {
|
||||
AAMDNodes AAInfo;
|
||||
I->getAAMetadata(AAInfo);
|
||||
|
||||
MemoryLocation Loc(Arg, MemoryLocation::UnknownSize, AAInfo);
|
||||
if (!AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) {
|
||||
if (MRB & MRI_Mod)
|
||||
// Writes non-local memory. Give up.
|
||||
return MAK_MayWrite;
|
||||
if (MRB & MRI_Ref)
|
||||
// Ok, it reads non-local memory.
|
||||
ReadsMemory = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// The call could access any memory. If that includes writes, give up.
|
||||
if (MRB & MRI_Mod)
|
||||
return MAK_MayWrite;
|
||||
// If it reads, note it.
|
||||
if (MRB & MRI_Ref)
|
||||
ReadsMemory = true;
|
||||
continue;
|
||||
} else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
|
||||
// Ignore non-volatile loads from local memory. (Atomic is okay here.)
|
||||
if (!LI->isVolatile()) {
|
||||
MemoryLocation Loc = MemoryLocation::get(LI);
|
||||
if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true))
|
||||
continue;
|
||||
}
|
||||
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
|
||||
// Ignore non-volatile stores to local memory. (Atomic is okay here.)
|
||||
if (!SI->isVolatile()) {
|
||||
MemoryLocation Loc = MemoryLocation::get(SI);
|
||||
if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true))
|
||||
continue;
|
||||
}
|
||||
} else if (VAArgInst *VI = dyn_cast<VAArgInst>(I)) {
|
||||
// Ignore vaargs on local memory.
|
||||
MemoryLocation Loc = MemoryLocation::get(VI);
|
||||
if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Any remaining instructions need to be taken seriously! Check if they
|
||||
// read or write memory.
|
||||
if (I->mayWriteToMemory())
|
||||
// Writes memory. Just give up.
|
||||
return MAK_MayWrite;
|
||||
|
||||
// If this instruction may read memory, remember that.
|
||||
ReadsMemory |= I->mayReadFromMemory();
|
||||
}
|
||||
|
||||
return ReadsMemory ? MAK_ReadOnly : MAK_ReadNone;
|
||||
}
|
||||
|
||||
/// Deduce readonly/readnone attributes for the SCC.
|
||||
bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) {
|
||||
SmallPtrSet<Function *, 8> SCCNodes;
|
||||
|
@ -117,97 +226,15 @@ bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) {
|
|||
// work around the limitations of the legacy pass manager.
|
||||
AAResults AAR(createLegacyPMAAResults(*this, *F, BAR));
|
||||
|
||||
FunctionModRefBehavior MRB = AAR.getModRefBehavior(F);
|
||||
if (MRB == FMRB_DoesNotAccessMemory)
|
||||
// Already perfect!
|
||||
continue;
|
||||
|
||||
// Definitions with weak linkage may be overridden at linktime with
|
||||
// something that writes memory, so treat them like declarations.
|
||||
if (F->isDeclaration() || F->mayBeOverridden()) {
|
||||
if (!AliasAnalysis::onlyReadsMemory(MRB))
|
||||
// May write memory. Just give up.
|
||||
return false;
|
||||
|
||||
switch (checkFunctionMemoryAccess(*F, AAR, SCCNodes)) {
|
||||
case MAK_MayWrite:
|
||||
return false;
|
||||
case MAK_ReadOnly:
|
||||
ReadsMemory = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Scan the function body for instructions that may read or write memory.
|
||||
for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) {
|
||||
Instruction *I = &*II;
|
||||
|
||||
// Some instructions can be ignored even if they read or write memory.
|
||||
// Detect these now, skipping to the next instruction if one is found.
|
||||
CallSite CS(cast<Value>(I));
|
||||
if (CS) {
|
||||
// Ignore calls to functions in the same SCC.
|
||||
if (CS.getCalledFunction() && SCCNodes.count(CS.getCalledFunction()))
|
||||
continue;
|
||||
FunctionModRefBehavior MRB = AAR.getModRefBehavior(CS);
|
||||
// If the call doesn't access arbitrary memory, we may be able to
|
||||
// figure out something.
|
||||
if (AliasAnalysis::onlyAccessesArgPointees(MRB)) {
|
||||
// If the call does access argument pointees, check each argument.
|
||||
if (AliasAnalysis::doesAccessArgPointees(MRB))
|
||||
// Check whether all pointer arguments point to local memory, and
|
||||
// ignore calls that only access local memory.
|
||||
for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
|
||||
CI != CE; ++CI) {
|
||||
Value *Arg = *CI;
|
||||
if (Arg->getType()->isPointerTy()) {
|
||||
AAMDNodes AAInfo;
|
||||
I->getAAMetadata(AAInfo);
|
||||
|
||||
MemoryLocation Loc(Arg, MemoryLocation::UnknownSize, AAInfo);
|
||||
if (!AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true)) {
|
||||
if (MRB & MRI_Mod)
|
||||
// Writes non-local memory. Give up.
|
||||
return false;
|
||||
if (MRB & MRI_Ref)
|
||||
// Ok, it reads non-local memory.
|
||||
ReadsMemory = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// The call could access any memory. If that includes writes, give up.
|
||||
if (MRB & MRI_Mod)
|
||||
return false;
|
||||
// If it reads, note it.
|
||||
if (MRB & MRI_Ref)
|
||||
ReadsMemory = true;
|
||||
continue;
|
||||
} else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
|
||||
// Ignore non-volatile loads from local memory. (Atomic is okay here.)
|
||||
if (!LI->isVolatile()) {
|
||||
MemoryLocation Loc = MemoryLocation::get(LI);
|
||||
if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true))
|
||||
continue;
|
||||
}
|
||||
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
|
||||
// Ignore non-volatile stores to local memory. (Atomic is okay here.)
|
||||
if (!SI->isVolatile()) {
|
||||
MemoryLocation Loc = MemoryLocation::get(SI);
|
||||
if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true))
|
||||
continue;
|
||||
}
|
||||
} else if (VAArgInst *VI = dyn_cast<VAArgInst>(I)) {
|
||||
// Ignore vaargs on local memory.
|
||||
MemoryLocation Loc = MemoryLocation::get(VI);
|
||||
if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Any remaining instructions need to be taken seriously! Check if they
|
||||
// read or write memory.
|
||||
if (I->mayWriteToMemory())
|
||||
// Writes memory. Just give up.
|
||||
return false;
|
||||
|
||||
// If this instruction may read memory, remember that.
|
||||
ReadsMemory |= I->mayReadFromMemory();
|
||||
break;
|
||||
case MAK_ReadNone:
|
||||
// Nothing to do!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue