feat: remove insert_deallocate pass
Instead of inserting deallocate for temporary assignment targets at the exits of loops, insert a deallocate before the assignment.
After this there is no need for insert_deallocate pass, so remove it from default passes.
@assem2002 can you please also review it?
@xaerru I believe what you're targeting here is deallocating the temporary created in the array_struct_temporary pass (that pass usually add a deallocate statement, but you handling a case where the pass decides no not insert).
Can we deallocate that variable when it's first inserted? seems cleaner and more obvious?
I'll explain why this deallocate is needed:
integration_tests/do_loop_07.f90 :
program do_loop_07
integer :: i, s
do i = 1, 3
if (i == 1) then
cycle
end if
! There should be an ImplicitDeallocate for __libasr_created_string_format here
print *, new_array(i)
end do
contains
function new_array(i) result(t)
integer, intent(in) :: i
integer, allocatable :: t(:)
allocate(t(i))
t = 1
end function
end program
After --dump-all-passes-fortran:
! Fortran code after applying the pass: array_struct_temporary
program do_loop_07
implicit none
integer(4), dimension(:), allocatable :: __libasr_created_string_format
integer(4) :: i
integer(4) :: s
do i = 1, 3
if (i == 1) then
cycle
end if
__libasr_created_string_format = new_array(i)
print *, __libasr_created_string_format
end do
contains
function new_array(i) result(t)
integer(4), intent(in) :: i
integer(4), dimension(:), allocatable :: t
allocate(t(i))
t = 1
end function new_array
end program do_loop_07
! Fortran code after applying the pass: array_op
program do_loop_07
implicit none
integer(4), dimension(:), allocatable :: __libasr_created_string_format
integer(4) :: i
integer(4) :: s
do i = 1, 3
if (i == 1) then
cycle
end if
__libasr_created_string_format = new_array(i)
print *, __libasr_created_string_format
end do
contains
function new_array(i) result(t)
integer(4) :: __libasr_index_0_
integer(4), intent(in) :: i
integer(4), dimension(:), allocatable :: t
allocate(t(i))
do __libasr_index_0_ = lbound(t, 1), ubound(t, 1)
t(__libasr_index_0_) = 1
end do
end function new_array
end program do_loop_07
! Fortran code after applying the pass: subroutine_from_function
program do_loop_07
implicit none
integer(4), dimension(:), allocatable :: __libasr_created__subroutine_from_function_
integer(4), dimension(:), allocatable :: __libasr_created_string_format
integer(4) :: i
integer(4) :: s
do i = 1, 3
if (i == 1) then
cycle
end if
deallocate(__libasr_created__subroutine_from_function_) ! Implicit deallocate
call new_array(i, __libasr_created__subroutine_from_function_)
__libasr_created_string_format = __libasr_created__subroutine_from_function_
print *, __libasr_created_string_format
end do
contains
subroutine new_array(i, t)
integer(4) :: __libasr_index_0_
integer(4), intent(in) :: i
integer(4), dimension(:), allocatable, intent(out) :: t
allocate(t(i))
do __libasr_index_0_ = lbound(t, 1), ubound(t, 1)
t(__libasr_index_0_) = 1
end do
end subroutine new_array
end program do_loop_07
! Fortran code after applying the pass: array_op
program do_loop_07
implicit none
integer(4), dimension(:), allocatable :: __libasr_created__subroutine_from_function_
integer(4), dimension(:), allocatable :: __libasr_created_string_format
integer(4) :: i
integer(4) :: s
do i = 1, 3
if (i == 1) then
cycle
end if
deallocate(__libasr_created__subroutine_from_function_) ! Implicit deallocate
call new_array(i, __libasr_created__subroutine_from_function_)
deallocate(__libasr_created_string_format) ! Implicit deallocate
! CheckBounds LHS = __libasr_created_string_format, RHS = __libasr_created__subroutine_from_function_,
__libasr_created_string_format = __libasr_created__subroutine_from_function_
print *, __libasr_created_string_format
end do
contains
subroutine new_array(i, t)
integer(4) :: __libasr_index_0_
integer(4), intent(in) :: i
integer(4), dimension(:), allocatable, intent(out) :: t
allocate(t(i))
do __libasr_index_0_ = lbound(t, 1), ubound(t, 1)
t(__libasr_index_0_) = 1
end do
end subroutine new_array
end program do_loop_07
When the array_op pass is applied for the second time, the deallocate above the ! CheckBounds comment is being inserted. If it is not inserted the temporary __libasr_created_string_format would be allocated from the previous loop iteration and CheckBounds will fail when it shouldn't.
Can we deallocate that variable when it's first inserted? seems cleaner and more obvious?
We can try it, need to figure out the conditions.
I think the implicit deallocate only deallocates if it is allocated. The regular deallocate would give an error (at least it should in our Debug mode).
So this is only needed in a for loop? And it happens only in a for loop? If so, then I think that's fine. The alternative design is to call deallocate at the end of the for loop. But I think for now this is fine.
So this is only needed in a for loop? And it happens only in a for loop?
@xaerru please let me know the answers. So that we can get it merged.
So this is only needed in a for loop? And it happens only in a for loop? If so, then I think that's fine. The alternative design is to call deallocate at the end of the for loop. But I think for now this is fine.
This will insert it even if the assignment is not in a loop.
The deallocation at the end or exit of the loop was implemented in insert_deallocate with LoopTempVarDeallocateVisitor. This PR is disabling that pass and inserting the deallocation before the assignment for simplicity.
This will insert it even if the assignment is not in a loop.
So now before every assignment we insert a deallocate check?
If so, that would negate the work we have been working so hard to achieve, which is no checks like this in Release mode.
A solution is to keep the original visitor from insert_deallocate which adds deallocate to the end of the loop and move it to do_loops pass.
Ok, let's keep this PR as a draft for now.