<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/129812>129812</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Early exit optimization of Fortran array expressions
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          ivan-pi
      </td>
    </tr>
</table>

<pre>
    Consider a function for checking if an array is sorted:
```fortran
!
! Check an array of integers is sorted in ascending order
!
logical function is_sorted_scalar(n,a) result(is_sorted)
 integer, intent(in) :: n
    integer, intent(in) :: a(n)
    integer :: i
 !$omp simd simdlen(8) early_exit
    do i = 2, n
        if (a(i) < a(i-1)) then
            is_sorted = .false.
            return
 end if
    end do
    is_sorted = .true.
end function

logical function is_sorted_all(n,a) result(is_sorted)
    integer, intent(in) :: n
 integer, intent(in) :: a(n)
    is_sorted = all(a(2:n) >= a(1:n-1))
end function

program benchmark

    implicit none
    integer, allocatable :: a(:)

    integer :: i, n

    external :: is_sorted_scalar
 external :: is_sorted_all

    logical :: is_sorted_scalar
    logical :: is_sorted_all

    character(len=32) :: str
    integer :: tmp

    tmp = 0
    n = 20000

    if (command_argument_count() > 0) then
 call get_command_argument(1,str)
        read(str,*) tmp
        if (tmp > 0) n = tmp
    end if
    print *, "n = ",  n

    allocate(a(n))

 ! Fill ascending numbers
    do i = 1, n
        a(i) = i
    end do

 ! Introduce an unsorted value
    a(100) = 1001
    !a(101) = 1000

 call measure(100000,a,is_sorted_scalar,"scalar")
    call measure(100000,a,is_sorted_all,   "all")

contains

    impure subroutine measure(nreps,a,func,name)
        integer, intent(in) :: nreps
 integer, intent(in) :: a(:)
        logical :: func
 character(len=*), intent(in) :: name
        integer(8) :: t1, t2, rate
 real(kind(1.0d0)) :: elapsed
        logical :: res

 character(len=12) :: str

        integer :: k
        call system_clock(t1)
        do k = 1, nreps
            res = func(size(a),a)
        end do
        call system_clock(t2,rate)

 elapsed = (t2 - t1)/real(rate,kind(elapsed))

        str = adjustl(name)
        print '(A12,F12.4,L2)', str, elapsed/nreps*1.e6, res

        ! Time is in microseconds

    end subroutine

end program
```

It appears to me that in `is_sorted_all` flang generates a temporary array for the `a(2:n) >= a(1:n-1)` expression, and then performs the `all` reduction. This is fast due to vectorization, but it missed the chance of early exit. 

The effect is noticeable in the runtime:
```
~/fortran/is_sorted$ make FC=flang-new FFLAGS="-O2 -march=native" standalone
flang-new -O2 -march=native -o standalone standalone.f90
~/fortran/is_sorted$ ./standalone 
 n =  20000
scalar 0.0673 F
all               1.7358 F
~/fortran/is_sorted$ make clean
rm -rf *.o benchmark standalone
~/fortran/is_sorted$ make FC=gfortran FFLAGS="-O2 -march=native" standalone
gfortran -O2 -march=native -o standalone standalone.f90
~/fortran/is_sorted$ ./standalone 
 n = 20000
scalar            0.0389 F
all               0.0390 F
```

