Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Passing pointer arrays as actual arguments to a subroutine with non-pointer dummy arguments

Felipe1
Beginner
1,473 Views

Dear all,

I am confused with what should be the correct behavior of a Fortran code when one passes overlapping pointer arrays as actual arguments to a subroutine that takes non-pointer arrays as dummy arguments. Please, take a look at the code below:

! my_axpy.f90

module my_axpy_m
  implicit none
contains

  subroutine my_axpy(N, alpha, x, y)
    integer, intent(in) :: N
    double precision, intent(in) :: alpha
    ! Incorrect results happens if x/y are either assumed-shape or
    ! assumed-size arrays, but not if they are pointer dummy arguments.
    double precision, intent(inout) :: x(:)
    double precision, intent(inout) :: y(:)

    integer :: ii

    do ii = 1, N
      x(ii) = alpha*x(ii) + y(ii)
    enddo

  end subroutine my_axpy

end module my_axpy_m
! main.f90
program main
  use my_axpy_m
  implicit none

  ! Need N>=4 to trigger the wrong result.
  integer, parameter :: N=4, OFFSET=1, M=N+OFFSET
  double precision, pointer :: x(:), y(:)
  integer :: ii

  allocate(y(M))
  x => y(OFFSET+1:M)

  do ii = 1, M
    y(ii) = ii
  enddo
  print *, 'Input x and y:'
  do ii = 1, N
    print *, x(ii), y(ii)
  enddo

  call my_axpy(N, 1d0, x, y)

  print *
  print *, 'Output x:'
  do ii = 1, N
    print *, x(ii)
  enddo

end program main

Makefile:

! Makefile
QOPT = -qopt-report1 -qopt-report-file=stderr -qopt-report-phase=vec

# Correct result
F90 = ifort -O3 $(QOPT)
# Incorrect result on a Intel(R) Xeon(R) CPU E5-2698 v3 @ 2.30GHz
#F90 = ifort -xHost $(QOPT)

default: main

clean:
	rm -f *.o *.mod main

.PHONY: clean

main.o: my_axpy.o

%.o: %.f90
	$(F90) -c $<

main: main.o my_axpy.o
	$(F90) -o main $^

Depending on the optimization level (see the Makefile) I get different results. With ifort -O3 (or simply ifort), I get

   3.00000000000000
   6.00000000000000
   10.0000000000000
   15.0000000000000

But with ifort -xHost, I get

   3.00000000000000
   5.00000000000000
   7.00000000000000
   9.00000000000000

The first result is clearly taking into account that the arrays actually point to overlapping memory regions, while the second one does not (or vectorizes and does not capture the overlap)

At any rate, what is the correct behavior of a Fortran program in this case? I quickly went over the Fortran 2003 standard, but couldn't find anything concrete about a case like this. I am missing something?

Since the dummy arguments in the `my_axpy` subroutine are non-pointer arrays, I assume that the correct behavior is to vectorize and assume that x and y point to non-overlapping memory regions inside the subroutine. Does that mean that the compiler should make a copy of the arrays x and y before calling the subroutine, which is not happening with ifort -xHost?

Thanks,

Felipe

0 Kudos
7 Replies
Juergen_R_R
Valued Contributor I
1,473 Views

I see a similar behaviour with gfortran. However, nagfor seems to print out in all cases 3, 6, 10, 15. It looks like that the compiler is optimizing

in the case -xHost for ifort or -O4/-Ofast for gfortran the do loop inside the subroutine and then not taking into account the memory addresses of the x and y actual arguments. You can avoid this by giving the two dummy arguments the volatile attribute, then both ifort and gfortran do not do their optimizations, probably taking into account the possibility that the actual arguments might have changed elsewhere (e.g. by means of pointer assignment). 

0 Kudos
Steve_Lionel
Honored Contributor III
1,473 Views

Your program is not legal Fortran because of the aliasing. If you add the TARGET attribute to the dummy arguments, then it will be ok.

Section 12.5.2.13 of the F2008 standard says:

Action that affects the value of the entity or any subobject of it shall be taken only through the dummy argument unless
 (a) the dummy argument has the POINTER attribute or
 (b) the dummy argument has the TARGET attribute, the dummy argument does not have INTENT (IN), the dummy argument is a scalar object or an assumed-shape array without the CONTIGUOUS attribute, and the actual argument is a target other than an array section with a vector subscript.

If the value of the entity or any subobject of it is affected through the dummy argument, then at any time during the invocation and execution of the procedure, either before or after the definition, it may be referenced only through that dummy argument unless
(a) the dummy argument has the POINTER attribute or
(b) the dummy argument has the TARGET attribute, the dummy argument does not have INTENT (IN), the dummy argument is a scalar object or an assumed-shape array without the CONTIGUOUS attribute,

0 Kudos
Felipe1
Beginner
1,473 Views

Hi,

thanks for your answers.

In, particular, Steve, thanks for pointing out to the standard. I also see that Note 12.34 is very clear about this:

If there is a partial or complete overlap between the effective arguments of two different dummy arguments of the same procedure and the dummy arguments have neither the POINTER nor TARGET attribute, the overlapped portions shall not be defined, redefined, or become undefined during the execution of the procedure.

However, even after I added the TARGET attribute to the dummy arguments x and y in the my_axpy subroutine, I still get the same inconsistent results. I only get the same results (which takes aliasing into account) when I add the POINTER attribute. Shouldn't TARGET be enough?

By the way, I always get the correct answering (i.e., which considers aliasing) when I use gfortran or cray compiler. I am surprised that they give the "right" answer even without the TARGET attribute..

Thanks,

Felipe

0 Kudos
Steve_Lionel
Honored Contributor III
1,473 Views

I would think so. What happens if you add -assume dummy_aliases

Adding TARGET should be sufficient. Which compiler version are you using?

0 Kudos
Felipe1
Beginner
1,473 Views
Hi Steve, I tried intel 18.0.1.163, 17.0.3.191, and 16.0.3.210, and they all give the wrong results with -xHost and without the POINTER attribute. If I add -assume dummy_aliases, I get the right result – though I get the right result even without the POINTER or TARGET attributes. Thanks, Felipe
0 Kudos
Steve_Lionel
Honored Contributor III
1,473 Views

Please submit this through the Intel Online Service Center. I think there's a compiler bug. I have a rather old machine (Ivy Bridge) and could not reproduce the problem.

0 Kudos
mecej4
Honored Contributor III
1,473 Views

FELIPE L. wrote:

Hi Steve,

I tried intel 18.0.1.163, 17.0.3.191, and 16.0.3.210, and they all give the wrong results with -xHost and without the POINTER attribute.

If I add -assume dummy_aliases, I get the right result – though I get the right result even without the POINTER or TARGET attributes.

That should not be a cause for much surprise. If you have code that satisfies the anti-aliasing rules, optimization options should have no effect on the functioning of the code and you should get the correct results.

If the code does not satisfy the anti-aliasing rules, you may see errors when optimization features are used that are of such a nature that the presence of aliasing may produce incorrect results. Setting the optimization level low or specifying the POINTER attribute may inhibit the application of unsafe optimizations.

As long as your code does not satisfy the anti-aliasing rules, you should not assume that a certain set of optimization options will continue to give you correct results just because the results were correct at one time with the same options.

0 Kudos
Reply