- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The following code exhibits a difference between Intel and some other compilers:
program p
implicit none
integer :: a(4) = [-1, -2, -3, -4]
integer :: n(4) = [4, 2, 1, 3]
call s (a(n), a)
print *, a
contains
elemental subroutine s (x, y)
integer, value :: x
integer, intent(out) :: y
y = x
end
end
While NAG and Cray print:
-4 -2 -1 -3
Intel prints:
-4 -2 -4 -4
My interpretation is that while NAG and Cray create a temporary for a(n), Intel does not.
Q1: is the code legal?
Q2: if so, who is right?
Q3: does the following excerpt from F2018 apply and explain why a temporary is needed here?
! 15.5.2.3 Argument association ! (4) A present dummy argument with the VALUE attribute becomes argument ! associated with a definable anonymous data object whose initial value is ! the value of the actual argument.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For whatever it's worth, my take on the standard is as follows.
- Strictly considering the standard, the code in the original post does not conform, there is what is colloquially mentioned as an aliasing issue with the actual arguments, and the standard places the onus on the program writer to not bring that about. The processor is not required to detect and report the problem.
- Under the circumstances, there is not the question of "who is right?"
- The standard does not mention an array temporary if that is what is your mind.
Placing aside point 1 above for a moment with "aliasing", the rest of the standard semantics with the `ELEMENTAL` procedure and the `VALUE` attribute inform a processor to take the code in the original post and deal with it as follows:
integer :: a(4) = [-1, -2, -3, -4]
integer :: n(4) = [4, 2, 1, 3]
do i = 1, size(a)
block
integer :: anonymous_object
anonymous_object = a(n(i))
call some_sub(anonymous_object, a(i))
end block
end do
print *, a
contains
subroutine some_sub(x, y)
integer :: x
integer, intent(out) :: y
y = x
end
end
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@FortranFan wrote:
Placing aside point 1 above for a moment with "aliasing", the rest of the standard semantics with the `ELEMENTAL` procedure and the `VALUE` attribute inform a processor to take the code in the original post and deal with it as follows:
integer :: a(4) = [-1, -2, -3, -4] integer :: n(4) = [4, 2, 1, 3] do i = 1, size(a) block integer :: anonymous_object anonymous_object = a(n(i)) call some_sub(anonymous_object, a(i)) end block end do print *, a contains subroutine some_sub(x, y) integer :: x integer, intent(out) :: y y = x end end
Can you point to the places in the standard supporting your interpretation?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FWIW, the VALUE attribute should have required that the value of the actual argument be placed onto the stack as opposed to a reference to the object. Without placing the value on the stack, recursive routines (using value) could not be written.
Also, due to value attribute on x (assuming calling code obeys convention) makes x not an alias of an element of the array y.
Lets see what Steve has to say about this.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Harold,
Please try an experiment . Add BIND(C) to the subroutine declaration.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jim,
this is not allowed in F2018:
C1546 An elemental procedure shall not have the BIND attribute.
And it is correctly diagnosed by ifort
Harald
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The key words in the standard are:
15.8.3 Elemental subroutine actual arguments
1 In a reference to an elemental subroutine, if the actual arguments corresponding to INTENT (OUT) and INTENT (INOUT) dummy arguments are arrays, the values of the elements, if any, of the results are the same as would be obtained if the subroutine had been applied separately, in array element order, to corresponding elements of each array actual argument.
So, let's rewrite the elemental call as a loop of scalar calls:
program p
implicit none
integer :: a(4) = [-1, -2, -3, -4]
integer :: n(4) = [4, 2, 1, 3]
integer :: i
do i=1,4
call s(a(n(i)),a(i))
end do
!call s (a(n), a)
print *, a
contains
elemental subroutine s (x, y)
integer, value :: x
integer, intent(out) :: y
y = x
end
end
If we do that, what does NAG Fortran give?
D:\Projects>nagfor -o t.exe t.f90
NAG Fortran Compiler Release 7.1(Hanzomon) Build 7114
[NAG Fortran Compiler normal termination]
D:\Projects>t.exe
-4 -2 -4 -4
I also agree with @FortranFan that the original code violates the standard's aliasing rules, though that is more subtle due to the VALUE attribute.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
Can you explain how a VALUE argument can be an alias of anything?
program p
implicit none
integer :: a(4) = [-1, -2, -3, -4]
integer :: n(4) = [4, 2, 1, 3]
! when the 1st argument is by VALUE
call s ( (a(n)), a) ! explicitly construct a temporary (then places on stack as value)
call s (a(n), a) ! the interface implicitly constructs a temporary on stack
print *, a
contains
elemental subroutine s (x, y)
integer, value :: x
integer, intent(out) :: y
y = x
end
end
Also note, while X has no intent specified, permits OUT, any modification to X would modify the stack value, and not the callers actual argument (which was copied to stack by value).
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jim, it's Y that is being modified, not X. The mistake here is thinking that the entire array a(n) is computed once and saved in a temporary due to VALUE. As the standard says, the reference to the elemental subroutine behaves as if it were a series of scalar calls, and once one of those calls modifies an element of array a, that can change the value of one of the elements of a(n).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
just to make it crystal clear: the key formulation is 15.8.3 saying "... if the subroutine had been applied separately, in array element order, to corresponding elements of each array actual argument." instead of "... effective argument."?
(This would mean that NAG and Cray are wrong.)
Thanks,
Harald
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>>The mistake here is thinking that the entire array a(n) is computed once and saved in a temporary due to VALUE.
VALUE is attributed to the scalar X. Being value argument, this is a stack local copy of the original calling argument A(2) and thus cannot possibly be an alias of any element of array Y (array A in the calling argument). For this subroutine, there is no requirement for a temporary array of A/Y to construct the return value. IOW a copy of X is made, not a temporary copy of Y.
IMHO (for this elemental example) if the standard requires a temporary array for Y = X, then the standard is wrong....
.OR. the implementation is wrong in the event that X (A(2)) is permitted to be passed by reference and thus presenting an alias.
Also, on the
call s(a(2), a)
Should the interface to s .NOT. be known then the arguments are aliased (the call is non-conforming).
However, because the interface is known, the actual argument for the first argument is the stack copy of a(2) and thus becomes inaliasable with the second argument.
IOW, this specific call does not violate the no aliases rule and thus is conforming.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I don't think "actual argument" is inappropriate. And no, NAG and Cray aren't wrong because your code is not standard-conforming.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It has been interesting following this thread. Essentially which number do I have?
Add in a sensor that allows you to read a register, but it does not guarantee that there is anything meaningful in the register adds a dimension to the problem.
The other challenge is the manual is always behind the current iteration of the device. To read one temp register and check for the errors is about 300 lines of code. Then it looks like this. Anyway, life in the slow lane.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
program p
implicit none
integer :: a(4) = [-1, -2, -3, -4]
integer :: n(4) = [4, 2, 1, 3]
! when the 1st argument is by VALUE
call s ( (a(n)), a) ! explicitly construct a temporary (then places on stack as value)
call s (a(n), a) ! the interface implicitly constructs a temporary on stack
print *, a
contains
elemental subroutine s (x, y)
integer, value :: x
integer, intent(out) :: y
y = x
end
end
The Intel version - all I have to use on the first call gets:
It should not have picked up the fourth element of A on the first run through the system --
On the second run it gets the value correctly as it does after that
I do not use elemental functions but from a Fortran manual
-------------------------------------------------------------
Elemental functions are defined as scalar operators, with a single scalar dummy argument and a scalar return value, but they may be invoked with arrays as actual arguments in which case the function will be applied element-wise, with a conforming array return value. Such functions must also be pure functions, with no side effects, and can be indicated with the elemental
prefix. Since it is implied that an elemental function is also pure, the pure
prefix is not necessary.
Elemental subroutines may be defined in a similar way, however, side effects are permitted for intent(out)
or intent(inout)
arguments.
The main benefit of elemental procedures is that advance knowledge that a function is elemental simplifies parallel execution.
---------------------------------------------------------------------------------------------------------------------------------------------
The Intel is not following the rules, unless elementwise does not mean 1, 2,3, 4 but means 4,2,3,4.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There is really nothing wrong with the call from I Iike to do recursion, but the compiler has a bug.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I don't agree that there's a bug. See my earlier post where I cite the standard and show an "unrolled" version and its result.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
call s ( (a(n)), a)
So now the call to a(n) counts up n from i = 1 to 4 and using the n(i) returns in the first instance a(4).
That makes the code difficult to read, but if that is the correct method then the answer is correct. But how many layers deep can you make the call. It is a shorthand for a do loop then
(a(b(c(n)))
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page