This patch implements tracking of the live range of subregs and synchronously
modifies conflict detection.

gcc/ChangeLog:

        * ira-build.cc (print_copy): Adjust print.
        (setup_pseudos_has_subreg_object): New.
        (ira_build): collect subreg object allocno.
        * lra-assigns.cc (set_offset_conflicts): New.
        (setup_live_pseudos_and_spill_after_risky_transforms): Adjust.
        (lra_assign): Adjust.
        * lra-constraints.cc (process_alt_operands): Relax.
        * lra-int.h (GCC_LRA_INT_H): New include.
        (struct lra_live_range): New field subreg.
        (struct lra_insn_reg): New fields.
        (get_range_hard_regs):  Exported.
        (get_nregs): New.
        (has_subreg_object_p): New.
        * lra-lives.cc (INCLUDE_VECTOR): New.
        (lra_live_range_pool): New.
        (create_live_range): Adjust.
        (lra_merge_live_ranges): Adjust.
        (update_pseudo_point): Adjust.
        (class bb_data_pseudos): New.
        (mark_regno_live): Adjust.
        (mark_regno_dead): Adjust.
        (process_bb_lives): Adjust.
        (remove_some_program_points_and_update_live_ranges): Adjust.
        (lra_print_live_range_list): Adjust print.
        (class subreg_live_item): New class.
        (create_subregs_live_ranges): New.
        (lra_create_live_ranges_1): Add subreg live ranges.
        * lra.cc (get_range_blocks): New.
        (get_range_hard_regs): New.
        (new_insn_reg): Adjust.
        (collect_non_operand_hard_regs): Adjust.
        (initialize_lra_reg_info_element): Adjust.
        (reg_same_range_p): New.
        (add_regs_to_insn_regno_info): Adjust.
        * subreg-live-range.h: New constructor.

---
 gcc/ira-build.cc        |  40 ++++-
 gcc/lra-assigns.cc      | 111 ++++++++++--
 gcc/lra-constraints.cc  |  18 +-
 gcc/lra-int.h           |  33 ++++
 gcc/lra-lives.cc        | 361 ++++++++++++++++++++++++++++++++++------
 gcc/lra.cc              | 139 ++++++++++++++--
 gcc/subreg-live-range.h |   1 +
 7 files changed, 614 insertions(+), 89 deletions(-)

diff --git a/gcc/ira-build.cc b/gcc/ira-build.cc
index 379f877ca67..cba38d5fecb 100644
--- a/gcc/ira-build.cc
+++ b/gcc/ira-build.cc
@@ -95,6 +95,9 @@ int ira_copies_num;
    basic block.  */
 static int last_basic_block_before_change;
 
+/* Record these pseudos which has subreg object. Used by LRA pass.  */
+bitmap_head pseudos_has_subreg_object;
+
 /* Initialize some members in loop tree node NODE.  Use LOOP_NUM for
    the member loop_num.  */
 static void
@@ -1688,8 +1691,13 @@ print_copy (FILE *f, ira_copy_t cp)
 {
   ira_allocno_t a1 = OBJECT_ALLOCNO (cp->first);
   ira_allocno_t a2 = OBJECT_ALLOCNO (cp->second);
-  fprintf (f, "  cp%d:a%d(r%d)<->a%d(r%d)@%d:%s\n", cp->num, ALLOCNO_NUM (a1),
-          ALLOCNO_REGNO (a1), ALLOCNO_NUM (a2), ALLOCNO_REGNO (a2), cp->freq,
+  fprintf (f, "  cp%d:a%d(r%d", cp->num, ALLOCNO_NUM (a1), ALLOCNO_REGNO (a1));
+  if (ALLOCNO_NREGS (a1) != OBJECT_NREGS (cp->first))
+    fprintf (f, "_obj%d", OBJECT_INDEX (cp->first));
+  fprintf (f, ")<->a%d(r%d", ALLOCNO_NUM (a2), ALLOCNO_REGNO (a2));
+  if (ALLOCNO_NREGS (a2) != OBJECT_NREGS (cp->second))
+    fprintf (f, "_obj%d", OBJECT_INDEX (cp->second));
+  fprintf (f, ")@%d:%s\n", cp->freq,
           cp->insn != NULL   ? "move"
           : cp->constraint_p ? "constraint"
                              : "shuffle");
@@ -3706,6 +3714,33 @@ update_conflict_hard_reg_costs (void)
     }
 }
 
+/* Setup speudos_has_subreg_object.  */
+static void
+setup_pseudos_has_subreg_object ()
+{
+  bitmap_initialize (&pseudos_has_subreg_object, &reg_obstack);
+  ira_allocno_t a;
+  ira_allocno_iterator ai;
+  FOR_EACH_ALLOCNO (a, ai)
+    if (has_subreg_object_p (a))
+      {
+       bitmap_set_bit (&pseudos_has_subreg_object, ALLOCNO_REGNO (a));
+       if (ira_dump_file != NULL)
+         {
+           fprintf (ira_dump_file,
+                    "  a%d(r%d, nregs: %d) has subreg objects:\n",
+                    ALLOCNO_NUM (a), ALLOCNO_REGNO (a), ALLOCNO_NREGS (a));
+           ira_allocno_object_iterator oi;
+           ira_object_t obj;
+           FOR_EACH_ALLOCNO_OBJECT (a, obj, oi)
+             fprintf (ira_dump_file, "    object %d: start: %d, nregs: %d\n",
+                      OBJECT_INDEX (obj), OBJECT_START (obj),
+                      OBJECT_NREGS (obj));
+           fprintf (ira_dump_file, "\n");
+         }
+      }
+}
+
 /* Create a internal representation (IR) for IRA (allocnos, copies,
    loop tree nodes).  The function returns TRUE if we generate loop
    structure (besides nodes representing all function and the basic
@@ -3726,6 +3761,7 @@ ira_build (void)
   create_allocnos ();
   ira_costs ();
   create_allocno_objects ();
+  setup_pseudos_has_subreg_object ();
   ira_create_allocno_live_ranges ();
   remove_unnecessary_regions (false);
   ira_compress_allocno_live_ranges ();
diff --git a/gcc/lra-assigns.cc b/gcc/lra-assigns.cc
index d2ebcfd5056..6588a740162 100644
--- a/gcc/lra-assigns.cc
+++ b/gcc/lra-assigns.cc
@@ -1131,6 +1131,52 @@ assign_hard_regno (int hard_regno, int regno)
 /* Array used for sorting different pseudos.  */
 static int *sorted_pseudos;
 
