OSDN Git Service

* c-common.c, c-decl.c, c-format.c, c-typeck.c: Use %D for
[pf3gnuchains/gcc-fork.git] / gcc / reg-stack.c
index d5983bb..e92e73c 100644 (file)
@@ -1,6 +1,6 @@
 /* Register to Stack convert for GNU compiler.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -251,6 +251,7 @@ static rtx emit_pop_insn (rtx, stack, rtx, enum emit_where);
 static void emit_swap_insn (rtx, stack, rtx);
 static void swap_to_top(rtx, stack, rtx, rtx);
 static bool move_for_stack_reg (rtx, stack, rtx);
+static bool move_nan_for_stack_reg (rtx, stack, rtx);
 static int swap_rtx_condition_1 (rtx);
 static int swap_rtx_condition (rtx);
 static void compare_for_stack_reg (rtx, stack, rtx);
@@ -1055,10 +1056,14 @@ move_for_stack_reg (rtx insn, stack regstack, rtx pat)
            if (regstack->reg[i] == REGNO (src))
              break;
 
-         /* The source must be live, and the dest must be dead.  */
-         gcc_assert (i >= 0);
+         /* The destination must be dead, or life analysis is borked.  */
          gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG);
 
+         /* If the source is not live, this is yet another case of
+            uninitialized variables.  Load up a NaN instead.  */
+         if (i < 0)
+           return move_nan_for_stack_reg (insn, regstack, dest);
+
          /* It is possible that the dest is unused after this insn.
             If so, just pop the src.  */
 
@@ -1127,11 +1132,11 @@ move_for_stack_reg (rtx insn, stack regstack, rtx pat)
             available.  Push the source value here if the register
             stack is not full, and then write the value to memory via
             a pop.  */
-         rtx push_rtx, push_insn;
+         rtx push_rtx;
          rtx top_stack_reg = FP_MODE_REG (FIRST_STACK_REG, GET_MODE (src));
 
          push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
-         push_insn = emit_insn_before (push_rtx, insn);
+         emit_insn_before (push_rtx, insn);
          REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, top_stack_reg,
                                                REG_NOTES (insn));
        }
@@ -1159,6 +1164,22 @@ move_for_stack_reg (rtx insn, stack regstack, rtx pat)
 
   return control_flow_insn_deleted;
 }
+
+/* A helper function which replaces INSN with a pattern that loads up
+   a NaN into DEST, then invokes move_for_stack_reg.  */
+
+static bool
+move_nan_for_stack_reg (rtx insn, stack regstack, rtx dest)
+{
+  rtx pat;
+
+  dest = FP_MODE_REG (REGNO (dest), SFmode);
+  pat = gen_rtx_SET (VOIDmode, dest, not_a_num);
+  PATTERN (insn) = pat;
+  INSN_CODE (insn) = -1;
+
+  return move_for_stack_reg (insn, regstack, pat);
+}
 \f
 /* Swap the condition on a branch, if there is one.  Return true if we
    found a condition to swap.  False if the condition was not used as
@@ -1287,11 +1308,9 @@ compare_for_stack_reg (rtx insn, stack regstack, rtx pat_src)
 {
   rtx *src1, *src2;
   rtx src1_note, src2_note;
-  rtx flags_user;
 
   src1 = get_true_reg (&XEXP (pat_src, 0));
   src2 = get_true_reg (&XEXP (pat_src, 1));
-  flags_user = next_flags_user (insn);
 
   /* ??? If fxch turns out to be cheaper than fstp, give priority to
      registers that die in this insn - move those to stack top first.  */
@@ -1430,23 +1449,19 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
                   all other clobbers, this must be due to a function
                   returning without a value.  Load up a NaN.  */
 
-               if (! note
-                   && get_hard_regnum (regstack, *dest) == -1)
-                 {
-                   pat = gen_rtx_SET (VOIDmode,
-                                      FP_MODE_REG (REGNO (*dest), SFmode),
-                                      not_a_num);
-                   PATTERN (insn) = pat;
-                   control_flow_insn_deleted |= move_for_stack_reg (insn, regstack, pat);
-                 }
-               if (! note && COMPLEX_MODE_P (GET_MODE (*dest))
-                   && get_hard_regnum (regstack, FP_MODE_REG (REGNO (*dest), DFmode)) == -1)
+               if (!note)
                  {
-                   pat = gen_rtx_SET (VOIDmode,
-                                      FP_MODE_REG (REGNO (*dest) + 1, SFmode),
-                                      not_a_num);
-                   PATTERN (insn) = pat;
-                   control_flow_insn_deleted |= move_for_stack_reg (insn, regstack, pat);
+                   rtx t = *dest;
+                   if (get_hard_regnum (regstack, t) == -1)
+                     control_flow_insn_deleted
+                       |= move_nan_for_stack_reg (insn, regstack, t);
+                   if (COMPLEX_MODE_P (GET_MODE (t)))
+                     {
+                       t = FP_MODE_REG (REGNO (t) + 1, DFmode);
+                       if (get_hard_regnum (regstack, t) == -1)
+                         control_flow_insn_deleted
+                           |= move_nan_for_stack_reg (insn, regstack, t);
+                     }
                  }
              }
          }
