]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/lra.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / lra.c
index 8ced164f6469eb2c20670000eec69ae8b9f6e2b1..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-2015 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.
@@ -104,39 +104,24 @@ along with GCC; see the file COPYING3.    If not see
 #include "system.h"
 #include "coretypes.h"
 #include "backend.h"
-#include "predict.h"
-#include "tree.h"
+#include "target.h"
 #include "rtl.h"
+#include "tree.h"
+#include "predict.h"
 #include "df.h"
+#include "memmodel.h"
 #include "tm_p.h"
+#include "optabs.h"
 #include "regs.h"
-#include "insn-config.h"
-#include "insn-codes.h"
+#include "ira.h"
 #include "recog.h"
-#include "output.h"
-#include "addresses.h"
-#include "flags.h"
-#include "optabs.h"
-#include "alias.h"
-#include "expmed.h"
-#include "dojump.h"
-#include "explow.h"
-#include "calls.h"
-#include "emit-rtl.h"
-#include "varasm.h"
-#include "stmt.h"
 #include "expr.h"
 #include "cfgrtl.h"
 #include "cfgbuild.h"
-#include "except.h"
-#include "tree-pass.h"
-#include "timevar.h"
-#include "target.h"
-#include "ira.h"
-#include "alloc-pool.h"
 #include "lra.h"
-#include "insn-attr.h"
 #include "lra-int.h"
+#include "print-rtl.h"
+#include "function-abi.h"
 
 /* Dump bitmap SET with TITLE and BB INDEX.  */
 void
@@ -175,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)
@@ -399,7 +383,7 @@ lra_emit_add (rtx x, rtx y, rtx z)
          base = a1;
          index = a2;
        }
-      if (! (REG_P (base) || GET_CODE (base) == SUBREG)
+      if ((base != NULL_RTX && ! (REG_P (base) || GET_CODE (base) == SUBREG))
          || (index != NULL_RTX
              && ! (REG_P (index) || GET_CODE (index) == SUBREG))
          || (disp != NULL_RTX && ! CONSTANT_P (disp))
@@ -459,18 +443,28 @@ lra_emit_add (rtx x, rtx y, rtx z)
                  rtx_insn *insn = emit_add2_insn (x, disp);
                  if (insn != NULL_RTX)
                    {
-                     insn = emit_add2_insn (x, base);
-                     if (insn != NULL_RTX)
+                     if (base == NULL_RTX)
                        ok_p = true;
+                     else
+                       {
+                         insn = emit_add2_insn (x, base);
+                         if (insn != NULL_RTX)
+                           ok_p = true;
+                       }
                    }
                }
              if (! ok_p)
                {
+                 rtx_insn *insn;
+                 
                  delete_insns_since (last);
                  /* Generate x = disp; x = x + base; x = x + index_scale.  */
                  emit_move_insn (x, disp);
-                 rtx_insn *insn = emit_add2_insn (x, base);
-                 lra_assert (insn != NULL_RTX);
+                 if (base != NULL_RTX)
+                   {
+                     insn = emit_add2_insn (x, base);
+                     lra_assert (insn != NULL_RTX);
+                   }
                  insn = emit_add2_insn (x, index_scale);
                  lra_assert (insn != NULL_RTX);
                }
@@ -486,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
@@ -494,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
@@ -533,26 +536,28 @@ lra_update_dups (lra_insn_recog_data_t id, signed char *nops)
    insns.  */
 
 /* Pools for insn reg info.  */
-object_allocator<lra_insn_reg> lra_insn_reg_pool ("insn regs", 100);
-
-/* 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 insn reg
-   info (NEXT).         */
+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), 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, struct lra_insn_reg *next)
+             machine_mode 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 (GET_MODE_SIZE (mode) > GET_MODE_SIZE (lra_reg_info[regno].biggest_mode)
-      && NONDEBUG_INSN_P (insn))
+  if (NONDEBUG_INSN_P (insn)
+      && 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;
   return ir;
@@ -585,7 +590,7 @@ finish_insn_regs (void)
 
 /* Map INSN_CODE -> the static insn data.  This info is valid during
    all translation unit.  */
-struct lra_static_insn_data *insn_code_data[LAST_INSN_CODE];
+struct lra_static_insn_data *insn_code_data[NUM_INSN_CODES];
 
 /* Debug insns are represented as a special insn with one input
    operand which is RTL expression in var_location.  */
@@ -596,15 +601,16 @@ struct lra_static_insn_data *insn_code_data[LAST_INSN_CODE];
 static struct lra_operand_data debug_operand_data =
   {
     NULL, /* alternative  */
-    VOIDmode, /* We are not interesting in the operand mode.  */
+    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
@@ -631,12 +653,13 @@ init_insn_code_data_once (void)
 static void
 finish_insn_code_data_once (void)
 {
-  int i;
-
-  for (i = 0; i < LAST_INSN_CODE; i++)
+  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;
+       }
     }
 }
 