It would be nice if early exit vectorization were also supported (https://discourse.llvm.org/t/rfc-supporting-more-early-exit-loops/84690). With x86 SIMD extensions this still has to be done manually it seems: http://0x80.pl/notesen/2018-04-11-simd-is-sorted.html
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJy8V81u4zgSfhr6UpBAUbYjH3zwOuNFA7PYwzSwx4CmSjYnFCmQVLozh332RVGSLSWd7uxlgkZaUf3wY1V9VSUZgr5YxD3b_INtHleyj1fn9_pF2qzTq7OrX_dHZ4Ou0YOEprcqamehcR7UFdWzthfQDUgL0nv5CjpAcD5izcoD4we25cO_xvnopaVXohh-w5Ec3E1dA9pGvKAPdzegLcig0NZ0kvM1-psP4y5aSXNHpcPTYPUUlDTSM1FZJo6SiR14DL2JTFQ3JSZ2jB-mM5k4pkebdCyZ0BXKAxBoAPi1ohzO2y31J6mm1wRcrF3bQdBtnX4ZtExUFflB6c3rE37XcXRRO9DAykcQdOoEJDlvgImKTtQDgmM6XmcFARA7iFec6yeb6ebJZd5IEzB_o-Mx9j4Zoq1BN6OY_qjddLGln-j75IZ0plRQjn6aIGnMp7LzmbjbT6XxbXYWlxjgkIpg5WE0-y1JmKgKejdF9oc37by7eNnCGa26ttI_D6_TQW1ntNIRrLP4_krSGKdklGeDc6T0mM76qJjGepjy8z2it9Lc5G-ZQAn9UIduf3M1Je0nnn6mtfClrtJLFemmFdV5-ViKWUpC9D--Xmy7u5PYdilHfPzbDozgnPNZfBIflGtbaesn6S99izY-KdenShgTCnxODSWNgQuS1tIspVwcCd6tXgZyyJqJKr0_MnFIzhLUJS0HxONpA9y72oJXndc2QnJ1BCbEoMxE4vs8wWOZ4Fil9laLY1eBkzZm1ilt357Rh7d9pHjbR2Yd5HFoUXO2T86_2Ohd3Sukbt3bkTgv0vRTRSeacD55KjgvRgkTxSAsZsIpcykFLcrQexw8kCw1heP7bn5kQkzP4p6azzlJFD8mQCI9i1sAlbNRahsWpO09QujP3vVRW5z5tx67MLqnLsDE0coWl6Xy66aVvHy2cd3aweT_Df8SDornO8INZfoTHAT9B7iraqYUU93EVJWeqpAfiAzUM5-1JU4UOa_5OHpGIzSyC1h_DNrjFPH3sIv3feI9ykn-PBOlYgivIWL7pIxTz8THYhm82sHzjA5TJhZjMCSFIb9V0H-NzNuNE2umv5iNH0Kg2KXQ3Vg7xmdkfBUFZDAgFacxuIPBcYzxFNA59cefEP0wx-o_-xDTaH1XklOveWCiOlB8j6dC5Gsmjr8nKpDgCENzuyVPnMZyPxQ5blP-MSzPpgbxVbdIS5u20GrlXUDlbD1TpCDd2TS8p3fj4JyvioPwSwTZdSh9gOigRYhXGck_2_IlqbccGiPtBS5okSIWQELEtnNe-tdxuaSFNV6RrD8x5bcc8HvnMQSa8DSlbZ3GBnToG-fbcHM2APBY92kdyOHrVaf9tZEhQt0jwX9BFZ3Xf8k4-jv3EXSEVgeqAPKlrtIqpCU4bYFAW2AOQyy-XhGwaVBFcmxd1ArTwqBtsvW9jbrFNys344f_MnGaNm9xmu1Wa2jlM8LpyMrHFLzM4jc4nX4__POP1DRE9m8BWSu9urLy0cqoX5AJASFKW0szrDJ3yx9oQ-Zm2rPHvNn9AlvOxGlmSiU0DMbb1B-mAPCcbx9KODF-IM4tf4r8odxUSfirOCiD6dvEt5B5GuGH3N13ueWlPxXTy6jxf4f0Zvg3RfRNQGc_POdltfsgtiTc8SR8z9tvrjc1nBGsVkgr0b2il0yAb-gRpAkOQt914zouqmuMXUgj78TEqdZBud4HzI15aXPnL0ycIjXJRmWjnbaXrHUes3RURkdlxjlqXKdqvd3RaMrhPzpe4Xu1hT--_Osx7cOWCE5kpg_OSCvUVaaGc0aoKVKttL005pXYGhBbggWE7waPf6943hnqlC5ioK-5k-BFlfF1VhQZfeJlOmRDLvJrbM2q3pf1rtzJFe6Lh3VRlFXJ16vrXqFoqqoqdkrKcrNrNlKW56JSD5tmLdS5Wem94GLDS77hRVms1_mu4FLuRLXZbh8KsavYmmMrtbmFaqVD6HFPskKsjDyjCeljXwjibZLSKrR5XPk9GWXn_hLYmhsdYri7iToa3P92T6Trom6nPLoGTmPdDu323j3Dqvdmv8zoRcdrf86Va5k40RHjf1nn3Z-oYqre0CNlb0T-shf_CwAA__-jqfI-">