diff options
author | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-06-28 00:52:35 +0000 |
---|---|---|
committer | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-06-28 00:52:35 +0000 |
commit | 68c35eb8e6a605a0db9d18d697ec13d7ae413060 (patch) | |
tree | 6ac1b1fa0c3b8ade5a237d12fe531f37f0172b03 /gcc/tree-ssa-loop-niter.c | |
parent | 15bd9b39978dfa7d533b7708b9a31240bb9deaa7 (diff) | |
download | gcc-68c35eb8e6a605a0db9d18d697ec13d7ae413060.tar.gz |
PR 21959
* tree-ssa-loop-niter.c (scev_probably_wraps_p): Handle type
casts between unsigned and signed types with different size
or precision.
testsuite/ChangeLog
PR 21959
* gcc.dg/tree-ssa/pr21959.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@101365 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-loop-niter.c')
-rw-r--r-- | gcc/tree-ssa-loop-niter.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c index 83c291d5913..c99aa386be3 100644 --- a/gcc/tree-ssa-loop-niter.c +++ b/gcc/tree-ssa-loop-niter.c @@ -1649,6 +1649,41 @@ scev_probably_wraps_p (tree type, tree base, tree step, return true; } + /* If AT_STMT represents a cast operation, we may not be able to + take advantage of the undefinedness of signed type evolutions. + See PR 21959 for a test case. Essentially, given a cast + operation + unsigned char i; + signed char i.0; + ... + i.0_6 = (signed char) i_2; + if (i.0_6 < 0) + ... + + where i_2 and i.0_6 have the scev {0, +, 1}, we would consider + i_2 to wrap around, but not i.0_6, because it is of a signed + type. This causes VRP to erroneously fold the predicate above + because it thinks that i.0_6 cannot be negative. */ + if (TREE_CODE (at_stmt) == MODIFY_EXPR) + { + tree rhs = TREE_OPERAND (at_stmt, 1); + tree outer_t = TREE_TYPE (rhs); + + if (!TYPE_UNSIGNED (outer_t) + && (TREE_CODE (rhs) == NOP_EXPR || TREE_CODE (rhs) == CONVERT_EXPR)) + { + tree inner_t = TREE_TYPE (TREE_OPERAND (rhs, 0)); + + /* If the inner type is unsigned and its size and/or + precision are smaller to that of the outer type, then the + expression may wrap around. */ + if (TYPE_UNSIGNED (inner_t) + && (TYPE_SIZE (inner_t) <= TYPE_SIZE (outer_t) + || TYPE_PRECISION (inner_t) <= TYPE_PRECISION (outer_t))) + return true; + } + } + /* After having set INIT_IS_MAX, we can return false: when not using wrapping arithmetic, signed types don't wrap. */ if (!flag_wrapv && !TYPE_UNSIGNED (type)) |