@@ -650,7 +673,7 @@ get_static_insn_data (int icode, int nop, int ndup, int nalt)
   struct lra_static_insn_data *data;
   size_t n_bytes;
 
-  lra_assert (icode < LAST_INSN_CODE);
+  lra_assert (icode < (int) NUM_INSN_CODES);
   if (icode >= 0 && (data = insn_code_data[icode]) != NULL)
     return data;
   lra_assert (nop >= 0 && ndup >= 0 && nalt >= 0);
@@ -697,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)
@@ -742,11 +769,11 @@ 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.  */
-static object_allocator<lra_copy> lra_copy_pool ("lra copies", 100);
+static object_allocator<lra_copy> lra_copy_pool ("lra copies");
 
 /* Finish LRA data about all insns.  */
 static void
@@ -761,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);
 }
 
@@ -779,7 +807,7 @@ setup_operand_alternative (lra_insn_recog_data_t data,
   static_data->operand_alternative = op_alt;
   for (i = 0; i < nop; i++)
     {
-      static_data->operand[i].early_clobber = false;
+      static_data->operand[i].early_clobber_alts = 0;
       static_data->operand[i].is_address = false;
       if (static_data->operand[i].constraint[0] == '%')
        {
@@ -795,7 +823,8 @@ 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;
       }
 }
@@ -806,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)
 {
@@ -819,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++)
@@ -830,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))
     {
@@ -845,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
@@ -855,13 +881,13 @@ collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
              {
                if (curr->type != type)
                  curr->type = OP_INOUT;
-               if (curr->early_clobber != early_clobber)
-                 curr->early_clobber = true;
+               if (early_clobber)
+                 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
@@ -872,7 +898,7 @@ 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, list);
+                                  early_clobber ? ALL_ALTERNATIVES : 0, list);
            }
        }
       return list;
@@ -880,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:
@@ -906,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;
@@ -938,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)
@@ -987,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++)
@@ -1014,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);
        }
     }
@@ -1054,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))
@@ -1081,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;
@@ -1163,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
@@ -1182,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)
@@ -1200,30 +1231,22 @@ lra_update_insn_recog_data (rtx_insn *insn)
          decode_asm_operands (PATTERN (insn), NULL,
                               data->operand_loc,
                               constraints, operand_mode, NULL);
-#ifdef ENABLE_CHECKING
-         {
-           int i;
 
-           for (i = 0; i < nop; i++)
+         if (flag_checking)
+           for (int i = 0; i < nop; i++)
              lra_assert
                (insn_static_data->operand[i].mode == operand_mode[i]
                 && insn_static_data->operand[i].constraint == constraints[i]
                 && ! insn_static_data->operand[i].is_operator);
-         }
-#endif
        }
-#ifdef ENABLE_CHECKING
-      {
-       int i;
 
-       for (i = 0; i < insn_static_data->n_operands; i++)
+      if (flag_checking)
+       for (int i = 0; i < insn_static_data->n_operands; i++)
          lra_assert
            (insn_static_data->operand[i].type
             == (insn_static_data->operand[i].constraint[0] == '=' ? OP_OUT
                 : insn_static_data->operand[i].constraint[0] == '+' ? OP_INOUT
                 : OP_IN));
-      }
-#endif
     }
   else
     {
@@ -1270,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;
@@ -1294,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;
@@ -1303,7 +1327,7 @@ initialize_lra_reg_info_element (int i)
   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;
-  lra_reg_info[i].restore_regno = -1;
+  lra_reg_info[i].restore_rtx = NULL_RTX;
   lra_reg_info[i].val = get_new_reg_value ();
   lra_reg_info[i].offset = 0;
   lra_reg_info[i].copies = NULL;
@@ -1317,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.create (100);
+  copy_vec.truncate (0);
+  CLEAR_HARD_REG_SET (hard_regs_spilled_into);
 }
 
 
@@ -1345,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);
 }
