OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / regs.h
index 848c306..328b839 100644 (file)
@@ -1,12 +1,13 @@
 /* Define per-register tables for data flow info and register allocation.
    Copyright (C) 1987, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2010 Free Software
+   Foundation, Inc.
 
 This file is part of GCC.
 
 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
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,16 +16,14 @@ 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 GCC; 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 COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #ifndef GCC_REGS_H
 #define GCC_REGS_H
 
-#include "varray.h"
+#include "machmode.h"
 #include "hard-reg-set.h"
-#include "basic-block.h"
 
 #define REG_BYTES(R) mode_size[(int) GET_MODE (R)]
 
@@ -37,46 +36,95 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #define REGMODE_NATURAL_SIZE(MODE)     UNITS_PER_WORD
 #endif
 
-#ifndef SMALL_REGISTER_CLASSES
-#define SMALL_REGISTER_CLASSES 0
-#endif
-
 /* Maximum register number used in this function, plus one.  */
 
 extern int max_regno;
 
-/* Register information indexed by register number */
-typedef struct reg_info_def
-{                              /* fields set by reg_scan */
-  int first_uid;               /* UID of first insn to use (REG n) */
-  int last_uid;                        /* UID of last insn to use (REG n) */
-  int last_note_uid;           /* UID of last note to use (REG n) */
+/* REG_N_REFS and REG_N_SETS are initialized by a call to
+   regstat_init_n_sets_and_refs from the current values of
+   DF_REG_DEF_COUNT and DF_REG_USE_COUNT.  REG_N_REFS and REG_N_SETS
+   should only be used if a pass need to change these values in some
+   magical way or the pass needs to have accurate values for these
+   and is not using incremental df scanning.
+
+   At the end of a pass that uses REG_N_REFS and REG_N_SETS, a call
+   should be made to regstat_free_n_sets_and_refs.
+
+   Local alloc seems to play pretty loose with these values.
+   REG_N_REFS is set to 0 if the register is used in an asm.
+   Furthermore, local_alloc calls regclass to hack both REG_N_REFS and
+   REG_N_SETS for three address insns.  Other passes seem to have
+   other special values.  */
 
-                               /* fields set by reg_scan & flow_analysis */
-  int sets;                    /* # of times (REG n) is set */
 
-                               /* fields set by flow_analysis */
+
+/* Structure to hold values for REG_N_SETS (i) and REG_N_REFS (i). */
+
+struct regstat_n_sets_and_refs_t
+{
+  int sets;                    /* # of times (REG n) is set */
   int refs;                    /* # of times (REG n) is used or set */
+};
+
+extern struct regstat_n_sets_and_refs_t *regstat_n_sets_and_refs;
+
+/* Indexed by n, gives number of times (REG n) is used or set.  */
+static inline int
+REG_N_REFS(int regno)
+{
+  return regstat_n_sets_and_refs[regno].refs;
+}
+
+/* Indexed by n, gives number of times (REG n) is used or set.  */
+#define SET_REG_N_REFS(N,V) (regstat_n_sets_and_refs[N].refs = V)
+#define INC_REG_N_REFS(N,V) (regstat_n_sets_and_refs[N].refs += V)
+
+/* Indexed by n, gives number of times (REG n) is set.  */
+static inline int
+REG_N_SETS (int regno)
+{
+  return regstat_n_sets_and_refs[regno].sets;
+}
+
+/* Indexed by n, gives number of times (REG n) is set.  */
+#define SET_REG_N_SETS(N,V) (regstat_n_sets_and_refs[N].sets = V)
+#define INC_REG_N_SETS(N,V) (regstat_n_sets_and_refs[N].sets += V)
+
+
+/* Functions defined in reg-stat.c.  */
+extern void regstat_init_n_sets_and_refs (void);
+extern void regstat_free_n_sets_and_refs (void);
+extern void regstat_compute_ri (void);
+extern void regstat_free_ri (void);
+extern bitmap regstat_get_setjmp_crosses (void);
+extern void regstat_compute_calls_crossed (void);
+extern void regstat_free_calls_crossed (void);
+
+
+/* Register information indexed by register number.  This structure is
+   initialized by calling regstat_compute_ri and is destroyed by
+   calling regstat_free_ri.  */
+struct reg_info_t
+{
   int freq;                    /* # estimated frequency (REG n) is used or set */
   int deaths;                  /* # of times (REG n) dies */
   int live_length;             /* # of instructions (REG n) is live */
   int calls_crossed;           /* # of calls (REG n) is live across */
+  int freq_calls_crossed;      /* # estimated frequency (REG n) crosses call */
+  int throw_calls_crossed;     /* # of calls that may throw (REG n) is live across */
   int basic_block;             /* # of basic blocks (REG n) is used in */
-  char changes_mode;           /* whether (SUBREG (REG n)) exists and
-                                  is illegal.  */
-} reg_info;
+};
 
