]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/lra.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / lra.c
index 61e40eebe3ff949be1dc82db8e118bf3cda5095b..5a4b6638913f1112e538fd3417cc6c6b7d9e2958 100644 (file)
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -1,5 +1,5 @@
 /* LRA (local register allocator) driver and LRA utilities.
-   Copyright (C) 2010-2017 Free Software Foundation, Inc.
+   Copyright (C) 2010-2021 Free Software Foundation, Inc.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
 This file is part of GCC.
@@ -121,6 +121,7 @@ along with GCC; see the file COPYING3.      If not see
 #include "lra.h"
 #include "lra-int.h"
 #include "print-rtl.h"
+#include "function-abi.h"
 
 /* Dump bitmap SET with TITLE and BB INDEX.  */
 void
@@ -159,7 +160,6 @@ static void invalidate_insn_recog_data (int);
 static int get_insn_freq (rtx_insn *);
 static void invalidate_insn_data_regno_info (lra_insn_recog_data_t,
                                             rtx_insn *, int);
-
 /* Expand all regno related info needed for LRA.  */
 static void
 expand_reg_data (int old)
@@ -480,6 +480,8 @@ lra_emit_add (rtx x, rtx y, rtx z)
 /* The number of emitted reload insns so far.  */
 int lra_curr_reload_num;
 
+static void remove_insn_scratches (rtx_insn *insn);
+
 /* Emit x := y, processing special case when y = u + v or y = u + v *
    scale + w through emit_add (Y can be an address which is base +
    index reg * scale + displacement in general case).  X may be used
@@ -488,13 +490,20 @@ void
 lra_emit_move (rtx x, rtx y)
 {
   int old;
-
+  rtx_insn *insn;
+  
   if (GET_CODE (y) != PLUS)
     {
       if (rtx_equal_p (x, y))
        return;
       old = max_reg_num ();
-      emit_move_insn (x, y);
+
+      insn = (GET_CODE (x) != STRICT_LOW_PART
+             ? emit_move_insn (x, y) : emit_insn (gen_rtx_SET (x, y)));
+      /* The move pattern may require scratch registers, so convert them
+        into real registers now.  */
+      if (insn != NULL_RTX)
+       remove_insn_scratches (insn);
       if (REG_P (x))
        lra_reg_info[ORIGINAL_REGNO (x)].last_reload = ++lra_curr_reload_num;
       /* Function emit_move can create pseudos -- so expand the pseudo
@@ -531,15 +540,13 @@ object_allocator<lra_insn_reg> lra_insn_reg_pool ("insn regs");
 
 /* 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), flag that is early
-   clobbered in the insn (EARLY_CLOBBER), and reference to the next
+   is reference through subreg (SUBREG_P), and reference to the next
    insn reg info (NEXT).  If REGNO can be early clobbered,
    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, bool early_clobber,
+             machine_mode mode, bool subreg_p,
              alternative_mask early_clobber_alts,
              struct lra_insn_reg *next)
 {
@@ -550,7 +557,6 @@ new_insn_reg (rtx_insn *insn, int regno, enum op_type type,
       && partial_subreg_p (lra_reg_info[regno].biggest_mode, mode))
     lra_reg_info[regno].biggest_mode = mode;
   ir->subreg_p = subreg_p;
-  ir->early_clobber = early_clobber;
   ir->early_clobber_alts = early_clobber_alts;
   ir->regno = regno;
   ir->next = next;
@@ -598,13 +604,13 @@ static struct lra_operand_data debug_operand_data =
     0, /* early_clobber_alts */
     E_VOIDmode, /* We are not interesting in the operand mode.  */
     OP_IN,
-    0, 0, 0, 0
+    0, 0, 0
   };
 
 /* The following data are used as static insn data for all debug
-   insns.  If structure lra_static_insn_data is changed, the
+   bind insns.  If structure lra_static_insn_data is changed, the
    initializer should be changed too.  */
-static struct lra_static_insn_data debug_insn_static_data =
+static struct lra_static_insn_data debug_bind_static_data =
   {
     &debug_operand_data,
     0, /* Duplication operands #.  */
@@ -618,6 +624,22 @@ static struct lra_static_insn_data debug_insn_static_data =
     NULL  /* Descriptions of operands in alternatives. */
   };
 
+/* The following data are used as static insn data for all debug
+   marker insns.  If structure lra_static_insn_data is changed, the
+   initializer should be changed too.  */
+static struct lra_static_insn_data debug_marker_static_data =
+  {
+    &debug_operand_data,
+    0, /* Duplication operands #.  */
+    -1, /* Commutative operand #.  */
+    0, /* Operands #.  There isn't any operand.  */
+    0, /* Duplications #.  */
+    0, /* Alternatives #.  We are not interesting in alternatives
+          because we does not proceed debug_insns for reloads.  */
+    NULL, /* Hard registers referenced in machine description. */
+    NULL  /* Descriptions of operands in alternatives. */
+  };
+
 /* Called once per compiler work to initialize some LRA data related
    to insns.  */
 static void
@@ -634,7 +656,10 @@ finish_insn_code_data_once (void)
   for (unsigned int i = 0; i < NUM_INSN_CODES; i++)
     {
       if (insn_code_data[i] != NULL)
-       free (insn_code_data[i]);
+       {
+         free (insn_code_data[i]);
+         insn_code_data[i] = NULL;
+       }
     }
 }
 
@@ -695,6 +720,10 @@ int lra_insn_recog_data_len;
 /* Map INSN_UID -> the insn recog data (NULL if unknown).  */
 lra_insn_recog_data_t *lra_insn_recog_data;
 
+/* Alloc pool we allocate entries for lra_insn_recog_data from.  */
+static object_allocator<class lra_insn_recog_data>
+  lra_insn_recog_data_pool ("insn recog data pool");
+
 /* Initialize LRA data about insns.  */
 static void
 init_insn_recog_data (void)
@@ -740,7 +769,7 @@ free_insn_recog_data (lra_insn_recog_data_t data)
     }
   free_insn_regs (data->regs);
   data->regs = NULL;
