[getUnderlyingOjbects] Analyze loop PHIs further to remove false positives

Specifically, if a pointer accesses different underlying objects in each
iteration, don't look through the phi node defining the pointer.

The motivating case is the underlyling-objects-2.ll testcase.  Consider
the loop nest:

  int **A;
  for (i)
    for (j)
       A[i][j] = A[i-1][j] * B[j]

This loop is transformed by Load-PRE to stash away A[i] for the next
iteration of the outer loop:

  Curr = A[0];          // Prev_0
  for (i: 1..N) {
    Prev = Curr;        // Prev = PHI (Prev_0, Curr)
    Curr = A[i];
    for (j: 0..N)
       Curr[j] = Prev[j] * B[j]
  }

Since A[i] and A[i-1] are likely to be independent pointers,
getUnderlyingObjects should not assume that Curr and Prev share the same
underlying object in the inner loop.

If it did we would try to dependence-analyze Curr and Prev and the
analysis of the corresponding SCEVs would fail with non-constant
distance.

To fix this, the getUnderlyingObjects API is extended with an optional
LoopInfo parameter.  This is effectively what controls whether we want
the above behavior or the original.  Currently, I only changed to use
this approach for LoopAccessAnalysis.

The other testcase is to guard the opposite case where we do want to
look through the loop PHI.  If we step through an array by incrementing
a pointer, the underlying object is the incoming value of the phi as the
loop is entered.

Fixes rdar://problem/19566729

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235634 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Adam Nemet
2015-04-23 20:09:20 +00:00
parent 12f341611a
commit 50b9e7f7d4
6 changed files with 230 additions and 16 deletions

View File

@@ -370,7 +370,8 @@ public:
LoopAccessInfo(Loop *L, ScalarEvolution *SE, const DataLayout &DL,
const TargetLibraryInfo *TLI, AliasAnalysis *AA,
DominatorTree *DT, const ValueToValueMap &Strides);
DominatorTree *DT, LoopInfo *LI,
const ValueToValueMap &Strides);
/// Return true we can analyze the memory accesses in the loop and there are
/// no memory dependence cycles.
@@ -467,6 +468,7 @@ private:
const TargetLibraryInfo *TLI;
AliasAnalysis *AA;
DominatorTree *DT;
LoopInfo *LI;
unsigned NumLoads;
unsigned NumStores;
@@ -541,6 +543,7 @@ private:
const TargetLibraryInfo *TLI;
AliasAnalysis *AA;
DominatorTree *DT;
LoopInfo *LI;
};
} // End llvm namespace

View File

@@ -28,6 +28,7 @@ namespace llvm {
class AssumptionCache;
class DominatorTree;
class TargetLibraryInfo;
class LoopInfo;
/// Determine which bits of V are known to be either zero or one and return
/// them in the KnownZero/KnownOne bit sets.
@@ -176,11 +177,37 @@ namespace llvm {
return GetUnderlyingObject(const_cast<Value *>(V), DL, MaxLookup);
}
/// GetUnderlyingObjects - This method is similar to GetUnderlyingObject
/// except that it can look through phi and select instructions and return
/// multiple objects.
/// \brief This method is similar to GetUnderlyingObject except that it can
/// look through phi and select instructions and return multiple objects.
///
/// If LoopInfo is passed, loop phis are further analyzed. If a pointer
/// accesses different objects in each iteration, we don't look through the
/// phi node. E.g. consider this loop nest:
///
/// int **A;
/// for (i)
/// for (j) {
/// A[i][j] = A[i-1][j] * B[j]
/// }
///
/// This is transformed by Load-PRE to stash away A[i] for the next iteration
/// of the outer loop:
///
/// Curr = A[0]; // Prev_0
/// for (i: 1..N) {
/// Prev = Curr; // Prev = PHI (Prev_0, Curr)
/// Curr = A[i];
/// for (j: 0..N) {
/// Curr[j] = Prev[j] * B[j]
/// }
/// }
///
/// Since A[i] and A[i-1] are independent pointers, getUnderlyingObjects
/// should not assume that Curr and Prev share the same underlying object thus
/// it shouldn't look through the phi above.
void GetUnderlyingObjects(Value *V, SmallVectorImpl<Value *> &Objects,
const DataLayout &DL, unsigned MaxLookup = 6);
const DataLayout &DL, LoopInfo *LI = nullptr,
unsigned MaxLookup = 6);
/// onlyUsedByLifetimeMarkers - Return true if the only users of this pointer
/// are lifetime markers.