+/* The detail conflict offsets If two live ranges conflict. Use to record
+   partail conflict.  */
+static bitmap_head live_range_conflicts;
+
+/* Set the conflict offset of the two registers REGNO1 and REGNO2. Use the
+   regno with bigger nregs as the base.  */
+static void
+set_offset_conflicts (int regno1, int regno2)
+{
+  gcc_assert (reg_renumber[regno1] >= 0 && reg_renumber[regno2] >= 0);
+  int nregs1 = get_nregs (regno1);
+  int nregs2 = get_nregs (regno2);
+  if (nregs1 < nregs2)
+    {
+      std::swap (nregs1, nregs2);
+      std::swap (regno1, regno2);
+    }
+
+  lra_live_range_t r1 = lra_reg_info[regno1].live_ranges;
+  lra_live_range_t r2 = lra_reg_info[regno2].live_ranges;
+  int total = nregs1;
+
+  bitmap_clear (&live_range_conflicts);
+  while (r1 != NULL && r2 != NULL)
+    {
+      if (r1->start > r2->finish)
+       r1 = r1->next;
+      else if (r2->start > r1->finish)
+       r2 = r2->next;
+      else
+       {
+         for (const subreg_range &range1 : r1->subreg.ranges)
+           for (const subreg_range &range2 : r2->subreg.ranges)
+             /* Record all overlap offset.  */
+             for (int i = range1.start - (range2.end - range2.start) + 1;
+                  i < range1.end; i++)
+               if (i >= 0 && i < total)
+                 bitmap_set_bit (&live_range_conflicts, i);
+         if (r1->finish < r2->finish)
+           r1 = r1->next;
+         else
+           r2 = r2->next;
+       }
+    }
+}
+
 /* The constraints pass is allowed to create equivalences between
    pseudos that make the current allocation "incorrect" (in the sense
    that pseudos are assigned to hard registers from their own conflict
@@ -1226,19 +1272,56 @@ setup_live_pseudos_and_spill_after_risky_transforms 
(bitmap
               the same hard register.  */
            || hard_regno != reg_renumber[conflict_regno])
          {
-           int conflict_hard_regno = reg_renumber[conflict_regno];
-           
-           biggest_mode = lra_reg_info[conflict_regno].biggest_mode;
-           biggest_nregs = hard_regno_nregs (conflict_hard_regno,
-                                             biggest_mode);
-           nregs_diff
-             = (biggest_nregs
-                - hard_regno_nregs (conflict_hard_regno,
-                                    PSEUDO_REGNO_MODE (conflict_regno)));
-           add_to_hard_reg_set (&conflict_set,
-                                biggest_mode,
-                                conflict_hard_regno
-                                - (WORDS_BIG_ENDIAN ? nregs_diff : 0));
+         if (hard_regno >= 0 && reg_renumber[conflict_regno] >= 0
+             && (has_subreg_object_p (regno)
+                 || has_subreg_object_p (conflict_regno)))
+           {
+             int nregs1 = get_nregs (regno);
+             int nregs2 = get_nregs (conflict_regno);
+             /* Quick check it is no overlap at all between them.  */
+             if (hard_regno + nregs1 <= reg_renumber[conflict_regno]
+                 || reg_renumber[conflict_regno] + nregs2 <= hard_regno)
+               continue;
+
+             /* Check the overlap is ok if them have partial overlap.  */
+             set_offset_conflicts (regno, conflict_regno);
+             if (nregs1 >= nregs2)
+               EXECUTE_IF_SET_IN_BITMAP (&live_range_conflicts, 0, k, bi)
+                 {
+                   int start_regno
+                     = WORDS_BIG_ENDIAN
+                         ? reg_renumber[conflict_regno] + nregs2 + k - nregs1
+                         : reg_renumber[conflict_regno] - k;
+                   if (start_regno >= 0 && hard_regno == start_regno)
+                     SET_HARD_REG_BIT (conflict_set, start_regno);
+                 }
+             else
+               EXECUTE_IF_SET_IN_BITMAP (&live_range_conflicts, 0, k, bi)
+                 {
+                   int start_regno
+                     = WORDS_BIG_ENDIAN
+                         ? reg_renumber[conflict_regno] + nregs2 - k - nregs1
+                         : reg_renumber[conflict_regno] + k;
+                   if (start_regno < FIRST_PSEUDO_REGISTER
+                       && hard_regno == start_regno)
+                     SET_HARD_REG_BIT (conflict_set, start_regno);
+                 }
+           }
+         else
+           {
+             int conflict_hard_regno = reg_renumber[conflict_regno];
+
+             biggest_mode = lra_reg_info[conflict_regno].biggest_mode;
+             biggest_nregs
+               = hard_regno_nregs (conflict_hard_regno, biggest_mode);
+             nregs_diff
+               = (biggest_nregs
+                  - hard_regno_nregs (conflict_hard_regno,
+                                      PSEUDO_REGNO_MODE (conflict_regno)));
+             add_to_hard_reg_set (&conflict_set, biggest_mode,
+                                  conflict_hard_regno
+                                    - (WORDS_BIG_ENDIAN ? nregs_diff : 0));
+           }
          }
       if (! overlaps_hard_reg_set_p (conflict_set, mode, hard_regno))
        {
@@ -1637,7 +1720,9 @@ lra_assign (bool &fails_p)
   init_regno_assign_info ();
   bitmap_initialize (&all_spilled_pseudos, &reg_obstack);
   create_live_range_start_chains ();
+  bitmap_initialize (&live_range_conflicts, &reg_obstack);
   setup_live_pseudos_and_spill_after_risky_transforms (&all_spilled_pseudos);
+  bitmap_clear (&live_range_conflicts);
   if (! lra_hard_reg_split_p && ! lra_asm_error_p && flag_checking)
     /* Check correctness of allocation but only when there are no hard reg
        splits and asm errors as in the case of errors explicit insns involving
diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index c3ad846b97b..912d0c3feec 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -2363,13 +2363,19 @@ process_alt_operands (int only_alternative)
                      {
                        /* We should reject matching of an early
                           clobber operand if the matching operand is
-                          not dying in the insn.  */
-                       if (!TEST_BIT (curr_static_id->operand[m]
-                                      .early_clobber_alts, nalt)
+                          not dying in the insn. But for subreg of pseudo which
+                          has subreg live be tracked in ira, the REG_DEAD note
+                          doesn't have. that case we think them the matching is
+                          ok. */
+                       if (!TEST_BIT (
+                             curr_static_id->operand[m].early_clobber_alts,
+                             nalt)
                            || operand_reg[nop] == NULL_RTX
-                           || (find_regno_note (curr_insn, REG_DEAD,
-                                                REGNO (op))
-                               || REGNO (op) == REGNO (operand_reg[m])))
+                           || find_regno_note (curr_insn, REG_DEAD, REGNO (op))
+                           || (read_modify_subreg_p (
+                                 *curr_id->operand_loc[nop])
+                               && has_subreg_object_p (REGNO (op)))
+                           || REGNO (op) == REGNO (operand_reg[m]))
                          match_p = true;
                      }
                    if (match_p)
