diff options
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 18 |
1 files changed, 18 insertions, 0 deletions
@@ -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; } |