OSDN Git Service

* decl2.c: Include "timevar.h".
[pf3gnuchains/gcc-fork.git] / gcc / regmove.c
index 31b9355..3553a40 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 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -27,6 +27,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h" /* stdio.h must precede rtl.h for FFS.  */
 #include "tm_p.h"
 #include "insn-config.h"
@@ -80,7 +82,7 @@ static int regclass_compatible_p PARAMS ((int, int));
 static int replacement_quality PARAMS ((rtx));
 static int fixup_match_2 PARAMS ((rtx, rtx, rtx, rtx, FILE *));
 
-/* Return non-zero if registers with CLASS1 and CLASS2 can be merged without
+/* Return nonzero if registers with CLASS1 and CLASS2 can be merged without
    causing too much register allocation problems.  */
 static int
 regclass_compatible_p (class0, class1)
@@ -111,7 +113,7 @@ try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre)
       /* Can't use the size of SET_SRC, we might have something like
         (sign_extend:SI (mem:QI ...  */
       rtx use = find_use_as_address (pset, reg, 0);
-      if (use != 0 && use != (rtx) 1)
+      if (use != 0 && use != (rtx) (size_t) 1)
        {
          int size = GET_MODE_SIZE (GET_MODE (use));
          if (0
@@ -223,7 +225,7 @@ mark_flags_life_zones (flags)
 {
   int flags_regno;
   int flags_nregs;
-  int block;
+  basic_block block;
 
 #ifdef HAVE_cc0
   /* If we found a flags register on a cc0 host, bail.  */
@@ -239,7 +241,7 @@ mark_flags_life_zones (flags)
     {
       enum machine_mode mode = (flags ? HImode : VOIDmode);
       rtx insn;
-      for (insn = get_insns(); insn; insn = NEXT_INSN (insn))
+      for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
        PUT_MODE (insn, mode);
       return;
     }
@@ -254,13 +256,13 @@ mark_flags_life_zones (flags)
   flags_set_1_rtx = flags;
 
   /* Process each basic block.  */
-  for (block = n_basic_blocks - 1; block >= 0; block--)
+  FOR_EACH_BB_REVERSE (block)
     {
       rtx insn, end;
       int live;
 
-      insn = BLOCK_HEAD (block);
-      end = BLOCK_END (block);
+      insn = block->head;
+      end = block->end;
 
       /* Look out for the (unlikely) case of flags being live across
         basic block boundaries.  */
@@ -269,7 +271,7 @@ mark_flags_life_zones (flags)
       {
        int i;
        for (i = 0; i < flags_nregs; ++i)
-          live |= REGNO_REG_SET_P (BASIC_BLOCK (block)->global_live_at_start,
+         live |= REGNO_REG_SET_P (block->global_live_at_start,
                                   flags_regno + i);
       }
 #endif
@@ -334,7 +336,7 @@ static int *regno_src_regno;
    a candidate for tying to a hard register, since the output might in
    turn be a candidate to be tied to a different hard register.  */
 static int
-replacement_quality(reg)
+replacement_quality (reg)
      rtx reg;
 {
   int src_regno;
@@ -645,7 +647,7 @@ optimize_reg_copy_2 (insn, dest, src)
 }
 /* INSN is a ZERO_EXTEND or SIGN_EXTEND of SRC to DEST.
    Look if SRC dies there, and if it is only set once, by loading
-   it from memory.  If so, try to encorporate the zero/sign extension
+   it from memory.  If so, try to incorporate the zero/sign extension
    into the memory read, change SRC to the mode of DEST, and alter
    the remaining accesses to use the appropriate SUBREG.  This allows
    SRC and DEST to be tied later.  */
@@ -664,6 +666,7 @@ optimize_reg_copy_3 (insn, dest, src)
   if (src_no < FIRST_PSEUDO_REGISTER
       || dst_no < FIRST_PSEUDO_REGISTER
       || ! find_reg_note (insn, REG_DEAD, src_reg)
+      || REG_N_DEATHS (src_no) != 1
       || REG_N_SETS (src_no) != 1)
     return;
   for (p = PREV_INSN (insn); p && ! reg_set_p (src_reg, p); p = PREV_INSN (p))
@@ -683,7 +686,7 @@ optimize_reg_copy_3 (insn, dest, src)
       || SET_DEST (set) != src_reg)
     return;
 
-  /* Be conserative: although this optimization is also valid for
+  /* Be conservative: although this optimization is also valid for
      volatile memory references, that could cause trouble in later passes.  */
   if (MEM_VOLATILE_P (SET_SRC (set)))
     return;
@@ -775,7 +778,7 @@ copy_src_to_dest (insn, src, dest, old_max_uid)
       /* Generate the src->dest move.  */
       start_sequence ();
       emit_move_insn (dest, src);
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
       /* If this sequence uses new registers, we may not use it.  */
       if (old_num_regs != reg_rtx_no
@@ -792,7 +795,7 @@ copy_src_to_dest (insn, src, dest, old_max_uid)
       p_move_notes = &REG_NOTES (move_insn);
       p_insn_notes = &REG_NOTES (insn);
 
-      /* Move any notes mentioning src to the move instruction */
+      /* Move any notes mentioning src to the move instruction */
       for (link = REG_NOTES (insn); link != NULL_RTX; link = next)
        {
          next = XEXP (link, 1);
@@ -811,7 +814,7 @@ copy_src_to_dest (insn, src, dest, old_max_uid)
       *p_move_notes = NULL_RTX;
       *p_insn_notes = NULL_RTX;
 
-      /* Is the insn the head of a basic block?  If so extend it */
+      /* Is the insn the head of a basic block?  If so extend it */
       insn_uid = INSN_UID (insn);
       move_uid = INSN_UID (move_insn);
       if (insn_uid < old_max_uid)
@@ -922,7 +925,7 @@ reg_is_remote_constant_p (reg, insn, first)
      (set (reg100) (plus reg100 offset2-offset1))  */
 
 /* ??? What does this comment mean?  */
-/* cse disrupts preincrement / postdecrement squences when it finds a
+/* cse disrupts preincrement / postdecrement sequences when it finds a
    hard register as ultimate source, like the frame pointer.  */
 
 static int
@@ -950,7 +953,7 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
       if (perhaps_ends_bb_p (p))
        break;
       else if (! INSN_P (p))
-        continue;
+       continue;
 
       if (find_regno_note (p, REG_DEAD, REGNO (dst)))
        dst_death = p;
@@ -962,7 +965,7 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
          && GET_CODE (SET_SRC (pset)) == PLUS
          && XEXP (SET_SRC (pset), 0) == src
          && GET_CODE (XEXP (SET_SRC (pset), 1)) == CONST_INT)
-        {
+       {
          HOST_WIDE_INT newconst
            = INTVAL (offset) - INTVAL (XEXP (SET_SRC (pset), 1));
          rtx add = gen_add3_insn (dst, dst, GEN_INT (newconst));
@@ -1013,10 +1016,10 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
 #endif
              return 1;
            }
-        }
+       }
 
       if (reg_set_p (dst, PATTERN (p)))
-        break;
+       break;
 
       /* If we have passed a call instruction, and the
          pseudo-reg SRC is not already live across a call,
@@ -1025,19 +1028,19 @@ fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
         hard regs are clobbered.  Thus, we only use it for src for
         non-call insns.  */
       if (GET_CODE (p) == CALL_INSN)
-        {
+       {
          if (! dst_death)
            num_calls++;
 
-          if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
-            break;
+         if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
+           break;
 
          if (call_used_regs [REGNO (dst)]
              || find_reg_fusage (p, CLOBBER, dst))
            break;
-        }
+       }
       else if (reg_set_p (src, PATTERN (p)))
-        break;
+       break;
     }
 
   return 0;
@@ -1061,6 +1064,7 @@ regmove_optimize (f, nregs, regmove_dump_file)
   int pass;
   int i;
   rtx copy_src, copy_dst;
+  basic_block bb;
 
   /* ??? Hack.  Regmove doesn't examine the CFG, and gets mightily
      confused by non-call exceptions ending blocks.  */
@@ -1068,7 +1072,7 @@ regmove_optimize (f, nregs, regmove_dump_file)
     return;
 
   /* Find out where a potential flags register is live, and so that we
-     can supress some optimizations in those zones.  */
+     can suppress some optimizations in those zones.  */
   mark_flags_life_zones (discover_flags_reg ());
 
   regno_src_regno = (int *) xmalloc (sizeof *regno_src_regno * nregs);
@@ -1076,8 +1080,8 @@ regmove_optimize (f, nregs, regmove_dump_file)
 
   regmove_bb_head = (int *) xmalloc (sizeof (int) * (old_max_uid + 1));
   for (i = old_max_uid; i >= 0; i--) regmove_bb_head[i] = -1;
-  for (i = 0; i < n_basic_blocks; i++)
-    regmove_bb_head[INSN_UID (BLOCK_HEAD (i))] = i;
+  FOR_EACH_BB (bb)
+    regmove_bb_head[INSN_UID (bb->head)] = bb->index;
 
   /* A forward/backward pass.  Replace output operands with input operands.  */
 
@@ -1104,12 +1108,12 @@ regmove_optimize (f, nregs, regmove_dump_file)
              && (GET_CODE (SET_SRC (set)) == SIGN_EXTEND
                  || GET_CODE (SET_SRC (set)) == ZERO_EXTEND)
              && GET_CODE (XEXP (SET_SRC (set), 0)) == REG
-             && GET_CODE (SET_DEST(set)) == REG)
+             && GET_CODE (SET_DEST (set)) == REG)
            optimize_reg_copy_3 (insn, SET_DEST (set), SET_SRC (set));
 
          if (flag_expensive_optimizations && ! pass
              && GET_CODE (SET_SRC (set)) == REG
-             && GET_CODE (SET_DEST(set)) == REG)
+             && GET_CODE (SET_DEST (set)) == REG)
            {
              /* If this is a register-register copy where SRC is not dead,
                 see if we can optimize it.  If this optimization succeeds,
@@ -1124,15 +1128,15 @@ regmove_optimize (f, nregs, regmove_dump_file)
                  if (regno_src_regno[REGNO (SET_DEST (set))] < 0
                      && SET_SRC (set) != SET_DEST (set))
                    {
-                     int srcregno = REGNO (SET_SRC(set));
+                     int srcregno = REGNO (SET_SRC (set));
                      if (regno_src_regno[srcregno] >= 0)
                        srcregno = regno_src_regno[srcregno];
                      regno_src_regno[REGNO (SET_DEST (set))] = srcregno;
                    }
                }
            }
-          if (! flag_regmove)
-            continue;
+         if (! flag_regmove)
+           continue;
 
          if (! find_matches (insn, &match))
            continue;
@@ -1328,19 +1332,22 @@ regmove_optimize (f, nregs, regmove_dump_file)
                }
              src_class = reg_preferred_class (REGNO (src));
              dst_class = reg_preferred_class (REGNO (dst));
-             if (! regclass_compatible_p (src_class, dst_class))
+
+             if (! (src_note = find_reg_note (insn, REG_DEAD, src)))
                {
-                 if (!copy_src)
-                   {
-                     copy_src = src;
-                     copy_dst = dst;
-                   }
+                 /* We used to force the copy here like in other cases, but
+                    it produces worse code, as it eliminates no copy
+                    instructions and the copy emitted will be produced by
+                    reload anyway.  On patterns with multiple alternatives,
+                    there may be better solution available.
+
+                    In particular this change produced slower code for numeric
+                    i387 programs.  */
+
                  continue;
                }
 
-             /* Can not modify an earlier insn to set dst if this insn
-                uses an old value in the source.  */
-             if (reg_overlap_mentioned_p (dst, SET_SRC (set)))
+             if (! regclass_compatible_p (src_class, dst_class))
                {
                  if (!copy_src)
                    {
@@ -1350,7 +1357,9 @@ regmove_optimize (f, nregs, regmove_dump_file)
                  continue;
                }
 
-             if (! (src_note = find_reg_note (insn, REG_DEAD, src)))
+             /* Can not modify an earlier insn to set dst if this insn
+                uses an old value in the source.  */
+             if (reg_overlap_mentioned_p (dst, SET_SRC (set)))
                {
                  if (!copy_src)
                    {
@@ -1360,13 +1369,12 @@ regmove_optimize (f, nregs, regmove_dump_file)
                  continue;
                }
 
-
              /* If src is set once in a different basic block,
                 and is set equal to a constant, then do not use
                 it for this optimization, as this would make it
                 no longer equivalent to a constant.  */
 
-              if (reg_is_remote_constant_p (src, insn, f))
+             if (reg_is_remote_constant_p (src, insn, f))
                {
                  if (!copy_src)
                    {
@@ -1491,7 +1499,7 @@ regmove_optimize (f, nregs, regmove_dump_file)
            }
 
          /* If we weren't able to replace any of the alternatives, try an
-            alternative appoach of copying the source to the destination.  */
+            alternative approach of copying the source to the destination.  */
          if (!success && copy_src != NULL_RTX)
            copy_src_to_dest (insn, copy_src, copy_dst, old_max_uid);
 
@@ -1500,15 +1508,15 @@ regmove_optimize (f, nregs, regmove_dump_file)
 
   /* In fixup_match_1, some insns may have been inserted after basic block
      ends.  Fix that here.  */
-  for (i = 0; i < n_basic_blocks; i++)
+  FOR_EACH_BB (bb)
     {
-      rtx end = BLOCK_END (i);
+      rtx end = bb->end;
       rtx new = end;
       rtx next = NEXT_INSN (new);
       while (next != 0 && INSN_UID (next) >= old_max_uid
-            && (i == n_basic_blocks - 1 || BLOCK_HEAD (i + 1) != next))
+            && (bb->next_bb == EXIT_BLOCK_PTR || bb->next_bb->head != next))
        new = next, next = NEXT_INSN (new);
-      BLOCK_END (i) = new;
+      bb->end = new;
     }
 
  done:
@@ -1562,45 +1570,50 @@ find_matches (insn, matchp)
        if (*p == ',')
          i++;
 
-      while ((c = *p++) != '\0' && c != ',')
-       switch (c)
-         {
-         case '=':
-           break;
-         case '+':
-           break;
-         case '&':
-           matchp->early_clobber[op_no] = 1;
-           break;
-         case '%':
-           matchp->commutative[op_no] = op_no + 1;
-           matchp->commutative[op_no + 1] = op_no;
-           break;
-
-         case '0': case '1': case '2': case '3': case '4':
-         case '5': case '6': case '7': case '8': case '9':
+      while ((c = *p) != '\0' && c != ',')
+       {
+         switch (c)
            {
-             char *end;
-             unsigned long match = strtoul (p - 1, &end, 10);
-             p = end;
+           case '=':
+             break;
+           case '+':
+             break;
+           case '&':
+             matchp->early_clobber[op_no] = 1;
+             break;
+           case '%':
+             matchp->commutative[op_no] = op_no + 1;
+             matchp->commutative[op_no + 1] = op_no;
+             break;
 
-             if (match < op_no && likely_spilled[match])
-               break;
-             matchp->with[op_no] = match;
-             any_matches = 1;
-             if (matchp->commutative[op_no] >= 0)
-               matchp->with[matchp->commutative[op_no]] = match;
-           }
-           break;
+           case '0': case '1': case '2': case '3': case '4':
+           case '5': case '6': case '7': case '8': case '9':
+             {
+               char *end;
+               unsigned long match_ul = strtoul (p, &end, 10);
+               int match = match_ul;
+
+               p = end;
+
+               if (match < op_no && likely_spilled[match])
+                 continue;
+               matchp->with[op_no] = match;
+               any_matches = 1;
+               if (matchp->commutative[op_no] >= 0)
+                 matchp->with[matchp->commutative[op_no]] = match;
+             }
+           continue;
 
          case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h':
          case 'j': case 'k': case 'l': case 'p': case 'q': case 't': case 'u':
          case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
          case 'C': case 'D': case 'W': case 'Y': case 'Z':
-           if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_LETTER ((unsigned char)c)))
+           if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p) ))
              likely_spilled[op_no] = 1;
            break;
          }
