This is an archive of the discontinued LLVM Phabricator instance.

[Flang] Initial lowering of the Fortran Do loop
ClosedPublic

Authored by kiranchandramohan on Apr 22 2022, 10:34 AM.

Details

Summary

This patch adds code to lower simple Fortran Do loops with loop control.
Lowering is performed by the the genFIR function when called with a
Fortran::parser::DoConstruct. genFIR function calls genFIRIncrementLoopBegin
then calls functions to lower the body of the loop and finally calls
the function genFIRIncrementLoopEnd. genFIRIncrementLoopBegin is
responsible for creating the FIR do_loop as well as storing the value of
the loop index to the loop variable. genFIRIncrementLoopEnd returns
the incremented value of the loop index and also stores the index value
outside the loop. This is important since the loop variable can be used
outside the loop. Information about a loop is collected in a structure
IncrementLoopInfo.

Note 1: Future patches will bring in lowering for unstructured,
infinite, while loops
Note 2: This patch is part of upstreaming code from the fir-dev branch of
https://github.com/flang-compiler/f18-llvm-project.

Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
Co-authored-by: Jean Perier <jperier@nvidia.com>
Co-authored-by: Val Donaldson <vdonaldson@nvidia.com>
Co-authored-by: Peter Klausler <pklausler@nvidia.com>
Co-authored-by: Valentin Clement <clementval@gmail.com>

Diff Detail

Event Timeline

Herald added projects: Restricted Project, Restricted Project. · View Herald Transcript
Herald added a subscriber: mehdi_amini. · View Herald Transcript
kiranchandramohan requested review of this revision.Apr 22 2022, 10:34 AM

It's great to see do loop finally making its way into LLVM main, thanks for working on this @kiranchandramohan !

I would really appreciate if you could break the tests into smaller units. Currently, it's quite tricky to follow them. Indeed, do loop itself is quite complex and I think that it would be beneficial to keep the tests to the required minimum. For example, loop_test1 could be split into:

  • a test for a most basic do loop (i.e. just the loop),
  • a test for a nested do loop,
  • a test for do loop with accumulation that depends on the index variable.

I think that 2 nested loops should be enough, unless we know that things change when moving from 2 to 3 nested loops. Also:

  • is print ing really required in these tests? (that's adding complexity that's IMHO not really needed here)
  • why not use more descriptive names for tests?

Thank you!

