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]

match.pd tweaks for vectors and issues with HONOR_NANS


Hello,

this patch breaks gcc.dg/torture/pr50396.c, and I believe this is a symptom of a bigger issue: the HONOR_NANS interface is bad (or at least the way we are using it is bad). To know if a type honors NaN, we first get its TYPE_MODE and then call HONOR_NANS on that. But for vectors that do not directly map to hardware, the mode is BLKmode, for which HONOR_NANS returns false (bad luck, the default is unsafe).

We could introduce a function:

bool
honor_nans (machine_mode m)
{
  // check for BLKmode?
  return HONOR_NANS (m);
}
bool
honor_nans (const_tree t)
{
  if (!TYPE_P (t))
    t = TREE_TYPE (t);
  if (VECTOR_TYPE_P (t) || COMPLEX_TYPE_P (t))
    t = TREE_TYPE (t);
  return honor_nans (TYPE_MODE (t));
}

and use it in many places. Or call it honors_nan so we don't have to rename variables. Or maybe a function ignore_nans instead, that returns !honor_nans. I am hoping that the element type of a vector always has a mode, otherwise the function will need to be a bit more complicated.

But the same issue also affects HONOR_SIGNED_ZEROS, HONOR_SNANS, HONOR_INFINITIES, etc. It is going to be a pain to add a new function for each and replace uses. We could instead replace those calls to TYPE_MODE by a new:

machine_mode
element_mode (const_tree t)
{
  if (!TYPE_P (t))
    t = TREE_TYPE (t);
  if (VECTOR_TYPE_P (t) || COMPLEX_TYPE_P (t))
    t = TREE_TYPE (t);
  return TYPE_MODE (t);
}

so we still have to use HONOR_NANS on the result but at least we only
introduce one new function.

