diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 318b12f554ab67979a9bb52c088bbb7a0f8f2380..dcaa0b67b4938d537c94a6c54397e0b7333124f7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2004-03-11 Roger Sayle <roger@eyesopen.com> + + * fold-const.c (negate_expr_p) <RSHIFT_EXPR>: We can optimize + -((int)X>>C) where C is an integer constant one bit less than the + size of X into (unsigned)X>>C. Similarly for unsigned->signed. + (negate_expr) <RSHIFT_EXPR>: Implement the above transformations. + + * simplify-rtx.c (simplify_unary_operation): Also implement the + above transformations at the RTL level. + 2004-03-11 Alan Modra <amodra@bigpond.net.au> * real.c (encode_ibm_extended): Do round low word. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 58b6c70df4c65b5e05dff67c52a42629f46e34e8..5e18d6862ac09477729a5d5fd99250a9f2ba2fc9 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -920,6 +920,18 @@ negate_expr_p (tree t) return negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1))); break; + case RSHIFT_EXPR: + /* Optimize -((int)x >> 31) into (unsigned)x >> 31. */ + if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) + { + tree op1 = TREE_OPERAND (t, 1); + if (TREE_INT_CST_HIGH (op1) == 0 + && (unsigned HOST_WIDE_INT) (TYPE_PRECISION (type) - 1) + == TREE_INT_CST_LOW (op1)) + return true; + } + break; + default: break; } @@ -1065,6 +1077,25 @@ negate_expr (tree t) } break; + case RSHIFT_EXPR: + /* Optimize -((int)x >> 31) into (unsigned)x >> 31. */ + if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST) + { + tree op1 = TREE_OPERAND (t, 1); + if (TREE_INT_CST_HIGH (op1) == 0 + && (unsigned HOST_WIDE_INT) (TYPE_PRECISION (type) - 1) + == TREE_INT_CST_LOW (op1)) + { + tree ntype = TREE_UNSIGNED (type) + ? (*lang_hooks.types.signed_type) (type) + : (*lang_hooks.types.unsigned_type) (type); + tree temp = fold_convert (ntype, TREE_OPERAND (t, 0)); + temp = fold (build2 (RSHIFT_EXPR, ntype, temp, op1)); + return fold_convert (type, temp); + } + } + break; + default: break; } diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 3647c2440774aebdc59b08fc535f324290311504..2846bb7a80d304e1e97e760cf1f7bb2bae596739 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -1013,6 +1013,22 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode, XEXP (op, 1)); } + /* (neg (ashiftrt X C)) can be replaced by (lshiftrt X C) when + C is equal to the width of MODE minus 1. */ + if (GET_CODE (op) == ASHIFTRT + && GET_CODE (XEXP (op, 1)) == CONST_INT + && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1) + return simplify_gen_binary (LSHIFTRT, mode, + XEXP (op, 0), XEXP (op, 1)); + + /* (neg (lshiftrt X C)) can be replaced by (ashiftrt X C) when + C is equal to the width of MODE minus 1. */ + if (GET_CODE (op) == LSHIFTRT + && GET_CODE (XEXP (op, 1)) == CONST_INT + && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1) + return simplify_gen_binary (ASHIFTRT, mode, + XEXP (op, 0), XEXP (op, 1)); + break; case SIGN_EXTEND: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fb762d54db650fb1feb22ed37dc9defe678fff94..90916b8b98a76f5b205c3581ff0e206b2589bf0f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-03-11 Roger Sayle <roger@eyesopen.com> + + * gcc.c-torture/execute/20040311-1.c: New test case. + 2004-03-11 Mark Mitchell <mark@codesourcery.com> PR c++/14476 diff --git a/gcc/testsuite/gcc.c-torture/execute/20040311-1.c b/gcc/testsuite/gcc.c-torture/execute/20040311-1.c new file mode 100644 index 0000000000000000000000000000000000000000..013d869abf4de1f483d9ba815c703bfb686d9e19 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20040311-1.c @@ -0,0 +1,68 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Check that constant folding and RTL simplification of -(x >> y) doesn't + break anything and produces the expected results. + + Written by Roger Sayle, 11th March 2004. */ + +extern void abort (void); + +#define INT_BITS (sizeof(int)*8) + +int test1(int x) +{ + return -(x >> (INT_BITS-1)); +} + +int test2(unsigned int x) +{ + return -((int)(x >> (INT_BITS-1))); +} + +int test3(int x) +{ + int y; + y = INT_BITS-1; + return -(x >> y); +} + +int test4(unsigned int x) +{ + int y; + y = INT_BITS-1; + return -((int)(x >> y)); +} + +int main() +{ + if (test1(0) != 0) + abort (); + if (test1(1) != 0) + abort (); + if (test1(-1) != 1) + abort (); + + if (test2(0) != 0) + abort (); + if (test2(1) != 0) + abort (); + if (test2((unsigned int)-1) != -1) + abort (); + + if (test3(0) != 0) + abort (); + if (test3(1) != 0) + abort (); + if (test3(-1) != 1) + abort (); + + if (test4(0) != 0) + abort (); + if (test4(1) != 0) + abort (); + if (test4((unsigned int)-1) != -1) + abort (); + + return 0; +} +