https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82604
--- Comment #11 from rguenther at suse dot de <rguenther at suse dot de> --- On Thu, 18 Jan 2018, amker at gcc dot gnu.org wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82604 > > --- Comment #10 from amker at gcc dot gnu.org --- > For the record, there is another possible fix. Quoted loop nest from > gcc/testsuite/gfortran.dg/pr81303.f: > > do j=1,ny > jm1=mod(j+ny-2,ny)+1 > jp1=mod(j,ny)+1 > do i=1,nx > im1=mod(i+nx-2,nx)+1 > ip1=mod(i,nx)+1 > do l=1,nb > y(l,i,j,k)=0.0d0 > do m=1,nb > y(l,i,j,k)=y(l,i,j,k)+ > ;; .... > enddo > enddo > enddo > enddo > > Originally GCC can parallelize loop nest at i loop, but now GCC only > parallelize it at l loop because stmt "y(l,i,j,k)=0.0d0" is distributed into > memset into i loop. As a result the distributed memset call can't be analyzed > by data reference analyzer. > An idea is to distribute the stmt to outer loop j, so at least we can > parallelize at loop level i as before. > > Unfortunately this is not easy. To distribute it into memset at loop level j, > we have to prove that memory range set to ZERO at each loop level doesn't > leave > any bubble in it. > Given the array bound and loop niters are not constant, we need to prove > non-trivially equality for difference expressions. This needs to be done in > function tree-loop-distribution.c:compute_access_range. Specifically in this > function we have: > > <bb 2>: > _1 = *nb_113(D); > ubound.86_114 = (integer(kind=8)) _1; > stride.88_115 = MAX_EXPR <ubound.86_114, 0>; > > ... > > <bb 34>: // thus in loop nest we have _1 > 0 > if (_1 <= 0) > goto <bb 24>; [15.00%] > else > goto <bb 35>; [85.00%] > > ... > > And in the end, we need to prove: > > ((sizetype) ((unsigned int) _1 + 4294967295) + 1) * 8 > == (sizetype) stride.88_115 * 8 > > We first need to prove: > ((sizetype) ((unsigned int) _1 + 4294967295) + 1) > == (sizetype) _1 > using pre-condition "_1 > 0" > > Then need to prove: MAX_EXPR <ubound.86_114, 0> == ubound.86_114 also because > of "_1 > 0". > > I doubt this can be done (without heavy messy code) in GCC now. Or there > might > be another way out of this? I think the zeroing stmt can be distributed into a separate loop nest (up to whavever level we choose) and in the then non-parallelized nest the memset can stay at the current level. So distribute > do j=1,ny > jm1=mod(j+ny-2,ny)+1 > jp1=mod(j,ny)+1 > do i=1,nx > im1=mod(i+nx-2,nx)+1 > ip1=mod(i,nx)+1 > do l=1,nb > y(l,i,j,k)=0.0d0 > do m=1,nb > y(l,i,j,k)=y(l,i,j,k)+ > ;; .... > enddo > enddo > enddo > enddo to > do j=1,ny > jm1=mod(j+ny-2,ny)+1 > jp1=mod(j,ny)+1 > do i=1,nx > im1=mod(i+nx-2,nx)+1 > ip1=mod(i,nx)+1 > do l=1,nb > y(l,i,j,k)=0.0d0 > enddo > enddo > enddo > do j=1,ny > jm1=mod(j+ny-2,ny)+1 > jp1=mod(j,ny)+1 > do i=1,nx > im1=mod(i+nx-2,nx)+1 > ip1=mod(i,nx)+1 > do l=1,nb > do m=1,nb > y(l,i,j,k)=y(l,i,j,k)+ > ;; .... > enddo > enddo > enddo > enddo And then do memset replacement in the first loop. I think the current cost modeling doesn't consider this because of the re-use of y. IIRC this is what my original nest distribution patches did. This might be doable by just cost model changes?