This is the actual patch for fixing the binary expression cases in
PR49806 - adding unary expressions is easy but will slightly convolute
the code.

Only lightly tested sofar, bootstrap and regtest pending for 
x86_64-unknown-linux-gnu.

Any comments on general profitability issues?

Thanks,
Richard.

2011-07-29  Richard Guenther  <rguent...@suse.de>

        PR tree-optimization/49806
        * tree-vrp.c (range_fits_type_p): Move earlier.
        (simplify_converted_operation_using_ranges): New function.
        (simplify_stmt_using_ranges): Call it.

        * gcc.dg/tree-ssa/vrp47.c: Adjust.

Index: gcc/tree-vrp.c
===================================================================
*** gcc/tree-vrp.c.orig 2011-07-29 14:31:59.000000000 +0200
--- gcc/tree-vrp.c      2011-07-29 14:32:00.000000000 +0200
*************** simplify_switch_using_ranges (gimple stm
*** 7314,7319 ****
--- 7314,7532 ----
    return false;
  }
  
+ /* 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)
+ {
+   tree src_type;
+   unsigned src_precision;
+   double_int tem;
+ 
+   /* We can only handle integral and pointer types.  */
+   src_type = TREE_TYPE (vr->min);
+   if (!INTEGRAL_TYPE_P (src_type)
+       && !POINTER_TYPE_P (src_type))
+     return false;
+ 
+   /* An extension is always fine, so is an identity transform.  */
+   src_precision = TYPE_PRECISION (TREE_TYPE (vr->min));
+   if (src_precision < precision
+       || (src_precision == precision
+         && TYPE_UNSIGNED (src_type) == unsigned_p))
+     return true;
+ 
+   /* Now we can only handle ranges with constant bounds.  */
+   if (vr->type != VR_RANGE
+       || TREE_CODE (vr->min) != INTEGER_CST
+       || TREE_CODE (vr->max) != INTEGER_CST)
+     return false;
+ 
+   /* For precision-preserving sign-changes the MSB of the double-int
+      has to be clear.  */
+   if (src_precision == precision
+       && (TREE_INT_CST_HIGH (vr->min) | TREE_INT_CST_HIGH (vr->max)) < 0)
+     return false;
+ 
+   /* Then we can perform the conversion on both ends and compare
+      the result for equality.  */
+   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;
+ }
+ 
+ /* Convert an operation to the type of its converted result.  The conversion
+    statement is STMT.  Return true if we performed the replacement.  */
+ 
+ static bool
+ simplify_converted_operation_using_ranges (gimple stmt)
+ {
+   tree lhs, op_result, rhs1, rhs1_def_rhs, rhs2, rhs2_def_rhs, tem, var, 
iptype;
+   enum tree_code op_code;
+   gimple op, rhs1_def, rhs2_def, newop;
+   gimple_stmt_iterator gsi;
+   value_range_t rhs1_vr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+   value_range_t rhs2_vr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+   value_range_t res_vr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL };
+   unsigned orig_precision, precision;
+   bool orig_unsigned_p, unsigned_p;
+ 
+   lhs = gimple_assign_lhs (stmt);
+   op_result = gimple_assign_rhs1 (stmt);
+   if (TREE_CODE (op_result) != SSA_NAME
+       || !has_single_use (op_result))
+     return false;
+   op = SSA_NAME_DEF_STMT (op_result);
+   if (!is_gimple_assign (op))
+     return false;
+   op_code = gimple_assign_rhs_code (op);
+   if (TREE_CODE_CLASS (op_code) != tcc_binary)
+     return false;
+   rhs1 = gimple_assign_rhs1 (op);
+   rhs2 = gimple_assign_rhs2 (op);
+   if (TREE_CODE (rhs1) != SSA_NAME
+       || (TREE_CODE (rhs2) != SSA_NAME
+         && TREE_CODE (rhs2) != INTEGER_CST))
+     return false;
+   rhs1_def = SSA_NAME_DEF_STMT (rhs1);
+   if (!has_single_use (rhs1)
+       || !is_gimple_assign (rhs1_def)
+       || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (rhs1_def)))
+     return false;
+   rhs1_def_rhs = gimple_assign_rhs1 (rhs1_def);
+   if (TREE_CODE (rhs2) == SSA_NAME)
+     {
+       rhs2_def = SSA_NAME_DEF_STMT (rhs2);
+       if (!has_single_use (rhs2)
+         || !is_gimple_assign (rhs2_def)
+         || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (rhs2_def)))
+       return false;
+       rhs2_def_rhs = gimple_assign_rhs1 (rhs2_def);
+     }
+   else
+     rhs2_def_rhs = rhs2;
+ 
+   /* Now we have matched the statement pattern
+ 
+        rhs1 = (T1)x;
+        rhs2 = (T1)y;
+        op_result = rhs1 OP rhs2;
+        lhs = (T2)op_result;
+ 
+      We want to compute rhs1 OP rhs2 in type T2 to get rid of the
+      final conversion, either eliminating the conversions to T1
+      as well, or adjusting them accordingly.
+      For this to be valid we need to simulate rhs1 OP rhs2 in
+      infinite precision and verify the result fits both in T1 and T2.  */
+   orig_precision = TYPE_PRECISION (TREE_TYPE (op_result));
+   orig_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (op_result));
+   precision = TYPE_PRECISION (TREE_TYPE (lhs));
+   unsigned_p = TYPE_UNSIGNED (TREE_TYPE (lhs));
+ 
+   /* Restrict this transformation to seemingly profitable cases which
+      include a non-mode-precision operation type or a final truncation
+      and a new operation precision that matches its mode-precision.  */
+   if (!(((orig_precision
+         != GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (op_result))))
+        || precision < orig_precision)
+       && precision == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (lhs)))))
+     return false;
+ 
+   /* Of course x and y have to have value-ranges that fit in both T1
+      and T2 as well.  */
+   rhs1_vr = *get_value_range (rhs1_def_rhs);
+   if (rhs1_vr.type != VR_RANGE
+       || TREE_CODE (rhs1_vr.min) != INTEGER_CST
+       || TREE_CODE (rhs1_vr.max) != INTEGER_CST)
+     return false;
+   if (TREE_CODE (rhs2) == SSA_NAME)
+     {
+       rhs2_vr = *get_value_range (rhs2_def_rhs);
+       if (rhs2_vr.type != VR_RANGE
+         || TREE_CODE (rhs2_vr.min) != INTEGER_CST
+         || TREE_CODE (rhs2_vr.max) != INTEGER_CST)
+       return false;
+     }
+   else
+     set_value_range_to_value (&rhs2_vr, rhs2, NULL);
+   if (!range_fits_type_p (&rhs1_vr, orig_precision, orig_unsigned_p)
+       || !range_fits_type_p (&rhs2_vr, orig_precision, orig_unsigned_p)
+       || !range_fits_type_p (&rhs1_vr, precision, unsigned_p)
+       || !range_fits_type_p (&rhs2_vr, precision, unsigned_p))
+     return false;
+ 
+   /* Simulate it in infinite precision, if possible and check if the
+      result fits.  */
+   if (orig_precision > HOST_BITS_PER_WIDE_INT
+       || precision > HOST_BITS_PER_WIDE_INT)
+     return false;
+   iptype = build_nonstandard_integer_type (2 * HOST_BITS_PER_WIDE_INT, 0);
+   rhs1_vr.min = fold_convert (iptype, rhs1_vr.min);
+   rhs1_vr.max = fold_convert (iptype, rhs1_vr.max);
+   rhs2_vr.min = fold_convert (iptype, rhs2_vr.min);
+   rhs2_vr.max = fold_convert (iptype, rhs2_vr.max);
+   extract_range_from_binary_expr_1 (&res_vr,
+                                   op_code, iptype, &rhs1_vr, &rhs2_vr);
+   if (res_vr.type != VR_RANGE
+       || !range_fits_type_p (&res_vr, orig_precision, orig_unsigned_p)
+       || !range_fits_type_p (&res_vr, precision, unsigned_p))
+     return false;
+ 
+   var = create_tmp_reg (TREE_TYPE (lhs), NULL);
+ 
+   /* Re-write the operand conversions.  */
+   if (!useless_type_conversion_p (TREE_TYPE (lhs),
+                                 TREE_TYPE (rhs1_def_rhs)))
+     {
+       gsi = gsi_for_stmt (rhs1_def);
+       newop = gimple_build_assign_with_ops (NOP_EXPR, var, rhs1_def_rhs,
+                                           NULL_TREE);
+       rhs1 = make_ssa_name (var, newop);
+       gimple_assign_set_lhs (newop, rhs1);
+       gsi_insert_before (&gsi, newop, GSI_SAME_STMT);
+     }
+   else
+     rhs1 = rhs1_def_rhs;
+   if (TREE_CODE (rhs2) == SSA_NAME)
+     {
+       if (!useless_type_conversion_p (TREE_TYPE (lhs),
+                                     TREE_TYPE (rhs2_def_rhs)))
+       {
+         gsi = gsi_for_stmt (rhs2_def);
+         newop = gimple_build_assign_with_ops (NOP_EXPR, var, rhs2_def_rhs,
+                                               NULL_TREE);
+         rhs2 = make_ssa_name (var, newop);
+         gimple_assign_set_lhs (newop, rhs2);
+         gsi_insert_before (&gsi, newop, GSI_SAME_STMT);
+       }
+       else
+       rhs2 = rhs2_def_rhs;
+     }
+   else
+     rhs2 = fold_convert (TREE_TYPE (lhs), rhs2);
+ 
+   /* Re-write the operation in the target type.  */
+   gsi = gsi_for_stmt (op);
+   var = create_tmp_reg (TREE_TYPE (lhs), NULL);
+   newop = gimple_build_assign_with_ops (op_code, var, rhs1, rhs2);
+   tem = make_ssa_name (var, newop);
+   gimple_assign_set_lhs (newop, tem);
+   gsi_insert_before (&gsi, newop, GSI_SAME_STMT);
+ 
+   /* Adjust the final conversion.  */
+   gimple_assign_set_rhs1 (stmt, tem);
+   gimple_assign_set_rhs_code (stmt, SSA_NAME);
+   update_stmt (stmt);
+ 
+   return true;
+ }
+ 
  /* Simplify an integral conversion from an SSA name in STMT.  */
  
  static bool
