trans-stmt.c (gfc_trans_do): Conditionally compute countm1 dependent on sign of step...
authorRichard Biener <rguenther@suse.de>
Thu, 17 Jan 2013 09:53:19 +0000 (09:53 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 17 Jan 2013 09:53:19 +0000 (09:53 +0000)
2013-01-17  Richard Biener  <rguenther@suse.de>

fortran/
* trans-stmt.c (gfc_trans_do): Conditionally compute countm1
dependent on sign of step, avoids repeated evaluation of
step sign test.  Avoid undefined overflow issues by using unsigned
arithmetic.

From-SVN: r195260

gcc/fortran/ChangeLog
gcc/fortran/trans-stmt.c

index 6477c4849b8a693462d41feb7f46ac13a803de0e..730c41b4e1fa391b3a7cc196e6f2c48b8cd39c30 100644 (file)
@@ -1,3 +1,10 @@
+2013-01-17  Richard Biener  <rguenther@suse.de>
+
+       * trans-stmt.c (gfc_trans_do): Conditionally compute countm1
+       dependent on sign of step, avoids repeated evaluation of
+       step sign test.  Avoid undefined overflow issues by using unsigned
+       arithmetic.
+
 2013-01-16  Janus Weil  <janus@gcc.gnu.org>
 
        PR fortran/55983
index 1d240cb7ef5114d0c30b899c9d0c0cb04ded6d4d..14c37f715709d5d67c2527363b9a186ca380b4a9 100644 (file)
@@ -1543,7 +1543,6 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
   tree cycle_label;
   tree exit_label;
   tree tmp;
-  tree pos_step;
   stmtblock_t block;
   stmtblock_t body;
   location_t loc;
@@ -1588,8 +1587,6 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
        || tree_int_cst_equal (step, integer_minus_one_node)))
     return gfc_trans_simple_do (code, &block, dovar, from, to, step, exit_cond);
 
-  pos_step = fold_build2_loc (loc, GT_EXPR, boolean_type_node, step,
-                             build_zero_cst (type));
 
   if (TREE_CODE (type) == INTEGER_TYPE)
     utype = unsigned_type_for (type);
@@ -1618,65 +1615,67 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
 
   /* Initialize loop count and jump to exit label if the loop is empty.
      This code is executed before we enter the loop body. We generate:
-     step_sign = sign(1,step);
      if (step > 0)
        {
         if (to < from)
           goto exit_label;
+        countm1 = (to - from) / step;
        }
      else
        {
         if (to > from)
           goto exit_label;
+        countm1 = (from - to) / -step;
        }
-       countm1 = (to*step_sign - from*step_sign) / (step*step_sign);
-
-  */
+   */
 
   if (TREE_CODE (type) == INTEGER_TYPE)
     {
-      tree pos, neg, step_sign, to2, from2, step2;
+      tree pos, neg, tou, fromu, stepu, tmp2;
 
-      /* Calculate SIGN (1,step), as (step < 0 ? -1 : 1)  */
-
-      tmp = fold_build2_loc (loc, LT_EXPR, boolean_type_node, step,
-                            build_int_cst (TREE_TYPE (step), 0));
-      step_sign = fold_build3_loc (loc, COND_EXPR, type, tmp,
-                                  build_int_cst (type, -1),
-                                  build_int_cst (type, 1));
+      /* The distance from FROM to TO cannot always be represented in a signed
+         type, thus use unsigned arithmetic, also to avoid any undefined
+        overflow issues.  */
+      tou = fold_convert (utype, to);
+      fromu = fold_convert (utype, from);
+      stepu = fold_convert (utype, step);
 
+      /* For a positive step, when to < from, exit, otherwise compute
+         countm1 = ((unsigned)to - (unsigned)from) / (unsigned)step  */
       tmp = fold_build2_loc (loc, LT_EXPR, boolean_type_node, to, from);
+      tmp2 = fold_build2_loc (loc, TRUNC_DIV_EXPR, utype,
+                             fold_build2_loc (loc, MINUS_EXPR, utype,
+                                              tou, fromu),
+                             stepu);
       pos = fold_build3_loc (loc, COND_EXPR, void_type_node, tmp,
                             fold_build1_loc (loc, GOTO_EXPR, void_type_node,
                                              exit_label),
-                            build_empty_stmt (loc));
-
-      tmp = fold_build2_loc (loc, GT_EXPR, boolean_type_node, to,
-                            from);
+                            fold_build2 (MODIFY_EXPR, void_type_node,
+                                         countm1, tmp2));
+
+      /* For a negative step, when to > from, exit, otherwise compute
+         countm1 = ((unsigned)from - (unsigned)to) / -(unsigned)step  */
+      tmp = fold_build2_loc (loc, GT_EXPR, boolean_type_node, to, from);
+      tmp2 = fold_build2_loc (loc, TRUNC_DIV_EXPR, utype,
+                             fold_build2_loc (loc, MINUS_EXPR, utype,
+                                              fromu, tou),
+                             fold_build1_loc (loc, NEGATE_EXPR, utype, stepu));
       neg = fold_build3_loc (loc, COND_EXPR, void_type_node, tmp,
                             fold_build1_loc (loc, GOTO_EXPR, void_type_node,
                                              exit_label),
-                            build_empty_stmt (loc));
-      tmp = fold_build3_loc (loc, COND_EXPR, void_type_node,
-                            pos_step, pos, neg);
+                            fold_build2 (MODIFY_EXPR, void_type_node,
+                                         countm1, tmp2));
 
-      gfc_add_expr_to_block (&block, tmp);
+      tmp = fold_build2_loc (loc, LT_EXPR, boolean_type_node, step,
+                            build_int_cst (TREE_TYPE (step), 0));
+      tmp = fold_build3_loc (loc, COND_EXPR, void_type_node, tmp, neg, pos);
 
-      /* Calculate the loop count.  to-from can overflow, so
-        we cast to unsigned.  */
-
-      to2 = fold_build2_loc (loc, MULT_EXPR, type, step_sign, to);
-      from2 = fold_build2_loc (loc, MULT_EXPR, type, step_sign, from);
-      step2 = fold_build2_loc (loc, MULT_EXPR, type, step_sign, step);
-      step2 = fold_convert (utype, step2);
-      tmp = fold_build2_loc (loc, MINUS_EXPR, type, to2, from2);
-      tmp = fold_convert (utype, tmp);
-      tmp = fold_build2_loc (loc, TRUNC_DIV_EXPR, utype, tmp, step2);
-      tmp = fold_build2_loc (loc, MODIFY_EXPR, void_type_node, countm1, tmp);
       gfc_add_expr_to_block (&block, tmp);
     }
   else
     {
+      tree pos_step;
+
       /* TODO: We could use the same width as the real type.
         This would probably cause more problems that it solves
         when we implement "long double" types.  */
@@ -1688,6 +1687,8 @@ gfc_trans_do (gfc_code * code, tree exit_cond)
 
       /* We need a special check for empty loops:
         empty = (step > 0 ? to < from : to > from);  */
+      pos_step = fold_build2_loc (loc, GT_EXPR, boolean_type_node, step,
+                                 build_zero_cst (type));
       tmp = fold_build3_loc (loc, COND_EXPR, boolean_type_node, pos_step,
                             fold_build2_loc (loc, LT_EXPR,
                                              boolean_type_node, to, from),