The following patch fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102627
The patch was successfully bootstrapped and tested on x86-64.
commit fab2d977e69539aad9bef81caff17de48e53aedf (HEAD -> master) Author: Vladimir N. Makarov <vmaka...@redhat.com> Date: Fri Oct 8 10:16:09 2021 -0400 [PR102627] Use at least natural mode during splitting hard reg live range In the PR test case SImode was used to split live range of cx on x86-64 because it was the biggest mode for this hard reg in the function. But all 64-bits of cx contain structure members. We need always to use at least natural mode of hard reg in splitting to fix this problem. gcc/ChangeLog: PR rtl-optimization/102627 * lra-constraints.c (split_reg): Use at least natural mode of hard reg. gcc/testsuite/ChangeLog: PR rtl-optimization/102627 * gcc.target/i386/pr102627.c: New test. diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index 4d734548c38..8f75125fc2e 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -5799,11 +5799,12 @@ split_reg (bool before_p, int original_regno, rtx_insn *insn, part of a multi-word register. In that case, just use the reg_rtx mode. Do the same also if the biggest mode was larger than a register or we can not compare the modes. Otherwise, limit the size to that of - the biggest access in the function. */ + the biggest access in the function or to the natural mode at least. */ if (mode == VOIDmode || !ordered_p (GET_MODE_PRECISION (mode), GET_MODE_PRECISION (reg_rtx_mode)) - || paradoxical_subreg_p (mode, reg_rtx_mode)) + || paradoxical_subreg_p (mode, reg_rtx_mode) + || maybe_gt (GET_MODE_PRECISION (reg_rtx_mode), GET_MODE_PRECISION (mode))) { original_reg = regno_reg_rtx[hard_regno]; mode = reg_rtx_mode; diff --git a/gcc/testsuite/gcc.target/i386/pr102627.c b/gcc/testsuite/gcc.target/i386/pr102627.c new file mode 100644 index 00000000000..8ab9acaf002 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr102627.c @@ -0,0 +1,41 @@ +/* PR rtl-optimization/102627 */ +/* { dg-do run } */ +/* { dg-options "-O1" } */ + +int a, f, l, m, q, c, d, g; +long b, e; +struct g { + signed h; + signed i; + unsigned j; + unsigned k; +}; +unsigned n; +char o; +int *p = &m; +long r(int s) { return s && b ?: b; } +long __attribute__((noipa)) v() { + l = 0 || r(n & o); + return q; +} +void w(int, unsigned, struct g x) { + c ?: a; + for (; d < 2; d++) + *p = x.k; +} +struct g __attribute__((noipa)) y() { + struct g h = {3, 908, 1, 20}; + for (; g; g++) + ; + return h; +} +int main() { + long t; + struct g u = y(); + t = e << f; + w(0, t, u); + v(0, 4, 4, 4); + if (m != 20) + __builtin_abort (); + return 0; +}