Hi Richard,

On 2023/11/21 4:11, Richard Sandiford wrote:
Lehua Ding <lehua.d...@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 for providing such detailed instructions, this looks like it should perform well. I'll give it a try and come back with any questions.


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);
+}
-
  /*----------------------------------------------------------------------------
     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.d...@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.d...@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")


--
Best,
Lehua (RiVAI)

Reply via email to