summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/expmed.c18
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr57344-1.c32
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr57344-2.c32
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr57344-3.c28
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr57344-4.c28
7 files changed, 147 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 503215a741e..a4bf07a1f92 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2013-05-23 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/57344
+ * expmed.c (store_split_bit_field): If op0 is a REG or
+ SUBREG of a REG, don't lower unit. Handle unit not being
+ always BITS_PER_WORD.
+
2013-05-23 Richard Biener <rguenther@suse.de>
PR rtl-optimization/57341
diff --git a/gcc/expmed.c b/gcc/expmed.c
index c85e68cf617..daadd3def5d 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -1094,10 +1094,14 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
thispos = (bitpos + bitsdone) % unit;
/* When region of bytes we can touch is restricted, decrease
- UNIT close to the end of the region as needed. */
+ UNIT close to the end of the region as needed. If op0 is a REG
+ or SUBREG of REG, don't do this, as there can't be data races
+ on a register and we can expand shorter code in some cases. */
if (bitregion_end
&& unit > BITS_PER_UNIT
- && bitpos + bitsdone - thispos + unit > bitregion_end + 1)
+ && bitpos + bitsdone - thispos + unit > bitregion_end + 1
+ && !REG_P (op0)
+ && (GET_CODE (op0) != SUBREG || !REG_P (SUBREG_REG (op0))))
{
unit = unit / 2;
continue;
@@ -1147,14 +1151,15 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
the current word starting from the base register. */
if (GET_CODE (op0) == SUBREG)
{
- int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
+ int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD)
+ + (offset * unit / BITS_PER_WORD);
enum machine_mode sub_mode = GET_MODE (SUBREG_REG (op0));
if (sub_mode != BLKmode && GET_MODE_SIZE (sub_mode) < UNITS_PER_WORD)
word = word_offset ? const0_rtx : op0;
else
word = operand_subword_force (SUBREG_REG (op0), word_offset,
GET_MODE (SUBREG_REG (op0)));
- offset = 0;
+ offset &= BITS_PER_WORD / unit - 1;
}
else if (REG_P (op0))
{
@@ -1162,8 +1167,9 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
if (op0_mode != BLKmode && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD)
word = offset ? const0_rtx : op0;
else
- word = operand_subword_force (op0, offset, GET_MODE (op0));
- offset = 0;
+ word = operand_subword_force (op0, offset * unit / BITS_PER_WORD,
+ GET_MODE (op0));
+ offset &= BITS_PER_WORD / unit - 1;
}
else
word = op0;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d1c0dda3186..6485a5cfbe0 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2013-05-23 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/57344
+ * gcc.c-torture/execute/pr57344-1.c: New test.
+ * gcc.c-torture/execute/pr57344-2.c: New test.
+ * gcc.c-torture/execute/pr57344-3.c: New test.
+ * gcc.c-torture/execute/pr57344-4.c: New test.
+
2013-05-23 Richard Biener <rguenther@suse.de>
PR rtl-optimization/57341
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr57344-1.c b/gcc/testsuite/gcc.c-torture/execute/pr57344-1.c
new file mode 100644
index 00000000000..66893269efa
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr57344-1.c
@@ -0,0 +1,32 @@
+/* PR middle-end/57344 */
+
+struct __attribute__((packed)) S
+{
+ int a : 11;
+#if __SIZEOF_INT__ * __CHAR_BIT__ >= 32
+ int b : 22;
+#else
+ int b : 13;
+#endif
+ char c;
+ int : 0;
+} s[2];
+int i;
+
+__attribute__((noinline, noclone)) void
+foo (int x)
+{
+ if (x != -3161)
+ __builtin_abort ();
+ asm volatile ("" : : : "memory");
+}
+
+int
+main ()
+{
+ struct S t = { 0, -3161L };
+ s[1] = t;
+ for (; i < 1; i++)
+ foo (s[1].b);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr57344-2.c b/gcc/testsuite/gcc.c-torture/execute/pr57344-2.c
new file mode 100644
index 00000000000..9bf60cab8f0
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr57344-2.c
@@ -0,0 +1,32 @@
+/* PR middle-end/57344 */
+
+struct __attribute__((packed)) S
+{
+ int a : 27;
+#if __SIZEOF_INT__ * __CHAR_BIT__ >= 32
+ int b : 22;
+#else
+ int b : 13;
+#endif
+ char c;
+ int : 0;
+} s[2];
+int i;
+
+__attribute__((noinline, noclone)) void
+foo (int x)
+{
+ if (x != -3161)
+ __builtin_abort ();
+ asm volatile ("" : : : "memory");
+}
+
+int
+main ()
+{
+ struct S t = { 0, -3161L };
+ s[1] = t;
+ for (; i < 1; i++)
+ foo (s[1].b);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr57344-3.c b/gcc/testsuite/gcc.c-torture/execute/pr57344-3.c
new file mode 100644
index 00000000000..f9daea6d3a9
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr57344-3.c
@@ -0,0 +1,28 @@
+/* PR middle-end/57344 */
+
+struct __attribute__((packed)) S
+{
+ long long int a : 43;
+ long long int b : 22;
+ char c;
+ long long int : 0;
+} s[2];
+int i;
+
+__attribute__((noinline, noclone)) void
+foo (long long int x)
+{
+ if (x != -3161LL)
+ __builtin_abort ();
+ asm volatile ("" : : : "memory");
+}
+
+int
+main ()
+{
+ struct S t = { 0, -3161LL };
+ s[1] = t;
+ for (; i < 1; i++)
+ foo (s[1].b);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr57344-4.c b/gcc/testsuite/gcc.c-torture/execute/pr57344-4.c
new file mode 100644
index 00000000000..0b2bf152490
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr57344-4.c
@@ -0,0 +1,28 @@
+/* PR middle-end/57344 */
+
+struct __attribute__((packed)) S
+{
+ long long int a : 59;
+ long long int b : 54;
+ char c;
+ long long int : 0;
+} s[2];
+int i;
+
+__attribute__((noinline, noclone)) void
+foo (long long int x)
+{
+ if (x != -1220975898975746LL)
+ __builtin_abort ();
+ asm volatile ("" : : : "memory");
+}
+
+int
+main ()
+{
+ struct S t = { 0, -1220975898975746LL };
+ s[1] = t;
+ for (; i < 1; i++)
+ foo (s[1].b);
+ return 0;
+}