]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/lra-remat.c
Fix missed IPA-CP on by-ref argument directly passed through (PR 93429)
[thirdparty/gcc.git] / gcc / lra-remat.c
index f638a1d87407d284b74c3724568054ba14ff0229..72309e52694348a5078a0f5341e3b65342bb8ba8 100644 (file)
@@ -1,5 +1,5 @@
 /* Rematerialize pseudos values.
-   Copyright (C) 2014 Free Software Foundation, Inc.
+   Copyright (C) 2014-2020 Free Software Foundation, Inc.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
 This file is part of GCC.
@@ -55,47 +55,27 @@ along with GCC; see the file COPYING3.      If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "hard-reg-set.h"
+#include "backend.h"
 #include "rtl.h"
-#include "rtl-error.h"
-#include "tm_p.h"
-#include "target.h"
+#include "df.h"
 #include "insn-config.h"
-#include "recog.h"
-#include "output.h"
 #include "regs.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
-#include "input.h"
-#include "function.h"
-#include "expr.h"
-#include "predict.h"
-#include "dominance.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "except.h"
-#include "df.h"
+#include "memmodel.h"
 #include "ira.h"
-#include "sparseset.h"
-#include "params.h"
-#include "df.h"
+#include "recog.h"
+#include "lra.h"
 #include "lra-int.h"
+#include "function-abi.h"
 
 /* Number of candidates for rematerialization.  */
 static unsigned int cands_num;
 
-/* The following is used for representation of call_used_reg_set in
-   form array whose elements are hard register numbers with nonzero bit
-   in CALL_USED_REG_SET. */
-static int call_used_regs_arr_len;
-static int call_used_regs_arr[FIRST_PSEUDO_REGISTER];
-
 /* Bitmap used for different calculations.  */
 static bitmap_head temp_bitmap;
 
+/* Registers accessed via subreg_p.  */
+static bitmap_head subreg_regs;
+
 typedef struct cand *cand_t;
 typedef const struct cand *const_cand_t;
 