Any opinion on how best to handle that? I can't promise I'll have time to work on it any time soon (I might, but I don't know).

--
Marc Glisse
Index: gcc/match.pd
===================================================================
--- gcc/match.pd	(revision 217614)
+++ gcc/match.pd	(working copy)
@@ -19,21 +19,21 @@ FITNESS FOR A PARTICULAR PURPOSE.  See t
 for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 
 /* Generic tree predicates we inherit.  */
 (define_predicates
    integer_onep integer_zerop integer_all_onesp integer_minus_onep
-   integer_each_onep
+   integer_each_onep integer_truep
    real_zerop real_onep real_minus_onep
    CONSTANT_CLASS_P
    tree_expr_nonnegative_p)
 
 /* Operator lists.  */
 (define_operator_list tcc_comparison
   lt   le   eq ne ge   gt   unordered ordered   unlt unle ungt unge uneq ltgt)
 (define_operator_list inverted_tcc_comparison
   ge   gt   ne eq lt   le   ordered   unordered ge   gt   le   lt   ltgt uneq)
 (define_operator_list inverted_tcc_comparison_with_nans
@@ -110,47 +110,49 @@ along with GCC; see the file COPYING3.
 /* Make sure to preserve divisions by zero.  This is the reason why
    we don't simplify x / x to 1 or 0 / x to 0.  */
 (for op (mult trunc_div ceil_div floor_div round_div exact_div)
   (simplify
     (op @0 integer_onep)
     (non_lvalue @0)))
 
 /* X / -1 is -X.  */
 (for div (trunc_div ceil_div floor_div round_div exact_div)
  (simplify
-   (div @0 INTEGER_CST@1)
-   (if (!TYPE_UNSIGNED (type)
-        && wi::eq_p (@1, -1))
+   (div @0 integer_minus_onep@1)
+   (if (!TYPE_UNSIGNED (type))
     (negate @0))))
 
 /* For unsigned integral types, FLOOR_DIV_EXPR is the same as
    TRUNC_DIV_EXPR.  Rewrite into the latter in this case.  */
 (simplify
  (floor_div @0 @1)
- (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type))
+ (if ((INTEGRAL_TYPE_P (type) || VECTOR_INTEGER_TYPE_P (type))
+      && TYPE_UNSIGNED (type))
   (trunc_div @0 @1)))
 
 /* Optimize A / A to 1.0 if we don't care about
-   NaNs or Infinities.  Skip the transformation
-   for non-real operands.  */
+   NaNs or Infinities.  */
 (simplify
  (rdiv @0 @0)
- (if (SCALAR_FLOAT_TYPE_P (type)
+ (if (FLOAT_TYPE_P (type)
       && ! HONOR_NANS (TYPE_MODE (type))
       && ! HONOR_INFINITIES (TYPE_MODE (type)))
-  { build_real (type, dconst1); })
- /* The complex version of the above A / A optimization.  */
- (if (COMPLEX_FLOAT_TYPE_P (type)
-      && ! HONOR_NANS (TYPE_MODE (TREE_TYPE (type)))
-      && ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (type))))
-  { build_complex (type, build_real (TREE_TYPE (type), dconst1),
-		   build_real (TREE_TYPE (type), dconst0)); }))
+  { build_one_cst (type); }))
+
+/* Optimize -A / A to -1.0 if we don't care about
+   NaNs or Infinities.  */
+(simplify
+ (rdiv:c @0 (negate @0))
+ (if (FLOAT_TYPE_P (type)
+      && ! HONOR_NANS (TYPE_MODE (type))
+      && ! HONOR_INFINITIES (TYPE_MODE (type)))
+  { build_minus_one_cst (type); }))
 
 /* In IEEE floating point, x/1 is not equivalent to x for snans.  */
 (simplify
  (rdiv @0 real_onep)
  (if (!HONOR_SNANS (TYPE_MODE (type)))
   (non_lvalue @0)))
 
 /* In IEEE floating point, x/-1 is not equivalent to -x for snans.  */
 (simplify
  (rdiv @0 real_minus_onep)
@@ -184,23 +186,22 @@ along with GCC; see the file COPYING3.
   (mod integer_zerop@0 @1)
   /* But not for 0 % 0 so that we can get the proper warnings and errors.  */
   (if (!integer_zerop (@1))
    @0))
  /* X % 1 is always zero.  */
  (simplify
   (mod @0 integer_onep)
   { build_zero_cst (type); })
  /* X % -1 is zero.  */
  (simplify
-  (mod @0 INTEGER_CST@1)
-  (if (!TYPE_UNSIGNED (type)
-       && wi::eq_p (@1, -1))
+  (mod @0 integer_minus_onep@1)
+  (if (!TYPE_UNSIGNED (type))
    { build_zero_cst (type); })))
 
 /* X % -C is the same as X % C.  */
 (simplify
  (trunc_mod @0 INTEGER_CST@1)
   (if (TYPE_SIGN (type) == SIGNED
        && !TREE_OVERFLOW (@1)
        && wi::neg_p (@1)
        && !TYPE_OVERFLOW_TRAPS (type)
        /* Avoid this transformation if C is INT_MIN, i.e. C == -C.  */
@@ -301,28 +302,25 @@ along with GCC; see the file COPYING3.
  (if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)))
 (for op (tcc_comparison truth_and truth_andif truth_or truth_orif truth_xor)
  (match truth_valued_p
   (op @0 @1)))
 (match truth_valued_p
   (truth_not @0))
 
 (match (logical_inverted_value @0)
  (bit_not truth_valued_p@0))
 (match (logical_inverted_value @0)
- (eq @0 integer_zerop)
- (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))))
+ (eq @0 integer_zerop))
 (match (logical_inverted_value @0)
- (ne truth_valued_p@0 integer_onep)
- (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))))
+ (ne truth_valued_p@0 integer_truep))
 (match (logical_inverted_value @0)
- (bit_xor truth_valued_p@0 integer_onep)
- (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))))
+ (bit_xor truth_valued_p@0 integer_truep))
 
 /* X & !X -> 0.  */
 (simplify
  (bit_and:c @0 (logical_inverted_value @0))
  { build_zero_cst (type); })
 /* X | !X and X ^ !X -> 1, , if X is truth-valued.  */
 (for op (bit_ior bit_xor)
  (simplify
   (op:c truth_valued_p@0 (logical_inverted_value @0))
   { constant_boolean_node (true, type); }))
