re PR middle-end/79665 (gcc's signed (x*x)/200 is slower than clang's)
authorJakub Jelinek <jakub@gcc.gnu.org>
Thu, 23 Feb 2017 07:49:06 +0000 (08:49 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 23 Feb 2017 07:49:06 +0000 (08:49 +0100)
PR middle-end/79665
* internal-fn.c (get_range_pos_neg): Moved to ...
* tree.c (get_range_pos_neg): ... here.  No longer static.
* tree.h (get_range_pos_neg): New prototype.
* expr.c (expand_expr_real_2) <case TRUNC_DIV_EXPR>: If both arguments
are known to be in between 0 and signed maximum inclusive, try to
expand both unsigned and signed divmod and use the cheaper one from
those.

From-SVN: r245676

gcc/ChangeLog
gcc/expr.c
gcc/internal-fn.c
gcc/tree.c
gcc/tree.h

index 6da1d74115f18b879d5f90853d0dd72b7d127ac5..50566cc86853aeaaf74e526b4a2d15c09e67016a 100644 (file)
@@ -1,4 +1,15 @@
-2017-02-22 Jeff Law  <law@redhat.com>
+2017-02-23  Jakub Jelinek  <jakub@redhat.com>
+
+       PR middle-end/79665
+       * internal-fn.c (get_range_pos_neg): Moved to ...
+       * tree.c (get_range_pos_neg): ... here.  No longer static.
+       * tree.h (get_range_pos_neg): New prototype.
+       * expr.c (expand_expr_real_2) <case TRUNC_DIV_EXPR>: If both arguments
+       are known to be in between 0 and signed maximum inclusive, try to
+       expand both unsigned and signed divmod and use the cheaper one from
+       those.
+
+2017-02-22  Jeff Law  <law@redhat.com>
 
        PR tree-optimization/79578
        * tree-ssa-dse.c (clear_bytes_written_by): Use operand_equal_p
index 2d8868e52cefdfdc2d81135811cbf1cb3e6ff82b..34bbf3d7b47f5fdae0871c104a49b4f10773b7ee 100644 (file)
@@ -8809,6 +8809,34 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
         where some terms of the dividend have coeffs divisible by it.  */
       expand_operands (treeop0, treeop1,
                       subtarget, &op0, &op1, EXPAND_NORMAL);
+      if (SCALAR_INT_MODE_P (mode)
+         && optimize >= 2
+         && get_range_pos_neg (treeop0) == 1
+         && get_range_pos_neg (treeop1) == 1)
+       {
+         /* If both arguments are known to be positive when interpreted
+            as signed, we can expand it as both signed and unsigned
+            division or modulo.  Choose the cheaper sequence in that case.  */
+         bool speed_p = optimize_insn_for_speed_p ();
+         do_pending_stack_adjust ();
+         start_sequence ();
+         rtx uns_ret = expand_divmod (0, code, mode, op0, op1, target, 1);
+         rtx_insn *uns_insns = get_insns ();
+         end_sequence ();
+         start_sequence ();
+         rtx sgn_ret = expand_divmod (0, code, mode, op0, op1, target, 0);
+         rtx_insn *sgn_insns = get_insns ();
+         end_sequence ();
+         unsigned uns_cost = seq_cost (uns_insns, speed_p);
+         unsigned sgn_cost = seq_cost (sgn_insns, speed_p);
+         if (uns_cost < sgn_cost || (uns_cost == sgn_cost && unsignedp))
+           {
+             emit_insn (uns_insns);
+             return uns_ret;
+           }
+         emit_insn (sgn_insns);
+         return sgn_ret;
+       }
       return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
 
     case RDIV_EXPR:
index 1d84b260bf18703ca4a41a300d4899c23c380727..ffe291d62cf5936af2acc81e0c2efd7103966198 100644 (file)
@@ -413,86 +413,6 @@ expand_FALLTHROUGH (internal_fn, gcall *call)
            "invalid use of attribute %<fallthrough%>");
 }
 