flang/test/Lower/loop.f90
104 ↗(On Diff #424525)

Could you split this into seperate tests?

It's great to see do loop finally making its way into LLVM main, thanks for working on this @kiranchandramohan !

I would really appreciate if you could break the tests into smaller units. Currently, it's quite tricky to follow them. Indeed, do loop itself is quite complex and I think that it would be beneficial to keep the tests to the required minimum. For example, loop_test1 could be split into:

  • a test for a most basic do loop (i.e. just the loop),
  • a test for a nested do loop,
  • a test for do loop with accumulation that depends on the index variable.

I think that 2 nested loops should be enough, unless we know that things change when moving from 2 to 3 nested loops. Also:

  • is print ing really required in these tests? (that's adding complexity that's IMHO not really needed here)
  • why not use more descriptive names for tests?

Thank you!

I'm not sure I follow this. Kiran's patch is for the conversion of Fortran loops to FIR. It isn't about exercising FIR's DoLoopOp.

Lowering tests ought to include counted DO loops, unstructured loops, DO WHILE, DO CONCURRENT, and DO forever (modulo those already being present). If not, then some sort of justification for not lowering these Fortran constructs should be made, which is what Kiran did in his original description of the patch.

awarzynski added a comment.EditedApr 26 2022, 12:58 AM

I'm not sure I follow this. Kiran's patch is for the conversion of Fortran loops to FIR. It isn't about exercising FIR's DoLoopOp.

Sorry, it was quite late when I was typing that and perhaps could've been more specific (or used better formatting). To clarify - I meant Fortran's DO loops in all my comments.

Lowering tests ought to include counted DO loops, unstructured loops, DO WHILE, DO CONCURRENT, and DO forever (modulo those already being present). If not, then some sort of justification for not lowering these Fortran constructs should be made, which is what Kiran did in his original description of the patch.

I do believe that it's clear from the patch title and patch description that only DO loops are covered here. Which to me makes a lot of sense.

Going back to my comment, I was suggesting that the following case/test/subroutine:

subroutine loop_test1
  integer :: asum, arr(5,5,5)
  integer :: i, j, k

  do i=1,5
  end do
  print *, i

  asum = 0
  do i=1,5
    do j=1,5
      do k=1,5
        asum = asum + arr(i,j,k)
    end do
  end do
end subroutine loop_test1

is replaced with 3 more basic, isolated, minimised cases/tests (that can be separated though CHECK-LABEL):

subroutine basic_loop
  integer :: i

  do i=1,5
  end do
end subroutine basic_loop

subroutine loop_with_accumulation
  integer :: asum, arr(5)
  integer :: i, j, k

  asum = 0
  asum = asum + arr(i)
end subroutine loop_with_accumulation

subroutine nested_loop
  integer :: i, j

  do i=1,5
    do j=1,5
  end do
end subroutine loop_test1

To me, smaller tests are much easier to read, reasons about and (most importantly), triage. Apart from splitting loop_test1 into 3 subroutines, I'm also suggesting not using print and reducing the number of nested loops from 3 to 2. I'm also suggesting similar refactoring for other test subroutines in "loop.f90".

Btw, @kiranchandramohan, are you intending to use "loop.f90" for all loops or just DO loops? I would prefer multiple files, unless there is some way to split test files (akin to --split-input-file from MLIR).

Address @awarzynksi's comments regarding better tests.

Thanks @awarzynski for the review comments. The CHECK lines are mostly mechanical and I have tried to keep it all simple (all except one do not have a loop body). The pattern is something like the following, this is probably evident from the first test (simple_loop).
-> there are some constants/variables that are converted to index type. these form the start, end and step values of the loop
-> the fir.do_loop
-> store the mlir value of the index to the loop variable
-> compute the next value of the index and return or pass it to the next iteration
-> outside the loop the final/result value of the index is stored to the loop variable

It's great to see do loop finally making its way into LLVM main, thanks for working on this @kiranchandramohan !

+1. What is Fortran without a loop! And more importantly it will mean we can add support for worksharing OpenMP loop.

I would really appreciate if you could break the tests into smaller units. Currently, it's quite tricky to follow them. Indeed, do loop itself is quite complex and I think that it would be beneficial to keep the tests to the required minimum. For example, loop_test1 could be split into:

  • a test for a most basic do loop (i.e. just the loop),

Done.

  • a test for a nested do loop,
  • a test for do loop with accumulation that depends on the index variable.

This still exists as a combined one because it tests that indexing in nested loop works.

I think that 2 nested loops should be enough, unless we know that things change when moving from 2 to 3 nested loops. Also:

I was a bit conflicted about this. While 2-nested is easier to read, 3-nested seem to be in general a better test. Since it is not a strong opinion, I have changed to a 2-nested one.

  • is print ing really required in these tests? (that's adding complexity that's IMHO not really needed here)

Only one test uses a print. I needed a user outside the loop, while it could have been anything I don't really think it adds much noise.

  • why not use more descriptive names for tests?

No particular reason. I had included a comment and felt that the subroutine name would just be either replicating the same info or giving a weaker version of it.

Btw, @kiranchandramohan, are you intending to use "loop.f90" for all loops or just DO loops? I would prefer multiple files, unless there is some way to split test files (akin to --split-input-file from MLIR).

I have changed the name to do_loop.f90 and will write tests in separate files.

flang/test/Lower/loop.f90
104 ↗(On Diff #424525)

Done.

I think that 2 nested loops should be enough, unless we know that things change when moving from 2 to 3 nested loops. Also:

I was a bit conflicted about this. While 2-nested is easier to read, 3-nested seem to be in general a better test. Since it is not a strong opinion, I have changed to a 2-nested one.

I think 3 nested loops was a better test.

Btw, @kiranchandramohan, are you intending to use "loop.f90" for all loops or just DO loops? I would prefer multiple files, unless there is some way to split test files (akin to --split-input-file from MLIR).

I have changed the name to do_loop.f90 and will write tests in separate files.

I'm not against making test clearer to read but this is again changes that will make the end of upstreaming harder.

awarzynski accepted this revision.Apr 26 2022, 8:20 AM

Thanks for the updates @kiranchandramohan , the tests are so much easier to follow now!

I think 3 nested loops was a better test.

This was not a blocker for me. Since we see this differently, I suggest that Kiran decides what the final version should be.

I have changed the name to do_loop.f90 and will write tests in separate files.

I'm not against making test clearer to read but this is again changes that will make the end of upstreaming harder.

I don't quite see how. This was is not present in fir-dev anyway. Also, since we are near the end, perhaps it's OK to be a bit more relaxed?

Thanks @awarzynski for the review comments. The CHECK lines are mostly mechanical and I have tried to keep it all simple (all except one do not have a loop body). The pattern is something like the following, this is probably evident from the first test (simple_loop).
-> there are some constants/variables that are converted to index type. these form the start, end and step values of the loop
-> the fir.do_loop
-> store the mlir value of the index to the loop variable
-> compute the next value of the index and return or pass it to the next iteration
-> outside the loop the final/result value of the index is stored to the loop variable

This comment really helped me understand the tests - perhaps you could include it in the summary?

I've left a few nits, but feel free to ignore. LGTM, thanks!

flang/lib/Lower/Bridge.cpp
617–619

[nit]

flang/test/Lower/do_loop.f90
109
118

[nit]

This revision is now accepted and ready to land.Apr 26 2022, 8:20 AM
clementval added a comment.EditedApr 26 2022, 8:24 AM

I have changed the name to do_loop.f90 and will write tests in separate files.

I'm not against making test clearer to read but this is again changes that will make the end of upstreaming harder.

I don't quite see how. This was is not present in fir-dev anyway. Also, since we are near the end, perhaps it's OK to be a bit more relaxed?

These tests were present in fir-dev in their initial form. Near the end is exactly where it becomes harder to be sure everything is upstreamed if there is lots of noise in the diffs.

I have changed the name to do_loop.f90 and will write tests in separate files.

I'm not against making test clearer to read but this is again changes that will make the end of upstreaming harder.

I don't quite see how. This was is not present in fir-dev anyway. Also, since we are near the end, perhaps it's OK to be a bit more relaxed?

These tests were present in fir-dev in their initial form. Near the end is exactly where it becomes harder to be sure everything is upstreamed if there is lots of noise in the diffs.

+1.

Upstreaming isn't done and it seems self-defeating if the community doesn't at least try to make upstreaming the last pieces go smoothly.

These tests were present in fir-dev in their initial form. Near the end is exactly where it becomes harder to be sure everything is upstreamed if there is lots of noise in the diffs.

Hm, there's neither "loop.f90" nor "do_loop.f90" in fir-dev, so I assumed that there were no tests for this. Now I see that there's loops.f90 and loops2.f90, but it seems that tests added by Kiran were written from scratch.

I have no problem in relevant tests from "loops.f90" and "loops2.f90" being copied across so that we keep the diff clean.

Upstreaming isn't done and it seems self-defeating if the community doesn't at least try to make upstreaming the last pieces go smoothly.

This comment is unjustified. A lot of effort has gone into and is still being devoted to the upstreaming process. If you do see an omission being made, please assume that it is not intentional.

@clementval @schweitz Plan is to upstream the loop as a sequence of patches (if possible without code changes). Since the first patch (this one) only brings in a simple loop, the tests in fir-dev were not directly applicable and I decided to write a new one. Since it is a new test file, its name and contents do not matter much.
Once the loop is completely upstreamed, I will upstream all the remaining loop tests if they did not make it along with the code patches.

@clementval @schweitz Plan is to upstream the loop as a sequence of patches (if possible without code changes). Since the first patch (this one) only brings in a simple loop, the tests in fir-dev were not directly applicable and I decided to write a new one. Since it is a new test file, its name and contents do not matter much.
Once the loop is completely upstreamed, I will upstream all the remaining loop tests if they did not make it along with the code patches.

@kiranchandramohan Ok. It was not obvious that these tests were not extracted from loops.f90 especially the one with the sum (asum) that is very close. My comment was general about things that we upstream.

This revision was automatically updated to reflect the committed changes.
kiranchandramohan marked an inline comment as done.
kiranchandramohan marked an inline comment as done.Apr 28 2022, 6:07 AM

Changes made while submitting.

flang/test/Lower/do_loop.f90
109

In this case, I am opting for it to stay since we are checking code outside the loop body and the curly separates what is inside and outside.