OSDN Git Service

* pa.c (legitimize_pic_address): Use gcc_assert instead of abort.
[pf3gnuchains/gcc-fork.git] / gcc / regmove.c
index f309f21..08cacf4 100644 (file)
@@ -1,6 +1,6 @@
 /* Move registers around to reduce number of move instructions needed.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 /* This module looks for cases where matching constraints would force
@@ -43,6 +43,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "except.h"
 #include "toplev.h"
 #include "reload.h"
+#include "timevar.h"
+#include "tree-pass.h"
 
 
 /* Turn STACK_GROWS_DOWNWARD into a boolean.  */
@@ -135,7 +137,7 @@ try_auto_increment (rtx insn, rtx inc_insn, rtx inc_insn_set, rtx reg,
                  /* If there is a REG_DEAD note on this insn, we must
                     change this not to REG_UNUSED meaning that the register
                     is set, but the value is dead.  Failure to do so will
-                    result in a sched1 abort -- when it recomputes lifetime
+                    result in a sched1 dieing -- when it recomputes lifetime
                     information, the number of REG_DEAD notes will have
                     changed.  */
                  rtx note = find_reg_note (insn, REG_DEAD, reg);
@@ -266,7 +268,7 @@ mark_flags_life_zones (rtx flags)
       {
        int i;
        for (i = 0; i < flags_nregs; ++i)
-         live |= REGNO_REG_SET_P (block->global_live_at_start,
+         live |= REGNO_REG_SET_P (block->il.rtl->global_live_at_start,
                                   flags_regno + i);
       }
 #endif
@@ -431,6 +433,9 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
          || (sregno < FIRST_PSEUDO_REGISTER
              && asm_noperands (PATTERN (p)) >= 0
              && reg_overlap_mentioned_p (src, PATTERN (p)))
+         /* Don't change hard registers used by a call.  */
+         || (CALL_P (p) && sregno < FIRST_PSEUDO_REGISTER
+             && find_reg_fusage (p, USE, src))
          /* Don't change a USE of a register.  */
          || (GET_CODE (PATTERN (p)) == USE
              && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
@@ -491,7 +496,7 @@ optimize_reg_copy_1 (rtx insn, rtx dest, rtx src)
 
              /* If the insn in which SRC dies is a CALL_INSN, don't count it
                 as a call that has been crossed.  Otherwise, count it.  */
-             if (q != p && GET_CODE (q) == CALL_INSN)
+             if (q != p && CALL_P (q))
                {
                  /* Similarly, total calls for SREGNO, total calls beyond
                     the death note for DREGNO.  */
@@ -620,7 +625,7 @@ optimize_reg_copy_2 (rtx insn, rtx dest, rtx src)
                  PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
 
 
-             if (GET_CODE (q) == CALL_INSN)
+             if (CALL_P (q))
                {
                  REG_N_CALLS_CROSSED (dregno)--;
                  REG_N_CALLS_CROSSED (sregno)++;
@@ -636,7 +641,7 @@ optimize_reg_copy_2 (rtx insn, rtx dest, rtx src)
 
       if (reg_set_p (src, p)
          || find_reg_note (p, REG_DEAD, dest)
-         || (GET_CODE (p) == CALL_INSN && REG_N_CALLS_CROSSED (sregno) == 0))
+         || (CALL_P (p) && REG_N_CALLS_CROSSED (sregno) == 0))
        break;
     }
 }
@@ -652,7 +657,7 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src)
   rtx src_reg = XEXP (src, 0);
   int src_no = REGNO (src_reg);
   int dst_no = REGNO (dest);
-  rtx p, set, subreg;
+  rtx p, set;
   enum machine_mode old_mode;
 
   if (src_no < FIRST_PSEUDO_REGISTER
@@ -671,7 +676,7 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src)
     return;
 
   if (! (set = single_set (p))
-      || GET_CODE (SET_SRC (set)) != MEM
+      || !MEM_P (SET_SRC (set))
       /* If there's a REG_EQUIV note, this must be an insn that loads an
         argument.  Prefer keeping the note over doing this optimization.  */
       || find_reg_note (p, REG_EQUIV, NULL_RTX)
@@ -700,14 +705,15 @@ optimize_reg_copy_3 (rtx insn, rtx dest, rtx src)
 
   /* Now walk forward making additional replacements.  We want to be able
      to undo all the changes if a later substitution fails.  */
-  subreg = gen_lowpart_SUBREG (old_mode, src_reg);
   while (p = NEXT_INSN (p), p != insn)
     {
       if (! INSN_P (p))
        continue;
 
       /* Make a tentative change.  */
-      validate_replace_rtx_group (src_reg, subreg, p);
+      validate_replace_rtx_group (src_reg,
+                                 gen_lowpart_SUBREG (old_mode, src_reg),
+                                 p);
     }
 
   validate_replace_rtx_group (src, src_reg, insn);
@@ -755,7 +761,6 @@ copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid)
   if (REG_P (src)
       && REG_LIVE_LENGTH (REGNO (src)) > 0
       && REG_P (dest)
-      && !RTX_UNCHANGING_P (dest)
       && REG_LIVE_LENGTH (REGNO (dest)) > 0
       && (set = single_set (insn)) != NULL_RTX
       && !reg_mentioned_p (dest, SET_SRC (set))
@@ -831,9 +836,6 @@ copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid)
 
       if (REGNO_LAST_UID (src_regno) == insn_uid)
        REGNO_LAST_UID (src_regno) = move_uid;
-
-      if (REGNO_LAST_NOTE_UID (src_regno) == insn_uid)
-       REGNO_LAST_NOTE_UID (src_regno) = move_uid;
     }
 }
 