-  free (data);
+  lra_insn_recog_data_pool.remove (data);
 }
 
 /* Pools for copies.  */
@@ -759,6 +788,7 @@ finish_insn_recog_data (void)
   finish_insn_regs ();
   lra_copy_pool.release ();
   lra_insn_reg_pool.release ();
+  lra_insn_recog_data_pool.release ();
   free (lra_insn_recog_data);
 }
 
@@ -778,7 +808,6 @@ setup_operand_alternative (lra_insn_recog_data_t data,
   for (i = 0; i < nop; i++)
     {
       static_data->operand[i].early_clobber_alts = 0;
-      static_data->operand[i].early_clobber = false;
       static_data->operand[i].is_address = false;
       if (static_data->operand[i].constraint[0] == '%')
        {
@@ -794,7 +823,6 @@ setup_operand_alternative (lra_insn_recog_data_t data,
   for (j = 0; j < nalt; j++)
     for (i = 0; i < nop; i++, op_alt++)
       {
-       static_data->operand[i].early_clobber |= op_alt->earlyclobber;
        if (op_alt->earlyclobber)
          static_data->operand[i].early_clobber_alts |= (alternative_mask) 1 << j;
        static_data->operand[i].is_address |= op_alt->is_address;
@@ -807,7 +835,8 @@ setup_operand_alternative (lra_insn_recog_data_t data,
    to LIST.  X is a part of insn given by DATA.         Return the result
    list.  */
 static struct lra_insn_reg *
-collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
+collect_non_operand_hard_regs (rtx_insn *insn, rtx *x,
+                              lra_insn_recog_data_t data,
                               struct lra_insn_reg *list,
                               enum op_type type, bool early_clobber)
 {
@@ -820,7 +849,8 @@ collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
   const char *fmt = GET_RTX_FORMAT (code);
 
   for (i = 0; i < data->insn_static_data->n_operands; i++)
-    if (x == data->operand_loc[i])
+    if (! data->insn_static_data->operand[i].is_operator
+       && x == data->operand_loc[i])
       /* It is an operand loc. Stop here.  */
       return list;
   for (i = 0; i < data->insn_static_data->n_dups; i++)
@@ -831,14 +861,11 @@ collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
   subreg_p = false;
   if (code == SUBREG)
     {
+      mode = wider_subreg_mode (op);
+      if (read_modify_subreg_p (op))
+       subreg_p = true;
       op = SUBREG_REG (op);
       code = GET_CODE (op);
-      if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (op)))
-       {
-         mode = GET_MODE (op);
-         if (GET_MODE_SIZE (mode) > REGMODE_NATURAL_SIZE (mode))
-           subreg_p = true;
-       }
     }
   if (REG_P (op))
     {
@@ -846,9 +873,7 @@ collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
        return list;
       /* Process all regs even unallocatable ones as we need info
         about all regs for rematerialization pass.  */
-      for (last = regno + hard_regno_nregs[regno][mode];
-          regno < last;
-          regno++)
+      for (last = end_hard_regno (mode, regno); regno < last; regno++)
        {
          for (curr = list; curr != NULL; curr = curr->next)
            if (curr->regno == regno && curr->subreg_p == subreg_p
@@ -857,15 +882,12 @@ collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
                if (curr->type != type)
                  curr->type = OP_INOUT;
                if (early_clobber)
-                 {
-                   curr->early_clobber = true;
-                   curr->early_clobber_alts = ALL_ALTERNATIVES;
-                 }
+                 curr->early_clobber_alts = ALL_ALTERNATIVES;
                break;
              }
          if (curr == NULL)
            {
-             /* This is a new hard regno or the info can not be
+             /* This is a new hard regno or the info cannot be
                 integrated into the found structure.    */
 #ifdef STACK_REGS
              early_clobber
@@ -876,7 +898,6 @@ collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
                         && regno <= LAST_STACK_REG));
 #endif
              list = new_insn_reg (data->insn, regno, type, mode, subreg_p,
-                                  early_clobber,
                                   early_clobber ? ALL_ALTERNATIVES : 0, list);
            }
        }
@@ -885,25 +906,24 @@ collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
   switch (code)
     {
     case SET:
-      list = collect_non_operand_hard_regs (&SET_DEST (op), data,
+      list = collect_non_operand_hard_regs (insn, &SET_DEST (op), data,
                                            list, OP_OUT, false);
-      list = collect_non_operand_hard_regs (&SET_SRC (op), data,
+      list = collect_non_operand_hard_regs (insn, &SET_SRC (op), data,
                                            list, OP_IN, false);
       break;
     case CLOBBER:
-      /* We treat clobber of non-operand hard registers as early
-        clobber (the behavior is expected from asm).  */
-      list = collect_non_operand_hard_regs (&XEXP (op, 0), data,
+      /* We treat clobber of non-operand hard registers as early clobber.  */
+      list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
                                            list, OP_OUT, true);
       break;
     case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC:
-      list = collect_non_operand_hard_regs (&XEXP (op, 0), data,
+      list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
                                            list, OP_INOUT, false);
       break;
     case PRE_MODIFY: case POST_MODIFY:
-      list = collect_non_operand_hard_regs (&XEXP (op, 0), data,
+      list = collect_non_operand_hard_regs (insn, &XEXP (op, 0), data,
                                            list, OP_INOUT, false);
-      list = collect_non_operand_hard_regs (&XEXP (op, 1), data,
+      list = collect_non_operand_hard_regs (insn, &XEXP (op, 1), data,
                                            list, OP_IN, false);
       break;
     default:
@@ -911,12 +931,12 @@ collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
        {
          if (fmt[i] == 'e')
-           list = collect_non_operand_hard_regs (&XEXP (op, i), data,
+           list = collect_non_operand_hard_regs (insn, &XEXP (op, i), data,
                                                  list, OP_IN, false);
          else if (fmt[i] == 'E')
            for (j = XVECLEN (op, i) - 1; j >= 0; j--)
-             list = collect_non_operand_hard_regs (&XVECEXP (op, i, j), data,
-                                                   list, OP_IN, false);
+             list = collect_non_operand_hard_regs (insn, &XVECEXP (op, i, j),
+                                                   data, list, OP_IN, false);
        }
     }
   return list;
@@ -943,20 +963,28 @@ lra_set_insn_recog_data (rtx_insn *insn)
        /* It might be a new simple insn which is not recognized yet.  */
        INSN_CODE (insn) = icode = recog_memoized (insn);
     }
-  data = XNEW (struct lra_insn_recog_data);
+  data = lra_insn_recog_data_pool.allocate ();
   lra_insn_recog_data[uid] = data;
   data->insn = insn;
-  data->used_insn_alternative = -1;
+  data->used_insn_alternative = LRA_UNKNOWN_ALT;
   data->icode = icode;
   data->regs = NULL;
   if (DEBUG_INSN_P (insn))
     {
-      data->insn_static_data = &debug_insn_static_data;
       data->dup_loc = NULL;
       data->arg_hard_regs = NULL;
       data->preferred_alternatives = ALL_ALTERNATIVES;
-      data->operand_loc = XNEWVEC (rtx *, 1);
-      data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+      if (DEBUG_BIND_INSN_P (insn))
+       {
+         data->insn_static_data = &debug_bind_static_data;
+         data->operand_loc = XNEWVEC (rtx *, 1);
+         data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
+       }
+      else if (DEBUG_MARKER_INSN_P (insn))
+       {
+         data->insn_static_data = &debug_marker_static_data;
+         data->operand_loc = NULL;
+       }
       return data;
     }
   if (icode < 0)
@@ -992,12 +1020,8 @@ lra_set_insn_recog_data (rtx_insn *insn)
                               data->operand_loc,
                               constraints, operand_mode, NULL);
          if (nop > 0)
-           {
-             const char *p =  recog_data.constraints[0];
-
-             for (p =  constraints[0]; *p; p++)
-               nalt += *p == ',';
-           }
+           for (const char *p =constraints[0]; *p; p++)
+             nalt += *p == ',';
          data->insn_static_data = insn_static_data
            = get_static_insn_data (-1, nop, 0, nalt);
          for (i = 0; i < nop; i++)
@@ -1019,7 +1043,8 @@ lra_set_insn_recog_data (rtx_insn *insn)
        {
          operand_alternative *op_alt = XCNEWVEC (operand_alternative,
                                                  nalt * nop);
-         preprocess_constraints (nop, nalt, constraints, op_alt);
+         preprocess_constraints (nop, nalt, constraints, op_alt,
+                                 data->operand_loc);
          setup_operand_alternative (data, op_alt);
        }
     }
@@ -1059,7 +1084,7 @@ lra_set_insn_recog_data (rtx_insn *insn)
     insn_static_data->hard_regs = NULL;
   else
     insn_static_data->hard_regs
-      = collect_non_operand_hard_regs (&PATTERN (insn), data,
+      = collect_non_operand_hard_regs (insn, &PATTERN (insn), data,
                                       NULL, OP_IN, false);
   data->arg_hard_regs = NULL;
   if (CALL_P (insn))
@@ -1086,6 +1111,7 @@ lra_set_insn_recog_data (rtx_insn *insn)
              arg_hard_regs[n_hard_regs++]
                = regno + i + (use_p ? 0 : FIRST_PSEUDO_REGISTER);
          }
+
       if (n_hard_regs != 0)
        {
          arg_hard_regs[n_hard_regs++] = -1;
@@ -1168,7 +1194,7 @@ lra_update_insn_recog_data (rtx_insn *insn)
   int n;
   unsigned int uid = INSN_UID (insn);
   struct lra_static_insn_data *insn_static_data;
-  HOST_WIDE_INT sp_offset = 0;
+  poly_int64 sp_offset = 0;
 
   check_and_expand_insn_recog_data (uid);
   if ((data = lra_insn_recog_data[uid]) != NULL
@@ -1187,7 +1213,7 @@ lra_update_insn_recog_data (rtx_insn *insn)
       return data;
     }
   insn_static_data = data->insn_static_data;
-  data->used_insn_alternative = -1;
+  data->used_insn_alternative = LRA_UNKNOWN_ALT;
   if (DEBUG_INSN_P (insn))
     return data;
   if (data->icode < 0)
@@ -1267,7 +1293,9 @@ lra_set_used_insn_alternative_by_uid (int uid, int alt)
 /* The size of the following array.  */
 static int reg_info_size;
 /* Common info about each register.  */
-struct lra_reg *lra_reg_info;
+class lra_reg *lra_reg_info;
+
+HARD_REG_SET hard_regs_spilled_into;
 
 /* Last register value.         */
 static int last_reg_value;
@@ -1291,7 +1319,6 @@ initialize_lra_reg_info_element (int i)
   lra_reg_info[i].no_stack_p = false;
 #endif
   CLEAR_HARD_REG_SET (lra_reg_info[i].conflict_hard_regs);
-  CLEAR_HARD_REG_SET (lra_reg_info[i].actual_call_used_reg_set);
   lra_reg_info[i].preferred_hard_regno1 = -1;
   lra_reg_info[i].preferred_hard_regno2 = -1;
   lra_reg_info[i].preferred_hard_regno_profit1 = 0;
@@ -1314,10 +1341,11 @@ init_reg_info (void)
 
   last_reg_value = 0;
   reg_info_size = max_reg_num () * 3 / 2 + 1;
-  lra_reg_info = XNEWVEC (struct lra_reg, reg_info_size);
+  lra_reg_info = XNEWVEC (class lra_reg, reg_info_size);
   for (i = 0; i < reg_info_size; i++)
     initialize_lra_reg_info_element (i);
   copy_vec.truncate (0);
+  CLEAR_HARD_REG_SET (hard_regs_spilled_into);
 }
 
 
@@ -1342,7 +1370,7 @@ expand_reg_info (void)
   if (reg_info_size > max_reg_num ())
     return;
   reg_info_size = max_reg_num () * 3 / 2 + 1;
-  lra_reg_info = XRESIZEVEC (struct lra_reg, lra_reg_info, reg_info_size);
+  lra_reg_info = XRESIZEVEC (class lra_reg, lra_reg_info, reg_info_size);
   for (i = old; i < reg_info_size; i++)
     initialize_lra_reg_info_element (i);
 }
@@ -1406,14 +1434,13 @@ lra_get_copy (int n)
 /* This page contains code dealing with info about registers in
    insns.  */
 
-/* Process X of insn UID recursively and add info (operand type is
-   given by TYPE, flag of that it is early clobber is EARLY_CLOBBER)
-   about registers in X to the insn DATA.  If X can be early clobbered,
-   alternatives in which it can be early clobbered are given by
-   EARLY_CLOBBER_ALTS.  */
+/* Process X of INSN recursively and add info (operand type is given
+   by TYPE) about registers in X to the insn DATA.  If X can be early
+   clobbered, alternatives in which it can be early clobbered are given
+   by EARLY_CLOBBER_ALTS.  */
 static void
-add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
-                            enum op_type type, bool early_clobber,
+add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x,
+                            rtx_insn *insn, enum op_type type,
                             alternative_mask early_clobber_alts)
 {
   int i, j, regno;
@@ -1428,14 +1455,11 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
   subreg_p = false;
   if (GET_CODE (x) == SUBREG)
     {
+      mode = wider_subreg_mode (x);
+      if (read_modify_subreg_p (x))
+       subreg_p = true;
       x = SUBREG_REG (x);
       code = GET_CODE (x);
-      if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x)))
-       {
-         mode = GET_MODE (x);
-         if (GET_MODE_SIZE (mode) > REGMODE_NATURAL_SIZE (mode))
-           subreg_p = true;
-       }
     }
   if (REG_P (x))
     {
@@ -1443,11 +1467,10 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
       /* Process all regs even unallocatable ones as we need info about
         all regs for rematerialization pass.  */
       expand_reg_info ();
-      if (bitmap_set_bit (&lra_reg_info[regno].insn_bitmap, uid))
+      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,
-                                    early_clobber, early_clobber_alts,
-                                    data->regs);
+                                    early_clobber_alts, data->regs);
          return;
        }
       else
