https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118896

            Bug ID: 118896
           Summary: The fortran compiler is unable to devirtualize
                    typebound indirect calls
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: fortran
          Assignee: unassigned at gcc dot gnu.org
          Reporter: mikael at gcc dot gnu.org
  Target Milestone: ---

With the following example (which is a simplified class_assign_4.f90 from the
testsuite), I can see in the -O2 .optimized dump:

  <bb 4> [local count: 79480924]:
  ...
  _223 = MEM[(struct __vtype_m_T1 * {ref-all})&__vtab_m_T1]._copy;
  ...
  _223 (_231, _228);
  ...

all this in the same basic block.
The compiler should obviously be able to simplify the indirect call to a direct
call, but it is unfortunately not the case.  In this case the copy function is
a simple integral copy, so devirtualizing and inlining the devirtualized
function would have an important cascading effect to simplify the finally
generated code.

Testcase:

module m
  implicit none
  type :: t1
    integer :: i
  CONTAINS
  end type
  type, extends(t1) :: t2
    real :: r
  end type

end module m

subroutine test_t1
  use m
  implicit none

  class(t1), dimension(:), allocatable :: x, y

  x = [t1(3), t1(2), t1(1)]

  x = realloc_t1 (x)
  if (.not.check_t1 (x, [2,3,1], 1) ) stop 3

contains

  function realloc_t1 (arg) result (res)
    class(t1), dimension(:), allocatable :: arg
    class(t1), dimension(:), allocatable :: res
    select type (arg)
      type is (t2)
        allocate (res, source = [t1 (arg(3)%i), t1 (arg(2)%i), t1 (arg(1)%i)])
      type is (t1)
        allocate (res, source = [t1 (arg(2)%i), t1 (arg(1)%i), t1 (arg(3)%i)])
    end select
  end function realloc_t1

  logical function check_t1 (arg, array, t, array2)
    class(t1) :: arg(:)
    integer :: array (:), t
    integer, optional :: array2(:)
    check_t1 = .true.
    select type (arg)
    type is (t1)
      if (any (arg%i .ne. array)) check_t1 = .false.
      if (t .eq. 2) check_t1 = .false.
    type is (t2)
      if (any (arg%i .ne. array)) check_t1 = .false.
      if (t .eq. 1) check_t1 = .false.
      if (present (array2)) then
        if (any(int (arg%r) .ne. array2)) check_t1 = .false.
      end if
    class default
      check_t1 = .false.
    end select
  end function check_t1

end subroutine test_t1

  call test_t1
end

Reply via email to