[llvm] 7fa2045 - [LoopTerminology] Rotated Loops
Stefanos Baziotis via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 16 15:56:00 PDT 2020
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
-----------------------------------
More information about the llvm-commits
mailing list