re PR tree-optimization/49715 (Could do more efficient unsigned-to-float to conversio...
authorRichard Guenther <rguenther@suse.de>
Mon, 25 Jul 2011 08:30:46 +0000 (08:30 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Mon, 25 Jul 2011 08:30:46 +0000 (08:30 +0000)
2011-07-25  Richard Guenther  <rguenther@suse.de>

PR tree-optimization/49715
* tree-vrp.c: Include expr.h and optabs.h.
(range_fits_type_): New function.
(simplify_float_conversion_using_ranges): Likewise.
(simplify_stmt_using_ranges): Call it.
* Makefile.in (tree-vrp.o): Add $(EXPR_H) and $(OPTABS_H) dependencies.
* optabs.c (can_float_p): Export.
* optabs.h (can_float_p): Declare.

* gcc.target/i386/pr49715-1.c: New testcase.
* gcc.target/i386/pr49715-2.c: Likewise.

From-SVN: r176735

gcc/ChangeLog
gcc/Makefile.in
gcc/optabs.c
gcc/optabs.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr49715-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr49715-2.c [new file with mode: 0644]
gcc/tree-vrp.c

index 47b1b3bd4813c25d055ed5205d42ad223746cd26..cf4463d194959b13ad7c6ccb3656ed2d0012b8fc 100644 (file)
@@ -1,3 +1,14 @@
+2011-07-25  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/49715
+       * tree-vrp.c: Include expr.h and optabs.h.
+       (range_fits_type_): New function.
+       (simplify_float_conversion_using_ranges): Likewise.
+       (simplify_stmt_using_ranges): Call it.
+       * Makefile.in (tree-vrp.o): Add $(EXPR_H) and $(OPTABS_H) dependencies.
+       * optabs.c (can_float_p): Export.
+       * optabs.h (can_float_p): Declare.
+
 2011-07-25  Richard Guenther  <rguenther@suse.de>
 
        * tree-vrp.c (num_vr_values, values_propagated): New global vars.
index b215cd669afc3ec200f3ca469caeb3841472f8c7..88d851351727e49bf904f4fb45335f19a4589f94 100644 (file)
@@ -2504,7 +2504,7 @@ tree-vrp.o : tree-vrp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    $(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(GGC_H) \
    $(BASIC_BLOCK_H) tree-ssa-propagate.h $(FLAGS_H) $(TREE_DUMP_H) \
    $(CFGLOOP_H) $(SCEV_H) $(TIMEVAR_H) intl.h tree-pretty-print.h \
-   gimple-pretty-print.h gimple-fold.h
+   gimple-pretty-print.h gimple-fold.h $(OPTABS_H) $(EXPR_H)
 tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
    $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
    $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
index 915a45e2abbb082149c39edf4f5b1c3d40558d40..12717b67ab7b6d6fed3e1a3e91d901ccd9fe8914 100644 (file)
@@ -4626,7 +4626,7 @@ can_fix_p (enum machine_mode fixmode, enum machine_mode fltmode,
   return CODE_FOR_nothing;
 }
 
-static enum insn_code
+enum insn_code
 can_float_p (enum machine_mode fltmode, enum machine_mode fixmode,
             int unsignedp)
 {
index 477fce356c7e8604ce15838f5a098b424cc96be9..c7cb123e442a3ce00b12e2af975b9089a620d528 100644 (file)
@@ -849,6 +849,9 @@ extern void expand_fixed_convert (rtx, rtx, int, int);
 /* Generate code for a FLOAT_EXPR.  */
 extern void expand_float (rtx, rtx, int);
 
+/* Return the insn_code for a FLOAT_EXPR.  */
+enum insn_code can_float_p (enum machine_mode, enum machine_mode, int);
+
 /* Generate code for a FIX_EXPR.  */
 extern void expand_fix (rtx, rtx, int);
 
index 9eb5de6fcd56cc656e5d8d4a1dbf7a1304212233..4869657af974ba1bce436edcef5dbb1c7b16d4c1 100644 (file)
@@ -1,3 +1,9 @@
+2011-07-25  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/49715
+       * gcc.target/i386/pr49715-1.c: New testcase.
+       * gcc.target/i386/pr49715-2.c: Likewise.
+
 2011-07-23  Jason Merrill  <jason@redhat.com>
 
        * g++.dg/cpp0x/decltype21.C: Add 49823 examples.
diff --git a/gcc/testsuite/gcc.target/i386/pr49715-1.c b/gcc/testsuite/gcc.target/i386/pr49715-1.c
new file mode 100644 (file)
index 0000000..d959f9e
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse -mfpmath=sse" } */
+
+float func(unsigned x)
+{
+  return (x & 0xfffff) * 0.01f;
+}
+
+/* { dg-final { scan-assembler-times "cvtsi2ss" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr49715-2.c b/gcc/testsuite/gcc.target/i386/pr49715-2.c
new file mode 100644 (file)
index 0000000..3fc8e4e
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-O2" } */
+
+double func(unsigned long long x)
+{
+  if (x <= 0x7ffffffffffffffeULL)
+    return (x + 1) * 0.01;
+  return 0.0;
+}
+
+/* { dg-final { scan-assembler-times "cvtsi2sdq" 1 } } */
index 380c17fc5ab10567666a5d911352077bc443d346..c6a4c4476ff496bb03528077b7aec781c885bff8 100644 (file)
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-propagate.h"
 #include "tree-chrec.h"
 #include "gimple-fold.h"
+#include "expr.h"
+#include "optabs.h"
 
 
 /* Type of value ranges.  See value_range_d for a description of these
@@ -7415,6 +7417,99 @@ simplify_conversion_using_ranges (gimple stmt)
   return true;
 }
 
+/* Return whether the value range *VR fits in an integer type specified
+   by PRECISION and UNSIGNED_P.  */
+
+static bool
+range_fits_type_p (value_range_t *vr, unsigned precision, bool unsigned_p)
+{
+  double_int tem;
+
+  /* We can only handle constant ranges.  */
+  if (vr->type != VR_RANGE
+      || TREE_CODE (vr->min) != INTEGER_CST
+      || TREE_CODE (vr->max) != INTEGER_CST)
+    return false;
+
+  tem = double_int_ext (tree_to_double_int (vr->min), precision, unsigned_p);
+  if (!double_int_equal_p (tree_to_double_int (vr->min), tem))
+    return false;
+
+  tem = double_int_ext (tree_to_double_int (vr->max), precision, unsigned_p);
+  if (!double_int_equal_p (tree_to_double_int (vr->max), tem))
+    return false;
+
+  return true;
+}
+
+/* Simplify a conversion from integral SSA name to float in STMT.  */
+
+static bool
+simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
+{
+  tree rhs1 = gimple_assign_rhs1 (stmt);
+  value_range_t *vr = get_value_range (rhs1);
+  enum machine_mode fltmode = TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt)));
+  enum machine_mode mode;
+  tree tem;
+  gimple conv;
+
+  /* We can only handle constant ranges.  */
+  if (vr->type != VR_RANGE
+      || TREE_CODE (vr->min) != INTEGER_CST
+      || TREE_CODE (vr->max) != INTEGER_CST)
+    return false;
+
+  /* First check if we can use a signed type in place of an unsigned.  */
+  if (TYPE_UNSIGNED (TREE_TYPE (rhs1))
+      && (can_float_p (fltmode, TYPE_MODE (TREE_TYPE (rhs1)), 0)
+         != CODE_FOR_nothing)
+      && range_fits_type_p (vr, GET_MODE_PRECISION
+                                 (TYPE_MODE (TREE_TYPE (rhs1))), 0))
+    mode = TYPE_MODE (TREE_TYPE (rhs1));
+  /* If we can do the conversion in the current input mode do nothing.  */
+  else if (can_float_p (fltmode, TYPE_MODE (TREE_TYPE (rhs1)),
+                       TYPE_UNSIGNED (TREE_TYPE (rhs1))))
+    return false;
+  /* Otherwise search for a mode we can use, starting from the narrowest
+     integer mode available.  */
+  else
+    {
+      mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+      do
+       {
+         /* If we cannot do a signed conversion to float from mode
+            or if the value-range does not fit in the signed type
+            try with a wider mode.  */
+         if (can_float_p (fltmode, mode, 0) != CODE_FOR_nothing
+             && range_fits_type_p (vr, GET_MODE_PRECISION (mode), 0))
+           break;
+
+         mode = GET_MODE_WIDER_MODE (mode);
+         /* But do not widen the input.  Instead leave that to the
+            optabs expansion code.  */
+         if (GET_MODE_PRECISION (mode) > TYPE_PRECISION (TREE_TYPE (rhs1)))
+           return false;
+       }
+      while (mode != VOIDmode);
+      if (mode == VOIDmode)
+       return false;
+    }
+
+  /* It works, insert a truncation or sign-change before the
+     float conversion.  */
+  tem = create_tmp_var (build_nonstandard_integer_type
+                         (GET_MODE_PRECISION (mode), 0), NULL);
+  conv = gimple_build_assign_with_ops (NOP_EXPR, tem, rhs1, NULL_TREE);
+  tem = make_ssa_name (tem, conv);
+  gimple_assign_set_lhs (conv, tem);
+  gsi_insert_before (gsi, conv, GSI_SAME_STMT);
+  gimple_assign_set_rhs1 (stmt, tem);
+  update_stmt (stmt);
+
+  return true;
+}
+
 /* Simplify STMT using ranges if possible.  */
 
 static bool
@@ -7474,6 +7569,12 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
            return simplify_conversion_using_ranges (stmt);
          break;
 
+       case FLOAT_EXPR:
+         if (TREE_CODE (rhs1) == SSA_NAME
+             && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
+           return simplify_float_conversion_using_ranges (gsi, stmt);
+         break;
+
        default:
          break;
        }