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

elemental function calls elemental function

Robert_van_Amerongen
New Contributor III
455 Views
I have a problem with the case that an elemental function calls an elemental function. In the example added below you will see a small program wherean elemental function sub1 is called that, in turn, calls the elemental function sub2. With the addition of /warn:all in the command line, everything is ok. But without this addition it fails. AFAIK it must compile correctly with or without this addition. I think that my code is correct. What is going on here? (Version 11.1.065)

Robert

Code:

PROGRAM ef

IMPLICIT none

REAL :: ar(10)

COMPLEX :: ac(10)

INTEGER :: i

COMPLEX :: sub1 ! the definition of the first function

ar=[(i,i=1,10)] ! initialise

ac=sub1(ar) ! call the first elemental function

write(*,'(2f10.4)') ac(1:10) ! print some results

STOP

END

!

COMPLEX ELEMENTAL FUNCTION sub1(ar) ! the first elem. func

IMPLICIT none

REAL,INTENT(in) :: ar

! explicit interface

INTERFACE

COMPLEX ELEMENTAL FUNCTION sub2(ar)

REAL, INTENT(in) :: ar

END FUNCTION sub2

END INTERFACE

!

sub1=3.*sub2(ar) ! call the second elemental function

RETURN

END

!

COMPLEX ELEMENTAL FUNCTION sub2(ar) ! the second elem. function

IMPLICIT none

REAL,INTENT(in) :: ar

sub2=CMPLX(0.,ar**2)

RETURN

END

0 Kudos
4 Replies
John4
Valued Contributor I
455 Views

What do you mean when you say "But without this addition it fails"? I don't have any problem compiling your code, with or without /warn:all.

The resulting executable, on the other hand, doesn't output the correct results because you're stating that the first function is:

[fortran]complex function sub1(ar)
implicit none
real, intent(IN) :: ar
... end[/fortran]
What I mean is that the definition of the first function in the program unit does not imply that the function sub1 is elemental, so sub1 is being called only once ---and the returned scalar is being assigned to the ac array.

The /warn:all flag implies /warn:interfaces which in turn implies /gen-interfaces. So with that option, a temporary module is being generated for every external function, and that's what corrects the mistake you made.

An easily corrected version of your code (with no interface blocks), would be:

[fortran]module subs

contains

    complex elemental function sub1(ar)     ! the first elem. func

    implicit none

    real,intent(in) :: ar

    sub1 = 3. * sub2(ar)                    ! call the second elemental function

    return

    end function


    complex elemental function sub2(ar)     ! the second elem. function

    implicit none

    real,intent(in) :: ar

    sub2 = CMPLX(0., ar ** 2)

    return

    end function

end module


program ef

    use subs

    implicit none

    real :: ar(10)

    complex :: ac(10)

    integer :: i

    ar = [(i, i = 1, 10)]   ! initialise

    ac = sub1(ar)           ! call the first elemental function

    write(*,'(2f10.4)') ac  ! print some results

end program
[/fortran]


0 Kudos
Jugoslav_Dujic
Valued Contributor II
455 Views
Cute example, Robert, but as John said, the fault is ultimately yours. Let me try to explain in a different way:

ELEMENTAL (as well as PURE) attribute requires an explicit interface, which you failed to provide. Without the interface, the compiler does not know that it should vectorize the call to Sub1, and calls it only once.

Now comes the /check:all /warn:all, which automatically generates the explicit interfaces, for the purpose of argument checking. However, the /check:all /warn:all only compares for matching of argument datatypes and shapes, not for other features. It finds the real array actual argument, and real scalar dummy argument, which would be illegal if it weren't for ELEMENTAL. Having find the ELEMENTAL attribute, the checker is happy. Thus, it "fixed" the problem as a side effect.

Thus, it is a minor flaw (or a feature) in /warn:all, but it's quite understandable why Intel folks overlooked it (or do not regard it as a bug).
0 Kudos
mecej4
Honored Contributor III
455 Views
Jugoslav is taking the point of view of the ISO standard authors. The standard does not prescribe what is to be done by the compiler with code that is not in conformity with the standard, and Robert's code sample is one such. (Jugoslav, please make this correction to your post: you probably meant /warn:all where you wrote /check:all).

However, one of the attributes that make up the quality of a compiler is the usefulness of the error messages that it gives the user when asked to compile non-conforming code. High in quality we know the Intel compiler to be; but, in this particular case, I find it deficient, for the following reasons.

With /warn:all correct results are produced, whereas with /check:all wrong results are produced. In neither case is any message given, either at compile time or during the run.

Intuitively, I expect "warn" to tell me about problems detected at compile-time, and "check" to tell me about problems detected at run-time. It is unsettling for the compiler to correct errors behind the scenes, with some options and only with some types of error, and not give out any error or warning messages. Without error messages, one has to examine the automatically produced interfaces and find the root cause of the error, if one has an inkling that it is the interfaces that hold the clues.

A competing compiler gives the following run-time message with Robert's original code, with checks turned on:

"An attribute of argument 1 is inconsistent (actual argument ar: array name, dummy argument ar: scalar variable name)."
"error occurs at sub1_ line 13 "

Line 13: COMPLEX ELEMENTAL FUNCTION sub1(ar) ! the first elem. func

This message is clear and goes straight to the point.

A third compiler gives a compile time error:

"Error: elemo.f90: Argument AR (no. 1) in reference to SUB1 from EF is not scalar"


This example shows some of the rough edges of /warn:all, which is a recent Intel innovation. We hope Intel will polish these rough edges while preparing forthcoming releases.
0 Kudos
Robert_van_Amerongen
New Contributor III
455 Views
John and Tim,

you both convinced me that I did made an error. After incorporating an explicit interface in the calling program,any problem is gone. I presume I have misread par. 6.10 of Metcalf c.s.; in any case in the standard, par. 12.6 "Pure Procedure"C1270 leaves no room for any misinterpretation.

Having said this, the situationleaves me in a somewhat uncomfortable mood. The code that I initially used turned out to be basically wrong. The use of the compuler option /warn:all caused theerror beingmade undetectable. So, anexecutable is generated based on a incorrect code. That soundsvery friendly but is, to my opinion, undesirable, to put it mildly. An error in the code must produce an error somewhere in the codedevelopment proces.Preferably in the compile phase (although Iunderstand that this is impossilbe in this case) or during execution, so during testing the construct. The compiler option /nogen-interfaces thus become now standard to my command line!

Again, thanksfor your nice help!

Robert
0 Kudos
Reply