mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
Remove context sensitivity concerns from interprocedural-basic-aa, and
make it more aggressive in cases where both pointers are known to live in the same function. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@107420 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
94610588af
commit
21de4c0daf
@ -55,10 +55,9 @@ static bool isKnownNonNull(const Value *V) {
|
|||||||
|
|
||||||
/// isNonEscapingLocalObject - Return true if the pointer is to a function-local
|
/// isNonEscapingLocalObject - Return true if the pointer is to a function-local
|
||||||
/// object that never escapes from the function.
|
/// object that never escapes from the function.
|
||||||
static bool isNonEscapingLocalObject(const Value *V, bool Interprocedural) {
|
static bool isNonEscapingLocalObject(const Value *V) {
|
||||||
// If this is a local allocation, check to see if it escapes.
|
// If this is a local allocation, check to see if it escapes.
|
||||||
if (isa<AllocaInst>(V) ||
|
if (isa<AllocaInst>(V) || isNoAliasCall(V))
|
||||||
(!Interprocedural && isNoAliasCall(V)))
|
|
||||||
// Set StoreCaptures to True so that we can assume in our callers that the
|
// Set StoreCaptures to True so that we can assume in our callers that the
|
||||||
// pointer is not the result of a load instruction. Currently
|
// pointer is not the result of a load instruction. Currently
|
||||||
// PointerMayBeCaptured doesn't have any special analysis for the
|
// PointerMayBeCaptured doesn't have any special analysis for the
|
||||||
@ -69,23 +68,21 @@ static bool isNonEscapingLocalObject(const Value *V, bool Interprocedural) {
|
|||||||
// If this is an argument that corresponds to a byval or noalias argument,
|
// If this is an argument that corresponds to a byval or noalias argument,
|
||||||
// then it has not escaped before entering the function. Check if it escapes
|
// then it has not escaped before entering the function. Check if it escapes
|
||||||
// inside the function.
|
// inside the function.
|
||||||
if (!Interprocedural)
|
if (const Argument *A = dyn_cast<Argument>(V))
|
||||||
if (const Argument *A = dyn_cast<Argument>(V))
|
if (A->hasByValAttr() || A->hasNoAliasAttr()) {
|
||||||
if (A->hasByValAttr() || A->hasNoAliasAttr()) {
|
// Don't bother analyzing arguments already known not to escape.
|
||||||
// Don't bother analyzing arguments already known not to escape.
|
if (A->hasNoCaptureAttr())
|
||||||
if (A->hasNoCaptureAttr())
|
return true;
|
||||||
return true;
|
return !PointerMayBeCaptured(V, false, /*StoreCaptures=*/true);
|
||||||
return !PointerMayBeCaptured(V, false, /*StoreCaptures=*/true);
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// isEscapeSource - Return true if the pointer is one which would have
|
/// isEscapeSource - Return true if the pointer is one which would have
|
||||||
/// been considered an escape by isNonEscapingLocalObject.
|
/// been considered an escape by isNonEscapingLocalObject.
|
||||||
static bool isEscapeSource(const Value *V, bool Interprocedural) {
|
static bool isEscapeSource(const Value *V) {
|
||||||
if (!Interprocedural)
|
if (isa<CallInst>(V) || isa<InvokeInst>(V) || isa<Argument>(V))
|
||||||
if (isa<CallInst>(V) || isa<InvokeInst>(V) || isa<Argument>(V))
|
return true;
|
||||||
return true;
|
|
||||||
|
|
||||||
// The load case works because isNonEscapingLocalObject considers all
|
// The load case works because isNonEscapingLocalObject considers all
|
||||||
// stores to be escapes (it passes true for the StoreCaptures argument
|
// stores to be escapes (it passes true for the StoreCaptures argument
|
||||||
@ -197,7 +194,6 @@ ImmutablePass *llvm::createNoAAPass() { return new NoAA(); }
|
|||||||
// BasicAliasAnalysis Pass
|
// BasicAliasAnalysis Pass
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#ifdef XDEBUG
|
|
||||||
static const Function *getParent(const Value *V) {
|
static const Function *getParent(const Value *V) {
|
||||||
if (const Instruction *inst = dyn_cast<Instruction>(V))
|
if (const Instruction *inst = dyn_cast<Instruction>(V))
|
||||||
return inst->getParent()->getParent();
|
return inst->getParent()->getParent();
|
||||||
@ -213,6 +209,15 @@ static bool sameParent(const Value *O1, const Value *O2) {
|
|||||||
const Function *F1 = getParent(O1);
|
const Function *F1 = getParent(O1);
|
||||||
const Function *F2 = getParent(O2);
|
const Function *F2 = getParent(O2);
|
||||||
|
|
||||||
|
return F1 && F1 == F2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef XDEBUG
|
||||||
|
static bool notDifferentParent(const Value *O1, const Value *O2) {
|
||||||
|
|
||||||
|
const Function *F1 = getParent(O1);
|
||||||
|
const Function *F2 = getParent(O2);
|
||||||
|
|
||||||
return !F1 || !F2 || F1 == F2;
|
return !F1 || !F2 || F1 == F2;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -236,7 +241,7 @@ namespace {
|
|||||||
const Value *V2, unsigned V2Size) {
|
const Value *V2, unsigned V2Size) {
|
||||||
assert(Visited.empty() && "Visited must be cleared after use!");
|
assert(Visited.empty() && "Visited must be cleared after use!");
|
||||||
#ifdef XDEBUG
|
#ifdef XDEBUG
|
||||||
assert((Interprocedural || sameParent(V1, V2)) &&
|
assert((Interprocedural || notDifferentParent(V1, V2)) &&
|
||||||
"BasicAliasAnalysis (-basicaa) doesn't support interprocedural "
|
"BasicAliasAnalysis (-basicaa) doesn't support interprocedural "
|
||||||
"queries; use InterproceduralAliasAnalysis "
|
"queries; use InterproceduralAliasAnalysis "
|
||||||
"(-interprocedural-basic-aa) instead.");
|
"(-interprocedural-basic-aa) instead.");
|
||||||
@ -331,11 +336,17 @@ BasicAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
|
|||||||
if (CI->isTailCall())
|
if (CI->isTailCall())
|
||||||
return NoModRef;
|
return NoModRef;
|
||||||
|
|
||||||
|
// If we can identify an object and it's known to be within the
|
||||||
|
// same function as the call, we can ignore interprocedural concerns.
|
||||||
|
bool EffectivelyInterprocedural =
|
||||||
|
Interprocedural && !sameParent(Object, CS.getInstruction());
|
||||||
|
|
||||||
// If the pointer is to a locally allocated object that does not escape,
|
// If the pointer is to a locally allocated object that does not escape,
|
||||||
// then the call can not mod/ref the pointer unless the call takes the pointer
|
// then the call can not mod/ref the pointer unless the call takes the pointer
|
||||||
// as an argument, and itself doesn't capture it.
|
// as an argument, and itself doesn't capture it.
|
||||||
if (!isa<Constant>(Object) && CS.getInstruction() != Object &&
|
if (!isa<Constant>(Object) && CS.getInstruction() != Object &&
|
||||||
isNonEscapingLocalObject(Object, Interprocedural)) {
|
!EffectivelyInterprocedural &&
|
||||||
|
isNonEscapingLocalObject(Object)) {
|
||||||
bool PassedAsArg = false;
|
bool PassedAsArg = false;
|
||||||
unsigned ArgNo = 0;
|
unsigned ArgNo = 0;
|
||||||
for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
|
for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
|
||||||
@ -754,27 +765,32 @@ BasicAliasAnalysis::aliasCheck(const Value *V1, unsigned V1Size,
|
|||||||
if (CPN->getType()->getAddressSpace() == 0)
|
if (CPN->getType()->getAddressSpace() == 0)
|
||||||
return NoAlias;
|
return NoAlias;
|
||||||
|
|
||||||
|
// If we can identify two objects and they're known to be within the
|
||||||
|
// same function, we can ignore interprocedural concerns.
|
||||||
|
bool EffectivelyInterprocedural =
|
||||||
|
Interprocedural && !sameParent(O1, O2);
|
||||||
|
|
||||||
if (O1 != O2) {
|
if (O1 != O2) {
|
||||||
// If V1/V2 point to two different objects we know that we have no alias.
|
// If V1/V2 point to two different objects we know that we have no alias.
|
||||||
if (isIdentifiedObject(O1, Interprocedural) &&
|
if (isIdentifiedObject(O1, EffectivelyInterprocedural) &&
|
||||||
isIdentifiedObject(O2, Interprocedural))
|
isIdentifiedObject(O2, EffectivelyInterprocedural))
|
||||||
return NoAlias;
|
return NoAlias;
|
||||||
|
|
||||||
// Constant pointers can't alias with non-const isIdentifiedObject objects.
|
// Constant pointers can't alias with non-const isIdentifiedObject objects.
|
||||||
if ((isa<Constant>(O1) &&
|
if ((isa<Constant>(O1) &&
|
||||||
isIdentifiedObject(O2, Interprocedural) &&
|
isIdentifiedObject(O2, EffectivelyInterprocedural) &&
|
||||||
!isa<Constant>(O2)) ||
|
!isa<Constant>(O2)) ||
|
||||||
(isa<Constant>(O2) &&
|
(isa<Constant>(O2) &&
|
||||||
isIdentifiedObject(O1, Interprocedural) &&
|
isIdentifiedObject(O1, EffectivelyInterprocedural) &&
|
||||||
!isa<Constant>(O1)))
|
!isa<Constant>(O1)))
|
||||||
return NoAlias;
|
return NoAlias;
|
||||||
|
|
||||||
// Arguments can't alias with local allocations or noalias calls, unless
|
// Arguments can't alias with local allocations or noalias calls
|
||||||
// we have to consider interprocedural aliasing.
|
// in the same function.
|
||||||
if (!Interprocedural)
|
if (!EffectivelyInterprocedural &&
|
||||||
if ((isa<Argument>(O1) && (isa<AllocaInst>(O2) || isNoAliasCall(O2))) ||
|
((isa<Argument>(O1) && (isa<AllocaInst>(O2) || isNoAliasCall(O2))) ||
|
||||||
(isa<Argument>(O2) && (isa<AllocaInst>(O1) || isNoAliasCall(O1))))
|
(isa<Argument>(O2) && (isa<AllocaInst>(O1) || isNoAliasCall(O1)))))
|
||||||
return NoAlias;
|
return NoAlias;
|
||||||
|
|
||||||
// Most objects can't alias null.
|
// Most objects can't alias null.
|
||||||
if ((isa<ConstantPointerNull>(V2) && isKnownNonNull(O1)) ||
|
if ((isa<ConstantPointerNull>(V2) && isKnownNonNull(O1)) ||
|
||||||
@ -790,14 +806,18 @@ BasicAliasAnalysis::aliasCheck(const Value *V1, unsigned V1Size,
|
|||||||
return NoAlias;
|
return NoAlias;
|
||||||
|
|
||||||
// If one pointer is the result of a call/invoke or load and the other is a
|
// If one pointer is the result of a call/invoke or load and the other is a
|
||||||
// non-escaping local object, then we know the object couldn't escape to a
|
// non-escaping local object within the same function, then we know the
|
||||||
// point where the call could return it.
|
// object couldn't escape to a point where the call could return it.
|
||||||
if (O1 != O2) {
|
//
|
||||||
if (isEscapeSource(O1, Interprocedural) &&
|
// Note that if the pointers are in different functions, there are a
|
||||||
isNonEscapingLocalObject(O2, Interprocedural))
|
// variety of complications. A call with a nocapture argument may still
|
||||||
|
// temporary store the nocapture argument's value in a temporary memory
|
||||||
|
// location if that memory location doesn't escape. Or it may pass a
|
||||||
|
// nocapture value to other functions as long as they don't capture it.
|
||||||
|
if (O1 != O2 && !EffectivelyInterprocedural) {
|
||||||
|
if (isEscapeSource(O1) && isNonEscapingLocalObject(O2))
|
||||||
return NoAlias;
|
return NoAlias;
|
||||||
if (isEscapeSource(O2, Interprocedural) &&
|
if (isEscapeSource(O2) && isNonEscapingLocalObject(O1))
|
||||||
isNonEscapingLocalObject(O1, Interprocedural))
|
|
||||||
return NoAlias;
|
return NoAlias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1722
test/Analysis/BasicAA/args-rets-allocas-loads.ll
Normal file
1722
test/Analysis/BasicAA/args-rets-allocas-loads.ll
Normal file
File diff suppressed because it is too large
Load Diff
@ -27,23 +27,33 @@ define void @s1() {
|
|||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; An alloca can alias an argument in a recursive function.
|
; An alloca does not alias an argument in the same function.
|
||||||
; CHECK: MayAlias: i64* %t, i64* %u
|
; CHECK: NoAlias: i64* %t, i64* %u
|
||||||
|
; CHECK: NoAlias: i64* %a, i64* %u
|
||||||
|
; CHECK: NoAlias: i64* %a, i64* %t
|
||||||
; CHECK: MayAlias: i64* %u, i64* %v
|
; CHECK: MayAlias: i64* %u, i64* %v
|
||||||
; CHECK: MayAlias: i64* %t, i64* %v
|
; CHECK: MayAlias: i64* %t, i64* %v
|
||||||
|
; CHECK: NoAlias: i64* %a, i64* %v
|
||||||
|
; CHECK: MayAlias: i64* %b, i64* %u
|
||||||
|
; CHECK: MayAlias: i64* %b, i64* %t
|
||||||
|
; CHECK: MayAlias: i64* %b, i64* %v
|
||||||
|
declare i64* @r0_callee(i64*)
|
||||||
define i64* @r0(i64* %u) {
|
define i64* @r0(i64* %u) {
|
||||||
%t = alloca i64, i32 10
|
%t = alloca i64, i32 10
|
||||||
%v = call i64* @r0(i64* %t)
|
%a = alloca i64, i32 10
|
||||||
|
%v = call i64* @r0_callee(i64* %t)
|
||||||
|
%b = call i64* @r0_callee(i64* %t)
|
||||||
store i64 0, i64* %t
|
store i64 0, i64* %t
|
||||||
store i64 0, i64* %u
|
store i64 0, i64* %u
|
||||||
store i64 0, i64* %v
|
store i64 0, i64* %v
|
||||||
|
store i64 0, i64* %a
|
||||||
|
store i64 0, i64* %b
|
||||||
ret i64* %t
|
ret i64* %t
|
||||||
}
|
}
|
||||||
|
|
||||||
; The noalias attribute is not necessarily safe in an interprocedural context even
|
; The noalias attribute is safe when both arguments belong to the same function
|
||||||
; in comparison to other noalias arguments in the same function.
|
; even in an interprocedural context.
|
||||||
; CHECK: MayAlias: i8* %w, i8* %x
|
; CHECK: NoAlias: i8* %w, i8* %x
|
||||||
|
|
||||||
define void @q0(i8* noalias %w, i8* noalias %x) {
|
define void @q0(i8* noalias %w, i8* noalias %x) {
|
||||||
store i8 0, i8* %w
|
store i8 0, i8* %w
|
||||||
|
Loading…
Reference in New Issue
Block a user