@@ -1409,12 +1434,14 @@ 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.  */
+/* 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;
   bool subreg_p;
@@ -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,10 +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, data->regs);
+                                    early_clobber_alts, data->regs);
          return;
        }
       else
@@ -1455,17 +1479,16 @@ 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,
+                                            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;
              }
@@ -1476,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);
-      add_regs_to_insn_regno_info (data, SET_SRC (x), uid, OP_IN, false);
+      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);
+        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);
+      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);
-      add_regs_to_insn_regno_info (data, XEXP (x, 1), uid, OP_IN, false);
+      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)
@@ -1510,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);
+           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);
+               add_regs_to_insn_regno_info (data, XVECEXP (x, i, j), insn,
+                                            type, 0);
            }
        }
     }
@@ -1590,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;
@@ -1600,16 +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);
+    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
@@ -1618,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);
+      {
+       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);
 }
@@ -1638,6 +1664,94 @@ lra_get_insn_regs (int uid)
 
 \f
 
+/* Recursive hash function for RTL X.  */
+hashval_t
+lra_rtx_hash (rtx x)
+{
+  int i, j;
+  enum rtx_code code;
+  const char *fmt;
+  hashval_t val = 0;
+
+  if (x == 0)
+    return val;
+
+  code = GET_CODE (x);
+  val += (int) code + 4095;
+
+  /* Some RTL can be compared nonrecursively.  */
+  switch (code)
+    {
+    case REG:
+      return val + REGNO (x);
+
+    case LABEL_REF:
+      return iterative_hash_object (XEXP (x, 0), val);
+
+    case SYMBOL_REF:
+      return iterative_hash_object (XSTR (x, 0), val);
+
+    case SCRATCH:
+    case CONST_DOUBLE:
+    case CONST_VECTOR:
+      return val;
+
+    case CONST_INT:
+      return val + UINTVAL (x);
+
+    default:
+      break;
+    }
+
+  /* Hash the elements.  */
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      switch (fmt[i])
+       {
+       case 'w':
+         val += XWINT (x, i);
+         break;
+
+       case 'n':
+       case 'i':
+         val += XINT (x, i);
+         break;
+
+       case 'V':
+       case 'E':
+         val += XVECLEN (x, i);
+
+         for (j = 0; j < XVECLEN (x, i); j++)
+           val += lra_rtx_hash (XVECEXP (x, i, j));
+         break;
+
+       case 'e':
+         val += lra_rtx_hash (XEXP (x, i));
+         break;
+
+       case 'S':
+       case 's':
+         val += htab_hash_string (XSTR (x, i));
+         break;
+
+       case 'u':
+       case '0':
+       case 't':
+         break;
+
+         /* It is believed that rtx's at this level will never
+            contain anything but integers and other rtx's, except for
+            within LABEL_REFs and SYMBOL_REFs.  */
+       default:
+         abort ();
+       }
+    }
+  return val;
+}
+
+\f
+
 /* This page contains code dealing with stack of the insns which
    should be processed by the next constraint pass.  */
 
@@ -1723,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;
@@ -1738,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)
@@ -1750,36 +1862,98 @@ 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)
     {
+      if (cfun->can_throw_non_call_exceptions)
+       copy_reg_eh_region_note_forward (insn, before, NULL);
       emit_insn_before (before, insn);
       push_insns (PREV_INSN (insn), PREV_INSN (before));
       setup_sp_offset (before, PREV_INSN (insn));
     }
   if (after != NULL_RTX)
     {
-      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 (cfun->can_throw_non_call_exceptions)
+       copy_reg_eh_region_note_forward (insn, after, NULL);
+      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);
+      if (note && !insn_could_throw_p (insn))
+       remove_note (insn, note);
     }
 }
-
 \f
 
 /* 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;
@@ -1813,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 (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (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;
@@ -1832,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;
        }
     }
@@ -1854,159 +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
+/* 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)
 {
-  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 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);
-      }
+      if (INSN_P (insn))
+        remove_insn_scratches (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++)
-    {
-      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);
-}
-
-\f
-
-#ifdef ENABLE_CHECKING
-
 /* 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
@@ -2025,9 +2084,7 @@ check_rtl (bool final_p)
       {
        if (final_p)
          {
-#ifdef ENABLED_CHECKING
            extract_constrain_insn (insn);
-#endif
            continue;
          }
        /* LRA code is based on assumption that all addresses can be
@@ -2040,7 +2097,6 @@ check_rtl (bool final_p)
          fatal_insn_not_found (insn);
       }
 }
-#endif /* #ifdef ENABLE_CHECKING */
 
 /* Determine if the current function has an exception receiver block
    that reaches the exit block via non-exceptional edges  */