diff --git a/gcc/lra-int.h b/gcc/lra-int.h
index d0752c2ae50..5a97bd61475 100644
--- a/gcc/lra-int.h
+++ b/gcc/lra-int.h
@@ -21,6 +21,9 @@ along with GCC; see the file COPYING3.        If not see
 #ifndef GCC_LRA_INT_H
 #define GCC_LRA_INT_H
 
+#include "lra.h"
+#include "subreg-live-range.h"
+
 #define lra_assert(c) gcc_checking_assert (c)
 
 /* The parameter used to prevent infinite reloading for an insn.  Each
@@ -46,6 +49,8 @@ struct lra_live_range
   lra_live_range_t next;
   /* Pointer to structures with the same start.         */
   lra_live_range_t start_next;
+  /* Object whose live range is described by given structure.  */
+  subreg_ranges subreg;
 };
 
 typedef struct lra_copy *lra_copy_t;
@@ -108,6 +113,8 @@ public:
   /* The biggest size mode in which each pseudo reg is referred in
      whole function (possibly via subreg).  */
   machine_mode biggest_mode;
+  /* The real reg MODE.  */
+  machine_mode reg_mode;
   /* Live ranges of the pseudo.         */
   lra_live_range_t live_ranges;
   /* This member is set up in lra-lives.cc for subsequent
@@ -159,6 +166,12 @@ struct lra_insn_reg
   unsigned int subreg_p : 1;
   /* The corresponding regno of the register.  */
   int regno;
+  /* The start and end of current ref of blocks, remember the use/def can be
+     a normal subreg.  */
+  int start, end;
+  /* The start and end of current ref of hard regs, remember the use/def can be
+     a normal subreg.  */
+  int start_reg, end_reg;
   /* Next reg info of the same insn.  */
   struct lra_insn_reg *next;
 };
@@ -330,6 +343,8 @@ extern struct lra_insn_reg *lra_get_insn_regs (int);
 extern void lra_free_copies (void);
 extern void lra_create_copy (int, int, int);
 extern lra_copy_t lra_get_copy (int);
+extern subreg_range
+get_range_hard_regs (int regno, const subreg_range &r);
 
 extern int lra_new_regno_start;
 extern int lra_constraint_new_regno_start;
@@ -531,4 +546,22 @@ lra_assign_reg_val (int from, int to)
   lra_reg_info[to].offset = lra_reg_info[from].offset;
 }
 
+/* Return the number regs of REGNO.  */
+inline int
+get_nregs (int regno)
+{
+  enum reg_class aclass = lra_get_allocno_class (regno);
+  gcc_assert (aclass != NO_REGS);
+  int nregs = ira_reg_class_max_nregs[aclass][lra_reg_info[regno].reg_mode];
+  return nregs;
+}
+
+extern bitmap_head pseudos_has_subreg_object;
+/* Return true if pseudo REGNO has subreg live range.  */
+inline bool
+has_subreg_object_p (int regno)
+{
+  return bitmap_bit_p (&pseudos_has_subreg_object, regno);
+}
+
 #endif /* GCC_LRA_INT_H */
diff --git a/gcc/lra-lives.cc b/gcc/lra-lives.cc
index 477b82786cf..814b3960541 100644
--- a/gcc/lra-lives.cc
+++ b/gcc/lra-lives.cc
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.        If not see
    stack memory slots to spilled pseudos.  */
 
 #include "config.h"
+#define INCLUDE_VECTOR
 #include "system.h"
 #include "coretypes.h"
 #include "backend.h"
@@ -44,6 +45,7 @@ along with GCC; see the file COPYING3.        If not see
 #include "lra-int.h"
 #include "target.h"
 #include "function-abi.h"
+#include "subreg-live-range.h"
 
 /* Program points are enumerated by numbers from range
    0..LRA_LIVE_MAX_POINT-1.  There are approximately two times more
@@ -97,6 +99,9 @@ static bitmap_head temp_bitmap;
 /* Pool for pseudo live ranges.         */
 static object_allocator<lra_live_range> lra_live_range_pool ("live ranges");
 
+/* Store def/use point of has_subreg_object_p register.  */
+static class subregs_live_points *live_points;
+
 /* Free live range list LR.  */
 static void
 free_live_range_list (lra_live_range_t lr)
@@ -113,16 +118,26 @@ free_live_range_list (lra_live_range_t lr)
 
 /* Create and return pseudo live range with given attributes.  */
 static lra_live_range_t
-create_live_range (int regno, int start, int finish, lra_live_range_t next)
+create_live_range (int regno, const subreg_ranges &sr, int start, int finish,
+                  lra_live_range_t next)
 {
   lra_live_range_t p = lra_live_range_pool.allocate ();
   p->regno = regno;
   p->start = start;
   p->finish = finish;
   p->next = next;
+  p->subreg = sr;
   return p;
 }
 