@@ -109,10 +89,10 @@ struct cand
 {
   /* Index of the candidates in all_cands. */
   int index;
-  /* The candidate insn.  */
-  rtx_insn *insn;
   /* Insn pseudo regno for rematerialization.  */
   int regno;
+  /* The candidate insn.  */
+  rtx_insn *insn;
   /* Non-negative if a reload pseudo is in the insn instead of the
      pseudo for rematerialization.  */
   int reload_regno;
@@ -125,9 +105,13 @@ struct cand
 
 /* Vector containing all candidates.  */
 static vec<cand_t> all_cands;
-/* Map: insn -> candidate representing it.  It is null if the insn can
-   not be used for rematerialization.  */
+/* Map: insn -> candidate representing it.  It is null if the insn cannot
+   be used for rematerialization.  */
 static cand_t *insn_to_cand;
+/* A secondary map, for candidates that involve two insns, where the
+   second one makes the equivalence.  The candidate must not be used
+   before seeing this activation insn.  */
+static cand_t *insn_to_cand_activation;
 
 /* Map regno -> candidates can be used for the regno
    rematerialization.  */
@@ -135,8 +119,9 @@ static cand_t *regno_cands;
 
 /* Data about basic blocks used for the rematerialization
    sub-pass.  */
-struct remat_bb_data
+class remat_bb_data
 {
+public:
   /* Basic block about which the below data are.  */
   basic_block bb;
   /* Registers changed in the basic block: */
@@ -155,7 +140,7 @@ struct remat_bb_data
 };
 
 /* Array for all BB data.  Indexed by the corresponding BB index.  */
-typedef struct remat_bb_data *remat_bb_data_t;
+typedef class remat_bb_data *remat_bb_data_t;
 
 /* Basic blocks for data flow problems -- all bocks except the special
    ones.  */
@@ -179,92 +164,6 @@ get_remat_bb_data_by_index (int index)
 
 \f
 
-/* Recursive hash function for RTL X.  */
-static hashval_t
-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_INT:
-    case CONST_VECTOR:
-      return val;
-
-    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 += rtx_hash (XVECEXP (x, i, j));
-         break;
-
-       case 'e':
-         val += 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
-
 /* Hash table for the candidates.  Different insns (e.g. structurally
    the same insns or even insns with different unused output regs) can
    be represented by the same candidate in the table.  */
@@ -350,12 +249,12 @@ finish_cand_table (void)
 
 \f
 
-/* Return true if X contains memory or UNSPEC.  We can not just check
-   insn operands as memory or unspec might be not an operand itself
-   but contain an operand.  Insn with memory access is not profitable
-   for rematerialization.  Rematerialization of UNSPEC might result in
-   wrong code generation as the UNPEC effect is unknown
-   (e.g. generating a label).  */
+/* Return true if X contains memory or some UNSPEC.  We cannot just
+   check insn operands as memory or unspec might be not an operand
+   itself but contain an operand.  Insn with memory access is not
+   profitable for rematerialization.  Rematerialization of UNSPEC
+   might result in wrong code generation as the UNPEC effect is
+   unknown (e.g. generating a label).  */
 static bool
 bad_for_rematerialization_p (rtx x)
 {
@@ -363,7 +262,7 @@ bad_for_rematerialization_p (rtx x)
   const char *fmt;
   enum rtx_code code;
 
-  if (MEM_P (x) || GET_CODE (x) == UNSPEC)
+  if (MEM_P (x) || GET_CODE (x) == UNSPEC || GET_CODE (x) == UNSPEC_VOLATILE)
     return true;
   code = GET_CODE (x);
   fmt = GET_RTX_FORMAT (code);
@@ -384,7 +283,7 @@ bad_for_rematerialization_p (rtx x)
   return false;
 }
 
-/* If INSN can not be used for rematerialization, return negative
+/* If INSN cannot be used for rematerialization, return negative
    value.  If INSN can be considered as a candidate for
    rematerialization, return value which is the operand number of the
    pseudo for which the insn can be used for rematerialization.  Here
@@ -397,16 +296,39 @@ operand_to_remat (rtx_insn *insn)
   struct lra_static_insn_data *static_id = id->insn_static_data;
   struct lra_insn_reg *reg, *found_reg = NULL;
 
+  /* Don't rematerialize insns which can change PC.  */
+  if (JUMP_P (insn) || CALL_P (insn))
+    return -1;
   /* First find a pseudo which can be rematerialized.  */
   for (reg = id->regs; reg != NULL; reg = reg->next)
-    if (reg->type == OP_OUT && ! reg->subreg_p
-       && find_regno_note (insn, REG_UNUSED, reg->regno) == NULL)
-      {
-       /* We permits only one spilled reg.  */
-       if (found_reg != NULL)
-         return -1;
-       found_reg = reg;
-      }
+    {
+      /* True FRAME_POINTER_NEEDED might be because we cannot follow
+        changing sp offsets, e.g. alloca is used.  If the insn contains
+        stack pointer in such case, we cannot rematerialize it as we
+        cannot know sp offset at a rematerialization place.  */
+      if (reg->regno == STACK_POINTER_REGNUM && frame_pointer_needed)
+       return -1;
+      else if (reg->type == OP_OUT && ! reg->subreg_p
+              && find_regno_note (insn, REG_UNUSED, reg->regno) == NULL)
+       {
+         /* We permits only one spilled reg.  */
+         if (found_reg != NULL)
+           return -1;
+         found_reg = reg;
+        }
+      /* IRA calculates conflicts separately for subregs of two words
+        pseudo.  Even if the pseudo lives, e.g. one its subreg can be
+        used lately, another subreg hard register can be already used
+        for something else.  In such case, it is not safe to
+        rematerialize the insn.  */
+      if (reg->regno >= FIRST_PSEUDO_REGISTER
+         && bitmap_bit_p (&subreg_regs, reg->regno))
+       return -1;
+
+      /* Don't allow hard registers to be rematerialized.  */
+      if (reg->regno < FIRST_PSEUDO_REGISTER)
+       return -1;
+    }
   if (found_reg == NULL)
     return -1;
   if (found_reg->regno < FIRST_PSEUDO_REGISTER)
@@ -434,6 +356,31 @@ operand_to_remat (rtx_insn *insn)
             reg2 = reg2->next)
          if (reg2->type == OP_OUT && reg->regno == reg2->regno)
            return -1;
+       if (reg->regno < FIRST_PSEUDO_REGISTER)
+         for (struct lra_insn_reg *reg2 = static_id->hard_regs;
+              reg2 != NULL;
+              reg2 = reg2->next)
+           if (reg2->type == OP_OUT
+               && reg->regno <= reg2->regno
+               && (reg2->regno
+                   < (int) end_hard_regno (reg->biggest_mode, reg->regno)))
+             return -1;
+      }
+  /* Check hard coded insn registers.  */
+  for (struct lra_insn_reg *reg = static_id->hard_regs;
+       reg != NULL;
+       reg = reg->next)
+    if (reg->type == OP_INOUT)
+      return -1;
+    else if (reg->type == OP_IN)
+      {
+       /* Check that there is no output hard reg as the input
+          one.  */
+         for (struct lra_insn_reg *reg2 = static_id->hard_regs;
+              reg2 != NULL;
+              reg2 = reg2->next)
+           if (reg2->type == OP_OUT && reg->regno == reg2->regno)
+               return -1;
       }
   /* Find the rematerialization operand.  */
   int nop = static_id->n_operands;
@@ -448,7 +395,7 @@ operand_to_remat (rtx_insn *insn)
    REGNO.  Insert the candidate into the table and set up the
    corresponding INSN_TO_CAND element.  */
 static void
-create_cand (rtx_insn *insn, int nop, int regno)
+create_cand (rtx_insn *insn, int nop, int regno, rtx_insn *activation = NULL)
 {
   lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
   rtx reg = *id->operand_loc[nop];
@@ -473,6 +420,8 @@ create_cand (rtx_insn *insn, int nop, int regno)
       cand->next_regno_cand = regno_cands[cand->regno];
       regno_cands[cand->regno] = cand;
     }
