OSDN Git Service

* stor-layout.c (layout_type): Complain if an array's size can
[pf3gnuchains/gcc-fork.git] / gcc / local-alloc.c
index ac2183e..eaa4450 100644 (file)
@@ -1,23 +1,23 @@
 /* Allocate registers within a basic block, for GNU compiler.
    Copyright (C) 1987, 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+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.  */
 
 /* Allocation of hard register numbers to pseudo registers is done in
    two passes.  In this pass we consider only regs that are born and
@@ -73,6 +73,7 @@ Boston, MA 02111-1307, USA.  */
 #include "recog.h"
 #include "output.h"
 #include "toplev.h"
+#include "except.h"
 \f
 /* Next quantity number available for allocation.  */
 
@@ -85,6 +86,10 @@ struct qty
 
   int n_refs;
 
+  /* The frequency of uses of quantity Q.  */
+
+  int freq;
+
   /* Insn number (counting from head of basic block)
      where quantity Q was born.  -1 if birth has not been recorded.  */
 
@@ -321,6 +326,7 @@ alloc_qty (regno, mode, size, birth)
   qty[qtyno].min_class = reg_preferred_class (regno);
   qty[qtyno].alternate_class = reg_alternate_class (regno);
   qty[qtyno].n_refs = REG_N_REFS (regno);
+  qty[qtyno].freq = REG_FREQ (regno);
   qty[qtyno].changes_mode = REG_CHANGES_MODE (regno);
 }
 \f
@@ -493,7 +499,7 @@ validate_equiv_mem (start, reg, memref)
        return 1;
 
       if (GET_CODE (insn) == CALL_INSN && ! RTX_UNCHANGING_P (memref)
-         && ! CONST_CALL_P (insn))
+         && ! CONST_OR_PURE_CALL_P (insn))
        return 0;
 
       note_stores (PATTERN (insn), validate_equiv_mem_from_store, NULL);
@@ -540,7 +546,7 @@ equiv_init_varies_p (x)
       return 0;
 
     case REG:
-      return reg_equiv[REGNO (x)].replace == 0 && rtx_varies_p (x);
+      return reg_equiv[REGNO (x)].replace == 0 && rtx_varies_p (x, 0);
 
     case ASM_OPERANDS:
       if (MEM_VOLATILE_P (x))
@@ -604,7 +610,7 @@ equiv_init_movable_p (x, regno)
     case REG:
       return (reg_equiv[REGNO (x)].loop_depth >= reg_equiv[regno].loop_depth
              && reg_equiv[REGNO (x)].replace)
-            || (REG_BASIC_BLOCK (REGNO (x)) < 0 && ! rtx_varies_p (x));
+            || (REG_BASIC_BLOCK (REGNO (x)) < 0 && ! rtx_varies_p (x, 0));
 
     case UNSPEC_VOLATILE:
       return 0;
@@ -804,8 +810,11 @@ update_equiv_regs ()
   rtx insn;
   int block;
   int loop_depth;
+  regset_head cleared_regs;
+  int clear_regnos = 0;
 
   reg_equiv = (struct equivalence *) xcalloc (max_regno, sizeof *reg_equiv);
+  INIT_REG_SET (&cleared_regs);
 
   init_alias_analysis ();
 
@@ -930,7 +939,7 @@ update_equiv_regs ()
       /* cse sometimes generates function invariants, but doesn't put a
         REG_EQUAL note on the insn.  Since this note would be redundant,
          there's no point creating it earlier than here.  */
-      if (! note && ! rtx_varies_p (src))
+      if (! note && ! rtx_varies_p (src, 0))
        REG_NOTES (insn)
          = note = gen_rtx_EXPR_LIST (REG_EQUAL, src, REG_NOTES (insn));
 
@@ -941,7 +950,7 @@ update_equiv_regs ()
 
       if (REG_N_SETS (regno) != 1
          && (! note
-             || rtx_varies_p (XEXP (note, 0))
+             || rtx_varies_p (XEXP (note, 0), 0)
              || (reg_equiv[regno].replacement
                  && ! rtx_equal_p (XEXP (note, 0),
                                    reg_equiv[regno].replacement))))
@@ -955,7 +964,7 @@ update_equiv_regs ()
 
       /* If this register is known to be equal to a constant, record that
         it is always equivalent to the constant.  */
-      if (note && ! rtx_varies_p (XEXP (note, 0)))
+      if (note && ! rtx_varies_p (XEXP (note, 0), 0))
        PUT_MODE (note, (enum machine_mode) REG_EQUIV);
 
       /* If this insn introduces a "constant" register, decrease the priority
@@ -1002,7 +1011,7 @@ update_equiv_regs ()
          reg_equiv[regno].loop_depth = loop_depth;
 
          /* Don't mess with things live during setjmp.  */