-/* Helper function for expand_addsub_overflow.  Return 1
-   if ARG interpreted as signed in its precision is known to be always
-   positive or 2 if ARG is known to be always negative, or 3 if ARG may
-   be positive or negative.  */
-
-static int
-get_range_pos_neg (tree arg)
-{
-  if (arg == error_mark_node)
-    return 3;
-
-  int prec = TYPE_PRECISION (TREE_TYPE (arg));
-  int cnt = 0;
-  if (TREE_CODE (arg) == INTEGER_CST)
-    {
-      wide_int w = wi::sext (arg, prec);
-      if (wi::neg_p (w))
-       return 2;
-      else
-       return 1;
-    }
-  while (CONVERT_EXPR_P (arg)
-        && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
-        && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
-    {
-      arg = TREE_OPERAND (arg, 0);
-      /* Narrower value zero extended into wider type
-        will always result in positive values.  */
-      if (TYPE_UNSIGNED (TREE_TYPE (arg))
-         && TYPE_PRECISION (TREE_TYPE (arg)) < prec)
-       return 1;
-      prec = TYPE_PRECISION (TREE_TYPE (arg));
-      if (++cnt > 30)
-       return 3;
-    }
-
-  if (TREE_CODE (arg) != SSA_NAME)
-    return 3;
-  wide_int arg_min, arg_max;
-  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
-    {
-      gimple *g = SSA_NAME_DEF_STMT (arg);
-      if (is_gimple_assign (g)
-         && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
-       {
-         tree t = gimple_assign_rhs1 (g);
-         if (INTEGRAL_TYPE_P (TREE_TYPE (t))
-             && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
-           {
-             if (TYPE_UNSIGNED (TREE_TYPE (t))
-                 && TYPE_PRECISION (TREE_TYPE (t)) < prec)
-               return 1;
-             prec = TYPE_PRECISION (TREE_TYPE (t));
-             arg = t;
-             if (++cnt > 30)
-               return 3;
-             continue;
-           }
-       }
-      return 3;
-    }
-  if (TYPE_UNSIGNED (TREE_TYPE (arg)))
-    {
-      /* For unsigned values, the "positive" range comes
-        below the "negative" range.  */
-      if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
-       return 1;
-      if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
-       return 2;
-    }
-  else
-    {
-      if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
-       return 1;
-      if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
-       return 2;
-    }
-  return 3;
-}
-
 /* Return minimum precision needed to represent all values
    of ARG in SIGNed integral type.  */
 
index 3e63415e673eadeca286bfff9786e729e2e83373..42c8a2ddd8a50106e87c92bf160431d8ea66cedc 100644 (file)
@@ -14205,6 +14205,88 @@ verify_type (const_tree t)
 }
 
 
+/* Return 1 if ARG interpreted as signed in its precision is known to be
+   always positive or 2 if ARG is known to be always negative, or 3 if
+   ARG may be positive or negative.  */
+
+int
+get_range_pos_neg (tree arg)
+{
+  if (arg == error_mark_node)
+    return 3;
+
+  int prec = TYPE_PRECISION (TREE_TYPE (arg));
+  int cnt = 0;
+  if (TREE_CODE (arg) == INTEGER_CST)
+    {
+      wide_int w = wi::sext (arg, prec);
+      if (wi::neg_p (w))
+       return 2;
+      else
+       return 1;
+    }
+  while (CONVERT_EXPR_P (arg)
+        && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
+        && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
+    {
+      arg = TREE_OPERAND (arg, 0);
+      /* Narrower value zero extended into wider type
+        will always result in positive values.  */
+      if (TYPE_UNSIGNED (TREE_TYPE (arg))
+         && TYPE_PRECISION (TREE_TYPE (arg)) < prec)
+       return 1;
+      prec = TYPE_PRECISION (TREE_TYPE (arg));
+      if (++cnt > 30)
+       return 3;
+    }
+
+  if (TREE_CODE (arg) != SSA_NAME)
+    return 3;
+  wide_int arg_min, arg_max;
+  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
+    {
+      gimple *g = SSA_NAME_DEF_STMT (arg);
+      if (is_gimple_assign (g)
+         && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
+       {
+         tree t = gimple_assign_rhs1 (g);
+         if (INTEGRAL_TYPE_P (TREE_TYPE (t))
+             && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
+           {
+             if (TYPE_UNSIGNED (TREE_TYPE (t))
+                 && TYPE_PRECISION (TREE_TYPE (t)) < prec)
+               return 1;
+             prec = TYPE_PRECISION (TREE_TYPE (t));
+             arg = t;
+             if (++cnt > 30)
+               return 3;
+             continue;
+           }
+       }
+      return 3;
+    }
+  if (TYPE_UNSIGNED (TREE_TYPE (arg)))
+    {
+      /* For unsigned values, the "positive" range comes
+        below the "negative" range.  */
+      if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
+       return 1;
+      if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
+       return 2;
+    }
+  else
+    {
+      if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
+       return 1;
+      if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
+       return 2;
+    }
+  return 3;
+}
+
+
+
+
 /* Return true if ARG is marked with the nonnull attribute in the
    current function signature.  */
 
index 3b12509e7df7eb5e51d72eab7e15250c08d3569b..aa137e4132bb5c5ca3f397a51b475307c7ab91b6 100644 (file)
@@ -4876,6 +4876,7 @@ extern bool gimple_canonical_types_compatible_p (const_tree, const_tree,
                                                 bool trust_type_canonical = true);
 extern bool type_with_interoperable_signedness (const_tree);
 extern bitmap get_nonnull_args (const_tree);
+extern int get_range_pos_neg (tree);
 
 /* Return simplified tree code of type that is used for canonical type
    merging.  */