OSDN Git Service

PR rtl-opt/24160
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 16 Nov 2005 17:23:23 +0000 (17:23 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 16 Nov 2005 17:23:23 +0000 (17:23 +0000)
        PR target/24621
        * reload1.c (reg_equiv_invariant): New.
        (reload): Allocate, initialize, and free it.
        (calculate_needs_all_insns): Check it when skipping equivalence
        setting insns.
        (alter_reg): Likewise.
        (eliminate_regs_1): Rename from eliminate_regs.  Add new
        may_use_invariant argument; only use reg_equiv_invariant when true.
        (eliminate_regs): New.
        (eliminate_regs_in_insn): Use eliminate_regs_1; track when we're in
        a context for which may_use_invariant may be true.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@107093 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/reload1.c

index 8fb3e38..9c2d85a 100644 (file)
@@ -1,3 +1,20 @@
+2005-11-16  Richard Henderson  <rth@redhat.com>
+           J"orn Rennecke <joern.rennecke@st.com>
+           Ulrich Weigand  <uweigand@de.ibm.com>
+
+       PR rtl-opt/24160
+       PR target/24621
+       * reload1.c (reg_equiv_invariant): New.
+       (reload): Allocate, initialize, and free it.
+       (calculate_needs_all_insns): Check it when skipping equivalence
+       setting insns.
+       (alter_reg): Likewise.
+       (eliminate_regs_1): Rename from eliminate_regs.  Add new
+       may_use_invariant argument; only use reg_equiv_invariant when true.
+       (eliminate_regs): New.
+       (eliminate_regs_in_insn): Use eliminate_regs_1; track when we're in
+       a context for which may_use_invariant may be true.
+
 2005-11-16  Eric Botcazou  <ebotcazou@adacore.com>
 
        * fold-const.c (const_binop): Don't constant fold the operation
index d8eeb2a..ba395da 100644 (file)
@@ -96,6 +96,11 @@ static HARD_REG_SET reg_is_output_reload;
    with the constant it stands for.  */
 rtx *reg_equiv_constant;
 
+/* Element N is an invariant value to which pseudo reg N is equivalent.
+   eliminate_regs_in_insn uses this to replace pseudos in particular
+   contexts.  */
+rtx *reg_equiv_invariant;
+
 /* Element N is a memory location to which pseudo reg N is equivalent,
    prior to any register elimination (such as frame pointer to stack
    pointer).  Depending on whether or not it is a valid address, this value
@@ -693,6 +698,7 @@ reload (rtx first, int global)
      be substituted eventually by altering the REG-rtx's.  */
 
   reg_equiv_constant = xcalloc (max_regno, sizeof (rtx));
+  reg_equiv_invariant = xcalloc (max_regno, sizeof (rtx));
   reg_equiv_mem = xcalloc (max_regno, sizeof (rtx));
   reg_equiv_address = xcalloc (max_regno, sizeof (rtx));
   reg_max_ref_width = xcalloc (max_regno, sizeof (int));
@@ -762,13 +768,12 @@ reload (rtx first, int global)
                    {
                      /* This is PLUS of frame pointer and a constant,
                         and might be shared.  Unshare it.  */
-                     reg_equiv_constant[i] = copy_rtx (x);
+                     reg_equiv_invariant[i] = copy_rtx (x);
                      num_eliminable_invariants++;
                    }
-                 else if (x == frame_pointer_rtx
-                          || x == arg_pointer_rtx)
+                 else if (x == frame_pointer_rtx || x == arg_pointer_rtx)
                    {
-                     reg_equiv_constant[i] = x;
+                     reg_equiv_invariant[i] = x;
                      num_eliminable_invariants++;
                    }
                  else if (LEGITIMATE_CONSTANT_P (x))
@@ -1238,7 +1243,10 @@ reload (rtx first, int global)
   /* Indicate that we no longer have known memory locations or constants.  */
   if (reg_equiv_constant)
     free (reg_equiv_constant);
+  if (reg_equiv_invariant)
+    free (reg_equiv_invariant);
   reg_equiv_constant = 0;
+  reg_equiv_invariant = 0;
   VARRAY_GROW (reg_equiv_memory_loc_varray, 0);
   reg_equiv_memory_loc = 0;
 
@@ -1454,7 +1462,9 @@ calculate_needs_all_insns (int global)
          /* Skip insns that only set an equivalence.  */
          if (set && REG_P (SET_DEST (set))
              && reg_renumber[REGNO (SET_DEST (set))] < 0
-             && reg_equiv_constant[REGNO (SET_DEST (set))])
+             && (reg_equiv_constant[REGNO (SET_DEST (set))]
+                 || (reg_equiv_invariant[REGNO (SET_DEST (set))]))
+                     && reg_equiv_init[REGNO (SET_DEST (set))])
            continue;
 
          /* If needed, eliminate any eliminable registers.  */
