diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 4513d40cda5..054ee524c7a 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 c2cf1a94f94..632a241a964 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 cbb4bf0b32d..4d290ad3c25 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<> " "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 9a2ff6227b4..466be20f155 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);