/* Compute register class preferences for pseudo-registers.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996
- 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hard-reg-set.h"
#include "rtl.h"
#include "expr.h"
#include "tm_p.h"
-#include "hard-reg-set.h"
#include "flags.h"
#include "basic-block.h"
#include "regs.h"
#endif /* FORBIDDEN_INC_DEC_CLASSES */
-#ifdef CLASS_CANNOT_CHANGE_MODE
-
-/* These are the classes containing only registers that can be used in
- a SUBREG expression that changes the mode of the register in some
- way that is illegal. */
-
-static int class_can_change_mode[N_REG_CLASSES];
-
-/* Registers, including pseudos, which change modes in some way that
- is illegal. */
-
-static regset reg_changes_mode;
-
-#endif /* CLASS_CANNOT_CHANGE_MODE */
+#ifdef CANNOT_CHANGE_MODE_CLASS
+/* All registers that have been subreged. Indexed by mode, where each
+ entry is a regset of registers. */
+regset_head subregs_of_mode [NUM_MACHINE_MODES];
+#endif
/* Sample MEM values for use by memory_move_secondary_cost. */
;
#endif
#ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
- else if (i == PIC_OFFSET_TABLE_REGNUM && fixed_regs[i])
+ else if (i == (unsigned) PIC_OFFSET_TABLE_REGNUM && fixed_regs[i])
;
#endif
else if (0
may_move_out_cost[m][i][j] = 65536;
}
}
-
-#ifdef CLASS_CANNOT_CHANGE_MODE
- {
- HARD_REG_SET c;
- COMPL_HARD_REG_SET (c, reg_class_contents[CLASS_CANNOT_CHANGE_MODE]);
-
- for (i = 0; i < N_REG_CLASSES; i++)
- {
- GO_IF_HARD_REG_SUBSET (reg_class_contents[i], c, ok_class);
- class_can_change_mode [i] = 0;
- continue;
- ok_class:
- class_can_change_mode [i] = 1;
- }
- }
-#endif /* CLASS_CANNOT_CHANGE_MODE */
}
/* Compute the table of register modes.
int mem_cost;
};
-/* Structure used to record preferrences of given pseudo. */
+/* Structure used to record preferences of given pseudo. */
struct reg_pref
{
/* (enum reg_class) prefclass is the preferred class. */
static struct costs init_cost;
-/* Record preferrences of each pseudo.
+/* Record preferences of each pseudo.
This is available after `regclass' is run. */
static struct reg_pref *reg_pref;
&& (!in_inc_dec[i]
|| !forbidden_inc_dec_class[(enum reg_class) class])
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && (!REGNO_REG_SET_P (reg_changes_mode, i)
- || class_can_change_mode [(enum reg_class) class])
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && ! invalid_mode_change_p (i, (enum reg_class) class,
+ PSEUDO_REGNO_MODE (i))
#endif
)
fprintf (dump, " %s:%i", reg_class_names[class],
op_costs[i] = init_cost;
if (GET_CODE (recog_data.operand[i]) == SUBREG)
- {
- rtx inner = SUBREG_REG (recog_data.operand[i]);
-#ifdef CLASS_CANNOT_CHANGE_MODE
- if (GET_CODE (inner) == REG
- && CLASS_CANNOT_CHANGE_MODE_P (modes[i], GET_MODE (inner)))
- SET_REGNO_REG_SET (reg_changes_mode, REGNO (inner));
-#endif
- recog_data.operand[i] = inner;
- }
+ recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]);
if (GET_CODE (recog_data.operand[i]) == MEM)
record_address_regs (XEXP (recog_data.operand[i], 0),
MODE_BASE_REG_CLASS (modes[i]), frequency * 2);
else if (constraints[i][0] == 'p'
- || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0]))
+ || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
record_address_regs (recog_data.operand[i],
MODE_BASE_REG_CLASS (modes[i]), frequency * 2);
}
costs = (struct costs *) xmalloc (nregs * sizeof (struct costs));
-#ifdef CLASS_CANNOT_CHANGE_MODE
- reg_changes_mode = BITMAP_XMALLOC ();
-#endif
-
#ifdef FORBIDDEN_INC_DEC_CLASSES
in_inc_dec = (char *) xmalloc (nregs);
#ifdef FORBIDDEN_INC_DEC_CLASSES
|| (in_inc_dec[i] && forbidden_inc_dec_class[class])
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
- || (REGNO_REG_SET_P (reg_changes_mode, i)
- && ! class_can_change_mode [class])
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ || invalid_mode_change_p (i, (enum reg_class) class,
+ PSEUDO_REGNO_MODE (i))
#endif
)
;
#ifdef FORBIDDEN_INC_DEC_CLASSES
&& ! (in_inc_dec[i] && forbidden_inc_dec_class[class])
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
- && ! (REGNO_REG_SET_P (reg_changes_mode, i)
- && ! class_can_change_mode [class])
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ && ! invalid_mode_change_p (i, (enum reg_class) class,
+ PSEUDO_REGNO_MODE (i))
#endif
)
alt = reg_class_subunion[(int) alt][class];
#ifdef FORBIDDEN_INC_DEC_CLASSES
free (in_inc_dec);
#endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
- BITMAP_XFREE (reg_changes_mode);
-#endif
free (costs);
}
\f
any of the constraints. Collect the valid register classes
and see if this operand accepts memory. */
- while (*p && (c = *p++) != ',')
- switch (c)
- {
- case '*':
- /* Ignore the next letter for this pass. */
- p++;
- break;
-
- case '?':
- alt_cost += 2;
- case '!': case '#': case '&':
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- break;
+ while ((c = *p))
+ {
+ switch (c)
+ {
+ case ',':
+ break;
+ case '*':
+ /* Ignore the next letter for this pass. */
+ c = *++p;
+ break;
- case 'p':
- allows_addr = 1;
- win = address_operand (op, GET_MODE (op));
- /* We know this operand is an address, so we want it to be
- allocated to a register that can be the base of an
- address, ie BASE_REG_CLASS. */
- classes[i]
- = reg_class_subunion[(int) classes[i]]
- [(int) MODE_BASE_REG_CLASS (VOIDmode)];
- break;
+ case '?':
+ alt_cost += 2;
+ case '!': case '#': case '&':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ break;
- case 'm': case 'o': case 'V':
- /* It doesn't seem worth distinguishing between offsettable
- and non-offsettable addresses here. */
- allows_mem[i] = 1;
- if (GET_CODE (op) == MEM)
- win = 1;
- break;
+ case 'p':
+ allows_addr = 1;
+ win = address_operand (op, GET_MODE (op));
+ /* We know this operand is an address, so we want it to be
+ allocated to a register that can be the base of an
+ address, ie BASE_REG_CLASS. */
+ classes[i]
+ = reg_class_subunion[(int) classes[i]]
+ [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+ break;
- case '<':
- if (GET_CODE (op) == MEM
- && (GET_CODE (XEXP (op, 0)) == PRE_DEC
- || GET_CODE (XEXP (op, 0)) == POST_DEC))
- win = 1;
- break;
+ case 'm': case 'o': case 'V':
+ /* It doesn't seem worth distinguishing between offsettable
+ and non-offsettable addresses here. */
+ allows_mem[i] = 1;
+ if (GET_CODE (op) == MEM)
+ win = 1;
+ break;
- case '>':
- if (GET_CODE (op) == MEM
- && (GET_CODE (XEXP (op, 0)) == PRE_INC
- || GET_CODE (XEXP (op, 0)) == POST_INC))
- win = 1;
- break;
+ case '<':
+ if (GET_CODE (op) == MEM
+ && (GET_CODE (XEXP (op, 0)) == PRE_DEC
+ || GET_CODE (XEXP (op, 0)) == POST_DEC))
+ win = 1;
+ break;
- case 'E':
- case 'F':
- if (GET_CODE (op) == CONST_DOUBLE
- || (GET_CODE (op) == CONST_VECTOR
- && (GET_MODE_CLASS (GET_MODE (op))
- == MODE_VECTOR_FLOAT)))
- win = 1;
- break;
+ case '>':
+ if (GET_CODE (op) == MEM
+ && (GET_CODE (XEXP (op, 0)) == PRE_INC
+ || GET_CODE (XEXP (op, 0)) == POST_INC))
+ win = 1;
+ break;
- case 'G':
- case 'H':
- if (GET_CODE (op) == CONST_DOUBLE
- && CONST_DOUBLE_OK_FOR_LETTER_P (op, c))
- win = 1;
- break;
+ case 'E':
+ case 'F':
+ if (GET_CODE (op) == CONST_DOUBLE
+ || (GET_CODE (op) == CONST_VECTOR
+ && (GET_MODE_CLASS (GET_MODE (op))
+ == MODE_VECTOR_FLOAT)))
+ win = 1;
+ break;
- case 's':
- if (GET_CODE (op) == CONST_INT
- || (GET_CODE (op) == CONST_DOUBLE
- && GET_MODE (op) == VOIDmode))
+ case 'G':
+ case 'H':
+ if (GET_CODE (op) == CONST_DOUBLE
+ && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
+ win = 1;
break;
- case 'i':
- if (CONSTANT_P (op)
+
+ case 's':
+ if (GET_CODE (op) == CONST_INT
+ || (GET_CODE (op) == CONST_DOUBLE
+ && GET_MODE (op) == VOIDmode))
+ break;
+ case 'i':
+ if (CONSTANT_P (op)
#ifdef LEGITIMATE_PIC_OPERAND_P
- && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
+ && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
#endif
- )
- win = 1;
- break;
+ )
+ win = 1;
+ break;
- case 'n':
- if (GET_CODE (op) == CONST_INT
- || (GET_CODE (op) == CONST_DOUBLE
- && GET_MODE (op) == VOIDmode))
- win = 1;
- break;
+ case 'n':
+ if (GET_CODE (op) == CONST_INT
+ || (GET_CODE (op) == CONST_DOUBLE
+ && GET_MODE (op) == VOIDmode))
+ win = 1;
+ break;
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- case 'N':
- case 'O':
- case 'P':
- if (GET_CODE (op) == CONST_INT
- && CONST_OK_FOR_LETTER_P (INTVAL (op), c))
- win = 1;
- break;
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ if (GET_CODE (op) == CONST_INT
+ && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
+ win = 1;
+ break;
- case 'X':
- win = 1;
- break;
+ case 'X':
+ win = 1;
+ break;
- case 'g':
- if (GET_CODE (op) == MEM
- || (CONSTANT_P (op)
+ case 'g':
+ if (GET_CODE (op) == MEM
+ || (CONSTANT_P (op)
#ifdef LEGITIMATE_PIC_OPERAND_P
- && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
+ && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
#endif
- ))
- win = 1;
- allows_mem[i] = 1;
- case 'r':
- classes[i]
- = reg_class_subunion[(int) classes[i]][(int) GENERAL_REGS];
- break;
-
- default:
- if (REG_CLASS_FROM_LETTER (c) != NO_REGS)
+ ))
+ win = 1;
+ allows_mem[i] = 1;
+ case 'r':
classes[i]
- = reg_class_subunion[(int) classes[i]]
- [(int) REG_CLASS_FROM_LETTER (c)];
-#ifdef EXTRA_CONSTRAINT
- else if (EXTRA_CONSTRAINT (op, c))
- win = 1;
+ = reg_class_subunion[(int) classes[i]][(int) GENERAL_REGS];
+ break;
- if (EXTRA_MEMORY_CONSTRAINT (c))
- {
- /* Every MEM can be reloaded to fit. */
- allows_mem[i] = 1;
- if (GET_CODE (op) == MEM)
- win = 1;
- }
- if (EXTRA_ADDRESS_CONSTRAINT (op))
- {
- /* Every address can be reloaded to fit. */
- allows_addr = 1;
- if (address_operand (op, GET_MODE (op)))
- win = 1;
- /* We know this operand is an address, so we want it to be
- allocated to a register that can be the base of an
- address, ie BASE_REG_CLASS. */
+ default:
+ if (REG_CLASS_FROM_CONSTRAINT (c, p) != NO_REGS)
classes[i]
= reg_class_subunion[(int) classes[i]]
- [(int) MODE_BASE_REG_CLASS (VOIDmode)];
- }
+ [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
+#ifdef EXTRA_CONSTRAINT_STR
+ else if (EXTRA_CONSTRAINT_STR (op, c, p))
+ win = 1;
+
+ if (EXTRA_MEMORY_CONSTRAINT (c, p))
+ {
+ /* Every MEM can be reloaded to fit. */
+ allows_mem[i] = 1;
+ if (GET_CODE (op) == MEM)
+ win = 1;
+ }
+ if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+ {
+ /* Every address can be reloaded to fit. */
+ allows_addr = 1;
+ if (address_operand (op, GET_MODE (op)))
+ win = 1;
+ /* We know this operand is an address, so we want it to
+ be allocated to a register that can be the base of an
+ address, ie BASE_REG_CLASS. */
+ classes[i]
+ = reg_class_subunion[(int) classes[i]]
+ [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+ }
#endif
+ break;
+ }
+ p += CONSTRAINT_LEN (c, p);
+ if (c == ',')
break;
- }
+ }
constraints[i] = p;
&& REGNO (SET_DEST (x)) >= min_regno
/* If the destination pseudo is set more than once, then other
sets might not be to a pointer value (consider access to a
- union in two threads of control in the presense of global
+ union in two threads of control in the presence of global
optimizations). So only set REG_POINTER on the destination
pseudo if this is the only set of that pseudo. */
&& REG_N_SETS (REGNO (SET_DEST (x))) == 1
bitmap_release_memory ();
}
+#ifdef CANNOT_CHANGE_MODE_CLASS
+/* Set bits in *USED which correspond to registers which can't change
+ their mode from FROM to any mode in which REGNO was encountered. */
+
+void
+cannot_change_mode_set_regs (used, from, regno)
+ HARD_REG_SET *used;
+ enum machine_mode from;
+ unsigned int regno;
+{
+ enum machine_mode to;
+ enum reg_class class;
+
+ for (to = VOIDmode; to < MAX_MACHINE_MODE; ++to)
+ if (REGNO_REG_SET_P (&subregs_of_mode[to], regno))
+ {
+ class = CANNOT_CHANGE_MODE_CLASS (from, to);
+ if (class != NO_REGS)
+ IOR_HARD_REG_SET (*used, reg_class_contents [(int) class]);
+ }
+}
+
+/* Return 1 if REGNO has had an invalid mode change in CLASS from FROM
+ mode. */
+
+bool
+invalid_mode_change_p (regno, class, from_mode)
+ unsigned int regno;
+ enum reg_class class;
+ enum machine_mode from_mode;
+{
+ enum machine_mode to_mode;
+
+ for (to_mode = 0; to_mode < NUM_MACHINE_MODES; ++to_mode)
+ if (REGNO_REG_SET_P (&subregs_of_mode[(int) to_mode], regno)
+ && reg_classes_intersect_p
+ (class, CANNOT_CHANGE_MODE_CLASS (from_mode, to_mode)))
+ return 1;
+ return 0;
+}
+#endif /* CANNOT_CHANGE_MODE_CLASS */
+
#include "gt-regclass.h"