Fix unaligned load with small memcpy on the ARM

store_integral_bit_field is ready to handle BLKmode fields, there is
even a subtlety with their handling on big-endian targets, see e.g.
PR middle-end/50325, but not if they are unaligned, so the fix is
simply to call extract_bit_field for them in order to generate an
unaligned load.  As a bonus, this subsumes  the big-endian specific
path that was added under PR middle-end/50325.

	PR middle-end/92071
	* expmed.c (store_integral_bit_field): For fields larger than a
	word, call extract_bit_field on the value if the mode is BLKmode.
	Remove specific path for big-endian targets and tidy things up a
	little bit.
This commit is contained in:
Eric Botcazou 2020-03-13 09:16:29 +01:00
parent 54e69cb00d
commit 82f620e2ba
4 changed files with 50 additions and 30 deletions

View File

@ -1,3 +1,10 @@
2019-03-13 Eric Botcazou <ebotcazou@adacore.com>
PR middle-end/92071
* expmed.c (store_integral_bit_field): For fields larger than a word,
call extract_bit_field on the value if the mode is BLKmode. Remove
specific path for big-endian targets and tidy things up a little bit.
2020-03-12 Richard Sandiford <richard.sandiford@arm.com>
PR rtl-optimization/90275

View File

@ -933,8 +933,7 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
However, only do that if the value is not BLKmode. */
const bool backwards = WORDS_BIG_ENDIAN && fieldmode != BLKmode;
unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
unsigned int i;
const int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
rtx_insn *last;
/* This is the mode we must force value to, so that there will be enough
@ -950,35 +949,31 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
value_mode = smallest_int_mode_for_size (nwords * BITS_PER_WORD);
last = get_last_insn ();
for (i = 0; i < nwords; i++)
for (int i = 0; i < nwords; i++)
{
/* If I is 0, use the low-order word in both field and target;
if I is 1, use the next to lowest word; and so on. */
unsigned int wordnum = (backwards
? GET_MODE_SIZE (value_mode) / UNITS_PER_WORD
- i - 1
: i);
unsigned int bit_offset = (backwards ^ reverse
? MAX ((int) bitsize - ((int) i + 1)
* BITS_PER_WORD,
0)
: (int) i * BITS_PER_WORD);
rtx value_word = operand_subword_force (value, wordnum, value_mode);
unsigned HOST_WIDE_INT new_bitsize =
MIN (BITS_PER_WORD, bitsize - i * BITS_PER_WORD);
/* If the remaining chunk doesn't have full wordsize we have
to make sure that for big-endian machines the higher order
bits are used. */
if (new_bitsize < BITS_PER_WORD && BYTES_BIG_ENDIAN && !backwards)
{
int shift = BITS_PER_WORD - new_bitsize;
rtx shift_rtx = gen_int_shift_amount (word_mode, shift);
value_word = simplify_expand_binop (word_mode, lshr_optab,
value_word, shift_rtx,
NULL_RTX, true,
OPTAB_LIB_WIDEN);
}
/* Number of bits to be stored in this iteration, i.e. BITS_PER_WORD
except maybe for the last iteration. */
const unsigned HOST_WIDE_INT new_bitsize
= MIN (BITS_PER_WORD, bitsize - i * BITS_PER_WORD);
/* Bit offset from the starting bit number in the target. */
const unsigned int bit_offset
= backwards ^ reverse
? MAX ((int) bitsize - (i + 1) * BITS_PER_WORD, 0)
: i * BITS_PER_WORD;
/* Starting word number in the value. */
const unsigned int wordnum
= backwards
? GET_MODE_SIZE (value_mode) / UNITS_PER_WORD - (i + 1)
: i;
/* The chunk of the value in word_mode. We use bit-field extraction
in BLKmode to handle unaligned memory references and to shift the
last chunk right on big-endian machines if need be. */
rtx value_word
= fieldmode == BLKmode
? extract_bit_field (value, new_bitsize, wordnum * BITS_PER_WORD,
1, NULL_RTX, word_mode, word_mode, false,
NULL)
: operand_subword_force (value, wordnum, value_mode);
if (!store_bit_field_1 (op0, new_bitsize,
bitnum + bit_offset,

View File

@ -1,3 +1,7 @@
2019-03-13 Eric Botcazou <ebotcazou@adacore.com>
* gcc.c-torture/compile/20200313-1.c: New test.
2020-03-12 Jeff Law <law@redhat.com>
PR rtl-optimization/90275

View File

@ -0,0 +1,14 @@
/* PR middle-end/92071 */
/* Testcase by David Binderman <dcb314@hotmail.com> */
void *a;
union U { double c; char d[8]; };
void bar (union U);
void
foo (void)
{
union U b;
__builtin_memcpy (b.d, a, 8);
bar (b);
}