@@ -971,8 +973,8 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset, FILE *regmove_dump_file)
 #ifdef AUTO_INC_DEC
              for (p = PREV_INSN (insn); p; p = PREV_INSN (p))
                {
-                 if (GET_CODE (p) == CODE_LABEL
-                     || GET_CODE (p) == JUMP_INSN)
+                 if (LABEL_P (p)
+                     || JUMP_P (p))
                    break;
                  if (! INSN_P (p))
                    continue;
@@ -985,8 +987,8 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset, FILE *regmove_dump_file)
                }
              for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
                {
-                 if (GET_CODE (p) == CODE_LABEL
-                     || GET_CODE (p) == JUMP_INSN)
+                 if (LABEL_P (p)
+                     || JUMP_P (p))
                    break;
                  if (! INSN_P (p))
                    continue;
@@ -1010,7 +1012,7 @@ fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset, FILE *regmove_dump_file)
       /* reg_set_p is overly conservative for CALL_INSNS, thinks that all
         hard regs are clobbered.  Thus, we only use it for src for
         non-call insns.  */
-      if (GET_CODE (p) == CALL_INSN)
+      if (CALL_P (p))
        {
          if (! dst_death)
            num_calls++;
@@ -1150,10 +1152,11 @@ regmove_optimize (rtx f, int nregs, FILE *regmove_dump_file)
                  && GET_MODE_SIZE (GET_MODE (dst))
                     >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dst))))
                {
-                 src_subreg
-                   = gen_rtx_SUBREG (GET_MODE (SUBREG_REG (dst)),
-                                     src, SUBREG_BYTE (dst));
                  dst = SUBREG_REG (dst);
+                 src_subreg = lowpart_subreg (GET_MODE (dst),
+                                              src, GET_MODE (src));
+                 if (!src_subreg)
+                   continue;
                }
              if (!REG_P (dst)
                  || REGNO (dst) < FIRST_PSEUDO_REGISTER)
@@ -1259,7 +1262,6 @@ regmove_optimize (rtx f, int nregs, FILE *regmove_dump_file)
              if (!REG_P (dst)
                  || REGNO (dst) < FIRST_PSEUDO_REGISTER
                  || REG_LIVE_LENGTH (REGNO (dst)) < 0
-                 || RTX_UNCHANGING_P (dst)
                  || GET_MODE (src) != GET_MODE (dst))
                continue;
 
@@ -1423,7 +1425,7 @@ regmove_optimize (rtx f, int nregs, FILE *regmove_dump_file)
                  /* If we have passed a call instruction, and the
                     pseudo-reg DST is not already live across a call,
                     then don't perform the optimization.  */
