I am following up on the following issue on contained functions for Fortran programs compiled with AOCC:
https://community.amd.com/t5/server-gurus-discussions/aocc-issue-with-contained-functions/m-p/391773
The new version of the compiler indeed solved the problem as described there, but now our code has evolved and the issue has re-emerged in the same context but involving slightly different "building blocks". In particular, we are now using classes and objects, and the problem faced is exemplified by the two programs that follow.
In the first one, given below, the solver is encapsulated into the derived type (class) gensolver. The procedure pointer pResidualSub is a class-wide variable that is set by the command "call solver_obj%initialise(evallhs)" in the main program; evallhs points to subroutine eval_left_hand_side contained in the main program. When pResidualSub is called, while making use of the object, the flow of the program is successfully directed to eval_left_hand_side, but accessing kparam results in a segmentation fault in the AOCC compiler but not in GNU Fortran (sample output given in the end of the post).
!------
!Solver_ContainedFunctions_v2_FAILS_W_AOCC3.f90
!------
module function_interface
interface
subroutine eval_integer_function(iarg,ireslt)
integer, intent(in) :: iarg
integer, intent(out) :: ireslt
end subroutine eval_integer_function
end interface
end module function_interface
module solver
use function_interface
implicit none
public
procedure(eval_integer_function), pointer :: pResidualSub => NULL()
type gensolver
integer niter
contains
procedure :: initialise => solver_initialise
procedure :: find_solution => brute_force_solution_search
end type gensolver
contains
subroutine solver_initialise(this,ResidualSub_in)
implicit none
class(gensolver) this
procedure (eval_integer_function), pointer, intent(in) :: ResidualSub_in
pResidualSub => ResidualSub_in
end subroutine solver_initialise
subroutine brute_force_solution_search(this,imin,imax,isolution,iflag)
implicit none
class(gensolver) this
integer, intent(in) :: imin, imax
integer, intent(out) :: isolution, iflag
integer :: i, reslt
iflag = 1 ! flag values: 0 = no error, 1 = no solution found
do i = imin,imax
call pResidualSub(i,reslt)
if (reslt == 0) then
isolution = i
iflag = 0
return
end if
end do
this%niter = i
return
end subroutine brute_force_solution_search
end module solver
program main_test
use function_interface
use solver
implicit none
class(gensolver), allocatable :: solver_obj
integer :: isolution, iflag, kparam
procedure(eval_integer_function), pointer :: evallhs
! Trying to solve f(i,kparam) == 0 but the solver only understands: g(i) == 0
! To bypass the limitation we define a locally contained function, which "knows"
! the value of kparam by its membership to "main_test"
allocate(gensolver::solver_obj)
kparam = 5
evallhs => eval_left_hand_side
call solver_obj%initialise(evallhs)
call solver_obj%find_solution(0,10,isolution,iflag)
if (iflag == 0) then
write(*,*) 'solution found:',isolution
else
write(*,*) 'no solution found'
end if
contains
subroutine eval_left_hand_side(i,lhs)
implicit none
integer, intent(in) :: i
integer, intent(out) :: lhs
write(*,*) 'in eval_left_hand_side'
write(*,*) i
write(*,*) lhs
write(*,*) kparam
write(*,*) 'starting evaluation'
lhs = (i+1)*(i-kparam) ! this compiles but leads to seg-fault in AOCC;
! yet, it compiles and runs fine in GNU and Intel Fortran
! lhs = (i+1)*(i-5) ! this is fine with all 3 compilers but has kparam "hardcoded"
return
end subroutine eval_left_hand_side
end program main_test
In another variant of the above program (see below), the procedure pointer pResidualSub is a "field" in gensolver, instead of a class-wide variable. The logic is exactly as that discussed previously...
!------
!Solver_ContainedFunctions_v3_FAILS_W_AOCC3.f90
!------
module solver
implicit none
public
type gensolver
integer niter
procedure(ResidualSub), pointer, pass(this) :: pResidualSub
contains
procedure :: initialise => solver_initialise
procedure :: find_solution => brute_force_solution_search
end type gensolver
abstract interface
subroutine ResidualSub(iarg, ireslt, this)
import gensolver
implicit none
class(gensolver), intent(inout) :: this
integer, intent(in) :: iarg
integer, intent(out) :: ireslt
end subroutine ResidualSub
end interface
contains
subroutine solver_initialise(this,ResidualSub_in)
implicit none
class(gensolver) this
procedure (ResidualSub), pointer, intent(in) :: ResidualSub_in
this%pResidualSub => ResidualSub_in
end subroutine solver_initialise
subroutine brute_force_solution_search(this,imin,imax,isolution,iflag)
implicit none
class(gensolver) this
integer, intent(in) :: imin, imax
integer, intent(out) :: isolution, iflag
integer :: i, reslt
iflag = 1 ! flag values: 0 = no error, 1 = no solution found
do i = imin,imax
call this%pResidualSub(i,reslt)
if (reslt == 0) then
isolution = i
iflag = 0
return
end if
end do
this%niter = i
return
end subroutine brute_force_solution_search
end module solver
program main_test
use solver
implicit none
class(gensolver), allocatable :: solver_obj
integer :: isolution, iflag, kparam
procedure(ResidualSub), pointer :: evallhs
! Trying to solve f(i,kparam) == 0 but the solver only understands: g(i) == 0
! To bypass the limitation we define a locally contained function, which "knows"
! the value of kparam by its membership to "main_test"
allocate(gensolver::solver_obj)
kparam = 5
evallhs => eval_left_hand_side
call solver_obj%initialise(evallhs)
call solver_obj%find_solution(0,10,isolution,iflag)
if (iflag == 0) then
write(*,*) 'solution found:',isolution
else
write(*,*) 'no solution found'
end if
contains
subroutine eval_left_hand_side(i,lhs,solver_obj)
implicit none
class(gensolver), intent(inout) :: solver_obj
integer, intent(in) :: i
integer, intent(out) :: lhs
write(*,*) 'in eval_left_hand_side'
write(*,*) i
write(*,*) lhs
write(*,*) kparam
write(*,*) 'starting evaluation'
lhs = (i+1)*(i-kparam) ! this compiles but leads to seg-fault in AOCC;
! yet, it compiles and runs fine in GNU and Intel Fortran
! lhs = (i+1)*(i-5) ! this is fine with all 3 compilers but has kparam "hardcoded"
return
end subroutine eval_left_hand_side
end program main_test
Could you please check this and advise? Should I be doing something different or wait for the next version of the compiler?
Sample output is given below (for AOCC and GNU Fortran):
mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$ flang --version AMD clang version 12.0.0 (CLANG: AOCC_3.0.0-Build#78 2020_12_10) (based on LLVM Mirror.Version.12.0.0) Target: x86_64-unknown-linux-gnu Thread model: posix InstalledDir: /opt/AMD/aocc-compiler-3.0.0/bin mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$ flang Solver_ContainedFunctions_v2_FAILS_W_AOCC3.f90 mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$ ./a.out in eval_left_hand_side 0 32535 Segmentation fault (core dumped) mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$ flang Solver_ContainedFunctions_v3_FAILS_W_AOCC3.f90 mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$ ./a.out in eval_left_hand_side 0 0 Segmentation fault (core dumped) mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$ gfortran --version GNU Fortran (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$ gfortran Solver_ContainedFunctions_v2_FAILS_W_AOCC3.f90 mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$ ./a.out in eval_left_hand_side 0 -1000557868 5 starting evaluation in eval_left_hand_side 1 -5 5 starting evaluation in eval_left_hand_side 2 -8 5 starting evaluation in eval_left_hand_side 3 -9 5 starting evaluation in eval_left_hand_side 4 -8 5 starting evaluation in eval_left_hand_side 5 -5 5 starting evaluation solution found: 5 mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$ gfortran Solver_ContainedFunctions_v3_FAILS_W_AOCC3.f90 mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$ ./a.out in eval_left_hand_side 0 -1971522860 5 starting evaluation in eval_left_hand_side 1 -5 5 starting evaluation in eval_left_hand_side 2 -8 5 starting evaluation in eval_left_hand_side 3 -9 5 starting evaluation in eval_left_hand_side 4 -8 5 starting evaluation in eval_left_hand_side 5 -5 5 starting evaluation solution found: 5 mich@machine:~/Desktop/CodingExamples/Fortran/AMD_AOCC$
Thanks!
Hello, I was wondering whether there was any development activity to try and address this issue...
You should probably be posting in the Server Gurus section.