On Wed, Nov 8, 2023 at 4:48 AM Lehua Ding <[email protected]> wrote:
>
> This patch does not make any functional changes. It mainly refactor two parts:
>
> 1. The ira_allocno's objects field is expanded to an scalable array, and
> multi-word
> pseduo registers are split and tracked only when necessary.
> 2. Since the objects array has been expanded, there will be more subreg
> objects
> that pass through later, rather than the previous fixed two. Therefore, it
> is necessary to modify the detection of whether two objects conflict, and
> the check method is to pull back the registers occupied by the object to
> the first register of the allocno for judgment.
Did you profile this before/after? RA performance is critical ...
> gcc/ChangeLog:
>
> * hard-reg-set.h (struct HARD_REG_SET): Add operator>>.
> * ira-build.cc (init_object_start_and_nregs): New func.
> (find_object): Ditto.
> (ira_create_allocno): Adjust.
> (ira_set_allocno_class): Set subreg info.
> (ira_create_allocno_objects): Adjust.
> (init_regs_with_subreg): Collect access in subreg.
> (ira_build): Call init_regs_with_subreg
> (ira_destroy): Clear regs_with_subreg
> * ira-color.cc (setup_profitable_hard_regs): Adjust.
> (get_conflict_and_start_profitable_regs): Adjust.
> (check_hard_reg_p): Adjust.
> (assign_hard_reg): Adjust.
> (improve_allocation): Adjust.
> * ira-int.h (struct ira_object): Adjust fields.
> (struct ira_allocno): Adjust objects filed.
> (ALLOCNO_NUM_OBJECTS): Adjust.
> (ALLOCNO_UNIT_SIZE): New.
> (ALLOCNO_TRACK_SUBREG_P): New.
> (ALLOCNO_NREGS): New.
> (OBJECT_SIZE): New.
> (OBJECT_OFFSET): New.
> (OBJECT_START): New.
> (OBJECT_NREGS): New.
> (find_object): New.
> (has_subreg_object_p): New.
> (get_full_object): New.
> * ira.cc (check_allocation): Adjust.
>
> ---
> gcc/hard-reg-set.h | 33 +++++++
> gcc/ira-build.cc | 106 +++++++++++++++++++-
> gcc/ira-color.cc | 234 ++++++++++++++++++++++++++++++---------------
> gcc/ira-int.h | 45 ++++++++-
> gcc/ira.cc | 52 ++++------
> 5 files changed, 349 insertions(+), 121 deletions(-)
>
> diff --git a/gcc/hard-reg-set.h b/gcc/hard-reg-set.h
> index b0bb9bce074..760eadba186 100644
> --- a/gcc/hard-reg-set.h
> +++ b/gcc/hard-reg-set.h
> @@ -113,6 +113,39 @@ struct HARD_REG_SET
> return !operator== (other);
> }
>
> + HARD_REG_SET
> + operator>> (unsigned int shift_amount) const
This is a quite costly operation, why do we need it instead
of keeping an "offset" for set queries?
> + {
> + if (shift_amount == 0)
> + return *this;
> +
> + HARD_REG_SET res;
> + unsigned int total_bits = sizeof (HARD_REG_ELT_TYPE) * 8;
> + if (shift_amount >= total_bits)
> + {
> + unsigned int n_elt = shift_amount % total_bits;
> + shift_amount -= n_elt * total_bits;
> + for (unsigned int i = 0; i < ARRAY_SIZE (elts) - n_elt - 1; i += 1)
> + res.elts[i] = elts[i + n_elt];
> + /* clear upper n_elt elements. */
> + for (unsigned int i = 0; i < n_elt; i += 1)
> + res.elts[ARRAY_SIZE (elts) - 1 - i] = 0;
> + }
> +
> + if (shift_amount > 0)
> + {
> + /* The left bits of an element be shifted. */
> + HARD_REG_ELT_TYPE left = 0;
> + /* Total bits of an element. */
> + for (int i = ARRAY_SIZE (elts); i >= 0; --i)
> + {
> + res.elts[i] = (elts[i] >> shift_amount) | left;
> + left = elts[i] << (total_bits - shift_amount);
> + }
> + }
> + return res;
> + }
> +
> HARD_REG_ELT_TYPE elts[HARD_REG_SET_LONGS];
> };
> typedef const HARD_REG_SET &const_hard_reg_set;
> diff --git a/gcc/ira-build.cc b/gcc/ira-build.cc
> index 93e46033170..07aba27c1c9 100644
> --- a/gcc/ira-build.cc
> +++ b/gcc/ira-build.cc
> @@ -440,6 +440,40 @@ initiate_allocnos (void)
> memset (ira_regno_allocno_map, 0, max_reg_num () * sizeof (ira_allocno_t));
> }
>
> +/* Update OBJ's start and nregs field according A and OBJ info. */
> +static void
> +init_object_start_and_nregs (ira_allocno_t a, ira_object_t obj)
> +{
> + enum reg_class aclass = ALLOCNO_CLASS (a);
> + gcc_assert (aclass != NO_REGS);
> +
> + machine_mode mode = ALLOCNO_MODE (a);
> + int nregs = ira_reg_class_max_nregs[aclass][mode];
> + if (ALLOCNO_TRACK_SUBREG_P (a))
> + {
> + poly_int64 end = OBJECT_OFFSET (obj) + OBJECT_SIZE (obj);
> + for (int i = 0; i < nregs; i += 1)
> + {
> + poly_int64 right = ALLOCNO_UNIT_SIZE (a) * (i + 1);
> + if (OBJECT_START (obj) < 0 && maybe_lt (OBJECT_OFFSET (obj), right))
> + {
> + OBJECT_START (obj) = i;
> + }
> + if (OBJECT_NREGS (obj) < 0 && maybe_le (end, right))
> + {
> + OBJECT_NREGS (obj) = i + 1 - OBJECT_START (obj);
> + break;
> + }
> + }
> + gcc_assert (OBJECT_START (obj) >= 0 && OBJECT_NREGS (obj) > 0);
> + }
> + else
> + {
> + OBJECT_START (obj) = 0;
> + OBJECT_NREGS (obj) = nregs;
> + }
> +}
> +
> /* Create and return an object corresponding to a new allocno A. */
> static ira_object_t
> ira_create_object (ira_allocno_t a, int subword)
> @@ -460,15 +494,36 @@ ira_create_object (ira_allocno_t a, int subword)
> OBJECT_MIN (obj) = INT_MAX;
> OBJECT_MAX (obj) = -1;
> OBJECT_LIVE_RANGES (obj) = NULL;
> + OBJECT_SIZE (obj) = UNITS_PER_WORD;
> + OBJECT_OFFSET (obj) = subword * UNITS_PER_WORD;
> + OBJECT_START (obj) = -1;
> + OBJECT_NREGS (obj) = -1;
>
> ira_object_id_map_vec.safe_push (obj);
> ira_object_id_map
> = ira_object_id_map_vec.address ();
> ira_objects_num = ira_object_id_map_vec.length ();
>
> + if (aclass != NO_REGS)
> + init_object_start_and_nregs (a, obj);
> +
> + a->objects.push_back (obj);
> +
> return obj;
> }
>
> +/* Return the object in allocno A which match START & NREGS. */
> +ira_object_t
> +find_object (ira_allocno_t a, int start, int nregs)
> +{
> + for (ira_object_t obj : a->objects)
linear search? really?
> + {
> + if (OBJECT_START (obj) == start && OBJECT_NREGS (obj) == nregs)
> + return obj;
> + }
> + return NULL;
> +}
> +
> /* Create and return the allocno corresponding to REGNO in
> LOOP_TREE_NODE. Add the allocno to the list of allocnos with the
> same regno if CAP_P is FALSE. */
> @@ -525,7 +580,8 @@ ira_create_allocno (int regno, bool cap_p,
> ALLOCNO_MEMORY_COST (a) = 0;
> ALLOCNO_UPDATED_MEMORY_COST (a) = 0;
> ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a) = 0;
> - ALLOCNO_NUM_OBJECTS (a) = 0;
> + ALLOCNO_UNIT_SIZE (a) = 0;
> + ALLOCNO_TRACK_SUBREG_P (a) = false;
>
> ALLOCNO_ADD_DATA (a) = NULL;
> allocno_vec.safe_push (a);
> @@ -535,6 +591,9 @@ ira_create_allocno (int regno, bool cap_p,
> return a;
> }
>
> +/* Record the regs referenced by subreg. */
> +static bitmap_head regs_with_subreg;
> +
> /* Set up register class for A and update its conflict hard
> registers. */
> void
> @@ -549,6 +608,19 @@ ira_set_allocno_class (ira_allocno_t a, enum reg_class
> aclass)
> OBJECT_CONFLICT_HARD_REGS (obj) |= ~reg_class_contents[aclass];
> OBJECT_TOTAL_CONFLICT_HARD_REGS (obj) |= ~reg_class_contents[aclass];
> }
> +
> + if (aclass == NO_REGS)
> + return;
> + /* SET the unit_size of one register. */
> + machine_mode mode = ALLOCNO_MODE (a);
> + int nregs = ira_reg_class_max_nregs[aclass][mode];
> + if (nregs == 2 && maybe_eq (GET_MODE_SIZE (mode), nregs * UNITS_PER_WORD)
> + && bitmap_bit_p (®s_with_subreg, ALLOCNO_REGNO (a)))
> + {
> + ALLOCNO_UNIT_SIZE (a) = UNITS_PER_WORD;
> + ALLOCNO_TRACK_SUBREG_P (a) = true;
> + return;
> + }
> }
>
> /* Determine the number of objects we should associate with allocno A
> @@ -561,12 +633,12 @@ ira_create_allocno_objects (ira_allocno_t a)
> int n = ira_reg_class_max_nregs[aclass][mode];
> int i;
>
> - if (n != 2 || maybe_ne (GET_MODE_SIZE (mode), n * UNITS_PER_WORD))
> + if (n != 2 || maybe_ne (GET_MODE_SIZE (mode), n * UNITS_PER_WORD)
> + || !bitmap_bit_p (®s_with_subreg, ALLOCNO_REGNO (a)))
> n = 1;
>
> - ALLOCNO_NUM_OBJECTS (a) = n;
> for (i = 0; i < n; i++)
> - ALLOCNO_OBJECT (a, i) = ira_create_object (a, i);
> + ira_create_object (a, i);
> }
>
> /* For each allocno, set ALLOCNO_NUM_OBJECTS and create the
> @@ -3460,6 +3532,30 @@ update_conflict_hard_reg_costs (void)
> }
> }
>
> +/* Traverse all instructions to determine which ones have access through
> subreg.
> + */
> +static void
> +init_regs_with_subreg ()
> +{
> + bitmap_initialize (®s_with_subreg, ®_obstack);
> + basic_block bb;
> + rtx_insn *insn;
> + df_ref def, use;
> + FOR_ALL_BB_FN (bb, cfun)
> + FOR_BB_INSNS (bb, insn)
> + {
> + if (!NONDEBUG_INSN_P (insn))
> + continue;
> + df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
> + FOR_EACH_INSN_INFO_DEF (def, insn_info)
> + if (DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_SUBREG))
> + bitmap_set_bit (®s_with_subreg, DF_REF_REGNO (def));
> + FOR_EACH_INSN_INFO_USE (use, insn_info)
> + if (DF_REF_FLAGS (use) & (DF_REF_PARTIAL | DF_REF_SUBREG))
> + bitmap_set_bit (®s_with_subreg, DF_REF_REGNO (use));
> + }
> +}
> +
> /* Create a internal representation (IR) for IRA (allocnos, copies,
> loop tree nodes). The function returns TRUE if we generate loop
> structure (besides nodes representing all function and the basic
> @@ -3475,6 +3571,7 @@ ira_build (void)
> initiate_allocnos ();
> initiate_prefs ();
> initiate_copies ();
> + init_regs_with_subreg ();
> create_loop_tree_nodes ();
> form_loop_tree ();
> create_allocnos ();
> @@ -3565,4 +3662,5 @@ ira_destroy (void)
> finish_allocnos ();
> finish_cost_vectors ();
> ira_finish_allocno_live_ranges ();
> + bitmap_clear (®s_with_subreg);
> }
> diff --git a/gcc/ira-color.cc b/gcc/ira-color.cc
> index f2e8ea34152..6af8318e5f5 100644
> --- a/gcc/ira-color.cc
> +++ b/gcc/ira-color.cc
> @@ -1031,7 +1031,7 @@ static void
> setup_profitable_hard_regs (void)
> {
> unsigned int i;
> - int j, k, nobj, hard_regno, nregs, class_size;
> + int j, k, nobj, hard_regno, class_size;
> ira_allocno_t a;
> bitmap_iterator bi;
> enum reg_class aclass;
> @@ -1076,7 +1076,6 @@ setup_profitable_hard_regs (void)
> || (hard_regno = ALLOCNO_HARD_REGNO (a)) < 0)
> continue;
> mode = ALLOCNO_MODE (a);
> - nregs = hard_regno_nregs (hard_regno, mode);
> nobj = ALLOCNO_NUM_OBJECTS (a);
> for (k = 0; k < nobj; k++)
> {
> @@ -1088,24 +1087,39 @@ setup_profitable_hard_regs (void)
> {
> ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
>
> - /* We can process the conflict allocno repeatedly with
> - the same result. */
> - if (nregs == nobj && nregs > 1)
> + if (!has_subreg_object_p (a))
> {
> - int num = OBJECT_SUBWORD (conflict_obj);
> -
> - if (REG_WORDS_BIG_ENDIAN)
> - CLEAR_HARD_REG_BIT
> - (ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs,
> - hard_regno + nobj - num - 1);
> - else
> - CLEAR_HARD_REG_BIT
> - (ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs,
> - hard_regno + num);
> + ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs
> + &= ~ira_reg_mode_hard_regset[hard_regno][mode];
> + continue;
> + }
> +
> + /* Clear all hard regs occupied by obj. */
> + if (REG_WORDS_BIG_ENDIAN)
> + {
> + int start_regno
> + = hard_regno + ALLOCNO_NREGS (a) - 1 - OBJECT_START (obj);
> + for (int i = 0; i < OBJECT_NREGS (obj); i += 1)
> + {
> + int regno = start_regno - i;
> + if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER)
> + CLEAR_HARD_REG_BIT (
> + ALLOCNO_COLOR_DATA
> (conflict_a)->profitable_hard_regs,
> + regno);
> + }
> }
> else
> - ALLOCNO_COLOR_DATA (conflict_a)->profitable_hard_regs
> - &= ~ira_reg_mode_hard_regset[hard_regno][mode];
> + {
> + int start_regno = hard_regno + OBJECT_START (obj);
> + for (int i = 0; i < OBJECT_NREGS (obj); i += 1)
> + {
> + int regno = start_regno + i;
> + if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER)
> + CLEAR_HARD_REG_BIT (
> + ALLOCNO_COLOR_DATA
> (conflict_a)->profitable_hard_regs,
> + regno);
> + }
> + }
> }
> }
> }
> @@ -1677,18 +1691,25 @@ update_conflict_hard_regno_costs (int *costs, enum
> reg_class aclass,
> aligned. */
> static inline void
> get_conflict_and_start_profitable_regs (ira_allocno_t a, bool retry_p,
> - HARD_REG_SET *conflict_regs,
> + HARD_REG_SET *start_conflict_regs,
> HARD_REG_SET *start_profitable_regs)
> {
> int i, nwords;
> ira_object_t obj;
>
> nwords = ALLOCNO_NUM_OBJECTS (a);
> - for (i = 0; i < nwords; i++)
> - {
> - obj = ALLOCNO_OBJECT (a, i);
> - conflict_regs[i] = OBJECT_TOTAL_CONFLICT_HARD_REGS (obj);
> - }
> + CLEAR_HARD_REG_SET (*start_conflict_regs);
> + if (has_subreg_object_p (a))
> + for (i = 0; i < nwords; i++)
> + {
> + obj = ALLOCNO_OBJECT (a, i);
> + for (int j = 0; j < OBJECT_NREGS (obj); j += 1)
> + *start_conflict_regs |= OBJECT_TOTAL_CONFLICT_HARD_REGS (obj)
> + >> (OBJECT_START (obj) + j);
> + }
> + else
> + *start_conflict_regs
> + = OBJECT_TOTAL_CONFLICT_HARD_REGS (get_full_object (a));
> if (retry_p)
> *start_profitable_regs
> = (reg_class_contents[ALLOCNO_CLASS (a)]
> @@ -1702,9 +1723,9 @@ get_conflict_and_start_profitable_regs (ira_allocno_t
> a, bool retry_p,
> PROFITABLE_REGS and whose objects have CONFLICT_REGS. */
> static inline bool
> check_hard_reg_p (ira_allocno_t a, int hard_regno,
> - HARD_REG_SET *conflict_regs, HARD_REG_SET profitable_regs)
> + HARD_REG_SET start_conflict_regs,
> + HARD_REG_SET profitable_regs)
> {
> - int j, nwords, nregs;
> enum reg_class aclass;
> machine_mode mode;
>
> @@ -1716,28 +1737,17 @@ check_hard_reg_p (ira_allocno_t a, int hard_regno,
> /* Checking only profitable hard regs. */
> if (! TEST_HARD_REG_BIT (profitable_regs, hard_regno))
> return false;
> - nregs = hard_regno_nregs (hard_regno, mode);
> - nwords = ALLOCNO_NUM_OBJECTS (a);
> - for (j = 0; j < nregs; j++)
> +
> + if (has_subreg_object_p (a))
> + return !TEST_HARD_REG_BIT (start_conflict_regs, hard_regno);
> + else
> {
> - int k;
> - int set_to_test_start = 0, set_to_test_end = nwords;
> -
> - if (nregs == nwords)
> - {
> - if (REG_WORDS_BIG_ENDIAN)
> - set_to_test_start = nwords - j - 1;
> - else
> - set_to_test_start = j;
> - set_to_test_end = set_to_test_start + 1;
> - }
> - for (k = set_to_test_start; k < set_to_test_end; k++)
> - if (TEST_HARD_REG_BIT (conflict_regs[k], hard_regno + j))
> - break;
> - if (k != set_to_test_end)
> - break;
> + int nregs = hard_regno_nregs (hard_regno, mode);
> + for (int i = 0; i < nregs; i += 1)
> + if (TEST_HARD_REG_BIT (start_conflict_regs, hard_regno + i))
> + return false;
> + return true;
> }
> - return j == nregs;
> }
>
> /* Return number of registers needed to be saved and restored at
> @@ -1945,7 +1955,7 @@ spill_soft_conflicts (ira_allocno_t a, bitmap
> allocnos_to_spill,
> static bool
> assign_hard_reg (ira_allocno_t a, bool retry_p)
> {
> - HARD_REG_SET conflicting_regs[2], profitable_hard_regs;
> + HARD_REG_SET start_conflicting_regs, profitable_hard_regs;
> int i, j, hard_regno, best_hard_regno, class_size;
> int cost, mem_cost, min_cost, full_cost, min_full_cost, nwords, word;
> int *a_costs;
> @@ -1962,8 +1972,7 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
> HARD_REG_SET soft_conflict_regs = {};
>
> ira_assert (! ALLOCNO_ASSIGNED_P (a));
> - get_conflict_and_start_profitable_regs (a, retry_p,
> - conflicting_regs,
> + get_conflict_and_start_profitable_regs (a, retry_p,
> &start_conflicting_regs,
> &profitable_hard_regs);
> aclass = ALLOCNO_CLASS (a);
> class_size = ira_class_hard_regs_num[aclass];
> @@ -2041,7 +2050,6 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
> (hard_regno, ALLOCNO_MODE (conflict_a),
> reg_class_contents[aclass])))
> {
> - int n_objects = ALLOCNO_NUM_OBJECTS (conflict_a);
> int conflict_nregs;
>
> mode = ALLOCNO_MODE (conflict_a);
> @@ -2076,24 +2084,95 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
> note_conflict (r);
> }
> }
> + else if (has_subreg_object_p (a))
> + {
> + /* Set start_conflicting_regs if that cause obj and
> + conflict_obj overlap. the overlap position:
> + +--------------+
> + | conflict_obj |
> + +--------------+
> +
> + +-----------+ +-----------+
> + | obj | ... | obj |
> + +-----------+ +-----------+
> +
> + Point: A B C
> +
> + the hard regs from A to C point will cause overlap.
> + For REG_WORDS_BIG_ENDIAN:
> + A = hard_regno + ALLOCNO_NREGS (conflict_a) - 1
> + - OBJECT_START (conflict_obj)
> + - OBJECT_NREGS (obj) + 1
> + C = A + OBJECT_NREGS (obj)
> + + OBJECT_NREGS (conflict_obj) - 2
> + For !REG_WORDS_BIG_ENDIAN:
> + A = hard_regno + OBJECT_START (conflict_obj)
> + - OBJECT_NREGS (obj) + 1
> + C = A + OBJECT_NREGS (obj)
> + + OBJECT_NREGS (conflict_obj) - 2
> + */
> + int start_regno;
> + int conflict_allocno_nregs, conflict_object_nregs,
> + conflict_object_start;
> + if (has_subreg_object_p (conflict_a))
> + {
> + conflict_allocno_nregs = ALLOCNO_NREGS (conflict_a);
> + conflict_object_nregs = OBJECT_NREGS (conflict_obj);
> + conflict_object_start = OBJECT_START (conflict_obj);
> + }
> + else
> + {
> + conflict_allocno_nregs = conflict_object_nregs
> + = hard_regno_nregs (hard_regno, mode);
> + conflict_object_start = 0;
> + }
> + if (REG_WORDS_BIG_ENDIAN)
> + {
> + int A = hard_regno + conflict_allocno_nregs - 1
> + - conflict_object_start - OBJECT_NREGS (obj)
> + + 1;
> + start_regno = A + OBJECT_NREGS (obj) - 1
> + + OBJECT_START (obj) - ALLOCNO_NREGS
> (a)
> + + 1;
> + }
> + else
> + {
> + int A = hard_regno + conflict_object_start
> + - OBJECT_NREGS (obj) + 1;
> + start_regno = A - OBJECT_START (obj);
> + }
> +
> + for (int i = 0;
> + i <= OBJECT_NREGS (obj) + conflict_object_nregs -
> 2;
> + i += 1)
> + {
> + int regno = start_regno + i;
> + if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER)
> + SET_HARD_REG_BIT (start_conflicting_regs, regno);
> + }
> + if (hard_reg_set_subset_p (profitable_hard_regs,
> + start_conflicting_regs))
> + goto fail;
> + }
> else
> {
> - if (conflict_nregs == n_objects && conflict_nregs > 1)
> + if (has_subreg_object_p (conflict_a))
> {
> - int num = OBJECT_SUBWORD (conflict_obj);
> -
> - if (REG_WORDS_BIG_ENDIAN)
> - SET_HARD_REG_BIT (conflicting_regs[word],
> - hard_regno + n_objects - num -
> 1);
> - else
> - SET_HARD_REG_BIT (conflicting_regs[word],
> - hard_regno + num);
> + int start_hard_regno
> + = REG_WORDS_BIG_ENDIAN
> + ? hard_regno + ALLOCNO_NREGS (conflict_a)
> + - OBJECT_START (conflict_obj)
> + : hard_regno + OBJECT_START (conflict_obj);
> + for (int i = 0; i < OBJECT_NREGS (conflict_obj);
> + i += 1)
> + SET_HARD_REG_BIT (start_conflicting_regs,
> + start_hard_regno + i);
> }
> else
> - conflicting_regs[word]
> + start_conflicting_regs
> |= ira_reg_mode_hard_regset[hard_regno][mode];
> if (hard_reg_set_subset_p (profitable_hard_regs,
> - conflicting_regs[word]))
> + start_conflicting_regs))
> goto fail;
> }
> }
> @@ -2160,8 +2239,8 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
> && FIRST_STACK_REG <= hard_regno && hard_regno <= LAST_STACK_REG)
> continue;
> #endif
> - if (! check_hard_reg_p (a, hard_regno,
> - conflicting_regs, profitable_hard_regs))
> + if (!check_hard_reg_p (a, hard_regno, start_conflicting_regs,
> + profitable_hard_regs))
> continue;
> cost = costs[i];
> full_cost = full_costs[i];
> @@ -3154,7 +3233,7 @@ improve_allocation (void)
> machine_mode mode;
> int *allocno_costs;
> int costs[FIRST_PSEUDO_REGISTER];
> - HARD_REG_SET conflicting_regs[2], profitable_hard_regs;
> + HARD_REG_SET start_conflicting_regs, profitable_hard_regs;
> ira_allocno_t a;
> bitmap_iterator bi;
> int saved_nregs;
> @@ -3193,7 +3272,7 @@ improve_allocation (void)
> - allocno_copy_cost_saving (a, hregno));
> try_p = false;
> get_conflict_and_start_profitable_regs (a, false,
> - conflicting_regs,
> + &start_conflicting_regs,
> &profitable_hard_regs);
> class_size = ira_class_hard_regs_num[aclass];
> mode = ALLOCNO_MODE (a);
> @@ -3202,8 +3281,8 @@ improve_allocation (void)
> for (j = 0; j < class_size; j++)
> {
> hregno = ira_class_hard_regs[aclass][j];
> - if (! check_hard_reg_p (a, hregno,
> - conflicting_regs, profitable_hard_regs))
> + if (!check_hard_reg_p (a, hregno, start_conflicting_regs,
> + profitable_hard_regs))
> continue;
> ira_assert (ira_class_hard_reg_index[aclass][hregno] == j);
> k = allocno_costs == NULL ? 0 : j;
> @@ -3287,16 +3366,15 @@ improve_allocation (void)
> }
> conflict_nregs = hard_regno_nregs (conflict_hregno,
> ALLOCNO_MODE (conflict_a));
> - auto note_conflict = [&](int r)
> - {
> - if (check_hard_reg_p (a, r,
> - conflicting_regs,
> profitable_hard_regs))
> - {
> - if (spill_a)
> - SET_HARD_REG_BIT (soft_conflict_regs, r);
> - costs[r] += spill_cost;
> - }
> - };
> + auto note_conflict = [&] (int r) {
> + if (check_hard_reg_p (a, r, start_conflicting_regs,
> + profitable_hard_regs))
> + {
> + if (spill_a)
> + SET_HARD_REG_BIT (soft_conflict_regs, r);
> + costs[r] += spill_cost;
> + }
> + };
> for (r = conflict_hregno;
> r >= 0 && (int) end_hard_regno (mode, r) > conflict_hregno;
> r--)
> @@ -3314,8 +3392,8 @@ improve_allocation (void)
> for (j = 0; j < class_size; j++)
> {
> hregno = ira_class_hard_regs[aclass][j];
> - if (check_hard_reg_p (a, hregno,
> - conflicting_regs, profitable_hard_regs)
> + if (check_hard_reg_p (a, hregno, start_conflicting_regs,
> + profitable_hard_regs)
> && min_cost > costs[hregno])
> {
> best = hregno;
> diff --git a/gcc/ira-int.h b/gcc/ira-int.h
> index 0685e1f4e8d..b6281d3df6d 100644
> --- a/gcc/ira-int.h
> +++ b/gcc/ira-int.h
> @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
>
> #include "recog.h"
> #include "function-abi.h"
> +#include <vector>
>
> /* To provide consistency in naming, all IRA external variables,
> functions, common typedefs start with prefix ira_. */
> @@ -240,6 +241,13 @@ struct ira_object
> Zero means the lowest-order subword (or the entire allocno in case
> it is not being tracked in subwords). */
> int subword;
> + /* Reprensent OBJECT occupied [start, start + nregs) registers of it's
> + ALLOCNO. */
> + int start, nregs;
> + /* Reprensent the size and offset of current object, use to track subreg
> + range, For full reg, the size is GET_MODE_SIZE (ALLOCNO_MODE (allocno)),
> + offset is 0. */
> + poly_int64 size, offset;
> /* Allocated size of the conflicts array. */
> unsigned int conflicts_array_size;
> /* A unique number for every instance of this structure, which is used
> @@ -295,6 +303,11 @@ struct ira_allocno
> reload (at this point pseudo-register has only one allocno) which
> did not get stack slot yet. */
> signed int hard_regno : 16;
> + /* Unit size of one register that allocate for the allocno. Only use to
> + compute the start and nregs of subreg which be tracked. */
> + poly_int64 unit_size;
> + /* Flag means need track subreg live range for the allocno. */
> + bool track_subreg_p;
> /* A bitmask of the ABIs used by calls that occur while the allocno
> is live. */
> unsigned int crossed_calls_abis : NUM_ABI_IDS;
> @@ -353,8 +366,6 @@ struct ira_allocno
> register class living at the point than number of hard-registers
> of the class available for the allocation. */
> int excess_pressure_points_num;
> - /* The number of objects tracked in the following array. */
> - int num_objects;
> /* Accumulated frequency of calls which given allocno
> intersects. */
> int call_freq;
> @@ -387,8 +398,8 @@ struct ira_allocno
> /* An array of structures describing conflict information and live
> ranges for each object associated with the allocno. There may be
> more than one such object in cases where the allocno represents a
> - multi-word register. */
> - ira_object_t objects[2];
> + multi-hardreg pesudo. */
> + std::vector<ira_object_t> objects;
> /* Registers clobbered by intersected calls. */
> HARD_REG_SET crossed_calls_clobbered_regs;
> /* Array of usage costs (accumulated and the one updated during
> @@ -468,8 +479,12 @@ struct ira_allocno
> #define ALLOCNO_EXCESS_PRESSURE_POINTS_NUM(A) \
> ((A)->excess_pressure_points_num)
> #define ALLOCNO_OBJECT(A,N) ((A)->objects[N])
> -#define ALLOCNO_NUM_OBJECTS(A) ((A)->num_objects)
> +#define ALLOCNO_NUM_OBJECTS(A) ((int) (A)->objects.size ())
> #define ALLOCNO_ADD_DATA(A) ((A)->add_data)
> +#define ALLOCNO_UNIT_SIZE(A) ((A)->unit_size)
> +#define ALLOCNO_TRACK_SUBREG_P(A) ((A)->track_subreg_p)
> +#define ALLOCNO_NREGS(A)
> \
> + (ira_reg_class_max_nregs[ALLOCNO_CLASS (A)][ALLOCNO_MODE (A)])
>
> /* Typedef for pointer to the subsequent structure. */
> typedef struct ira_emit_data *ira_emit_data_t;
> @@ -511,6 +526,8 @@ allocno_emit_reg (ira_allocno_t a)
> }
>
> #define OBJECT_ALLOCNO(O) ((O)->allocno)
> +#define OBJECT_SIZE(O) ((O)->size)
> +#define OBJECT_OFFSET(O) ((O)->offset)
> #define OBJECT_SUBWORD(O) ((O)->subword)
> #define OBJECT_CONFLICT_ARRAY(O) ((O)->conflicts_array)
> #define OBJECT_CONFLICT_VEC(O) ((ira_object_t *)(O)->conflicts_array)
> @@ -524,6 +541,8 @@ allocno_emit_reg (ira_allocno_t a)
> #define OBJECT_MAX(O) ((O)->max)
> #define OBJECT_CONFLICT_ID(O) ((O)->id)
> #define OBJECT_LIVE_RANGES(O) ((O)->live_ranges)
> +#define OBJECT_START(O) ((O)->start)
> +#define OBJECT_NREGS(O) ((O)->nregs)
>
> /* Map regno -> allocnos with given regno (see comments for
> allocno member `next_regno_allocno'). */
> @@ -1041,6 +1060,8 @@ extern void ira_free_cost_vector (int *, reg_class_t);
> extern void ira_flattening (int, int);
> extern bool ira_build (void);
> extern void ira_destroy (void);
> +extern ira_object_t
> +find_object (ira_allocno_t, int, int);
>
> /* ira-costs.cc */
> extern void ira_init_costs_once (void);
> @@ -1708,4 +1729,18 @@ ira_caller_save_loop_spill_p (ira_allocno_t a,
> ira_allocno_t subloop_a,
> return call_cost && call_cost >= spill_cost;
> }
>
> +/* Return true if allocno A has subreg object. */
> +inline bool
> +has_subreg_object_p (ira_allocno_t a)
> +{
> + return ALLOCNO_NUM_OBJECTS (a) > 1;
> +}
> +
> +/* Return the full object of allocno A. */
> +inline ira_object_t
> +get_full_object (ira_allocno_t a)
> +{
> + return find_object (a, 0, ALLOCNO_NREGS (a));
> +}
> +
> #endif /* GCC_IRA_INT_H */
> diff --git a/gcc/ira.cc b/gcc/ira.cc
> index d7530f01380..2fa6e0e5c94 100644
> --- a/gcc/ira.cc
> +++ b/gcc/ira.cc
> @@ -2623,7 +2623,7 @@ static void
> check_allocation (void)
> {
> ira_allocno_t a;
> - int hard_regno, nregs, conflict_nregs;
> + int hard_regno;
> ira_allocno_iterator ai;
>
> FOR_EACH_ALLOCNO (a, ai)
> @@ -2634,28 +2634,18 @@ check_allocation (void)
> if (ALLOCNO_CAP_MEMBER (a) != NULL
> || (hard_regno = ALLOCNO_HARD_REGNO (a)) < 0)
> continue;
> - nregs = hard_regno_nregs (hard_regno, ALLOCNO_MODE (a));
> - if (nregs == 1)
> - /* We allocated a single hard register. */
> - n = 1;
> - else if (n > 1)
> - /* We allocated multiple hard registers, and we will test
> - conflicts in a granularity of single hard regs. */
> - nregs = 1;
>
> for (i = 0; i < n; i++)
> {
> ira_object_t obj = ALLOCNO_OBJECT (a, i);
> ira_object_t conflict_obj;
> ira_object_conflict_iterator oci;
> - int this_regno = hard_regno;
> - if (n > 1)
> - {
> - if (REG_WORDS_BIG_ENDIAN)
> - this_regno += n - i - 1;
> - else
> - this_regno += i;
> - }
> + int this_regno;
> + if (REG_WORDS_BIG_ENDIAN)
> + this_regno = hard_regno + ALLOCNO_NREGS (a) - 1 - OBJECT_START
> (obj)
> + - OBJECT_NREGS (obj) + 1;
> + else
> + this_regno = hard_regno + OBJECT_START (obj);
> FOR_EACH_OBJECT_CONFLICT (obj, conflict_obj, oci)
> {
> ira_allocno_t conflict_a = OBJECT_ALLOCNO (conflict_obj);
> @@ -2665,24 +2655,18 @@ check_allocation (void)
> if (ira_soft_conflict (a, conflict_a))
> continue;
>
> - conflict_nregs = hard_regno_nregs (conflict_hard_regno,
> - ALLOCNO_MODE (conflict_a));
> -
> - if (ALLOCNO_NUM_OBJECTS (conflict_a) > 1
> - && conflict_nregs == ALLOCNO_NUM_OBJECTS (conflict_a))
> - {
> - if (REG_WORDS_BIG_ENDIAN)
> - conflict_hard_regno += (ALLOCNO_NUM_OBJECTS (conflict_a)
> - - OBJECT_SUBWORD (conflict_obj) -
> 1);
> - else
> - conflict_hard_regno += OBJECT_SUBWORD (conflict_obj);
> - conflict_nregs = 1;
> - }
> + if (REG_WORDS_BIG_ENDIAN)
> + conflict_hard_regno = conflict_hard_regno
> + + ALLOCNO_NREGS (conflict_a) - 1
> + - OBJECT_START (conflict_obj)
> + - OBJECT_NREGS (conflict_obj) + 1;
> + else
> + conflict_hard_regno
> + = conflict_hard_regno + OBJECT_START (conflict_obj);
>
> - if ((conflict_hard_regno <= this_regno
> - && this_regno < conflict_hard_regno + conflict_nregs)
> - || (this_regno <= conflict_hard_regno
> - && conflict_hard_regno < this_regno + nregs))
> + if (!(this_regno + OBJECT_NREGS (obj) <= conflict_hard_regno
> + || conflict_hard_regno + OBJECT_NREGS (conflict_obj)
> + <= this_regno))
> {
> fprintf (stderr, "bad allocation for %d and %d\n",
> ALLOCNO_REGNO (a), ALLOCNO_REGNO (conflict_a));
> --
> 2.36.3
>