+static lra_live_range_t
+create_live_range (int regno, int start, int finish, lra_live_range_t next)
+{
+  subreg_ranges sr = subreg_ranges (1);
+  sr.add_range (1, subreg_range (0, 1));
+  return create_live_range (regno, sr, start, finish, next);
+}
+
 /* Copy live range R and return the result.  */
 static lra_live_range_t
 copy_live_range (lra_live_range_t r)
@@ -164,7 +179,8 @@ lra_merge_live_ranges (lra_live_range_t r1, 
lra_live_range_t r2)
       if (r1->start < r2->start)
        std::swap (r1, r2);
 
-      if (r1->start == r2->finish + 1)
+      if (r1->start == r2->finish + 1
+         && (r1->regno != r2->regno || r1->subreg.same_p (r2->subreg)))
        {
          /* Joint ranges: merge r1 and r2 into r1.  */
          r1->start = r2->start;
@@ -174,7 +190,8 @@ lra_merge_live_ranges (lra_live_range_t r1, 
lra_live_range_t r2)
        }
       else
        {
-         gcc_assert (r2->finish + 1 < r1->start);
+         gcc_assert (r2->finish + 1 < r1->start
+                     || !r1->subreg.same_p (r2->subreg));
          /* Add r1 to the result.  */
          if (first == NULL)
            first = last = r1;
@@ -237,6 +254,10 @@ sparseset_contains_pseudos_p (sparseset a)
   return false;
 }
 
+static void
+update_pseudo_point (int regno, const subreg_range &range, int point,
+                    enum point_type type);
+
 /* Mark pseudo REGNO as living or dying at program point POINT, depending on
    whether TYPE is a definition or a use.  If this is the first reference to
    REGNO that we've encountered, then create a new live range for it.  */
@@ -249,31 +270,100 @@ update_pseudo_point (int regno, int point, enum 
point_type type)
   /* Don't compute points for hard registers.  */
   if (HARD_REGISTER_NUM_P (regno))
     return;
+  if (!complete_info_p && lra_get_regno_hard_regno (regno) >= 0)
+    return;
 
-  if (complete_info_p || lra_get_regno_hard_regno (regno) < 0)
+  if (has_subreg_object_p (regno))
     {
-      if (type == DEF_POINT)
-       {
-         if (sparseset_bit_p (pseudos_live, regno))
-           {
-             p = lra_reg_info[regno].live_ranges;
-             lra_assert (p != NULL);
-             p->finish = point;
-           }
-       }
-      else /* USE_POINT */
+      update_pseudo_point (regno, subreg_range (0, get_nregs (regno)), point,
+                          type);
+      return;
+    }
+
+  if (type == DEF_POINT)
+    {
+      if (sparseset_bit_p (pseudos_live, regno))
        {
-         if (!sparseset_bit_p (pseudos_live, regno)
-             && ((p = lra_reg_info[regno].live_ranges) == NULL
-                 || (p->finish != point && p->finish + 1 != point)))
-           lra_reg_info[regno].live_ranges
-             = create_live_range (regno, point, -1, p);
+         p = lra_reg_info[regno].live_ranges;
+         lra_assert (p != NULL);
+         p->finish = point;
        }
     }
+  else /* USE_POINT */
+    {
+      if (!sparseset_bit_p (pseudos_live, regno)
+         && ((p = lra_reg_info[regno].live_ranges) == NULL
+             || (p->finish != point && p->finish + 1 != point)))
+       lra_reg_info[regno].live_ranges
+         = create_live_range (regno, point, -1, p);
+    }
 }
 
-/* The corresponding bitmaps of BB currently being processed.  */
-static bitmap bb_killed_pseudos, bb_gen_pseudos;
+/* Like the above mark_regno_dead but for has_subreg_object_p REGNO.  */
+static void
+update_pseudo_point (int regno, const subreg_range &range, int point,
+                    enum point_type type)
+{
+  /* Don't compute points for hard registers.  */
+  if (HARD_REGISTER_NUM_P (regno))
+    return;
+
+  if (!complete_info_p && lra_get_regno_hard_regno (regno) >= 0)
+    {
+      if (has_subreg_object_p (regno))
+       live_points->add_range (regno, get_nregs (regno), range,
+                               type == DEF_POINT);
+      return;
+    }
+
+  if (!has_subreg_object_p (regno))
+    {
+      update_pseudo_point (regno, point, type);
+      return;
+    }
+
+  if (lra_dump_file != NULL)
+    {
+      fprintf (lra_dump_file, "       %s r%d",
+              type == DEF_POINT ? "def" : "use", regno);
+      fprintf (lra_dump_file, "[subreg: start %d, nregs: %d]", range.start,
+              range.end - range.start);
+      fprintf (lra_dump_file, " at point %d\n", point);
+    }
+
+  live_points->add_point (regno, get_nregs (regno), range, type == DEF_POINT,
+                         point);
+}
+
+/* Update each range in SR.  */
+static void
+update_pseudo_point (int regno, const subreg_ranges sr, int point,
+                    enum point_type type)
+{
+  for (const subreg_range &range : sr.ranges)
+    update_pseudo_point (regno, range, point, type);
+}
+
+/* Structure describing local BB data used for pseudo
+   live-analysis.  */
+class bb_data_pseudos : public basic_block_subreg_live_info
+{
+public:
+  /* Basic block about which the below data are.  */
+  basic_block bb;
+};
+
+/* Array for all BB data.  Indexed by the corresponding BB index.  */
+typedef class bb_data_pseudos *bb_data_t;
+
+/* All basic block data are referred through the following array.  */
+static bb_data_t bb_data;
+
+/* The corresponding basic block info of BB currently being processed.  */
+static bb_data_t curr_bb_info;
+
+/* Flag mean curr function has subreg ref need be tracked.  */
+static bool has_subreg_live_p;
 
 /* Record hard register REGNO as now being live.  It updates
    living hard regs and START_LIVING.  */
@@ -336,12 +426,18 @@ mark_pseudo_dead (int regno)
   if (!sparseset_bit_p (pseudos_live, regno))
     return;
 
+  /* Just return if regno have partial subreg live for subreg access.  */
+  if (has_subreg_object_p (regno) && !live_points->empty_live_p (regno))
+    return;
+
   sparseset_clear_bit (pseudos_live, regno);
   sparseset_set_bit (start_dying, regno);
 }
 