-extern varray_type reg_n_info;
-
-/* Indexed by n, gives number of times (REG n) is used or set.  */
+extern struct reg_info_t *reg_info_p;
 
-#define REG_N_REFS(N) (VARRAY_REG (reg_n_info, N)->refs)
+/* The number allocated elements of reg_info_p.  */
+extern size_t reg_info_p_size;
 
 /* Estimate frequency of references to register N.  */
 
-#define REG_FREQ(N) (VARRAY_REG (reg_n_info, N)->freq)
+#define REG_FREQ(N) (reg_info_p[N].freq)
 
-/* The weights for each insn varries from 0 to REG_FREQ_BASE.
+/* The weights for each insn varies from 0 to REG_FREQ_BASE.
    This constant does not need to be high, as in infrequently executed
    regions we want to count instructions equivalently to optimize for
    size instead of speed.  */
@@ -94,19 +142,13 @@ extern varray_type reg_n_info;
                              ? ((bb)->frequency * REG_FREQ_MAX / BB_FREQ_MAX)\
                              : 1)
 
-/* Indexed by n, gives number of times (REG n) is set.
-   ??? both regscan and flow allocate space for this.  We should settle
-   on just copy.  */
-
-#define REG_N_SETS(N) (VARRAY_REG (reg_n_info, N)->sets)
-
 /* Indexed by N, gives number of insns in which register N dies.
    Note that if register N is live around loops, it can die
    in transitions between basic blocks, and that is not counted here.
    So this is only a reliable indicator of how many regions of life there are
    for registers that are contained in one basic block.  */
 
-#define REG_N_DEATHS(N) (VARRAY_REG (reg_n_info, N)->deaths)
+#define REG_N_DEATHS(N) (reg_info_p[N].deaths)
 
 /* Get the number of consecutive words required to hold pseudo-reg N.  */
 
@@ -125,13 +167,20 @@ extern varray_type reg_n_info;
 
 /* Indexed by N, gives number of CALL_INSNS across which (REG n) is live.  */
 
-#define REG_N_CALLS_CROSSED(N) (VARRAY_REG (reg_n_info, N)->calls_crossed)
+#define REG_N_CALLS_CROSSED(N)  (reg_info_p[N].calls_crossed)
+#define REG_FREQ_CALLS_CROSSED(N)  (reg_info_p[N].freq_calls_crossed)
+
+/* Indexed by N, gives number of CALL_INSNS that may throw, across which
+   (REG n) is live.  */
 