@@ -2092,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
@@ -2164,25 +2192,34 @@ 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;
 
 /* Split regnos before the new spill pass.  */
 bitmap_head lra_split_regs;
 
-/* Reload pseudo regnos before the new assignmnet pass which still can
-   be spilled after the assinment pass as memory is also accepted in
+/* Reload pseudo regnos before the new assignment pass which still can
+   be spilled after the assignment pass as memory is also accepted in
    insns for the reload pseudos.  */
 bitmap_head lra_optional_reload_pseudos;
 
 /* Pseudo regnos used for subreg reloads before the new assignment
-   pass.  Such pseudos still can be spilled after the assinment
+   pass.  Such pseudos still can be spilled after the assignment
    pass.  */
 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;
@@ -2217,27 +2254,28 @@ void
 lra (FILE *f)
 {
   int i;
-  bool live_p, scratch_p, inserted_p;
+  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 ();
 
   init_insn_recog_data ();
 
-#ifdef ENABLE_CHECKING
   /* Some quick check on RTL generated by previous passes.  */
-  check_rtl (false);
-#endif
+  if (flag_checking)
+    check_rtl (false);
 
   lra_in_progress = 1;
 
@@ -2255,7 +2293,6 @@ lra (FILE *f)
   lra_constraint_new_regno_start = lra_new_regno_start = max_reg_num ();
   lra_bad_spill_regno_start = INT_MAX;
   remove_scratches ();
-  scratch_p = lra_constraint_new_regno_start != max_reg_num ();
 
   /* A function that has a non-local label that can reach the exit
      block via non-exceptional paths must save all call-saved
@@ -2265,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
@@ -2284,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.  */
@@ -2294,13 +2333,7 @@ lra (FILE *f)
     {
       for (;;)
        {
-         /* We should try to assign hard registers to scratches even
-            if there were no RTL transformations in
-            lra_constraints.  */
-         if (! lra_constraints (lra_constraint_iter == 0)
-             && (lra_constraint_iter > 1
-                 || (! scratch_p && ! caller_save_needed)))
-           break;
+         bool reloads_p = lra_constraints (lra_constraint_iter == 0);
          /* Constraint transformations may result in that eliminable
             hard regs become uneliminable and pseudos which use them
             should be spilled.  It is better to do it before pseudo
@@ -2310,55 +2343,83 @@ lra (FILE *f)
             RS6000_PIC_OFFSET_TABLE_REGNUM uneliminable if we started
             to use a constant pool.  */
          lra_eliminate (false, false);
-         /* Do inheritance only for regular algorithms.  */
-         if (! lra_simple_p)
+         /* We should try to assign hard registers to scratches even
+            if there were no RTL transformations in lra_constraints.
+            Also we should check IRA assignments on the first
+            iteration as they can be wrong because of early clobbers
+            operands which are ignored in IRA.  */
+         if (! reloads_p && lra_constraint_iter > 1)
            {
-             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 ();
+             /* Stack is not empty here only when there are changes
+                during the elimination sub-pass.  */
+             if (bitmap_empty_p (lra_constraint_insn_stack_bitmap))
+               break;
+             else
+               /* If there are no reloads but changing due
+                  elimination, restart the constraint sub-pass
+                  first.  */
+               continue;
            }
+         /* Do inheritance only for regular algorithms.  */
+         if (! lra_simple_p)
+           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.  */
@@ -2385,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
@@ -2401,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;
@@ -2423,11 +2488,9 @@ lra (FILE *f)
   /* We've possibly turned single trapping insn into multiple ones.  */
   if (cfun->can_throw_non_call_exceptions)
     {
-      sbitmap blocks;
-      blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
+      auto_sbitmap blocks (last_basic_block_for_fn (cfun));
       bitmap_ones (blocks);
       find_many_sub_basic_blocks (blocks);
-      sbitmap_free (blocks);
     }
 
   if (inserted_p)
@@ -2438,9 +2501,8 @@ lra (FILE *f)
      by this, so unshare everything here.  */
   unshare_all_rtl_again (get_insns ());
 
-#ifdef ENABLE_CHECKING
-  check_rtl (true);
-#endif
+  if (flag_checking)
+    check_rtl (true);
 
   timevar_pop (TV_LRA);
 }