[PATCH] D76132: [LoopUnrollAndJam] Changed safety checks to consider more than 2-levels loop nest.
Michael Kruse via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 1 09:34:12 PDT 2020
Meinersbur added a comment.
Given that the DependencyAnalysis result has to be interpreted different than I initially though, I came up with a new legality check.
Since DA returns (lexical) forward and backwards dependency in a single result, both have to be checked. There is also a symmetry between them as the alternative would be to invoke `->depends(Src,Dst)` and well as `->depends(Dst,Src)` and check them separately.
static bool preservesForwardDependence(Instruction *Src, Instruction *Dst,
unsigned UnrollLevel, unsigned JamLevel,
bool Sequentialized, Dependence *D) {
// UnrollLevel might carry the dependency Src --> Dst
// Does a different loop after unrolling?
for (unsigned d = UnrollLevel + 1; d <= JamLevel; ++d) {
auto JammedDir = D->getDirection(d);
if (JammedDir == Dependence::DVEntry::LT)
return true;
if (JammedDir & Dependence::DVEntry::GT)
return false;
}
return true;
}
static bool preservesBackwardDependence(Instruction *Src, Instruction *Dst,
unsigned UnrollLevel, unsigned JamLevel,
bool Sequentialized, Dependence *D) {
// UnrollLevel might carry the dependency Dst --> Src
for (unsigned d = UnrollLevel + 1; d <= JamLevel; ++d) {
auto JammedDir = D->getDirection(d);
if (JammedDir == Dependence::DVEntry::GT)
return true;
if (JammedDir & Dependence::DVEntry::LT)
return false;
}
// Backward dependencies are only preserved if not interleaved.
return Sequentialized;
}
/// Also a forward-dependency, but not carried by UnrollLoop.
static bool preservesNonCarriedDependence(Instruction *Src, Instruction *Dst,
unsigned UnrollLevel,
unsigned JamLevel,
bool Sequentialized, Dependence *D) {
// There might be dependency Src --> Dst that is not carried by UnrollLoop.
for (unsigned d = UnrollLevel + 1; d <= JamLevel; ++d) {
// TODO: Justify this; without it, sub_sub_eq fails
if (D->isScalar(d))
continue;
auto JammedDir = D->getDirection(d);
if (JammedDir == Dependence::DVEntry::LT)
return true;
if (JammedDir & Dependence::DVEntry::GT)
return false;
}
return true;
}
static bool checkDependency(Instruction *Src, Instruction *Dst,
unsigned UnrollLevel, unsigned JamLevel,
bool Sequentialized, DependenceInfo &DI) {
assert(UnrollLevel <= JamLevel);
if (Src == Dst)
return true;
if (isa<LoadInst>(Src) && isa<LoadInst>(Dst))
return true;
std::unique_ptr<Dependence> D = DI.depends(Src, Dst, true);
if (!D)
return true;
assert(D->isOrdered() && "Expected an output, flow or anti dep.");
// Quick bail-out.
if (D->isConfused())
return false;
for (unsigned d = 1; d < UnrollLevel; ++d) {
// Insert comment justifying this here
if (!(D->getDirection(d) & Dependence::DVEntry::EQ))
return true;
}
auto UnrollDir = D->getDirection(UnrollLevel);
if (UnrollDir & Dependence::DVEntry::LT &&
!preservesForwardDependence(Src, Dst, UnrollLevel, JamLevel,
Sequentialized, D.get()))
return false;
if (UnrollDir & Dependence::DVEntry::GT &&
!preservesBackwardDependence(Src, Dst, UnrollLevel, JamLevel,
Sequentialized, D.get()))
return false;
if (UnrollDir & Dependence::DVEntry::EQ &&
!preservesNonCarriedDependence(Src, Dst, UnrollLevel, JamLevel,
Sequentialized, D.get()))
return false;
return true;
}
This seem to work nicely with that checks, but I am not sure whether it is correct to ignore `isScalar` in the EQ case and why. It seems obvious that the `sub_sub_eq` test case can be unroll-and-jammed. Bit if we add the same skip to `preservesForwardDependence`, the test case `sub_sub_less` is unroll-and-jammed which it must not,
================
Comment at: llvm/test/Transforms/LoopUnrollAndJam/dependencies.ll:363
; CHECK-NOT: %j.1 = phi
-define void @sub_sub_less(i32* noalias nocapture %A, i32 %N, i32* noalias nocapture readonly %B) {
entry:
----------------
Whitney wrote:
> dmgreen wrote:
> > Whitney wrote:
> > > This test was orignally testing
> > > ```
> > > for i
> > > for j
> > > A[i]
> > > A[i-1]
> > > ```
> > > which should be **safe** to unroll and jam.
> > >
> > > I think it actually want to test the code for sub with sub with the dependence distance of the inner loop is less.
> > > ```
> > > for i
> > > for j
> > > A[i][j]
> > > A[i+1][j-1]
> > > ```
> > Hmm. I don't remember what this was trying to test. It feels like a very long time ago now.
> >
> > Thanks for splitting the new tests out. More are always a good thing.
> For sure. I guess is hard to speculate what it was trying to test now.
This is not safe to unroll-and-jam. For %N == 2 the excution sequence is (Sa being the first access in the loop body, Sb the second)
```
Sa(0,0): A[0]
Sb(0,0): A[-1]
Sa(0,1): A[0]
Sb(0,1): A[-1]
Sa(1,0): A[1]
Sb(1,0): A[0]
Sa(1,1): A[1]
Sb(1,1): A[0]
```
After unroll-and-jam by 2:
```
Sa(0,0): A[0]
Sb(0,0): A[-1]
Sa(1,0): A[1]
Sb(1,0): A[0]
Sa(0,1): A[0]
Sb(0,1): A[-1]
Sa(1,1): A[1]
Sb(1,1): A[0]
```
That is, the dependency chain `Sa(0,0)->Sa(0,1)->Sb(1,0)->Sb(1,1)` has become `Sa(0,0)->Sb(1,0)->Sa(0,1)->Sb(1,1)` and therefore has been violated.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D76132/new/
https://reviews.llvm.org/D76132
More information about the llvm-commits
mailing list