mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-20 12:41:17 +08:00
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:
parent
499651e438
commit
3e60ddeb82
24
gcc/expr.c
24
gcc/expr.c
@ -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,
|
||||
|
33
gcc/testsuite/gcc.dg/pr98190.c
Normal file
33
gcc/testsuite/gcc.dg/pr98190.c
Normal 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user