+static void
+mark_regno_live (int regno, const subreg_range &range, machine_mode mode);
 /* Mark register REGNO (pseudo or hard register) in MODE as being live
-   and update BB_GEN_PSEUDOS.  */
+   and update CURR_BB_INFO.  */
 static void
 mark_regno_live (int regno, machine_mode mode)
 {
@@ -352,6 +448,11 @@ mark_regno_live (int regno, machine_mode mode)
       for (last = end_hard_regno (mode, regno); regno < last; regno++)
        make_hard_regno_live (regno);
     }
+  else if (has_subreg_object_p (regno))
+    {
+      machine_mode mode = lra_reg_info[regno].reg_mode;
+      mark_regno_live (regno, subreg_range (0, get_nregs (regno)), mode);
+    }
   else
     {
       mark_pseudo_live (regno);
@@ -361,9 +462,26 @@ mark_regno_live (int regno, machine_mode mode)
     }
 }
 
+/* Like the above mark_regno_dead but for has_subreg_object_p REGNO.  */
+static void
+mark_regno_live (int regno, const subreg_range &range, machine_mode mode)
+{
+  if (HARD_REGISTER_NUM_P (regno) || !has_subreg_object_p (regno))
+    mark_regno_live (regno, mode);
+  else
+    {
+      mark_pseudo_live (regno);
+      machine_mode mode = lra_reg_info[regno].reg_mode;
+      if (!range.full_p (get_nregs (regno)))
+       has_subreg_live_p = true;
+      add_subreg_range (curr_bb_info, regno, mode, range, false);
+    }
+}
 
+static void
+mark_regno_dead (int regno, const subreg_range &range, machine_mode mode);
 /* Mark register REGNO (pseudo or hard register) in MODE as being dead
-   and update BB_GEN_PSEUDOS and BB_KILLED_PSEUDOS.  */
+   and update CURR_BB_INFO.  */
 static void
 mark_regno_dead (int regno, machine_mode mode)
 {
@@ -374,6 +492,12 @@ mark_regno_dead (int regno, machine_mode mode)
       for (last = end_hard_regno (mode, regno); regno < last; regno++)
        make_hard_regno_dead (regno);
     }
+  else if (has_subreg_object_p (regno))
+    {
+      machine_mode mode = lra_reg_info[regno].reg_mode;
+      subreg_range range = subreg_range (0, get_nregs (regno));
+      mark_regno_dead (regno, range, mode);
+    }
   else
     {
       mark_pseudo_dead (regno);
@@ -384,7 +508,22 @@ mark_regno_dead (int regno, machine_mode mode)
     }
 }
 
-
+/* Like the above mark_regno_dead but for has_subreg_object_p REGNO.  */
+static void
+mark_regno_dead (int regno, const subreg_range &range, machine_mode mode)
+{
+  if (HARD_REGISTER_NUM_P (regno) || !has_subreg_object_p (regno))
+    mark_regno_dead (regno, mode);
+  else
+    {
+      mark_pseudo_dead (regno);
+      machine_mode mode = lra_reg_info[regno].reg_mode;
+      if (!range.full_p (get_nregs (regno)))
+       has_subreg_live_p = true;
+      remove_subreg_range (curr_bb_info, regno, mode, range);
+      add_subreg_range (curr_bb_info, regno, mode, range, true);
+    }
+}
 
 /* This page contains code for making global live analysis of pseudos.
    The code works only when pseudo live info is changed on a BB
@@ -814,7 +953,12 @@ process_bb_lives (basic_block bb, int &curr_point, bool 
dead_insn_p)
   hard_regs_live &= ~eliminable_regset;
   EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi)
     {
-      update_pseudo_point (j, curr_point, USE_POINT);
+      if (bitmap_bit_p (reg_live_partial_out, j) && has_subreg_object_p (j))
+       for (const subreg_range &r : range_out->lives.at (j).ranges)
+         update_pseudo_point (j, get_range_hard_regs (j, r), curr_point,
+                              USE_POINT);
+      else
+       update_pseudo_point (j, curr_point, USE_POINT);
       mark_pseudo_live (j);
     }
 
@@ -1007,8 +1151,11 @@ process_bb_lives (basic_block bb, int &curr_point, bool 
dead_insn_p)
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
        if (reg->type != OP_IN)
          {
-           update_pseudo_point (reg->regno, curr_point, USE_POINT);
-           mark_regno_live (reg->regno, reg->biggest_mode);
+           const subreg_range &range = subreg_range (reg->start, reg->end);
+           update_pseudo_point (reg->regno,
+                                get_range_hard_regs (reg->regno, range),
+                                curr_point, USE_POINT);
+           mark_regno_live (reg->regno, range, reg->biggest_mode);
            /* ??? Should be a no-op for unused registers.  */
            check_pseudos_live_through_calls (reg->regno, last_call_abi);
          }