-/* Total number of instructions at which (REG n) is live.
-   The larger this is, the less priority (REG n) gets for
-   allocation in a hard register (in global-alloc).
-   This is set in flow.c and remains valid for the rest of the compilation
-   of the function; it is used to control register allocation.
+#define REG_N_THROWING_CALLS_CROSSED(N) (reg_info_p[N].throw_calls_crossed)
+
+/* Total number of instructions at which (REG n) is live.  The larger
+   this is, the less priority (REG n) gets for allocation in a hard
+   register (in global-alloc).  This is set in df-problems.c whenever
+   register info is requested and remains valid for the rest of the
+   compilation of the function; it is used to control register
+   allocation.
 
    local-alloc.c may alter this number to change the priority.
 
@@ -142,7 +191,19 @@ extern varray_type reg_n_info;
    is not required.  global.c makes an allocno for this but does
    not try to assign a hard register to it.  */
 
-#define REG_LIVE_LENGTH(N) (VARRAY_REG (reg_n_info, N)->live_length)
+#define REG_LIVE_LENGTH(N)  (reg_info_p[N].live_length)
+
+/* Indexed by n, gives number of basic block that  (REG n) is used in.
+   If the value is REG_BLOCK_GLOBAL (-1),
+   it means (REG n) is used in more than one basic block.
+   REG_BLOCK_UNKNOWN (0) means it hasn't been seen yet so we don't know.
+   This information remains valid for the rest of the compilation
+   of the current function; it is used to control register allocation.  */
+
+#define REG_BLOCK_UNKNOWN 0
+#define REG_BLOCK_GLOBAL -1
+
+#define REG_BASIC_BLOCK(N) (reg_info_p[N].basic_block)
 
 /* Vector of substitutions of register numbers,
    used to map pseudo regs into hardware regs.
@@ -153,48 +214,6 @@ extern varray_type reg_n_info;
 
 extern short *reg_renumber;
 
-/* Vector indexed by hardware reg saying whether that reg is ever used.  */
-
-extern char regs_ever_live[FIRST_PSEUDO_REGISTER];
-
-/* Like regs_ever_live, but saying whether reg is set by asm statements.  */
-
-extern char regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
-
-/* Vector indexed by machine mode saying whether there are regs of that mode.  */
-
-extern bool have_regs_of_mode [MAX_MACHINE_MODE];
-
-/* For each hard register, the widest mode object that it can contain.
-   This will be a MODE_INT mode if the register can hold integers.  Otherwise
-   it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
-   register.  */
-
-extern enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
-
-/* Vector indexed by regno; gives uid of first insn using that reg.
-   This is computed by reg_scan for use by cse and loop.
-   It is sometimes adjusted for subsequent changes during loop,
-   but not adjusted by cse even if cse invalidates it.  */
-
-#define REGNO_FIRST_UID(N) (VARRAY_REG (reg_n_info, N)->first_uid)
-
-/* Vector indexed by regno; gives uid of last insn using that reg.
-   This is computed by reg_scan for use by cse and loop.
-   It is sometimes adjusted for subsequent changes during loop,
-   but not adjusted by cse even if cse invalidates it.
-   This is harmless since cse won't scan through a loop end.  */
-
-#define REGNO_LAST_UID(N) (VARRAY_REG (reg_n_info, N)->last_uid)
-
-/* Similar, but includes insns that mention the reg in their notes.  */
-
-#define REGNO_LAST_NOTE_UID(N) (VARRAY_REG (reg_n_info, N)->last_note_uid)
-
-/* List made of EXPR_LIST rtx's which gives pairs of pseudo registers
-   that have to go in the same hard reg.  */
-extern rtx regs_may_share;
-
 /* Flag set by local-alloc or global-alloc if they decide to allocate
    something in a call-clobbered register.  */
 
@@ -208,12 +227,6 @@ extern int caller_save_needed;
 #define CALLER_SAVE_PROFITABLE(REFS, CALLS)  (4 * (CALLS) < (REFS))
 #endif
 
-/* On most machines a register class is likely to be spilled if it
-   only has one register.  */
-#ifndef CLASS_LIKELY_SPILLED_P
-#define CLASS_LIKELY_SPILLED_P(CLASS) (reg_class_size[(int) (CLASS)] == 1)
-#endif
-
 /* Select a register mode required for caller save of hard regno REGNO.  */
 #ifndef HARD_REGNO_CALLER_SAVE_MODE
 #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \
