/* Compute different info about registers.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996
1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- 2009 Free Software Foundation, Inc.
+ 2009, 2010, 2011 Free Software Foundation, Inc.
This file is part of GCC.
#include "insn-config.h"
#include "recog.h"
#include "reload.h"
-#include "toplev.h"
#include "diagnostic-core.h"
#include "output.h"
#include "timevar.h"
and are also considered fixed. */
char global_regs[FIRST_PSEUDO_REGISTER];
+/* Declaration for the global register. */
+static tree GTY(()) global_regs_decl[FIRST_PSEUDO_REGISTER];
+
/* Same information as REGS_INVALIDATED_BY_CALL but in regset form to be used
in dataflow more conveniently. */
regset regs_invalidated_by_call_regset;
+/* Same information as FIXED_REG_SET but in regset form. */
+regset fixed_reg_set_regset;
+
/* The bitmap_obstack is used to hold some static variables that
should not be reset after each function is compiled. */
static bitmap_obstack persistent_obstack;
memcpy (reg_alloc_order, initial_reg_alloc_order, sizeof reg_alloc_order);
#endif
memcpy (reg_names, initial_reg_names, sizeof reg_names);
+
+ SET_HARD_REG_SET (accessible_reg_set);
+ SET_HARD_REG_SET (operand_reg_set);
}
/* Initialize may_move_cost and friends for mode M. */
static char saved_call_really_used_regs[FIRST_PSEUDO_REGISTER];
#endif
static const char *saved_reg_names[FIRST_PSEUDO_REGISTER];
+static HARD_REG_SET saved_accessible_reg_set;
+static HARD_REG_SET saved_operand_reg_set;
/* Save the register information. */
void
/* And similarly for reg_names. */
gcc_assert (sizeof reg_names == sizeof saved_reg_names);
memcpy (saved_reg_names, reg_names, sizeof reg_names);
+ COPY_HARD_REG_SET (saved_accessible_reg_set, accessible_reg_set);
+ COPY_HARD_REG_SET (saved_operand_reg_set, operand_reg_set);
}
/* Restore the register information. */
#endif
memcpy (reg_names, saved_reg_names, sizeof reg_names);
+ COPY_HARD_REG_SET (accessible_reg_set, saved_accessible_reg_set);
+ COPY_HARD_REG_SET (operand_reg_set, saved_operand_reg_set);
}
/* After switches have been processed, which perhaps alter
inv_reg_alloc_order[reg_alloc_order[i]] = i;
#endif
- /* This macro allows the fixed or call-used registers
- and the register classes to depend on target flags. */
+ /* Let the target tweak things if necessary. */
-#ifdef CONDITIONAL_REGISTER_USAGE
- CONDITIONAL_REGISTER_USAGE;
-#endif
+ targetm.conditional_register_usage ();
/* Compute number of hard regs in each class. */
}
else
CLEAR_REG_SET (regs_invalidated_by_call_regset);
+ if (!fixed_reg_set_regset)
+ fixed_reg_set_regset = ALLOC_REG_SET (&persistent_obstack);
+ else
+ CLEAR_REG_SET (fixed_reg_set_regset);
+ AND_HARD_REG_SET (operand_reg_set, accessible_reg_set);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
+ /* As a special exception, registers whose class is NO_REGS are
+ not accepted by `register_operand'. The reason for this change
+ is to allow the representation of special architecture artifacts
+ (such as a condition code register) without extending the rtl
+ definitions. Since registers of class NO_REGS cannot be used
+ as registers in any case where register classes are examined,
+ it is better to apply this exception in a target-independent way. */
+ if (REGNO_REG_CLASS (i) == NO_REGS)
+ CLEAR_HARD_REG_BIT (operand_reg_set, i);
+
+ /* If a register is too limited to be treated as a register operand,
+ then it should never be allocated to a pseudo. */
+ if (!TEST_HARD_REG_BIT (operand_reg_set, i))
+ {
+ fixed_regs[i] = 1;
+ call_used_regs[i] = 1;
+ }
+
/* call_used_regs must include fixed_regs. */
gcc_assert (!fixed_regs[i] || call_used_regs[i]);
#ifdef CALL_REALLY_USED_REGISTERS
#endif
if (fixed_regs[i])
- SET_HARD_REG_BIT (fixed_reg_set, i);
+ {
+ SET_HARD_REG_BIT (fixed_reg_set, i);
+ SET_REGNO_REG_SET (fixed_reg_set_regset, i);
+ }
if (call_used_regs[i])
SET_HARD_REG_BIT (call_used_reg_set, i);
}
else if (i == FRAME_POINTER_REGNUM)
;
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
else if (i == HARD_FRAME_POINTER_REGNUM)
;
#endif
else if (i == ARG_POINTER_REGNUM && fixed_regs[i])
;
#endif
-#ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
- else if (i == (unsigned) PIC_OFFSET_TABLE_REGNUM && fixed_regs[i])
+ else if (!PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+ && i == (unsigned) PIC_OFFSET_TABLE_REGNUM && fixed_regs[i])
;
-#endif
else if (CALL_REALLY_USED_REGNO_P (i))
{
SET_HARD_REG_BIT (regs_invalidated_by_call, i);
SET_HARD_REG_BIT (ok_regs, j);
for (i = 0; i < N_REG_CLASSES; i++)
- if (((unsigned) CLASS_MAX_NREGS ((enum reg_class) i,
- (enum machine_mode) m)
+ if ((targetm.class_max_nregs ((reg_class_t) i, (enum machine_mode) m)
<= reg_class_size[i])
&& hard_reg_set_intersect_p (ok_regs, reg_class_contents[i]))
{
TO, using MODE. */
int
-register_move_cost (enum machine_mode mode, enum reg_class from,
- enum reg_class to)
+register_move_cost (enum machine_mode mode, reg_class_t from, reg_class_t to)
{
return targetm.register_move_cost (mode, from, to);
}
/* Compute cost of moving registers to/from memory. */
+
int
-memory_move_cost (enum machine_mode mode, enum reg_class rclass, bool in)
+memory_move_cost (enum machine_mode mode, reg_class_t rclass, bool in)
{
return targetm.memory_move_cost (mode, rclass, in);
}
/* Compute extra cost of moving registers to/from memory due to reloads.
Only needed if secondary reloads are required for memory moves. */
int
-memory_move_secondary_cost (enum machine_mode mode, enum reg_class rclass,
+memory_move_secondary_cost (enum machine_mode mode, reg_class_t rclass,
bool in)
{
- enum reg_class altclass;
+ reg_class_t altclass;
int partial_cost = 0;
/* We need a memory reference to feed to SECONDARY... macros. */
/* mem may be unused even if the SECONDARY_ macros are defined. */
fix_register (const char *name, int fixed, int call_used)
{
int i;
+ int reg, nregs;
/* Decode the name and update the primary form of
the register info. */
- if ((i = decode_reg_name (name)) >= 0)
+ if ((reg = decode_reg_name_and_count (name, &nregs)) >= 0)
{
- if ((i == STACK_POINTER_REGNUM
+ gcc_assert (nregs >= 1);
+ for (i = reg; i < reg + nregs; i++)
+ {
+ if ((i == STACK_POINTER_REGNUM
#ifdef HARD_FRAME_POINTER_REGNUM
- || i == HARD_FRAME_POINTER_REGNUM
+ || i == HARD_FRAME_POINTER_REGNUM
#else
- || i == FRAME_POINTER_REGNUM
+ || i == FRAME_POINTER_REGNUM
#endif
- )
- && (fixed == 0 || call_used == 0))
- {
- static const char * const what_option[2][2] = {
- { "call-saved", "call-used" },
- { "no-such-option", "fixed" }};
-
- error ("can't use '%s' as a %s register", name,
- what_option[fixed][call_used]);
- }
- else
- {
- fixed_regs[i] = fixed;
- call_used_regs[i] = call_used;
+ )
+ && (fixed == 0 || call_used == 0))
+ {
+ switch (fixed)
+ {
+ case 0:
+ switch (call_used)
+ {
+ case 0:
+ error ("can%'t use %qs as a call-saved register", name);
+ break;
+
+ case 1:
+ error ("can%'t use %qs as a call-used register", name);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case 1:
+ switch (call_used)
+ {
+ case 1:
+ error ("can%'t use %qs as a fixed register", name);
+ break;
+
+ case 0:
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ fixed_regs[i] = fixed;
+ call_used_regs[i] = call_used;
#ifdef CALL_REALLY_USED_REGISTERS
- if (fixed == 0)
- call_really_used_regs[i] = call_used;
+ if (fixed == 0)
+ call_really_used_regs[i] = call_used;
#endif
+ }
}
}
else
/* Mark register number I as global. */
void
-globalize_reg (int i)
+globalize_reg (tree decl, int i)
{
+ location_t loc = DECL_SOURCE_LOCATION (decl);
+
+#ifdef STACK_REGS
+ if (IN_RANGE (i, FIRST_STACK_REG, LAST_STACK_REG))
+ {
+ error ("stack register used for global register variable");
+ return;
+ }
+#endif
+
if (fixed_regs[i] == 0 && no_global_reg_vars)
- error ("global register variable follows a function definition");
+ error_at (loc, "global register variable follows a function definition");
if (global_regs[i])
{
- warning (0, "register used for two global register variables");
+ warning_at (loc, 0,
+ "register of %qD used for multiple global register variables",
+ decl);
+ inform (DECL_SOURCE_LOCATION (global_regs_decl[i]),
+ "conflicts with %qD", global_regs_decl[i]);
return;
}
if (call_used_regs[i] && ! fixed_regs[i])
- warning (0, "call-clobbered register used for global register variable");
+ warning_at (loc, 0, "call-clobbered register used for global register variable");
global_regs[i] = 1;
+ global_regs_decl[i] = decl;
/* If we're globalizing the frame pointer, we need to set the
appropriate regs_invalidated_by_call bit, even if it's already
union of most major pair of classes, that generality is not required. */
char altclass;
- /* coverclass is a register class that IRA uses for allocating
+ /* allocnoclass is a register class that IRA uses for allocating
the pseudo. */
- char coverclass;
+ char allocnoclass;
};
/* Record preferences of each pseudo. This is available after RA is
/* Return the reg_class which is used by IRA for its allocation. */
enum reg_class
-reg_cover_class (int regno)
+reg_allocno_class (int regno)
{
if (reg_pref == 0)
return NO_REGS;
- return (enum reg_class) reg_pref[regno].coverclass;
+ return (enum reg_class) reg_pref[regno].allocnoclass;
}
\f
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- TV_NONE, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
\f
/* Set up preferred, alternate, and cover classes for REGNO as
- PREFCLASS, ALTCLASS, and COVERCLASS. */
+ PREFCLASS, ALTCLASS, and ALLOCNOCLASS. */
void
setup_reg_classes (int regno,
enum reg_class prefclass, enum reg_class altclass,
- enum reg_class coverclass)
+ enum reg_class allocnoclass)
{
if (reg_pref == NULL)
return;
gcc_assert (reg_info_size == max_reg_num ());
reg_pref[regno].prefclass = prefclass;
reg_pref[regno].altclass = altclass;
- reg_pref[regno].coverclass = coverclass;
+ reg_pref[regno].allocnoclass = allocnoclass;
}
\f
/* Return nonzero if C1 is a subset of C2, i.e., if every register in C1
is also in C2. */
int
-reg_class_subset_p (enum reg_class c1, enum reg_class c2)
+reg_class_subset_p (reg_class_t c1, reg_class_t c2)
{
return (c1 == c2
|| c2 == ALL_REGS
#ifdef CANNOT_CHANGE_MODE_CLASS
-struct subregs_of_mode_node
-{
- unsigned int block;
- unsigned char modes[MAX_MACHINE_MODE];
-};
-
-static htab_t subregs_of_mode;
-
-static hashval_t
-som_hash (const void *x)
-{
- const struct subregs_of_mode_node *const a =
- (const struct subregs_of_mode_node *) x;
- return a->block;
-}
-
-static int
-som_eq (const void *x, const void *y)
-{
- const struct subregs_of_mode_node *const a =
- (const struct subregs_of_mode_node *) x;
- const struct subregs_of_mode_node *const b =
- (const struct subregs_of_mode_node *) y;
- return a->block == b->block;
-}
+static bitmap invalid_mode_changes;
static void
-record_subregs_of_mode (rtx subreg)
+record_subregs_of_mode (rtx subreg, bitmap subregs_of_mode)
{
- struct subregs_of_mode_node dummy, *node;
enum machine_mode mode;
unsigned int regno;
- void **slot;
if (!REG_P (SUBREG_REG (subreg)))
return;
if (regno < FIRST_PSEUDO_REGISTER)
return;
- dummy.block = regno & -8;
- slot = htab_find_slot_with_hash (subregs_of_mode, &dummy,
- dummy.block, INSERT);
- node = (struct subregs_of_mode_node *) *slot;
- if (node == NULL)
+ if (bitmap_set_bit (subregs_of_mode,
+ regno * NUM_MACHINE_MODES + (unsigned int) mode))
{
- node = XCNEW (struct subregs_of_mode_node);
- node->block = regno & -8;
- *slot = node;
+ unsigned int rclass;
+ for (rclass = 0; rclass < N_REG_CLASSES; rclass++)
+ if (!bitmap_bit_p (invalid_mode_changes,
+ regno * N_REG_CLASSES + rclass)
+ && CANNOT_CHANGE_MODE_CLASS (PSEUDO_REGNO_MODE (regno),
+ mode, (enum reg_class) rclass))
+ bitmap_set_bit (invalid_mode_changes,
+ regno * N_REG_CLASSES + rclass);
}
-
- node->modes[mode] |= 1 << (regno & 7);
}
/* Call record_subregs_of_mode for all the subregs in X. */
static void
-find_subregs_of_mode (rtx x)
+find_subregs_of_mode (rtx x, bitmap subregs_of_mode)
{
enum rtx_code code = GET_CODE (x);
const char * const fmt = GET_RTX_FORMAT (code);
int i;
if (code == SUBREG)
- record_subregs_of_mode (x);
+ record_subregs_of_mode (x, subregs_of_mode);
/* Time for some deep diving. */
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
- find_subregs_of_mode (XEXP (x, i));
+ find_subregs_of_mode (XEXP (x, i), subregs_of_mode);
else if (fmt[i] == 'E')
{
int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- find_subregs_of_mode (XVECEXP (x, i, j));
+ find_subregs_of_mode (XVECEXP (x, i, j), subregs_of_mode);
}
}
}
{
basic_block bb;
rtx insn;
+ bitmap_obstack srom_obstack;
+ bitmap subregs_of_mode;
- if (subregs_of_mode)
- htab_empty (subregs_of_mode);
- else
- subregs_of_mode = htab_create (100, som_hash, som_eq, free);
+ gcc_assert (invalid_mode_changes == NULL);
+ invalid_mode_changes = BITMAP_ALLOC (NULL);
+ bitmap_obstack_initialize (&srom_obstack);
+ subregs_of_mode = BITMAP_ALLOC (&srom_obstack);
FOR_EACH_BB (bb)
FOR_BB_INSNS (bb, insn)
- if (INSN_P (insn))
- find_subregs_of_mode (PATTERN (insn));
+ if (NONDEBUG_INSN_P (insn))
+ find_subregs_of_mode (PATTERN (insn), subregs_of_mode);
+
+ BITMAP_FREE (subregs_of_mode);
+ bitmap_obstack_release (&srom_obstack);
}
/* Return 1 if REGNO has had an invalid mode change in CLASS from FROM
mode. */
bool
invalid_mode_change_p (unsigned int regno,
- enum reg_class rclass ATTRIBUTE_UNUSED,
- enum machine_mode from)
+ enum reg_class rclass)
{
- struct subregs_of_mode_node dummy, *node;
- unsigned int to;
- unsigned char mask;
-
- gcc_assert (subregs_of_mode);
- dummy.block = regno & -8;
- node = (struct subregs_of_mode_node *)
- htab_find_with_hash (subregs_of_mode, &dummy, dummy.block);
- if (node == NULL)
- return false;
-
- mask = 1 << (regno & 7);
- for (to = VOIDmode; to < NUM_MACHINE_MODES; to++)
- if (node->modes[to] & mask)
- if (CANNOT_CHANGE_MODE_CLASS (from, (enum machine_mode) to, rclass))
- return true;
-
- return false;
+ return bitmap_bit_p (invalid_mode_changes,
+ regno * N_REG_CLASSES + (unsigned) rclass);
}
void
finish_subregs_of_mode (void)
{
- htab_delete (subregs_of_mode);
- subregs_of_mode = 0;
+ BITMAP_FREE (invalid_mode_changes);
}
#else
void