diff options
author | Kazu Hirata <kazu@gcc.gnu.org> | 2003-07-10 12:40:10 +0000 |
---|---|---|
committer | Kazu Hirata <kazu@gcc.gnu.org> | 2003-07-10 12:40:10 +0000 |
commit | c87d821bd4efac92a032809b16b2951221b7a55b (patch) | |
tree | a8e19967fdd99d0fc53016195487b80ac8f20ece | |
parent | bcda12f4f4110d1376d822112c9c00d6287471a6 (diff) | |
download | gcc-c87d821bd4efac92a032809b16b2951221b7a55b.zip gcc-c87d821bd4efac92a032809b16b2951221b7a55b.tar.gz gcc-c87d821bd4efac92a032809b16b2951221b7a55b.tar.bz2 |
re PR c/11449 (ICE in invert_truthvalue called on AND operation)
PR c/11449
* fold-const.c (sign_bit_p): Return EXP if VAL is the sign bit
of HOST_WIDE_INT.
(fold_single_bit_test): If sign_bit_p() fails, assume that the
bit being tested is not a sign bit.
PR c/11449
* gcc.c-torture/compile/20030707-1.c: New.
* config/h8300/h8300.md (a peephole2): New.
From-SVN: r69184
-rw-r--r-- | gcc/fold-const.c | 32 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/20030707-1.c | 13 |
2 files changed, 35 insertions, 10 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7ef2b22..95a68bc 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -2730,8 +2730,8 @@ all_ones_mask_p (tree mask, int size) static tree sign_bit_p (tree exp, tree val) { - unsigned HOST_WIDE_INT lo; - HOST_WIDE_INT hi; + unsigned HOST_WIDE_INT mask_lo, lo; + HOST_WIDE_INT mask_hi, hi; int width; tree t; @@ -2750,14 +2750,25 @@ sign_bit_p (tree exp, tree val) { hi = (unsigned HOST_WIDE_INT) 1 << (width - HOST_BITS_PER_WIDE_INT - 1); lo = 0; + + mask_hi = ((unsigned HOST_WIDE_INT) -1 + >> (2 * HOST_BITS_PER_WIDE_INT - width)); + mask_lo = -1; } else { hi = 0; lo = (unsigned HOST_WIDE_INT) 1 << (width - 1); + + mask_hi = 0; + mask_lo = ((unsigned HOST_WIDE_INT) -1 + >> (HOST_BITS_PER_WIDE_INT - width)); } - if (TREE_INT_CST_HIGH (val) == hi && TREE_INT_CST_LOW (val) == lo) + /* We mask off those bits beyond TREE_TYPE (exp) so that we can + treat VAL as if it were unsigned. */ + if ((TREE_INT_CST_HIGH (val) & mask_hi) == hi + && (TREE_INT_CST_LOW (val) & mask_lo) == lo) return exp; /* Handle extension from a narrower type. */ @@ -4840,6 +4851,10 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1, convert (stype, arg00), convert (stype, integer_zero_node))); } + + /* At this point, we know that arg0 is not testing the sign bit. */ + if (TYPE_PRECISION (type) - 1 == bitnum) + abort (); /* Otherwise we have (A & C) != 0 where C is a single bit, convert that into ((A >> C2) & 1). Where C2 = log2(C). @@ -4861,13 +4876,11 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1, /* If we are going to be able to omit the AND below, we must do our operations as unsigned. If we must use the AND, we have a choice. Normally unsigned is faster, but for some machines signed is. */ - ops_unsigned = (bitnum == TYPE_PRECISION (type) - 1 ? 1 #ifdef LOAD_EXTEND_OP - : (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1) + ops_unsigned = (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1); #else - : 1 + ops_unsigned = 1; #endif - ); signed_type = (*lang_hooks.types.type_for_mode) (operand_mode, 0); unsigned_type = (*lang_hooks.types.type_for_mode) (operand_mode, 1); @@ -4881,9 +4894,8 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1, inner, integer_one_node); /* Put the AND last so it can combine with more things. */ - if (bitnum != TYPE_PRECISION (type) - 1) - inner = build (BIT_AND_EXPR, ops_unsigned ? unsigned_type : signed_type, - inner, integer_one_node); + inner = build (BIT_AND_EXPR, ops_unsigned ? unsigned_type : signed_type, + inner, integer_one_node); /* Make sure to return the proper type. */ if (TREE_TYPE (inner) != result_type) diff --git a/gcc/testsuite/gcc.c-torture/compile/20030707-1.c b/gcc/testsuite/gcc.c-torture/compile/20030707-1.c new file mode 100644 index 0000000..8ce9645 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030707-1.c @@ -0,0 +1,13 @@ +/* PR c/11449. */ + +/* sign_bit_p() in fold-const.c failed to notice that (int) 0x80000000 + was the sign bit of m. As a result, fold_single_bit_test() + returned ((unsigned int) m >> 31), and that was eventually passed + to invert_truthvalue(), which did not know how to handle + RROTATE_EXPR, causing an ICE. */ + +int +foo (int m) +{ + return !(m & ((int) 0x80000000)); +} |