aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/constexpr.c15
-rw-r--r--gcc/fold-const.c27
-rw-r--r--gcc/match.pd3
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr96929.c21
-rw-r--r--gcc/tree-ssa-ccp.c8
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);