forked from OSchip/llvm-project
[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 llvm-svn: 276939
This commit is contained in:
parent
37f4e0e096
commit
dbd35c44d4
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue