diff options
author | Paolo Bonzini <bonzini@gnu.org> | 2004-05-28 16:37:08 +0000 |
---|---|---|
committer | Paolo Bonzini <bonzini@gcc.gnu.org> | 2004-05-28 16:37:08 +0000 |
commit | d1a7edafe6a978e8f380a74f1f6d386d871bf417 (patch) | |
tree | 7ddeb479040eb4166d908a90967e3c0027eb6800 /gcc/fold-const.c | |
parent | 2966b00e88d24531be8ff24ac6c82d5cf70ae116 (diff) | |
download | gcc-d1a7edafe6a978e8f380a74f1f6d386d871bf417.zip gcc-d1a7edafe6a978e8f380a74f1f6d386d871bf417.tar.gz gcc-d1a7edafe6a978e8f380a74f1f6d386d871bf417.tar.bz2 |
re PR rtl-optimization/15649 (ICE with __builtin_isgreater and -ffast-math)
gcc/ChangeLog:
2004-05-27 Paolo Bonzini <bonzini@gnu.org>
Roger Sayle <roger@eyesopen.com>
PR rtl-optimization/15649
Add LTGT_EXPR and improve pretty-printing of unordered
comparisons.
* c-common.c (c_common_truthvalue_conversion):
Handle LTGT_EXPR.
* c-typeck.c (build_binary_op): Likewise.
* dojump.c (do_jump): Likewise.
* expr.c (expand_expr_real_1, do_store_flag): Likewise.
* predict.c (tree_predict_by_opcode): Likewise.
* real.c (real_compare): Likewise.
* tree-cfg.c (verify_expr): Likewise.
* tree-inline.c (estimate_num_insns_1): Likewise.
* tree-pretty-print.c (dump_generic_node): Likewise.
Handle ORDERED_EXPR, UNORDERED_EXPR.
(op_symbol): Print unordered comparisons differently
than ordered ones.
* tree.def (LTGT_EXPR): New '<' tree code.
* doc/c-tree.texi (Expressions): Document floating-point
comparison nodes.
Fold comparisons between floating point values.
* fold-const.c (enum comparison_code): New, from
#define'd constants. Define compcodes for unordered
comparisons and for invalid transformations.
(invert_tree_comparison): Add "honor_nans" parameter.
(fold_truthop): Revamp to work on floating-point types too.
(comparison_to_compcode): Support unordered comparisons.
Use new enum comparison_code.
(compcode_to_comparison): Likewise.
(combine_compcodes): New function.
(invert_truthvalue): Let invert_tree_comparison decide
whether it is valid to fold the comparison. Fold ORDERED
and UNORDERED even if flag_unsafe_math_optimizations is off,
and the remaining even if flag_unsafe_math_optimizations
is off but we are under -fno-trapping-math.
(fold_relational_const): Integer modes do not honor NaNs.
gcc/testsuite/ChangeLog:
2004-05-27 Paolo Bonzini <bonzini@gnu.org>
* gcc.c-torture/compare-fp-1.c, gcc.c-torture/compare-fp-2.c,
gcc.c-torture/compare-fp-3.c, gcc.c-torture/compare-fp-4.c,
gcc.c-torture/compare-fp-3.x, gcc.c-torture/compare-fp-4.x,
gcc.c-torture/pr15649-1.c: New.
Co-Authored-By: Roger Sayle <roger@eyesopen.com>
From-SVN: r82365
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 280 |
1 files changed, 206 insertions, 74 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 3fa46ca..98e98f7 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -58,6 +58,28 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "langhooks.h" #include "md5.h" +/* The following constants represent a bit based encoding of GCC's + comparison operators. This encoding simplifies transformations + on relational comparison operators, such as AND and OR. */ +enum comparison_code { + COMPCODE_FALSE = 0, + COMPCODE_LT = 1, + COMPCODE_EQ = 2, + COMPCODE_LE = 3, + COMPCODE_GT = 4, + COMPCODE_LTGT = 5, + COMPCODE_GE = 6, + COMPCODE_ORD = 7, + COMPCODE_UNORD = 8, + COMPCODE_UNLT = 9, + COMPCODE_UNEQ = 10, + COMPCODE_UNLE = 11, + COMPCODE_UNGT = 12, + COMPCODE_NE = 13, + COMPCODE_UNGE = 14, + COMPCODE_TRUE = 15 +}; + static void encode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT, HOST_WIDE_INT); static void decode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *); static bool negate_mathfn_p (enum built_in_function); @@ -69,10 +91,12 @@ static tree const_binop (enum tree_code, tree, tree, int); static hashval_t size_htab_hash (const void *); static int size_htab_eq (const void *, const void *); static tree fold_convert_const (enum tree_code, tree, tree); -static enum tree_code invert_tree_comparison (enum tree_code); +static enum tree_code invert_tree_comparison (enum tree_code, bool); static enum tree_code swap_tree_comparison (enum tree_code); -static int comparison_to_compcode (enum tree_code); -static enum tree_code compcode_to_comparison (int); +static enum comparison_code comparison_to_compcode (enum tree_code); +static enum tree_code compcode_to_comparison (enum comparison_code); +static tree combine_comparisons (enum tree_code, enum tree_code, + enum tree_code, tree, tree, tree); static int truth_value_p (enum tree_code); static int operand_equal_for_comparison_p (tree, tree, tree); static int twoval_comparison_p (tree, tree *, tree *, int *); @@ -115,18 +139,6 @@ static tree fold_abs_const (tree, tree); static tree fold_relational_const (enum tree_code, tree, tree, tree); static tree fold_relational_hi_lo (enum tree_code *, const tree, tree *, tree *); -/* The following constants represent a bit based encoding of GCC's - comparison operators. This encoding simplifies transformations - on relational comparison operators, such as AND and OR. */ -#define COMPCODE_FALSE 0 -#define COMPCODE_LT 1 -#define COMPCODE_EQ 2 -#define COMPCODE_LE 3 -#define COMPCODE_GT 4 -#define COMPCODE_NE 5 -#define COMPCODE_GE 6 -#define COMPCODE_TRUE 7 - /* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring overflow. Suppose A, B and SUM have the same respective signs as A1, B1, and SUM1. Then this yields nonzero if overflow occurred during the @@ -2057,11 +2069,15 @@ pedantic_non_lvalue (tree x) /* Given a tree comparison code, return the code that is the logical inverse of the given code. It is not safe to do this for floating-point - comparisons, except for NE_EXPR and EQ_EXPR. */ + comparisons, except for NE_EXPR and EQ_EXPR, so we receive a machine mode + as well: if reversing the comparison is unsafe, return ERROR_MARK. */ static enum tree_code -invert_tree_comparison (enum tree_code code) +invert_tree_comparison (enum tree_code code, bool honor_nans) { + if (honor_nans && flag_trapping_math) + return ERROR_MARK; + switch (code) { case EQ_EXPR: @@ -2069,13 +2085,29 @@ invert_tree_comparison (enum tree_code code) case NE_EXPR: return EQ_EXPR; case GT_EXPR: - return LE_EXPR; + return honor_nans ? UNLE_EXPR : LE_EXPR; case GE_EXPR: - return LT_EXPR; + return honor_nans ? UNLT_EXPR : LT_EXPR; case LT_EXPR: - return GE_EXPR; + return honor_nans ? UNGE_EXPR : GE_EXPR; case LE_EXPR: + return honor_nans ? UNGT_EXPR : GT_EXPR; + case LTGT_EXPR: + return UNEQ_EXPR; + case UNEQ_EXPR: + return LTGT_EXPR; + case UNGT_EXPR: + return LE_EXPR; + case UNGE_EXPR: + return LT_EXPR; + case UNLT_EXPR: + return GE_EXPR; + case UNLE_EXPR: return GT_EXPR; + case ORDERED_EXPR: + return UNORDERED_EXPR; + case UNORDERED_EXPR: + return ORDERED_EXPR; default: abort (); } @@ -2110,7 +2142,7 @@ swap_tree_comparison (enum tree_code code) into a compcode bit-based encoding. This function is the inverse of compcode_to_comparison. */ -static int +static enum comparison_code comparison_to_compcode (enum tree_code code) { switch (code) @@ -2127,6 +2159,22 @@ comparison_to_compcode (enum tree_code code) return COMPCODE_NE; case GE_EXPR: return COMPCODE_GE; + case ORDERED_EXPR: + return COMPCODE_ORD; + case UNORDERED_EXPR: + return COMPCODE_UNORD; + case UNLT_EXPR: + return COMPCODE_UNLT; + case UNEQ_EXPR: + return COMPCODE_UNEQ; + case UNLE_EXPR: + return COMPCODE_UNLE; + case UNGT_EXPR: + return COMPCODE_UNGT; + case LTGT_EXPR: + return COMPCODE_LTGT; + case UNGE_EXPR: + return COMPCODE_UNGE; default: abort (); } @@ -2137,7 +2185,7 @@ comparison_to_compcode (enum tree_code code) inverse of comparison_to_compcode. */ static enum tree_code -compcode_to_comparison (int code) +compcode_to_comparison (enum comparison_code code) { switch (code) { @@ -2153,11 +2201,111 @@ compcode_to_comparison (int code) return NE_EXPR; case COMPCODE_GE: return GE_EXPR; + case COMPCODE_ORD: + return ORDERED_EXPR; + case COMPCODE_UNORD: + return UNORDERED_EXPR; + case COMPCODE_UNLT: + return UNLT_EXPR; + case COMPCODE_UNEQ: + return UNEQ_EXPR; + case COMPCODE_UNLE: + return UNLE_EXPR; + case COMPCODE_UNGT: + return UNGT_EXPR; + case COMPCODE_LTGT: + return LTGT_EXPR; + case COMPCODE_UNGE: + return UNGE_EXPR; default: abort (); } } +/* Return a tree for the comparison which is the combination of + doing the AND or OR (depending on CODE) of the two operations LCODE + and RCODE on the identical operands LL_ARG and LR_ARG. Take into account + the possibility of trapping if the mode has NaNs, and return NULL_TREE + if this makes the transformation invalid. */ + +tree +combine_comparisons (enum tree_code code, enum tree_code lcode, + enum tree_code rcode, tree truth_type, + tree ll_arg, tree lr_arg) +{ + bool honor_nans = HONOR_NANS (TYPE_MODE (TREE_TYPE (ll_arg))); + enum comparison_code lcompcode = comparison_to_compcode (lcode); + enum comparison_code rcompcode = comparison_to_compcode (rcode); + enum comparison_code compcode; + + switch (code) + { + case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR: + compcode = lcompcode & rcompcode; + break; + + case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: + compcode = lcompcode | rcompcode; + break; + + default: + return NULL_TREE; + } + + if (!honor_nans) + { + /* Eliminate unordered comparisons, as well as LTGT and ORD + which are not used unless the mode has NaNs. */ + compcode &= ~COMPCODE_UNORD; + if (compcode == COMPCODE_LTGT) + compcode = COMPCODE_NE; + else if (compcode == COMPCODE_ORD) + compcode = COMPCODE_TRUE; + } + else if (flag_trapping_math) + { + /* Check that the original operation and the optimized ones will trap + under the same condition. */ + bool ltrap = (lcompcode & COMPCODE_UNORD) == 0 + && (lcompcode != COMPCODE_EQ) + && (lcompcode != COMPCODE_ORD); + bool rtrap = (rcompcode & COMPCODE_UNORD) == 0 + && (rcompcode != COMPCODE_EQ) + && (rcompcode != COMPCODE_ORD); + bool trap = (compcode & COMPCODE_UNORD) == 0 + && (compcode != COMPCODE_EQ) + && (compcode != COMPCODE_ORD); + + /* In a short-circuited boolean expression the LHS might be + such that the RHS, if evaluated, will never trap. For + example, in ORD (x, y) && (x < y), we evaluate the RHS only + if neither x nor y is NaN. (This is a mixed blessing: for + example, the expression above will never trap, hence + optimizing it to x < y would be invalid). */ + if ((code == TRUTH_ORIF_EXPR && (lcompcode & COMPCODE_UNORD)) + || (code == TRUTH_ANDIF_EXPR && !(lcompcode & COMPCODE_UNORD))) + rtrap = false; + + /* If the comparison was short-circuited, and only the RHS + trapped, we may now generate a spurious trap. */ + if (rtrap && !ltrap + && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)) + return NULL_TREE; + + /* If we changed the conditions that cause a trap, we lose. */ + if ((ltrap || rtrap) != trap) + return NULL_TREE; + } + + if (compcode == COMPCODE_TRUE) + return fold_convert (truth_type, integer_one_node); + else if (compcode == COMPCODE_FALSE) + return fold_convert (truth_type, integer_zero_node); + else + return fold (build2 (compcode_to_comparison (compcode), + truth_type, ll_arg, lr_arg)); +} + /* Return nonzero if CODE is a tree code that represents a truth value. */ static int @@ -2680,8 +2828,10 @@ pedantic_omit_one_operand (tree type, tree result, tree omitted) /* Return a simplified tree node for the truth-negation of ARG. This never alters ARG itself. We assume that ARG is an operation that - returns a truth value (0 or 1). */ + returns a truth value (0 or 1). + FIXME: one would think we would fold the result, but it causes + problems with the dominator optimizer. */ tree invert_truthvalue (tree arg) { @@ -2697,22 +2847,22 @@ invert_truthvalue (tree arg) if (TREE_CODE_CLASS (code) == '<') { - if (FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0))) - && !flag_unsafe_math_optimizations - && code != NE_EXPR - && code != EQ_EXPR) - return build1 (TRUTH_NOT_EXPR, type, arg); - else if (code == UNORDERED_EXPR - || code == ORDERED_EXPR - || code == UNEQ_EXPR - || code == UNLT_EXPR - || code == UNLE_EXPR - || code == UNGT_EXPR - || code == UNGE_EXPR) + tree op_type = TREE_TYPE (TREE_OPERAND (arg, 0)); + if (FLOAT_TYPE_P (op_type) + && flag_trapping_math + && code != ORDERED_EXPR && code != UNORDERED_EXPR + && code != NE_EXPR && code != EQ_EXPR) return build1 (TRUTH_NOT_EXPR, type, arg); else - return build2 (invert_tree_comparison (code), type, - TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1)); + { + code = invert_tree_comparison (code, + HONOR_NANS (TYPE_MODE (op_type))); + if (code == ERROR_MARK) + return build1 (TRUTH_NOT_EXPR, type, arg); + else + return build2 (code, type, + TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1)); + } } switch (code) @@ -4011,9 +4161,6 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs) if (TREE_CODE_CLASS (lcode) != '<' || TREE_CODE_CLASS (rcode) != '<') return 0; - code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR) - ? TRUTH_AND_EXPR : TRUTH_OR_EXPR); - ll_arg = TREE_OPERAND (lhs, 0); lr_arg = TREE_OPERAND (lhs, 1); rl_arg = TREE_OPERAND (rhs, 0); @@ -4021,46 +4168,31 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs) /* Simplify (x<y) && (x==y) into (x<=y) and related optimizations. */ if (simple_operand_p (ll_arg) - && simple_operand_p (lr_arg) - && !FLOAT_TYPE_P (TREE_TYPE (ll_arg))) + && simple_operand_p (lr_arg)) { - int compcode; - + tree result; if (operand_equal_p (ll_arg, rl_arg, 0) && operand_equal_p (lr_arg, rr_arg, 0)) - { - int lcompcode, rcompcode; - - lcompcode = comparison_to_compcode (lcode); - rcompcode = comparison_to_compcode (rcode); - compcode = (code == TRUTH_AND_EXPR) - ? lcompcode & rcompcode - : lcompcode | rcompcode; - } + { + result = combine_comparisons (code, lcode, rcode, + truth_type, ll_arg, lr_arg); + if (result) + return result; + } else if (operand_equal_p (ll_arg, rr_arg, 0) && operand_equal_p (lr_arg, rl_arg, 0)) - { - int lcompcode, rcompcode; - - rcode = swap_tree_comparison (rcode); - lcompcode = comparison_to_compcode (lcode); - rcompcode = comparison_to_compcode (rcode); - compcode = (code == TRUTH_AND_EXPR) - ? lcompcode & rcompcode - : lcompcode | rcompcode; - } - else - compcode = -1; - - if (compcode == COMPCODE_TRUE) - return fold_convert (truth_type, integer_one_node); - else if (compcode == COMPCODE_FALSE) - return fold_convert (truth_type, integer_zero_node); - else if (compcode != -1) - return build2 (compcode_to_comparison (compcode), - truth_type, ll_arg, lr_arg); + { + result = combine_comparisons (code, lcode, + swap_tree_comparison (rcode), + truth_type, ll_arg, lr_arg); + if (result) + return result; + } } + code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR) + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR); + /* If the RHS can be evaluated unconditionally and its operands are simple, it wins to evaluate the RHS unconditionally on machines with expensive branches. In this case, this isn't a comparison @@ -9856,7 +9988,7 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1) if (code == NE_EXPR || code == GE_EXPR) { invert = 1; - code = invert_tree_comparison (code); + code = invert_tree_comparison (code, false); } /* Compute a result for LT or EQ if args permit; |