+         p += CONSTRAINT_LEN (c, p);
+       }
     }
   return any_matches;
 }
@@ -1663,7 +1676,7 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
   int success = 0;
   int num_calls = 0, s_num_calls = 0;
   enum rtx_code code = NOTE;
-  HOST_WIDE_INT insn_const = 0, newconst;
+  HOST_WIDE_INT insn_const = 0, newconst = 0;
   rtx overlap = 0; /* need to move insn ? */
   rtx src_note = find_reg_note (insn, REG_DEAD, src), dst_note = NULL_RTX;
   int length, s_length;
@@ -1920,7 +1933,7 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
 
       if (note && CONSTANT_P (XEXP (note, 0)))
        {
-         for (q = PREV_INSN (insn); q; q = PREV_INSN(q))
+         for (q = PREV_INSN (insn); q; q = PREV_INSN (q))
            {
              /* ??? We can't scan past the end of a basic block without
                 updating the register lifetime info
@@ -2132,10 +2145,10 @@ static int record_stack_memrefs PARAMS ((rtx *, void *));
 void
 combine_stack_adjustments ()
 {
-  int i;
+  basic_block bb;
 
-  for (i = 0; i < n_basic_blocks; ++i)
-    combine_stack_adjustments_for_block (BASIC_BLOCK (i));
+  FOR_EACH_BB (bb)
+    combine_stack_adjustments_for_block (bb);
 }
 
 /* Recognize a MEM of the form (sp) or (plus sp const).  */
@@ -2305,7 +2318,7 @@ record_stack_memrefs (xp, data)
 
         We can't just compare with STACK_POINTER_RTX because the
         reference to the stack pointer might be in some other mode.
-        In particular, an explict clobber in an asm statement will
+        In particular, an explicit clobber in an asm statement will
         result in a QImode clober.  */
       if (REGNO (x) == STACK_POINTER_REGNUM)
        return 1;
@@ -2325,19 +2338,17 @@ combine_stack_adjustments_for_block (bb)
   HOST_WIDE_INT last_sp_adjust = 0;
   rtx last_sp_set = NULL_RTX;
   struct csa_memlist *memlist = NULL;
-  rtx pending_delete;
-  rtx insn, next;
+  rtx insn, next, set;
   struct record_stack_memrefs_data data;
+  bool end_of_block = false;
 
-  for (insn = bb->head; ; insn = next)
+  for (insn = bb->head; !end_of_block ; insn = next)
     {
-      rtx set;
-
-      pending_delete = NULL_RTX;
+      end_of_block = insn == bb->end;
       next = NEXT_INSN (insn);
 
       if (! INSN_P (insn))
-       goto processed;
+       continue;
 
       set = single_set_for_csa (insn);
       if (set)
@@ -2359,14 +2370,14 @@ combine_stack_adjustments_for_block (bb)
                {
                  last_sp_set = insn;
                  last_sp_adjust = this_adjust;
-                 goto processed;
+                 continue;
                }
 
              /* If not all recorded memrefs can be adjusted, or the
                 adjustment is now too large for a constant addition,
                 we cannot merge the two stack adjustments.
 
-                Also we need to be carefull to not move stack pointer
+                Also we need to be careful to not move stack pointer
                 such that we create stack accesses outside the allocated
                 area.  We can combine an allocation into the first insn,
                 or a deallocation into the second insn.  We can not
@@ -2391,9 +2402,9 @@ combine_stack_adjustments_for_block (bb)
                                                  this_adjust))
                    {
                      /* It worked!  */
-                     pending_delete = insn;
+                     delete_insn (insn);
                      last_sp_adjust += this_adjust;
-                     goto processed;
+                     continue;
                    }
                }
 
@@ -2412,16 +2423,20 @@ combine_stack_adjustments_for_block (bb)
                      last_sp_adjust += this_adjust;
                      free_csa_memlist (memlist);
                      memlist = NULL;
-                     goto processed;
+                     continue;
                    }
                }
 