@@ -485,21 +483,21 @@ along with GCC; see the file COPYING3.
   /* ~A + 1 -> -A */
   (simplify
    (plus (bit_not @0) integer_each_onep)
    (negate @0))
 
   /* (T)(P + A) - (T)P -> (T) A */
   (for add (plus pointer_plus)
    (simplify
     (minus (convert (add @0 @1))
      (convert @0))
-    (if (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (@1))
+    (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
 	 /* For integer types, if A has a smaller type
 	    than T the result depends on the possible
 	    overflow in P + A.
 	    E.g. T=size_t, A=(unsigned)429497295, P>0.
 	    However, if an overflow in P + A would cause
 	    undefined behavior, we can assume that there
 	    is no overflow.  */
 	 || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
 	     && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
 	 /* For pointer types, if the conversion of A to the
@@ -618,33 +616,33 @@ along with GCC; see the file COPYING3.
  (for icvt (convert float)
   (simplify
    (ocvt (icvt@1 @0))
    (with
     {
       tree inside_type = TREE_TYPE (@0);
       tree inter_type = TREE_TYPE (@1);
       int inside_int = INTEGRAL_TYPE_P (inside_type);
       int inside_ptr = POINTER_TYPE_P (inside_type);
       int inside_float = FLOAT_TYPE_P (inside_type);
-      int inside_vec = TREE_CODE (inside_type) == VECTOR_TYPE;
+      int inside_vec = VECTOR_TYPE_P (inside_type);
       unsigned int inside_prec = TYPE_PRECISION (inside_type);
       int inside_unsignedp = TYPE_UNSIGNED (inside_type);
       int inter_int = INTEGRAL_TYPE_P (inter_type);
       int inter_ptr = POINTER_TYPE_P (inter_type);
       int inter_float = FLOAT_TYPE_P (inter_type);
-      int inter_vec = TREE_CODE (inter_type) == VECTOR_TYPE;
+      int inter_vec = VECTOR_TYPE_P (inter_type);
       unsigned int inter_prec = TYPE_PRECISION (inter_type);
       int inter_unsignedp = TYPE_UNSIGNED (inter_type);
       int final_int = INTEGRAL_TYPE_P (type);
       int final_ptr = POINTER_TYPE_P (type);
       int final_float = FLOAT_TYPE_P (type);
-      int final_vec = TREE_CODE (type) == VECTOR_TYPE;
+      int final_vec = VECTOR_TYPE_P (type);
       unsigned int final_prec = TYPE_PRECISION (type);
       int final_unsignedp = TYPE_UNSIGNED (type);
     }
    /* In addition to the cases of two conversions in a row
       handled below, if we are converting something to its own
       type via an object of identical or wider precision, neither
       conversion is needed.  */
    (if (((GIMPLE && useless_type_conversion_p (type, inside_type))
 	 || (GENERIC
 	     && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (inside_type)))
@@ -837,26 +835,26 @@ along with GCC; see the file COPYING3.
  (simplify
   (cnd @0 (cnd @0 @1 @2) @3)
   (cnd @0 @1 @3))
  (simplify
   (cnd @0 @1 (cnd @0 @2 @3))
   (cnd @0 @1 @3))
 
  /* A ? B : B -> B.  */
  (simplify
   (cnd @0 @1 @1)
-  @1))
+  @1)
 
-/* !A ? B : C -> A ? C : B.  */
-(simplify
- (cond (logical_inverted_value truth_valued_p@0) @1 @2)
- (cond @0 @2 @1))
+ /* !A ? B : C -> A ? C : B.  */
+ (simplify
+  (cnd (logical_inverted_value truth_valued_p@0) @1 @2)
+  (cnd @0 @2 @1)))
 
 
 /* Simplifications of comparisons.  */
 
 /* We can simplify a logical negation of a comparison to the
    inverted comparison.  As we cannot compute an expression
    operator using invert_tree_comparison we have to simulate
    that with expression code iteration.  */
 (for cmp (tcc_comparison)
      icmp (inverted_tcc_comparison)
@@ -874,18 +872,17 @@ along with GCC; see the file COPYING3.
       invert_tree_comparison will tell us.  But we can't use
       a computed operator in the replacement tree thus we have
       to play the trick below.  */
    (with { enum tree_code ic = invert_tree_comparison
              (cmp, HONOR_NANS (TYPE_MODE (TREE_TYPE (@0)))); }
     (if (ic == icmp)
      (icmp @0 @1))
     (if (ic == ncmp)
      (ncmp @0 @1)))))
  (simplify
-  (bit_xor (cmp @0 @1) integer_onep)
-  (if (INTEGRAL_TYPE_P (type))
-   (with { enum tree_code ic = invert_tree_comparison
-             (cmp, HONOR_NANS (TYPE_MODE (TREE_TYPE (@0)))); }
-    (if (ic == icmp)
-     (icmp @0 @1))
-    (if (ic == ncmp)
-     (ncmp @0 @1))))))
+  (bit_xor (cmp @0 @1) integer_truep)
+  (with { enum tree_code ic = invert_tree_comparison
+            (cmp, HONOR_NANS (TYPE_MODE (TREE_TYPE (@0)))); }
+   (if (ic == icmp)
+    (icmp @0 @1))
+   (if (ic == ncmp)
+    (ncmp @0 @1)))))
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 217614)
+++ gcc/tree.c	(working copy)
@@ -2268,20 +2268,34 @@ integer_nonzerop (const_tree expr)
 {
   STRIP_NOPS (expr);
 
   return ((TREE_CODE (expr) == INTEGER_CST
 	   && !wi::eq_p (expr, 0))
 	  || (TREE_CODE (expr) == COMPLEX_CST
 	      && (integer_nonzerop (TREE_REALPART (expr))
 		  || integer_nonzerop (TREE_IMAGPART (expr)))));
 }
 
