Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29231 ディスカッション

pointer to procedure is constant while should not

foxtran
新規コントリビューター II
2,593件の閲覧回数

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 件の賞賛
1 解決策
foxtran
新規コントリビューター II
1,942件の閲覧回数

Fixed in ifx 2025.1! Hooray!

元の投稿で解決策を見る

8 返答(返信)
Ron_Green
モデレーター
2,572件の閲覧回数

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

 

ron

Ron_Green
モデレーター
2,544件の閲覧回数

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
モデレーター
2,504件の閲覧回数

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
モデレーター
2,396件の閲覧回数

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.

foxtran
新規コントリビューター II
2,391件の閲覧回数

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  

foxtran
新規コントリビューター II
1,943件の閲覧回数

Fixed in ifx 2025.1! Hooray!

foxtran
新規コントリビューター II
1,514件の閲覧回数

@Ron_Green, an example with pointers works fine, but if the common block variables are used, the issue still exists, unfortunately.

Steve_Lionel
名誉コントリビューター III
1,493件の閲覧回数

See my reply to your latest thread. The program violates the standard.

返信