From: Jakub Jelinek Date: Sun, 5 Nov 2006 12:13:46 +0000 (+0100) Subject: re PR middle-end/29695 (Folding breaks (a & 0x80) ? 0x80 : 0 for unsigned char or... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=789e604dfa7e323198db58ad181a4f7842e52aa8;p=gcc.git re PR middle-end/29695 (Folding breaks (a & 0x80) ? 0x80 : 0 for unsigned char or unsigned short a) PR middle-end/29695 * fold-const.c (fold_ternary): Fix A < 0 ? : 0 simplification. * gcc.c-torture/execute/pr29695-1.c: New test. * gcc.c-torture/execute/pr29695-2.c: New test. From-SVN: r118497 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 81ae94fc47c..72ee3fe5a0b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2006-11-05 Jakub Jelinek + + PR middle-end/29695 + * fold-const.c (fold_ternary): Fix A < 0 ? : 0 + simplification. + 2006-11-04 Uros Bizjak PR target/26915 diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 0ac3c8656d2..d70e5b02605 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -11380,13 +11380,76 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2) /* A < 0 ? : 0 is simply (A & ). */ if (TREE_CODE (arg0) == LT_EXPR - && integer_zerop (TREE_OPERAND (arg0, 1)) - && integer_zerop (op2) - && (tem = sign_bit_p (TREE_OPERAND (arg0, 0), arg1))) - return fold_convert (type, - fold_build2 (BIT_AND_EXPR, - TREE_TYPE (tem), tem, - fold_convert (TREE_TYPE (tem), arg1))); + && integer_zerop (TREE_OPERAND (arg0, 1)) + && integer_zerop (op2) + && (tem = sign_bit_p (TREE_OPERAND (arg0, 0), arg1))) + { + /* sign_bit_p only checks ARG1 bits within A's precision. + If has wider type than A, bits outside + of A's precision in need to be checked. + If they are all 0, this optimization needs to be done + in unsigned A's type, if they are all 1 in signed A's type, + otherwise this can't be done. */ + if (TYPE_PRECISION (TREE_TYPE (tem)) + < TYPE_PRECISION (TREE_TYPE (arg1)) + && TYPE_PRECISION (TREE_TYPE (tem)) + < TYPE_PRECISION (type)) + { + unsigned HOST_WIDE_INT mask_lo; + HOST_WIDE_INT mask_hi; + int inner_width, outer_width; + tree tem_type; + + inner_width = TYPE_PRECISION (TREE_TYPE (tem)); + outer_width = TYPE_PRECISION (TREE_TYPE (arg1)); + if (outer_width > TYPE_PRECISION (type)) + outer_width = TYPE_PRECISION (type); + + if (outer_width > HOST_BITS_PER_WIDE_INT) + { + mask_hi = ((unsigned HOST_WIDE_INT) -1 + >> (2 * HOST_BITS_PER_WIDE_INT - outer_width)); + mask_lo = -1; + } + else + { + mask_hi = 0; + mask_lo = ((unsigned HOST_WIDE_INT) -1 + >> (HOST_BITS_PER_WIDE_INT - outer_width)); + } + if (inner_width > HOST_BITS_PER_WIDE_INT) + { + mask_hi &= ~((unsigned HOST_WIDE_INT) -1 + >> (HOST_BITS_PER_WIDE_INT - inner_width)); + mask_lo = 0; + } + else + mask_lo &= ~((unsigned HOST_WIDE_INT) -1 + >> (HOST_BITS_PER_WIDE_INT - inner_width)); + + if ((TREE_INT_CST_HIGH (arg1) & mask_hi) == mask_hi + && (TREE_INT_CST_LOW (arg1) & mask_lo) == mask_lo) + { + tem_type = lang_hooks.types.signed_type (TREE_TYPE (tem)); + tem = fold_convert (tem_type, tem); + } + else if ((TREE_INT_CST_HIGH (arg1) & mask_hi) == 0 + && (TREE_INT_CST_LOW (arg1) & mask_lo) == 0) + { + tem_type = lang_hooks.types.unsigned_type (TREE_TYPE (tem)); + tem = fold_convert (tem_type, tem); + } + else + tem = NULL; + } + + if (tem) + return fold_convert (type, + fold_build2 (BIT_AND_EXPR, + TREE_TYPE (tem), tem, + fold_convert (TREE_TYPE (tem), + arg1))); + } /* (A >> N) & 1 ? (1 << N) : 0 is simply A & (1 << N). A & 1 was already handled above. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8d4b189f87a..bacc45a91e6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2006-11-05 Jakub Jelinek + + PR middle-end/29695 + * gcc.c-torture/execute/pr29695-1.c: New test. + * gcc.c-torture/execute/pr29695-2.c: New test. + 2006-11-05 Paul Thomas PR fortran/29565 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr29695-1.c b/gcc/testsuite/gcc.c-torture/execute/pr29695-1.c new file mode 100644 index 00000000000..9ecb3142509 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr29695-1.c @@ -0,0 +1,83 @@ +/* PR middle-end/29695 */ + +extern void abort (void); + +int +f1 (void) +{ + int a = 128; + return (a & 0x80) ? 0x80 : 0; +} + +int +f2 (void) +{ + unsigned char a = 128; + return (a & 0x80) ? 0x80 : 0; +} + +int +f3 (void) +{ + unsigned char a = 128; + return (a & 0x80) ? 0x380 : 0; +} + +int +f4 (void) +{ + unsigned char a = 128; + return (a & 0x80) ? -128 : 0; +} + +long long +f5 (void) +{ + long long a = 0x80000000LL; + return (a & 0x80000000) ? 0x80000000LL : 0LL; +} + +long long +f6 (void) +{ + unsigned int a = 0x80000000; + return (a & 0x80000000) ? 0x80000000LL : 0LL; +} + +long long +f7 (void) +{ + unsigned int a = 0x80000000; + return (a & 0x80000000) ? 0x380000000LL : 0LL; +} + +long long +f8 (void) +{ + unsigned int a = 0x80000000; + return (a & 0x80000000) ? -2147483648LL : 0LL; +} + +int +main (void) +{ + if ((char) 128 != -128 || (int) 0x80000000 != -2147483648) + return 0; + if (f1 () != 128) + abort (); + if (f2 () != 128) + abort (); + if (f3 () != 896) + abort (); + if (f4 () != -128) + abort (); + if (f5 () != 0x80000000LL) + abort (); + if (f6 () != 0x80000000LL) + abort (); + if (f7 () != 0x380000000LL) + abort (); + if (f8 () != -2147483648LL) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/pr29695-2.c b/gcc/testsuite/gcc.c-torture/execute/pr29695-2.c new file mode 100644 index 00000000000..339428e3279 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr29695-2.c @@ -0,0 +1,80 @@ +/* PR middle-end/29695 */ + +extern void abort (void); + +int a = 128; +unsigned char b = 128; +long long c = 0x80000000LL; +unsigned int d = 0x80000000; + +int +f1 (void) +{ + return (a & 0x80) ? 0x80 : 0; +} + +int +f2 (void) +{ + return (b & 0x80) ? 0x80 : 0; +} + +int +f3 (void) +{ + return (b & 0x80) ? 0x380 : 0; +} + +int +f4 (void) +{ + return (b & 0x80) ? -128 : 0; +} + +long long +f5 (void) +{ + return (c & 0x80000000) ? 0x80000000LL : 0LL; +} + +long long +f6 (void) +{ + return (d & 0x80000000) ? 0x80000000LL : 0LL; +} + +long long +f7 (void) +{ + return (d & 0x80000000) ? 0x380000000LL : 0LL; +} + +long long +f8 (void) +{ + return (d & 0x80000000) ? -2147483648LL : 0LL; +} + +int +main (void) +{ + if ((char) 128 != -128 || (int) 0x80000000 != -2147483648) + return 0; + if (f1 () != 128) + abort (); + if (f2 () != 128) + abort (); + if (f3 () != 896) + abort (); + if (f4 () != -128) + abort (); + if (f5 () != 0x80000000LL) + abort (); + if (f6 () != 0x80000000LL) + abort (); + if (f7 () != 0x380000000LL) + abort (); + if (f8 () != -2147483648LL) + abort (); + return 0; +}