aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/expr.c18
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20120207-1.c27
4 files changed, 55 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a05e801..3d6fe25 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2012-02-07 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR middle-end/51994
+ * expr.c (get_inner_reference): If there is an offset, add a negative
+ bit position to it (if any).
+
2012-02-07 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/52060
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;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1f63642..a433613 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2012-02-07 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc.c-torture/execute/20120207-1.c: New test.
+
2012-02-07 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/52060
diff --git a/gcc/testsuite/gcc.c-torture/execute/20120207-1.c b/gcc/testsuite/gcc.c-torture/execute/20120207-1.c
new file mode 100644
index 0000000..c4716ae
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20120207-1.c
@@ -0,0 +1,27 @@
+/* PR middle-end/51994 */
+/* Testcase by Uros Bizjak <ubizjak@gmail.com> */
+
+extern char *strcpy (char *, const char *);
+extern void abort (void);
+
+char __attribute__((noinline))
+test (int a)
+{
+ char buf[16];
+ char *output = buf;
+
+ strcpy (&buf[0], "0123456789");
+
+ output += a;
+ output -= 1;
+
+ return output[0];
+}
+
+int main ()
+{
+ if (test (2) != '1')
+ abort ();
+
+ return 0;
+}