@@ -2367,10 +2382,97 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
 
   /* Pop any registers that are not needed in the new block.  */
 
-  for (reg = old->top; reg >= 0; reg--)
-    if (! TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]))
-      emit_pop_insn (insn, old, FP_MODE_REG (old->reg[reg], DFmode),
-                    EMIT_BEFORE);
+  /* If the destination block's stack already has a specified layout
+     and contains two or more registers, use a more intelligent algorithm
+     to pop registers that minimizes the number number of fxchs below.  */
+  if (new->top > 0)
+    {
+      bool slots[REG_STACK_SIZE];
+      int pops[REG_STACK_SIZE];
+      int next, dest, topsrc;
+
+      /* First pass to determine the free slots.  */
+      for (reg = 0; reg <= new->top; reg++)
+       slots[reg] = TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]);
+
+      /* Second pass to allocate preferred slots.  */
+      topsrc = -1;
+      for (reg = old->top; reg > new->top; reg--)
+       if (TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]))
+         {
+           dest = -1;
+           for (next = 0; next <= new->top; next++)
+             if (!slots[next] && new->reg[next] == old->reg[reg])
+               {
+                 /* If this is a preference for the new top of stack, record
+                    the fact by remembering it's old->reg in topsrc.  */
+                  if (next == new->top)
+                   topsrc = reg;
+                 slots[next] = true;
+                 dest = next;
+                 break;
+               }
+           pops[reg] = dest;
+         }
+       else
+         pops[reg] = reg;
+
+      /* Intentionally, avoid placing the top of stack in it's correct
+        location, if we still need to permute the stack below and we
+        can usefully place it somewhere else.  This is the case if any
+        slot is still unallocated, in which case we should place the
+        top of stack there.  */
+      if (topsrc != -1)
+       for (reg = 0; reg < new->top; reg++)
+         if (!slots[reg])
+           {
+             pops[topsrc] = reg;
+             slots[new->top] = false;
+             slots[reg] = true;
+             break;
+           }
+
+      /* Third pass allocates remaining slots and emits pop insns.  */
+      next = new->top;
+      for (reg = old->top; reg > new->top; reg--)
+       {
+         dest = pops[reg];
+         if (dest == -1)
+           {
+             /* Find next free slot.  */
+             while (slots[next])
+               next--;
+             dest = next--;
+           }
+         emit_pop_insn (insn, old, FP_MODE_REG (old->reg[dest], DFmode),
+                        EMIT_BEFORE);
+       }
+    }
+  else
+    {
+      /* The following loop attempts to maximize the number of times we
+        pop the top of the stack, as this permits the use of the faster
+        ffreep instruction on platforms that support it.  */
+      int live, next;
+
+      live = 0;
+      for (reg = 0; reg <= old->top; reg++)
+        if (TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]))
+          live++;
+
+      next = live;
+      while (old->top >= live)
+        if (TEST_HARD_REG_BIT (new->reg_set, old->reg[old->top]))
+         {
+           while (TEST_HARD_REG_BIT (new->reg_set, old->reg[next]))
+             next--;
+           emit_pop_insn (insn, old, FP_MODE_REG (old->reg[next], DFmode),
+                          EMIT_BEFORE);
+         }
+       else
+         emit_pop_insn (insn, old, FP_MODE_REG (old->reg[old->top], DFmode),
+                        EMIT_BEFORE);
+    }
 
   if (new->top == -2)
     {
@@ -2711,14 +2813,13 @@ convert_regs_1 (FILE *file, basic_block block)
 {
   struct stack_def regstack;
   block_info bi = BLOCK_INFO (block);
-  int deleted, inserted, reg;
+  int inserted, reg;
   rtx insn, next;
   edge e, beste = NULL;
   bool control_flow_insn_deleted = false;
   edge_iterator ei;
 
   inserted = 0;
-  deleted = 0;
   any_malformed_asm = false;
 
   /* Find the edge we will copy stack from.  It should be the most frequent
@@ -2834,13 +2935,9 @@ convert_regs_1 (FILE *file, basic_block block)
          rtx set;
 
          if (file)
-           {
-             fprintf (file, "Emitting insn initializing reg %d\n",
-                      reg);
-           }
+           fprintf (file, "Emitting insn initializing reg %d\n", reg);
 
-         set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode),
-                            not_a_num);
+         set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode), not_a_num);
          insn = emit_insn_after (set, insn);
          control_flow_insn_deleted |= subst_stack_regs (insn, &regstack);
        }
@@ -2949,6 +3046,8 @@ convert_regs_2 (FILE *file, basic_block block)
     }
   while (sp != stack);
 
+  free (stack);
+
   return inserted;
 }