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(); }
|
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.
|
/// Deduce readonly/readnone attributes for the SCC.
|
||||||
bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) {
|
bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) {
|
||||||
SmallPtrSet<Function *, 8> SCCNodes;
|
SmallPtrSet<Function *, 8> SCCNodes;
|
||||||
|
@ -117,97 +226,15 @@ bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) {
|
||||||
// work around the limitations of the legacy pass manager.
|
// work around the limitations of the legacy pass manager.
|
||||||
AAResults AAR(createLegacyPMAAResults(*this, *F, BAR));
|
AAResults AAR(createLegacyPMAAResults(*this, *F, BAR));
|
||||||
|
|
||||||
FunctionModRefBehavior MRB = AAR.getModRefBehavior(F);
|
switch (checkFunctionMemoryAccess(*F, AAR, SCCNodes)) {
|
||||||
if (MRB == FMRB_DoesNotAccessMemory)
|
case MAK_MayWrite:
|
||||||
// Already perfect!
|
return false;
|
||||||
continue;
|
case MAK_ReadOnly:
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
ReadsMemory = true;
|
ReadsMemory = true;
|
||||||
continue;
|
break;
|
||||||
}
|
case MAK_ReadNone:
|
||||||
|
// Nothing to do!
|
||||||
// Scan the function body for instructions that may read or write memory.
|
break;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue