aboutsummaryrefslogtreecommitdiff
path: root/gcc/expmed.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2013-05-23 11:17:34 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2013-05-23 11:17:34 +0200
commitbd3647bf76d1d207eaa80c7c6b5a460fecc327a9 (patch)
tree57fea5153070c42926cb9de1a4e5502db3ae37bd /gcc/expmed.c
parenta55757eae4c6711e558143595cbbfad97550b3e0 (diff)
downloadgcc-bd3647bf76d1d207eaa80c7c6b5a460fecc327a9.zip
gcc-bd3647bf76d1d207eaa80c7c6b5a460fecc327a9.tar.gz
gcc-bd3647bf76d1d207eaa80c7c6b5a460fecc327a9.tar.bz2
re PR rtl-optimization/57344 (wrong code with pragma pack(1) and -O1 on x86)
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. * 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. From-SVN: r199238
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r--gcc/expmed.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c
index c85e68c..daadd3d 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;