@@ -1029,17 +1176,20 @@ process_bb_lives (basic_block bb, int &curr_point, bool 
dead_insn_p)
 
       /* See which defined values die here.  */
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
-       if (reg->type != OP_IN
-           && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
+       if (reg->type != OP_IN && !reg_early_clobber_p (reg, n_alt)
+           && (!reg->subreg_p || has_subreg_object_p (reg->regno)))
          {
+           const subreg_range &range = subreg_range (reg->start, reg->end);
            if (reg->type == OP_OUT)
-             update_pseudo_point (reg->regno, curr_point, DEF_POINT);
-           mark_regno_dead (reg->regno, reg->biggest_mode);
+             update_pseudo_point (reg->regno,
+                                  get_range_hard_regs (reg->regno, range),
+                                  curr_point, DEF_POINT);
+           mark_regno_dead (reg->regno, range, reg->biggest_mode);
          }
 
       for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
-       if (reg->type != OP_IN
-           && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
+       if (reg->type != OP_IN && !reg_early_clobber_p (reg, n_alt)
+           && !reg->subreg_p)
          make_hard_regno_dead (reg->regno);
 
       if (curr_id->arg_hard_regs != NULL)
@@ -1070,7 +1220,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool 
dead_insn_p)
 
       /* Increment the current program point if we must.  */
       if (sparseset_contains_pseudos_p (unused_set)
-         || sparseset_contains_pseudos_p (start_dying))
+         || sparseset_contains_pseudos_p (start_dying) || has_subreg_live_p)
        next_program_point (curr_point, freq);
 
       /* If we removed the source reg from a simple register copy from the
@@ -1091,9 +1241,12 @@ process_bb_lives (basic_block bb, int &curr_point, bool 
dead_insn_p)
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
        if (reg->type != OP_OUT)
          {
+           const subreg_range &range = subreg_range (reg->start, reg->end);
            if (reg->type == OP_IN)
-             update_pseudo_point (reg->regno, curr_point, USE_POINT);
-           mark_regno_live (reg->regno, reg->biggest_mode);
+             update_pseudo_point (reg->regno,
+                                  get_range_hard_regs (reg->regno, range),
+                                  curr_point, USE_POINT);
+           mark_regno_live (reg->regno, range, reg->biggest_mode);
            check_pseudos_live_through_calls (reg->regno, last_call_abi);
          }
 
@@ -1113,22 +1266,25 @@ process_bb_lives (basic_block bb, int &curr_point, bool 
dead_insn_p)
 
       /* Mark early clobber outputs dead.  */
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
-       if (reg->type != OP_IN
-           && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
+       if (reg->type != OP_IN && reg_early_clobber_p (reg, n_alt)
+           && (!reg->subreg_p || has_subreg_object_p (reg->regno)))
          {
+           const subreg_range &range = subreg_range (reg->start, reg->end);
            if (reg->type == OP_OUT)
-             update_pseudo_point (reg->regno, curr_point, DEF_POINT);
-           mark_regno_dead (reg->regno, reg->biggest_mode);
+             update_pseudo_point (reg->regno,
+                                  get_range_hard_regs (reg->regno, range),
+                                  curr_point, DEF_POINT);
+           mark_regno_dead (reg->regno, range, reg->biggest_mode);
 
            /* We're done processing inputs, so make sure early clobber
               operands that are both inputs and outputs are still live.  */
            if (reg->type == OP_INOUT)
-             mark_regno_live (reg->regno, reg->biggest_mode);
+             mark_regno_live (reg->regno, range, reg->biggest_mode);
          }
 
       for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
-       if (reg->type != OP_IN
-           && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
+       if (reg->type != OP_IN && reg_early_clobber_p (reg, n_alt)
+           && !reg->subreg_p)
          {
            struct lra_insn_reg *reg2;
 
@@ -1144,7 +1300,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool 
dead_insn_p)
 
       /* Increment the current program point if we must.  */
       if (sparseset_contains_pseudos_p (dead_set)
-         || sparseset_contains_pseudos_p (start_dying))
+         || sparseset_contains_pseudos_p (start_dying) || has_subreg_live_p)
        next_program_point (curr_point, freq);
 
       /* Update notes. */
@@ -1277,13 +1433,17 @@ process_bb_lives (basic_block bb, int &curr_point, bool 
dead_insn_p)
 
   EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i)
     {
-      update_pseudo_point (i, curr_point, DEF_POINT);
+      if (has_subreg_object_p (i))
+       update_pseudo_point (i, live_points->subreg_live_ranges.at (i),
+                            curr_point, DEF_POINT);
+      else
+       update_pseudo_point (i, curr_point, DEF_POINT);
       mark_pseudo_dead (i);
     }
 
-    EXECUTE_IF_SET_IN_BITMAP (DF_LIVE_SUBREG_IN (bb), FIRST_PSEUDO_REGISTER, j,
-                             bi)
-      {
+  EXECUTE_IF_SET_IN_BITMAP (DF_LIVE_SUBREG_IN (bb), FIRST_PSEUDO_REGISTER, j,
+                           bi)
+    {
       if (sparseset_cardinality (pseudos_live_through_calls) == 0)
        break;
       if (sparseset_bit_p (pseudos_live_through_calls, j))
@@ -1384,7 +1544,8 @@ remove_some_program_points_and_update_live_ranges (void)
              next_r = r->next;
              r->start = map[r->start];
              r->finish = map[r->finish];
-             if (prev_r == NULL || prev_r->start > r->finish + 1)
+             if (prev_r == NULL || prev_r->start > r->finish + 1
+                 || !prev_r->subreg.same_p (r->subreg))
                {
                  prev_r = r;
                  continue;
@@ -1402,8 +1563,18 @@ remove_some_program_points_and_update_live_ranges (void)
 void
 lra_print_live_range_list (FILE *f, lra_live_range_t r)
 {
-  for (; r != NULL; r = r->next)
-    fprintf (f, " [%d..%d]", r->start, r->finish);
+  if (r != NULL && has_subreg_object_p (r->regno))
+    {
+      for (; r != NULL; r = r->next)
+       {
+         fprintf (f, " [%d..%d]{", r->start, r->finish);
+         r->subreg.dump (f);
+         fprintf (f, "}");
+       }
+    }
+  else
+    for (; r != NULL; r = r->next)
+      fprintf (f, " [%d..%d]", r->start, r->finish);
   fprintf (f, "\n");
 }
 
@@ -1476,7 +1647,84 @@ compress_live_ranges (void)
     }
 }
 
-
+/* Use to temp record subregs live range in create_subregs_live_ranges 
function.
+ */
+class subreg_live_item
+{
+public:
+  subreg_ranges subreg;
+  int start, finish;
+};
+
+/* Create subreg live ranges from objects def/use point info.  */
+static void
+create_subregs_live_ranges ()
+{
+  for (const auto &subreg_point_it : live_points->subreg_points)
+    {
+      unsigned int regno = subreg_point_it.first;
+      const class live_points &points = subreg_point_it.second;
+      class lra_reg *reg_info = &lra_reg_info[regno];
+      std::vector<subreg_live_item> temps;
+      gcc_assert (has_subreg_object_p (regno));
+      for (const auto &point_it : points.points)
+       {
+         int point = point_it.first;
+         const live_point &regs = point_it.second;
+         gcc_assert (temps.empty () || temps.back ().finish <= point);
+         if (!regs.use_reg.empty_p ())
+           {
+             if (temps.empty ())
+               temps.push_back ({regs.use_reg, point, -1});
+             else if (temps.back ().finish == -1)
+               {
+                 if (!temps.back ().subreg.same_p (regs.use_reg))
+                   {
+                     if (temps.back ().start == point)
+                       temps.back ().subreg.add_ranges (regs.use_reg);
+                     else
+                       {
+                         temps.back ().finish = point - 1;
+
+                         subreg_ranges temp = regs.use_reg;
+                         temp.add_ranges (temps.back ().subreg);
+                         temps.push_back ({temp, point, -1});
+                       }
+                   }
+               }
+             else if (temps.back ().subreg.same_p (regs.use_reg)
+                      && (temps.back ().finish == point
+                          || temps.back ().finish + 1 == point))
+               temps.back ().finish = -1;
+             else
+               temps.push_back ({regs.use_reg, point, -1});
+           }
+         if (!regs.def_reg.empty_p ())
+           {
+             gcc_assert (!temps.empty ());
+             if (regs.def_reg.include_ranges_p (temps.back ().subreg))
+               temps.back ().finish = point;
+             else if (temps.back ().subreg.include_ranges_p (regs.def_reg))
+               {
+                 temps.back ().finish = point;
+
+                 subreg_ranges diff = temps.back ().subreg;
+                 diff.remove_ranges (regs.def_reg);
+                 temps.push_back ({diff, point + 1, -1});
+               }
+             else
+               gcc_unreachable ();
+           }
+       }
+
+      gcc_assert (reg_info->live_ranges == NULL);
+
+      for (const subreg_live_item &item : temps)
+       reg_info->live_ranges
+         = create_live_range (regno, item.subreg, item.start, item.finish,
+                              reg_info->live_ranges);
+    }
+}
 
 /* The number of the current live range pass.  */
 int lra_live_range_iter;
@@ -1557,6 +1805,8 @@ lra_create_live_ranges_1 (bool all_p, bool dead_insn_p)
   int n = inverted_rev_post_order_compute (cfun, rpo);
   lra_assert (n == n_basic_blocks_for_fn (cfun));
   bb_live_change_p = false;
+  has_subreg_live_p = false;
+  live_points = new subregs_live_points ();
   for (i = 0; i < n; ++i)
     {
       bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]);