-         if (REG_LIVE_LENGTH (regno) >= 0)
+         if (REG_LIVE_LENGTH (regno) >= 0 && optimize)
            {
              /* Note that the statement below does not affect the priority
                 in local-alloc!  */
@@ -1094,6 +1103,12 @@ update_equiv_regs ()
                abort ();
              equiv_insn = XEXP (reg_equiv[regno].init_insns, 0);
 
+             /* We may not move instructions that can throw, since
+                that changes basic block boundaries and we are not
+                prepared to adjust the CFG to match.  */
+             if (can_throw_internal (equiv_insn))
+               continue;
+
              if (asm_noperands (PATTERN (equiv_insn)) < 0
                  && validate_replace_rtx (regno_reg_rtx[regno],
                                           reg_equiv[regno].src, insn))
@@ -1124,25 +1139,28 @@ update_equiv_regs ()
 
                  remove_death (regno, insn);
                  REG_N_REFS (regno) = 0;
+                 REG_FREQ (regno) = 0;
                  PUT_CODE (equiv_insn, NOTE);
                  NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
                  NOTE_SOURCE_FILE (equiv_insn) = 0;
                  
-                 reg_equiv[regno].init_insns = 
-                   XEXP (reg_equiv[regno].init_insns, 1);
+                 reg_equiv[regno].init_insns
+                   XEXP (reg_equiv[regno].init_insns, 1);
                }
              /* Move the initialization of the register to just before
                 INSN.  Update the flow information.  */
              else if (PREV_INSN (insn) != equiv_insn)
                {
-                 int l;
                  rtx new_insn;
 
-                 new_insn = emit_insn_before (copy_rtx (PATTERN (equiv_insn)),
-                                              insn);
-                 REG_NOTES (PREV_INSN (insn)) = REG_NOTES (equiv_insn);
+                 new_insn = emit_insn_before (PATTERN (equiv_insn), insn);
+                 REG_NOTES (new_insn) = REG_NOTES (equiv_insn);
                  REG_NOTES (equiv_insn) = 0;
 
+                 /* Make sure this insn is recognized before reload begins,
+                    otherwise eliminate_regs_in_insn will abort.  */
+                 INSN_CODE (new_insn) = INSN_CODE (equiv_insn);
+
                  PUT_CODE (equiv_insn, NOTE);
                  NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
                  NOTE_SOURCE_FILE (equiv_insn) = 0;
@@ -1156,22 +1174,43 @@ update_equiv_regs ()
                  if (block >= 0 && insn == BLOCK_HEAD (block))
                    BLOCK_HEAD (block) = PREV_INSN (insn);
 
-                 for (l = 0; l < n_basic_blocks; l++)
-                   {
-                     CLEAR_REGNO_REG_SET (
-                                       BASIC_BLOCK (l)->global_live_at_start,
-                                          regno);
-                     CLEAR_REGNO_REG_SET (
-                                       BASIC_BLOCK (l)->global_live_at_end,
-                                          regno);
-                   }
+                 /* Remember to clear REGNO from all basic block's live
+                    info.  */
+                 SET_REGNO_REG_SET (&cleared_regs, regno);
+                 clear_regnos++;
                }
            }
        }
     }
 
+  /* Clear all dead REGNOs from all basic block's live info.  */
+  if (clear_regnos)
+    {
+      int j, l;
+      if (clear_regnos > 8)
+        {
+         for (l = 0; l < n_basic_blocks; l++)
+           {
+             AND_COMPL_REG_SET (BASIC_BLOCK (l)->global_live_at_start,
+                                &cleared_regs);
+             AND_COMPL_REG_SET (BASIC_BLOCK (l)->global_live_at_end,
+                                &cleared_regs);
+           }
+       }
+      else
+        EXECUTE_IF_SET_IN_REG_SET (&cleared_regs, 0, j,
+          {
+           for (l = 0; l < n_basic_blocks; l++)
+             {
+               CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_start, j);
+               CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_end, j);
+             }
+         });
+    }
+
   /* Clean up.  */
   end_alias_analysis ();
+  CLEAR_REG_SET (&cleared_regs);
   free (reg_equiv);
 }
 