+  if (activation)
+    insn_to_cand_activation[INSN_UID (activation)] = cand_in_table;
 }
 
 /* Create rematerialization candidates (inserting them into the
@@ -491,40 +440,55 @@ create_cands (void)
   /* Create candidates.  */
   regno_potential_cand = XCNEWVEC (struct potential_cand, max_reg_num ());
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
+    if (NONDEBUG_INSN_P (insn))
       {
-       rtx set;
-       int src_regno, dst_regno;
-       rtx_insn *insn2;
        lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
-       int nop = operand_to_remat (insn);
-       int regno = -1;
-
-       if ((set = single_set (insn)) != NULL
-           && REG_P (SET_SRC (set)) && REG_P (SET_DEST (set))
-           && (src_regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER
-           && (dst_regno = REGNO (SET_DEST (set))) >= FIRST_PSEUDO_REGISTER
-           && reg_renumber[dst_regno] < 0
-           && (insn2 = regno_potential_cand[src_regno].insn) != NULL
-           && BLOCK_FOR_INSN (insn2) == BLOCK_FOR_INSN (insn))
-         create_cand (insn2, regno_potential_cand[src_regno].nop, dst_regno);
-       if (nop < 0)
-         goto fail;
-       gcc_assert (REG_P (*id->operand_loc[nop]));
-       regno = REGNO (*id->operand_loc[nop]);
-       gcc_assert (regno >= FIRST_PSEUDO_REGISTER);
-       if (reg_renumber[regno] < 0)
-         create_cand (insn, nop, regno);
-       else
+       int keep_regno = -1;
+       rtx set = single_set (insn);
+       int nop;
+
+       /* See if this is an output reload for a previous insn.  */
+       if (set != NULL
+           && REG_P (SET_SRC (set)) && REG_P (SET_DEST (set)))
          {
-           regno_potential_cand[regno].insn = insn;
-           regno_potential_cand[regno].nop = nop;
-           goto fail;
+           rtx dstreg = SET_DEST (set);
+           int src_regno = REGNO (SET_SRC (set));
+           int dst_regno = REGNO (dstreg);
+           rtx_insn *insn2 = regno_potential_cand[src_regno].insn;
+
+           if (insn2 != NULL 
+               && dst_regno >= FIRST_PSEUDO_REGISTER
+               && reg_renumber[dst_regno] < 0
+               && BLOCK_FOR_INSN (insn2) == BLOCK_FOR_INSN (insn))
+             {
+               create_cand (insn2, regno_potential_cand[src_regno].nop,
+                            dst_regno, insn);
+               goto done;
+             }
+         }
+
+       nop = operand_to_remat (insn);
+       if (nop >= 0)
+         {
+           gcc_assert (REG_P (*id->operand_loc[nop]));
+           int regno = REGNO (*id->operand_loc[nop]);
+           gcc_assert (regno >= FIRST_PSEUDO_REGISTER);
+           /* If we're setting an unrenumbered pseudo, make a candidate immediately.
+              If it's an output reload register, save it for later; the code above
+              looks for output reload insns later on.  */
+           if (reg_renumber[regno] < 0)
+             create_cand (insn, nop, regno);
+           else if (regno >= lra_constraint_new_regno_start)
+             {
+               regno_potential_cand[regno].insn = insn;
+               regno_potential_cand[regno].nop = nop;
+               keep_regno = regno;
+             }
          }
-       regno = -1;
-      fail:
+
+      done:
        for (struct lra_insn_reg *reg = id->regs; reg != NULL; reg = reg->next)
-         if (reg->type != OP_IN && reg->regno != regno
+         if (reg->type != OP_IN && reg->regno != keep_regno
              && reg->regno >= FIRST_PSEUDO_REGISTER)
            regno_potential_cand[reg->regno].insn = NULL;
       }
@@ -541,14 +505,12 @@ create_remat_bb_data (void)
   basic_block bb;
   remat_bb_data_t bb_info;
 
-  remat_bb_data = XNEWVEC (struct remat_bb_data,
+  remat_bb_data = XNEWVEC (class remat_bb_data,
                           last_basic_block_for_fn (cfun));
   FOR_ALL_BB_FN (bb, cfun)
     {
-#ifdef ENABLE_CHECKING
-      if (bb->index < 0 || bb->index >= last_basic_block_for_fn (cfun))
-       abort ();
-#endif
+      gcc_checking_assert (bb->index >= 0
+                          && bb->index < last_basic_block_for_fn (cfun));
       bb_info = get_remat_bb_data (bb);
       bb_info->bb = bb;
       bitmap_initialize (&bb_info->changed_regs, &reg_obstack);
@@ -620,6 +582,9 @@ dump_candidates_and_remat_bb_data (void)
       lra_dump_bitmap_with_title ("avout cands in BB",
                                  &get_remat_bb_data (bb)->avout_cands, bb->index);
     }
+  fprintf (lra_dump_file, "subreg regs:");
+  dump_regset (&subreg_regs, lra_dump_file);
+  putc ('\n', lra_dump_file);
 }
 
 /* Free all BB data.  */
@@ -644,25 +609,31 @@ finish_remat_bb_data (void)
 
 \f
 
-/* Update changed_regs and dead_regs of BB from INSN.  */
+/* Update changed_regs, dead_regs, subreg_regs of BB from INSN.  */
 static void
 set_bb_regs (basic_block bb, rtx_insn *insn)
 {
   lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
+  remat_bb_data_t bb_info = get_remat_bb_data (bb);
   struct lra_insn_reg *reg;
 
   for (reg = id->regs; reg != NULL; reg = reg->next)
-    if (reg->type != OP_IN)
-      bitmap_set_bit (&get_remat_bb_data (bb)->changed_regs, reg->regno);
-    else
-      {
-       if (find_regno_note (insn, REG_DEAD, (unsigned) reg->regno) != NULL)
-         bitmap_set_bit (&get_remat_bb_data (bb)->dead_regs, reg->regno);
-      }
+    {
+      unsigned regno = reg->regno;
+      if (reg->type != OP_IN)
+        bitmap_set_bit (&bb_info->changed_regs, regno);
+      else if (find_regno_note (insn, REG_DEAD, regno) != NULL)
+       bitmap_set_bit (&bb_info->dead_regs, regno);
+      if (regno >= FIRST_PSEUDO_REGISTER && reg->subreg_p)
+       bitmap_set_bit (&subreg_regs, regno);
+    }
   if (CALL_P (insn))
-    for (int i = 0; i < call_used_regs_arr_len; i++)
-      bitmap_set_bit (&get_remat_bb_data (bb)->dead_regs,
-                     call_used_regs_arr[i]);
+    {
+      /* Partially-clobbered registers might still be live.  */
+      HARD_REG_SET clobbers = insn_callee_abi (insn).full_reg_clobbers ();
+      bitmap_ior_into (&get_remat_bb_data (bb)->dead_regs,
+                      bitmap_view<HARD_REG_SET> (clobbers));
+    }
 }
 
 /* Calculate changed_regs and dead_regs for each BB.  */
@@ -674,36 +645,72 @@ calculate_local_reg_remat_bb_data (void)
 
   FOR_EACH_BB_FN (bb, cfun)
     FOR_BB_INSNS (bb, insn)
-      if (INSN_P (insn))
+      if (NONDEBUG_INSN_P (insn))
        set_bb_regs (bb, insn);
 }
 
 \f
 
-/* Return true if REGNO is an input operand of INSN.  */
+/* Return true if REG overlaps an input operand of INSN.  */
 static bool
-input_regno_present_p (rtx_insn *insn, int regno)
+reg_overlap_for_remat_p (lra_insn_reg *reg, rtx_insn *insn)
 {
+  int iter;
   lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
-  struct lra_insn_reg *reg;
+  struct lra_static_insn_data *static_id = id->insn_static_data;
+  unsigned regno = reg->regno;
+  int nregs;
 
-  for (reg = id->regs; reg != NULL; reg = reg->next)
-    if (reg->type == OP_IN && reg->regno == regno)
-      return true;
+  if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0)
+    regno = reg_renumber[regno];
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    nregs = 1;
+  else
+    nregs = hard_regno_nregs (regno, reg->biggest_mode);
+
+  struct lra_insn_reg *reg2;
+
+  for (iter = 0; iter < 2; iter++)
+    for (reg2 = (iter == 0 ? id->regs : static_id->hard_regs);
+        reg2 != NULL;
+        reg2 = reg2->next)
+      {
+       if (reg2->type != OP_IN)
+         continue;
+       unsigned regno2 = reg2->regno;
+       int nregs2;
+
+       if (regno2 >= FIRST_PSEUDO_REGISTER && reg_renumber[regno2] >= 0)
+         regno2 = reg_renumber[regno2];
+       if (regno2 >= FIRST_PSEUDO_REGISTER)
+         nregs2 = 1;
+       else
+         nregs2 = hard_regno_nregs (regno2, reg->biggest_mode);
+
+       if ((regno2 + nregs2 - 1 >= regno && regno2 < regno + nregs)
+           || (regno + nregs - 1 >= regno2 && regno < regno2 + nregs2))
+         return true;
+      }
   return false;
 }
 
 /* Return true if a call used register is an input operand of INSN.  */
 static bool
