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

Wrong code generation with assume recursive in version 19.0.0.117

Christian
Novice
777 Views

Hello,

the following program crashes with an access violation when compiled with "ifort /debug /recursive bug.f":

      program bug
        implicit none
        integer get_value
        external get_value
        print *, get_value()
      end program


      integer function get_value()
        implicit none
        get_value = 0
        call get_value_sub(get_value)
      end function get_value


      subroutine get_value_sub (outval)
        implicit none
        integer, intent(out) :: outval
        outval = 1
      end

Cause is the "call get_value_sub" with the argument "get_value". The compiler pushes a wrong address to the stack.

The bug doesn't appear when compiled with 18.0.3.210 or with 19.0.0.117 without the /resursive flag.

In the moment this prevents us from upgrading the compiler.

Best regards,

Christian

0 Kudos
10 Replies
FortranFan
Honored Contributor II
777 Views

It looks a regression in the official release of Intel Fortran 19.0 compiler.  You may want to submit a support request at the Intel Online Service Center: https://supporttickets.intel.com/?lang=en-US

In the mean time, you may want to consider using the facilities in the Fortran standard starting with MODULEs and "informing" the compiler of coding instructions explicitly (!!) which may then avoid the issue e.g.,

module m
   implicit none
contains
   function get_value() result( r )
      integer :: r
      r = 0
      call get_value_sub( r )
      return
   end function get_value
   subroutine get_value_sub (outval)
     integer, intent(out) :: outval
     outval = 1
     return
   end
end module 
program bug
   use m, only : get_value
   implicit none
   print *, get_value()
   stop
end program
C:\Temp>ifort /debug /recursive p.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R
) 64, Version 19.0.0.117 Build 20180804
Copyright (C) 1985-2018 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.14.26433.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-debug
-pdb:p.pdb
-subsystem:console
p.obj

C:\Temp>p.exe
           1

C:\Temp>

 

0 Kudos
vishal_p_
Beginner
777 Views

It is not clear to me what /recursive is supposed to do. It is listed under Floating-Point Options in the IFort 18 developer guide and reference. With the 18.0.3 compiler, the assembly output for the code of #1 is the same with or without the /recursive option. That is perhaps to be expected, since there is no recursion in the example code. Furthermore, the default optimization has done away with the call to GET_VALUE_SUB, and the assembly code for GET_VALUE() corresponds to

integer function get_value()
  implicit none
  get_value = 1
end function get_value

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
777 Views

>>It is not clear to me what /recursive is supposed to do.

subroutine foo
  real :: a(3)

Without recursive, local arrays such as a(3) are SAVE (static)
With recursive, local arrays such as a(3) are Automatic (stack)

Similar behavior with user defined types.

Jim Dempsey

0 Kudos
mecej4
Honored Contributor III
777 Views

jimdempseyatthecove wrote:
Without /recursive, local arrays such as a(3) are SAVE (static)

Only if /Qsave has also been specified. By default (i.e., without /Qsave or another option with that effect), local arrays are allocated on the stack; there is an option to allocate some local variables on the heap. I suspect that these options interact, and that one of these options may override the effects of other options. The documentation does not make these interactions known.

0 Kudos
jimdempseyatthecove
Honored Contributor III
777 Views

Mecej4,

The behavior of local arrays being save or automatic has traditionally been default save. Newer language specifications may have changed the default behavior. From IVF 2017 documentation:

SAVE

Statement and Attribute: Causes the values and definition of objects to be retained after execution of a RETURN or END statement in a subprogram.


The SAVE attribute can be specified in a type declaration statement or a SAVE statement, and takes one of the following forms:

Type Declaration Statement:

type,[att-ls,]  SAVE [, att-ls] :: entity[, entity ] ...

Statement:

SAVE [[::]entity [, entity ] ...]


type
 
Is a data type specifier. 
 

att-ls
 
Is an optional list of attribute specifiers. 
 

entity 
 
Is the name of an object, the name of a procedure pointer, or the name of a common block enclosed in slashes (/common-block-name/).
 


Description

In Intel® Fortran, certain variables are given the SAVE attribute, or not, by default:

•The following variables are not saved by default: 

  ◦Scalar local variables of intrinsic types INTEGER, REAL, COMPLEX, and LOGICAL without default initialization 
  ◦Variables that are declared AUTOMATIC
  ◦Local variables that are allocatable arrays
  ◦Derived-type variables that are data initialized by default initialization of any of their components
  ◦RECORD variables that are data initialized by default initialization specified in its STRUCTURE declaration

•The following variables are saved by default: 

  ◦COMMON variables
  ◦Scalar local variables not of intrinsic types INTEGER, REAL, COMPLEX, and LOGICAL of non-recursive subprograms 
  ◦Non-scalar local variables of non-recursive subprograms
  ◦Module or submodule variables
  ◦Data initialized by DATA statements 

•Local variables that are not described in the preceding two lists are saved by default.

Note

Certain compiler options (such as options save and automatic) and the use of OpenMP* features can change the defaults. 
To enhance portability and avoid possible compiler warning messages, Intel recommends that you use the SAVE statement to name variables whose values you want to preserve between subprogram invocations.
When a SAVE statement does not explicitly contain a list, all allowable items in the scoping unit are saved.

A SAVE statement cannot specify the following (their values cannot be saved): 
  •A blank common
  •An object in a common block
  •A procedure
  •A dummy argument
  •A function result
  •An automatic object
  •A PARAMETER (named) constant

Even though a common block can be included in a SAVE statement, individual variables within the common block can become undefined (or redefined) in another scoping unit.
If a common block is saved in any scoping unit of a program (other than the main program), it must be saved in every scoping unit in which the common block appears.
A SAVE statement has no effect in a main program.

Jim Dempsey

0 Kudos
mecej4
Honored Contributor III
777 Views

OK, I see that you are thinking of more general codes. The example posted in #1 has only scalar variables, and my comments were in that context.

0 Kudos
Longhurst__Rodney
777 Views

Have just encountered this trying to update from XE2013 to XE2019.

  • It's passing the address of the function itself, rather than the address of the (same-named) result variable
  • Using a differently-named result variable avoids the problem
  • Can reproduce in XE2013 by explicitly declaring a function as recursive (but not with the /recursive compile flag). With 2019 the /recursive flag and explicit recursive declaration are equivalent, but in 2013 the behaviour is subtly different.

It does seem a bug, although it's understandable as for a recursive function the compiler has to decide whether the function name refers to the function or the result variable. When being passed to another routine it has no way of knowing in older-style Fortran.

0 Kudos
Steve_Lionel
Honored Contributor III
777 Views

If the compiler is passing the function address rather than the result variable, when RESULT is omitted, that's clearly a bug and should be reported to Intel. (Was it?) I'll note that Fortran 2018 makes procedures RECURSIVE by default, but I don't think ifort has formally adopted that change. (The RECURSIVE keyword is now "advisory-only" - a new NON_RECURSIVE keyword is used to specify the older behavior.) 

I disagree with Jim that "default save" has been the default. Intel Fortran, in the absence of a specification that a procedure is recursive, has chosen to make arrays static - this is not the same as SAVE. Clearly this will have to change when ifort adopts the F2018 semantics.

0 Kudos
jimdempseyatthecove
Honored Contributor III
777 Views

>>has chosen to make arrays static - this is not the same as SAVE

Correct, the SAVE attribute is missing, but otherwise they are both located in static memory areas (may have different name manglings).

Jim Dempsey

0 Kudos
Christian
Novice
777 Views

In Version 19.1.0.166 Build 20191121 the bug is fixed.

0 Kudos
Reply