diff --git a/gcc/expr.c b/gcc/expr.c index 798285eb52ca..a56594e78d55 100644 --- a/gcc/expr.c +++ b/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, diff --git a/gcc/testsuite/gcc.dg/pr98190.c b/gcc/testsuite/gcc.dg/pr98190.c new file mode 100644 index 000000000000..bfdd17d92708 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr98190.c @@ -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; +}