From: Richard Sandiford <richard.sandiford@arm.com>
To: Lehua Ding <lehua.ding@rivai.ai>
Cc: gcc-patches@gcc.gnu.org, vmakarov@redhat.com, juzhe.zhong@rivai.ai
Subject: Re: [PATCH V3 1/7] df: Add DF_LIVE_SUBREG problem
Date: Mon, 20 Nov 2023 20:11:11 +0000 [thread overview]
Message-ID: <mptmsv8kwww.fsf@arm.com> (raw)
In-Reply-To: <20231112120817.2635864-2-lehua.ding@rivai.ai> (Lehua Ding's message of "Sun, 12 Nov 2023 20:08:11 +0800")
Lehua Ding <lehua.ding@rivai.ai> writes:
> This patch adds a live_subreg problem to extend the original live_reg to
> track the liveness of subreg. We will only try to trace speudo registers
> who's mode size is a multiple of nature size and eventually a small portion
> of the inside will appear to use subreg. With live_reg problem, live_subreg
> prbolem will have the following output. full_in/out mean the entire pesudo
> live in/out, partial_in/out mean the subregs of the pesudo are live in/out,
> and range_in/out indicates which part of the pesudo is live. all_in/out is
> the union of full_in/out and partial_in/out:
>
> bitmap_head all_in, full_in;
> bitmap_head all_out, full_out;
> bitmap_head partial_in;
> bitmap_head partial_out;
> subregs_live *range_in = NULL;
> subregs_live *range_out = NULL;
I haven't fully processed the patch yet, sorry. And I think I might be
about to cover things that you dealt with elsewhere.
My assumption going into this was that a subreg liveness tracker would
work as follows:
- First we would work out which registers need to have subreg tracking.
This could be done ahead of time by iterating over regno_reg_rtx.
The condition in need_track_subreg looks like the correct one.
For every other register, subreg liveness degenerates to the existing
liveness problems. Such registers can be ignored.
- We would assign a unique identifier to each subreg that we want to track,
with subregs for the same register being consecutive.
- There would be a mapping from pseudo registers to the first subreg
that we want to track. The mapping would probably just be a linear
array, but perhaps there are times when something more compact is
appropriate.
- The dataflow problem itself would then be very similar to the existing
ones. But rather than computing bitmaps with a single bit per register,
we'd be computing bitmaps that have N bits for N-register pseudos
(and no bits for single-register pseudos).
- There would be helper functions that consumers could use to iterate
over a block. E.g. for a backwards walk over a block, a consumer
would start with the bitmap of live-out subregs. It would then use
these helper functions to keep the values up-to-date as it moves
up through the block.
That's done for normal liveness via the df_simulate_* helpers.
But now that the codebase is C++, it might be more convenient for
the subreg code to provide classes for walking a block.
That should be relatively compile-time-friendly, although I agree
with Vlad of course that DF does have efficiency problems. The nature
of the way it works makes it at least O(#blocks * #regs).
Did you consider doing it that way? Or does it not provide the
information that you need?
Thanks,
Richard
> gcc/ChangeLog:
>
> * Makefile.in: Add new object file.
> * df-problems.cc (struct df_live_subreg_problem_data):
> The data of the new live_subreg problem.
> (need_track_subreg): New function.
> (get_range): Ditto.
> (remove_subreg_range): Ditto.
> (add_subreg_range): Ditto.
> (df_live_subreg_free_bb_info): Ditto.
> (df_live_subreg_alloc): Ditto.
> (df_live_subreg_reset): Ditto.
> (df_live_subreg_bb_local_compute): Ditto.
> (df_live_subreg_local_compute): Ditto.
> (df_live_subreg_init): Ditto.
> (df_live_subreg_check_result): Ditto.
> (df_live_subreg_confluence_0): Ditto.
> (df_live_subreg_confluence_n): Ditto.
> (df_live_subreg_transfer_function): Ditto.
> (df_live_subreg_finalize): Ditto.
> (df_live_subreg_free): Ditto.
> (df_live_subreg_top_dump): Ditto.
> (df_live_subreg_bottom_dump): Ditto.
> (df_live_subreg_add_problem): Ditto.
> * df.h (enum df_problem_id): Add live_subreg id.
> (DF_LIVE_SUBREG_INFO): Data accessor.
> (DF_LIVE_SUBREG_IN): Ditto.
> (DF_LIVE_SUBREG_OUT): Ditto.
> (DF_LIVE_SUBREG_FULL_IN): Ditto.
> (DF_LIVE_SUBREG_FULL_OUT): Ditto.
> (DF_LIVE_SUBREG_PARTIAL_IN): Ditto.
> (DF_LIVE_SUBREG_PARTIAL_OUT): Ditto.
> (DF_LIVE_SUBREG_RANGE_IN): Ditto.
> (DF_LIVE_SUBREG_RANGE_OUT): Ditto.
> (class subregs_live): New class.
> (class basic_block_subreg_live_info): Ditto.
> (class df_live_subreg_bb_info): Ditto.
> (df_live_subreg): Ditto.
> (df_live_subreg_add_problem): Ditto.
> (df_live_subreg_finalize): Ditto.
> (class subreg_range): Ditto.
> (need_track_subreg): Ditto.
> (remove_subreg_range): Ditto.
> (add_subreg_range): Ditto.
> (df_live_subreg_get_bb_info): Ditto.
> * regs.h (get_nblocks): Helper function.
> * timevar.def (TV_DF_LIVE_SUBREG): New timevar.
> * subreg-live-range.cc: New file.
> * subreg-live-range.h: New file.
>
> ---
> gcc/Makefile.in | 1 +
> gcc/df-problems.cc | 889 ++++++++++++++++++++++++++++++++++++++-
> gcc/df.h | 67 +++
> gcc/regs.h | 7 +
> gcc/subreg-live-range.cc | 628 +++++++++++++++++++++++++++
> gcc/subreg-live-range.h | 333 +++++++++++++++
> gcc/timevar.def | 1 +
> 7 files changed, 1925 insertions(+), 1 deletion(-)
> create mode 100644 gcc/subreg-live-range.cc
> create mode 100644 gcc/subreg-live-range.h
>
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 29cec21c825..e4403b5a30c 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1675,6 +1675,7 @@ OBJS = \
> store-motion.o \
> streamer-hooks.o \
> stringpool.o \
> + subreg-live-range.o \
> substring-locations.o \
> target-globals.o \
> targhooks.o \
> diff --git a/gcc/df-problems.cc b/gcc/df-problems.cc
> index d2cfaf7f50f..2585c762fd1 100644
> --- a/gcc/df-problems.cc
> +++ b/gcc/df-problems.cc
> @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
> #include "target.h"
> #include "rtl.h"
> #include "df.h"
> +#include "subreg-live-range.h"
> #include "memmodel.h"
> #include "tm_p.h"
> #include "insn-config.h"
> @@ -1344,8 +1345,894 @@ df_lr_verify_transfer_functions (void)
> bitmap_clear (&all_blocks);
> }
>
> +/*----------------------------------------------------------------------------
> + REGISTER AND SUBREG LIVES
> + Like DF_RL, but fine-grained tracking of subreg lifecycle.
> + ----------------------------------------------------------------------------*/
> +
> +/* Private data used to verify the solution for this problem. */
> +struct df_live_subreg_problem_data
> +{
> + /* An obstack for the bitmaps we need for this problem. */
> + bitmap_obstack live_subreg_bitmaps;
> + bool has_subreg_live_p;
> +};
> +
> +/* Helper functions */
> +
> +/* Return true if REGNO is a pseudo and MODE is a multil regs size. */
> +bool
> +need_track_subreg (int regno, machine_mode reg_mode)
> +{
> + poly_int64 total_size = GET_MODE_SIZE (reg_mode);
> + poly_int64 natural_size = REGMODE_NATURAL_SIZE (reg_mode);
> + return maybe_gt (total_size, natural_size)
> + && multiple_p (total_size, natural_size)
> + && regno >= FIRST_PSEUDO_REGISTER;
> +}
> +
> +/* Return subreg_range of REF. */
> +static subreg_range
> +get_range (df_ref ref)
> +{
> + rtx reg = DF_REF_REAL_REG (ref);
> + machine_mode reg_mode = GET_MODE (reg);
> +
> + if (!read_modify_subreg_p (DF_REF_REG (ref)))
> + return subreg_range (0, get_nblocks (reg_mode));
> +
> + rtx subreg = DF_REF_REG (ref);
> + machine_mode subreg_mode = GET_MODE (subreg);
> + poly_int64 offset = SUBREG_BYTE (subreg);
> + int nblocks = get_nblocks (reg_mode);
> + poly_int64 unit_size = REGMODE_NATURAL_SIZE (reg_mode);
> + poly_int64 subreg_size = GET_MODE_SIZE (subreg_mode);
> + poly_int64 left = offset + subreg_size;
> +
> + int subreg_start = -1;
> + int subreg_nblocks = -1;
> + for (int i = 0; i < nblocks; i += 1)
> + {
> + poly_int64 right = unit_size * (i + 1);
> + if (subreg_start < 0 && maybe_lt (offset, right))
> + subreg_start = i;
> + if (subreg_nblocks < 0 && maybe_le (left, right))
> + {
> + subreg_nblocks = i + 1 - subreg_start;
> + break;
> + }
> + }
> + gcc_assert (subreg_start >= 0 && subreg_nblocks > 0);
> +
> + return subreg_range (subreg_start, subreg_start + subreg_nblocks);
> +}
> +
> +/* Remove REF from BB_INFO use. */
> +void
> +remove_subreg_range (basic_block_subreg_live_info *bb_info, unsigned int regno,
> + machine_mode mode, const subreg_range &range)
> +{
> + int max = get_nblocks (mode);
> + bitmap full = &bb_info->full_use;
> + bitmap partial = &bb_info->partial_use;
> + subregs_live *range_live = bb_info->range_use;
> +
> + if (!range.full_p (max))
> + {
> + if (bitmap_bit_p (full, regno))
> + {
> + bitmap_clear_bit (full, regno);
> + gcc_assert (!bitmap_bit_p (partial, regno));
> + gcc_assert (range_live->empty_p (regno));
> + subreg_ranges temp = subreg_ranges (max);
> + temp.make_full ();
> + temp.remove_range (max, range);
> + range_live->add_ranges (regno, temp);
> + bitmap_set_bit (partial, regno);
> + return;
> + }
> + else if (bitmap_bit_p (partial, regno))
> + {
> + range_live->remove_range (regno, max, range);
> + if (range_live->empty_p (regno))
> + bitmap_clear_bit (partial, regno);
> + }
> + }
> + else if (bitmap_bit_p (full, regno))
> + {
> + bitmap_clear_bit (full, regno);
> + gcc_assert (!bitmap_bit_p (partial, regno));
> + }
> + else if (bitmap_bit_p (partial, regno))
> + {
> + bitmap_clear_bit (partial, regno);
> + range_live->remove_live (regno);
> + }
> +}
> +
> +/* Return true if ref is a tracked subreg access. */
> +bool
> +remove_subreg_range (basic_block_subreg_live_info *bb_info, df_ref ref)
> +{
> + unsigned int regno = DF_REF_REGNO (ref);
> + machine_mode mode = GET_MODE (DF_REF_REAL_REG (ref));
> + bool subreg_p = read_modify_subreg_p (DF_REF_REG (ref));
> +
> + if (need_track_subreg (regno, mode))
> + {
> + remove_subreg_range (bb_info, regno, mode, get_range (ref));
> + return subreg_p;
> + }
> + else
> + {
> + bitmap_clear_bit (&bb_info->full_use, regno);
> + gcc_assert (!bitmap_bit_p (&bb_info->partial_use, regno));
> + gcc_assert (!bitmap_bit_p (&bb_info->partial_def, regno));
> + return false;
> + }
> +}
> +
> +/* add REF to BB_INFO def/use. */
> +void
> +add_subreg_range (basic_block_subreg_live_info *bb_info, unsigned int regno,
> + machine_mode mode, const subreg_range &range, bool is_def)
> +{
> + int max = get_nblocks (mode);
> + bitmap full = is_def ? &bb_info->full_def : &bb_info->full_use;
> + bitmap partial = is_def ? &bb_info->partial_def : &bb_info->partial_use;
> + subregs_live *range_live = is_def ? bb_info->range_def : bb_info->range_use;
> +
> + if (!range.full_p (max))
> + {
> + if (bitmap_bit_p (full, regno))
> + return;
> + range_live->add_range (regno, max, range);
> + if (range_live->full_p (regno))
> + {
> + bitmap_set_bit (full, regno);
> + gcc_assert (bitmap_bit_p (partial, regno));
> + bitmap_clear_bit (partial, regno);
> + range_live->remove_live (regno);
> + }
> + else if (!bitmap_bit_p (partial, regno))
> + bitmap_set_bit (partial, regno);
> + }
> + else if (!bitmap_bit_p (full, regno))
> + {
> + bitmap_set_bit (full, regno);
> + if (bitmap_bit_p (partial, regno))
> + {
> + bitmap_clear_bit (partial, regno);
> + range_live->remove_live (regno);
> + }
> + }
> +}
> +
> +/* Return true if ref is a tracked subreg access. */
> +bool
> +add_subreg_range (basic_block_subreg_live_info *bb_info, df_ref ref,
> + bool is_def)
> +{
> + unsigned int regno = DF_REF_REGNO (ref);
> + machine_mode mode = GET_MODE (DF_REF_REAL_REG (ref));
> + bool subreg_p = read_modify_subreg_p (DF_REF_REG (ref));
> +
> + if (need_track_subreg (regno, mode))
> + {
> + add_subreg_range (bb_info, regno, mode, get_range (ref), is_def);
> + return subreg_p;
> + }
> + else
> + {
> + bitmap full = is_def ? &bb_info->full_def : &bb_info->full_use;
> + bitmap partial = is_def ? &bb_info->partial_def : &bb_info->partial_use;
> + bitmap_set_bit (full, regno);
> + gcc_assert (!bitmap_bit_p (partial, regno));
> +
> + if (is_def && DF_REF_FLAGS (ref) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL))
> + add_subreg_range (bb_info, ref, false);
> + return false;
> + }
> +}
> +
> +/* Free basic block info. */
> +
> +static void
> +df_live_subreg_free_bb_info (basic_block bb ATTRIBUTE_UNUSED, void *vbb_info)
> +{
> + df_live_subreg_bb_info *bb_info = (df_live_subreg_bb_info *) vbb_info;
> + if (bb_info)
> + {
> + delete bb_info->range_def;
> + bb_info->range_def = NULL;
> + delete bb_info->range_use;
> + bb_info->range_use = NULL;
> + delete bb_info->range_in;
> + bb_info->range_in = NULL;
> + delete bb_info->range_out;
> + bb_info->range_out = NULL;
> +
> + bitmap_clear (&bb_info->full_use);
> + bitmap_clear (&bb_info->partial_use);
> + bitmap_clear (&bb_info->full_def);
> + bitmap_clear (&bb_info->partial_def);
> + bitmap_clear (&bb_info->all_in);
> + bitmap_clear (&bb_info->full_in);
> + bitmap_clear (&bb_info->partial_in);
> + bitmap_clear (&bb_info->all_out);
> + bitmap_clear (&bb_info->full_out);
> + bitmap_clear (&bb_info->partial_out);
> + }
> +}
> +
> +/* Allocate or reset bitmaps for DF_LIVE_SUBREG blocks. The solution bits are
> + not touched unless the block is new. */
> +
> +static void
> +df_live_subreg_alloc (bitmap all_blocks ATTRIBUTE_UNUSED)
> +{
> + struct df_live_subreg_problem_data *problem_data;
> + df_grow_bb_info (df_live_subreg);
> + if (df_live_subreg->problem_data)
> + problem_data
> + = (struct df_live_subreg_problem_data *) df_live_subreg->problem_data;
> + else
> + {
> + problem_data = XNEW (struct df_live_subreg_problem_data);
> + df_live_subreg->problem_data = problem_data;
> +
> + bitmap_obstack_initialize (&problem_data->live_subreg_bitmaps);
> + problem_data->has_subreg_live_p = false;
> + }
> +
> + basic_block bb;
> + FOR_EACH_BB_FN (bb, cfun)
> + bitmap_set_bit (df_live_subreg->out_of_date_transfer_functions, bb->index);
> +
> + bitmap_set_bit (df_live_subreg->out_of_date_transfer_functions, ENTRY_BLOCK);
> + bitmap_set_bit (df_live_subreg->out_of_date_transfer_functions, EXIT_BLOCK);
> +
> + unsigned int bb_index;
> + bitmap_iterator bi;
> + EXECUTE_IF_SET_IN_BITMAP (df_live_subreg->out_of_date_transfer_functions, 0,
> + bb_index, bi)
> + {
> + df_live_subreg_bb_info *bb_info = df_live_subreg_get_bb_info (bb_index);
> +
> + /* When bitmaps are already initialized, just clear them. */
> + if (bb_info->full_use.obstack)
> + {
> + bitmap_clear (&bb_info->full_def);
> + bitmap_clear (&bb_info->partial_def);
> + bitmap_clear (&bb_info->full_use);
> + bitmap_clear (&bb_info->partial_use);
> + bitmap_clear (&bb_info->all_in);
> + bitmap_clear (&bb_info->full_in);
> + bitmap_clear (&bb_info->partial_in);
> + bitmap_clear (&bb_info->all_out);
> + bitmap_clear (&bb_info->full_out);
> + bitmap_clear (&bb_info->partial_out);
> + }
> + else
> + {
> + bitmap_initialize (&bb_info->full_def,
> + &problem_data->live_subreg_bitmaps);
> + bitmap_initialize (&bb_info->partial_def,
> + &problem_data->live_subreg_bitmaps);
> + bitmap_initialize (&bb_info->full_use,
> + &problem_data->live_subreg_bitmaps);
> + bitmap_initialize (&bb_info->partial_use,
> + &problem_data->live_subreg_bitmaps);
> + bitmap_initialize (&bb_info->all_in,
> + &problem_data->live_subreg_bitmaps);
> + bitmap_initialize (&bb_info->full_in,
> + &problem_data->live_subreg_bitmaps);
> + bitmap_initialize (&bb_info->partial_in,
> + &problem_data->live_subreg_bitmaps);
> + bitmap_initialize (&bb_info->all_out,
> + &problem_data->live_subreg_bitmaps);
> + bitmap_initialize (&bb_info->full_out,
> + &problem_data->live_subreg_bitmaps);
> + bitmap_initialize (&bb_info->partial_out,
> + &problem_data->live_subreg_bitmaps);
> + }
> +
> + if (bb_info->range_def)
> + {
> + bb_info->range_def->clear ();
> + bb_info->range_use->clear ();
> + bb_info->range_in->clear ();
> + bb_info->range_out->clear ();
> + }
> + else
> + {
> + bb_info->range_def = new subregs_live ();
> + bb_info->range_use = new subregs_live ();
> + bb_info->range_in = new subregs_live ();
> + bb_info->range_out = new subregs_live ();
> + }
> + }
> + df_live_subreg->optional_p = true;
> +}
> +
> +/* Reset the global solution for recalculation. */
> +
> +static void
> +df_live_subreg_reset (bitmap all_blocks)
> +{
> + unsigned int bb_index;
> + bitmap_iterator bi;
> +
> + EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
> + {
> + df_live_subreg_bb_info *bb_info = df_live_subreg_get_bb_info (bb_index);
> + gcc_assert (bb_info);
> + bitmap_clear (&bb_info->all_in);
> + bitmap_clear (&bb_info->full_in);
> + bitmap_clear (&bb_info->partial_in);
> + bitmap_clear (&bb_info->all_out);
> + bitmap_clear (&bb_info->full_out);
> + bitmap_clear (&bb_info->partial_out);
> + bb_info->range_in->clear ();
> + bb_info->range_out->clear ();
> + }
> +}
> +
> +/* Compute local live register info for basic block BB. */
> +
> +static void
> +df_live_subreg_bb_local_compute (unsigned int bb_index)
> +{
> + basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
> + df_live_subreg_bb_info *bb_info = df_live_subreg_get_bb_info (bb_index);
> + df_live_subreg_problem_data *problem_data
> + = (df_live_subreg_problem_data *) df_live_subreg->problem_data;
> + rtx_insn *insn;
> + df_ref def, use;
> +
> + /* Process the registers set in an exception handler. */
> + FOR_EACH_ARTIFICIAL_DEF (def, bb_index)
> + if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0)
> + {
> + problem_data->has_subreg_live_p
> + |= add_subreg_range (bb_info, def, true);
> + problem_data->has_subreg_live_p |= remove_subreg_range (bb_info, def);
> + }
> +
> + /* Process the hardware registers that are always live. */
> + FOR_EACH_ARTIFICIAL_USE (use, bb_index)
> + /* Add use to set of uses in this BB. */
> + if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == 0)
> + problem_data->has_subreg_live_p |= add_subreg_range (bb_info, use);
> +
> + FOR_BB_INSNS_REVERSE (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)
> + {
> + problem_data->has_subreg_live_p |= remove_subreg_range (bb_info, def);
> + problem_data->has_subreg_live_p
> + |= add_subreg_range (bb_info, def, true);
> + }
> +
> + FOR_EACH_INSN_INFO_USE (use, insn_info)
> + {
> + unsigned int regno = DF_REF_REGNO (use);
> + machine_mode mode = GET_MODE (DF_REF_REAL_REG (use));
> + /* Ignore the use of SET_DEST which is (subreg (reg) offset). */
> + if (need_track_subreg (regno, mode)
> + && DF_REF_FLAGS (use) & (DF_REF_READ_WRITE | DF_REF_SUBREG))
> + continue;
> + problem_data->has_subreg_live_p |= add_subreg_range (bb_info, use);
> + }
> + }
> +
> + /* Process the registers set in an exception handler or the hard
> + frame pointer if this block is the target of a non local
> + goto. */
> + FOR_EACH_ARTIFICIAL_DEF (def, bb_index)
> + if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
> + {
> + problem_data->has_subreg_live_p
> + |= add_subreg_range (bb_info, def, true);
> + problem_data->has_subreg_live_p |= remove_subreg_range (bb_info, def);
> + }
> +
> +#ifdef EH_USES
> + /* Process the uses that are live into an exception handler. */
> + FOR_EACH_ARTIFICIAL_USE (use, bb_index)
> + /* Add use to set of uses in this BB. */
> + if (DF_REF_FLAGS (use) & DF_REF_AT_TOP)
> + problem_data->has_subreg_live_p |= add_subreg_range (bb_info, use);
> +#endif
> +}
> +
> +/* Compute local live register info for each basic block within BLOCKS. */
> +
> +static void
> +df_live_subreg_local_compute (bitmap all_blocks ATTRIBUTE_UNUSED)
> +{
> + unsigned int bb_index, i;
> + bitmap_iterator bi;
> +
> + bitmap_clear (&df->hardware_regs_used);
> +
> + /* The all-important stack pointer must always be live. */
> + bitmap_set_bit (&df->hardware_regs_used, STACK_POINTER_REGNUM);
> +
> + /* Global regs are always live, too. */
> + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> + if (global_regs[i])
> + bitmap_set_bit (&df->hardware_regs_used, i);
> +
> + /* Before reload, there are a few registers that must be forced
> + live everywhere -- which might not already be the case for
> + blocks within infinite loops. */
> + if (!reload_completed)
> + {
> + unsigned int pic_offset_table_regnum = PIC_OFFSET_TABLE_REGNUM;
> + /* Any reference to any pseudo before reload is a potential
> + reference of the frame pointer. */
> + bitmap_set_bit (&df->hardware_regs_used, FRAME_POINTER_REGNUM);
> +
> + /* Pseudos with argument area equivalences may require
> + reloading via the argument pointer. */
> + if (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
> + && fixed_regs[ARG_POINTER_REGNUM])
> + bitmap_set_bit (&df->hardware_regs_used, ARG_POINTER_REGNUM);
> +
> + /* Any constant, or pseudo with constant equivalences, may
> + require reloading from memory using the pic register. */
> + if (pic_offset_table_regnum != INVALID_REGNUM
> + && fixed_regs[pic_offset_table_regnum])
> + bitmap_set_bit (&df->hardware_regs_used, pic_offset_table_regnum);
> + }
> +
> + EXECUTE_IF_SET_IN_BITMAP (df_live_subreg->out_of_date_transfer_functions, 0,
> + bb_index, bi)
> + {
> + if (bb_index == EXIT_BLOCK)
> + {
> + /* The exit block is special for this problem and its bits are
> + computed from thin air. */
> + class df_live_subreg_bb_info *bb_info
> + = df_live_subreg_get_bb_info (EXIT_BLOCK);
> + bitmap_copy (&bb_info->full_use, df->exit_block_uses);
> + }
> + else
> + df_live_subreg_bb_local_compute (bb_index);
> + }
> +
> + bitmap_clear (df_live_subreg->out_of_date_transfer_functions);
> +}
> +
> +/* Initialize the solution vectors. */
> +
> +static void
> +df_live_subreg_init (bitmap all_blocks)
> +{
> + unsigned int bb_index;
> + bitmap_iterator bi;
> +
> + EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
> + {
> + df_live_subreg_bb_info *bb_info = df_live_subreg_get_bb_info (bb_index);
> + bitmap_copy (&bb_info->full_in, &bb_info->full_use);
> + bitmap_copy (&bb_info->partial_in, &bb_info->partial_use);
> + bb_info->range_in->copy_lives (*bb_info->range_use);
> + bitmap_clear (&bb_info->full_out);
> + bitmap_clear (&bb_info->partial_out);
> + bb_info->range_out->clear ();
> + }
> +}
> +
> +/* Check the result is golden. */
> +static void
> +df_live_subreg_check_result (bitmap full, bitmap partial,
> + subregs_live *partial_live)
> +{
> + unsigned int regno;
> + bitmap_iterator bi;
> + gcc_assert (!bitmap_intersect_p (full, partial));
> + EXECUTE_IF_SET_IN_BITMAP (full, 0, regno, bi)
> + gcc_assert (partial_live->empty_p (regno));
> + EXECUTE_IF_SET_IN_BITMAP (partial, 0, regno, bi)
> + gcc_assert (!partial_live->empty_p (regno));
> +}
> +
> +/* Confluence function that processes infinite loops. This might be a
> + noreturn function that throws. And even if it isn't, getting the
> + unwind info right helps debugging. */
> +static void
> +df_live_subreg_confluence_0 (basic_block bb)
> +{
> + bitmap full_out = &df_live_subreg_get_bb_info (bb->index)->full_out;
> + if (bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
> + bitmap_copy (full_out, &df->hardware_regs_used);
> +}
> +
> +/* Confluence function that ignores fake edges. */
> +
> +static bool
> +df_live_subreg_confluence_n (edge e)
> +{
> + df_live_subreg_problem_data *problem_data
> + = (df_live_subreg_problem_data *) df_live_subreg->problem_data;
> + class df_live_subreg_bb_info *src_bb_info
> + = df_live_subreg_get_bb_info (e->src->index);
> + class df_live_subreg_bb_info *dest_bb_info
> + = df_live_subreg_get_bb_info (e->dest->index);
> +
> + if (!problem_data->has_subreg_live_p)
> + {
> + bool changed = false;
> +
> + /* Call-clobbered registers die across exception and call edges.
> + Conservatively treat partially-clobbered registers as surviving
> + across the edges; they might or might not, depending on what
> + mode they have. */
> + /* ??? Abnormal call edges ignored for the moment, as this gets
> + confused by sibling call edges, which crashes reg-stack. */
> + if (e->flags & EDGE_EH)
> + {
> + bitmap_view<HARD_REG_SET> eh_kills (eh_edge_abi.full_reg_clobbers ());
> + changed
> + = bitmap_ior_and_compl_into (&src_bb_info->full_out,
> + &dest_bb_info->full_in, eh_kills);
> + }
> + else
> + changed
> + = bitmap_ior_into (&src_bb_info->full_out, &dest_bb_info->full_in);
> +
> + changed
> + |= bitmap_ior_into (&src_bb_info->full_out, &df->hardware_regs_used);
> + return changed;
> + }
> +
> + /* If there has subreg live need be tracked. Calculation formula:
> + temp_full mean:
> + 1. partial in out/in, full in other in/out
> + 2. partial in out and in, and mrege range is full
> + temp_range mean:
> + the range of regno which partial live
> + src_bb_info->partial_out = (src_bb_info->partial_out |
> + dest_bb_info->partial_in) & ~temp_full
> + src_bb_info->range_out = copy(temp_range)
> + src_bb_info->full_out |= dest_bb_info->full_in | temp_full
> + */
> + subregs_live temp_range;
> + temp_range.add_lives (*src_bb_info->range_out);
> + temp_range.add_lives (*dest_bb_info->range_in);
> +
> + bitmap_head temp_partial_all;
> + bitmap_initialize (&temp_partial_all, &bitmap_default_obstack);
> + bitmap_ior (&temp_partial_all, &src_bb_info->partial_out,
> + &dest_bb_info->partial_in);
> +
> + bitmap_head temp_full;
> + bitmap_initialize (&temp_full, &bitmap_default_obstack);
> +
> + /* Collect regno that become full after merge src_bb_info->partial_out
> + and dest_bb_info->partial_in. */
> + unsigned int regno;
> + bitmap_iterator bi;
> + EXECUTE_IF_SET_IN_BITMAP (&temp_partial_all, FIRST_PSEUDO_REGISTER, regno, bi)
> + {
> + if (bitmap_bit_p (&src_bb_info->full_out, regno)
> + || bitmap_bit_p (&dest_bb_info->full_in, regno))
> + {
> + bitmap_set_bit (&temp_full, regno);
> + temp_range.remove_live (regno);
> + continue;
> + }
> + else if (!bitmap_bit_p (&src_bb_info->partial_out, regno)
> + || !bitmap_bit_p (&dest_bb_info->partial_in, regno))
> + continue;
> +
> + subreg_ranges temp = src_bb_info->range_out->lives.at (regno);
> + temp.add_ranges (dest_bb_info->range_in->lives.at (regno));
> + if (temp.full_p ())
> + {
> + bitmap_set_bit (&temp_full, regno);
> + temp_range.remove_live (regno);
> + }
> + }
> +
> + /* Calculating src_bb_info->partial_out and src_bb_info->range_out. */
> + bool changed = bitmap_and_compl (&src_bb_info->partial_out, &temp_partial_all,
> + &temp_full);
> + changed |= src_bb_info->range_out->copy_lives (temp_range);
> +
> + /* Calculating src_bb_info->full_out. */
> + bitmap_ior_into (&temp_full, &dest_bb_info->full_in);
> +
> + /* Call-clobbered registers die across exception and call edges.
> + Conservatively treat partially-clobbered registers as surviving
> + across the edges; they might or might not, depending on what
> + mode they have. */
> + /* ??? Abnormal call edges ignored for the moment, as this gets
> + confused by sibling call edges, which crashes reg-stack. */
> + if (e->flags & EDGE_EH)
> + {
> + bitmap_view<HARD_REG_SET> eh_kills (eh_edge_abi.full_reg_clobbers ());
> + changed |= bitmap_ior_and_compl_into (&src_bb_info->full_out, &temp_full,
> + eh_kills);
> + }
> + else
> + changed |= bitmap_ior_into (&src_bb_info->full_out, &temp_full);
> +
> + changed |= bitmap_ior_into (&src_bb_info->full_out, &df->hardware_regs_used);
> +
> + bitmap_clear (&temp_full);
> + bitmap_clear (&temp_partial_all);
> +
> + df_live_subreg_check_result (&src_bb_info->full_out,
> + &src_bb_info->partial_out,
> + src_bb_info->range_out);
> + return changed;
> +}
> +
> +/* Transfer function. */
> +
> +static bool
> +df_live_subreg_transfer_function (int bb_index)
> +{
> + class df_live_subreg_bb_info *bb_info = df_live_subreg_get_bb_info (bb_index);
> + df_live_subreg_problem_data *problem_data
> + = (df_live_subreg_problem_data *) df_live_subreg->problem_data;
> + if (!problem_data->has_subreg_live_p)
> + {
> + bitmap in = &bb_info->full_in;
> + bitmap out = &bb_info->full_out;
> + bitmap use = &bb_info->full_use;
> + bitmap def = &bb_info->full_def;
> +
> + return bitmap_ior_and_compl (in, use, out, def);
> + }
> +
> + /* If there has subreg live need be tracked, follow the bellow calculation
> + formula:
> + all_def = full_def | partial_def
> + temp_partial_out = ((full_out & partail_def)
> + | (partail_out & ~all_def)
> + | (partial_out remove partail_def not empty))
> + & ~full_use
> + temp_partial_be_full = (temp_partial_out & partial_use) merge be full
> + full_in = full_use | full_out & ~all_def | temp_partial_be_full
> + partail_in = (temp_partial_out | partial_use) & ~temp_partial_be_full */
> + unsigned int regno;
> + bitmap_iterator bi;
> + bool changed = false;
> + bitmap_head temp_partial_out;
> + bitmap_head temp_partial_be_full;
> + bitmap_head all_def;
> + subregs_live temp_range_out;
> + bitmap_initialize (&temp_partial_out, &bitmap_default_obstack);
> + bitmap_initialize (&temp_partial_be_full, &bitmap_default_obstack);
> + bitmap_initialize (&all_def, &bitmap_default_obstack);
> +
> + bitmap_ior (&all_def, &bb_info->full_def, &bb_info->partial_def);
> +
> + /* temp_partial_out = (full_out & partail_def) */
> + bitmap_and (&temp_partial_out, &bb_info->full_out, &bb_info->partial_def);
> + EXECUTE_IF_SET_IN_BITMAP (&temp_partial_out, FIRST_PSEUDO_REGISTER, regno, bi)
> + {
> + subreg_ranges temp (bb_info->range_def->lives.at (regno).max);
> + temp.make_full ();
> + temp.remove_ranges (bb_info->range_def->lives.at (regno));
> + temp_range_out.add_ranges (regno, temp);
> + }
> +
> + /* temp_partial_out |= (partail_out & ~all_def) */
> + bitmap_ior_and_compl_into (&temp_partial_out, &bb_info->partial_out,
> + &all_def);
> + EXECUTE_IF_AND_COMPL_IN_BITMAP (&bb_info->partial_out, &all_def,
> + FIRST_PSEUDO_REGISTER, regno, bi)
> + {
> + temp_range_out.add_ranges (regno, bb_info->range_out->lives.at (regno));
> + }
> +
> + /* temp_partial_out |= (partial_out remove partail_def not empty) */
> + EXECUTE_IF_AND_IN_BITMAP (&bb_info->partial_out, &bb_info->partial_def, 0,
> + regno, bi)
> + {
> + subreg_ranges temp = bb_info->range_out->lives.at (regno);
> + temp.remove_ranges (bb_info->range_def->lives.at (regno));
> + if (!temp.empty_p ())
> + {
> + bitmap_set_bit (&temp_partial_out, regno);
> + temp_range_out.add_ranges (regno, temp);
> + }
> + }
> +
> + /* temp_partial_out = temp_partial_out & ~full_use */
> + bitmap_and_compl_into (&temp_partial_out, &bb_info->full_use);
> + EXECUTE_IF_SET_IN_BITMAP (&bb_info->full_use, 0, regno, bi)
> + if (!temp_range_out.empty_p (regno))
> + temp_range_out.remove_live (regno);
> +
> + /* temp_partial_be_full = (temp_partial_out & partial_use) merge become full
> + */
> + temp_range_out.add_lives (*bb_info->range_use);
> + /* Remove all range which in partial_use and in full_out and not in all_def.
> + */
> + EXECUTE_IF_SET_IN_BITMAP (&bb_info->full_out, 0, regno, bi)
> + if (!bitmap_bit_p (&all_def, regno) && !temp_range_out.empty_p (regno))
> + temp_range_out.remove_live (regno);
> +
> + EXECUTE_IF_AND_IN_BITMAP (&temp_partial_out, &bb_info->partial_use, 0, regno,
> + bi)
> + {
> + subreg_ranges temp = temp_range_out.lives.at (regno);
> + temp.add_ranges (bb_info->range_use->lives.at (regno));
> + if (temp.full_p ())
> + {
> + bitmap_set_bit (&temp_partial_be_full, regno);
> + temp_range_out.remove_live (regno);
> + }
> + }
> +
> + /* Calculating full_in. */
> + bitmap_ior_and_compl_into (&temp_partial_be_full, &bb_info->full_out,
> + &all_def);
> + changed |= bitmap_ior (&bb_info->full_in, &temp_partial_be_full,
> + &bb_info->full_use);
> +
> + /* Calculating partial_in and range_in. */
> + bitmap_ior_into (&temp_partial_out, &bb_info->partial_use);
> + changed |= bitmap_and_compl (&bb_info->partial_in, &temp_partial_out,
> + &temp_partial_be_full);
> + changed |= bb_info->range_in->copy_lives (temp_range_out);
> +
> + bitmap_clear (&temp_partial_out);
> + bitmap_clear (&temp_partial_be_full);
> + bitmap_clear (&all_def);
> +
> + df_live_subreg_check_result (&bb_info->full_in, &bb_info->partial_in,
> + bb_info->range_in);
> +
> + return changed;
> +}
> +
> +/* Run the fast dce as a side effect of building LR. */
> +
> +void
> +df_live_subreg_finalize (bitmap all_blocks)
> +{
> + unsigned int bb_index;
> + bitmap_iterator bi;
> + EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
> + {
> + class df_live_subreg_bb_info *bb_info
> + = df_live_subreg_get_bb_info (bb_index);
> + gcc_assert (bb_info);
> + bitmap_ior (&bb_info->all_in, &bb_info->full_in, &bb_info->partial_in);
> + bitmap_ior (&bb_info->all_out, &bb_info->full_out, &bb_info->partial_out);
> + }
> +}
> +
> +/* Free all storage associated with the problem. */
> +
> +static void
> +df_live_subreg_free (void)
> +{
> + df_live_subreg_problem_data *problem_data
> + = (df_live_subreg_problem_data *) df_live_subreg->problem_data;
> + if (df_live_subreg->block_info)
> + {
> + df_live_subreg->block_info_size = 0;
> + free (df_live_subreg->block_info);
> + df_live_subreg->block_info = NULL;
> + bitmap_obstack_release (&problem_data->live_subreg_bitmaps);
> + free (df_live_subreg->problem_data);
> + df_live_subreg->problem_data = NULL;
> + }
> +
> + BITMAP_FREE (df_live_subreg->out_of_date_transfer_functions);
> + free (df_live_subreg);
> +}
> +
> +/* Debugging info at top of bb. */
> +
> +static void
> +df_live_subreg_top_dump (basic_block bb, FILE *file)
> +{
> + df_live_subreg_bb_info *bb_info = df_live_subreg_get_bb_info (bb->index);
> + if (!bb_info)
> + return;
> +
> + fprintf (file, ";; subreg live all in \t");
> + df_print_regset (file, &bb_info->all_in);
> + fprintf (file, ";; subreg live full in \t");
> + df_print_regset (file, &bb_info->full_in);
> + fprintf (file, ";; subreg live partial in \t");
> + df_print_regset (file, &bb_info->partial_in);
> + fprintf (file, ";; subreg live range in \t");
> + bb_info->range_in->dump (file, "");
> +
> + fprintf (file, "\n;; subreg live full use \t");
> + df_print_regset (file, &bb_info->full_use);
> + fprintf (file, ";; subreg live partial use \t");
> + df_print_regset (file, &bb_info->partial_use);
> + fprintf (file, ";; subreg live range use \t");
> + bb_info->range_use->dump (file, "");
> +
> + fprintf (file, "\n;; subreg live full def \t");
> + df_print_regset (file, &bb_info->full_def);
> + fprintf (file, ";; subreg live partial def \t");
> + df_print_regset (file, &bb_info->partial_def);
> + fprintf (file, ";; subreg live range def \t");
> + bb_info->range_def->dump (file, "");
> +}
> +
> +/* Debugging info at bottom of bb. */
> +
> +static void
> +df_live_subreg_bottom_dump (basic_block bb, FILE *file)
> +{
> + df_live_subreg_bb_info *bb_info = df_live_subreg_get_bb_info (bb->index);
> + if (!bb_info)
> + return;
> +
> + fprintf (file, ";; subreg live all out \t");
> + df_print_regset (file, &bb_info->all_out);
> + fprintf (file, ";; subreg live full out \t");
> + df_print_regset (file, &bb_info->full_out);
> + fprintf (file, ";; subreg live partial out \t");
> + df_print_regset (file, &bb_info->partial_out);
> + fprintf (file, ";; subreg live range out \t");
> + bb_info->range_out->dump (file, "");
> +}
> +
> +/* All of the information associated with every instance of the problem. */
> +
> +static const struct df_problem problem_LIVE_SUBREG = {
> + DF_LIVE_SUBREG, /* Problem id. */
> + DF_BACKWARD, /* Direction. */
> + df_live_subreg_alloc, /* Allocate the problem specific data. */
> + df_live_subreg_reset, /* Reset global information. */
> + df_live_subreg_free_bb_info, /* Free basic block info. */
> + df_live_subreg_local_compute, /* Local compute function. */
> + df_live_subreg_init, /* Init the solution specific data. */
> + df_worklist_dataflow, /* Worklist solver. */
> + df_live_subreg_confluence_0, /* Confluence operator 0. */
> + df_live_subreg_confluence_n, /* Confluence operator n. */
> + df_live_subreg_transfer_function, /* Transfer function. */
> + df_live_subreg_finalize, /* Finalize function. */
> + df_live_subreg_free, /* Free all of the problem information. */
> + df_live_subreg_free, /* Remove this problem from the stack of dataflow
> + problems. */
> + NULL, /* Debugging. */
> + df_live_subreg_top_dump, /* Debugging start block. */
> + df_live_subreg_bottom_dump, /* Debugging end block. */
> + NULL, /* Debugging start insn. */
> + NULL, /* Debugging end insn. */
> + NULL, /* Incremental solution verify start. */
> + NULL, /* Incremental solution verify end. */
> + &problem_LR, /* Dependent problem. */
> + sizeof (df_live_subreg_bb_info), /* Size of entry of block_info array. */
> + TV_DF_LIVE_SUBREG, /* Timing variable. */
> + false /* Reset blocks on dropping out of blocks_to_analyze. */
> +};
> +
> +/* Create a new DATAFLOW instance and add it to an existing instance
> + of DF. The returned structure is what is used to get at the
> + solution. */
> +
> +void
> +df_live_subreg_add_problem (void)
> +{
> + df_add_problem (&problem_LIVE_SUBREG);
> +
> + /* These will be initialized when df_scan_blocks processes each
> + block. */
> + df_live_subreg->out_of_date_transfer_functions
> + = BITMAP_ALLOC (&df_bitmap_obstack);
> +}
>
> -\f
> /*----------------------------------------------------------------------------
> LIVE AND MAY-INITIALIZED REGISTERS.
>
> diff --git a/gcc/df.h b/gcc/df.h
> index 402657a7076..50a6cf99863 100644
> --- a/gcc/df.h
> +++ b/gcc/df.h
> @@ -47,6 +47,7 @@ enum df_problem_id
> {
> DF_SCAN,
> DF_LR, /* Live Registers backward. */
> + DF_LIVE_SUBREG, /* Live Ranges and Live Subreg */
> DF_LIVE, /* Live Registers & Uninitialized Registers */
> DF_RD, /* Reaching Defs. */
> DF_CHAIN, /* Def-Use and/or Use-Def Chains. */
> @@ -619,6 +620,7 @@ public:
> #define DF_SCAN_BB_INFO(BB) (df_scan_get_bb_info ((BB)->index))
> #define DF_RD_BB_INFO(BB) (df_rd_get_bb_info ((BB)->index))
> #define DF_LR_BB_INFO(BB) (df_lr_get_bb_info ((BB)->index))
> +#define DF_LIVE_SUBREG_INFO(BB) (df_live_subreg_get_bb_info ((BB)->index))
> #define DF_LIVE_BB_INFO(BB) (df_live_get_bb_info ((BB)->index))
> #define DF_WORD_LR_BB_INFO(BB) (df_word_lr_get_bb_info ((BB)->index))
> #define DF_MD_BB_INFO(BB) (df_md_get_bb_info ((BB)->index))
> @@ -632,6 +634,15 @@ public:
> #define DF_MIR_IN(BB) (&DF_MIR_BB_INFO (BB)->in)
> #define DF_MIR_OUT(BB) (&DF_MIR_BB_INFO (BB)->out)
>
> +#define DF_LIVE_SUBREG_IN(BB) (&DF_LIVE_SUBREG_INFO (BB)->all_in)
> +#define DF_LIVE_SUBREG_OUT(BB) (&DF_LIVE_SUBREG_INFO (BB)->all_out)
> +#define DF_LIVE_SUBREG_FULL_IN(BB) (&DF_LIVE_SUBREG_INFO (BB)->full_in)
> +#define DF_LIVE_SUBREG_FULL_OUT(BB) (&DF_LIVE_SUBREG_INFO (BB)->full_out)
> +#define DF_LIVE_SUBREG_PARTIAL_IN(BB) (&DF_LIVE_SUBREG_INFO (BB)->partial_in)
> +#define DF_LIVE_SUBREG_PARTIAL_OUT(BB) (&DF_LIVE_SUBREG_INFO (BB)->partial_out)
> +#define DF_LIVE_SUBREG_RANGE_IN(BB) (DF_LIVE_SUBREG_INFO (BB)->range_in)
> +#define DF_LIVE_SUBREG_RANGE_OUT(BB) (DF_LIVE_SUBREG_INFO (BB)->range_out)
> +
> /* These macros are used by passes that are not tolerant of
> uninitialized variables. This intolerance should eventually
> be fixed. */
> @@ -878,6 +889,32 @@ public:
> bitmap_head out; /* At the bottom of the block. */
> };
>
> +class subregs_live;
> +
> +class basic_block_subreg_live_info
> +{
> +public:
> + bitmap_head full_def;
> + bitmap_head full_use;
> + /* Only for pseudo registers. */
> + bitmap_head partial_def;
> + bitmap_head partial_use;
> + subregs_live *range_def = NULL;
> + subregs_live *range_use = NULL;
> +};
> +
> +/* Live registers and live ranges including specifial subreg. */
> +class df_live_subreg_bb_info : public basic_block_subreg_live_info
> +{
> +public:
> + bitmap_head all_in, full_in;
> + bitmap_head all_out, full_out;
> + /* Only for pseudo registers. */
> + bitmap_head partial_in;
> + bitmap_head partial_out;
> + subregs_live *range_in = NULL;
> + subregs_live *range_out = NULL;
> +};
>
> /* Uninitialized registers. All bitmaps are referenced by the
> register number. Anded results of the forwards and backward live
> @@ -946,6 +983,7 @@ extern class df_d *df;
> #define df_note (df->problems_by_index[DF_NOTE])
> #define df_md (df->problems_by_index[DF_MD])
> #define df_mir (df->problems_by_index[DF_MIR])
> +#define df_live_subreg (df->problems_by_index[DF_LIVE_SUBREG])
>
> /* This symbol turns on checking that each modification of the cfg has
> been identified to the appropriate df routines. It is not part of
> @@ -1031,6 +1069,25 @@ extern void df_lr_add_problem (void);
> extern void df_lr_verify_transfer_functions (void);
> extern void df_live_verify_transfer_functions (void);
> extern void df_live_add_problem (void);
> +extern void
> +df_live_subreg_add_problem (void);
> +extern void
> +df_live_subreg_finalize (bitmap all_blocks);
> +class subreg_range;
> +extern bool
> +need_track_subreg (int regno, machine_mode mode);
> +extern void
> +remove_subreg_range (basic_block_subreg_live_info *bb_info, unsigned int regno,
> + machine_mode mode, const subreg_range &range);
> +extern bool
> +remove_subreg_range (basic_block_subreg_live_info *bb_info, df_ref ref);
> +extern void
> +add_subreg_range (basic_block_subreg_live_info *bb_info, unsigned int regno,
> + machine_mode mode, const subreg_range &range,
> + bool is_def = false);
> +extern bool
> +add_subreg_range (basic_block_subreg_live_info *bb_info, df_ref ref,
> + bool is_def = false);
> extern void df_live_set_all_dirty (void);
> extern void df_chain_add_problem (unsigned int);
> extern void df_word_lr_add_problem (void);
> @@ -1124,6 +1181,16 @@ df_lr_get_bb_info (unsigned int index)
> return NULL;
> }
>
> +inline class df_live_subreg_bb_info *
> +df_live_subreg_get_bb_info (unsigned int index)
> +{
> + if (index < df_live_subreg->block_info_size)
> + return &(
> + (class df_live_subreg_bb_info *) df_live_subreg->block_info)[index];
> + else
> + return NULL;
> +}
> +
> inline class df_md_bb_info *
> df_md_get_bb_info (unsigned int index)
> {
> diff --git a/gcc/regs.h b/gcc/regs.h
> index aea093ed795..84c6bdb980c 100644
> --- a/gcc/regs.h
> +++ b/gcc/regs.h
> @@ -389,4 +389,11 @@ range_in_hard_reg_set_p (const_hard_reg_set set, unsigned regno, int nregs)
> return true;
> }
>
> +/* Return the number of blocks the MODE overlap. One block equal mode's natural
> + size. So, satisfy the following equation:
> + (nblocks - 1) * natural_size < GET_MODE_SIZE (mode)
> + <= nblocks * natural_size. */
> +#define get_nblocks(mode) \
> + (exact_div (GET_MODE_SIZE (mode), REGMODE_NATURAL_SIZE (mode)).to_constant ())
> +
> #endif /* GCC_REGS_H */
> diff --git a/gcc/subreg-live-range.cc b/gcc/subreg-live-range.cc
> new file mode 100644
> index 00000000000..43a5eafedf1
> --- /dev/null
> +++ b/gcc/subreg-live-range.cc
> @@ -0,0 +1,628 @@
> +/* SUBREG live range track classes for DF & IRA & LRA.
> + Copyright (C) 2023 Free Software Foundation, Inc.
> + Contributed by Lehua Ding (lehua.ding@rivai.ai), RiVAI Technologies Ltd.
> +
> + This file is part of GCC.
> +
> + GCC is free software; you can redistribute it and/or modify it
> + under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3, or (at your option)
> + any later version.
> +
> + GCC is distributed in the hope that it will be useful, but
> + WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with GCC; see the file COPYING3. If not see
> + <http://www.gnu.org/licenses/>. */
> +
> +#include "subreg-live-range.h"
> +#include "selftest.h"
> +#include "print-rtl.h"
> +
> +/* class subreg_range */
> +void
> +subreg_range::dump (FILE *file) const
> +{
> + fprintf (file, "[%d, %d)", start, end);
> +}
> +
> +/* class subreg_ranges */
> +bool
> +subreg_ranges::add_range (int max, const subreg_range &new_range)
> +{
> + subreg_range range = new_range;
> + if (full_p ())
> + return false;
> + else if (max == 1)
> + {
> + gcc_assert (range.start == 0 && range.end == 1);
> + make_full ();
> + return true;
> + }
> +
> + if (this->max == 1)
> + change_max (max);
> +
> + gcc_assert (this->max == max);
> + gcc_assert (range.start < range.end);
> +
> + bool changed = empty_p ();
> + auto it = ranges.begin ();
> + while (it != ranges.end ())
> + {
> + const subreg_range &r = *it;
> + gcc_assert (r.start < r.end);
> +
> + /* The possible positional relationship of R and RANGE.
> + 1~5 means R.start's possible position relative to RANGE
> + A~G means R.end's possible position relative to RANGE
> + caseN means when R.start at N positon, the R.end can be in which
> + positions.
> +
> + RANGE.start RANGE.end
> + [ )
> + | |
> + R.start 1 2 3 4 5
> + R.end | |
> + case1 A B C D E
> + case2 | C D E
> + case3 | F D E
> + case4 | | E
> + case5 | | G
> +
> + */
> +
> + /* R.start at 1 position. */
> + if (r.start < range.start)
> + {
> + /* R.end at A position. That means R and RANGE do not overlap. */
> + if (r.end < range.start)
> + it++;
> + /* R.end at B/C position. That means RANGE's left part overlap R's
> + right part. Expand RANGE.start to R.start and remove R. */
> + else if (r.end < range.end)
> + {
> + changed = true;
> + range.start = r.start;
> + it = ranges.erase (it);
> + }
> + /* R.end at D/E position. That means R already contains RANGE, nothing
> + todo. */
> + else
> + return false;
> + }
> + /* R.start at 2 position. */
> + else if (r.start == range.start)
> + {
> + /* R.end at C/D position. That means RANGE contains R, remove R and
> + insert RANGE. */
> + if (r.end < range.end)
> + {
> + changed = true;
> + it = ranges.erase (it);
> + }
> + /* R.end at E position. That means R already contains RANGE, nothing
> + todo. */
> + else
> + return false;
> + }
> + /* R.start at 3 position. */
> + else if (r.start > range.start && r.start < range.end)
> + {
> + /* R.end at F/D position. That means RANGE contains R, just remove R
> + and insert RANGE later. */
> + if (r.end <= range.end)
> + {
> + changed = true;
> + it = ranges.erase (it);
> + }
> + /* R.end at E position. That means RANGE's right part overlap R's
> + left part. Expand RANGE.end to R.end and remove R. */
> + else if (r.end > range.end)
> + {
> + changed = true;
> + range.end = r.end;
> + it = ranges.erase (it);
> + break;
> + }
> + }
> + /* R.start at 4 position and R.end at E position. That means RANGE and R
> + are adjacent and can be merged. */
> + else if (r.start == range.end)
> + {
> + changed = true;
> + range.end = r.end;
> + it = ranges.erase (it);
> + }
> + /* R.start at 5 position and R.end at G position. That means R and RANGE
> + do not overlap. */
> + else
> + break;
> + }
> + ranges.insert (range);
> + return changed;
> +}
> +
> +bool
> +subreg_ranges::remove_range (int max, const subreg_range &range)
> +{
> + if (empty_p ())
> + return false;
> + else if (max == 1)
> + {
> + gcc_assert (range.start == 0 && range.end == 1);
> + make_empty ();
> + return true;
> + }
> +
> + if (this->max == 1)
> + {
> + gcc_assert (full_p ());
> + change_max (max);
> + }
> + gcc_assert (this->max == max);
> + gcc_assert (range.start < range.end);
> +
> + bool changed = false;
> + auto it = ranges.begin ();
> + std::set<subreg_range> new_ranges;
> + while (it != ranges.end ())
> + {
> + auto &r = *it;
> + gcc_assert (r.start < r.end);
> +
> + /* The possible positional relationship of R and RANGE.
> + 1~5 means R.start's possible position relative to RANGE
> + A~G means R.end's possible position relative to RANGE
> + caseN means when R.start at N positon, the R.end can be in which
> + positions.
> +
> + RANGE.start RANGE.end
> + [ )
> + | |
> + R.start 1 2 3 4 5
> + R.end | |
> + case1 A B C D E
> + case2 | C D E
> + case3 | F D E
> + case4 | | E
> + case5 | | G
> +
> + */
> +
> + /* R.start at 1 position. */
> + if (r.start < range.start)
> + {
> + /* R.end at A/B position. That means RANGE and R do not overlap,
> + nothing to remove. */
> + if (r.end <= range.start)
> + it++;
> + /* R.end at C/D position. That means R's rigth part contains RANGE,
> + need shrink R.end to RANGE.start. */
> + else if (r.end <= range.end)
> + {
> + changed = true;
> + new_ranges.insert (subreg_range (r.start, range.start));
> + it = ranges.erase (it);
> + }
> + /* R.end at E position. That means R's center part contains RANGE,
> + need split R to two range, one range is [R.start, RANGE.start),
> + another range is [RANGE.end, R.end). */
> + else
> + {
> + changed = true;
> + new_ranges.insert (subreg_range (r.start, range.start));
> + new_ranges.insert (subreg_range (range.end, r.end));
> + it = ranges.erase (it);
> + break;
> + }
> + }
> + /* R.start at 2 position. */
> + else if (r.start == range.start)
> + {
> + /* R.end at C/D position. That means RANGE contains R, remove R. */
> + if (r.end <= range.end)
> + {
> + changed = true;
> + it = ranges.erase (it);
> + }
> + /* R.end at E position. That means R's left part contains RANGE,
> + shrink R.start to RANGE.end. */
> + else
> + {
> + changed = true;
> + new_ranges.insert (subreg_range (range.end, r.end));
> + it = ranges.erase (it);
> + break;
> + }
> + }
> + /* R.start at 3 position. */
> + else if (r.start > range.start && r.start < range.end)
> + {
> + /* R.end at F/D position. That means RANGE contains R, remove R. */
> + if (r.end <= range.end)
> + {
> + changed = true;
> + it = ranges.erase (it);
> + }
> + /* R.end at E position. That means RANGE's right part overlap R's left
> + part, shrink R.start to RANGE.end. */
> + else
> + {
> + changed = true;
> + new_ranges.insert (subreg_range (range.end, r.end));
> + it = ranges.erase (it);
> + break;
> + }
> + }
> + /* R.start at 4/5 position. That means RANGE and R do not overlap. */
> + else
> + break;
> + }
> + for (auto &r : new_ranges)
> + add_range (this->max, r);
> + return changed;
> +}
> +
> +bool
> +subreg_ranges::add_ranges (const subreg_ranges &sr)
> +{
> + gcc_assert (max == sr.max || max == 1 || sr.max == 1);
> +
> + if (full_p () || sr.empty_p ())
> + return false;
> + else if (sr.full_p ())
> + {
> + make_full ();
> + return true;
> + }
> +
> + bool changed = false;
> + for (auto &r : sr.ranges)
> + changed |= add_range (sr.max, r);
> + return changed;
> +}
> +
> +bool
> +subreg_ranges::remove_ranges (const subreg_ranges &sr)
> +{
> + if (empty_p () || sr.empty_p ())
> + return false;
> + else if (sr.full_p ())
> + {
> + make_empty ();
> + return true;
> + }
> +
> + gcc_assert (max == sr.max || max == 1 || sr.max == 1);
> +
> + bool changed = false;
> + for (auto &r : sr.ranges)
> + changed |= remove_range (sr.max, r);
> + return changed;
> +}
> +
> +bool
> +subreg_ranges::same_p (const subreg_ranges &sr) const
> +{
> + if (max == 1 || sr.max == 1)
> + return (empty_p () && sr.empty_p ()) || (full_p () && sr.full_p ());
> + else if (max == sr.max)
> + {
> + if (ranges.size () != sr.ranges.size ())
> + return false;
> + /* Make sure that the elements in each position are the same. */
> + auto it1 = ranges.begin ();
> + auto it2 = sr.ranges.begin ();
> + while (it1 != ranges.end ())
> + {
> + const subreg_range &r1 = *it1;
> + const subreg_range &r2 = *it2;
> + if (r1.start != r2.start || r1.end != r2.end)
> + return false;
> + it1++;
> + it2++;
> + }
> + return true;
> + }
> + else
> + gcc_unreachable ();
> +}
> +
> +bool
> +subreg_ranges::include_ranges_p (const subreg_ranges &sr) const
> +{
> + gcc_assert (max == sr.max || max == 1 || sr.max == 1);
> + if (full_p ())
> + return true;
> + if (empty_p () && sr.empty_p ())
> + return true;
> + if (same_p (sr))
> + return true;
> +
> + for (const auto &r : sr.ranges)
> + if (!include_range_p (sr.max, r))
> + return false;
> + return true;
> +}
> +
> +bool
> +subreg_ranges::include_range_p (int max, const subreg_range &range) const
> +{
> + gcc_assert (this->max == max);
> + for (const auto &r : ranges)
> + {
> + if (r.start <= range.start && r.end >= range.end)
> + return true;
> + else if (r.start >= range.end)
> + return false;
> + }
> + return false;
> +}
> +
> +void
> +subreg_ranges::dump (FILE *file) const
> +{
> + if (empty_p ())
> + {
> + fprintf (file, "empty");
> + return;
> + }
> + else if (full_p ())
> + {
> + fprintf (file, "full");
> + return;
> + }
> +
> + fprintf (file, "patial(max:%d", max);
> + fprintf (file, " {");
> + for (auto &range : ranges)
> + {
> + fprintf (file, " ");
> + range.dump (file);
> + }
> + fprintf (file, " })");
> +}
> +
> +/* class subregs_live */
> +bool
> +subregs_live::copy_lives (const subregs_live &sl)
> +{
> + bool changed = false;
> + subregs_live temp;
> + for (auto &kv : sl.lives)
> + {
> + unsigned int regno = kv.first;
> + const subreg_ranges &sr = kv.second;
> + if (lives.count (regno) == 0 && !sr.empty_p ())
> + {
> + changed = true;
> + temp.add_ranges (regno, sr);
> + }
> + else if (lives.count (regno) != 0)
> + {
> + changed |= !lives.at (regno).same_p (sr);
> + temp.add_ranges (regno, sr);
> + }
> + }
> +
> + for (auto &kv : lives)
> + {
> + unsigned int regno = kv.first;
> + subreg_ranges &sr = kv.second;
> + if (temp.lives.count (regno) == 0 && !sr.empty_p ())
> + changed = true;
> + }
> + lives = temp.lives;
> + return changed;
> +}
> +
> +bool
> +subregs_live::add_lives (const subregs_live &sl)
> +{
> + bool changed = false;
> + for (auto &kv : sl.lives)
> + {
> + unsigned int regno = kv.first;
> + const subreg_ranges &sr = kv.second;
> + if (sr.empty_p ())
> + continue;
> +
> + if (lives.count (regno) == 0)
> + {
> + changed = true;
> + lives.insert ({regno, sr});
> + }
> + else
> + changed |= lives.at (regno).add_ranges (sr);
> + }
> + return changed;
> +}
> +
> +bool
> +subregs_live::remove_lives (const subregs_live &sl)
> +{
> + bool changed = false;
> + for (auto &kv : sl.lives)
> + {
> + unsigned int regno = kv.first;
> + const subreg_ranges &sr = kv.second;
> + if (sr.empty_p ())
> + continue;
> +
> + if (lives.count (regno) != 0)
> + {
> + changed |= lives.at (regno).remove_ranges (sr);
> + if (lives.at (regno).empty_p ())
> + lives.erase (regno);
> + }
> + }
> + return changed;
> +}
> +
> +void
> +subregs_live::dump (FILE *file, const char *indent) const
> +{
> + if (lives.empty ())
> + {
> + fprintf (file, "%sempty\n", indent);
> + return;
> + }
> + fprintf (file, "%s", indent);
> + for (auto &kv : lives)
> + {
> + const subreg_ranges &sr = kv.second;
> + if (sr.empty_p ())
> + continue;
> + fprintf (file, "%d ", kv.first);
> + if (!sr.full_p ())
> + {
> + sr.dump (file);
> + fprintf (file, " ");
> + }
> + }
> + fprintf (file, "\n");
> +}
> +
> +/* class live_point */
> +void
> +live_point::dump (FILE *file) const
> +{
> + if (!use_reg.empty_p ())
> + {
> + fprintf (file, "use ");
> + use_reg.dump (file);
> + if (!def_reg.empty_p ())
> + {
> + fprintf (file, ", def ");
> + def_reg.dump (file);
> + }
> + }
> + else if (!def_reg.empty_p ())
> + {
> + fprintf (file, "def ");
> + def_reg.dump (file);
> + }
> + else
> + gcc_unreachable ();
> +}
> +
> +/* class live_points */
> +void
> +live_points::dump (FILE *file) const
> +{
> + fprintf (file, "%u :", id);
> + if (points.empty ())
> + {
> + fprintf (file, " empty");
> + return;
> + }
> + for (const auto &kv : points)
> + {
> + fprintf (file, " ");
> + kv.second.dump (file);
> + fprintf (file, " at point %u;", kv.first);
> + }
> +}
> +
> +/* class reg_live_ranges */
> +void
> +subregs_live_points::dump (FILE *file) const
> +{
> + if (subreg_points.empty ())
> + {
> + fprintf (file, ";; empty\n");
> + return;
> + }
> + for (const auto &kv : subreg_points)
> + {
> + fprintf (file, ";; ");
> + kv.second.dump (file);
> + fprintf (file, "\n");
> + }
> +}
> +
> +/* Define some usefull debug functions. */
> +
> +DEBUG_FUNCTION void
> +debug (const subreg_range &r)
> +{
> + r.dump (stderr);
> +}
> +
> +DEBUG_FUNCTION void
> +debug (const subreg_ranges &sr)
> +{
> + sr.dump (stderr);
> +}
> +
> +DEBUG_FUNCTION void
> +debug (const subregs_live &l)
> +{
> + l.dump (stderr, "");
> +}
> +
> +DEBUG_FUNCTION void
> +debug (const subregs_live *l)
> +{
> + debug (*l);
> +}
> +
> +DEBUG_FUNCTION void
> +debug (const live_point &l)
> +{
> + l.dump (stderr);
> +}
> +
> +DEBUG_FUNCTION void
> +debug (const live_points &ls)
> +{
> + ls.dump (stderr);
> +}
> +
> +DEBUG_FUNCTION void
> +debug (const subregs_live_points &sls)
> +{
> + sls.dump (stderr);
> +}
> +
> +DEBUG_FUNCTION void
> +debug (const subregs_live_points *sls)
> +{
> + debug (*sls);
> +}
> +
> +#if CHECKING_P
> +
> +namespace selftest {
> +
> +class subreg_range_tests
> +{
> +public:
> + static void run ()
> + {
> + /* class subreg_range tests. */
> + subreg_range r1 = subreg_range (1, 2);
> + subreg_range r2 = subreg_range (2, 3);
> + subreg_range r3 = subreg_range (2, 3);
> + ASSERT_FALSE (r1.same_p (r2));
> + ASSERT_TRUE (r2.same_p (r3));
> + ASSERT_TRUE (r1 < r2);
> + ASSERT_FALSE (r2 < r1);
> +
> + /* class subreg_ranges tests. */
> + }
> +};
> +
> +void
> +subreg_live_range_tests ()
> +{
> + subreg_range_tests::run ();
> +}
> +
> +} // namespace selftest
> +
> +#endif /* CHECKING_P */
> diff --git a/gcc/subreg-live-range.h b/gcc/subreg-live-range.h
> new file mode 100644
> index 00000000000..76e442d08e8
> --- /dev/null
> +++ b/gcc/subreg-live-range.h
> @@ -0,0 +1,333 @@
> +/* SUBREG live range track classes for DF & IRA & LRA.
> + Copyright (C) 2023 Free Software Foundation, Inc.
> + Contributed by Lehua Ding (lehua.ding@rivai.ai), RiVAI Technologies Ltd.
> +
> + This file is part of GCC.
> +
> + GCC is free software; you can redistribute it and/or modify it
> + under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3, or (at your option)
> + any later version.
> +
> + GCC is distributed in the hope that it will be useful, but
> + WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with GCC; see the file COPYING3. If not see
> + <http://www.gnu.org/licenses/>. */
> +
> +#ifndef GCC_SUBREG_LIVE_RANGE_H
> +#define GCC_SUBREG_LIVE_RANGE_H
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include <set>
> +#include <map>
> +
> +/* class subreg_range represent bytes range [start, end) of a reg. */
> +class subreg_range
> +{
> +public:
> + int start; /* Range start point. */
> + int end; /* Range start point. */
> +
> + subreg_range (int start, int end) : start (start), end (end)
> + {
> + gcc_assert (start < end);
> + }
> +
> + /* For sorting. */
> + bool operator<(const subreg_range &r) const
> + {
> + if (end <= r.start)
> + return true;
> + else if (start >= r.end)
> + return false;
> + else
> + /* Cannot sorting for overlap range. */
> + gcc_unreachable ();
> + }
> + /* Return true if R same with self. */
> + bool same_p (const subreg_range &r) const
> + {
> + return start == r.start && end == r.end;
> + }
> +
> + /* Return true if range is full for 0-MAX range. */
> + bool full_p (int max) const { return start == 0 && end == max; }
> +
> + /* Debug methods. */
> + void dump (FILE *file) const;
> +};
> +
> +/* class subreg_ranges represent multiple disjoint and discontinuous
> + subreg_range. */
> +class subreg_ranges
> +{
> +public:
> + /* The maximum boundary value of range. If for a unknown mode hard register,
> + the max set to 1. */
> + int max;
> + std::set<subreg_range> ranges;
> +
> + subreg_ranges () : max (1) {}
> + subreg_ranges (int max) : max (max) { gcc_assert (max >= 1); }
> +
> + /* Modify ranges. */
> + /* Return true if ranges changed. */
> + bool add_range (int max, const subreg_range &range);
> + /* Return true if ranges changed. */
> + bool remove_range (int max, const subreg_range &range);
> + /* Add SR, return true if ranges changed. */
> + bool add_ranges (const subreg_ranges &sr);
> + /* Clear ranges of SR, return true if ranges changed. */
> + bool remove_ranges (const subreg_ranges &sr);
> + /* Make range empty. */
> + void make_empty () { ranges.clear (); }
> + /* Make range full. */
> + void make_full ()
> + {
> + make_empty ();
> + ranges.insert (subreg_range (0, max));
> + }
> + /* Change max to MAX, corresponding adjust ranges. */
> + void change_max (int max)
> + {
> + gcc_assert (this->max == 1);
> + this->max = max;
> + if (full_p ())
> + make_full ();
> + }
> +
> + /* Predicators. */
> + bool full_p () const
> + {
> + if (ranges.size () != 1)
> + return false;
> + const subreg_range &r = *ranges.begin ();
> + return r.start == 0 && r.end == max;
> + }
> + bool empty_p () const { return ranges.empty (); }
> + bool same_p (const subreg_ranges &sr) const;
> + bool same_p (int max, const subreg_range &range) const
> + {
> + subreg_ranges sr = subreg_ranges (max);
> + sr.add_range (max, range);
> + return same_p (sr);
> + }
> + bool include_ranges_p (const subreg_ranges &sr) const;
> + bool include_range_p (int max, const subreg_range &range) const;
> +
> + /* Debug methods. */
> + void dump (FILE *file) const;
> +};
> +
> +/* class subregs_live record the live subreg_ranges of registers. */
> +class subregs_live
> +{
> +public:
> + /* The key is usually the register's regno. */
> + std::map<unsigned int, subreg_ranges> lives;
> +
> + /* Add/clear live range. */
> + bool add_range (unsigned int regno, int max, const subreg_range &range)
> + {
> + if (lives.count (regno) == 0)
> + lives.insert ({regno, subreg_ranges (max)});
> + return lives.at (regno).add_range (max, range);
> + }
> + bool remove_range (unsigned int regno, int max, const subreg_range &range)
> + {
> + if (lives.count (regno) != 0)
> + {
> + bool changed = lives.at (regno).remove_range (max, range);
> + if (lives.at (regno).empty_p ())
> + remove_live (regno);
> + return changed;
> + }
> + return false;
> + }
> + /* Add a unexist register live range. */
> + void add_ranges (unsigned int regno, const subreg_ranges &ranges)
> + {
> + if (lives.count (regno) == 0)
> + lives.insert ({regno, ranges});
> + else
> + lives.at (regno).add_ranges (ranges);
> + }
> + bool copy_lives (const subregs_live &sl);
> + bool add_lives (const subregs_live &sl);
> + bool remove_lives (const subregs_live &sl);
> + void remove_live (unsigned int regno) { lives.erase (regno); }
> + /* Remove all register live range. */
> + void clear () { lives.clear (); }
> + void clear (unsigned min_regno)
> + {
> + if (lives.lower_bound (min_regno) != lives.end ())
> + lives.erase (lives.lower_bound (min_regno), lives.end ());
> + }
> +
> + /* Return true if regno's live range is full. */
> + bool full_p (unsigned int regno) const
> + {
> + return lives.count (regno) != 0 && lives.at (regno).full_p ();
> + }
> + /* Return true if regno's live range is empty. */
> + bool empty_p (unsigned int regno) const
> + {
> + return lives.count (regno) == 0 || lives.at (regno).empty_p ();
> + }
> + /* Return true if SL same with this. */
> + bool same_p (const subregs_live &sl)
> + {
> + if (lives.size () != sl.lives.size ())
> + return false;
> + for (auto &kv : lives)
> + {
> + unsigned int regno = kv.first;
> + if (sl.empty_p (regno))
> + return false;
> + const subreg_ranges &sr = kv.second;
> + if (!sr.same_p (sl.lives.at (regno)))
> + return false;
> + }
> + return true;
> + }
> +
> + /* Debug methods. */
> + void dump (FILE *file, const char *indent = ";; ") const;
> +};
> +
> +class live_point
> +{
> +public:
> + int point;
> + /* subreg range be defined in current point. */
> + subreg_ranges def_reg;
> + /* subreg range be used in current point. */
> + subreg_ranges use_reg;
> +
> + live_point (int max, const subreg_range &range, bool is_def)
> + : def_reg (max), use_reg (max)
> + {
> + add_range (max, range, is_def);
> + }
> + live_point (const subreg_ranges &sr, bool is_def)
> + : def_reg (sr.max), use_reg (sr.max)
> + {
> + add_ranges (sr, is_def);
> + }
> + live_point (int point, int max) : point (point), def_reg (max), use_reg (max)
> + {}
> +
> + void add_range (int max, const subreg_range &r, bool is_def)
> + {
> + if (is_def)
> + def_reg.add_range (max, r);
> + else
> + use_reg.add_range (max, r);
> + }
> +
> + void add_ranges (const subreg_ranges &sr, bool is_def)
> + {
> + if (is_def)
> + def_reg.add_ranges (sr);
> + else
> + use_reg.add_ranges (sr);
> + }
> +
> + void dump (FILE *file) const;
> +};
> +
> +class live_points
> +{
> +public:
> + int id;
> + int max;
> + std::map<int, live_point> points;
> +
> + live_points (int id, int max) : id (id), max (max) {}
> +
> + void add_point (int max, const subreg_range &range, bool is_def, int point)
> + {
> + gcc_assert (this->max == max || this->max == 1 || max == 1);
> + if (points.count (point) == 0)
> + points.insert ({point, {max, range, is_def}});
> + else
> + points.at (point).add_range (max, range, is_def);
> + }
> + void dump (FILE *file) const;
> +};
> +
> +class subregs_live_points
> +{
> +public:
> + std::map<int, live_points> subreg_points;
> + std::map<int, int> last_start_points;
> + std::map<int, subreg_ranges> subreg_live_ranges;
> +
> + void add_point (int id, int max, const subreg_range &range, bool is_def,
> + int point)
> + {
> + if (!is_def && empty_live_p (id))
> + {
> + if (last_start_points.count (id) == 0)
> + last_start_points.insert ({id, point});
> + else
> + last_start_points.at (id) = point;
> + }
> +
> + if (subreg_points.count (id) == 0)
> + subreg_points.insert ({id, live_points (id, max)});
> +
> + subreg_points.at (id).add_point (max, range, is_def, point);
> +
> + if (subreg_live_ranges.count (id) == 0)
> + subreg_live_ranges.insert ({id, subreg_ranges (max)});
> +
> + if (is_def)
> + subreg_live_ranges.at (id).remove_range (max, range);
> + else
> + subreg_live_ranges.at (id).add_range (max, range);
> + }
> +
> + void add_range (int id, int max, const subreg_range &range, bool is_def)
> + {
> + if (subreg_live_ranges.count (id) == 0)
> + subreg_live_ranges.insert ({id, subreg_ranges (max)});
> +
> + if (is_def)
> + subreg_live_ranges.at (id).remove_range (max, range);
> + else
> + subreg_live_ranges.at (id).add_range (max, range);
> + }
> +
> + bool full_live_p (int id)
> + {
> + return subreg_live_ranges.count (id) != 0
> + && subreg_live_ranges.at (id).full_p ();
> + }
> +
> + bool empty_live_p (int id)
> + {
> + return subreg_live_ranges.count (id) == 0
> + || subreg_live_ranges.at (id).empty_p ();
> + }
> +
> + int get_start_point (int id)
> + {
> + int start_point = last_start_points.at (id);
> + gcc_assert (start_point != -1);
> + return start_point;
> + }
> +
> + void clear_live_ranges () { subreg_live_ranges.clear (); }
> +
> + /* Debug methods. */
> + void dump (FILE *file) const;
> +};
> +
> +#endif /* GCC_SUBREG_LIVE_RANGE_H */
> diff --git a/gcc/timevar.def b/gcc/timevar.def
> index d21b08c030d..7c173d3c7c8 100644
> --- a/gcc/timevar.def
> +++ b/gcc/timevar.def
> @@ -120,6 +120,7 @@ DEFTIMEVAR (TV_DF_SCAN , "df scan insns")
> DEFTIMEVAR (TV_DF_MD , "df multiple defs")
> DEFTIMEVAR (TV_DF_RD , "df reaching defs")
> DEFTIMEVAR (TV_DF_LR , "df live regs")
> +DEFTIMEVAR (TV_DF_LIVE_SUBREG , "df live subregs")
> DEFTIMEVAR (TV_DF_LIVE , "df live&initialized regs")
> DEFTIMEVAR (TV_DF_MIR , "df must-initialized regs")
> DEFTIMEVAR (TV_DF_CHAIN , "df use-def / def-use chains")
next prev parent reply other threads:[~2023-11-20 20:11 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-12 12:08 [PATCH V3 0/7] ira/lra: Support subreg coalesce Lehua Ding
2023-11-12 12:08 ` [PATCH V3 1/7] df: Add DF_LIVE_SUBREG problem Lehua Ding
2023-11-13 22:38 ` Vladimir Makarov
2023-11-14 8:14 ` Richard Biener
2023-11-14 8:38 ` Lehua Ding
2023-11-14 9:03 ` Richard Biener
2023-11-14 14:52 ` Vladimir Makarov
2023-11-14 17:18 ` Vladimir Makarov
2023-11-14 18:29 ` Vladimir Makarov
2023-11-20 20:11 ` Richard Sandiford [this message]
2023-11-21 6:35 ` Lehua Ding
2023-11-12 12:08 ` [PATCH V3 2/7] ira: Switch to live_subreg data Lehua Ding
2023-11-14 20:26 ` Vladimir Makarov
2023-11-12 12:08 ` [PATCH V3 3/7] ira: Support subreg live range track Lehua Ding
2023-11-14 20:37 ` Vladimir Makarov
2023-11-12 12:08 ` [PATCH V3 4/7] ira: Support subreg copy Lehua Ding
2023-11-16 21:13 ` Vladimir Makarov
2023-11-17 2:06 ` Lehua Ding
2023-11-17 14:05 ` Vladimir Makarov
2023-11-18 8:00 ` Lehua Ding
2023-11-18 8:06 ` Sam James
2023-11-18 8:16 ` Lehua Ding
2023-11-18 8:24 ` Sam James
2023-11-18 8:27 ` Lehua Ding
2023-11-12 12:08 ` [PATCH V3 5/7] ira: Add all nregs >= 2 pseudos to tracke subreg list Lehua Ding
2023-11-16 21:14 ` Vladimir Makarov
2023-11-12 12:08 ` [PATCH V3 6/7] lra: Switch to live_subreg data flow Lehua Ding
2023-11-12 12:08 ` [PATCH V3 7/7] lra: Support subreg live range track and conflict detect Lehua Ding
2023-11-13 16:43 ` [PATCH V3 0/7] ira/lra: Support subreg coalesce Dimitar Dimitrov
2023-11-15 2:10 ` Lehua Ding
2023-11-13 19:37 ` Vladimir Makarov
2023-11-14 5:37 ` Lehua Ding
2023-11-14 23:33 ` Peter Bergner
2023-11-14 23:22 ` Peter Bergner
2023-11-15 3:12 ` Lehua Ding
2023-11-15 3:33 ` Peter Bergner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=mptmsv8kwww.fsf@arm.com \
--to=richard.sandiford@arm.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=juzhe.zhong@rivai.ai \
--cc=lehua.ding@rivai.ai \
--cc=vmakarov@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).