diff options
author | Roger Sayle <roger@eyesopen.com> | 2004-04-09 21:39:14 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2004-04-09 21:39:14 +0000 |
commit | 0b24db885b67a354b09746a9af49a5b4333cc249 (patch) | |
tree | 48b3dead6c152c128f09b4ca6fa75231cacb39d9 /gcc | |
parent | ce58118c3d596e5732e17cbca57b6e7518b50d70 (diff) | |
download | gcc-0b24db885b67a354b09746a9af49a5b4333cc249.zip gcc-0b24db885b67a354b09746a9af49a5b4333cc249.tar.gz gcc-0b24db885b67a354b09746a9af49a5b4333cc249.tar.bz2 |
simplify-rtx.c (mode_signbit_p): New function to check whether an RTX is an immediate constant that represents...
* simplify-rtx.c (mode_signbit_p): New function to check whether
an RTX is an immediate constant that represents the most significant
bit of a given machine mode.
(simplify_unary_operation) <NOT>: Optimize ~(X+C) as X ^ ~C, where
C is the sign bit.
(simplify_binary_operation) <PLUS>: Optimize (X^C1) + C2 as X^(C1^C2)
when C2 is the sign bit.
(simplify_binary_operation) <XOR>: Canonicalize X^C as X+C when C
is the sign bit. Optimize (X+C1) ^ C2 as X^(C1^C2) when C1 is the
sign bit.
* gcc.c-torture/execute/20040409-1.c: New test case.
* gcc.c-torture/execute/20040409-2.c: New test case.
* gcc.c-torture/execute/20040409-3.c: New test case.
From-SVN: r80568
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/simplify-rtx.c | 75 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/20040409-1.c | 142 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/20040409-2.c | 243 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/20040409-3.c | 142 |
6 files changed, 620 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f96a2b4..3a41ae9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2004-04-09 Roger Sayle <roger@eyesopen.com> + + * simplify-rtx.c (mode_signbit_p): New function to check whether + an RTX is an immediate constant that represents the most significant + bit of a given machine mode. + (simplify_unary_operation) <NOT>: Optimize ~(X+C) as X ^ ~C, where + C is the sign bit. + (simplify_binary_operation) <PLUS>: Optimize (X^C1) + C2 as X^(C1^C2) + when C2 is the sign bit. + (simplify_binary_operation) <XOR>: Canonicalize X^C as X+C when C + is the sign bit. Optimize (X+C1) ^ C2 as X^(C1^C2) when C1 is the + sign bit. + 2004-04-09 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> * builtins.c (mathfn_built_in): Check TYPE_MAIN_VARIANT, not diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 0d283cd..49f2d37 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -50,6 +50,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0)) static rtx neg_const_int (enum machine_mode, rtx); +static bool mode_signbit_p (enum machine_mode, rtx); static int simplify_plus_minus_op_data_cmp (const void *, const void *); static rtx simplify_plus_minus (enum rtx_code, enum machine_mode, rtx, rtx, int); @@ -66,6 +67,39 @@ neg_const_int (enum machine_mode mode, rtx i) return gen_int_mode (- INTVAL (i), mode); } +/* Test whether expression, X, is an immediate constant that represents + the most significant bit of machine mode MODE. */ + +static bool +mode_signbit_p (enum machine_mode mode, rtx x) +{ + unsigned HOST_WIDE_INT val; + unsigned int width; + + if (GET_MODE_CLASS (mode) != MODE_INT) + return false; + + width = GET_MODE_BITSIZE (mode); + if (width == 0) + return false; + + if (width <= HOST_BITS_PER_WIDE_INT + && GET_CODE (x) == CONST_INT) + val = INTVAL (x); + else if (width <= 2 * HOST_BITS_PER_WIDE_INT + && GET_CODE (x) == CONST_DOUBLE + && CONST_DOUBLE_LOW (x) == 0) + { + val = CONST_DOUBLE_HIGH (x); + width -= HOST_BITS_PER_WIDE_INT; + } + else + return false; + + if (width < HOST_BITS_PER_WIDE_INT) + val &= ((unsigned HOST_WIDE_INT) 1 << width) - 1; + return val == ((unsigned HOST_WIDE_INT) 1 << (width - 1)); +} /* Make a binary operation by properly ordering the operands and seeing if the expression folds. */ @@ -912,6 +946,16 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode, mode)) != 0) return simplify_gen_binary (XOR, mode, XEXP (op, 0), temp); + /* (not (plus X C)) for signbit C is (xor X D) with D = ~C. */ + if (GET_CODE (op) == PLUS + && GET_CODE (XEXP (op, 1)) == CONST_INT + && mode_signbit_p (mode, XEXP (op, 1)) + && (temp = simplify_unary_operation (NOT, mode, + XEXP (op, 1), + mode)) != 0) + return simplify_gen_binary (XOR, mode, XEXP (op, 0), temp); + + /* (not (ashift 1 X)) is (rotate ~1 X). We used to do this for operands other than 1, but that is not valid. We could do a @@ -1514,6 +1558,17 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode, } } + /* (plus (xor X C1) C2) is (xor X (C1^C2)) if C2 is signbit. */ + if ((GET_CODE (op1) == CONST_INT + || GET_CODE (op1) == CONST_DOUBLE) + && GET_CODE (op0) == XOR + && (GET_CODE (XEXP (op0, 1)) == CONST_INT + || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE) + && mode_signbit_p (mode, op1)) + return simplify_gen_binary (XOR, mode, XEXP (op0, 0), + simplify_gen_binary (XOR, mode, op1, + XEXP (op0, 1))); + /* If one of the operands is a PLUS or a MINUS, see if we can simplify this by the associative law. Don't use the associative law for floating point. @@ -1797,9 +1852,27 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode, && ((INTVAL (trueop1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))) return simplify_gen_unary (NOT, mode, op0, mode); - if (trueop0 == trueop1 && ! side_effects_p (op0) + if (trueop0 == trueop1 + && ! side_effects_p (op0) && GET_MODE_CLASS (mode) != MODE_CC) return const0_rtx; + + /* Canonicalize XOR of the most significant bit to PLUS. */ + if ((GET_CODE (op1) == CONST_INT + || GET_CODE (op1) == CONST_DOUBLE) + && mode_signbit_p (mode, op1)) + return simplify_gen_binary (PLUS, mode, op0, op1); + /* (xor (plus X C1) C2) is (xor X (C1^C2)) if C1 is signbit. */ + if ((GET_CODE (op1) == CONST_INT + || GET_CODE (op1) == CONST_DOUBLE) + && GET_CODE (op0) == PLUS + && (GET_CODE (XEXP (op0, 1)) == CONST_INT + || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE) + && mode_signbit_p (mode, XEXP (op0, 1))) + return simplify_gen_binary (XOR, mode, XEXP (op0, 0), + simplify_gen_binary (XOR, mode, op1, + XEXP (op0, 1))); + tem = simplify_associative_operation (code, mode, op0, op1); if (tem) return tem; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1161a0d..40d5e47 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2004-04-09 Roger Sayle <roger@eyesopen.com> + + * gcc.c-torture/execute/20040409-1.c: New test case. + * gcc.c-torture/execute/20040409-2.c: New test case. + * gcc.c-torture/execute/20040409-3.c: New test case. + 2004-04-09 Andrew Pinski <pinskia@physics.uc.edu> * gcc.dg/20040409-1.c: New test. diff --git a/gcc/testsuite/gcc.c-torture/execute/20040409-1.c b/gcc/testsuite/gcc.c-torture/execute/20040409-1.c new file mode 100644 index 0000000..1e81edb --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20040409-1.c @@ -0,0 +1,142 @@ +#include <limits.h> + +extern void abort (); + +int test1(int x) +{ + return x ^ INT_MIN; +} + +unsigned int test1u(unsigned int x) +{ + return x ^ (unsigned int)INT_MIN; +} + +int test2(int x) +{ + return x + INT_MIN; +} + +unsigned int test2u(unsigned int x) +{ + return x + (unsigned int)INT_MIN; +} + +int test3(int x) +{ + return x - INT_MIN; +} + +unsigned int test3u(unsigned int x) +{ + return x - (unsigned int)INT_MIN; +} + +int test4(int x) +{ + int y = INT_MIN; + return x ^ y; +} + +unsigned int test4u(unsigned int x) +{ + unsigned int y = (unsigned int)INT_MIN; + return x ^ y; +} + +int test5(int x) +{ + int y = INT_MIN; + return x + y; +} + +unsigned int test5u(unsigned int x) +{ + unsigned int y = (unsigned int)INT_MIN; + return x + y; +} + +int test6(int x) +{ + int y = INT_MIN; + return x - y; +} + +unsigned int test6u(unsigned int x) +{ + unsigned int y = (unsigned int)INT_MIN; + return x - y; +} + + + +void test(int a, int b) +{ + if (test1(a) != b) + abort(); + if (test2(a) != b) + abort(); + if (test3(a) != b) + abort(); + if (test4(a) != b) + abort(); + if (test5(a) != b) + abort(); + if (test6(a) != b) + abort(); +} + +void testu(unsigned int a, unsigned int b) +{ + if (test1u(a) != b) + abort(); + if (test2u(a) != b) + abort(); + if (test3u(a) != b) + abort(); + if (test4u(a) != b) + abort(); + if (test5u(a) != b) + abort(); + if (test6u(a) != b) + abort(); +} + + +int main() +{ +#if INT_MAX == 2147483647 + test(0x00000000,0x80000000); + test(0x80000000,0x00000000); + test(0x12345678,0x92345678); + test(0x92345678,0x12345678); + test(0x7fffffff,0xffffffff); + test(0xffffffff,0x7fffffff); + + testu(0x00000000,0x80000000); + testu(0x80000000,0x00000000); + testu(0x12345678,0x92345678); + testu(0x92345678,0x12345678); + testu(0x7fffffff,0xffffffff); + testu(0xffffffff,0x7fffffff); +#endif + +#if INT_MAX == 32767 + test(0x0000,0x8000); + test(0x8000,0x0000); + test(0x1234,0x9234); + test(0x9234,0x1234); + test(0x7fff,0xffff); + test(0xffff,0x7fff); + + testu(0x0000,0x8000); + testu(0x8000,0x0000); + testu(0x1234,0x9234); + testu(0x9234,0x1234); + testu(0x7fff,0xffff); + testu(0xffff,0x7fff); +#endif + + return 0; +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/20040409-2.c b/gcc/testsuite/gcc.c-torture/execute/20040409-2.c new file mode 100644 index 0000000..5bec7ee --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20040409-2.c @@ -0,0 +1,243 @@ +#include <limits.h> + +extern void abort (); + +int test1(int x) +{ + return (x ^ INT_MIN) ^ 0x1234; +} + +unsigned int test1u(unsigned int x) +{ + return (x ^ (unsigned int)INT_MIN) ^ 0x1234; +} + +int test2(int x) +{ + return (x ^ 0x1234) ^ INT_MIN; +} + +unsigned int test2u(unsigned int x) +{ + return (x ^ 0x1234) ^ (unsigned int)INT_MIN; +} + +int test3(int x) +{ + return (x + INT_MIN) ^ 0x1234; +} + +unsigned int test3u(unsigned int x) +{ + return (x + (unsigned int)INT_MIN) ^ 0x1234; +} + +int test4(int x) +{ + return (x ^ 0x1234) + INT_MIN; +} + +unsigned int test4u(unsigned int x) +{ + return (x ^ 0x1234) + (unsigned int)INT_MIN; +} + +int test5(int x) +{ + return (x - INT_MIN) ^ 0x1234; +} + +unsigned int test5u(unsigned int x) +{ + return (x - (unsigned int)INT_MIN) ^ 0x1234; +} + +int test6(int x) +{ + return (x ^ 0x1234) - INT_MIN; +} + +unsigned int test6u(unsigned int x) +{ + return (x ^ 0x1234) - (unsigned int)INT_MIN; +} + +int test7(int x) +{ + int y = INT_MIN; + int z = 0x1234; + return (x ^ y) ^ z; +} + +unsigned int test7u(unsigned int x) +{ + unsigned int y = (unsigned int)INT_MIN; + unsigned int z = 0x1234; + return (x ^ y) ^ z; +} + +int test8(int x) +{ + int y = 0x1234; + int z = INT_MIN; + return (x ^ y) ^ z; +} + +unsigned int test8u(unsigned int x) +{ + unsigned int y = 0x1234; + unsigned int z = (unsigned int)INT_MIN; + return (x ^ y) ^ z; +} + +int test9(int x) +{ + int y = INT_MIN; + int z = 0x1234; + return (x + y) ^ z; +} + +unsigned int test9u(unsigned int x) +{ + unsigned int y = (unsigned int)INT_MIN; + unsigned int z = 0x1234; + return (x + y) ^ z; +} + +int test10(int x) +{ + int y = 0x1234; + int z = INT_MIN; + return (x ^ y) + z; +} + +unsigned int test10u(unsigned int x) +{ + unsigned int y = 0x1234; + unsigned int z = (unsigned int)INT_MIN; + return (x ^ y) + z; +} + +int test11(int x) +{ + int y = INT_MIN; + int z = 0x1234; + return (x - y) ^ z; +} + +unsigned int test11u(unsigned int x) +{ + unsigned int y = (unsigned int)INT_MIN; + unsigned int z = 0x1234; + return (x - y) ^ z; +} + +int test12(int x) +{ + int y = 0x1234; + int z = INT_MIN; + return (x ^ y) - z; +} + +unsigned int test12u(unsigned int x) +{ + unsigned int y = 0x1234; + unsigned int z = (unsigned int)INT_MIN; + return (x ^ y) - z; +} + + +void test(int a, int b) +{ + if (test1(a) != b) + abort(); + if (test2(a) != b) + abort(); + if (test3(a) != b) + abort(); + if (test4(a) != b) + abort(); + if (test5(a) != b) + abort(); + if (test6(a) != b) + abort(); + if (test7(a) != b) + abort(); + if (test8(a) != b) + abort(); + if (test9(a) != b) + abort(); + if (test10(a) != b) + abort(); + if (test11(a) != b) + abort(); + if (test12(a) != b) + abort(); +} + +void testu(unsigned int a, unsigned int b) +{ + if (test1u(a) != b) + abort(); + if (test2u(a) != b) + abort(); + if (test3u(a) != b) + abort(); + if (test4u(a) != b) + abort(); + if (test5u(a) != b) + abort(); + if (test6u(a) != b) + abort(); + if (test7u(a) != b) + abort(); + if (test8u(a) != b) + abort(); + if (test9u(a) != b) + abort(); + if (test10u(a) != b) + abort(); + if (test11u(a) != b) + abort(); + if (test12u(a) != b) + abort(); +} + + +int main() +{ +#if INT_MAX == 2147483647 + test(0x00000000,0x80001234); + test(0x00001234,0x80000000); + test(0x80000000,0x00001234); + test(0x80001234,0x00000000); + test(0x7fffffff,0xffffedcb); + test(0xffffffff,0x7fffedcb); + + testu(0x00000000,0x80001234); + testu(0x00001234,0x80000000); + testu(0x80000000,0x00001234); + testu(0x80001234,0x00000000); + testu(0x7fffffff,0xffffedcb); + testu(0xffffffff,0x7fffedcb); +#endif + +#if INT_MAX == 32767 + test(0x0000,0x9234); + test(0x1234,0x8000); + test(0x8000,0x1234); + test(0x9234,0x0000); + test(0x7fff,0xffff); + test(0xffff,0x7fff); + + testu(0x0000,0x8000); + testu(0x8000,0x0000); + testu(0x1234,0x9234); + testu(0x9234,0x1234); + testu(0x7fff,0xedcb); + testu(0xffff,0x6dcb); +#endif + + return 0; +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/20040409-3.c b/gcc/testsuite/gcc.c-torture/execute/20040409-3.c new file mode 100644 index 0000000..07aa99c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20040409-3.c @@ -0,0 +1,142 @@ +#include <limits.h> + +extern void abort (); + +int test1(int x) +{ + return ~(x ^ INT_MIN); +} + +unsigned int test1u(unsigned int x) +{ + return ~(x ^ (unsigned int)INT_MIN); +} + +int test2(int x) +{ + return ~(x + INT_MIN); +} + +unsigned int test2u(unsigned int x) +{ + return ~(x + (unsigned int)INT_MIN); +} + +int test3(int x) +{ + return ~(x - INT_MIN); +} + +unsigned int test3u(unsigned int x) +{ + return ~(x - (unsigned int)INT_MIN); +} + +int test4(int x) +{ + int y = INT_MIN; + return ~(x ^ y); +} + +unsigned int test4u(unsigned int x) +{ + unsigned int y = (unsigned int)INT_MIN; + return ~(x ^ y); +} + +int test5(int x) +{ + int y = INT_MIN; + return ~(x + y); +} + +unsigned int test5u(unsigned int x) +{ + unsigned int y = (unsigned int)INT_MIN; + return ~(x + y); +} + +int test6(int x) +{ + int y = INT_MIN; + return ~(x - y); +} + +unsigned int test6u(unsigned int x) +{ + unsigned int y = (unsigned int)INT_MIN; + return ~(x - y); +} + + + +void test(int a, int b) +{ + if (test1(a) != b) + abort(); + if (test2(a) != b) + abort(); + if (test3(a) != b) + abort(); + if (test4(a) != b) + abort(); + if (test5(a) != b) + abort(); + if (test6(a) != b) + abort(); +} + +void testu(unsigned int a, unsigned int b) +{ + if (test1u(a) != b) + abort(); + if (test2u(a) != b) + abort(); + if (test3u(a) != b) + abort(); + if (test4u(a) != b) + abort(); + if (test5u(a) != b) + abort(); + if (test6u(a) != b) + abort(); +} + + +int main() +{ +#if INT_MAX == 2147483647 + test(0x00000000,0x7fffffff); + test(0x80000000,0xffffffff); + test(0x12345678,0x6dcba987); + test(0x92345678,0xedcba987); + test(0x7fffffff,0x00000000); + test(0xffffffff,0x80000000); + + testu(0x00000000,0x7fffffff); + testu(0x80000000,0xffffffff); + testu(0x12345678,0x6dcba987); + testu(0x92345678,0xedcba987); + testu(0x7fffffff,0x00000000); + testu(0xffffffff,0x80000000); +#endif + +#if INT_MAX == 32767 + test(0x0000,0x7fff); + test(0x8000,0xffff); + test(0x1234,0x6dcb); + test(0x9234,0xedcb); + test(0x7fff,0x0000); + test(0xffff,0x8000); + + testu(0x0000,0x7fff); + testu(0x8000,0xffff); + testu(0x1234,0x6dcb); + testu(0x9234,0xedcb); + testu(0x7fff,0x0000); + testu(0xffff,0x8000); +#endif + + return 0; +} + |