expansion: Sign or zero extend on MEM_REF stores into SUBREG with SUBREG_PROMOTED_VAR_P [PR98190]

Some targets decide to promote certain scalar variables to wider mode,
so their DECL_RTL is a SUBREG with SUBREG_PROMOTED_VAR_P.
When storing to such vars, store_expr takes care of sign or zero extending,
but if we store e.g. through MEM_REF into them, no sign or zero extension
happens and that leads to wrong-code e.g. on the following testcase on
aarch64-linux.

The following patch uses store_expr if we overwrite all the bits and it is
not reversed storage order, i.e. something that store_expr handles normally,
and otherwise (if the most significant bit is (or for pdp11 might be, but
pdp11 doesn't promote) being modified), the code extends manually.

2020-12-11  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/98190
	* expr.c (expand_assignment): If to_rtx is a promoted SUBREG,
	ensure sign or zero extension either through use of store_expr
	or by extending manually.

	* gcc.dg/pr98190.c: New test.
This commit is contained in:
Jakub Jelinek 2020-12-11 11:10:17 +01:00
parent 499651e438
commit 3e60ddeb82
2 changed files with 57 additions and 0 deletions

View File

@ -5451,6 +5451,30 @@ expand_assignment (tree to, tree from, bool nontemporal)
mode1, to_rtx, to, from,
reversep))
result = NULL;
else if (SUBREG_P (to_rtx)
&& SUBREG_PROMOTED_VAR_P (to_rtx))
{
/* If to_rtx is a promoted subreg, we need to zero or sign
extend the value afterwards. */
if (TREE_CODE (to) == MEM_REF
&& !REF_REVERSE_STORAGE_ORDER (to)
&& known_eq (bitpos, 0)
&& known_eq (bitsize, GET_MODE_BITSIZE (GET_MODE (to_rtx))))
result = store_expr (from, to_rtx, 0, nontemporal, false);
else
{
rtx to_rtx1
= lowpart_subreg (subreg_unpromoted_mode (to_rtx),
SUBREG_REG (to_rtx),
subreg_promoted_mode (to_rtx));
result = store_field (to_rtx1, bitsize, bitpos,
bitregion_start, bitregion_end,
mode1, from, get_alias_set (to),
nontemporal, reversep);
convert_move (SUBREG_REG (to_rtx), to_rtx1,
SUBREG_PROMOTED_SIGN (to_rtx));
}
}
else
result = store_field (to_rtx, bitsize, bitpos,
bitregion_start, bitregion_end,

View File

@ -0,0 +1,33 @@
/* PR middle-end/98190 */
/* { dg-do run } */
/* { dg-options "-O2" } */
static int __attribute__((noipa))
foo (const char *p, const char *q, const int len)
{
for (int i = 0; i < len; p++, q++, i++)
{
int equal;
_Bool x, y;
__builtin_memcpy ((char *) &x, p, sizeof x);
__builtin_memcpy ((char *) &y, q, sizeof y);
equal = (x == y);
if (equal <= 0)
return equal;
}
return 1;
}
int
main ()
{
const _Bool buf[4] = { 1, 0, 0, 0 };
#ifdef __aarch64__
register long x4 asm ("x4") = 0xdeadbeefULL;
register long x5 asm ("x5") = 0xcafebabeULL;
asm volatile (""::"r" (x4), "r" (x5));
#endif
if (foo ((char *) &buf[0], (char *) &buf[0], 1) != 1)
__builtin_abort ();
return 0;
}