-call_used_input_regno_present_p (rtx_insn *insn)
+call_used_input_regno_present_p (const function_abi &abi, rtx_insn *insn)
 {
+  int iter;
   lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
+  struct lra_static_insn_data *static_id = id->insn_static_data;
   struct lra_insn_reg *reg;
 
-  for (reg = id->regs; reg != NULL; reg = reg->next)
-    if (reg->type == OP_IN && reg->regno <= FIRST_PSEUDO_REGISTER
-       && TEST_HARD_REG_BIT (call_used_reg_set, reg->regno))
-      return true;
+  for (iter = 0; iter < 2; iter++)
+    for (reg = (iter == 0 ? id->regs : static_id->hard_regs);
+        reg != NULL;
+        reg = reg->next)
+      if (reg->type == OP_IN
+         && reg->regno < FIRST_PSEUDO_REGISTER
+         && abi.clobbers_reg_p (reg->biggest_mode, reg->regno))
+       return true;
   return false;
 }
 
@@ -738,23 +745,23 @@ calculate_gen_cands (void)
 {
   basic_block bb;
   bitmap gen_cands;
-  bitmap_head gen_insns;
   rtx_insn *insn;
 
-  bitmap_initialize (&gen_insns, &reg_obstack);
   FOR_EACH_BB_FN (bb, cfun)
     {
       gen_cands = &get_remat_bb_data (bb)->gen_cands;
-      bitmap_clear (&gen_insns);
+      auto_bitmap gen_insns (&reg_obstack);
       FOR_BB_INSNS (bb, insn)
        if (INSN_P (insn))
          {
            lra_insn_recog_data_t id = lra_get_insn_recog_data (insn);
+           struct lra_static_insn_data *static_id = id->insn_static_data;
            struct lra_insn_reg *reg;
            unsigned int uid;
            bitmap_iterator bi;
            cand_t cand;
            rtx set;
+           int iter;
            int src_regno = -1, dst_regno = -1;
 
            if ((set = single_set (insn)) != NULL
@@ -766,51 +773,56 @@ calculate_gen_cands (void)
 
            /* Update gen_cands:  */
            bitmap_clear (&temp_bitmap);
-           for (reg = id->regs; reg != NULL; reg = reg->next)
-             if (reg->type != OP_IN
-                 || find_regno_note (insn, REG_DEAD, reg->regno) != NULL)
-               EXECUTE_IF_SET_IN_BITMAP (&gen_insns, 0, uid, bi)
+           for (iter = 0; iter < 2; iter++)
+             for (reg = (iter == 0 ? id->regs : static_id->hard_regs);
+                  reg != NULL;
+                  reg = reg->next)
+               if (reg->type != OP_IN
+                   || find_regno_note (insn, REG_DEAD, reg->regno) != NULL)
+                 EXECUTE_IF_SET_IN_BITMAP (gen_insns, 0, uid, bi)
+                   {
+                     rtx_insn *insn2 = lra_insn_recog_data[uid]->insn;
+                     
+                     cand = insn_to_cand[INSN_UID (insn2)];
+                     gcc_assert (cand != NULL);
+                     /* Ignore the reload insn.  */
+                     if (src_regno == cand->reload_regno
+                         && dst_regno == cand->regno)
+                       continue;
+                     if (cand->regno == reg->regno
+                         || reg_overlap_for_remat_p (reg, insn2))
+                       {
+                         bitmap_clear_bit (gen_cands, cand->index);
+                         bitmap_set_bit (&temp_bitmap, uid);
+                       }
+                   }
+           
+           if (CALL_P (insn))
+             {
+               function_abi callee_abi = insn_callee_abi (insn);
+               EXECUTE_IF_SET_IN_BITMAP (gen_insns, 0, uid, bi)
                  {
                    rtx_insn *insn2 = lra_insn_recog_data[uid]->insn;
-
+                 
                    cand = insn_to_cand[INSN_UID (insn2)];
                    gcc_assert (cand != NULL);
-                   /* Ignore the reload insn.  */
-                   if (src_regno == cand->reload_regno
-                       && dst_regno == cand->regno)
-                     continue;
-                   if (cand->regno == reg->regno
-                       || input_regno_present_p (insn2, reg->regno))
+                   if (call_used_input_regno_present_p (callee_abi, insn2))
                      {
                        bitmap_clear_bit (gen_cands, cand->index);
                        bitmap_set_bit (&temp_bitmap, uid);
                      }
                  }
-           
-           if (CALL_P (insn))
-             EXECUTE_IF_SET_IN_BITMAP (&gen_insns, 0, uid, bi)
-               {
-                 rtx_insn *insn2 = lra_insn_recog_data[uid]->insn;
-                 
-                 cand = insn_to_cand[INSN_UID (insn2)];
-                 gcc_assert (cand != NULL);
-                 if (call_used_input_regno_present_p (insn2))
-                   {
-                     bitmap_clear_bit (gen_cands, cand->index);
-                     bitmap_set_bit (&temp_bitmap, uid);
-                   }
-               }
-           bitmap_and_compl_into (&gen_insns, &temp_bitmap);
+             }
+           bitmap_and_compl_into (gen_insns, &temp_bitmap);
 
            cand = insn_to_cand[INSN_UID (insn)];
            if (cand != NULL)
              {
                bitmap_set_bit (gen_cands, cand->index);
-               bitmap_set_bit (&gen_insns, INSN_UID (insn));
+               bitmap_set_bit (gen_insns, INSN_UID (insn));
              }
          }
     }  
-  bitmap_clear (&gen_insns);
 }
 
 \f
@@ -860,6 +872,10 @@ cand_trans_fun (int bb_index, bitmap bb_in, bitmap bb_out)
            bitmap_set_bit (&temp_bitmap, cid);
            break;
          }