+/* Return 1 if EXPR is the integer constant one.  For vector,
+   return 1 if every piece is the integer constant minus one
+   (representing the value TRUE).  */
+
+int
+integer_truep (const_tree expr)
+{
+  STRIP_NOPS (expr);
+
+  if (TREE_CODE (expr) == VECTOR_CST)
+    return integer_all_onesp (expr);
+  return integer_onep (expr);
+}
+
 /* Return 1 if EXPR is the fixed-point constant zero.  */
 
 int
 fixed_zerop (const_tree expr)
 {
   return (TREE_CODE (expr) == FIXED_CST
 	  && TREE_FIXED_CST (expr).data.is_zero ());
 }
 
 /* Return the power of two represented by a tree node known to be a
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 217614)
+++ gcc/tree.h	(working copy)
@@ -3992,20 +3992,25 @@ extern int integer_minus_onep (const_tre
 /* integer_pow2p (tree x) is nonzero is X is an integer constant with
    exactly one bit 1.  */
 
 extern int integer_pow2p (const_tree);
 
 /* integer_nonzerop (tree x) is nonzero if X is an integer constant
    with a nonzero value.  */
 
 extern int integer_nonzerop (const_tree);
 
+/* integer_truep (tree x) is nonzero if X is an integer constant of value 1 or
+   a vector where each element is an integer constant of value -1.  */
+
+extern int integer_truep (const_tree);
+
 extern bool cst_and_fits_in_hwi (const_tree);
 extern tree num_ending_zeros (const_tree);
 
 /* fixed_zerop (tree x) is nonzero if X is a fixed-point constant of
    value 0.  */
 
 extern int fixed_zerop (const_tree);
 
 /* staticp (tree x) is nonzero if X is a reference to data allocated
    at a fixed address in memory.  Returns the outermost data.  */

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