-                 if (GET_CODE (p) == CALL_INSN)
+                 if (CALL_P (p))
                    {
                      num_calls++;
 
@@ -1654,12 +1656,6 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst,
   rtx src_note = find_reg_note (insn, REG_DEAD, src), dst_note = NULL_RTX;
   int length, s_length;
 
-  /* If SRC is marked as unchanging, we may not change it.
-     ??? Maybe we could get better code by removing the unchanging bit
-     instead, and changing it back if we don't succeed?  */
-  if (RTX_UNCHANGING_P (src))
-    return 0;
-
   if (! src_note)
     {
       /* Look for (set (regX) (op regA constX))
@@ -1702,7 +1698,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst,
 
   for (length = s_length = 0, p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
     {
-      if (GET_CODE (p) == CALL_INSN)
+      if (CALL_P (p))
        replace_in_call_usage (& CALL_INSN_FUNCTION_USAGE (p),
                               REGNO (dst), src, p);
 
@@ -1839,7 +1835,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst,
 
       /* If we have passed a call instruction, and the pseudo-reg SRC is not
         already live across a call, then don't perform the optimization.  */
-      if (GET_CODE (p) == CALL_INSN)
+      if (CALL_P (p))
        {
          if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
            break;
@@ -1930,7 +1926,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst,
                  q = 0;
                  break;
                }
-             if (GET_CODE (p) == CALL_INSN)
+             if (CALL_P (p))
                num_calls2++;
            }
          if (q && set2 && SET_DEST (set2) == src && CONSTANT_P (SET_SRC (set2))
@@ -2036,10 +2032,7 @@ fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst,
    mentioning SRC or mentioning / changing DST .  If in doubt, presume
    it is unstable.
    The rationale is that we want to check if we can move an insn easily
-   while just paying attention to SRC and DST.  A register is considered
-   stable if it has the RTX_UNCHANGING_P bit set, but that would still
-   leave the burden to update REG_DEAD / REG_UNUSED notes, so we don't
-   want any registers but SRC and DST.  */
+   while just paying attention to SRC and DST.  */
 static int
 stable_and_no_regs_but_for_p (rtx x, rtx src, rtx dst)
 {
@@ -2134,7 +2127,7 @@ combine_stack_adjustments (void)
 static int
 stack_memref_p (rtx x)
 {
-  if (GET_CODE (x) != MEM)
+  if (!MEM_P (x))
     return 0;
   x = XEXP (x, 0);
 
@@ -2159,7 +2152,7 @@ single_set_for_csa (rtx insn)
   if (tmp)
     return tmp;
 
-  if (GET_CODE (insn) != INSN
+  if (!NONJUMP_INSN_P (insn)
       || GET_CODE (PATTERN (insn)) != PARALLEL)
     return NULL_RTX;
 
@@ -2411,7 +2404,7 @@ combine_stack_adjustments_for_block (basic_block bb)
             turn it into a direct store.  Obviously we can't do this if
             there were any intervening uses of the stack pointer.  */
          if (memlist == NULL
-             && GET_CODE (dest) == MEM
+             && MEM_P (dest)
              && ((GET_CODE (XEXP (dest, 0)) == PRE_DEC
                   && (last_sp_adjust
                       == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest))))
@@ -2441,7 +2434,7 @@ combine_stack_adjustments_for_block (basic_block bb)
 
       data.insn = insn;
       data.memlist = memlist;
-      if (GET_CODE (insn) != CALL_INSN && last_sp_set
+      if (!CALL_P (insn) && last_sp_set
          && !for_each_rtx (&PATTERN (insn), record_stack_memrefs, &data))
        {
           memlist = data.memlist;
@@ -2452,7 +2445,7 @@ combine_stack_adjustments_for_block (basic_block bb)
       /* Otherwise, we were not able to process the instruction.
         Do not continue collecting data across such a one.  */
       if (last_sp_set
-         && (GET_CODE (insn) == CALL_INSN
+         && (CALL_P (insn)
              || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
        {
          if (last_sp_set && last_sp_adjust == 0)
@@ -2466,4 +2459,84 @@ combine_stack_adjustments_for_block (basic_block bb)
 
   if (last_sp_set && last_sp_adjust == 0)
     delete_insn (last_sp_set);
+
+  if (memlist)
+    free_csa_memlist (memlist);
+}
+\f
+static bool
+gate_handle_regmove (void)
+{
+  return (optimize > 0 && flag_regmove);
 }
+
+
+/* Register allocation pre-pass, to reduce number of moves necessary
+   for two-address machines.  */
+static void
+rest_of_handle_regmove (void)
+{
+  regmove_optimize (get_insns (), max_reg_num (), dump_file);
+  cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
+}
+
+struct tree_opt_pass pass_regmove =
+{
+  "regmove",                            /* name */
+  gate_handle_regmove,                  /* gate */
+  rest_of_handle_regmove,               /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_REGMOVE,                           /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  'N'                                   /* letter */
+};
+
+
+static bool
+gate_handle_stack_adjustments (void)
+{
+  return (optimize > 0);
+}
+
+static void
+rest_of_handle_stack_adjustments (void)
+{
+  life_analysis (dump_file, PROP_POSTRELOAD);
+  cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE
+               | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
+
+  /* This is kind of a heuristic.  We need to run combine_stack_adjustments
+     even for machines with possibly nonzero RETURN_POPS_ARGS
+     and ACCUMULATE_OUTGOING_ARGS.  We expect that only ports having
+     push instructions will have popping returns.  */
+#ifndef PUSH_ROUNDING
+  if (!ACCUMULATE_OUTGOING_ARGS)
+#endif
+    combine_stack_adjustments ();
+}
+
+struct tree_opt_pass pass_stack_adjustments =
+{
+  NULL,                                 /* name */
+  gate_handle_stack_adjustments,        /* gate */
+  rest_of_handle_stack_adjustments,     /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  0,                                    /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  0                                     /* letter */
+};
+