@@ -226,10 +239,206 @@ extern int caller_save_needed;
 #define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) 0
 #endif
 
-/* Allocate reg_n_info tables */
-extern void allocate_reg_info (size_t, int, int);
+typedef unsigned short move_table[N_REG_CLASSES];
+
+/* Target-dependent globals.  */
+struct target_regs {
+  /* For each starting hard register, the number of consecutive hard
+     registers that a given machine mode occupies.  */
+  unsigned char x_hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
+
+  /* For each hard register, the widest mode object that it can contain.
+     This will be a MODE_INT mode if the register can hold integers.  Otherwise
+     it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
+     register.  */
+  enum machine_mode x_reg_raw_mode[FIRST_PSEUDO_REGISTER];
+
+  /* Vector indexed by machine mode saying whether there are regs of
+     that mode.  */
+  bool x_have_regs_of_mode[MAX_MACHINE_MODE];
+
+  /* 1 if the corresponding class contains a register of the given mode.  */
+  char x_contains_reg_of_mode[N_REG_CLASSES][MAX_MACHINE_MODE];
+
+  /* Maximum cost of moving from a register in one class to a register
+     in another class.  Based on TARGET_REGISTER_MOVE_COST.  */
+  move_table *x_move_cost[MAX_MACHINE_MODE];
+
+  /* Similar, but here we don't have to move if the first index is a
+     subset of the second so in that case the cost is zero.  */
+  move_table *x_may_move_in_cost[MAX_MACHINE_MODE];
+
+  /* Similar, but here we don't have to move if the first index is a
+     superset of the second so in that case the cost is zero.  */
+  move_table *x_may_move_out_cost[MAX_MACHINE_MODE];
+
+  /* Keep track of the last mode we initialized move costs for.  */
+  int x_last_mode_for_init_move_cost;
+
+  /* Record for each mode whether we can move a register directly to or
+     from an object of that mode in memory.  If we can't, we won't try
+     to use that mode directly when accessing a field of that mode.  */
+  char x_direct_load[NUM_MACHINE_MODES];
+  char x_direct_store[NUM_MACHINE_MODES];
+
+  /* Record for each mode whether we can float-extend from memory.  */
+  bool x_float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
+};
+
+extern struct target_regs default_target_regs;
+#if SWITCHABLE_TARGET
+extern struct target_regs *this_target_regs;
+#else
+#define this_target_regs (&default_target_regs)
+#endif
 
