trans.c (Loop_Statement_to_gnu): In the case of an iteration scheme...
authorEric Botcazou <ebotcazou@adacore.com>
Sun, 25 Sep 2011 20:27:37 +0000 (20:27 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Sun, 25 Sep 2011 20:27:37 +0000 (20:27 +0000)
* gcc-interface/trans.c (Loop_Statement_to_gnu): In the case of an
iteration scheme, always generate the do-while form if optimization
is enabled.  Use more straightforward test at the end.

From-SVN: r179169

gcc/ada/ChangeLog
gcc/ada/gcc-interface/trans.c

index 34f6f1dd89d6bffcbfaab0b5b59cea330ebcf345..ac679302bf6e7a9a3c36bc958ad1b41276ef7f62 100644 (file)
@@ -1,3 +1,9 @@
+2011-09-25  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gcc-interface/trans.c (Loop_Statement_to_gnu): In the case of an
+       iteration scheme, always generate the do-while form if optimization
+       is enabled.  Use more straightforward test at the end.
+
 2011-09-25  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Access_Subtype>: Use
index 8a8fef8dc35f96ce36784baa1e1a45c5c3729300..2f41ad3309db418feac75a27a6bec8bbb7d24e3d 100644 (file)
@@ -218,6 +218,7 @@ static bool set_end_locus_from_node (tree, Node_Id);
 static void set_gnu_expr_location_from_node (tree, Node_Id);
 static int lvalue_required_p (Node_Id, tree, bool, bool, bool);
 static tree build_raise_check (int, enum exception_info_kind);
+static tree create_init_temporary (const char *, tree, tree *, Node_Id);
 
 /* Hooks for debug info back-ends, only supported and used in a restricted set
    of configurations.  */
@@ -2161,8 +2162,7 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
   tree gnu_loop_stmt = build4 (LOOP_STMT, void_type_node, NULL_TREE,
                               NULL_TREE, NULL_TREE, NULL_TREE);
   tree gnu_loop_label = create_artificial_label (input_location);
-  tree gnu_loop_var = NULL_TREE, gnu_cond_expr = NULL_TREE;
-  tree gnu_result;
+  tree gnu_cond_expr = NULL_TREE, gnu_result;
 
   /* Set location information for statement and end label.  */
   set_expr_location_from_node (gnu_loop_stmt, gnat_node);
@@ -2196,9 +2196,9 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
       tree gnu_high = TYPE_MAX_VALUE (gnu_type);
       tree gnu_base_type = get_base_type (gnu_type);
       tree gnu_one_node = convert (gnu_base_type, integer_one_node);
-      tree gnu_first, gnu_last;
+      tree gnu_loop_var, gnu_loop_iv, gnu_first, gnu_last, gnu_stmt;
       enum tree_code update_code, test_code, shift_code;
-      bool reverse = Reverse_Present (gnat_loop_spec), fallback = false;
+      bool reverse = Reverse_Present (gnat_loop_spec), use_iv = false;
 
       /* We must disable modulo reduction for the iteration variable, if any,
         in order for the loop comparison to be effective.  */
@@ -2222,8 +2222,8 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
       /* We use two different strategies to translate the loop, depending on
         whether optimization is enabled.
 
-        If it is, we try to generate the canonical form of loop expected by
-        the loop optimizer, which is the do-while form:
+        If it is, we generate the canonical loop form expected by the loop
+        optimizer and the loop vectorizer, which is the do-while form:
 
             ENTRY_COND
           loop:
@@ -2232,10 +2232,12 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
             BOTTOM_COND
             GOTO loop
 
-        This makes it possible to bypass loop header copying and to turn the
-        BOTTOM_COND into an inequality test.  This should catch (almost) all
-        loops with constant starting point.  If we cannot, we try to generate
-        the default form, which is:
+        This avoids an implicit dependency on loop header copying and makes
+        it possible to turn BOTTOM_COND into an inequality test.
+
+        If optimization is disabled, loop header copying doesn't come into
+        play and we try to generate the loop form with the fewer conditional
+        branches.  First, the default form, which is:
 
           loop:
             TOP_COND
@@ -2243,53 +2245,54 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
             BOTTOM_UPDATE
             GOTO loop
 
-        It will be rotated during loop header copying and an entry test added
-        to yield the do-while form.  This should catch (almost) all loops with
-        constant ending point.  If we cannot, we generate the fallback form:
+        It should catch most loops with constant ending point.  Then, if we
+        cannot, we try to generate the shifted form:
 
-            ENTRY_COND
           loop:
+            TOP_COND
+            TOP_UPDATE
             BODY
-            BOTTOM_COND
-            BOTTOM_UPDATE
             GOTO loop
 
-        which works in all cases but for which loop header copying will copy
-        the BOTTOM_COND, thus adding a third conditional branch.
-
-        If optimization is disabled, loop header copying doesn't come into
-        play and we try to generate the loop forms with the less conditional
-        branches directly.  First, the default form, it should catch (almost)
-        all loops with constant ending point.  Then, if we cannot, we try to
-        generate the shifted form:
+        which should catch loops with constant starting point.  Otherwise, if
+        we cannot, we generate the fallback form:
 
+            ENTRY_COND
           loop:
-            TOP_COND
-            TOP_UPDATE
             BODY
+            BOTTOM_COND
+            BOTTOM_UPDATE
             GOTO loop
 
-        which should catch loops with constant starting point.  Otherwise, if
-        we cannot, we generate the fallback form.  */
+        which works in all cases.  */
 
       if (optimize)
        {
-         /* We can use the do-while form if GNU_FIRST-1 doesn't overflow.  */
+         /* We can use the do-while form directly if GNU_FIRST-1 doesn't
+            overflow.  */
          if (!can_equal_min_val_p (gnu_first, gnu_base_type, reverse))
-           {
-             gnu_first = build_binary_op (shift_code, gnu_base_type,
-                                          gnu_first, gnu_one_node);
-             LOOP_STMT_TOP_UPDATE_P (gnu_loop_stmt) = 1;
-             LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt) = 1;
-           }
-
-         /* Otherwise, we can use the default form if GNU_LAST+1 doesn't.  */
-         else if (!can_equal_max_val_p (gnu_last, gnu_base_type, reverse))
            ;
 
-         /* Otherwise, use the fallback form.  */
+         /* Otherwise, use the do-while form with the help of a special
+            induction variable in the (unsigned version of) the base
+            type, in order to have wrap-around arithmetics for it.  */
          else
-           fallback = true;
+           {
+             if (!TYPE_UNSIGNED (gnu_base_type))
+               {
+                 gnu_base_type = gnat_unsigned_type (gnu_base_type);
+                 gnu_first = convert (gnu_base_type, gnu_first);
+                 gnu_last = convert (gnu_base_type, gnu_last);
+                 gnu_one_node = convert (gnu_base_type, integer_one_node);
+               }
+             use_iv = true;
+           }
+
+         gnu_first
+           = build_binary_op (shift_code, gnu_base_type, gnu_first,
+                              gnu_one_node);
+         LOOP_STMT_TOP_UPDATE_P (gnu_loop_stmt) = 1;
+         LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt) = 1;
        }
       else
        {
@@ -2302,21 +2305,20 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
          else if (!can_equal_min_val_p (gnu_first, gnu_base_type, reverse)
                   && !can_equal_min_val_p (gnu_last, gnu_base_type, reverse))
            {
-             gnu_first = build_binary_op (shift_code, gnu_base_type,
-                                          gnu_first, gnu_one_node);
-             gnu_last = build_binary_op (shift_code, gnu_base_type,
-                                         gnu_last, gnu_one_node);
+             gnu_first
+               = build_binary_op (shift_code, gnu_base_type, gnu_first,
+                                  gnu_one_node);
+             gnu_last
+               = build_binary_op (shift_code, gnu_base_type, gnu_last,
+                                  gnu_one_node);
              LOOP_STMT_TOP_UPDATE_P (gnu_loop_stmt) = 1;
            }
 
          /* Otherwise, use the fallback form.  */
          else
-           fallback = true;
+           LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt) = 1;
        }
 
