On Thu, Dec 10, 2020 at 11:15:30AM +0100, Eric Botcazou wrote: > Are you sure that the optimization is worth the hassle (and maybe the risk, > i.e. can't store_field clobber the entire field)?
I'm not sure, after all, only the testcases I've mentioned were affected in the whole bootstrap/regtest. And, if there is no insv, store_fixed_* might indeed expand it as (to_rtx & mask) | value which isn't 100% clear what it do to the bits beyond the bit-field. It is true that CONST_INTs are sign-extended, so maybe it wouldn't clear them for sign promoted to_rtx, but who knows. > > Any particular reason not to use the canonical idiom at the end, i.e. just > > convert_move (SUBREG_REG (to_rtx), to_rtx1, > SUBREG_PROMOTED_SIGN (to_rtx)); Ah, wasn't aware of that. So like this instead (if it passes another bootstrap/regtest)? 2020-12-10 Jakub Jelinek <ja...@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. --- gcc/expr.c.jj 2020-12-09 23:50:41.385776978 +0100 +++ gcc/expr.c 2020-12-10 11:38:07.853189206 +0100 @@ -5451,6 +5451,30 @@ expand_assignment (tree to, tree from, b 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, --- gcc/testsuite/gcc.dg/pr98190.c.jj 2020-12-10 09:08:54.838216477 +0100 +++ gcc/testsuite/gcc.dg/pr98190.c 2020-12-10 09:08:54.838216477 +0100 @@ -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; +} Jakub