*************** simplify_conversion_using_ranges (gimple
*** 7374,7426 ****
    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)
- {
-   tree src_type;
-   unsigned src_precision;
-   double_int tem;
- 
-   /* We can only handle integral and pointer types.  */
-   src_type = TREE_TYPE (vr->min);
-   if (!INTEGRAL_TYPE_P (src_type)
-       && !POINTER_TYPE_P (src_type))
-     return false;
- 
-   /* An extension is always fine, so is an identity transform.  */
-   src_precision = TYPE_PRECISION (TREE_TYPE (vr->min));
-   if (src_precision < precision
-       || (src_precision == precision
-         && TYPE_UNSIGNED (src_type) == unsigned_p))
-     return true;
- 
-   /* Now we can only handle ranges with constant bounds.  */
-   if (vr->type != VR_RANGE
-       || TREE_CODE (vr->min) != INTEGER_CST
-       || TREE_CODE (vr->max) != INTEGER_CST)
-     return false;
- 
-   /* For precision-preserving sign-changes the MSB of the double-int
-      has to be clear.  */
-   if (src_precision == precision
-       && (TREE_INT_CST_HIGH (vr->min) | TREE_INT_CST_HIGH (vr->max)) < 0)
-     return false;
- 
-   /* Then we can perform the conversion on both ends and compare
-      the result for equality.  */
-   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
--- 7587,7592 ----
*************** simplify_stmt_using_ranges (gimple_stmt_
*** 7540,7546 ****
        CASE_CONVERT:
          if (TREE_CODE (rhs1) == SSA_NAME
              && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
!           return simplify_conversion_using_ranges (stmt);
          break;
  
        case FLOAT_EXPR:
--- 7706,7713 ----
        CASE_CONVERT:
          if (TREE_CODE (rhs1) == SSA_NAME
              && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
!           return (simplify_conversion_using_ranges (stmt)
!                   || simplify_converted_operation_using_ranges (stmt));
          break;
  
        case FLOAT_EXPR:
Index: gcc/testsuite/gcc.dg/tree-ssa/vrp47.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/vrp47.c.orig  2011-07-29 14:34:56.000000000 
+0200
--- gcc/testsuite/gcc.dg/tree-ssa/vrp47.c       2011-07-29 14:35:09.000000000 
+0200
***************
*** 4,11 ****
     jumps when evaluating an && condition.  VRP is not able to optimize
     this.  */
  /* { dg-do compile { target { ! "mips*-*-* s390*-*-*  avr-*-* mn10300-*-*" } 
} } */
! /* { dg-options "-O2 -fdump-tree-vrp -fdump-tree-dom" } */
! /* { dg-options "-O2 -fdump-tree-vrp -fdump-tree-dom -march=i586" { target { 
i?86-*-* && ilp32 } } } */
  
  int h(int x, int y)
  {
--- 4,11 ----
     jumps when evaluating an && condition.  VRP is not able to optimize
     this.  */
  /* { dg-do compile { target { ! "mips*-*-* s390*-*-*  avr-*-* mn10300-*-*" } 
} } */
! /* { dg-options "-O2 -fdump-tree-vrp1" } */
! /* { dg-options "-O2 -fdump-tree-vrp1 -march=i586" { target { i?86-*-* && 
ilp32 } } } */
  
  int h(int x, int y)
  {
*************** int f(int x)
*** 36,48 ****
     0 or 1.  */
  /* { dg-final { scan-tree-dump-times "\[xy\]\[^ \]* !=" 0 "vrp1" } } */
  
! /* This one needs more copy propagation that only happens in dom1.  */
! /* { dg-final { scan-tree-dump-times "x\[^ \]* & y" 1 "dom1" } } */
! /* { dg-final { scan-tree-dump-times "x\[^ \]* & y" 1 "vrp1" { xfail *-*-* } 
} } */
! 
! /* These two are fully simplified by VRP.  */
! /* { dg-final { scan-tree-dump-times "x\[^ \]* \[|\] y" 1 "vrp1" } } */
  /* { dg-final { scan-tree-dump-times "x\[^ \]* \\^ 1" 1 "vrp1" } } */
  
! /* { dg-final { cleanup-tree-dump "vrp\[0-9\]" } } */
! /* { dg-final { cleanup-tree-dump "dom\[0-9\]" } } */
--- 36,44 ----
     0 or 1.  */
  /* { dg-final { scan-tree-dump-times "\[xy\]\[^ \]* !=" 0 "vrp1" } } */
  
! /* These three are fully simplified by VRP.  */
! /* { dg-final { scan-tree-dump-times "x\[^ \]* & y" 1 "vrp1" } } */
! /* { dg-final { scan-tree-dump-times "x\[^ \]* \\| y" 1 "vrp1" } } */
  /* { dg-final { scan-tree-dump-times "x\[^ \]* \\^ 1" 1 "vrp1" } } */
  
! /* { dg-final { cleanup-tree-dump "vrp1" } } */

Reply via email to