@@ -1456,17 +1479,15 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
            if (curr->regno == regno)
              {
                if (curr->subreg_p != subreg_p || curr->biggest_mode != mode)
-                 /* The info can not be integrated into the found
+                 /* The info cannot be integrated into the found
                     structure.  */
                  data->regs = new_insn_reg (data->insn, regno, type, mode,
-                                            subreg_p, early_clobber,
-                                            early_clobber_alts, data->regs);
+                                            subreg_p, early_clobber_alts,
+                                            data->regs);
                else
                  {
                    if (curr->type != type)
                      curr->type = OP_INOUT;
-                   if (curr->early_clobber != early_clobber)
-                     curr->early_clobber = true;
                    curr->early_clobber_alts |= early_clobber_alts;
                  }
                return;
@@ -1478,20 +1499,21 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
   switch (code)
     {
     case SET:
-      add_regs_to_insn_regno_info (data, SET_DEST (x), uid, OP_OUT, false, 0);
-      add_regs_to_insn_regno_info (data, SET_SRC (x), uid, OP_IN, false, 0);
+      add_regs_to_insn_regno_info (data, SET_DEST (x), insn, OP_OUT, 0);
+      add_regs_to_insn_regno_info (data, SET_SRC (x), insn, OP_IN, 0);
       break;
     case CLOBBER:
       /* We treat clobber of non-operand hard registers as early
-        clobber (the behavior is expected from asm).  */
-      add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_OUT, true, ALL_ALTERNATIVES);
+        clobber.  */
+      add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_OUT,
+                                  ALL_ALTERNATIVES);
       break;
     case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC:
