Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[from discourse] Wrong understanding of the rules for lbound and ubound for non-pointer dummy arguments #1435

Open
pawosm-arm opened this issue Jan 13, 2024 · 7 comments

Comments

@pawosm-arm
Copy link
Collaborator

This issue was signaled on discourse as such: https://fortran-lang.discourse.group/t/an-interesting-difference-between-compilers/7131

There is also a reproducer initially written for AOCC, but since AOCC is based on classic flang, it can also be reproduced with it:

program aocc_run_test
  implicit none
  real :: arr_in1(0:10, 2:5), arr1(0:10,2:5)
  real :: arr_in2(0:10, 2:5), arr2(0:10,2:5)
  real :: arr_in3(0:10, 2:5), arr3(0:10,2:5)
  integer  i, j
  do i=0,10 
  do j=2,5
    arr_in1(i,j) = 1000*i+j
    arr_in2(i,j) = 1000*i+j
    arr_in3(i,j) = 1000*i+j
  end do
  end do

  call evaluate(arr_in1,arr_in2,arr_in3,arr1,arr2,arr3)
contains

  function justcopy(arr_in) 
   real, intent(in) :: arr_in(0:,:)
   real :: justcopy(0:ubound(arr_in,dim=1), 2:5)  !This works for "A" GNU,Intel/InteLLVM,lfortran,NAG,IBM. Does not work for "B" AOCC, NVidia, ARM.
!   real :: justcopy(0:size(arr_in,dim=1)-1, 2:5) !This works for all compilers
   write(*,*)lbound(arr_in,dim=1),ubound(arr_in,dim=1),size(arr_in,1)
   write(*,*)lbound(arr_in,dim=2),ubound(arr_in,dim=2),size(arr_in,2)
   write(*,*)lbound(justcopy,dim=1),ubound(justcopy,dim=1),size(justcopy,1)
   justcopy=arr_in
   write(*,*)lbound(justcopy,dim=1),ubound(justcopy,dim=1),size(justcopy,1)
  end function justcopy
  
  subroutine evaluate(arr_in1,arr_in2,arr_in3,arr_out1,arr_out2,arr_out3)
    real,    intent(in)  :: arr_in1(:,:)
    real,    intent(in)  :: arr_in2(:,:)
    real,    intent(in)  :: arr_in3(:,:)
    real,    intent(out) :: arr_out1(:,:)
    real,    intent(out) :: arr_out2(:,:)
    real,    intent(out) :: arr_out3(:,:)
    real, allocatable  :: X(:,:)

    arr_out1 = justcopy(arr_in1)
    X = justcopy(arr_in2)       
    arr_out2 = X
    arr_out3 = 1.0*justcopy(arr_in3)

    write(*,*)"X--       ", lbound(X), ubound(X),size(X,1) !This line is different for "A" and "B" compilers with "ubound"
    write(*,*)X
    write(*,*)"arr_out1--", lbound(arr_out1), ubound(arr_out1),size(arr_out1,1)
    write(*,*)arr_out1
    write(*,*)"arr_out2--", lbound(arr_out2), ubound(arr_out2),size(arr_out2,1)
    write(*,*)arr_out2
    write(*,*)"arr_out3--", lbound(arr_out3), ubound(arr_out3),size(arr_out3,1)
    write(*,*)arr_out3
    !With ubound arr_out3=arr_out2 != arr_out1 != X
  end subroutine evaluate  
end program aocc_run_test

Note that the most recent changes to LBOUND/UBOUND in classic flang did not improve the reported behavior.

@bryanpkc
Copy link
Collaborator

@wanbinchen-hnc Would you be able to take a look at this issue?

@wanbinchen-hnc
Copy link
Contributor

IMHO, this difference is an undefined behavior.
As mentioned in paragraph 1 of section 12.3.3 of the Fortran 2008 standard,
the characteristics of the function results include the shape, but not the lower bound.

In addition, as mentioned in paragraph 3 of section 7.2.1.3 of the Fortran 2008 standard,
an allocatable assignment will result in the unallocated LHS having the same shape and lower bounds as the RHS.
For the following testcase,

program main
  print *, lbound(foo()), ubound(foo()), shape(foo())
contains
  function foo()
    integer :: foo(0:10, 2:5)
  end function
end program

gfortran outputs: 1 1 11 4 11 4
flang outputs: 0 2 10 5 11 4
It seems that gfortran normalizes the lower bound of the function result while flang makes no changes.

@pawosm-arm
Copy link
Collaborator Author

Eventually, we'd contacted the Fortran committee and the response was that there is no undefined behaviour here, quite contrary, the behavior is well-defined as per J3/10-007r1 (Fortran 2008). The subclause 7.2.1.3 paragraph 3 states the array is allocated with o if /expr/ is an array, the shape of the /expr/ with each lower bound equal to the corresponding element of LBOUND(/expr/). The subclause 13.7.90 (LBOUND) says that in this case, the lower bounds have the value 1.

@bryanpkc
Copy link
Collaborator

@pawosm-arm Section 13.7.90 on LBOUND states the following for its result value:

If ARRAY is a whole array and either ARRAY is an assumed-size array of rank DIM or dimension DIM of ARRAY has nonzero extent, LBOUND(ARRAY, DIM) has a value equal to the lower bound for subscript DIM of ARRAY. Otherwise the result value is 1.

Could you explain why, in the example programs above, arr_in1 (as defined in the main program and passed into evaluate) or foo() should not be considered whole arrays?

@shivaramaarao
Copy link
Collaborator

There is a comment from Robert Corbett on this issue.

https://mailman.j3-fortran.org/pipermail/j3/2024-July/014788.html

@bryanpkc
Copy link
Collaborator

@shivaramaarao Thanks for the link! That clears it up really well.

@bryanpkc
Copy link
Collaborator

@wanbinchen-hnc Do you have any time to consider this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants