OSDN Git Service

PR rtl-optimization/21299
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index f426e1d..58f77cb 100644 (file)
@@ -87,7 +87,7 @@ static rtx *reg_last_reload_reg;
 
 /* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn
    for an output reload that stores into reg N.  */
-static char *reg_has_output_reload;
+static regset_head reg_has_output_reload;
 
 /* Indicates which hard regs are reload-registers for an output reload
    in the current insn.  */
@@ -123,6 +123,10 @@ rtx *reg_equiv_address;
    or zero if pseudo reg N is not equivalent to a memory slot.  */
 rtx *reg_equiv_mem;
 
+/* Element N is an EXPR_LIST of REG_EQUIVs containing MEMs with
+   alternate representations of the location of pseudo reg N.  */
+rtx *reg_equiv_alt_mem_list;
+
 /* Widest width in which each pseudo reg is referred to (via subreg).  */
 static unsigned int *reg_max_ref_width;
 
@@ -404,6 +408,7 @@ static void count_pseudo (int);
 static void order_regs_for_reload (struct insn_chain *);
 static void reload_as_needed (int);
 static void forget_old_reloads_1 (rtx, rtx, void *);
+static void forget_marked_reloads (regset);
 static int reload_reg_class_lower (const void *, const void *);
 static void mark_reload_reg_in_use (unsigned int, int, enum reload_type,
                                    enum machine_mode);
@@ -703,6 +708,7 @@ reload (rtx first, int global)
   reg_equiv_constant = XCNEWVEC (rtx, max_regno);
   reg_equiv_invariant = XCNEWVEC (rtx, max_regno);
   reg_equiv_mem = XCNEWVEC (rtx, max_regno);
+  reg_equiv_alt_mem_list = XCNEWVEC (rtx, max_regno);
   reg_equiv_address = XCNEWVEC (rtx, max_regno);
   reg_max_ref_width = XCNEWVEC (unsigned int, max_regno);
   reg_old_renumber = XCNEWVEC (short, max_regno);
@@ -1161,6 +1167,20 @@ reload (rtx first, int global)
       {
        rtx *pnote;
 
+       /* Clean up invalid ASMs so that they don't confuse later passes.
+          See PR 21299.  */
+       if (asm_noperands (PATTERN (insn)) >= 0)
+         {
+           extract_insn (insn);
+           if (!constrain_operands (1))
+             {
+               error_for_asm (insn,
+                              "%<asm%> operand has impossible constraints");
+               delete_insn (insn);
+               continue;
+             }
+         }
+
        if (CALL_P (insn))
          replace_pseudos_in (& CALL_INSN_FUNCTION_USAGE (insn),
                              VOIDmode, CALL_INSN_FUNCTION_USAGE (insn));
@@ -1260,6 +1280,11 @@ reload (rtx first, int global)
   if (offsets_at)
     free (offsets_at);
 
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (reg_equiv_alt_mem_list[i])
+      free_EXPR_LIST_list (&reg_equiv_alt_mem_list[i]);
+  free (reg_equiv_alt_mem_list);
+
   free (reg_equiv_mem);
   reg_equiv_init = 0;
   free (reg_equiv_address);
@@ -3878,7 +3903,7 @@ reload_as_needed (int live_known)
   memset (spill_reg_rtx, 0, sizeof spill_reg_rtx);
   memset (spill_reg_store, 0, sizeof spill_reg_store);
   reg_last_reload_reg = XCNEWVEC (rtx, max_regno);
-  reg_has_output_reload = XNEWVEC (char, max_regno);
+  INIT_REG_SET (&reg_has_output_reload);
   CLEAR_HARD_REG_SET (reg_reloaded_valid);
   CLEAR_HARD_REG_SET (reg_reloaded_call_part_clobbered);
 
@@ -3897,7 +3922,9 @@ reload_as_needed (int live_known)
 
       else if (INSN_P (insn))
        {
-         rtx oldpat = copy_rtx (PATTERN (insn));
+         regset_head regs_to_forget;
+         INIT_REG_SET (&regs_to_forget);
+         note_stores (PATTERN (insn), forget_old_reloads_1, &regs_to_forget);
 
          /* If this is a USE and CLOBBER of a MEM, ensure that any
             references to eliminable registers have been removed.  */
@@ -3918,6 +3945,7 @@ reload_as_needed (int live_known)
              if (NOTE_P (insn))
                {
                  update_eliminable_offsets ();
+                 CLEAR_REG_SET (&regs_to_forget);
                  continue;
                }
            }
@@ -3938,7 +3966,7 @@ reload_as_needed (int live_known)
             rtx's for those pseudo regs.  */
          else
            {
-             memset (reg_has_output_reload, 0, max_regno);
+             CLEAR_REG_SET (&reg_has_output_reload);
              CLEAR_HARD_REG_SET (reg_is_output_reload);
 
              find_reloads (insn, 1, spill_indirect_levels, live_known,
@@ -4004,7 +4032,8 @@ reload_as_needed (int live_known)
             for this insn in order to be stored in
             (obeying register constraints).  That is correct; such reload
             registers ARE still valid.  */
-         note_stores (oldpat, forget_old_reloads_1, NULL);
+         forget_marked_reloads (&regs_to_forget);
+         CLEAR_REG_SET (&regs_to_forget);
 
          /* There may have been CLOBBER insns placed after INSN.  So scan
             between INSN and NEXT and use them to forget old reloads.  */
@@ -4091,7 +4120,8 @@ reload_as_needed (int live_known)
                             the reload for inheritance.  */
                          SET_HARD_REG_BIT (reg_is_output_reload,
                                            REGNO (reload_reg));
-                         reg_has_output_reload[REGNO (XEXP (in_reg, 0))] = 1;
+                         SET_REGNO_REG_SET (&reg_has_output_reload,
+                                            REGNO (XEXP (in_reg, 0)));
                        }
                      else
                        forget_old_reloads_1 (XEXP (in_reg, 0), NULL_RTX,
@@ -4107,7 +4137,8 @@ reload_as_needed (int live_known)
                    {
                      SET_HARD_REG_BIT (reg_is_output_reload,
                                        REGNO (rld[i].reg_rtx));
-                     reg_has_output_reload[REGNO (XEXP (in_reg, 0))] = 1;
+                     SET_REGNO_REG_SET (&reg_has_output_reload,
+                                        REGNO (XEXP (in_reg, 0)));
                    }
                }
            }
@@ -4145,7 +4176,7 @@ reload_as_needed (int live_known)
 
   /* Clean up.  */
   free (reg_last_reload_reg);
-  free (reg_has_output_reload);
+  CLEAR_REG_SET (&reg_has_output_reload);
 }
 
 /* Discard all record of any value reloaded from X,
@@ -4153,14 +4184,18 @@ reload_as_needed (int live_known)
    unless X is an output reload reg of the current insn.
 
    X may be a hard reg (the reload reg)
-   or it may be a pseudo reg that was reloaded from.  */
+   or it may be a pseudo reg that was reloaded from.  
+
+   When DATA is non-NULL just mark the registers in regset
+   to be forgotten later.  */
 
 static void
 forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED,
-                     void *data ATTRIBUTE_UNUSED)
+                     void *data)
 {
   unsigned int regno;
   unsigned int nr;
+  regset regs = (regset) data;
 
   /* note_stores does give us subregs of hard regs,
      subreg_regno_offset requires a hard reg.  */
@@ -4188,26 +4223,58 @@ forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED,
         This can happen if a block-local pseudo is allocated to that reg
         and it wasn't spilled because this block's total need is 0.
         Then some insn might have an optional reload and use this reg.  */
-      for (i = 0; i < nr; i++)
-       /* But don't do this if the reg actually serves as an output
-          reload reg in the current instruction.  */
+      if (!regs)
+       for (i = 0; i < nr; i++)
+         /* But don't do this if the reg actually serves as an output
+            reload reg in the current instruction.  */
+         if (n_reloads == 0
+             || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i))
+           {
+             CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i);
+             CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + i);
+             spill_reg_store[regno + i] = 0;
+           }
+    }
+
+  if (regs)
+    while (nr-- > 0)
+      SET_REGNO_REG_SET (regs, regno + nr);
+  else
+    {
+      /* Since value of X has changed,
+        forget any value previously copied from it.  */
+
+      while (nr-- > 0)
+       /* But don't forget a copy if this is the output reload
+          that establishes the copy's validity.  */
        if (n_reloads == 0
-           || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i))
+           || !REGNO_REG_SET_P (&reg_has_output_reload, regno + nr))
+         reg_last_reload_reg[regno + nr] = 0;
+     }
+}
+
+/* Forget the reloads marked in regset by previous function.  */
+static void
+forget_marked_reloads (regset regs)
+{
+  unsigned int reg;
+  reg_set_iterator rsi;
+  EXECUTE_IF_SET_IN_REG_SET (regs, 0, reg, rsi)
+    {
+      if (reg < FIRST_PSEUDO_REGISTER
+         /* But don't do this if the reg actually serves as an output
+            reload reg in the current instruction.  */
+         && (n_reloads == 0
+             || ! TEST_HARD_REG_BIT (reg_is_output_reload, reg)))
          {
-           CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i);
-           CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + i);
-           spill_reg_store[regno + i] = 0;
+           CLEAR_HARD_REG_BIT (reg_reloaded_valid, reg);
+           CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, reg);
+           spill_reg_store[reg] = 0;
          }
+      if (n_reloads == 0
+         || !REGNO_REG_SET_P (&reg_has_output_reload, reg))
+       reg_last_reload_reg[reg] = 0;
     }