-      add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false, 0);
+      add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_INOUT, 0);
       break;
     case PRE_MODIFY: case POST_MODIFY:
-      add_regs_to_insn_regno_info (data, XEXP (x, 0), uid, OP_INOUT, false, 0);
-      add_regs_to_insn_regno_info (data, XEXP (x, 1), uid, OP_IN, false, 0);
+      add_regs_to_insn_regno_info (data, XEXP (x, 0), insn, OP_INOUT, 0);
+      add_regs_to_insn_regno_info (data, XEXP (x, 1), insn, OP_IN, 0);
       break;
     default:
       if ((code != PARALLEL && code != EXPR_LIST) || type != OP_OUT)
@@ -1512,12 +1534,12 @@ add_regs_to_insn_regno_info (lra_insn_recog_data_t data, rtx x, int uid,
       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
        {
          if (fmt[i] == 'e')
-           add_regs_to_insn_regno_info (data, XEXP (x, i), uid, type, false, 0);
+           add_regs_to_insn_regno_info (data, XEXP (x, i), insn, type, 0);
          else if (fmt[i] == 'E')
            {
              for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-               add_regs_to_insn_regno_info (data, XVECEXP (x, i, j), uid,
-                                            type, false, 0);
+               add_regs_to_insn_regno_info (data, XVECEXP (x, i, j), insn,
+                                            type, 0);
            }
        }
     }