@@ -1639,9 +1889,14 @@ lra_create_live_ranges_1 (bool all_p, bool dead_insn_p)
        }
     }
   lra_live_max_point = curr_point;
+  create_subregs_live_ranges ();
   if (lra_dump_file != NULL)
-    print_live_ranges (lra_dump_file);
+    {
+      live_points->dump (lra_dump_file);
+      print_live_ranges (lra_dump_file);
+    }
   /* Clean up. */
+  delete live_points;
   sparseset_free (unused_set);
   sparseset_free (dead_set);
   sparseset_free (start_dying);
diff --git a/gcc/lra.cc b/gcc/lra.cc
index bcc00ff7d6b..47d378b371e 100644
--- a/gcc/lra.cc
+++ b/gcc/lra.cc
@@ -566,6 +566,54 @@ lra_asm_insn_error (rtx_insn *insn)
 /* Pools for insn reg info.  */
 object_allocator<lra_insn_reg> lra_insn_reg_pool ("insn regs");
 
+/* Return the subreg range of rtx SUBREG in blocks.  */
+static subreg_range
+get_range_blocks (int regno, bool subreg_p, machine_mode reg_mode,
+                 poly_int64 offset, poly_int64 size)
+{
+  gcc_assert (has_subreg_object_p (regno));
+  int nblocks = get_nblocks (reg_mode);
+  if (!subreg_p)
+    return subreg_range (0, nblocks);
+
+  poly_int64 unit_size = REGMODE_NATURAL_SIZE (reg_mode);
+  poly_int64 left = offset + size;
+
+  int subreg_start = -1;
+  int subreg_nregs = -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_nregs < 0 && maybe_le (left, right))
+       {
+         subreg_nregs = i + 1 - subreg_start;
+         break;
+       }
+    }
+  gcc_assert (subreg_start >= 0 && subreg_nregs > 0);
+  return subreg_range (subreg_start, subreg_start + subreg_nregs);
+}
+
+/* Return the subreg range of rtx SUBREG in hard regs.  */
+subreg_range
+get_range_hard_regs (int regno, const subreg_range &r)
+{
+  if (!has_subreg_object_p (regno))
+    return subreg_range (0, 1);
+  enum reg_class aclass = lra_get_allocno_class (regno);
+  gcc_assert (aclass != NO_REGS);
+  int nregs = ira_reg_class_max_nregs[aclass][lra_reg_info[regno].reg_mode];
+  int nblocks = get_nblocks (lra_reg_info[regno].reg_mode);
+  int times = nblocks / nregs;
+  gcc_assert (nblocks >= nregs && times * nregs == nblocks);
+  int start = r.start / times;
+  int end = CEIL (r.end, times);
+
+  return subreg_range (start, end);
+}
+
 /* Create LRA insn related info about a reference to REGNO in INSN
    with TYPE (in/out/inout), biggest reference mode MODE, flag that it
    is reference through subreg (SUBREG_P), and reference to the next
@@ -573,21 +621,49 @@ object_allocator<lra_insn_reg> lra_insn_reg_pool ("insn 
regs");
    alternatives in which it can be early clobbered are given by
    EARLY_CLOBBER_ALTS.  */
 static struct lra_insn_reg *
