diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/constexpr.c | 15 | ||||
-rw-r--r-- | gcc/fold-const.c | 27 | ||||
-rw-r--r-- | gcc/match.pd | 3 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/pr96929.c | 21 | ||||
-rw-r--r-- | gcc/tree-ssa-ccp.c | 8 |
5 files changed, 48 insertions, 26 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 4513d40..054ee52 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3162,6 +3162,21 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, if (r == NULL_TREE) r = fold_binary_loc (loc, code, type, lhs, rhs); + if (r == NULL_TREE + && (code == LSHIFT_EXPR || code == RSHIFT_EXPR) + && TREE_CODE (lhs) == INTEGER_CST + && TREE_CODE (rhs) == INTEGER_CST + && wi::neg_p (wi::to_wide (rhs))) + { + /* For diagnostics and -fpermissive emulate previous behavior of + handling shifts by negative amount. */ + tree nrhs = const_unop (NEGATE_EXPR, TREE_TYPE (rhs), rhs); + if (nrhs) + r = fold_binary_loc (loc, + code == LSHIFT_EXPR ? RSHIFT_EXPR : LSHIFT_EXPR, + type, lhs, nrhs); + } + if (r == NULL_TREE) { if (lhs == orig_lhs && rhs == orig_rhs) diff --git a/gcc/fold-const.c b/gcc/fold-const.c index c2cf1a9..632a241 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -992,26 +992,19 @@ wide_int_binop (wide_int &res, res = wi::bit_and (arg1, arg2); break; - case RSHIFT_EXPR: case LSHIFT_EXPR: if (wi::neg_p (arg2)) - { - tmp = -arg2; - if (code == RSHIFT_EXPR) - code = LSHIFT_EXPR; - else - code = RSHIFT_EXPR; - } - else - tmp = arg2; + return false; + res = wi::lshift (arg1, arg2); + break; - if (code == RSHIFT_EXPR) - /* It's unclear from the C standard whether shifts can overflow. - The following code ignores overflow; perhaps a C standard - interpretation ruling is needed. */ - res = wi::rshift (arg1, tmp, sign); - else - res = wi::lshift (arg1, tmp); + case RSHIFT_EXPR: + if (wi::neg_p (arg2)) + return false; + /* It's unclear from the C standard whether shifts can overflow. + The following code ignores overflow; perhaps a C standard + interpretation ruling is needed. */ + res = wi::rshift (arg1, arg2, sign); break; case RROTATE_EXPR: diff --git a/gcc/match.pd b/gcc/match.pd index cbb4bf0..4d290ad 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -2900,8 +2900,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* Optimize -1 >> x for arithmetic right shifts. */ (simplify (rshift integer_all_onesp@0 @1) - (if (!TYPE_UNSIGNED (type) - && tree_expr_nonnegative_p (@1)) + (if (!TYPE_UNSIGNED (type)) @0)) /* Optimize (x >> c) << c into x & (-1<<c). */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96929.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96929.c new file mode 100644 index 0000000..65b6147 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96929.c @@ -0,0 +1,21 @@ +/* PR tree-optimization/96929 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump "baz \\\(\\\);" "optimized" } } */ +/* { dg-final { scan-tree-dump-times "return -1;" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-not " >> " "optimized" } } */ + +int baz (void); + +int +foo (void) +{ + return -1 >> baz (); +} + +int +bar (int y) +{ + int z = -1; + return z >> y; +} diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 9a2ff62..466be20 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -1432,13 +1432,7 @@ bit_value_binop (enum tree_code code, signop sgn, int width, else { if (wi::neg_p (shift)) - { - shift = -shift; - if (code == RSHIFT_EXPR) - code = LSHIFT_EXPR; - else - code = RSHIFT_EXPR; - } + break; if (code == RSHIFT_EXPR) { *mask = wi::rshift (wi::ext (r1mask, width, sgn), shift, sgn); |