@@ -1592,7 +1614,7 @@ setup_insn_reg_info (lra_insn_recog_data_t data, int freq)
 void
 lra_update_insn_regno_info (rtx_insn *insn)
 {
-  int i, uid, freq;
+  int i, freq;
   lra_insn_recog_data_t data;
   struct lra_static_insn_data *static_data;
   enum rtx_code code;
@@ -1602,17 +1624,15 @@ lra_update_insn_regno_info (rtx_insn *insn)
     return;
   data = lra_get_insn_recog_data (insn);
   static_data = data->insn_static_data;
-  freq = get_insn_freq (insn);
+  freq = NONDEBUG_INSN_P (insn) ? get_insn_freq (insn) : 0;
   invalidate_insn_data_regno_info (data, insn, freq);
-  uid = INSN_UID (insn);
   for (i = static_data->n_operands - 1; i >= 0; i--)
-    add_regs_to_insn_regno_info (data, *data->operand_loc[i], uid,
+    add_regs_to_insn_regno_info (data, *data->operand_loc[i], insn,
                                 static_data->operand[i].type,
-                                static_data->operand[i].early_clobber,
                                 static_data->operand[i].early_clobber_alts);
   if ((code = GET_CODE (PATTERN (insn))) == CLOBBER || code == USE)
-    add_regs_to_insn_regno_info (data, XEXP (PATTERN (insn), 0), uid,
-                                code == USE ? OP_IN : OP_OUT, false, 0);
+    add_regs_to_insn_regno_info (data, XEXP (PATTERN (insn), 0), insn,
+                                code == USE ? OP_IN : OP_OUT, 0);
   if (CALL_P (insn))
     /* On some targets call insns can refer to pseudos in memory in
        CALL_INSN_FUNCTION_USAGE list.  Process them in order to
@@ -1621,10 +1641,13 @@ lra_update_insn_regno_info (rtx_insn *insn)
     for (link = CALL_INSN_FUNCTION_USAGE (insn);
         link != NULL_RTX;
         link = XEXP (link, 1))
-      if (((code = GET_CODE (XEXP (link, 0))) == USE || code == CLOBBER)
-         && MEM_P (XEXP (XEXP (link, 0), 0)))
-       add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), uid,
-                                    code == USE ? OP_IN : OP_OUT, false, 0);
+      {
+       code = GET_CODE (XEXP (link, 0));
+       if ((code == USE || code == CLOBBER)
+           && MEM_P (XEXP (XEXP (link, 0), 0)))
+         add_regs_to_insn_regno_info (data, XEXP (XEXP (link, 0), 0), insn,
+                                      code == USE ? OP_IN : OP_OUT, 0);
+      }
   if (NONDEBUG_INSN_P (insn))
     setup_insn_reg_info (data, freq);
 }
@@ -1670,10 +1693,12 @@ lra_rtx_hash (rtx x)
 
     case SCRATCH:
     case CONST_DOUBLE:
-    case CONST_INT:
     case CONST_VECTOR:
       return val;
 
+    case CONST_INT:
+      return val + UINTVAL (x);
+
     default:
       break;
     }
@@ -1812,9 +1837,9 @@ push_insns (rtx_insn *from, rtx_insn *to)
 static void
 setup_sp_offset (rtx_insn *from, rtx_insn *last)
 {
-  rtx_insn *before = next_nonnote_insn_bb (last);
-  HOST_WIDE_INT offset = (before == NULL_RTX || ! INSN_P (before)
-                         ? 0 : lra_get_insn_recog_data (before)->sp_offset);
+  rtx_insn *before = next_nonnote_nondebug_insn_bb (last);
+  poly_int64 offset = (before == NULL_RTX || ! INSN_P (before)
+                      ? 0 : lra_get_insn_recog_data (before)->sp_offset);
 
   for (rtx_insn *insn = from; insn != NEXT_INSN (last); insn = NEXT_INSN (insn))
     lra_get_insn_recog_data (insn)->sp_offset = offset;
@@ -1827,8 +1852,6 @@ void
 lra_process_new_insns (rtx_insn *insn, rtx_insn *before, rtx_insn *after,
                       const char *title)
 {
-  rtx_insn *last;
-
   if (before == NULL_RTX && after == NULL_RTX)
     return;
   if (lra_dump_file != NULL)
@@ -1839,12 +1862,6 @@ lra_process_new_insns (rtx_insn *insn, rtx_insn *before, rtx_insn *after,
          fprintf (lra_dump_file,"    %s before:\n", title);
          dump_rtl_slim (lra_dump_file, before, NULL, -1, 0);
        }
-      if (after != NULL_RTX)
-       {
-         fprintf (lra_dump_file, "    %s after:\n", title);
-         dump_rtl_slim (lra_dump_file, after, NULL, -1, 0);
-       }
-      fprintf (lra_dump_file, "\n");
     }
   if (before != NULL_RTX)
     {
@@ -1858,12 +1875,69 @@ lra_process_new_insns (rtx_insn *insn, rtx_insn *before, rtx_insn *after,
     {
       if (cfun->can_throw_non_call_exceptions)
        copy_reg_eh_region_note_forward (insn, after, NULL);
-      for (last = after; NEXT_INSN (last) != NULL_RTX; last = NEXT_INSN (last))
-       ;
-      emit_insn_after (after, insn);
-      push_insns (last, insn);
-      setup_sp_offset (after, last);
+      if (! JUMP_P (insn))
+       {
+         rtx_insn *last;
+         
+         if (lra_dump_file != NULL)
+           {
+             fprintf (lra_dump_file, "    %s after:\n", title);
+             dump_rtl_slim (lra_dump_file, after, NULL, -1, 0);
+           }
+         for (last = after;
+              NEXT_INSN (last) != NULL_RTX;
+              last = NEXT_INSN (last))
+           ;
+         emit_insn_after (after, insn);
+         push_insns (last, insn);
+         setup_sp_offset (after, last);
+       }
+      else
+       {
+         /* Put output reload insns on successor BBs: */
+         edge_iterator ei;
+         edge e;
+         
+         FOR_EACH_EDGE (e, ei, BLOCK_FOR_INSN (insn)->succs)
+           if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
+             {
+               /* We already made the edge no-critical in ira.c::ira */
+               lra_assert (!EDGE_CRITICAL_P (e));
+               rtx_insn *curr, *tmp = BB_HEAD (e->dest);
+               if (LABEL_P (tmp))
+                 tmp = NEXT_INSN (tmp);
+               if (NOTE_INSN_BASIC_BLOCK_P (tmp))
+                 tmp = NEXT_INSN (tmp);
+               /* Do not put reload insns if it is the last BB
+                  without actual insns.  */
+               if (tmp == NULL)
+                 continue;
+               start_sequence ();
+               for (curr = after; curr != NULL_RTX; curr = NEXT_INSN (curr))
+                 emit_insn (copy_insn (PATTERN (curr)));
+               rtx_insn *copy = get_insns (), *last = get_last_insn ();
+               end_sequence ();
+               if (lra_dump_file != NULL)
+                 {
+                   fprintf (lra_dump_file, "    %s after in bb%d:\n", title,
+                            e->dest->index);
+                   dump_rtl_slim (lra_dump_file, copy, NULL, -1, 0);
+                 }
+               /* Use the right emit func for setting up BB_END/BB_HEAD: */
+               if (BB_END (e->dest) == PREV_INSN (tmp))
+                 emit_insn_after_noloc (copy, PREV_INSN (tmp), e->dest);
+               else
+                 emit_insn_before_noloc (copy, tmp, e->dest);
+               push_insns (last, PREV_INSN (copy));
+               setup_sp_offset (copy, last);
+               /* We can ignore BB live info here as it and reg notes
+                  will be updated before the next assignment
+                  sub-pass. */
+             }
+       }
     }