@@ -1666,13 +1705,14 @@ block_alloc (b)
 
 /* Note that the quotient will never be bigger than
    the value of floor_log2 times the maximum number of
-   times a register can occur in one insn (surely less than 100).
-   Multiplying this by 10000 can't overflow.
+   times a register can occur in one insn (surely less than 100)
+   weighted by frequency (max REG_FREQ_MAX).
+   Multiplying this by 10000/REG_FREQ_MAX can't overflow.
    QTY_CMP_PRI is also used by qty_sugg_compare.  */
 
 #define QTY_CMP_PRI(q)         \
-  ((int) (((double) (floor_log2 (qty[q].n_refs) * qty[q].n_refs * qty[q].size) \
-         / (qty[q].death - qty[q].birth)) * 10000))
+  ((int) (((double) (floor_log2 (qty[q].n_refs) * qty[q].freq * qty[q].size) \
+         / (qty[q].death - qty[q].birth)) * (10000 / REG_FREQ_MAX)))
 
 static int
 qty_compare (q1, q2)
@@ -1787,25 +1827,49 @@ combine_regs (usedreg, setreg, may_save_copy, insn_number, insn, already_dead)
     {
       if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (usedreg))) > UNITS_PER_WORD)
        may_save_copy = 0;
-      offset += SUBREG_WORD (usedreg);
+      if (REGNO (SUBREG_REG (usedreg)) < FIRST_PSEUDO_REGISTER)
+       offset += subreg_regno_offset (REGNO (SUBREG_REG (usedreg)),
+                                      GET_MODE (SUBREG_REG (usedreg)),
+                                      SUBREG_BYTE (usedreg),
+                                      GET_MODE (usedreg));
+      else
+       offset += (SUBREG_BYTE (usedreg)
+                  / REGMODE_NATURAL_SIZE (GET_MODE (usedreg)));
       usedreg = SUBREG_REG (usedreg);
     }
   if (GET_CODE (usedreg) != REG)
     return 0;
   ureg = REGNO (usedreg);
-  usize = REG_SIZE (usedreg);
+  if (ureg < FIRST_PSEUDO_REGISTER)
+    usize = HARD_REGNO_NREGS (ureg, GET_MODE (usedreg));
+  else
+    usize = ((GET_MODE_SIZE (GET_MODE (usedreg))
+             + (REGMODE_NATURAL_SIZE (GET_MODE (usedreg)) - 1))
+            / REGMODE_NATURAL_SIZE (GET_MODE (usedreg)));
 
   while (GET_CODE (setreg) == SUBREG)
     {
       if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (setreg))) > UNITS_PER_WORD)
        may_save_copy = 0;
-      offset -= SUBREG_WORD (setreg);
+      if (REGNO (SUBREG_REG (setreg)) < FIRST_PSEUDO_REGISTER)
+       offset -= subreg_regno_offset (REGNO (SUBREG_REG (setreg)),
+                                      GET_MODE (SUBREG_REG (setreg)),
+                                      SUBREG_BYTE (setreg),
+                                      GET_MODE (setreg));
+      else
+       offset -= (SUBREG_BYTE (setreg)
+                  / REGMODE_NATURAL_SIZE (GET_MODE (setreg)));
       setreg = SUBREG_REG (setreg);
     }
   if (GET_CODE (setreg) != REG)
     return 0;
   sreg = REGNO (setreg);
-  ssize = REG_SIZE (setreg);
+  if (sreg < FIRST_PSEUDO_REGISTER)
+    ssize = HARD_REGNO_NREGS (sreg, GET_MODE (setreg));
+  else
+    ssize = ((GET_MODE_SIZE (GET_MODE (setreg))
+             + (REGMODE_NATURAL_SIZE (GET_MODE (setreg)) - 1))
+            / REGMODE_NATURAL_SIZE (GET_MODE (setreg)));
 
   /* If UREG is a pseudo-register that hasn't already been assigned a
      quantity number, it means that it is not local to this block or dies
@@ -1916,6 +1980,7 @@ combine_regs (usedreg, setreg, may_save_copy, insn_number, insn, already_dead)
       /* Update info about quantity SQTY.  */
       qty[sqty].n_calls_crossed += REG_N_CALLS_CROSSED (sreg);
       qty[sqty].n_refs += REG_N_REFS (sreg);
+      qty[sqty].freq += REG_FREQ (sreg);
       if (usize < ssize)
        {
          register int i;
@@ -2006,7 +2071,11 @@ reg_is_born (reg, birth)
   register int regno;
 
   if (GET_CODE (reg) == SUBREG)
-    regno = REGNO (SUBREG_REG (reg)) + SUBREG_WORD (reg);
+    {
+      regno = REGNO (SUBREG_REG (reg));
+      if (regno < FIRST_PSEUDO_REGISTER)
+       regno = subreg_hard_regno (reg, 1);
+    }
   else
     regno = REGNO (reg);