-             /* Combination failed.  Restart processing from here.  */
+             /* Combination failed.  Restart processing from here.  If
+                deallocation+allocation conspired to cancel, we can
+                delete the old deallocation insn.  */
+             if (last_sp_set && last_sp_adjust == 0)
+               delete_insn (insn);
              free_csa_memlist (memlist);
              memlist = NULL;
              last_sp_set = insn;
              last_sp_adjust = this_adjust;
-             goto processed;
+             continue;
            }
 
          /* Find a predecrement of exactly the previous adjustment and
@@ -2447,15 +2462,12 @@ combine_stack_adjustments_for_block (bb)
                                                         stack_pointer_rtx),
                                  0))
            {
-             if (last_sp_set == bb->head)
-               bb->head = NEXT_INSN (last_sp_set);
              delete_insn (last_sp_set);
-
              free_csa_memlist (memlist);
              memlist = NULL;
              last_sp_set = NULL_RTX;
              last_sp_adjust = 0;
-             goto processed;
+             continue;
            }
        }
 
@@ -2465,7 +2477,7 @@ combine_stack_adjustments_for_block (bb)
          && !for_each_rtx (&PATTERN (insn), record_stack_memrefs, &data))
        {
           memlist = data.memlist;
-          goto processed;
+          continue;
        }
       memlist = data.memlist;
 
@@ -2475,20 +2487,15 @@ combine_stack_adjustments_for_block (bb)
          && (GET_CODE (insn) == CALL_INSN
              || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
        {
+         if (last_sp_set && last_sp_adjust == 0)
+           delete_insn (last_sp_set);
          free_csa_memlist (memlist);
          memlist = NULL;
          last_sp_set = NULL_RTX;
          last_sp_adjust = 0;
        }
-
-    processed:
-      if (insn == bb->end)
-       break;
-
-      if (pending_delete)
-       delete_insn (pending_delete);
     }
 
-  if (pending_delete)
-    delete_insn (pending_delete);
+  if (last_sp_set && last_sp_adjust == 0)
+    delete_insn (last_sp_set);
 }