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] |
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] |