aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2012-02-07 17:21:36 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2012-02-07 17:21:36 +0000
commitf22cfd73cd9eece5e426ddfe745f998ffc665945 (patch)
tree051e03d16190d715181a74c0cea2613985c0cdd3 /gcc/expr.c
parent13a72c0ba3e023f0f585654ed389c76efd4c1590 (diff)
downloadgcc-f22cfd73cd9eece5e426ddfe745f998ffc665945.zip
gcc-f22cfd73cd9eece5e426ddfe745f998ffc665945.tar.gz
gcc-f22cfd73cd9eece5e426ddfe745f998ffc665945.tar.bz2
re PR middle-end/51994 (git-1.7.8.3 miscompiled due to negative bitpos from get_inner_reference)
PR middle-end/51994 * expr.c (get_inner_reference): If there is an offset, add a negative bit position to it (if any). From-SVN: r183974
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index fcf177b..e63ed3b 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6716,6 +6716,24 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
/* Otherwise, split it up. */
if (offset)
{
+ /* Avoid returning a negative bitpos as this may wreak havoc later. */
+ if (double_int_negative_p (bit_offset))
+ {
+ double_int mask
+ = double_int_mask (BITS_PER_UNIT == 8
+ ? 3 : exact_log2 (BITS_PER_UNIT));
+ double_int tem = double_int_and_not (bit_offset, mask);
+ /* TEM is the bitpos rounded to BITS_PER_UNIT towards -Inf.
+ Subtract it to BIT_OFFSET and add it (scaled) to OFFSET. */
+ bit_offset = double_int_sub (bit_offset, tem);
+ tem = double_int_rshift (tem,
+ BITS_PER_UNIT == 8
+ ? 3 : exact_log2 (BITS_PER_UNIT),
+ HOST_BITS_PER_DOUBLE_INT, true);
+ offset = size_binop (PLUS_EXPR, offset,
+ double_int_to_tree (sizetype, tem));
+ }
+
*pbitpos = double_int_to_shwi (bit_offset);
*poffset = offset;
}