cancel
Showing results for 
Search instead for 
Did you mean: 

Drivers & Software

michstam
Journeyman III

AOCC Fortran: issue with contained functions when using classes

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!

 

 

0 Likes
2 Replies
michstam
Journeyman III

Hello, I was wondering whether there was any development activity to try and address this issue...

0 Likes

You should probably be posting in the Server Gurus section.

 

Ryzen 5 5600x, B550 aorus pro ac, Hyper 212 black, 2 x 16gb F4-3600c16dgtzn kit, Aorus gen4 1tb, Nitro+RX6900XT, RM850, Win.10 Pro., LC27G55T..
0 Likes