summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Burgess IV <george.burgess.iv@gmail.com>2016-07-27 23:07:07 +0000
committerGeorge Burgess IV <george.burgess.iv@gmail.com>2016-07-27 23:07:07 +0000
commitaa6ca74bfc8ad9afea299e89f3359004c820df84 (patch)
treed2c8fad6d3662d344ddd7605dde9f57eb1287b3a
parent741862c9964ebaddc88958cb0e607cc752a7a150 (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
-rw-r--r--include/llvm/Analysis/CFLAndersAliasAnalysis.h10
-rw-r--r--lib/Analysis/CFLAndersAliasAnalysis.cpp106
-rw-r--r--lib/Analysis/CFLSteensAliasAnalysis.cpp26
-rw-r--r--test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-arg.ll4
-rw-r--r--test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-deref-arg-multilevel.ll5
-rw-r--r--test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-deref-arg.ll6
-rw-r--r--test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-ref-arg-multilevel.ll3
-rw-r--r--test/Analysis/CFLAliasAnalysis/Andersen/interproc-ret-ref-arg.ll2
-rw-r--r--test/Analysis/CFLAliasAnalysis/Andersen/interproc-store-arg.ll5
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