@@ -1944,6 +1954,7 @@ alter_reg (int i, int from_reg)
   if (reg_renumber[i] < 0
       && REG_N_REFS (i) > 0
       && reg_equiv_constant[i] == 0
+      && (reg_equiv_invariant[i] == 0 || reg_equiv_init[i] == 0)
       && reg_equiv_memory_loc[i] == 0)
     {
       rtx x;
@@ -2252,8 +2263,9 @@ set_label_offsets (rtx x, rtx insn, int initial_p)
    encounter, return the actual location so that find_reloads will do
    the proper thing.  */
 
-rtx
-eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
+static rtx
+eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn,
+                 bool may_use_invariant)
 {
   enum rtx_code code = GET_CODE (x);
   struct elim_table *ep;
@@ -2296,10 +2308,16 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
 
        }
       else if (reg_renumber && reg_renumber[regno] < 0
-              && reg_equiv_constant && reg_equiv_constant[regno]
-              && ! CONSTANT_P (reg_equiv_constant[regno]))
-       return eliminate_regs (copy_rtx (reg_equiv_constant[regno]),
-                              mem_mode, insn);
+              && reg_equiv_invariant && reg_equiv_invariant[regno])
+       {
+         if (may_use_invariant)
+           return eliminate_regs_1 (copy_rtx (reg_equiv_invariant[regno]),
+                                    mem_mode, insn, true);
+         /* There exists at least one use of REGNO that cannot be
+            eliminated.  Prevent the defining insn from being deleted.  */
+         reg_equiv_init[regno] = NULL_RTX;
+         alter_reg (regno, -1);
+       }
       return x;
 
     /* You might think handling MINUS in a manner similar to PLUS is a
@@ -2359,8 +2377,8 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
         operand of a load-address insn.  */
 
       {
-       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn);
-       rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, insn);
+       rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true);
+       rtx new1 = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true);
 
        if (reg_renumber && (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)))
          {
@@ -2432,9 +2450,9 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
     case GE:       case GT:       case GEU:    case GTU:
     case LE:       case LT:       case LEU:    case LTU:
       {
-       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn);
-       rtx new1
-         = XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, insn) : 0;
+       rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false);
+       rtx new1 = XEXP (x, 1)
+                  ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, false) : 0;
 
        if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
          return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1);
@@ -2445,7 +2463,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
       /* If we have something in XEXP (x, 0), the usual case, eliminate it.  */
       if (XEXP (x, 0))
        {
-         new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+         new = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true);
          if (new != XEXP (x, 0))
            {
              /* If this is a REG_DEAD note, it is not valid anymore.
@@ -2453,7 +2471,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
                 REG_DEAD note for the stack or frame pointer.  */
              if (GET_MODE (x) == REG_DEAD)
                return (XEXP (x, 1)
-                       ? eliminate_regs (XEXP (x, 1), mem_mode, insn)
+                       ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true)
                        : NULL_RTX);
 
              x = gen_rtx_EXPR_LIST (REG_NOTE_KIND (x), new, XEXP (x, 1));
@@ -2468,7 +2486,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
         strictly needed, but it simplifies the code.  */
       if (XEXP (x, 1))
        {
-         new = eliminate_regs (XEXP (x, 1), mem_mode, insn);
+         new = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true);
          if (new != XEXP (x, 1))
            return
              gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new);
