This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [RFC][PATCH LRA] WIP patch to fix one part of PR87507
On 10/22/18 6:45 PM, Peter Bergner wrote:
> Bah, my bootstrap failed and I need to make a small change. Let me do that
> and verify my bootstraps get all the way thru before I give you the updated
> patch. Sorry.
Ok, the following updated patch survives bootstrap and regtesting on
powerpc64le-linux, x86_64-linux and s390x-linux with no regressions.
Changes from the previous patch is that checking for illegal hard register
usage in inline asm statements has been moved to expand time. Secondly, the
lra constraints code now checks for both HARD_REGISTER_P and REG_USERVAR_P.
This was because I was seeing combine forcing hard regs into a pattern
(not from inline asm) which lra needed to spill to match constraints,
which it should be able to do.
Jeff, can you give this a try on your testers to see how it behaves on
the other arches that were having problems?
Peter
PR rtl-optimization/87600
* cfgexpand.c (expand_asm_stmt): Catch illegal asm constraint usage.
* lra-constraints.c (process_alt_operands): Skip illegal hard
register usage. Prefer reloading non hard register operands.
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c (revision 265402)
+++ gcc/cfgexpand.c (working copy)
@@ -3010,6 +3010,55 @@ expand_asm_stmt (gasm *stmt)
&allows_mem, &allows_reg, &is_inout))
return;
+ /* If the output is a hard register, verify it doesn't conflict with
+ any other operand's possible hard register use. */
+ if (DECL_P (val)
+ && REG_P (DECL_RTL (val))
+ && HARD_REGISTER_P (DECL_RTL (val)))
+ {
+ unsigned j, output_hregno = REGNO (DECL_RTL (val));
+ bool early_clobber_p = strchr (constraints[i], '&') != NULL;
+ unsigned long match;
+
+ /* Verify the other outputs do not use the same hard register. */
+ for (j = i + 1; j < noutputs; ++j)
+ if (DECL_P (output_tvec[j])
+ && REG_P (DECL_RTL (output_tvec[j]))
+ && HARD_REGISTER_P (DECL_RTL (output_tvec[j]))
+ && output_hregno == REGNO (DECL_RTL (output_tvec[j])))
+ error ("invalid hard register usage between output operands");
+
+ /* Verify matching constraint operands use the same hard register
+ and that the non-matching constraint operands do not use the same
+ hard register if the output is an early clobber operand. */
+ for (j = 0; j < ninputs; ++j)
+ if (DECL_P (input_tvec[j])
+ && REG_P (DECL_RTL (input_tvec[j]))
+ && HARD_REGISTER_P (DECL_RTL (input_tvec[j])))
+ {
+ unsigned input_hregno = REGNO (DECL_RTL (input_tvec[j]));
+ switch (*constraints[j + noutputs])
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ match = strtoul (constraints[j + noutputs], NULL, 10);
+ break;
+ default:
+ match = ULONG_MAX;
+ break;
+ }
+ if (i == match
+ && output_hregno != input_hregno)
+ error ("invalid hard register usage between output operand "
+ "and matching constraint operand");
+ else if (early_clobber_p
+ && i != match
+ && output_hregno == input_hregno)
+ error ("invalid hard register usage between earlyclobber "
+ "operand and input operand");
+ }
+ }
+
if (! allows_reg
&& (allows_mem
|| is_inout
Index: gcc/lra-constraints.c
===================================================================
--- gcc/lra-constraints.c (revision 265402)
+++ gcc/lra-constraints.c (working copy)
@@ -2146,9 +2146,30 @@ process_alt_operands (int only_alternati
}
else
{
- /* Operands don't match. Both operands must
- allow a reload register, otherwise we
- cannot make them match. */
+ /* Operands don't match. If the operands are
+ different user defined explicit hard registers,
+ then we cannot make them match. */
+ if ((REG_P (*curr_id->operand_loc[nop])
+ || SUBREG_P (*curr_id->operand_loc[nop]))
+ && (REG_P (*curr_id->operand_loc[m])
+ || SUBREG_P (*curr_id->operand_loc[m])))
+ {
+ rtx nop_reg = *curr_id->operand_loc[nop];
+ if (SUBREG_P (nop_reg))
+ nop_reg = SUBREG_REG (nop_reg);
+ rtx m_reg = *curr_id->operand_loc[m];
+ if (SUBREG_P (m_reg))
+ m_reg = SUBREG_REG (m_reg);
+
+ if (HARD_REGISTER_P (nop_reg)
+ && REG_USERVAR_P (nop_reg)
+ && HARD_REGISTER_P (m_reg)
+ && REG_USERVAR_P (m_reg))
+ break;
+ }
+
+ /* Both operands must allow a reload register,
+ otherwise we cannot make them match. */
if (curr_alt[m] == NO_REGS)
break;
/* Retroactively mark the operand we had to
@@ -2910,18 +2931,31 @@ process_alt_operands (int only_alternati
if (first_conflict_j < 0)
first_conflict_j = j;
last_conflict_j = j;
+ /* Both the earlyclobber operand and conflicting operand
+ cannot both be user defined hard registers. */
+ if (HARD_REGISTER_P (operand_reg[i])
+ && REG_USERVAR_P (operand_reg[i])
+ && operand_reg[j] != NULL_RTX
+ && HARD_REGISTER_P (operand_reg[j])
+ && REG_USERVAR_P (operand_reg[j]))
+ fatal_insn ("unable to generate reloads for "
+ "impossible constraints:", curr_insn);
}
if (last_conflict_j < 0)
continue;
- /* If earlyclobber operand conflicts with another
- non-matching operand which is actually the same register
- as the earlyclobber operand, it is better to reload the
- another operand as an operand matching the earlyclobber
- operand can be also the same. */
- if (first_conflict_j == last_conflict_j
- && operand_reg[last_conflict_j] != NULL_RTX
- && ! curr_alt_match_win[last_conflict_j]
- && REGNO (operand_reg[i]) == REGNO (operand_reg[last_conflict_j]))
+
+ /* If an earlyclobber operand conflicts with another non-matching
+ operand (ie, they have been assigned the same hard register),
+ then it is better to reload the other operand, as there may
+ exist yet another operand with a matching constraint associated
+ with the earlyclobber operand. However, if one of the operands
+ is an explicit use of a hard register, then we must reload the
+ other non-hard register operand. */
+ if (HARD_REGISTER_P (operand_reg[i])
+ || (first_conflict_j == last_conflict_j
+ && operand_reg[last_conflict_j] != NULL_RTX
+ && !curr_alt_match_win[last_conflict_j]
+ && !HARD_REGISTER_P (operand_reg[last_conflict_j])))
{
curr_alt_win[last_conflict_j] = false;
curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++]