summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Analysis/GlobalsModRef.cpp
diff options
context:
space:
mode:
authorJames Molloy <james.molloy@arm.com>2015-09-25 15:39:29 +0000
committerJames Molloy <james.molloy@arm.com>2015-09-25 15:39:29 +0000
commiteb46641c28ea7bbe6b6870281c8a36af6b02fd30 (patch)
treeb33575c8d56b5f8586f3ef266514cabcc807bb34 /llvm/lib/Analysis/GlobalsModRef.cpp
parenteeb22f825172246c8ff7fc38980b7b0a93d45400 (diff)
downloadbcm5719-llvm-eb46641c28ea7bbe6b6870281c8a36af6b02fd30.tar.gz
bcm5719-llvm-eb46641c28ea7bbe6b6870281c8a36af6b02fd30.zip
[GlobalsAA] Teach GlobalsAA about nocapture
Arguments to function calls marked "nocapture" can be marked as non-escaping. However, nocapture is defined in terms of the lifetime of the callee, and if the callee can directly or indirectly recurse to the caller, the semantics of nocapture are invalid. Therefore, we eagerly discover which SCC each function belongs to, and later can check if callee and caller of a callsite belong to the same SCC, in which case there could be recursion. This means that we can't be so optimistic in getModRefInfo(ImmutableCallsite) - previously we assumed all call arguments never aliased with an escaping global. Now we need to check, because a global could now be passed as an argument but still not escape. This also solves a related conformance problem: MemCpyOptimizer can turn non-escaping stores of globals into calls to intrinsics like llvm.memcpy/llvm/memset. This confuses GlobalsAA, which knows the global can't escape and so returns NoModRef when queried, when obviously a memcpy/memset call does indeed reference and modify its arguments. This fixes PR24800, PR24801, and PR24802. llvm-svn: 248576
Diffstat (limited to 'llvm/lib/Analysis/GlobalsModRef.cpp')
-rw-r--r--llvm/lib/Analysis/GlobalsModRef.cpp62
1 files changed, 61 insertions, 1 deletions
diff --git a/llvm/lib/Analysis/GlobalsModRef.cpp b/llvm/lib/Analysis/GlobalsModRef.cpp
index a5820cd7a56..40915f45dff 100644
--- a/llvm/lib/Analysis/GlobalsModRef.cpp
+++ b/llvm/lib/Analysis/GlobalsModRef.cpp
@@ -358,6 +358,21 @@ bool GlobalsAAResult::AnalyzeUsesOfPointer(Value *V,
if (isFreeCall(I, &TLI)) {
if (Writers)
Writers->insert(CS->getParent()->getParent());
+ } else if (CS.doesNotCapture(CS.getArgumentNo(&U))) {
+ Function *ParentF = CS->getParent()->getParent();
+ // A nocapture argument may be read from or written to, but does not
+ // escape unless the call can somehow recurse.
+ //
+ // nocapture "indicates that the callee does not make any copies of
+ // the pointer that outlive itself". Therefore if we directly or
+ // indirectly recurse, we must treat the pointer as escaping.
+ if (FunctionToSCCMap[ParentF] ==
+ FunctionToSCCMap[CS.getCalledFunction()])
+ return true;
+ if (Readers)
+ Readers->insert(ParentF);
+ if (Writers)
+ Writers->insert(ParentF);
} else {
return true; // Argument of an unknown call.
}
@@ -439,6 +454,21 @@ bool GlobalsAAResult::AnalyzeIndirectGlobalMemory(GlobalValue *GV) {
return true;
}
+void GlobalsAAResult::CollectSCCMembership(CallGraph &CG) {
+ // We do a bottom-up SCC traversal of the call graph. In other words, we
+ // visit all callees before callers (leaf-first).
+ unsigned SCCID = 0;
+ for (scc_iterator<CallGraph *> I = scc_begin(&CG); !I.isAtEnd(); ++I) {
+ const std::vector<CallGraphNode *> &SCC = *I;
+ assert(!SCC.empty() && "SCC with no functions?");
+
+ for (auto *CGN : SCC)
+ if (Function *F = CGN->getFunction())
+ FunctionToSCCMap[F] = SCCID;
+ ++SCCID;
+ }
+}
+
/// AnalyzeCallGraph - At this point, we know the functions where globals are
/// immediately stored to and read from. Propagate this information up the call
/// graph to all callers and compute the mod/ref info for all memory for each
@@ -765,6 +795,32 @@ AliasResult GlobalsAAResult::alias(const MemoryLocation &LocA,
return AAResultBase::alias(LocA, LocB);
}
+ModRefInfo GlobalsAAResult::getModRefInfoForArgument(ImmutableCallSite CS,
+ const GlobalValue *GV) {
+ if (CS.doesNotAccessMemory())
+ return MRI_NoModRef;
+ ModRefInfo ConservativeResult = CS.onlyReadsMemory() ? MRI_Ref : MRI_ModRef;
+
+ // Iterate through all the arguments to the called function. If any argument
+ // is based on GV, return the conservative result.
+ for (auto &A : CS.args()) {
+ SmallVector<Value*, 4> Objects;
+ GetUnderlyingObjects(A, Objects, DL);
+
+ // All objects must be identified.
+ if (!std::all_of(Objects.begin(), Objects.end(), [&GV](const Value *V) {
+ return isIdentifiedObject(V);
+ }))
+ return ConservativeResult;
+
+ if (std::find(Objects.begin(), Objects.end(), GV) != Objects.end())
+ return ConservativeResult;
+ }
+
+ // We identified all objects in the argument list, and none of them were GV.
+ return MRI_NoModRef;
+}
+
ModRefInfo GlobalsAAResult::getModRefInfo(ImmutableCallSite CS,
const MemoryLocation &Loc) {
unsigned Known = MRI_ModRef;
@@ -777,7 +833,8 @@ ModRefInfo GlobalsAAResult::getModRefInfo(ImmutableCallSite CS,
if (const Function *F = CS.getCalledFunction())
if (NonAddressTakenGlobals.count(GV))
if (const FunctionInfo *FI = getFunctionInfo(F))
- Known = FI->getModRefInfoForGlobal(*GV);
+ Known = FI->getModRefInfoForGlobal(*GV) |
+ getModRefInfoForArgument(CS, GV);
if (Known == MRI_NoModRef)
return MRI_NoModRef; // No need to query other mod/ref analyses
@@ -807,6 +864,9 @@ GlobalsAAResult::analyzeModule(Module &M, const TargetLibraryInfo &TLI,
CallGraph &CG) {
GlobalsAAResult Result(M.getDataLayout(), TLI);
+ // Discover which functions aren't recursive, to feed into AnalyzeGlobals.
+ Result.CollectSCCMembership(CG);
+
// Find non-addr taken globals.
Result.AnalyzeGlobals(M);
OpenPOWER on IntegriCloud