+  if (lra_dump_file != NULL)
+    fprintf (lra_dump_file, "\n");
   if (cfun->can_throw_non_call_exceptions)
     {
       rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
@@ -1875,9 +1949,11 @@ lra_process_new_insns (rtx_insn *insn, rtx_insn *before, rtx_insn *after,
 
 /* Replace all references to register OLD_REGNO in *LOC with pseudo
    register NEW_REG.  Try to simplify subreg of constant if SUBREG_P.
-   Return true if any change was made.  */
+   DEBUG_P is if LOC is within a DEBUG_INSN.  Return true if any
+   change was made.  */
 bool
-lra_substitute_pseudo (rtx *loc, int old_regno, rtx new_reg, bool subreg_p)
+lra_substitute_pseudo (rtx *loc, int old_regno, rtx new_reg, bool subreg_p,
+                      bool debug_p)
 {
   rtx x = *loc;
   bool result = false;
@@ -1911,13 +1987,16 @@ lra_substitute_pseudo (rtx *loc, int old_regno, rtx new_reg, bool subreg_p)
       machine_mode inner_mode = GET_MODE (new_reg);
 
       if (mode != inner_mode
-         && ! (CONST_INT_P (new_reg) && SCALAR_INT_MODE_P (mode)))
+         && ! (CONST_SCALAR_INT_P (new_reg) && SCALAR_INT_MODE_P (mode)))
        {
-         if (!partial_subreg_p (mode, inner_mode)
-             || ! SCALAR_INT_MODE_P (inner_mode))
-           new_reg = gen_rtx_SUBREG (mode, new_reg, 0);
+         poly_uint64 offset = 0;
+         if (partial_subreg_p (mode, inner_mode)
+             && SCALAR_INT_MODE_P (inner_mode))
+           offset = subreg_lowpart_offset (mode, inner_mode);
+         if (debug_p)
+           new_reg = gen_rtx_raw_SUBREG (mode, new_reg, offset);
          else
-           new_reg = gen_lowpart_SUBREG (mode, new_reg);
+           new_reg = gen_rtx_SUBREG (mode, new_reg, offset);
        }
       *loc = new_reg;
       return true;
@@ -1930,14 +2009,14 @@ lra_substitute_pseudo (rtx *loc, int old_regno, rtx new_reg, bool subreg_p)
       if (fmt[i] == 'e')
        {
          if (lra_substitute_pseudo (&XEXP (x, i), old_regno,
-                                    new_reg, subreg_p))
+                                    new_reg, subreg_p, debug_p))
            result = true;
        }
       else if (fmt[i] == 'E')
        {
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            if (lra_substitute_pseudo (&XVECEXP (x, i, j), old_regno,
-                                      new_reg, subreg_p))
+                                      new_reg, subreg_p, debug_p))
              result = true;
        }
     }
@@ -1952,161 +2031,41 @@ lra_substitute_pseudo_within_insn (rtx_insn *insn, int old_regno,
                                   rtx new_reg, bool subreg_p)
 {
   rtx loc = insn;
-  return lra_substitute_pseudo (&loc, old_regno, new_reg, subreg_p);
+  return lra_substitute_pseudo (&loc, old_regno, new_reg, subreg_p,
+                               DEBUG_INSN_P (insn));
 }
 
 \f
 
-/* This page contains code dealing with scratches (changing them onto
-   pseudos and restoring them from the pseudos).
-
-   We change scratches into pseudos at the beginning of LRA to
-   simplify dealing with them (conflicts, hard register assignments).
-
-   If the pseudo denoting scratch was spilled it means that we do need
-   a hard register for it.  Such pseudos are transformed back to
-   scratches at the end of LRA.         */
-
-/* Description of location of a former scratch operand.         */
-struct sloc
-{
-  rtx_insn *insn; /* Insn where the scratch was.  */
-  int nop;  /* Number of the operand which was a scratch.  */
-};
-
-typedef struct sloc *sloc_t;
-
-/* Locations of the former scratches.  */
-static vec<sloc_t> scratches;
-
-/* Bitmap of scratch regnos.  */
-static bitmap_head scratch_bitmap;
-
-/* Bitmap of scratch operands. */
-static bitmap_head scratch_operand_bitmap;
-
-/* Return true if pseudo REGNO is made of SCRATCH.  */
-bool
-lra_former_scratch_p (int regno)
+/* Return new register of the same mode as ORIGINAL of class ALL_REGS.
+   Used in ira_remove_scratches.  */
+static rtx
+get_scratch_reg (rtx original)
 {
-  return bitmap_bit_p (&scratch_bitmap, regno);
+  return lra_create_new_reg (GET_MODE (original), original, ALL_REGS, NULL);
 }
 
-/* Return true if the operand NOP of INSN is a former scratch. */
-bool
-lra_former_scratch_operand_p (rtx_insn *insn, int nop)
+/* Remove all insn scratches in INSN.  */
+static void
+remove_insn_scratches (rtx_insn *insn)
 {
-  return bitmap_bit_p (&scratch_operand_bitmap,
-                      INSN_UID (insn) * MAX_RECOG_OPERANDS + nop) != 0;
+  if (ira_remove_insn_scratches (insn, true, lra_dump_file, get_scratch_reg))
+    df_insn_rescan (insn);
 }
 