+      /* Check regno for rematerialization.  */
+      if (bitmap_bit_p (bb_changed_regs, cand->regno)
+         || bitmap_bit_p (bb_dead_regs, cand->regno))
+       bitmap_set_bit (&temp_bitmap, cid);
     }
   return bitmap_ior_and_compl (bb_out,
                               &bb_info->gen_cands, bb_in, &temp_bitmap);
@@ -981,7 +997,7 @@ calculate_global_remat_bb_data (void)
 
 /* Setup sp offset attribute to SP_OFFSET for all INSNS.  */
 static void
-change_sp_offset (rtx_insn *insns, HOST_WIDE_INT sp_offset)
+change_sp_offset (rtx_insn *insns, poly_int64 sp_offset)
 {
   for (rtx_insn *insn = insns; insn != NULL; insn = NEXT_INSN (insn))
     eliminate_regs_in_insn (insn, false, false, sp_offset);
@@ -998,28 +1014,64 @@ get_hard_regs (struct lra_insn_reg *reg, int &nregs)
   int hard_regno = regno < FIRST_PSEUDO_REGISTER ? regno : reg_renumber[regno];
 
   if (hard_regno >= 0)
-    nregs = hard_regno_nregs[hard_regno][reg->biggest_mode];
+    nregs = hard_regno_nregs (hard_regno, reg->biggest_mode);
   return hard_regno;
 }
 