-/* Specify number of hard registers given machine mode occupy.  */
-extern unsigned char hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE];
+#define hard_regno_nregs \
+  (this_target_regs->x_hard_regno_nregs)
+#define reg_raw_mode \
+  (this_target_regs->x_reg_raw_mode)
+#define have_regs_of_mode \
+  (this_target_regs->x_have_regs_of_mode)
+#define contains_reg_of_mode \
+  (this_target_regs->x_contains_reg_of_mode)
+#define move_cost \
+  (this_target_regs->x_move_cost)
+#define may_move_in_cost \
+  (this_target_regs->x_may_move_in_cost)
+#define may_move_out_cost \
+  (this_target_regs->x_may_move_out_cost)
+#define direct_load \
+  (this_target_regs->x_direct_load)
+#define direct_store \
+  (this_target_regs->x_direct_store)
+#define float_extend_from_mem \
+  (this_target_regs->x_float_extend_from_mem)
+
+/* Return an exclusive upper bound on the registers occupied by hard
+   register (reg:MODE REGNO).  */
+
+static inline unsigned int
+end_hard_regno (enum machine_mode mode, unsigned int regno)
+{
+  return regno + hard_regno_nregs[regno][(int) mode];
+}
+
+/* Likewise for hard register X.  */
+
+#define END_HARD_REGNO(X) end_hard_regno (GET_MODE (X), REGNO (X))
+
+/* Likewise for hard or pseudo register X.  */
+
+#define END_REGNO(X) (HARD_REGISTER_P (X) ? END_HARD_REGNO (X) : REGNO (X) + 1)
+
+/* Add to REGS all the registers required to store a value of mode MODE
+   in register REGNO.  */
+
+static inline void
+add_to_hard_reg_set (HARD_REG_SET *regs, enum machine_mode mode,
+                    unsigned int regno)
+{
+  unsigned int end_regno;
+
+  end_regno = end_hard_regno (mode, regno);
+  do
+    SET_HARD_REG_BIT (*regs, regno);
+  while (++regno < end_regno);
+}
+
+/* Likewise, but remove the registers.  */
+
+static inline void
+remove_from_hard_reg_set (HARD_REG_SET *regs, enum machine_mode mode,
+                         unsigned int regno)
+{
+  unsigned int end_regno;
+
+  end_regno = end_hard_regno (mode, regno);
+  do
+    CLEAR_HARD_REG_BIT (*regs, regno);
+  while (++regno < end_regno);
+}
+
+/* Return true if REGS contains the whole of (reg:MODE REGNO).  */
+
+static inline bool
+in_hard_reg_set_p (const HARD_REG_SET regs, enum machine_mode mode,
+                  unsigned int regno)
+{
+  unsigned int end_regno;
+
+  if (!TEST_HARD_REG_BIT (regs, regno))
+    return false;
+
+  end_regno = end_hard_regno (mode, regno);
+  while (++regno < end_regno)
+    if (!TEST_HARD_REG_BIT (regs, regno))
+      return false;
+
+  return true;
+}
+
+/* Return true if (reg:MODE REGNO) includes an element of REGS.  */
+
+static inline bool
+overlaps_hard_reg_set_p (const HARD_REG_SET regs, enum machine_mode mode,
+                        unsigned int regno)
+{
+  unsigned int end_regno;
+
+  if (TEST_HARD_REG_BIT (regs, regno))
+    return true;
+
+  end_regno = end_hard_regno (mode, regno);
+  while (++regno < end_regno)
+    if (TEST_HARD_REG_BIT (regs, regno))
+      return true;
+
+  return false;
+}
+
+/* Like add_to_hard_reg_set, but use a REGNO/NREGS range instead of
+   REGNO and MODE.  */
+
+static inline void
+add_range_to_hard_reg_set (HARD_REG_SET *regs, unsigned int regno,
+                          int nregs)
+{
+  while (nregs-- > 0)
+    SET_HARD_REG_BIT (*regs, regno + nregs);
+}
+
+/* Likewise, but remove the registers.  */
+
+static inline void
+remove_range_from_hard_reg_set (HARD_REG_SET *regs, unsigned int regno,
+                               int nregs)
+{
+  while (nregs-- > 0)
+    CLEAR_HARD_REG_BIT (*regs, regno + nregs);
+}
+
+/* Like overlaps_hard_reg_set_p, but use a REGNO/NREGS range instead of
+   REGNO and MODE.  */
+static inline bool
+range_overlaps_hard_reg_set_p (const HARD_REG_SET set, unsigned regno,
+                              int nregs)
+{
+  while (nregs-- > 0)
+    if (TEST_HARD_REG_BIT (set, regno + nregs))
+      return true;
+  return false;
+}
+
+/* Like in_hard_reg_set_p, but use a REGNO/NREGS range instead of
+   REGNO and MODE.  */
+static inline bool
+range_in_hard_reg_set_p (const HARD_REG_SET set, unsigned regno, int nregs)
+{
+  while (nregs-- > 0)
+    if (!TEST_HARD_REG_BIT (set, regno + nregs))
+      return false;
+  return true;
+}
 
 #endif /* GCC_REGS_H */