-/* Register operand NOP in INSN as a former scratch.  It will be
-   changed to scratch back, if it is necessary, at the LRA end.  */
-void
-lra_register_new_scratch_op (rtx_insn *insn, int nop)
-{
-  lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
-  rtx op = *id->operand_loc[nop];
-  sloc_t loc = XNEW (struct sloc);
-  lra_assert (REG_P (op));
-  loc->insn = insn;
-  loc->nop = nop;
-  scratches.safe_push (loc);
-  bitmap_set_bit (&scratch_bitmap, REGNO (op));
-  bitmap_set_bit (&scratch_operand_bitmap,
-                 INSN_UID (insn) * MAX_RECOG_OPERANDS + nop);
-  add_reg_note (insn, REG_UNUSED, op);
-}
-
-/* Change scratches onto pseudos and save their location.  */
+/* Remove all insn scratches in the current function.  */
 static void
 remove_scratches (void)
 {
-  int i;
-  bool insn_changed_p;
   basic_block bb;
   rtx_insn *insn;
-  rtx reg;
-  lra_insn_recog_data_t id;
-  struct lra_static_insn_data *static_id;
 
-  scratches.create (get_max_uid ());
-  bitmap_initialize (&scratch_bitmap, &reg_obstack);
-  bitmap_initialize (&scratch_operand_bitmap, &reg_obstack);
   FOR_EACH_BB_FN (bb, cfun)
     FOR_BB_INSNS (bb, insn)
-    if (INSN_P (insn))
-      {
-       id = lra_get_insn_recog_data (insn);
-       static_id = id->insn_static_data;
-       insn_changed_p = false;
-       for (i = 0; i < static_id->n_operands; i++)
-         if (GET_CODE (*id->operand_loc[i]) == SCRATCH
-             && GET_MODE (*id->operand_loc[i]) != VOIDmode)
-           {
-             insn_changed_p = true;
-             *id->operand_loc[i] = reg
-               = lra_create_new_reg (static_id->operand[i].mode,
-                                     *id->operand_loc[i], ALL_REGS, NULL);
-             lra_register_new_scratch_op (insn, i);
-             if (lra_dump_file != NULL)
-               fprintf (lra_dump_file,
-                        "Removing SCRATCH in insn #%u (nop %d)\n",
-                        INSN_UID (insn), i);
-           }
-       if (insn_changed_p)
-         /* Because we might use DF right after caller-saves sub-pass
-            we need to keep DF info up to date.  */
-         df_insn_rescan (insn);
-      }
-}
-
-/* Changes pseudos created by function remove_scratches onto scratches.         */
-static void
-restore_scratches (void)
-{
-  int regno;
-  unsigned i;
-  sloc_t loc;
-  rtx_insn *last = NULL;
-  lra_insn_recog_data_t id = NULL;
-
-  for (i = 0; scratches.iterate (i, &loc); i++)
-    {
-      /* Ignore already deleted insns.  */
-      if (NOTE_P (loc->insn)
-         && NOTE_KIND (loc->insn) == NOTE_INSN_DELETED)
-       continue;
-      if (last != loc->insn)
-       {
-         last = loc->insn;
-         id = lra_get_insn_recog_data (last);
-       }
-      if (REG_P (*id->operand_loc[loc->nop])
-         && ((regno = REGNO (*id->operand_loc[loc->nop]))
-             >= FIRST_PSEUDO_REGISTER)
-         && lra_get_regno_hard_regno (regno) < 0)
-       {
-         /* It should be only case when scratch register with chosen
-            constraint 'X' did not get memory or hard register.  */
-         lra_assert (lra_former_scratch_p (regno));
-         *id->operand_loc[loc->nop]
-           = gen_rtx_SCRATCH (GET_MODE (*id->operand_loc[loc->nop]));
-         lra_update_dup (id, loc->nop);
-         if (lra_dump_file != NULL)
-           fprintf (lra_dump_file, "Restoring SCRATCH in insn #%u(nop %d)\n",
-                    INSN_UID (loc->insn), loc->nop);
-       }
-    }
-  for (i = 0; scratches.iterate (i, &loc); i++)
-    free (loc);
-  scratches.release ();
-  bitmap_clear (&scratch_bitmap);
-  bitmap_clear (&scratch_operand_bitmap);
+      if (INSN_P (insn))
+        remove_insn_scratches (insn);
 }
 
-\f
-
 /* Function checks RTL for correctness.         If FINAL_P is true, it is
    done at the end of LRA and the check is more rigorous.  */
 static void
@@ -2189,34 +2148,6 @@ has_nonexceptional_receiver (void)
   return false;
 }
 
-
-/* Process recursively X of INSN and add REG_INC notes if necessary.  */
-static void
-add_auto_inc_notes (rtx_insn *insn, rtx x)
-{
-  enum rtx_code code = GET_CODE (x);
-  const char *fmt;
-  int i, j;
-
-  if (code == MEM && auto_inc_p (XEXP (x, 0)))
-    {
-      add_reg_note (insn, REG_INC, XEXP (XEXP (x, 0), 0));
-      return;
-    }
-
-  /* Scan all X sub-expressions.  */
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      if (fmt[i] == 'e')
-       add_auto_inc_notes (insn, XEXP (x, i));
-      else if (fmt[i] == 'E')
-       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-         add_auto_inc_notes (insn, XVECEXP (x, i, j));
-    }
-}
-
-
 /* Remove all REG_DEAD and REG_UNUSED notes and regenerate REG_INC.
    We change pseudos by hard registers without notification of DF and
    that can make the notes obsolete.  DF-infrastructure does not deal
@@ -2261,6 +2192,9 @@ int lra_constraint_new_regno_start;
    it is possible.  */
 int lra_bad_spill_regno_start;
 
+/* A pseudo of Pmode.  */
+rtx lra_pmode_pseudo;
+
 /* Inheritance pseudo regnos before the new spill pass.         */
 bitmap_head lra_inheritance_pseudos;
 
@@ -2280,6 +2214,12 @@ bitmap_head lra_subreg_reload_pseudos;
 /* File used for output of LRA debug information.  */
 FILE *lra_dump_file;
 
