From 8d1628eb33d4f53832d6d4be2b0021353057a370 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 19 Jul 2017 14:31:59 +0200 Subject: [PATCH] re PR tree-optimization/81346 (Missed constant propagation into comparison) PR tree-optimization/81346 * fold-const.h (fold_div_compare, range_check_type): Declare. * fold-const.c (range_check_type): New function. (build_range_check): Use range_check_type. (fold_div_compare): No longer static, rewritten into a match.pd helper function. (fold_comparison): Don't call fold_div_compare here. * match.pd (X / C1 op C2): New optimization using fold_div_compare as helper function. * gcc.dg/tree-ssa/pr81346-1.c: New test. * gcc.dg/tree-ssa/pr81346-2.c: New test. * gcc.dg/tree-ssa/pr81346-3.c: New test. * gcc.dg/tree-ssa/pr81346-4.c: New test. * gcc.target/i386/umod-3.c: Hide comparison against 1 from the compiler to avoid X / C1 op C2 optimization to trigger. From-SVN: r250338 --- gcc/ChangeLog | 12 ++ gcc/fold-const.c | 228 ++++++++-------------- gcc/fold-const.h | 3 + gcc/match.pd | 54 +++++ gcc/testsuite/ChangeLog | 10 + gcc/testsuite/gcc.dg/tree-ssa/pr81346-1.c | 37 ++++ gcc/testsuite/gcc.dg/tree-ssa/pr81346-2.c | 37 ++++ gcc/testsuite/gcc.dg/tree-ssa/pr81346-3.c | 109 +++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr81346-4.c | 79 ++++++++ gcc/testsuite/gcc.target/i386/umod-3.c | 8 +- 10 files changed, 430 insertions(+), 147 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr81346-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr81346-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr81346-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr81346-4.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index be964c6ab9e..e6e7f9d01b1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2017-07-19 Jakub Jelinek + + PR tree-optimization/81346 + * fold-const.h (fold_div_compare, range_check_type): Declare. + * fold-const.c (range_check_type): New function. + (build_range_check): Use range_check_type. + (fold_div_compare): No longer static, rewritten into + a match.pd helper function. + (fold_comparison): Don't call fold_div_compare here. + * match.pd (X / C1 op C2): New optimization using fold_div_compare + as helper function. + 2017-07-19 Nathan Sidwell * tree.h (TYPE_MINVAL, TYPE_MAXVAL): Rename to ... diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 1bcbbb58154..d702de2f97f 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -132,7 +132,6 @@ static tree fold_binary_op_with_conditional_arg (location_t, enum tree_code, tree, tree, tree, tree, tree, int); -static tree fold_div_compare (location_t, enum tree_code, tree, tree, tree); static tree fold_negate_const (tree, tree); static tree fold_not_const (const_tree, tree); static tree fold_relational_const (enum tree_code, tree, tree, tree); @@ -4787,6 +4786,39 @@ maskable_range_p (const_tree low, const_tree high, tree type, tree *mask, return true; } +/* Helper routine for build_range_check and match.pd. Return the type to + perform the check or NULL if it shouldn't be optimized. */ + +tree +range_check_type (tree etype) +{ + /* First make sure that arithmetics in this type is valid, then make sure + that it wraps around. */ + if (TREE_CODE (etype) == ENUMERAL_TYPE || TREE_CODE (etype) == BOOLEAN_TYPE) + etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype), + TYPE_UNSIGNED (etype)); + + if (TREE_CODE (etype) == INTEGER_TYPE && !TYPE_OVERFLOW_WRAPS (etype)) + { + tree utype, minv, maxv; + + /* Check if (unsigned) INT_MAX + 1 == (unsigned) INT_MIN + for the type in question, as we rely on this here. */ + utype = unsigned_type_for (etype); + maxv = fold_convert (utype, TYPE_MAX_VALUE (etype)); + maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1, + build_int_cst (TREE_TYPE (maxv), 1), 1); + minv = fold_convert (utype, TYPE_MIN_VALUE (etype)); + + if (integer_zerop (range_binop (NE_EXPR, integer_type_node, + minv, 1, maxv, 1))) + etype = utype; + else + return NULL_TREE; + } + return etype; +} + /* Given a range, LOW, HIGH, and IN_P, an expression, EXP, and a result type, TYPE, return an expression to test if EXP is in (or out of, depending on IN_P) the range. Return 0 if the test couldn't be created. */ @@ -4869,31 +4901,10 @@ build_range_check (location_t loc, tree type, tree exp, int in_p, } /* Optimize (c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low). - This requires wrap-around arithmetics for the type of the expression. - First make sure that arithmetics in this type is valid, then make sure - that it wraps around. */ - if (TREE_CODE (etype) == ENUMERAL_TYPE || TREE_CODE (etype) == BOOLEAN_TYPE) - etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype), - TYPE_UNSIGNED (etype)); - - if (TREE_CODE (etype) == INTEGER_TYPE && !TYPE_OVERFLOW_WRAPS (etype)) - { - tree utype, minv, maxv; - - /* Check if (unsigned) INT_MAX + 1 == (unsigned) INT_MIN - for the type in question, as we rely on this here. */ - utype = unsigned_type_for (etype); - maxv = fold_convert_loc (loc, utype, TYPE_MAX_VALUE (etype)); - maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1, - build_int_cst (TREE_TYPE (maxv), 1), 1); - minv = fold_convert_loc (loc, utype, TYPE_MIN_VALUE (etype)); - - if (integer_zerop (range_binop (NE_EXPR, integer_type_node, - minv, 1, maxv, 1))) - etype = utype; - else - return 0; - } + This requires wrap-around arithmetics for the type of the expression. */ + etype = range_check_type (etype); + if (etype == NULL_TREE) + return NULL_TREE; high = fold_convert_loc (loc, etype, high); low = fold_convert_loc (loc, etype, low); @@ -6548,65 +6559,55 @@ fold_real_zero_addition_p (const_tree type, const_tree addend, int negate) return negate && !HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (type)); } -/* Subroutine of fold() that optimizes comparisons of a division by +/* Subroutine of match.pd that optimizes comparisons of a division by a nonzero integer constant against an integer constant, i.e. X/C1 op C2. CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR, - GE_EXPR or LE_EXPR. TYPE is the type of the result and ARG0 and ARG1 - are the operands of the comparison. ARG1 must be a TREE_REAL_CST. - - The function returns the constant folded tree if a simplification - can be made, and NULL_TREE otherwise. */ + GE_EXPR or LE_EXPR. ARG01 and ARG1 must be a INTEGER_CST. */ -static tree -fold_div_compare (location_t loc, - enum tree_code code, tree type, tree arg0, tree arg1) +enum tree_code +fold_div_compare (enum tree_code code, tree c1, tree c2, tree *lo, + tree *hi, bool *neg_overflow) { - tree prod, tmp, hi, lo; - tree arg00 = TREE_OPERAND (arg0, 0); - tree arg01 = TREE_OPERAND (arg0, 1); - signop sign = TYPE_SIGN (TREE_TYPE (arg0)); - bool neg_overflow = false; + tree prod, tmp, type = TREE_TYPE (c1); + signop sign = TYPE_SIGN (type); bool overflow; /* We have to do this the hard way to detect unsigned overflow. - prod = int_const_binop (MULT_EXPR, arg01, arg1); */ - wide_int val = wi::mul (arg01, arg1, sign, &overflow); - prod = force_fit_type (TREE_TYPE (arg00), val, -1, overflow); - neg_overflow = false; + prod = int_const_binop (MULT_EXPR, c1, c2); */ + wide_int val = wi::mul (c1, c2, sign, &overflow); + prod = force_fit_type (type, val, -1, overflow); + *neg_overflow = false; if (sign == UNSIGNED) { - tmp = int_const_binop (MINUS_EXPR, arg01, - build_int_cst (TREE_TYPE (arg01), 1)); - lo = prod; + tmp = int_const_binop (MINUS_EXPR, c1, build_int_cst (type, 1)); + *lo = prod; - /* Likewise hi = int_const_binop (PLUS_EXPR, prod, tmp). */ + /* Likewise *hi = int_const_binop (PLUS_EXPR, prod, tmp). */ val = wi::add (prod, tmp, sign, &overflow); - hi = force_fit_type (TREE_TYPE (arg00), val, - -1, overflow | TREE_OVERFLOW (prod)); + *hi = force_fit_type (type, val, -1, overflow | TREE_OVERFLOW (prod)); } - else if (tree_int_cst_sgn (arg01) >= 0) + else if (tree_int_cst_sgn (c1) >= 0) { - tmp = int_const_binop (MINUS_EXPR, arg01, - build_int_cst (TREE_TYPE (arg01), 1)); - switch (tree_int_cst_sgn (arg1)) + tmp = int_const_binop (MINUS_EXPR, c1, build_int_cst (type, 1)); + switch (tree_int_cst_sgn (c2)) { case -1: - neg_overflow = true; - lo = int_const_binop (MINUS_EXPR, prod, tmp); - hi = prod; + *neg_overflow = true; + *lo = int_const_binop (MINUS_EXPR, prod, tmp); + *hi = prod; break; - case 0: - lo = fold_negate_const (tmp, TREE_TYPE (arg0)); - hi = tmp; + case 0: + *lo = fold_negate_const (tmp, type); + *hi = tmp; break; - case 1: - hi = int_const_binop (PLUS_EXPR, prod, tmp); - lo = prod; + case 1: + *hi = int_const_binop (PLUS_EXPR, prod, tmp); + *lo = prod; break; default: @@ -6618,24 +6619,23 @@ fold_div_compare (location_t loc, /* A negative divisor reverses the relational operators. */ code = swap_tree_comparison (code); - tmp = int_const_binop (PLUS_EXPR, arg01, - build_int_cst (TREE_TYPE (arg01), 1)); - switch (tree_int_cst_sgn (arg1)) + tmp = int_const_binop (PLUS_EXPR, c1, build_int_cst (type, 1)); + switch (tree_int_cst_sgn (c2)) { case -1: - hi = int_const_binop (MINUS_EXPR, prod, tmp); - lo = prod; + *hi = int_const_binop (MINUS_EXPR, prod, tmp); + *lo = prod; break; - case 0: - hi = fold_negate_const (tmp, TREE_TYPE (arg0)); - lo = tmp; + case 0: + *hi = fold_negate_const (tmp, type); + *lo = tmp; break; - case 1: - neg_overflow = true; - lo = int_const_binop (PLUS_EXPR, prod, tmp); - hi = prod; + case 1: + *neg_overflow = true; + *lo = int_const_binop (PLUS_EXPR, prod, tmp); + *hi = prod; break; default: @@ -6643,63 +6643,17 @@ fold_div_compare (location_t loc, } } - switch (code) - { - case EQ_EXPR: - if (TREE_OVERFLOW (lo) && TREE_OVERFLOW (hi)) - return omit_one_operand_loc (loc, type, integer_zero_node, arg00); - if (TREE_OVERFLOW (hi)) - return fold_build2_loc (loc, GE_EXPR, type, arg00, lo); - if (TREE_OVERFLOW (lo)) - return fold_build2_loc (loc, LE_EXPR, type, arg00, hi); - return build_range_check (loc, type, arg00, 1, lo, hi); + if (code != EQ_EXPR && code != NE_EXPR) + return code; - case NE_EXPR: - if (TREE_OVERFLOW (lo) && TREE_OVERFLOW (hi)) - return omit_one_operand_loc (loc, type, integer_one_node, arg00); - if (TREE_OVERFLOW (hi)) - return fold_build2_loc (loc, LT_EXPR, type, arg00, lo); - if (TREE_OVERFLOW (lo)) - return fold_build2_loc (loc, GT_EXPR, type, arg00, hi); - return build_range_check (loc, type, arg00, 0, lo, hi); + if (TREE_OVERFLOW (*lo) + || operand_equal_p (*lo, TYPE_MIN_VALUE (type), 0)) + *lo = NULL_TREE; + if (TREE_OVERFLOW (*hi) + || operand_equal_p (*hi, TYPE_MAX_VALUE (type), 0)) + *hi = NULL_TREE; - case LT_EXPR: - if (TREE_OVERFLOW (lo)) - { - tmp = neg_overflow ? integer_zero_node : integer_one_node; - return omit_one_operand_loc (loc, type, tmp, arg00); - } - return fold_build2_loc (loc, LT_EXPR, type, arg00, lo); - - case LE_EXPR: - if (TREE_OVERFLOW (hi)) - { - tmp = neg_overflow ? integer_zero_node : integer_one_node; - return omit_one_operand_loc (loc, type, tmp, arg00); - } - return fold_build2_loc (loc, LE_EXPR, type, arg00, hi); - - case GT_EXPR: - if (TREE_OVERFLOW (hi)) - { - tmp = neg_overflow ? integer_one_node : integer_zero_node; - return omit_one_operand_loc (loc, type, tmp, arg00); - } - return fold_build2_loc (loc, GT_EXPR, type, arg00, hi); - - case GE_EXPR: - if (TREE_OVERFLOW (lo)) - { - tmp = neg_overflow ? integer_one_node : integer_zero_node; - return omit_one_operand_loc (loc, type, tmp, arg00); - } - return fold_build2_loc (loc, GE_EXPR, type, arg00, lo); - - default: - break; - } - - return NULL_TREE; + return code; } @@ -8793,20 +8747,6 @@ fold_comparison (location_t loc, enum tree_code code, tree type, } } - /* We can fold X/C1 op C2 where C1 and C2 are integer constants - into a single range test. */ - if (TREE_CODE (arg0) == TRUNC_DIV_EXPR - && TREE_CODE (arg1) == INTEGER_CST - && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST - && !integer_zerop (TREE_OPERAND (arg0, 1)) - && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1)) - && !TREE_OVERFLOW (arg1)) - { - tem = fold_div_compare (loc, code, type, arg0, arg1); - if (tem != NULL_TREE) - return tem; - } - return NULL_TREE; } diff --git a/gcc/fold-const.h b/gcc/fold-const.h index 7abf4d1bc06..780e5c781b7 100644 --- a/gcc/fold-const.h +++ b/gcc/fold-const.h @@ -88,6 +88,8 @@ extern void fold_undefer_overflow_warnings (bool, const gimple *, int); extern void fold_undefer_and_ignore_overflow_warnings (void); extern bool fold_deferring_overflow_warnings_p (void); extern void fold_overflow_warning (const char*, enum warn_strict_overflow_code); +extern enum tree_code fold_div_compare (enum tree_code, tree, tree, + tree *, tree *, bool *); extern int operand_equal_p (const_tree, const_tree, unsigned int); extern int multiple_of_p (tree, const_tree, const_tree); #define omit_one_operand(T1,T2,T3)\ @@ -175,6 +177,7 @@ extern bool tree_expr_nonnegative_warnv_p (tree, bool *, int = 0); extern tree make_range (tree, int *, tree *, tree *, bool *); extern tree make_range_step (location_t, enum tree_code, tree, tree, tree, tree *, tree *, int *, bool *); +extern tree range_check_type (tree); extern tree build_range_check (location_t, tree, tree, int, tree, tree); extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree, tree); diff --git a/gcc/match.pd b/gcc/match.pd index 979085aba5a..fe270934c03 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1132,6 +1132,60 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (wi::gt_p(@2, 0, TYPE_SIGN (TREE_TYPE (@2)))) (cmp @0 @1)))) +/* X / C1 op C2 into a simple range test. */ +(for cmp (simple_comparison) + (simplify + (cmp (trunc_div:s @0 INTEGER_CST@1) INTEGER_CST@2) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && integer_nonzerop (@1) + && !TREE_OVERFLOW (@1) + && !TREE_OVERFLOW (@2)) + (with { tree lo, hi; bool neg_overflow; + enum tree_code code = fold_div_compare (cmp, @1, @2, &lo, &hi, + &neg_overflow); } + (switch + (if (code == LT_EXPR || code == GE_EXPR) + (if (TREE_OVERFLOW (lo)) + { build_int_cst (type, (code == LT_EXPR) ^ neg_overflow); } + (if (code == LT_EXPR) + (lt @0 { lo; }) + (ge @0 { lo; })))) + (if (code == LE_EXPR || code == GT_EXPR) + (if (TREE_OVERFLOW (hi)) + { build_int_cst (type, (code == LE_EXPR) ^ neg_overflow); } + (if (code == LE_EXPR) + (le @0 { hi; }) + (gt @0 { hi; })))) + (if (!lo && !hi) + { build_int_cst (type, code == NE_EXPR); }) + (if (code == EQ_EXPR && !hi) + (ge @0 { lo; })) + (if (code == EQ_EXPR && !lo) + (le @0 { hi; })) + (if (code == NE_EXPR && !hi) + (lt @0 { lo; })) + (if (code == NE_EXPR && !lo) + (gt @0 { hi; })) + (if (GENERIC) + { build_range_check (UNKNOWN_LOCATION, type, @0, code == EQ_EXPR, + lo, hi); }) + (with + { + tree etype = range_check_type (TREE_TYPE (@0)); + if (etype) + { + if (! TYPE_UNSIGNED (etype)) + etype = unsigned_type_for (etype); + hi = fold_convert (etype, hi); + lo = fold_convert (etype, lo); + hi = const_binop (MINUS_EXPR, etype, hi, lo); + } + } + (if (etype && hi && !TREE_OVERFLOW (hi)) + (if (code == EQ_EXPR) + (le (minus (convert:etype @0) { lo; }) { hi; }) + (gt (minus (convert:etype @0) { lo; }) { hi; }))))))))) + /* X + Z < Y + Z is the same as X < Y when there is no overflow. */ (for op (lt le ge gt) (simplify diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a688b31bbcc..cad1ade6ea8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2017-07-19 Jakub Jelinek + + PR tree-optimization/81346 + * gcc.dg/tree-ssa/pr81346-1.c: New test. + * gcc.dg/tree-ssa/pr81346-2.c: New test. + * gcc.dg/tree-ssa/pr81346-3.c: New test. + * gcc.dg/tree-ssa/pr81346-4.c: New test. + * gcc.target/i386/umod-3.c: Hide comparison against 1 from the + compiler to avoid X / C1 op C2 optimization to trigger. + 2017-07-19 Martin Liska PR sanitizer/63361 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81346-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-1.c new file mode 100644 index 00000000000..c766d6ff996 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-1.c @@ -0,0 +1,37 @@ +/* PR tree-optimization/81346 */ +/* { dg-do compile { target int32 } } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times "return 1;" 32 "optimized" } } */ + +int f00 (int x) { return x / 49152 > -49152; } +int f01 (int x) { int a = 49152, b = -49152; return x / a > b; } +int f02 (int x) { return x / 49152 >= -49152; } +int f03 (int x) { int a = 49152, b = -49152; return x / a >= b; } +int f04 (int x) { return x / 49152 < 49152; } +int f05 (int x) { int a = 49152, b = 49152; return x / a < b; } +int f06 (int x) { return x / 49152 <= 49152; } +int f07 (int x) { int a = 49152, b = 49152; return x / a <= b; } +int f08 (int x) { return x / 46340 >= -46341; } +int f09 (int x) { int a = 46340, b = -46341; return x / a >= b; } +int f10 (int x) { return x / 46340 <= 46341; } +int f11 (int x) { int a = 46340, b = 46341; return x / a <= b; } +int f12 (int x) { return x / 49152 != -49152; } +int f13 (int x) { int a = 49152, b = -49152; return x / a != b; } +int f14 (int x) { return x / 49152 != 49152; } +int f15 (int x) { int a = 49152, b = 49152; return x / a != b; } +int f16 (int x) { return x / -49152 > -49152; } +int f17 (int x) { int a = -49152, b = -49152; return x / a > b; } +int f18 (int x) { return x / -49152 >= -49152; } +int f19 (int x) { int a = -49152, b = -49152; return x / a >= b; } +int f20 (int x) { return x / -49152 < 49152; } +int f21 (int x) { int a = -49152, b = 49152; return x / a < b; } +int f22 (int x) { return x / -49152 <= 49152; } +int f23 (int x) { int a = -49152, b = 49152; return x / a <= b; } +int f24 (int x) { return x / -46340 >= -46341; } +int f25 (int x) { int a = -46340, b = -46341; return x / a >= b; } +int f26 (int x) { return x / -46340 <= 46341; } +int f27 (int x) { int a = -46340, b = 46341; return x / a <= b; } +int f28 (int x) { return x / -49152 != 49152; } +int f29 (int x) { int a = -49152, b = 49152; return x / a != b; } +int f30 (int x) { return x / -49152 != -49152; } +int f31 (int x) { int a = -49152, b = -49152; return x / a != b; } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81346-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-2.c new file mode 100644 index 00000000000..87bad395c3b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-2.c @@ -0,0 +1,37 @@ +/* PR tree-optimization/81346 */ +/* { dg-do compile { target int32 } } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times "return 0;" 32 "optimized" } } */ + +int f00 (int x) { return x / 49152 > 49152; } +int f01 (int x) { int a = 49152, b = 49152; return x / a > b; } +int f02 (int x) { return x / 49152 >= 49152; } +int f03 (int x) { int a = 49152, b = 49152; return x / a >= b; } +int f04 (int x) { return x / 49152 < -49152; } +int f05 (int x) { int a = 49152, b = -49152; return x / a < b; } +int f06 (int x) { return x / 49152 <= -49152; } +int f07 (int x) { int a = 49152, b = -49152; return x / a <= b; } +int f08 (int x) { return x / 46340 > 46341; } +int f09 (int x) { int a = 46340, b = 46341; return x / a > b; } +int f10 (int x) { return x / 46340 < -46341; } +int f11 (int x) { int a = 46340, b = -46341; return x / a < b; } +int f12 (int x) { return x / 49152 == -49152; } +int f13 (int x) { int a = 49152, b = -49152; return x / a == b; } +int f14 (int x) { return x / 49152 == 49152; } +int f15 (int x) { int a = 49152, b = 49152; return x / a == b; } +int f16 (int x) { return x / -49152 > 49152; } +int f17 (int x) { int a = -49152, b = 49152; return x / a > b; } +int f18 (int x) { return x / -49152 >= 49152; } +int f19 (int x) { int a = -49152, b = 49152; return x / a >= b; } +int f20 (int x) { return x / -49152 < -49152; } +int f21 (int x) { int a = -49152, b = -49152; return x / a < b; } +int f22 (int x) { return x / -49152 <= -49152; } +int f23 (int x) { int a = -49152, b = -49152; return x / a <= b; } +int f24 (int x) { return x / -46340 > 46341; } +int f25 (int x) { int a = -46340, b = 46341; return x / a > b; } +int f26 (int x) { return x / -46340 < -46341; } +int f27 (int x) { int a = -46340, b = -46341; return x / a < b; } +int f28 (int x) { return x / -49152 == 49152; } +int f29 (int x) { int a = -49152, b = 49152; return x / a == b; } +int f30 (int x) { return x / -49152 == -49152; } +int f31 (int x) { int a = -49152, b = -49152; return x / a == b; } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81346-3.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-3.c new file mode 100644 index 00000000000..bef64a8746a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-3.c @@ -0,0 +1,109 @@ +/* PR tree-optimization/81346 */ +/* { dg-do compile { target int32 } } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-not " / " "optimized" } } */ + +__attribute__((noinline, noclone)) int f00 (int x) { return x / 46340 > -46341; } +__attribute__((noinline, noclone)) int f01 (int x) { int a = 46340, b = -46341; return x / a > b; } +__attribute__((noinline, noclone)) int f02 (int x) { return x / 46340 >= 46341; } +__attribute__((noinline, noclone)) int f03 (int x) { int a = 46340, b = 46341; return x / a >= b; } +__attribute__((noinline, noclone)) int f04 (int x) { return x / 46340 < 46341; } +__attribute__((noinline, noclone)) int f05 (int x) { int a = 46340, b = 46341; return x / a < b; } +__attribute__((noinline, noclone)) int f06 (int x) { return x / 46340 <= -46341; } +__attribute__((noinline, noclone)) int f07 (int x) { int a = 46340, b = -46341; return x / a <= b; } +__attribute__((noinline, noclone)) int f08 (int x) { return x / 46340 == -46341; } +__attribute__((noinline, noclone)) int f09 (int x) { int a = 46340, b = -46341; return x / a == b; } +__attribute__((noinline, noclone)) int f10 (int x) { return x / 46340 == 46341; } +__attribute__((noinline, noclone)) int f11 (int x) { int a = 46340, b = 46341; return x / a == b; } +__attribute__((noinline, noclone)) int f12 (int x) { return x / 46340 != -46341; } +__attribute__((noinline, noclone)) int f13 (int x) { int a = 46340, b = -46341; return x / a != b; } +__attribute__((noinline, noclone)) int f14 (int x) { return x / 46340 != 46341; } +__attribute__((noinline, noclone)) int f15 (int x) { int a = 46340, b = 46341; return x / a != b; } +__attribute__((noinline, noclone)) int f16 (int x) { return x / 15 > -15; } +__attribute__((noinline, noclone)) int f17 (int x) { int a = 15, b = -15; return x / a > b; } +__attribute__((noinline, noclone)) int f18 (int x) { return x / 15 > 15; } +__attribute__((noinline, noclone)) int f19 (int x) { int a = 15, b = 15; return x / a > b; } +__attribute__((noinline, noclone)) int f20 (int x) { return x / 15 >= -15; } +__attribute__((noinline, noclone)) int f21 (int x) { int a = 15, b = -15; return x / a >= b; } +__attribute__((noinline, noclone)) int f22 (int x) { return x / 15 >= 15; } +__attribute__((noinline, noclone)) int f23 (int x) { int a = 15, b = 15; return x / a >= b; } +__attribute__((noinline, noclone)) int f24 (int x) { return x / 15 < -15; } +__attribute__((noinline, noclone)) int f25 (int x) { int a = 15, b = -15; return x / a < b; } +__attribute__((noinline, noclone)) int f26 (int x) { return x / 15 < 15; } +__attribute__((noinline, noclone)) int f27 (int x) { int a = 15, b = 15; return x / a < b; } +__attribute__((noinline, noclone)) int f28 (int x) { return x / 15 <= -15; } +__attribute__((noinline, noclone)) int f29 (int x) { int a = 15, b = -15; return x / a <= b; } +__attribute__((noinline, noclone)) int f30 (int x) { return x / 15 <= 15; } +__attribute__((noinline, noclone)) int f31 (int x) { int a = 15, b = 15; return x / a <= b; } +__attribute__((noinline, noclone)) int f32 (int x) { return x / 15 == -15; } +__attribute__((noinline, noclone)) int f33 (int x) { int a = 15, b = -15; return x / a == b; } +__attribute__((noinline, noclone)) int f34 (int x) { return x / 15 == 15; } +__attribute__((noinline, noclone)) int f35 (int x) { int a = 15, b = 15; return x / a == b; } +__attribute__((noinline, noclone)) int f36 (int x) { return x / 15 != -15; } +__attribute__((noinline, noclone)) int f37 (int x) { int a = 15, b = -15; return x / a != b; } +__attribute__((noinline, noclone)) int f38 (int x) { return x / 15 != 15; } +__attribute__((noinline, noclone)) int f39 (int x) { int a = 15, b = 15; return x / a != b; } +__attribute__((noinline, noclone)) int f40 (int x) { return x / -46340 > -46341; } +__attribute__((noinline, noclone)) int f41 (int x) { int a = -46340, b = -46341; return x / a > b; } +__attribute__((noinline, noclone)) int f42 (int x) { return x / -46340 >= 46341; } +__attribute__((noinline, noclone)) int f43 (int x) { int a = -46340, b = 46341; return x / a >= b; } +__attribute__((noinline, noclone)) int f44 (int x) { return x / -46340 < 46341; } +__attribute__((noinline, noclone)) int f45 (int x) { int a = -46340, b = 46341; return x / a < b; } +__attribute__((noinline, noclone)) int f46 (int x) { return x / -46340 <= -46341; } +__attribute__((noinline, noclone)) int f47 (int x) { int a = -46340, b = -46341; return x / a <= b; } +__attribute__((noinline, noclone)) int f48 (int x) { return x / -46340 == 46341; } +__attribute__((noinline, noclone)) int f49 (int x) { int a = -46340, b = 46341; return x / a == b; } +__attribute__((noinline, noclone)) int f50 (int x) { return x / -46340 == -46341; } +__attribute__((noinline, noclone)) int f51 (int x) { int a = -46340, b = -46341; return x / a == b; } +__attribute__((noinline, noclone)) int f52 (int x) { return x / -46340 != 46341; } +__attribute__((noinline, noclone)) int f53 (int x) { int a = -46340, b = 46341; return x / a != b; } +__attribute__((noinline, noclone)) int f54 (int x) { return x / -46340 != -46341; } +__attribute__((noinline, noclone)) int f55 (int x) { int a = -46340, b = -46341; return x / a != b; } +__attribute__((noinline, noclone)) int f56 (int x) { return x / -15 > 15; } +__attribute__((noinline, noclone)) int f57 (int x) { int a = -15, b = 15; return x / a > b; } +__attribute__((noinline, noclone)) int f58 (int x) { return x / -15 > -15; } +__attribute__((noinline, noclone)) int f59 (int x) { int a = -15, b = -15; return x / a > b; } +__attribute__((noinline, noclone)) int f60 (int x) { return x / -15 >= 15; } +__attribute__((noinline, noclone)) int f61 (int x) { int a = -15, b = 15; return x / a >= b; } +__attribute__((noinline, noclone)) int f62 (int x) { return x / -15 >= -15; } +__attribute__((noinline, noclone)) int f63 (int x) { int a = -15, b = -15; return x / a >= b; } +__attribute__((noinline, noclone)) int f64 (int x) { return x / -15 < 15; } +__attribute__((noinline, noclone)) int f65 (int x) { int a = -15, b = 15; return x / a < b; } +__attribute__((noinline, noclone)) int f66 (int x) { return x / -15 < -15; } +__attribute__((noinline, noclone)) int f67 (int x) { int a = -15, b = -15; return x / a < b; } +__attribute__((noinline, noclone)) int f68 (int x) { return x / -15 <= 15; } +__attribute__((noinline, noclone)) int f69 (int x) { int a = -15, b = 15; return x / a <= b; } +__attribute__((noinline, noclone)) int f70 (int x) { return x / -15 <= -15; } +__attribute__((noinline, noclone)) int f71 (int x) { int a = -15, b = -15; return x / a <= b; } +__attribute__((noinline, noclone)) int f72 (int x) { return x / -15 == 15; } +__attribute__((noinline, noclone)) int f73 (int x) { int a = -15, b = 15; return x / a == b; } +__attribute__((noinline, noclone)) int f74 (int x) { return x / -15 == -15; } +__attribute__((noinline, noclone)) int f75 (int x) { int a = -15, b = -15; return x / a == b; } +__attribute__((noinline, noclone)) int f76 (int x) { return x / -15 != 15; } +__attribute__((noinline, noclone)) int f77 (int x) { int a = -15, b = 15; return x / a != b; } +__attribute__((noinline, noclone)) int f78 (int x) { return x / -15 != -15; } +__attribute__((noinline, noclone)) int f79 (int x) { int a = -15, b = -15; return x / a != b; } +__attribute__((noinline, noclone)) int f80 (int x) { return x / -15 > 0; } +__attribute__((noinline, noclone)) int f81 (int x) { int a = -15, b = 0; return x / a > b; } +__attribute__((noinline, noclone)) int f82 (int x) { return x / 15 > 0; } +__attribute__((noinline, noclone)) int f83 (int x) { int a = 15, b = 0; return x / a > b; } +__attribute__((noinline, noclone)) int f84 (int x) { return x / -15 >= 0; } +__attribute__((noinline, noclone)) int f85 (int x) { int a = -15, b = 0; return x / a >= b; } +__attribute__((noinline, noclone)) int f86 (int x) { return x / 15 >= 0; } +__attribute__((noinline, noclone)) int f87 (int x) { int a = 15, b = 0; return x / a >= b; } +__attribute__((noinline, noclone)) int f88 (int x) { return x / -15 < 0; } +__attribute__((noinline, noclone)) int f89 (int x) { int a = -15, b = 0; return x / a < b; } +__attribute__((noinline, noclone)) int f90 (int x) { return x / 15 < 0; } +__attribute__((noinline, noclone)) int f91 (int x) { int a = 15, b = 0; return x / a < b; } +__attribute__((noinline, noclone)) int f92 (int x) { return x / -15 <= 0; } +__attribute__((noinline, noclone)) int f93 (int x) { int a = -15, b = 0; return x / a <= b; } +__attribute__((noinline, noclone)) int f94 (int x) { return x / 15 <= 0; } +__attribute__((noinline, noclone)) int f95 (int x) { int a = 15, b = 0; return x / a <= b; } +__attribute__((noinline, noclone)) int f96 (int x) { return x / -15 == 0; } +__attribute__((noinline, noclone)) int f97 (int x) { int a = -15, b = 0; return x / a == b; } +__attribute__((noinline, noclone)) int f98 (int x) { return x / 15 == 0; } +__attribute__((noinline, noclone)) int f99 (int x) { int a = 15, b = 0; return x / a == b; } +__attribute__((noinline, noclone)) int f100 (int x) { return x / -15 != 0; } +__attribute__((noinline, noclone)) int f101 (int x) { int a = -15, b = 0; return x / a != b; } +__attribute__((noinline, noclone)) int f102 (int x) { return x / 15 != 0; } +__attribute__((noinline, noclone)) int f103 (int x) { int a = 15, b = 0; return x / a != b; } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81346-4.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-4.c new file mode 100644 index 00000000000..f93ad468c3f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr81346-4.c @@ -0,0 +1,79 @@ +/* PR tree-optimization/81346 */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#include "pr81346-3.c" + +#define INT_MAX __INT_MAX__ +#define INT_MIN (-__INT_MAX__ - 1) + +extern void abort (void); + +int +main () +{ + if (__CHAR_BIT__ != 8 || __SIZEOF_INT__ != 4) + return 0; +#define TEST(fn1, fn2, v1, v2) \ + do { \ + int w1 = v1; int w2 = v2; \ + int in = 1; if (w1 > w2) { in = w1; w1 = w2; w2 = in; in = 0; } \ + if (w1 != INT_MIN) { if (fn1 (w1 - 1) != !in || fn2 (w1 - 1) != !in) abort (); } \ + if (fn1 (w1) != in || fn2 (w1) != in) abort (); \ + if (fn1 (w2) != in || fn2 (w2) != in) abort (); \ + if (w2 != INT_MAX) { if (fn1 (w2 + 1) != !in || fn2 (w2 + 1) != !in) abort (); } \ + } while (0) +TEST (f00, f01, -2147441939, INT_MAX); +TEST (f02, f03, 2147441940, INT_MAX); +TEST (f04, f05, INT_MIN, 2147441939); +TEST (f06, f07, INT_MIN, -2147441940); +TEST (f08, f09, INT_MIN, -2147441940); +TEST (f10, f11, 2147441940, INT_MAX); +TEST (f12, f13, -2147441939, INT_MAX); +TEST (f14, f15, INT_MIN, 2147441939); +TEST (f16, f17, -224, INT_MAX); +TEST (f18, f19, 240, INT_MAX); +TEST (f20, f21, -239, INT_MAX); +TEST (f22, f23, 225, INT_MAX); +TEST (f24, f25, INT_MIN, -240); +TEST (f26, f27, INT_MIN, 224); +TEST (f28, f29, INT_MIN, -225); +TEST (f30, f31, INT_MIN, 239); +TEST (f32, f33, -239, -225); +TEST (f34, f35, 225, 239); +TEST (f36, f37, -225, -239); +TEST (f38, f39, 239, 225); +TEST (f40, f41, INT_MIN, 2147441939); +TEST (f42, f43, INT_MIN, -2147441940); +TEST (f44, f45, -2147441939, INT_MAX); +TEST (f46, f47, 2147441940, INT_MAX); +TEST (f48, f49, INT_MIN, -2147441940); +TEST (f50, f51, 2147441940, INT_MAX); +TEST (f52, f53, -2147441939, INT_MAX); +TEST (f54, f55, INT_MIN, 2147441939); +TEST (f56, f57, INT_MIN, -240); +TEST (f58, f59, INT_MIN, 224); +TEST (f60, f61, INT_MIN, -225); +TEST (f62, f63, INT_MIN, 239); +TEST (f64, f65, -224, INT_MAX); +TEST (f66, f67, 240, INT_MAX); +TEST (f68, f69, -239, INT_MAX); +TEST (f70, f71, 225, INT_MAX); +TEST (f72, f73, -239, -225); +TEST (f74, f75, 225, 239); +TEST (f76, f77, -225, -239); +TEST (f78, f79, 239, 225); +TEST (f80, f81, INT_MIN, -15); +TEST (f82, f83, 15, INT_MAX); +TEST (f84, f85, INT_MIN, 14); +TEST (f86, f87, -14, INT_MAX); +TEST (f88, f89, 15, INT_MAX); +TEST (f90, f91, INT_MIN, -15); +TEST (f92, f93, -14, INT_MAX); +TEST (f94, f95, INT_MIN, 14); +TEST (f96, f97, -14, 14); +TEST (f98, f99, -14, 14); +TEST (f100, f101, 14, -14); +TEST (f102, f103, 14, -14); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/umod-3.c b/gcc/testsuite/gcc.target/i386/umod-3.c index e1fb988263a..609ab520712 100644 --- a/gcc/testsuite/gcc.target/i386/umod-3.c +++ b/gcc/testsuite/gcc.target/i386/umod-3.c @@ -9,9 +9,11 @@ int main () { unsigned char cy; - - cy = cx / 6; if (cy != 1) exit (1); - cy = cx % 6; if (cy != 1) exit (1); + unsigned char cz = 1; + asm ("" : "+q" (cz)); + + cy = cx / 6; if (cy != cz) exit (1); + cy = cx % 6; if (cy != cz) exit (1); exit(0); } -- 2.30.2