-
-  /* Since value of X has changed,
-     forget any value previously copied from it.  */
-
-  while (nr-- > 0)
-    /* But don't forget a copy if this is the output reload
-       that establishes the copy's validity.  */
-    if (n_reloads == 0 || reg_has_output_reload[regno + nr] == 0)
-      reg_last_reload_reg[regno + nr] = 0;
 }
 \f
 /* The following HARD_REG_SETs indicate when each hard register is
@@ -6035,7 +6102,8 @@ choose_reload_regs (struct insn_chain *chain)
            nr = hard_regno_nregs[nregno][rld[r].mode];
 
          while (--nr >= 0)
-           reg_has_output_reload[nregno + nr] = 1;
+           SET_REGNO_REG_SET (&reg_has_output_reload,
+                              nregno + nr);
 
          if (i >= 0)
            {
@@ -7225,7 +7293,7 @@ emit_reload_insns (struct insn_chain *chain)
 
          if (REG_P (reg)
              && REGNO (reg) >= FIRST_PSEUDO_REGISTER
-             && ! reg_has_output_reload[REGNO (reg)])
+             && !REGNO_REG_SET_P (&reg_has_output_reload, REGNO (reg)))
            {
              int nregno = REGNO (reg);
 
@@ -7336,9 +7404,11 @@ emit_reload_insns (struct insn_chain *chain)
                       && rld[r].in != 0
                       && ((REG_P (rld[r].in)
                            && REGNO (rld[r].in) >= FIRST_PSEUDO_REGISTER
-                           && ! reg_has_output_reload[REGNO (rld[r].in)])
+                           && !REGNO_REG_SET_P (&reg_has_output_reload,
+                                                REGNO (rld[r].in)))
                           || (REG_P (rld[r].in_reg)
-                              && ! reg_has_output_reload[REGNO (rld[r].in_reg)]))
+                              && !REGNO_REG_SET_P (&reg_has_output_reload,
+                                                   REGNO (rld[r].in_reg))))
                       && ! reg_set_p (rld[r].reg_rtx, PATTERN (insn)))
                {
                  int nregno;
@@ -7496,7 +7566,8 @@ emit_reload_insns (struct insn_chain *chain)
                  /* We have to set reg_has_output_reload here, or else 
                     forget_old_reloads_1 will clear reg_last_reload_reg
                     right away.  */
-                 reg_has_output_reload[nregno] = 1;
+                 SET_REGNO_REG_SET (&reg_has_output_reload,
+                                    nregno);
                }
            }
          else
@@ -7757,7 +7828,11 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
     }
   /* If IN is a simple operand, use gen_move_insn.  */
   else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
-    emit_insn (gen_move_insn (out, in));
+    {
+      tem = emit_insn (gen_move_insn (out, in));
+      /* IN may contain a LABEL_REF, if so add a REG_LABEL note.  */
+      mark_jump_label (in, tem, 0);
+    }
 
 #ifdef HAVE_reload_load_address
   else if (HAVE_reload_load_address)
@@ -7845,6 +7920,11 @@ delete_output_reload (rtx insn, int j, int last_reload_reg)
     n_occurrences += count_occurrences (PATTERN (insn),
                                        eliminate_regs (substed, 0,
                                                        NULL_RTX), 0);
+  for (i1 = reg_equiv_alt_mem_list [REGNO (reg)]; i1; i1 = XEXP (i1, 1))
+    {
+      gcc_assert (!rtx_equal_p (XEXP (i1, 0), substed));
+      n_occurrences += count_occurrences (PATTERN (insn), XEXP (i1, 0), 0);
+    }
   if (n_occurrences > n_inherited)
     return;
 
@@ -8111,7 +8191,7 @@ static rtx
 inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount)
 {
   /* REG or MEM to be copied and incremented.  */
-  rtx incloc = XEXP (value, 0);
+  rtx incloc = find_replacement (&XEXP (value, 0));
   /* Nonzero if increment after copying.  */
   int post = (GET_CODE (value) == POST_DEC || GET_CODE (value) == POST_INC
              || GET_CODE (value) == POST_MODIFY);
@@ -8120,7 +8200,7 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount)
   rtx add_insn;
   int code;
   rtx store;
-  rtx real_in = in == value ? XEXP (in, 0) : in;
+  rtx real_in = in == value ? incloc : in;
 
   /* No hard register is equivalent to this register after
      inc/dec operation.  If REG_LAST_RELOAD_REG were nonzero,
@@ -8132,7 +8212,7 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount)
   if (GET_CODE (value) == PRE_MODIFY || GET_CODE (value) == POST_MODIFY)
     {
       gcc_assert (GET_CODE (XEXP (value, 1)) == PLUS);
-      inc = XEXP (XEXP (value, 1), 1);
+      inc = find_replacement (&XEXP (XEXP (value, 1), 1));
     }
   else
     {