+/* True if we split hard reg after the last constraint sub-pass.  */
+bool lra_hard_reg_split_p;
+
+/* True if we found an asm error.  */
+bool lra_asm_error_p;
+
 /* True if we should try spill into registers of different classes
    instead of memory.  */
 bool lra_reg_spill_p;
@@ -2317,14 +2257,16 @@ lra (FILE *f)
   bool live_p, inserted_p;
 
   lra_dump_file = f;
-
+  lra_asm_error_p = false;
+  lra_pmode_pseudo = gen_reg_rtx (Pmode);
+  
   timevar_push (TV_LRA);
 
   /* Make sure that the last insn is a note.  Some subsequent passes
      need it.  */
   emit_note (NOTE_INSN_DELETED);
 
-  COPY_HARD_REG_SET (lra_no_alloc_regs, ira_no_alloc_regs);
+  lra_no_alloc_regs = ira_no_alloc_regs;
 
   init_reg_info ();
   expand_reg_info ();
@@ -2360,7 +2302,9 @@ lra (FILE *f)
 
   if (crtl->saves_all_registers)
     for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-      if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i))
+      if (!crtl->abi->clobbers_full_reg_p (i)
+         && !fixed_regs[i]
+         && !LOCAL_REGNO (i))
        df_set_regs_ever_live (i, true);
 
   /* We don't DF from now and avoid its using because it is to
@@ -2379,7 +2323,7 @@ lra (FILE *f)
   bitmap_initialize (&lra_optional_reload_pseudos, &reg_obstack);
   bitmap_initialize (&lra_subreg_reload_pseudos, &reg_obstack);
   live_p = false;
-  if (get_frame_size () != 0 && crtl->stack_alignment_needed)
+  if (maybe_ne (get_frame_size (), 0) && crtl->stack_alignment_needed)
     /* If we have a stack frame, we must align it now.  The stack size
        may be a part of the offset computation for register
        elimination.  */
@@ -2418,53 +2362,64 @@ lra (FILE *f)
            }
          /* Do inheritance only for regular algorithms.  */
          if (! lra_simple_p)
-           {
-             if (flag_ipa_ra)
-               {
-                 if (live_p)
-                   lra_clear_live_ranges ();
-                 /* As a side-effect of lra_create_live_ranges, we calculate
-                    actual_call_used_reg_set,  which is needed during
-                    lra_inheritance.  */
-                 lra_create_live_ranges (true, true);
-                 live_p = true;
-               }
-             lra_inheritance ();
-           }
+           lra_inheritance ();
          if (live_p)
            lra_clear_live_ranges ();
-         /* We need live ranges for lra_assign -- so build them.  But
-            don't remove dead insns or change global live info as we
-            can undo inheritance transformations after inheritance
-            pseudo assigning.  */
-         lra_create_live_ranges (true, false);
-         live_p = true;
-         /* If we don't spill non-reload and non-inheritance pseudos,
-            there is no sense to run memory-memory move coalescing.
-            If inheritance pseudos were spilled, the memory-memory
-            moves involving them will be removed by pass undoing
-            inheritance.  */
-         if (lra_simple_p)
-           lra_assign ();
-         else
+         bool fails_p;
+         lra_hard_reg_split_p = false;
+         do
            {
-             bool spill_p = !lra_assign ();
-
-             if (lra_undo_inheritance ())
-               live_p = false;
-             if (spill_p)
+             /* We need live ranges for lra_assign -- so build them.
+                But don't remove dead insns or change global live
+                info as we can undo inheritance transformations after
+                inheritance pseudo assigning.  */
+             lra_create_live_ranges (true, !lra_simple_p);
+             live_p = true;
+             /* If we don't spill non-reload and non-inheritance
+                pseudos, there is no sense to run memory-memory move
+                coalescing.  If inheritance pseudos were spilled, the
+                memory-memory moves involving them will be removed by
+                pass undoing inheritance.  */
+             if (lra_simple_p)
+               lra_assign (fails_p);
+             else
                {
-                 if (! live_p)
+                 bool spill_p = !lra_assign (fails_p);
+                 
+                 if (lra_undo_inheritance ())
+                   live_p = false;
+                 if (spill_p && ! fails_p)
                    {
-                     lra_create_live_ranges (true, true);
-                     live_p = true;
+                     if (! live_p)
+                       {
+                         lra_create_live_ranges (true, true);
+                         live_p = true;
+                       }
+                     if (lra_coalesce ())
+                       live_p = false;
                    }
-                 if (lra_coalesce ())
-                   live_p = false;
+                 if (! live_p)
+                   lra_clear_live_ranges ();
+               }
+             if (fails_p)
+               {
+                 /* It is a very rare case.  It is the last hope to
+                    split a hard regno live range for a reload
+                    pseudo.  */
+                 if (live_p)
+                   lra_clear_live_ranges ();
+                 live_p = false;
+                 if (! lra_split_hard_reg_for ())
+                   break;
+                 lra_hard_reg_split_p = true;
                }
-             if (! live_p)
-               lra_clear_live_ranges ();
            }
+         while (fails_p);
+         if (! live_p) {
+           /* We need the correct reg notes for work of constraint sub-pass.  */
+           lra_create_live_ranges (true, true);
+           live_p = true;
+         }
        }
       /* Don't clear optional reloads bitmap until all constraints are
         satisfied as we need to differ them from regular reloads.  */
@@ -2491,7 +2446,11 @@ lra (FILE *f)
          lra_create_live_ranges (lra_reg_spill_p, true);
          live_p = true;
          if (! lra_need_for_spills_p ())
-           break;
+           {
+             if (lra_need_for_scratch_reg_p ())
+               continue;
+             break;
+           }
        }
       lra_spill ();
       /* Assignment of stack slots changes elimination offsets for
@@ -2507,7 +2466,7 @@ lra (FILE *f)
        lra_bad_spill_regno_start = lra_constraint_new_regno_start;
       lra_assignment_iter_after_spill = 0;
     }
-  restore_scratches ();
+  ira_restore_scratches (lra_dump_file);
   lra_eliminate (true, false);
   lra_final_code_change ();
   lra_in_progress = 0;