@@ -2492,7 +2510,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
     case CTZ:
     case POPCOUNT:
     case PARITY:
-      new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+      new = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false);
       if (new != XEXP (x, 0))
        return gen_rtx_fmt_e (code, GET_MODE (x), new);
       return x;
@@ -2513,7 +2531,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
          new = SUBREG_REG (x);
        }
       else
-       new = eliminate_regs (SUBREG_REG (x), mem_mode, insn);
+       new = eliminate_regs_1 (SUBREG_REG (x), mem_mode, insn, false);
 
       if (new != SUBREG_REG (x))
        {
@@ -2549,12 +2567,12 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
         case more efficiently.  */
       return
        replace_equiv_address_nv (x,
-                                 eliminate_regs (XEXP (x, 0),
-                                                 GET_MODE (x), insn));
+                                 eliminate_regs_1 (XEXP (x, 0), GET_MODE (x),
+                                                   insn, true));
 
     case USE:
       /* Handle insn_list USE that a call to a pure function may generate.  */
-      new = eliminate_regs (XEXP (x, 0), 0, insn);
+      new = eliminate_regs_1 (XEXP (x, 0), 0, insn, false);
       if (new != XEXP (x, 0))
        return gen_rtx_USE (GET_MODE (x), new);
       return x;
@@ -2575,7 +2593,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
     {
       if (*fmt == 'e')
        {
-         new = eliminate_regs (XEXP (x, i), mem_mode, insn);
+         new = eliminate_regs_1 (XEXP (x, i), mem_mode, insn, false);
          if (new != XEXP (x, i) && ! copied)
            {
              rtx new_x = rtx_alloc (code);
@@ -2590,7 +2608,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
          int copied_vec = 0;
          for (j = 0; j < XVECLEN (x, i); j++)
            {
-             new = eliminate_regs (XVECEXP (x, i, j), mem_mode, insn);
+             new = eliminate_regs_1 (XVECEXP (x, i, j), mem_mode, insn, false);
              if (new != XVECEXP (x, i, j) && ! copied_vec)
                {
                  rtvec new_v = gen_rtvec_v (XVECLEN (x, i),
@@ -2613,6 +2631,12 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
   return x;
 }
 
+rtx
+eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
+{
+  return eliminate_regs_1 (x, mem_mode, insn, false);
+}
+
 /* Scan rtx X for modifications of elimination target registers.  Update
    the table of eliminables to reflect the changed state.  MEM_MODE is
    the mode of an enclosing MEM rtx, or VOIDmode if not within a MEM.  */
@@ -2870,7 +2894,7 @@ eliminate_regs_in_insn (rtx insn, int replace)
   rtx substed_operand[MAX_RECOG_OPERANDS];
   rtx orig_operand[MAX_RECOG_OPERANDS];
   struct elim_table *ep;
-  rtx plus_src;
+  rtx plus_src, plus_cst_src;
 
   if (! insn_is_asm && icode < 0)
     {
@@ -2975,16 +2999,19 @@ eliminate_regs_in_insn (rtx insn, int replace)
   /* We allow one special case which happens to work on all machines we
      currently support: a single set with the source or a REG_EQUAL
      note being a PLUS of an eliminable register and a constant.  */
-  plus_src = 0;
+  plus_src = plus_cst_src = 0;
   if (old_set && REG_P (SET_DEST (old_set)))
     {
-      /* First see if the source is of the form (plus (reg) CST).  */
-      if (GET_CODE (SET_SRC (old_set)) == PLUS
-         && REG_P (XEXP (SET_SRC (old_set), 0))
-         && GET_CODE (XEXP (SET_SRC (old_set), 1)) == CONST_INT
-         && REGNO (XEXP (SET_SRC (old_set), 0)) < FIRST_PSEUDO_REGISTER)
+      if (GET_CODE (SET_SRC (old_set)) == PLUS)
        plus_src = SET_SRC (old_set);
-      else if (REG_P (SET_SRC (old_set)))
+      /* First see if the source is of the form (plus (reg) CST).  */
+      if (plus_src
+         && REG_P (XEXP (plus_src, 0))
+         && GET_CODE (XEXP (plus_src, 1)) == CONST_INT
+         && REGNO (XEXP (plus_src, 0)) < FIRST_PSEUDO_REGISTER)
+       plus_cst_src = plus_src;
+      else if (REG_P (SET_SRC (old_set))
+              || plus_src)
        {
          /* Otherwise, see if we have a REG_EQUAL note of the form
             (plus (reg) CST).  */
@@ -2997,16 +3024,16 @@ eliminate_regs_in_insn (rtx insn, int replace)
                  && GET_CODE (XEXP (XEXP (links, 0), 1)) == CONST_INT
                  && REGNO (XEXP (XEXP (links, 0), 0)) < FIRST_PSEUDO_REGISTER)
                {
-                 plus_src = XEXP (links, 0);
+                 plus_cst_src = XEXP (links, 0);
                  break;
                }
            }
        }
     }
-  if (plus_src)
+  if (plus_cst_src)
     {
-      rtx reg = XEXP (plus_src, 0);
-      HOST_WIDE_INT offset = INTVAL (XEXP (plus_src, 1));
+      rtx reg = XEXP (plus_cst_src, 0);
+      HOST_WIDE_INT offset = INTVAL (XEXP (plus_cst_src, 1));
 
       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
        if (ep->from_rtx == reg && ep->can_eliminate)
@@ -3038,9 +3065,9 @@ eliminate_regs_in_insn (rtx insn, int replace)
            /* If we have a nonzero offset, and the source is already
               a simple REG, the following transformation would
               increase the cost of the insn by replacing a simple REG
-              with (plus (reg sp) CST).  So try only when plus_src
-              comes from old_set proper, not REG_NOTES.  */
-           else if (SET_SRC (old_set) == plus_src)
+              with (plus (reg sp) CST).  So try only when we already
+              had a PLUS before.  */
+           else if (plus_src)
              {
                new_body = old_body;
                if (! replace)
@@ -3079,6 +3106,8 @@ eliminate_regs_in_insn (rtx insn, int replace)
       /* For an asm statement, every operand is eliminable.  */
       if (insn_is_asm || insn_data[icode].operand[i].eliminable)
        {
+         bool is_set_src, in_plus;
+
          /* Check for setting a register that we know about.  */
          if (recog_data.operand_type[i] != OP_IN
              && REG_P (orig_operand[i]))
@@ -3093,8 +3122,21 @@ eliminate_regs_in_insn (rtx insn, int replace)
                  ep->can_eliminate = 0;
            }
 
-         substed_operand[i] = eliminate_regs (recog_data.operand[i], 0,
-                                              replace ? insn : NULL_RTX);
+         /* Companion to the above plus substitution, we can allow
+            invariants as the source of a plain move.  */
+         is_set_src = false;
+         if (old_set && recog_data.operand_loc[i] == &SET_SRC (old_set))
+           is_set_src = true;
+         in_plus = false;
+         if (plus_src
+             && (recog_data.operand_loc[i] == &XEXP (plus_src, 0)
+                 || recog_data.operand_loc[i] == &XEXP (plus_src, 1)))
+           in_plus = true;
+
+         substed_operand[i]
+           = eliminate_regs_1 (recog_data.operand[i], 0,
+                               replace ? insn : NULL_RTX,
+                               is_set_src || in_plus);
          if (substed_operand[i] != orig_operand[i])
            val = 1;
          /* Terminate the search in check_eliminable_occurrences at
@@ -3222,7 +3264,8 @@ eliminate_regs_in_insn (rtx insn, int replace)
      of spill registers to be needed in the final reload pass than in
      the pre-passes.  */
   if (val && REG_NOTES (insn) != 0)
-    REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, REG_NOTES (insn));
+    REG_NOTES (insn)
+      = eliminate_regs_1 (REG_NOTES (insn), 0, REG_NOTES (insn), true);
 
   return val;
 }