https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116650
Michael Matz <matz at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |matz at gcc dot gnu.org --- Comment #2 from Michael Matz <matz at gcc dot gnu.org> --- Yep, exactly. It looks at the number of hardregs it used to use for the existing hardreg, and uses that as means to look up freeness in terms of the new candidate hardreg. That's never going to work. What's worse it also uses: for (i = nregs - 1; i >= 0; --) ... || ! HARD_REGNO_RENAME_OK (reg + i, new_reg + i)) I.e. it uses nregs as if it would be the same for 'reg' and 'new_reg'. That's just obviously wrong. Let's ignore that for now, and just have a candidate patch for the first problem. Try: diff --git a/gcc/regrename.cc b/gcc/regrename.cc index 054e601740b..22668d7bf57 100644 --- a/gcc/regrename.cc +++ b/gcc/regrename.cc @@ -324,10 +324,27 @@ static bool check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg, class du_head *this_head, HARD_REG_SET this_unavailable) { - int nregs = this_head->nregs; + int nregs = 1; int i; struct du_chain *tmp; + /* See whether new_reg accepts all modes that occur in + definition and uses and record the number of regs it would take. */ + for (tmp = this_head->first; tmp; tmp = tmp->next_use) + { + int n; + /* Completely ignore DEBUG_INSNs, otherwise we can get + -fcompare-debug failures. */ + if (DEBUG_INSN_P (tmp->insn)) + continue; + + if (!targetm.hard_regno_mode_ok (new_reg, GET_MODE (*tmp->loc))) + return false; + n = hard_regno_nregs (new_reg, GET_MODE (*tmp->loc)); + if (n > nregs) + nregs = n; + } + for (i = nregs - 1; i >= 0; --i) if (TEST_HARD_REG_BIT (this_unavailable, new_reg + i) || fixed_regs[new_reg + i] @@ -348,14 +365,10 @@ check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg, definition and uses. */ for (tmp = this_head->first; tmp; tmp = tmp->next_use) { - /* Completely ignore DEBUG_INSNs, otherwise we can get - -fcompare-debug failures. */ if (DEBUG_INSN_P (tmp->insn)) continue; - if (!targetm.hard_regno_mode_ok (new_reg, GET_MODE (*tmp->loc)) - || call_clobbered_in_chain_p (this_head, GET_MODE (*tmp->loc), - new_reg)) + if (call_clobbered_in_chain_p (this_head, GET_MODE (*tmp->loc), new_reg)) return false; }