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

pointer to procedure is constant while should not

foxtran
New Contributor I
511 Views

Hello!

Some time ago a reported a problem with global variables which are passed as argument to functions, and later, in some calls it was updated. See more here, https://community.intel.com/t5/Intel-Fortran-Compiler/common-variable-passed-as-argument-of-function-is-overoptimized/m-p/1573128 

I have tried to implement a static check into LLVM Flang to verify our source code, and for testing of my implementation, I have created the following example:

==> alloc.f90 <==

integer function alloc(n)
  use common_mod
  implicit none
  integer n
  alloc = imem + n
  imem = imem + n
  print_char => print_B
end function alloc

==> common.f90 <==

module print_mod
  implicit none
  abstract interface
    subroutine print_char_t()
    end subroutine print_char_t
  end interface
end module print_mod

module common_mod
  use print_mod, only: print_char_t
  implicit none
  private
  integer, pointer :: imem => null()
  procedure(print_char_t), pointer :: print_char
  public :: imem, print_char, print_A, print_B
contains
  subroutine print_A()
    print *, 'A'
  end subroutine print_A
  subroutine print_B()
    print *, 'B'
  end subroutine print_B
end module common_mod

==> main.f90 <==

program main
use common_mod
implicit none
integer, target :: real_mem
interface
subroutine test(i, f)
use print_mod
integer, pointer :: i
procedure(print_char_t), pointer :: f
end subroutine test
end interface
real_mem=0
imem=>real_mem
print_char=>print_A
call print_char()
call test(imem, print_char)
call print_char()
end program main

==> test.f90 <==

subroutine test(imem2, func)
use common_mod, only: imem
use print_mod
implicit none
integer, pointer :: imem2
procedure(print_char_t), pointer, intent(inout) :: func
integer :: res
integer, external :: alloc
print *, imem2, imem
call func()
res = alloc(8)
print *, imem2, imem
call func()
end subroutine test

However, it does not work well with ifx. With optimizations it gives a quite strange answer:

$ ifx common.f90 alloc.f90 test.f90 main.f90 -O3 && ./a.out
 A
           0           0
 A
           8           8
 A
 B

That, pointer to function was a constant in procedure test. 
Without, it is OK:

$ ifx common.f90 alloc.f90 test.f90 main.f90 -O0 && ./a.out
 A
           0           0
 A
           8           8
 B
 B

gfortran -O0/-O3, flang-new (Clang 20.0Git) -O0/-O3, ifort -O0/-O3 generates the same output as ifx -O0.

So, it looks like a bug in ifx. And it would be wonderful to have the same (consistent) behaviour between ifx/gfortran/flang-new not only with pointer attribute, but also without it. 

0 Kudos
5 Replies
Ron_Green
Moderator
490 Views

I'll take a look into this with the current code branches and report back.

 

ron

0 Kudos
Ron_Green
Moderator
462 Views

I combined the sources to one source to help with the analysis.

cat common.f90 alloc.f90 test.f90 main.f90 >> repro.f90

 

Indeed, ifx is behaving differently.  Using opt-bisect-limit I've isolated the difference at opt phase 

EarlyCSEPass

There is a LLVM bug report on this function but it seems completely unrelated to your test case.  

 

EarlyCSEPass In my compiler is optimization 421.  420 naturally abides. 

If you've not used opt-bisect-limit here is how to do it - binary search on the optimization numbers

ifx -O3 -mllvm -opt-bisect-limit=420 repro.f90 && ./a.out

this works, 420 friendly ( I can't make this stuff up)

and this does not

ifx -O3 -mllvm -opt-bisect-limit=421 repro.f90 && ./a.out

 

I have what I need to dig in deeper.  This issue is also present in the 2025.0 branch and the main branch "2025.1".  

I will now see if I can reduce this test case down some more. 

Ron_Green
Moderator
422 Views

I wrote it up, bug ID is CMPLRLLVM-62428

 

I was wrong on the optimization phase.  It's actually further up the list.  

O3 is 

BISECT: running pass (86) InstCombinePass on test_

 

O2 also points to InstCombinePass on test_

BISECT: running pass (78) InstCombinePass on test_

 

Optimizer bug it appears, although it is possible we are lowering test() with a missing attribute from our front end.  I'm letting the optimizer team take a look first.

Here's what I reduced this to:

module print_mod
  implicit none
  abstract interface
    subroutine print_char_t()
    end subroutine print_char_t
  end interface
end module print_mod

module common_mod
  use print_mod, only: print_char_t
  implicit none
  private
  procedure(print_char_t), pointer :: print_char
  public :: print_char, print_A, print_B
contains
  subroutine print_A()
    print *, 'A'
  end subroutine print_A
  subroutine print_B()
    print *, 'B'
  end subroutine print_B
end module common_mod

integer function alloc()
  use common_mod
  implicit none
  alloc = 42 
  print_char => print_B
end function alloc

subroutine test( func)
  use print_mod
  implicit none
  procedure(print_char_t), pointer, intent(inout) :: func
  integer :: res

  integer, external :: alloc

  print*, "calling print A"
  print*, " then call alloc() sets func ptr to print B.  should see A followed by B "
  call func()
  !...rwg commenting out both of the following print
  !...rwg statements  will give wrong results for func ptr
  !...rwg uncomment either print will set func ptr to B as it should be
  !print*, "calling alloc, setting func ptr to print B"
  res = alloc()
  !print*, "done with alloc, call func to print B"
  call func()
end subroutine test

program main
use common_mod
implicit none

interface
subroutine test(f)
use common_mod
use print_mod
procedure(print_char_t), pointer, intent(inout) :: f
end subroutine test
end interface

print_char=>print_A

print*, "calling test"
call test(print_char)
print*, "done with test, should be print B"
call print_char()
end program main

 

This is one of those tricky bugs.  Notice my comments around the call to alloc() at line 46.  There is a print before and a print after the call, commented out.  If you uncomment one or the other RPINT the code works at O1-O3!  

 

Ron_Green
Moderator
314 Views

Not in the optimizer, it's in our Fortran frontend code.  We know the problem, working on a fix.

 

I am curious, is this blocking you from moving your application to ifx?  If so, what is the name of your project or application, assuming you can share that information.

0 Kudos
foxtran
New Contributor I
309 Views

Yep, it is blocking. The project is MRCC developed in BME. Project page is mrcc.hu

I have replaced all places where this bug happens, however, I do not know the status of my patches... If you interested, I can add you into GitHub repo. It is my own development ahead of master branch.
If somebody push Prof. Mihaly Kallay to use git, I will be extremely happy  

0 Kudos
Reply