+/* Make copy of and register scratch pseudos in rematerialized insn
+   REMAT_INSN.  */
+static void
+update_scratch_ops (rtx_insn *remat_insn)
+{
+  lra_insn_recog_data_t id = lra_get_insn_recog_data (remat_insn);
+  struct lra_static_insn_data *static_id = id->insn_static_data;
+  for (int i = 0; i < static_id->n_operands; i++)
+    {
+      rtx *loc = id->operand_loc[i];
+      if (! REG_P (*loc))
+       continue;
+      int regno = REGNO (*loc);
+      if (! lra_former_scratch_p (regno))
+       continue;
+      *loc = lra_create_new_reg (GET_MODE (*loc), *loc,
+                                lra_get_allocno_class (regno),
+                                "scratch pseudo copy");
+      lra_register_new_scratch_op (remat_insn, i, id->icode);
+    }
+  
+}
+
 /* Insert rematerialization insns using the data-flow data calculated
    earlier.  */
 static bool
 do_remat (void)
 {
+  unsigned regno;
   rtx_insn *insn;
   basic_block bb;
-  bitmap_head avail_cands;
   bool changed_p = false;
   /* Living hard regs and hard registers of living pseudos.  */
   HARD_REG_SET live_hard_regs;
+  bitmap_iterator bi;
 
-  bitmap_initialize (&avail_cands, &reg_obstack);
+  auto_bitmap avail_cands (&reg_obstack);
+  auto_bitmap active_cands (&reg_obstack);
   FOR_EACH_BB_FN (bb, cfun)
     {
-      REG_SET_TO_HARD_REG_SET (live_hard_regs, df_get_live_out (bb));
-      bitmap_and (&avail_cands, &get_remat_bb_data (bb)->avin_cands,
+      CLEAR_HARD_REG_SET (live_hard_regs);
+      EXECUTE_IF_SET_IN_BITMAP (df_get_live_in (bb), 0, regno, bi)
+       {
+         int hard_regno = regno < FIRST_PSEUDO_REGISTER
+                          ? regno
+                          : reg_renumber[regno];
+         if (hard_regno >= 0)
+           SET_HARD_REG_BIT (live_hard_regs, hard_regno);
+       }
+      bitmap_and (avail_cands, &get_remat_bb_data (bb)->avin_cands,
                  &get_remat_bb_data (bb)->livein_cands);
+      /* Activating insns are always in the same block as their corresponding
+        remat insn, so at the start of a block the two bitsets are equal.  */
+      bitmap_copy (active_cands, avail_cands);
       FOR_BB_INSNS (bb, insn)
        {
          if (!NONDEBUG_INSN_P (insn))
@@ -1032,6 +1084,7 @@ do_remat (void)
          unsigned int cid;
          bitmap_iterator bi;
          rtx set;
+         int iter;
          int src_regno = -1, dst_regno = -1;
 
          if ((set = single_set (insn)) != NULL
@@ -1052,12 +1105,14 @@ do_remat (void)
              for (cand = regno_cands[src_regno];
                   cand != NULL;
                   cand = cand->next_regno_cand)
-               if (bitmap_bit_p (&avail_cands, cand->index))
+               if (bitmap_bit_p (avail_cands, cand->index)
+                   && bitmap_bit_p (active_cands, cand->index))
                  break;
            }
          int i, hard_regno, nregs;
+         int dst_hard_regno, dst_nregs;
          rtx_insn *remat_insn = NULL;
-         HOST_WIDE_INT cand_sp_offset = 0;
+         poly_int64 cand_sp_offset = 0;
          if (cand != NULL)
            {
              lra_insn_recog_data_t cand_id
@@ -1070,6 +1125,12 @@ do_remat (void)
              gcc_assert (REG_P (saved_op));
              int ignore_regno = REGNO (saved_op); 
 
+             dst_hard_regno = dst_regno < FIRST_PSEUDO_REGISTER
+               ? dst_regno : reg_renumber[dst_regno];
+             gcc_assert (dst_hard_regno >= 0);
+             machine_mode mode = GET_MODE (SET_DEST (set));
+             dst_nregs = hard_regno_nregs (dst_hard_regno, mode);
+
              for (reg = cand_id->regs; reg != NULL; reg = reg->next)
                if (reg->type != OP_IN && reg->regno != ignore_regno)
                  {
@@ -1080,6 +1141,10 @@ do_remat (void)
                        break;
                    if (i < nregs)
                      break;
+                   /* Ensure the clobber also doesn't overlap dst_regno.  */
+                   if (hard_regno + nregs > dst_hard_regno
+                       && hard_regno < dst_hard_regno + dst_nregs)
+                     break;
                  }
 
              if (reg == NULL)
@@ -1087,9 +1152,14 @@ do_remat (void)
                  for (reg = static_cand_id->hard_regs;
                       reg != NULL;
                       reg = reg->next)
-                   if (reg->type != OP_IN
-                       && TEST_HARD_REG_BIT (live_hard_regs, reg->regno))
-                     break;
+                   if (reg->type != OP_IN)
+                     {
+                       if (TEST_HARD_REG_BIT (live_hard_regs, reg->regno))
+                         break;
+                       if (reg->regno >= dst_hard_regno
+                           && reg->regno < dst_hard_regno + dst_nregs)
+                         break;
+                     }
                }
 
              if (reg == NULL)
@@ -1117,40 +1187,61 @@ do_remat (void)
          bitmap_clear (&temp_bitmap);
          /* Update avail_cands (see analogous code for
             calculate_gen_cands).  */
-         for (reg = id->regs; reg != NULL; reg = reg->next)
-           if (reg->type != OP_IN
-               || find_regno_note (insn, REG_DEAD, reg->regno) != NULL)
-             EXECUTE_IF_SET_IN_BITMAP (&avail_cands, 0, cid, bi)
+         for (iter = 0; iter < 2; iter++)
+           for (reg = (iter == 0 ? id->regs : static_id->hard_regs);
+                reg != NULL;
+                reg = reg->next)
+             if (reg->type != OP_IN
+                 || find_regno_note (insn, REG_DEAD, reg->regno) != NULL)
+               EXECUTE_IF_SET_IN_BITMAP (avail_cands, 0, cid, bi)
+                 {
+                   cand = all_cands[cid];
+                   
+                   /* Ignore the reload insn.  */
+                   if (src_regno == cand->reload_regno
+                       && dst_regno == cand->regno)
+                     continue;
+                   if (cand->regno == reg->regno
+                       || reg_overlap_for_remat_p (reg, cand->insn))
+                     bitmap_set_bit (&temp_bitmap, cand->index);
+                 }
+
+         if (CALL_P (insn))
+           {
+             function_abi callee_abi = insn_callee_abi (insn);
+             EXECUTE_IF_SET_IN_BITMAP (avail_cands, 0, cid, bi)
                {
                  cand = all_cands[cid];
-
-                 /* Ignore the reload insn.  */
-                 if (src_regno == cand->reload_regno
-                     && dst_regno == cand->regno)
-                   continue;
-                 if (cand->regno == reg->regno
-                     || input_regno_present_p (cand->insn, reg->regno))
+               
+                 if (call_used_input_regno_present_p (callee_abi, cand->insn))
                    bitmap_set_bit (&temp_bitmap, cand->index);
                }
+           }
 
-         if (CALL_P (insn))
-           EXECUTE_IF_SET_IN_BITMAP (&avail_cands, 0, cid, bi)
-             {
-               cand = all_cands[cid];
-               
-               if (call_used_input_regno_present_p (cand->insn))
-                 bitmap_set_bit (&temp_bitmap, cand->index);
-             }
+         bitmap_and_compl_into (avail_cands, &temp_bitmap);
+
+         /* Now see whether a candidate is made active or available
+            by this insn.  */
+         cand = insn_to_cand_activation[INSN_UID (insn)];
+         if (cand)
+           bitmap_set_bit (active_cands, cand->index);
+
+         cand = insn_to_cand[INSN_UID (insn)];
+         if (cand != NULL)
+           {
+             bitmap_set_bit (avail_cands, cand->index);
+             if (cand->reload_regno == -1)
+               bitmap_set_bit (active_cands, cand->index);
+             else
+               bitmap_clear_bit (active_cands, cand->index);
+           }
 
-         bitmap_and_compl_into (&avail_cands, &temp_bitmap);
-         if ((cand = insn_to_cand[INSN_UID (insn)]) != NULL)
-           bitmap_set_bit (&avail_cands, cand->index);
-           
          if (remat_insn != NULL)
            {
-             HOST_WIDE_INT sp_offset_change = cand_sp_offset - id->sp_offset;
-             if (sp_offset_change != 0)
+             poly_int64 sp_offset_change = cand_sp_offset - id->sp_offset;
+             if (maybe_ne (sp_offset_change, 0))
                change_sp_offset (remat_insn, sp_offset_change);
+             update_scratch_ops (remat_insn);
              lra_process_new_insns (insn, remat_insn, NULL,
                                     "Inserting rematerialization insn");
              lra_set_insn_deleted (insn);
@@ -1168,31 +1259,36 @@ do_remat (void)
                for (i = 0; i < nregs; i++)
                  CLEAR_HARD_REG_BIT (live_hard_regs, hard_regno + i);
              }
-           else if (reg->type != OP_IN
-                    && find_regno_note (insn, REG_UNUSED, reg->regno) == NULL)
+         /* Process also hard regs (e.g. CC register) which are part
+            of insn definition.  */
+         for (reg = static_id->hard_regs; reg != NULL; reg = reg->next)
+           if (reg->type == OP_IN
+               && find_regno_note (insn, REG_DEAD, reg->regno) != NULL)
+             CLEAR_HARD_REG_BIT (live_hard_regs, reg->regno);
+         /* Inputs have been processed, now process outputs.  */
+         for (reg = id->regs; reg != NULL; reg = reg->next)
+           if (reg->type != OP_IN
+               && find_regno_note (insn, REG_UNUSED, reg->regno) == NULL)
              {
                if ((hard_regno = get_hard_regs (reg, nregs)) < 0)
                  continue;
                for (i = 0; i < nregs; i++)
                  SET_HARD_REG_BIT (live_hard_regs, hard_regno + i);
              }
-         /* Process also hard regs (e.g. CC register) which are part
-            of insn definition.  */
          for (reg = static_id->hard_regs; reg != NULL; reg = reg->next)
-           if (reg->type == OP_IN
-               && find_regno_note (insn, REG_DEAD, reg->regno) != NULL)
-             CLEAR_HARD_REG_BIT (live_hard_regs, reg->regno);
-           else if (reg->type != OP_IN
-                    && find_regno_note (insn, REG_UNUSED, reg->regno) == NULL)
+           if (reg->type != OP_IN
+               && find_regno_note (insn, REG_UNUSED, reg->regno) == NULL)
              SET_HARD_REG_BIT (live_hard_regs, reg->regno);
        }
     }
-  bitmap_clear (&avail_cands);
   return changed_p;
 }
 
 \f
 
+/* Current number of rematerialization iteration.  */
+int lra_rematerialization_iter;
+
 /* Entry point of the rematerialization sub-pass.  Return true if we
    did any rematerialization.  */
 bool
@@ -1204,19 +1300,24 @@ lra_remat (void)
 
   if (! flag_lra_remat)
     return false;
+  lra_rematerialization_iter++;
+  if (lra_rematerialization_iter > LRA_MAX_REMATERIALIZATION_PASSES)
+    return false;
+  if (lra_dump_file != NULL)
+    fprintf (lra_dump_file,
+            "\n******** Rematerialization #%d: ********\n\n",
+            lra_rematerialization_iter);
   timevar_push (TV_LRA_REMAT);
   insn_to_cand = XCNEWVEC (cand_t, get_max_uid ());
+  insn_to_cand_activation = XCNEWVEC (cand_t, get_max_uid ());
   regno_cands = XCNEWVEC (cand_t, max_regno);
   all_cands.create (8000);
-  call_used_regs_arr_len = 0;
-  for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if (call_used_regs[i])
-      call_used_regs_arr[call_used_regs_arr_len++] = i;
   initiate_cand_table ();
-  create_cands ();
   create_remat_bb_data ();
   bitmap_initialize (&temp_bitmap, &reg_obstack);
+  bitmap_initialize (&subreg_regs, &reg_obstack);
   calculate_local_reg_remat_bb_data ();
+  create_cands ();
   calculate_livein_cands ();
   calculate_gen_cands ();
   bitmap_initialize (&all_blocks, &reg_obstack);
@@ -1227,11 +1328,13 @@ lra_remat (void)
   result = do_remat ();
   all_cands.release ();
   bitmap_clear (&temp_bitmap);
+  bitmap_clear (&subreg_regs);
   finish_remat_bb_data ();
   finish_cand_table ();
   bitmap_clear (&all_blocks);
   free (regno_cands);
   free (insn_to_cand);
+  free (insn_to_cand_activation);
   timevar_pop (TV_LRA_REMAT);
   return result;
 }