-      if (fallback)
-       LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt) = 1;
-
       /* If we use the BOTTOM_COND, we can turn the test into an inequality
         test but we may have to add ENTRY_COND to protect the empty loop.  */
       if (LOOP_STMT_BOTTOM_COND_P (gnu_loop_stmt))
@@ -2338,6 +2340,19 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
       start_stmt_group ();
       gnat_pushlevel ();
 
+      /* If we use the special induction variable, create it and set it to
+        its initial value.  Morever, the regular iteration variable cannot
+        itself be initialized, lest the initial value wrapped around.  */
+      if (use_iv)
+       {
+         gnu_loop_iv
+           = create_init_temporary ("I", gnu_first, &gnu_stmt, gnat_loop_var);
+         add_stmt (gnu_stmt);
+         gnu_first = NULL_TREE;
+       }
+      else
+       gnu_loop_iv = NULL_TREE;
+
       /* Declare the iteration variable and set it to its initial value.  */
       gnu_loop_var = gnat_to_gnu_entity (gnat_loop_var, gnu_first, 1);
       if (DECL_BY_REF_P (gnu_loop_var))
@@ -2347,18 +2362,42 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
       gnu_loop_var = convert (gnu_base_type, gnu_loop_var);
 
       /* Set either the top or bottom exit condition.  */
