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

Argument evaluation and elemental procedures

Harald1
New Contributor II
1,338 Views

Hello,

the following testcase seems to exhibit an issue with argument evaluation prior to invocation of an elemental procedure:

program p
  implicit none
  integer, parameter :: n = 3
  integer            :: a = 0, b(n) = 0 ! counters for argument evaluation
  integer            :: c(n)
  a = 0
  b = 0
  print *, merge (a, b, .true.) ! check: MERGE is elemental
  print *, merge (b, a, .true.)
  a = 0
  b = 0
  c = merge (g(a), g(b), .true.)
  print *, "a=", a, "   <- should be 1"
  print *, "c=", c
  a = 0
  b = 0
  c = merge (g(b), g(a), .false.)
  print *, "a=", a, "   <- should be 1"
  print *, "c=", c
  a = 0
  b = 0
  c = f(g(a), g(b))     ! g(a),g(b) should be evaluated just once
  print *, "a=", a, "   <- should be 1"
  print *, "b=", b
  print *, "c=", c
contains
  elemental function f (x, y)
    integer :: f
    integer, intent(in) :: x, y
    f = x+y
  end function f

  ! Helper function for counting of argument evaluations
  impure elemental integer function g (x)
    integer, intent(inout) :: x
    x = x+1
    g = x
    print *, "in g: x=", x
  end function g
end program p

E.g. F2023, 15.5.3 (functions) and 15.5.4 (subroutine reference) explicitly state that actual arguments are to be evaluated before argument association.  This means that g(a) and g(b) shall be invoked exactly once in each of the above cases when used as argument in a function reference.

I find this confirmed e.g. with the NAG compiler, which prints for the above:

 0 0 0
 0 0 0
 in g: x= 1
 in g: x= 1
 in g: x= 1
 in g: x= 1
 a= 1    <- should be 1
 c= 1 1 1
 in g: x= 1
 in g: x= 1
 in g: x= 1
 in g: x= 1
 a= 1    <- should be 1
 c= 1 1 1
 in g: x= 1
 in g: x= 1
 in g: x= 1
 in g: x= 1
 a= 1    <- should be 1
 b= 1 1 1
 c= 2 2 2

 However, with current ifort/ifx I get:

           0           0           0
           0           0           0
 in g: x=           1
 in g: x=           1
 in g: x=           2
 in g: x=           1
 in g: x=           3
 in g: x=           1
 a=           3    <- should be 1
 c=           1           2           3
 in g: x=           1
 in g: x=           1
 in g: x=           1
 in g: x=           2
 in g: x=           1
 in g: x=           3
 a=           3    <- should be 1
 c=           1           2           3
 in g: x=           1
 in g: x=           1
 in g: x=           2
 in g: x=           1
 in g: x=           3
 in g: x=           1
 a=           3    <- should be 1
 b=           1           1           1
 c=           2           3           4

 So neither the elemental intrinsic MERGE nor a user-defined elemental function case agree with NAG.

While the above may appear a little academic, it may be important for situations when the types involved are finalizable.

Thanks,

Harald

 

1 Solution
Harald1
New Contributor II
610 Views

Confirmed.  This now works for me.

Thanks!

 

View solution in original post

0 Kudos
4 Replies
andrew_4619
Honored Contributor III
1,314 Views

I agree that it looks like a compiler problem to me. When function g(x) is passed a scaler the result should be a scaler temp which merge should promote/expand to a temporary array  to match the size/shape of the other merge parameter. 

0 Kudos
Barbara_P_Intel
Employee
1,271 Views

Thank you for reporting this. Again you submitted a great reproducer.

I filed a bug, CMPLRLLVM-48874. I will let you know when a fix is ready.


0 Kudos
Barbara_P_Intel
Employee
617 Views

@Harald1, this issue with both ifx and ifort is fixed in the compilers that were fixed earlier this week. Please try them!



0 Kudos
Harald1
New Contributor II
611 Views

Confirmed.  This now works for me.

Thanks!

 

0 Kudos
Reply