-new_insn_reg (rtx_insn *insn, int regno, enum op_type type,
-             machine_mode mode, bool subreg_p,
-             alternative_mask early_clobber_alts,
+new_insn_reg (rtx_insn *insn, int regno, enum op_type type, poly_int64 size,
+             poly_int64 offset, machine_mode mode, machine_mode reg_mode,
+             bool subreg_p, alternative_mask early_clobber_alts,
              struct lra_insn_reg *next)
 {
   lra_insn_reg *ir = lra_insn_reg_pool.allocate ();
   ir->type = type;
   ir->biggest_mode = mode;
-  if (NONDEBUG_INSN_P (insn)
-      && partial_subreg_p (lra_reg_info[regno].biggest_mode, mode))
-    lra_reg_info[regno].biggest_mode = mode;
+  if (NONDEBUG_INSN_P (insn))
+    {
+      if (partial_subreg_p (lra_reg_info[regno].biggest_mode, mode))
+       {
+         lra_reg_info[regno].biggest_mode = mode;
+       }
+
+      if (regno >= FIRST_PSEUDO_REGISTER)
+       {
+         if (lra_reg_info[regno].reg_mode == VOIDmode)
+           lra_reg_info[regno].reg_mode = reg_mode;
+         else
+           gcc_assert (maybe_eq (GET_MODE_SIZE (lra_reg_info[regno].reg_mode),
+                                 GET_MODE_SIZE (reg_mode)));
+       }
+    }
   ir->subreg_p = subreg_p;
   ir->early_clobber_alts = early_clobber_alts;
   ir->regno = regno;
   ir->next = next;
+  if (has_subreg_object_p (regno))
+    {
+      const subreg_range &r
+       = get_range_blocks (regno, subreg_p, reg_mode, offset, size);
+      ir->start = r.start;
+      ir->end = r.end;
+      const subreg_range &r_hard = get_range_hard_regs (regno, r);
+      ir->start_reg = r_hard.start;
+      ir->end_reg = r_hard.end;
+    }
+  else
+    {
+      ir->start = 0;
+      ir->end = 1;
+    }
   return ir;
 }
 
@@ -887,11 +963,18 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
       return list;
   mode = GET_MODE (op);
   subreg_p = false;
+  poly_int64 size = GET_MODE_SIZE (mode);
+  poly_int64 offset = 0;
   if (code == SUBREG)
     {
       mode = wider_subreg_mode (op);
       if (read_modify_subreg_p (op))
-       subreg_p = true;
+       {
+         offset = SUBREG_BYTE (op);
+         subreg_p = true;
+       }
+      else
+       size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op)));
       op = SUBREG_REG (op);
       code = GET_CODE (op);
     }
@@ -925,7 +1008,8 @@ collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
                   && ! (FIRST_STACK_REG <= regno
                         && regno <= LAST_STACK_REG));
 #endif
-             list = new_insn_reg (data->insn, regno, type, mode, subreg_p,
+             list = new_insn_reg (data->insn, regno, type, size, offset, mode,
+                                  GET_MODE (op), subreg_p,
                                   early_clobber ? ALL_ALTERNATIVES : 0, list);
            }
        }
@@ -1354,6 +1438,7 @@ initialize_lra_reg_info_element (int i)
   lra_reg_info[i].preferred_hard_regno_profit1 = 0;
   lra_reg_info[i].preferred_hard_regno_profit2 = 0;
   lra_reg_info[i].biggest_mode = VOIDmode;
+  lra_reg_info[i].reg_mode = VOIDmode;
   lra_reg_info[i].live_ranges = NULL;
   lra_reg_info[i].nrefs = lra_reg_info[i].freq = 0;
   lra_reg_info[i].last_reload = 0;
@@ -1459,7 +1544,21 @@ lra_get_copy (int n)
   return copy_vec[n];
 }
 
-
+/* Return true if REG occupied the same blocks as OFFSET + SIZE subreg.  */
+static bool
+reg_same_range_p (lra_insn_reg *reg, poly_int64 offset, poly_int64 size,
+                 bool subreg_p)
+{
+  if (has_subreg_object_p (reg->regno))
+    {
+      const subreg_range &r
+       = get_range_blocks (reg->regno, subreg_p,
+                           lra_reg_info[reg->regno].reg_mode, offset, size);
+      return r.start == reg->start && r.end == reg->end;
+    }
+  else
+    return true;
+}
 
 /* This page contains code dealing with info about registers in
    insns.  */
@@ -1483,11 +1582,18 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t 
data, rtx x,
   code = GET_CODE (x);
   mode = GET_MODE (x);
   subreg_p = false;
+  poly_int64 size = GET_MODE_SIZE (mode);
+  poly_int64 offset = 0;
   if (GET_CODE (x) == SUBREG)
     {
       mode = wider_subreg_mode (x);
       if (read_modify_subreg_p (x))
-       subreg_p = true;
+       {
+         offset = SUBREG_BYTE (x);
+         subreg_p = true;
+       }
+      else
+       size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
       x = SUBREG_REG (x);
       code = GET_CODE (x);
     }
@@ -1499,7 +1605,8 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, 
rtx x,
       expand_reg_info ();
       if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, INSN_UID (insn)))
        {
-         data->regs = new_insn_reg (data->insn, regno, type, mode, subreg_p,
+         data->regs = new_insn_reg (data->insn, regno, type, size, offset,
+                                    mode, GET_MODE (x), subreg_p,
                                     early_clobber_alts, data->regs);
          return;
        }
@@ -1508,12 +1615,14 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t 
data, rtx x,
          for (curr = data->regs; curr != NULL; curr = curr->next)
            if (curr->regno == regno)
              {
-               if (curr->subreg_p != subreg_p || curr->biggest_mode != mode)
+               if (!reg_same_range_p (curr, offset, size, subreg_p)
+                   || curr->biggest_mode != mode)
                  /* The info cannot be integrated into the found
                     structure.  */
-                 data->regs = new_insn_reg (data->insn, regno, type, mode,
-                                            subreg_p, early_clobber_alts,
-                                            data->regs);
+                 data->regs
+                   = new_insn_reg (data->insn, regno, type, size, offset, mode,
+                                   GET_MODE (x), subreg_p, early_clobber_alts,
+                                   data->regs);
                else
                  {
                    if (curr->type != type)
diff --git a/gcc/subreg-live-range.h b/gcc/subreg-live-range.h
index bee97708a52..b703b9642f2 100644
--- a/gcc/subreg-live-range.h
+++ b/gcc/subreg-live-range.h
@@ -76,6 +76,7 @@ public:
   int max;
   std::set<subreg_range> ranges;
 
+  subreg_ranges () : max (1) {}
   subreg_ranges (int max) : max (max) { gcc_assert (maybe_ge (max, 1)); }
 
   /* Modify ranges.  */
-- 
2.36.3


Reply via email to