-      LOOP_STMT_COND (gnu_loop_stmt)
-       = build_binary_op (test_code, boolean_type_node, gnu_loop_var,
-                          gnu_last);
+      if (use_iv)
+        LOOP_STMT_COND (gnu_loop_stmt)
+         = build_binary_op (test_code, boolean_type_node, gnu_loop_iv,
+                            gnu_last);
+      else
+        LOOP_STMT_COND (gnu_loop_stmt)
+         = build_binary_op (test_code, boolean_type_node, gnu_loop_var,
+                            gnu_last);
 
       /* Set either the top or bottom update statement and give it the source
         location of the iteration for better coverage info.  */
-      LOOP_STMT_UPDATE (gnu_loop_stmt)
-       = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_loop_var,
-                          build_binary_op (update_code, gnu_base_type,
-                                           gnu_loop_var, gnu_one_node));
-      set_expr_location_from_node (LOOP_STMT_UPDATE (gnu_loop_stmt),
-                                  gnat_iter_scheme);
+      if (use_iv)
+       {
+         gnu_stmt
+           = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_loop_iv,
+                              build_binary_op (update_code, gnu_base_type,
+                                               gnu_loop_iv, gnu_one_node));
+         set_expr_location_from_node (gnu_stmt, gnat_iter_scheme);
+         append_to_statement_list (gnu_stmt,
+                                   &LOOP_STMT_UPDATE (gnu_loop_stmt));
+         gnu_stmt
+           = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_loop_var,
+                              gnu_loop_iv);
+         set_expr_location_from_node (gnu_stmt, gnat_iter_scheme);
+         append_to_statement_list (gnu_stmt,
+                                   &LOOP_STMT_UPDATE (gnu_loop_stmt));
+       }
+      else
+       {
+         gnu_stmt
+           = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_loop_var,
+                              build_binary_op (update_code, gnu_base_type,
+                                               gnu_loop_var, gnu_one_node));
+         set_expr_location_from_node (gnu_stmt, gnat_iter_scheme);
+         LOOP_STMT_UPDATE (gnu_loop_stmt) = gnu_stmt;
+       }
     }
 
   /* If the loop was named, have the name point to this loop.  In this case,
@@ -2372,9 +2411,9 @@ Loop_Statement_to_gnu (Node_Id gnat_node)
     = build_stmt_group (Statements (gnat_node), true);
   TREE_SIDE_EFFECTS (gnu_loop_stmt) = 1;
 
-  /* If we declared a variable, then we are in a statement group for that
-     declaration.  Add the LOOP_STMT to it and make that the "loop".  */
-  if (gnu_loop_var)
+  /* If we have an iteration scheme, then we are in a statement group.  Add
+     the LOOP_STMT to it, finish it and make it the "loop".  */
+  if (Present (gnat_iter_scheme) && No (Condition (gnat_iter_scheme)))
     {
       add_stmt (gnu_loop_stmt);
       gnat_poplevel ();