diff options
author | George Burgess IV <george.burgess.iv@gmail.com> | 2016-07-27 23:07:07 +0000 |
---|---|---|
committer | George Burgess IV <george.burgess.iv@gmail.com> | 2016-07-27 23:07:07 +0000 |
commit | aa6ca74bfc8ad9afea299e89f3359004c820df84 (patch) | |
tree | d2c8fad6d3662d344ddd7605dde9f57eb1287b3a | |
parent | 741862c9964ebaddc88958cb0e607cc752a7a150 (diff) |
[CFLAA] Add getModRefBehavior to CFLAnders.
This patch lets CFLAnders respond to mod-ref queries. It also includes
a small bugfix to CFLSteens.
Patch by Jia Chen.
Differential Revision: https://reviews.llvm.org/D22823
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@276939 91177308-0d34-0410-b5e6-96231b3b80d8
9 files changed, 159 insertions, 8 deletions
diff --git a/include/llvm/Analysis/CFLAndersAliasAnalysis.h b/include/llvm/Analysis/CFLAndersAliasAnalysis.h index 48eca888419..d9e99c0b845 100644 --- a/include/llvm/Analysis/CFLAndersAliasAnalysis.h +++ b/include/llvm/Analysis/CFLAndersAliasAnalysis.h @@ -53,6 +53,16 @@ public: AliasResult query(const MemoryLocation &, const MemoryLocation &); AliasResult alias(const MemoryLocation &, const MemoryLocation &); + /// Get the location associated with a pointer argument of a callsite. + ModRefInfo getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx); + + /// Returns the behavior when calling the given call site. + FunctionModRefBehavior getModRefBehavior(ImmutableCallSite CS); + + /// Returns the behavior when calling the given function. For use when the + /// call site is not known. + FunctionModRefBehavior getModRefBehavior(const Function *F); + private: struct FunctionHandle final : public CallbackVH { FunctionHandle(Function *Fn, CFLAndersAAResult *Result) diff --git a/lib/Analysis/CFLAndersAliasAnalysis.cpp b/lib/Analysis/CFLAndersAliasAnalysis.cpp index 5aa21d6a509..d699cbb4532 100644 --- a/lib/Analysis/CFLAndersAliasAnalysis.cpp +++ b/lib/Analysis/CFLAndersAliasAnalysis.cpp @@ -859,6 +859,112 @@ AliasResult CFLAndersAAResult::alias(const MemoryLocation &LocA, return QueryResult; } +ModRefInfo CFLAndersAAResult::getArgModRefInfo(ImmutableCallSite CS, + unsigned ArgIdx) { + if (auto CalledFunc = CS.getCalledFunction()) { + if (!CalledFunc->hasExactDefinition()) + return MRI_ModRef; + + auto &MaybeInfo = ensureCached(*CalledFunc); + if (!MaybeInfo.hasValue()) + return MRI_ModRef; + auto &RetParamAttributes = MaybeInfo->getAliasSummary().RetParamAttributes; + auto &RetParamRelations = MaybeInfo->getAliasSummary().RetParamRelations; + + bool ArgAttributeIsWritten = + any_of(RetParamAttributes, [ArgIdx](const ExternalAttribute &ExtAttr) { + return ExtAttr.IValue.Index == ArgIdx + 1; + }); + + // If the argument is unknown, escaped, or alias global, be conservative. + // FIXME: Do we really need to be conservative for AttrGlobal? + if (ArgAttributeIsWritten) + return MRI_ModRef; + + bool ArgIsRead = any_of(RetParamRelations, + [ArgIdx](const ExternalRelation &ExtRelation) { + return ExtRelation.From.Index == ArgIdx + 1; + }); + + bool ArgIsWritten = any_of(RetParamRelations, + [ArgIdx](const ExternalRelation &ExtRelation) { + return ExtRelation.To.Index == ArgIdx + 1; + }); + + if (ArgIsRead) + return ArgIsWritten ? MRI_ModRef : MRI_Ref; + return ArgIsWritten ? MRI_Mod : MRI_NoModRef; + } + + return MRI_ModRef; +} + +FunctionModRefBehavior +CFLAndersAAResult::getModRefBehavior(ImmutableCallSite CS) { + // If we know the callee, try analyzing it + if (auto CalledFunc = CS.getCalledFunction()) + return getModRefBehavior(CalledFunc); + + // Otherwise, be conservative + return FMRB_UnknownModRefBehavior; +} + +FunctionModRefBehavior CFLAndersAAResult::getModRefBehavior(const Function *F) { + assert(F != nullptr); + + // We cannot process external functions + if (!F->hasExactDefinition()) + return FMRB_UnknownModRefBehavior; + + auto &MaybeInfo = ensureCached(*F); + if (!MaybeInfo.hasValue()) + return FMRB_UnknownModRefBehavior; + auto &RetParamAttributes = MaybeInfo->getAliasSummary().RetParamAttributes; + auto &RetParamRelations = MaybeInfo->getAliasSummary().RetParamRelations; + + // First, if any argument is marked Escpaed, Unknown or Global, anything may + // happen to them and thus we can't draw any conclusion. + // FIXME: Do we really need to be conservative for AttrGlobal? + if (!RetParamAttributes.empty()) + return FMRB_UnknownModRefBehavior; + + // Check if memory gets touched. + bool MemIsRead = + any_of(RetParamRelations, [](const ExternalRelation &ExtRelation) { + return ExtRelation.From.DerefLevel > 0; + }); + bool MemIsWritten = + any_of(RetParamRelations, [](const ExternalRelation &ExtRelation) { + return ExtRelation.To.DerefLevel > 0; + }); + if (!MemIsRead && !MemIsWritten) + return FMRB_DoesNotAccessMemory; + + // Check if only argmem gets touched. + bool ArgMemIsAccessed = + all_of(RetParamRelations, [](const ExternalRelation &ExtRelation) { + return ExtRelation.From.Index > 0 && ExtRelation.From.DerefLevel <= 1 && + ExtRelation.To.Index > 0 && ExtRelation.To.DerefLevel <= 1; + }); + if (ArgMemIsAccessed) + return FMRB_OnlyAccessesArgumentPointees; + + if (!MemIsWritten) { + // Check if something beyond argmem gets read. + bool ArgMemReadOnly = + all_of(RetParamRelations, [](const ExternalRelation &ExtRelation) { + return ExtRelation.From.Index > 0 && ExtRelation.From.DerefLevel <= 1; + }); + return ArgMemReadOnly ? FMRB_OnlyReadsArgumentPointees + : FMRB_OnlyReadsMemory; + } + + if (!MemIsRead) + return FMRB_DoesNotReadMemory; + + return FMRB_UnknownModRefBehavior; +} + char CFLAndersAA::PassID; CFLAndersAAResult CFLAndersAA::run(Function &F, AnalysisManager<Function> &AM) { diff --git a/lib/Analysis/CFLSteensAliasAnalysis.cpp b/lib/Analysis/CFLSteensAliasAnalysis.cpp index 9b211540f4e..f1fac43a5dc 100644 --- a/lib/Analysis/CFLSteensAliasAnalysis.cpp +++ b/lib/Analysis/CFLSteensAliasAnalysis.cpp @@ -344,6 +344,9 @@ AliasResult CFLSteensAAResult::query(const MemoryLocation &LocA, ModRefInfo CFLSteensAAResult::getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx) { if (auto CalledFunc = CS.getCalledFunction()) { + if (!CalledFunc->hasExactDefinition()) + return MRI_ModRef; + auto &MaybeInfo = ensureCached(const_cast<Function *>(CalledFunc)); if (!MaybeInfo.hasValue()) return MRI_ModRef; @@ -382,6 +385,10 @@ CFLSteensAAResult::getModRefBehavior(ImmutableCallSite CS) { FunctionModRefBehavior CFLSteensAAResult::getModRefBehavior(const Function *F) { assert(F != nullptr); + // We cannot process external functions + if (!F->hasExactDefinition()) + return FMRB_UnknownModRefBehavior; + // TODO: Remove the const_cast auto &MaybeInfo = ensureCached(const_cast<Function *>(F)); if (!MaybeInfo.hasValue()) @@ -397,18 +404,21 @@ FunctionModRefBehavior CFLSteensAAResult::getModRefBehavior(const Function *F) { // Currently we don't (and can't) distinguish reads from writes in // RetParamRelations. All we can say is whether there may be memory access or // not. - if (RetParamRelations.empty()) + bool AccessNoMemory = + all_of(RetParamRelations, [](const ExternalRelation &ExtRelation) { + return ExtRelation.From.DerefLevel == 0 && + ExtRelation.To.DerefLevel == 0; + }); + if (AccessNoMemory) return FMRB_DoesNotAccessMemory; // Check if something beyond argmem gets touched. bool AccessArgMemoryOnly = - std::all_of(RetParamRelations.begin(), RetParamRelations.end(), - [](const ExternalRelation &ExtRelation) { - // Both DerefLevels has to be 0, since we don't know which - // one is a read and which is a write. - return ExtRelation.From.DerefLevel == 0 && - ExtRelation.To.DerefLevel == 0; - }); + all_of(RetParamRelations, [](const ExternalRelation &ExtRelation) { + return ExtRelation.From.Index > 0 && ExtRelation.To.Index > 0 && + ExtRelation.From.DerefLevel <= 1 && + ExtRelation.To.DerefLevel <= 1; + }); return AccessArgMemoryOnly ? FMRB_OnlyAccessesArgumentPointees : FMRB_UnknownModRefBehavior; } diff --git a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-arg.ll b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-arg.ll index b90ecab7df4..c42ec2b9dc4 100644 --- a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-arg.ll +++ b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-arg.ll @@ -11,6 +11,10 @@ define i32* @return_arg_callee(i32* %arg1, i32* %arg2) { ; CHECK: NoAlias: i32* %a, i32* %b ; CHECK: MayAlias: i32* %a, i32* %c ; CHECK: NoAlias: i32* %b, i32* %c + +; CHECK: NoModRef: Ptr: i32* %a <-> %c = call i32* @return_arg_callee(i32* %a, i32* %b) +; CHECK: NoModRef: Ptr: i32* %b <-> %c = call i32* @return_arg_callee(i32* %a, i32* %b) +; CHECK: NoModRef: Ptr: i32* %c <-> %c = call i32* @return_arg_callee(i32* %a, i32* %b) define void @test_return_arg() { %a = alloca i32, align 4 %b = alloca i32, align 4 diff --git a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-deref-arg-multilevel.ll b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-deref-arg-multilevel.ll index 3b129dc3017..97ce8bf55d6 100644 --- a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-deref-arg-multilevel.ll +++ b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-deref-arg-multilevel.ll @@ -28,6 +28,11 @@ define i32* @return_deref_arg_multilevel_callee(i32*** %arg1) { ; CHECK: MayAlias: i32* %c, i32* %lp ; CHECK: NoAlias: i32* %lp, i32** %lpp ; CHECK: MayAlias: i32* %lp, i32* %lpp_deref + +; CHECK: Just Ref: Ptr: i32** %p <-> %c = call i32* @return_deref_arg_multilevel_callee(i32*** %pp) +; CHECK: Just Ref: Ptr: i32*** %pp <-> %c = call i32* @return_deref_arg_multilevel_callee(i32*** %pp) +; CHECK: Just Ref: Ptr: i32** %lpp <-> %c = call i32* @return_deref_arg_multilevel_callee(i32*** %pp) + define void @test_return_deref_arg_multilevel() { %a = alloca i32, align 4 %b = alloca i32, align 4 diff --git a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-deref-arg.ll b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-deref-arg.ll index 13aab52f734..e4ddc56c13f 100644 --- a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-deref-arg.ll +++ b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-deref-arg.ll @@ -16,6 +16,12 @@ define i32* @return_deref_arg_callee(i32** %arg1) { ; CHECK: NoAlias: i32* %b, i32* %lp ; CHECK: NoAlias: i32* %lp, i32** %p ; CHECK: MayAlias: i32* %c, i32* %lp + +; CHECK: NoModRef: Ptr: i32* %a <-> %c = call i32* @return_deref_arg_callee(i32** %p) +; CHECK: NoModRef: Ptr: i32* %b <-> %c = call i32* @return_deref_arg_callee(i32** %p) +; CHECK: Just Ref: Ptr: i32** %p <-> %c = call i32* @return_deref_arg_callee(i32** %p) +; CHECK: NoModRef: Ptr: i32* %c <-> %c = call i32* @return_deref_arg_callee(i32** %p) +; CHECK: NoModRef: Ptr: i32* %lp <-> %c = call i32* @return_deref_arg_callee(i32** %p) define void @test_return_deref_arg() { %a = alloca i32, align 4 %b = alloca i32, align 4 diff --git a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-ref-arg-multilevel.ll b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-ref-arg-multilevel.ll index fab1de87b14..b64fdf30bc7 100644 --- a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-ref-arg-multilevel.ll +++ b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-ref-arg-multilevel.ll @@ -30,6 +30,9 @@ define i32*** @return_ref_arg_multilevel_callee(i32* %arg1) { ; CHECK: MayAlias: i32* %lb_deref, i32* %lp ; CHECK: NoAlias: i32* %lp, i32** %lpp ; CHECK: MayAlias: i32* %lp, i32* %lpp_deref + +; CHECK: Just Mod: Ptr: i32*** %b <-> %b = call i32*** @return_ref_arg_multilevel_callee(i32* %a) +; CHECK: Just Mod: Ptr: i32** %lb <-> %b = call i32*** @return_ref_arg_multilevel_callee(i32* %a) define void @test_return_ref_arg_multilevel() { %a = alloca i32, align 4 %p = alloca i32*, align 8 diff --git a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-ref-arg.ll b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-ref-arg.ll index 184aff1db18..c1938f063b2 100644 --- a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-ref-arg.ll +++ b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-ref-arg.ll @@ -20,6 +20,8 @@ define i32** @return_ref_arg_callee(i32* %arg1) { ; CHECK: NoAlias: i32* %lp, i32** %p ; CHECK: NoAlias: i32* %lp, i32** %b ; CHECK: MayAlias: i32* %lb, i32* %lp + +; CHECK: Just Mod: Ptr: i32** %b <-> %b = call i32** @return_ref_arg_callee(i32* %a) define void @test_return_ref_arg() { %a = alloca i32, align 4 %p = alloca i32*, align 8 diff --git a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-store-arg.ll b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-store-arg.ll index 92e720aec14..0953d764c51 100644 --- a/test/Analysis/CFLAliasAnalysis/Andersen/interproc-store-arg.ll +++ b/test/Analysis/CFLAliasAnalysis/Andersen/interproc-store-arg.ll @@ -17,6 +17,11 @@ define void @store_arg_callee(i32** %arg1, i32* %arg2) { ; CHECK: NoAlias: i32* %a, i32* %lq ; CHECK: MayAlias: i32* %b, i32* %lq ; CHECK: MayAlias: i32* %lp, i32* %lq + +; CHECK: NoModRef: Ptr: i32* %a <-> call void @store_arg_callee(i32** %p, i32* %b) +; CHECK: Just Ref: Ptr: i32* %b <-> call void @store_arg_callee(i32** %p, i32* %b) +; CHECK: Just Mod: Ptr: i32** %p <-> call void @store_arg_callee(i32** %p, i32* %b) +; CHECK: NoModRef: Ptr: i32** %q <-> call void @store_arg_callee(i32** %p, i32* %b) define void @test_store_arg() { %a = alloca i32, align 4 %b = alloca i32, align 4 |