This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR49715, (float)unsigned -> (float)signed


These two patches fix PR49715, the inability to optimize unsigned -> float
compares when the unsigned operand also fits into an SImode signed
integer.

The first patch makes VRP handle SSA name creation during 
substitute_and_fold nicely and the second implements the above transform.

Does anyone know if this transformation is not beneficial on
any architecture?

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

Thanks,
Richard.

2011-07-21  Richard Guenther  <rguenther@suse.de>

	* tree-vrp.c (num_vr_values, values_propagated): New global vars.
	(get_value_range): For out-of-range SSA names or names created
	after propagation return a read-only varying range.
	(dump_all_value_ranges): Adjust.
	(vrp_initialize): Likewise.
	(vrp_finalize): Likewise.

Index: trunk/gcc/tree-vrp.c
===================================================================
*** trunk.orig/gcc/tree-vrp.c	2011-07-21 16:23:30.000000000 +0200
--- trunk/gcc/tree-vrp.c	2011-07-21 16:46:39.000000000 +0200
*************** static assert_locus_t *asserts_for;
*** 138,144 ****
--- 138,146 ----
  
  /* Value range array.  After propagation, VR_VALUE[I] holds the range
     of values that SSA name N_I may take.  */
+ static unsigned num_vr_values;
  static value_range_t **vr_value;
+ static bool values_propagated;
  
  /* For a PHI node which sets SSA name N_I, VR_COUNTS[I] holds the
     number of executable edges we saw the last time we visited the
*************** abs_extent_range (value_range_t *vr, tre
*** 658,663 ****
--- 660,667 ----
  static value_range_t *
  get_value_range (const_tree var)
  {
+   static const struct value_range_d vr_const_varying
+     = { VR_VARYING, NULL_TREE, NULL_TREE, NULL };
    value_range_t *vr;
    tree sym;
    unsigned ver = SSA_NAME_VERSION (var);
*************** get_value_range (const_tree var)
*** 666,675 ****
--- 670,689 ----
    if (! vr_value)
      return NULL;
  
+   /* If we query the range for a new SSA name return an unmodifiable VARYING.
+      We should get here at most from the substitute-and-fold stage which
+      will never try to change values.  */
+   if (ver >= num_vr_values)
+     return CONST_CAST (value_range_t *, &vr_const_varying);
+ 
    vr = vr_value[ver];
    if (vr)
      return vr;
  
+   /* After propagation finished do not allocate new value-ranges.  */
+   if (values_propagated)
+     return CONST_CAST (value_range_t *, &vr_const_varying);
+ 
    /* Create a default value range.  */
    vr_value[ver] = vr = XCNEW (value_range_t);
  
*************** dump_all_value_ranges (FILE *file)
*** 3931,3937 ****
  {
    size_t i;
  
!   for (i = 0; i < num_ssa_names; i++)
      {
        if (vr_value[i])
  	{
--- 3945,3951 ----
  {
    size_t i;
  
!   for (i = 0; i < num_vr_values; i++)
      {
        if (vr_value[i])
  	{
*************** vrp_initialize (void)
*** 5593,5599 ****
  {
    basic_block bb;
  
!   vr_value = XCNEWVEC (value_range_t *, num_ssa_names);
    vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
  
    FOR_EACH_BB (bb)
--- 5607,5615 ----
  {
    basic_block bb;
  
!   values_propagated = false;
!   num_vr_values = num_ssa_names;
!   vr_value = XCNEWVEC (value_range_t *, num_vr_values);
    vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
  
    FOR_EACH_BB (bb)
*************** vrp_visit_assignment_or_call (gimple stm
*** 5720,5726 ****
  static inline value_range_t
  get_vr_for_comparison (int i)
  {
!   value_range_t vr = *(vr_value[i]);
  
    /* If name N_i does not have a valid range, use N_i as its own
       range.  This allows us to compare against names that may
--- 5736,5742 ----
  static inline value_range_t
  get_vr_for_comparison (int i)
  {
!   value_range_t vr = *get_value_range (ssa_name (i));
  
    /* If name N_i does not have a valid range, use N_i as its own
       range.  This allows us to compare against names that may
*************** static void
*** 7733,7739 ****
  vrp_finalize (void)
  {
    size_t i;
!   unsigned num = num_ssa_names;
  
    if (dump_file)
      {
--- 7749,7756 ----
  vrp_finalize (void)
  {
    size_t i;
! 
!   values_propagated = true;
  
    if (dump_file)
      {
*************** vrp_finalize (void)
*** 7753,7759 ****
    identify_jump_threads ();
  
    /* Free allocated memory.  */
!   for (i = 0; i < num; i++)
      if (vr_value[i])
        {
  	BITMAP_FREE (vr_value[i]->equiv);
--- 7770,7776 ----
    identify_jump_threads ();
  
    /* Free allocated memory.  */
!   for (i = 0; i < num_vr_values; i++)
      if (vr_value[i])
        {
  	BITMAP_FREE (vr_value[i]->equiv);


2011-07-21  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/49715
	* tree-vrp.c (simplify_float_conversion_using_ranges): New
	function.
	(simplify_stmt_using_ranges): Call it.

	* gcc.target/i386/pr49715.c: New testcase.

Index: gcc/tree-vrp.c
===================================================================
*** gcc/tree-vrp.c.orig	2011-07-21 16:46:39.000000000 +0200
--- gcc/tree-vrp.c	2011-07-21 16:56:08.000000000 +0200
*************** simplify_conversion_using_ranges (gimple
*** 7448,7453 ****
--- 7448,7496 ----
    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);
+   tree tem;
+   gimple conv;
+ 
+   /* It's not interesting to widen anything smaller than SImode.  */
+   if (TYPE_PRECISION (TREE_TYPE (rhs1)) < GET_MODE_PRECISION (SImode)
+       || (!TYPE_UNSIGNED (TREE_TYPE (rhs1))
+ 	  && TYPE_PRECISION (TREE_TYPE (rhs1)) == GET_MODE_PRECISION (SImode)))
+     return false;
+ 
+   /* 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;
+ 
+   /* Try if the value fits in a signed SImode integer, that's the only
+      interesting case.  */
+   if (!double_int_fits_to_tree_p (intSI_type_node,
+ 				  tree_to_double_int (vr->min))
+       || !double_int_fits_to_tree_p (intSI_type_node,
+ 				     tree_to_double_int (vr->max)))
+     return false;
+ 
+   /* It works, insert a truncation or sign-change before the
+      float conversion.  */
+   tem = create_tmp_var (intSI_type_node, 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
*************** simplify_stmt_using_ranges (gimple_stmt_
*** 7507,7512 ****
--- 7550,7561 ----
  	    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;
  	}
Index: gcc/testsuite/gcc.target/i386/pr49715.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.target/i386/pr49715.c	2011-07-21 16:55:57.000000000 +0200
***************
*** 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 } } */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]