[llvm] 7fa2045 - [LoopTerminology] Rotated Loops

Michael Kruse via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 17 08:38:01 PDT 2020


When committing, please add a "Differential Revision" line and a
description (typically the summary from Phabricator) to the commit
log. For this commit, it would have been:

Differential Revision: https://reviews.llvm.org/D75013

The line is parsed by Phabricator and will close the Review automatically.

Michael


Am Mo., 16. März 2020 um 17:56 Uhr schrieb Stefanos Baziotis via
llvm-commits <llvm-commits at lists.llvm.org>:
>
>
> Author: Stefanos Baziotis
> Date: 2020-03-17T00:54:26+02:00
> New Revision: 7fa204580dfeb447f8da4d7da482c187b851914f
>
> URL: https://github.com/llvm/llvm-project/commit/7fa204580dfeb447f8da4d7da482c187b851914f
> DIFF: https://github.com/llvm/llvm-project/commit/7fa204580dfeb447f8da4d7da482c187b851914f.diff
>
> LOG: [LoopTerminology] Rotated Loops
>
> Added:
>
>
> Modified:
>     llvm/docs/LoopTerminology.rst
>     llvm/docs/Passes.rst
>
> Removed:
>
>
>
> ################################################################################
> diff  --git a/llvm/docs/LoopTerminology.rst b/llvm/docs/LoopTerminology.rst
> index 207195ef79e2..b3822e638d4c 100644
> --- a/llvm/docs/LoopTerminology.rst
> +++ b/llvm/docs/LoopTerminology.rst
> @@ -170,4 +170,226 @@ TBD
>  "More Canonical" Loops
>  ======================
>
> -TBD
> +.. _loop-terminology-loop-rotate:
> +
> +Rotated Loops
> +-------------
> +
> +Loops are rotated by the LoopRotate (:ref:`loop-rotate <passes-loop-rotate>`)
> +pass, which converts loops into do/while style loops and is
> +implemented in
> +`LoopRotation.h <http://llvm.org/doxygen/LoopRotation_8h_source.html>`_.  Example:
> +
> +.. code-block:: C
> +
> +  void test(int n) {
> +    for (int i = 0; i < n; i += 1)
> +      // Loop body
> +  }
> +
> +is transformed to:
> +
> +.. code-block:: C
> +
> +  void test(int n) {
> +    int i = 0;
> +    do {
> +      // Loop body
> +      i += 1;
> +    } while (i < n);
> +  }
> +
> +**Warning**: This transformation is valid only if the compiler
> +can prove that the loop body will be executed at least once. Otherwise,
> +it has to insert a guard which will test it at runtime. In the example
> +above, that would be:
> +
> +.. code-block:: C
> +
> +  void test(int n) {
> +    int i = 0;
> +    if (n > 0) {
> +      do {
> +        // Loop body
> +        i += 1;
> +      } while (i < n);
> +    }
> +  }
> +
> +It's important to understand the effect of loop rotation
> +at the LLVM IR level. We follow with the previous examples
> +in LLVM IR while also providing a graphical representation
> +of the control-flow graphs (CFG). You can get the same graphical
> +results by utilizing the `view-cfg <passes-view-cfg>` pass.
> +
> +The initial **for** loop could be translated to:
> +
> +.. code-block:: none
> +
> +  define void @test(i32 %n) {
> +  entry:
> +    br label %for.header
> +
> +  for.header:
> +    %i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
> +    %cond = icmp slt i32 %i, %n
> +    br i1 %cond, label %body, label %exit
> +
> +  body:
> +    ; Loop body
> +    br label %latch
> +
> +  latch:
> +    %i.next = add nsw i32 %i, 1
> +    br label %for.header
> +
> +  exit:
> +    ret void
> +  }
> +
> +.. image:: ./loop-terminology-initial-loop.png
> +  :width: 400 px
> +
> +Before we explain how LoopRotate will actually
> +transform this loop, here's how we could convert
> +it (by hand) to a do-while style loop.
> +
> +.. code-block:: none
> +
> +  define void @test(i32 %n) {
> +  entry:
> +    br label %body
> +
> +  body:
> +    %i = phi i32 [ 0, %entry ], [ %i.next, %latch ]
> +    ; Loop body
> +    br label %latch
> +
> +  latch:
> +    %i.next = add nsw i32 %i, 1
> +    %cond = icmp slt i32 %i.next, %n
> +    br i1 %cond, label %body, label %exit
> +
> +  exit:
> +    ret void
> +  }
> +
> +.. image:: ./loop-terminology-rotated-loop.png
> +  :width: 400 px
> +
> +Note a two things:
> +
> +* The condition check was moved to the "bottom" of the loop, i.e.
> +  the latch. This is something that LoopRotate does by copying the header
> +  of the loop to the latch.
> +* The compiler in this case can't deduce that the loop will
> +  definitely execute at least once so the above transformation
> +  is not valid. As mentioned above, a guard has to be inserted,
> +  which is something that LoopRotate will do.
> +
> +This is how LoopRotate transforms this loop:
> +
> +.. code-block:: none
> +
> +  define void @test(i32 %n) {
> +  entry:
> +    %guard_cond = icmp slt i32 0, %n
> +    br i1 %guard_cond, label %loop.preheader, label %exit
> +
> +  loop.preheader:
> +    br label %body
> +
> +  body:
> +    %i2 = phi i32 [ 0, %loop.preheader ], [ %i.next, %latch ]
> +    br label %latch
> +
> +  latch:
> +    %i.next = add nsw i32 %i2, 1
> +    %cond = icmp slt i32 %i.next, %n
> +    br i1 %cond, label %body, label %loop.exit
> +
> +  loop.exit:
> +    br label %exit
> +
> +  exit:
> +    ret void
> +  }
> +
> +.. image:: ./loop-terminology-guarded-loop.png
> +  :width: 500 px
> +
> +The result is a little bit more complicated than we may expect
> +because LoopRotate ensures that the loop is in
> +`Loop Simplify Form <loop-terminology-loop-simplify>`
> +after rotation.
> +In this case, it inserted the %loop.preheader basic block so
> +that the loop has a preheader and it introduced the %loop.exit
> +basic block so that the loop has dedicated exits
> +(otherwise, %exit would be jumped from both %latch and %entry,
> +but %entry is not contained in the loop).
> +Note that a loop has to be in Loop Simplify Form beforehand
> +too for LoopRotate to be applied successfully.
> +
> +The main advantage of this form is that it allows hoisting
> +invariant instructions, especially loads, into the preheader.
> +That could be done in non-rotated loops as well but with
> +some disadvantages.  Let's illustrate them with an example:
> +
> +.. code-block:: C
> +
> +  for (int i = 0; i < n; ++i) {
> +    auto v = *p;
> +    use(v);
> +  }
> +
> +We assume that loading from p is invariant and use(v) is some
> +statement that uses v.
> +If we wanted to execute the load only once we could move it
> +"out" of the loop body, resulting in this:
> +
> +.. code-block:: C
> +
> +  auto v = *p;
> +  for (int i = 0; i < n; ++i) {
> +    use(v);
> +  }
> +
> +However, now, in the case that n <= 0, in the initial form,
> +the loop body would never execute, and so, the load would
> +never execute.  This is a problem mainly for semantic reasons.
> +Consider the case in which n <= 0 and loading from p is invalid.
> +In the initial program there would be no error.  However, with this
> +transformation we would introduce one, effectively breaking
> +the initial semantics.
> +
> +To avoid both of these problems, we can insert a guard:
> +
> +.. code-block:: C
> +
> +  if (n > 0) {  // loop guard
> +    auto v = *p;
> +    for (int i = 0; i < n; ++i) {
> +      use(v);
> +    }
> +  }
> +
> +This is certainly better but it could be improved slightly. Notice
> +that the check for whether n is bigger than 0 is executed twice (and
> +n does not change in between).  Once when we check the guard condition
> +and once in the first execution of the loop.  To avoid that, we could
> +do an unconditional first execution and insert the loop condition
> +in the end. This effectively means transforming the loop into a do-while loop:
> +
> +.. code-block:: C
> +
> +  if (0 < n) {
> +    auto v = *p;
> +    do {
> +      use(v);
> +      ++i;
> +    } while (i < n);
> +  }
> +
> +Note that LoopRotate does not generally do such
> +hoisting.  Rather, it is an enabling transformation for other
> +passes like Loop-Invariant Code Motion (:ref:`-licm <passes-licm>`).
>
> diff  --git a/llvm/docs/Passes.rst b/llvm/docs/Passes.rst
> index a13f1e6694ca..39451a915ee4 100644
> --- a/llvm/docs/Passes.rst
> +++ b/llvm/docs/Passes.rst
> @@ -798,10 +798,14 @@ accomplished by creating a new value to hold the initial value of the array
>  access for the first iteration, and then creating a new GEP instruction in the
>  loop to increment the value by the appropriate amount.
>
> +.. _passes-loop-rotate:
> +
>  ``-loop-rotate``: Rotate Loops
>  ------------------------------
>
> -A simple loop rotation transformation.
> +A simple loop rotation transformation.  A summary of it can be found in
> +:ref:`Loop Terminology for Rotated Loops <loop-terminology-loop-rotate>`.
> +
>
>  .. _passes-loop-simplify:
>
> @@ -1194,6 +1198,8 @@ performing optimizing transformations.
>  Note that this does not provide full security verification (like Java), but
>  instead just tries to ensure that code is well-formed.
>
> +.. _passes-view-cfg:
> +
>  ``-view-cfg``: View CFG of function
>  -----------------------------------
>
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list