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. */