lra: Updates of biggest mode for hard regs [PR112278]

LRA keeps track of the biggest mode for both hard registers and
pseudos.  The updates assume that the modes are ordered, i.e. that
we can tell whether one is no bigger than the other at compile time.

That is (or at least seemed to be) a reasonable restriction for pseudos.
But it isn't necessarily so for hard registers, since the uses of hard
registers can be logically distinct.  The testcase is an example of this.

The biggest mode of hard registers is also special for other reasons.
As the existing comment says:

  /* A reg can have a biggest_mode of VOIDmode if it was only ever seen as
     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 or to the natural mode at least.  */

This patch applies the same approach to the updates.

gcc/
	PR rtl-optimization/112278
	* lra-int.h (lra_update_biggest_mode): New function.
	* lra-coalesce.cc (merge_pseudos): Use it.
	* lra-lives.cc (process_bb_lives): Likewise.
	* lra.cc (new_insn_reg): Likewise.

gcc/testsuite/
	PR rtl-optimization/112278
	* gcc.target/aarch64/sve/pr112278.c: New test.
This commit is contained in:
Richard Sandiford 2023-12-05 09:20:55 +00:00
parent 1a84af19cd
commit 6e2e0ce679
5 changed files with 34 additions and 9 deletions

View file

@ -112,9 +112,7 @@ merge_pseudos (int regno1, int regno2)
= (lra_merge_live_ranges
(lra_reg_info[first].live_ranges,
lra_copy_live_range_list (lra_reg_info[first2].live_ranges)));
if (partial_subreg_p (lra_reg_info[first].biggest_mode,
lra_reg_info[first2].biggest_mode))
lra_reg_info[first].biggest_mode = lra_reg_info[first2].biggest_mode;
lra_update_biggest_mode (first, lra_reg_info[first2].biggest_mode);
}
/* Change pseudos in *LOC on their coalescing group

View file

@ -535,4 +535,19 @@ lra_assign_reg_val (int from, int to)
lra_reg_info[to].offset = lra_reg_info[from].offset;
}
/* Update REGNO's biggest recorded mode so that it includes a reference
in mode MODE. */
inline void
lra_update_biggest_mode (int regno, machine_mode mode)
{
if (!ordered_p (GET_MODE_SIZE (lra_reg_info[regno].biggest_mode),
GET_MODE_SIZE (mode)))
{
gcc_checking_assert (HARD_REGISTER_NUM_P (regno));
lra_reg_info[regno].biggest_mode = reg_raw_mode[regno];
}
else if (partial_subreg_p (lra_reg_info[regno].biggest_mode, mode))
lra_reg_info[regno].biggest_mode = mode;
}
#endif /* GCC_LRA_INT_H */

View file

@ -770,9 +770,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
{
int regno = reg->regno;
if (partial_subreg_p (lra_reg_info[regno].biggest_mode,
reg->biggest_mode))
lra_reg_info[regno].biggest_mode = reg->biggest_mode;
lra_update_biggest_mode (regno, reg->biggest_mode);
if (HARD_REGISTER_NUM_P (regno))
lra_hard_reg_usage[regno] += freq;
}

View file

@ -581,9 +581,8 @@ new_insn_reg (rtx_insn *insn, int regno, enum op_type type,
lra_insn_reg *ir = lra_insn_reg_pool.allocate ();
ir->type = type;
ir->biggest_mode = mode;
if (NONDEBUG_INSN_P (insn)
&& partial_subreg_p (lra_reg_info[regno].biggest_mode, mode))
lra_reg_info[regno].biggest_mode = mode;
if (NONDEBUG_INSN_P (insn))
lra_update_biggest_mode (regno, mode);
ir->subreg_p = subreg_p;
ir->early_clobber_alts = early_clobber_alts;
ir->regno = regno;

View file

@ -0,0 +1,15 @@
#include <arm_neon.h>
#include <arm_sve.h>
void
f (void)
{
{
register svint8_t v0 asm ("z0");
asm volatile ("" : "=w" (v0));
}
{
register int8x8x4_t v0 asm ("v0");
asm volatile ("" : "=w" (v0));
}
}