diff options
author | obrien <obrien@FreeBSD.org> | 2002-02-01 18:16:02 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2002-02-01 18:16:02 +0000 |
commit | c9ab9ae440a8066b2c2b85b157b1fdadcf09916a (patch) | |
tree | 086d9d6c8fbd4fc8fe4495059332f66bc0f8d12b /contrib/gcc/regclass.c | |
parent | 2ecfd8bd04b63f335c1ec6295740a4bfd97a4fa6 (diff) | |
download | FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.zip FreeBSD-src-c9ab9ae440a8066b2c2b85b157b1fdadcf09916a.tar.gz |
Enlist the FreeBSD-CURRENT users as testers of what is to become Gcc 3.1.0.
These bits are taken from the FSF anoncvs repo on 1-Feb-2002 08:20 PST.
Diffstat (limited to 'contrib/gcc/regclass.c')
-rw-r--r-- | contrib/gcc/regclass.c | 1228 |
1 files changed, 805 insertions, 423 deletions
diff --git a/contrib/gcc/regclass.c b/contrib/gcc/regclass.c index 4e16288..d064e24 100644 --- a/contrib/gcc/regclass.c +++ b/contrib/gcc/regclass.c @@ -1,22 +1,23 @@ /* Compute register class preferences for pseudo-registers. - Copyright (C) 1987, 88, 91-98, 1999 Free Software Foundation, Inc. + Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996 + 1997, 1998, 1999, 2000, 2001, 2002 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. */ /* This file contains two passes of the compiler: reg_scan and reg_class. @@ -26,23 +27,27 @@ Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.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" +#include "function.h" #include "insn-config.h" #include "recog.h" #include "reload.h" #include "real.h" #include "toplev.h" #include "output.h" +#include "ggc.h" #ifndef REGISTER_MOVE_COST -#define REGISTER_MOVE_COST(x, y) 2 +#define REGISTER_MOVE_COST(m, x, y) 2 #endif -static void init_reg_sets_1 PROTO((void)); -static void init_reg_modes PROTO((void)); +static void init_reg_sets_1 PARAMS ((void)); +static void init_reg_modes PARAMS ((void)); /* If we have auto-increment or auto-decrement and we can have secondary reloads, we are not allowed to use classes requiring secondary @@ -69,7 +74,7 @@ HARD_REG_SET fixed_reg_set; /* Data for initializing the above. */ -static char initial_fixed_regs[] = FIXED_REGISTERS; +static const char initial_fixed_regs[] = FIXED_REGISTERS; /* Indexed by hard register number, contains 1 for registers that are fixed use or are clobbered by function calls. @@ -88,7 +93,16 @@ HARD_REG_SET losing_caller_save_reg_set; /* Data for initializing the above. */ -static char initial_call_used_regs[] = CALL_USED_REGISTERS; +static const char initial_call_used_regs[] = CALL_USED_REGISTERS; + +/* This is much like call_used_regs, except it doesn't have to + be a superset of FIXED_REGISTERS. This vector indicates + what is really call clobbered, and is used when defining + regs_invalidated_by_call. */ + +#ifdef CALL_REALLY_USED_REGISTERS +char call_really_used_regs[] = CALL_REALLY_USED_REGISTERS; +#endif /* Indexed by hard register number, contains 1 for registers that are fixed use or call used registers that cannot hold quantities across @@ -111,10 +125,22 @@ int n_non_fixed_regs; and are also considered fixed. */ char global_regs[FIRST_PSEUDO_REGISTER]; - + +/* Contains 1 for registers that are set or clobbered by calls. */ +/* ??? Ideally, this would be just call_used_regs plus global_regs, but + for someone's bright idea to have call_used_regs strictly include + fixed_regs. Which leaves us guessing as to the set of fixed_regs + that are actually preserved. We know for sure that those associated + with the local stack frame are safe, but scant others. */ + +HARD_REG_SET regs_invalidated_by_call; + /* Table of register numbers in the order in which to try to use them. */ #ifdef REG_ALLOC_ORDER int reg_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER; + +/* The inverse of reg_alloc_order. */ +int inv_reg_alloc_order[FIRST_PSEUDO_REGISTER]; #endif /* For each reg class, a HARD_REG_SET saying which registers are in it. */ @@ -123,17 +149,18 @@ HARD_REG_SET reg_class_contents[N_REG_CLASSES]; /* The same information, but as an array of unsigned ints. We copy from these unsigned ints to the table above. We do this so the tm.h files - do not have to be aware of the wordsize for machines with <= 64 regs. */ + do not have to be aware of the wordsize for machines with <= 64 regs. + Note that we hard-code 32 here, not HOST_BITS_PER_INT. */ #define N_REG_INTS \ - ((FIRST_PSEUDO_REGISTER + (HOST_BITS_PER_INT - 1)) / HOST_BITS_PER_INT) + ((FIRST_PSEUDO_REGISTER + (32 - 1)) / 32) -static unsigned int_reg_class_contents[N_REG_CLASSES][N_REG_INTS] +static const unsigned int_reg_class_contents[N_REG_CLASSES][N_REG_INTS] = REG_CLASS_CONTENTS; /* For each reg class, number of regs it contains. */ -int reg_class_size[N_REG_CLASSES]; +unsigned int reg_class_size[N_REG_CLASSES]; /* For each reg class, table listing all the containing classes. */ @@ -153,9 +180,12 @@ enum reg_class reg_class_subunion[N_REG_CLASSES][N_REG_CLASSES]; enum reg_class reg_class_superunion[N_REG_CLASSES][N_REG_CLASSES]; -/* Array containing all of the register names */ +/* Array containing all of the register names. Unless + DEBUG_REGISTER_NAMES is defined, use the copy in print-rtl.c. */ -char *reg_names[] = REGISTER_NAMES; +#ifdef DEBUG_REGISTER_NAMES +const char * reg_names[] = REGISTER_NAMES; +#endif /* 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 @@ -164,15 +194,24 @@ char *reg_names[] = REGISTER_NAMES; enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER]; +/* 1 if class does contain register of given mode. */ + +static char 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 REGISTER_MOVE_COST. */ -static int move_cost[N_REG_CLASSES][N_REG_CLASSES]; +static int move_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES]; /* 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. */ -static int may_move_cost[N_REG_CLASSES][N_REG_CLASSES]; +static int may_move_in_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES]; + +/* 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. */ + +static int may_move_out_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES]; #ifdef FORBIDDEN_INC_DEC_CLASSES @@ -188,6 +227,21 @@ static char *in_inc_dec; #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 HAVE_SECONDARY_RELOADS /* Sample MEM values for use by memory_move_secondary_cost. */ @@ -210,6 +264,11 @@ struct reg_info_data { static struct reg_info_data *reg_info_head; +/* No more global register variables may be declared; true once + regclass has been initialized. */ + +static int no_global_reg_vars = 0; + /* Function called only once to initialize the above data on reg usage. Once this is done, various switches may override. */ @@ -217,7 +276,7 @@ static struct reg_info_data *reg_info_head; void init_reg_sets () { - register int i, j; + int i, j; /* First copy the register information from the initial int form into the regsets. */ @@ -226,18 +285,24 @@ init_reg_sets () { CLEAR_HARD_REG_SET (reg_class_contents[i]); + /* Note that we hard-code 32 here, not HOST_BITS_PER_INT. */ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) - if (int_reg_class_contents[i][j / HOST_BITS_PER_INT] - & ((unsigned) 1 << (j % HOST_BITS_PER_INT))) + if (int_reg_class_contents[i][j / 32] + & ((unsigned) 1 << (j % 32))) SET_HARD_REG_BIT (reg_class_contents[i], j); } - bcopy (initial_fixed_regs, fixed_regs, sizeof fixed_regs); - bcopy (initial_call_used_regs, call_used_regs, sizeof call_used_regs); - bzero (global_regs, sizeof global_regs); + memcpy (fixed_regs, initial_fixed_regs, sizeof fixed_regs); + memcpy (call_used_regs, initial_call_used_regs, sizeof call_used_regs); + memset (global_regs, 0, sizeof global_regs); /* Do any additional initialization regsets may need */ INIT_ONCE_REG_SET (); + +#ifdef REG_ALLOC_ORDER + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + inv_reg_alloc_order[reg_alloc_order[i]] = i; +#endif } /* After switches have been processed, which perhaps alter @@ -246,7 +311,9 @@ init_reg_sets () static void init_reg_sets_1 () { - register unsigned int i, j; + unsigned int i, j; + unsigned int /* enum machine_mode */ m; + char allocatable_regs_of_mode [MAX_MACHINE_MODE]; /* This macro allows the fixed or call-used registers and the register classes to depend on target flags. */ @@ -257,7 +324,7 @@ init_reg_sets_1 () /* Compute number of hard regs in each class. */ - bzero ((char *) reg_class_size, sizeof reg_class_size); + memset ((char *) reg_class_size, 0, sizeof reg_class_size); for (i = 0; i < N_REG_CLASSES; i++) for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) if (TEST_HARD_REG_BIT (reg_class_contents[i], j)) @@ -275,7 +342,7 @@ init_reg_sets_1 () register /* Declare it register if it's a scalar. */ #endif HARD_REG_SET c; - register int k; + int k; COPY_HARD_REG_SET (c, reg_class_contents[i]); IOR_HARD_REG_SET (c, reg_class_contents[j]); @@ -309,7 +376,7 @@ init_reg_sets_1 () register /* Declare it register if it's a scalar. */ #endif HARD_REG_SET c; - register int k; + int k; COPY_HARD_REG_SET (c, reg_class_contents[i]); IOR_HARD_REG_SET (c, reg_class_contents[j]); @@ -363,8 +430,9 @@ init_reg_sets_1 () CLEAR_HARD_REG_SET (fixed_reg_set); CLEAR_HARD_REG_SET (call_used_reg_set); CLEAR_HARD_REG_SET (call_fixed_reg_set); + CLEAR_HARD_REG_SET (regs_invalidated_by_call); - bcopy (fixed_regs, call_fixed_regs, sizeof call_fixed_regs); + memcpy (call_fixed_regs, fixed_regs, sizeof call_fixed_regs); n_non_fixed_regs = 0; @@ -381,39 +449,126 @@ init_reg_sets_1 () SET_HARD_REG_BIT (call_fixed_reg_set, i); if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (i))) SET_HARD_REG_BIT (losing_caller_save_reg_set, i); + + /* There are a couple of fixed registers that we know are safe to + exclude from being clobbered by calls: + + The frame pointer is always preserved across calls. The arg pointer + is if it is fixed. The stack pointer usually is, unless + RETURN_POPS_ARGS, in which case an explicit CLOBBER will be present. + If we are generating PIC code, the PIC offset table register is + preserved across calls, though the target can override that. */ + + if (i == STACK_POINTER_REGNUM || i == FRAME_POINTER_REGNUM) + ; +#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + else if (i == HARD_FRAME_POINTER_REGNUM) + ; +#endif +#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM + else if (i == ARG_POINTER_REGNUM && fixed_regs[i]) + ; +#endif +#ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED + else if (i == PIC_OFFSET_TABLE_REGNUM && fixed_regs[i]) + ; +#endif + else if (0 +#ifdef CALL_REALLY_USED_REGISTERS + || call_really_used_regs[i] +#else + || call_used_regs[i] +#endif + || global_regs[i]) + SET_HARD_REG_BIT (regs_invalidated_by_call, i); } + memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode)); + memset (allocatable_regs_of_mode, 0, sizeof (allocatable_regs_of_mode)); + for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++) + for (i = 0; i < N_REG_CLASSES; i++) + if (CLASS_MAX_NREGS (i, m) <= reg_class_size[i]) + for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) + if (!fixed_regs [j] && TEST_HARD_REG_BIT (reg_class_contents[i], j) + && HARD_REGNO_MODE_OK (j, m)) + { + contains_reg_of_mode [i][m] = 1; + allocatable_regs_of_mode [m] = 1; + break; + } + /* Initialize the move cost table. Find every subset of each class and take the maximum cost of moving any subset to any other. */ - for (i = 0; i < N_REG_CLASSES; i++) - for (j = 0; j < N_REG_CLASSES; j++) + for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++) + if (allocatable_regs_of_mode [m]) { - int cost = i == j ? 2 : REGISTER_MOVE_COST (i, j); - enum reg_class *p1, *p2; - - for (p2 = ®_class_subclasses[j][0]; *p2 != LIM_REG_CLASSES; p2++) - if (*p2 != i) - cost = MAX (cost, REGISTER_MOVE_COST (i, *p2)); - - for (p1 = ®_class_subclasses[i][0]; *p1 != LIM_REG_CLASSES; p1++) - { - if (*p1 != j) - cost = MAX (cost, REGISTER_MOVE_COST (*p1, j)); - - for (p2 = ®_class_subclasses[j][0]; - *p2 != LIM_REG_CLASSES; p2++) - if (*p1 != *p2) - cost = MAX (cost, REGISTER_MOVE_COST (*p1, *p2)); - } - - move_cost[i][j] = cost; - - if (reg_class_subset_p (i, j)) - cost = 0; + for (i = 0; i < N_REG_CLASSES; i++) + if (contains_reg_of_mode [i][m]) + for (j = 0; j < N_REG_CLASSES; j++) + { + int cost; + enum reg_class *p1, *p2; + + if (!contains_reg_of_mode [j][m]) + { + move_cost[m][i][j] = 65536; + may_move_in_cost[m][i][j] = 65536; + may_move_out_cost[m][i][j] = 65536; + } + else + { + cost = REGISTER_MOVE_COST (m, i, j); + + for (p2 = ®_class_subclasses[j][0]; + *p2 != LIM_REG_CLASSES; + p2++) + if (*p2 != i && contains_reg_of_mode [*p2][m]) + cost = MAX (cost, move_cost [m][i][*p2]); + + for (p1 = ®_class_subclasses[i][0]; + *p1 != LIM_REG_CLASSES; + p1++) + if (*p1 != j && contains_reg_of_mode [*p1][m]) + cost = MAX (cost, move_cost [m][*p1][j]); + + move_cost[m][i][j] = cost; + + if (reg_class_subset_p (i, j)) + may_move_in_cost[m][i][j] = 0; + else + may_move_in_cost[m][i][j] = cost; + + if (reg_class_subset_p (j, i)) + may_move_out_cost[m][i][j] = 0; + else + may_move_out_cost[m][i][j] = cost; + } + } + else + for (j = 0; j < N_REG_CLASSES; j++) + { + move_cost[m][i][j] = 65536; + may_move_in_cost[m][i][j] = 65536; + may_move_out_cost[m][i][j] = 65536; + } + } - may_move_cost[i][j] = cost; +#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. @@ -423,7 +578,7 @@ init_reg_sets_1 () static void init_reg_modes () { - register int i; + int i; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { @@ -456,8 +611,10 @@ init_regs () /* Make some fake stack-frame MEM references for use in memory_move_secondary_cost. */ int i; + for (i = 0; i < MAX_MACHINE_MODE; i++) top_of_stack[i] = gen_rtx_MEM (i, stack_pointer_rtx); + ggc_add_rtx_root (top_of_stack, MAX_MACHINE_MODE); } #endif } @@ -476,7 +633,9 @@ memory_move_secondary_cost (mode, class, in) enum reg_class altclass; int partial_cost = 0; /* We need a memory reference to feed to SECONDARY... macros. */ - rtx mem = top_of_stack[(int) mode]; + /* mem may be unused even if the SECONDARY_ macros are defined. */ + rtx mem ATTRIBUTE_UNUSED = top_of_stack[(int) mode]; + if (in) { @@ -499,9 +658,9 @@ memory_move_secondary_cost (mode, class, in) return 0; if (in) - partial_cost = REGISTER_MOVE_COST (altclass, class); + partial_cost = REGISTER_MOVE_COST (mode, altclass, class); else - partial_cost = REGISTER_MOVE_COST (class, altclass); + partial_cost = REGISTER_MOVE_COST (mode, class, altclass); if (class == altclass) /* This isn't simply a copy-to-temporary situation. Can't guess @@ -524,9 +683,10 @@ memory_move_secondary_cost (mode, class, in) enum machine_mode choose_hard_reg_mode (regno, nregs) - int regno; - int nregs; + unsigned int regno ATTRIBUTE_UNUSED; + unsigned int nregs; { + unsigned int /* enum machine_mode */ m; enum machine_mode found_mode = VOIDmode, mode; /* We first look for the largest integer mode that can be validly @@ -553,9 +713,34 @@ choose_hard_reg_mode (regno, nregs) if (found_mode != VOIDmode) return found_mode; - if (HARD_REGNO_NREGS (regno, CCmode) == nregs - && HARD_REGNO_MODE_OK (regno, CCmode)) - return CCmode; + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_NREGS (regno, mode) == nregs + && HARD_REGNO_MODE_OK (regno, mode)) + found_mode = mode; + + if (found_mode != VOIDmode) + return found_mode; + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + if (HARD_REGNO_NREGS (regno, mode) == nregs + && HARD_REGNO_MODE_OK (regno, mode)) + found_mode = mode; + + if (found_mode != VOIDmode) + return found_mode; + + /* Iterate over all of the CCmodes. */ + for (m = (unsigned int) CCmode; m < (unsigned int) NUM_MACHINE_MODES; ++m) + { + mode = (enum machine_mode) m; + if (HARD_REGNO_NREGS (regno, mode) == nregs + && HARD_REGNO_MODE_OK (regno, mode)) + return mode; + } /* We can't find a mode valid for this register. */ return VOIDmode; @@ -567,7 +752,7 @@ choose_hard_reg_mode (regno, nregs) void fix_register (name, fixed, call_used) - char *name; + const char *name; int fixed, call_used; { int i; @@ -586,7 +771,7 @@ fix_register (name, fixed, call_used) ) && (fixed == 0 || call_used == 0)) { - static char* what_option[2][2] = { + static const char * const what_option[2][2] = { { "call-saved", "call-used" }, { "no-such-option", "fixed" }}; @@ -597,6 +782,10 @@ fix_register (name, fixed, call_used) { 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; +#endif } } else @@ -611,6 +800,9 @@ void globalize_reg (i) int i; { + if (fixed_regs[i] == 0 && no_global_reg_vars) + error ("global register variable follows a function definition"); + if (global_regs[i]) { warning ("register used for two global register variables"); @@ -647,6 +839,22 @@ struct costs int mem_cost; }; +/* Structure used to record preferrences of given pseudo. */ +struct reg_pref +{ + /* (enum reg_class) prefclass is the preferred class. */ + char prefclass; + + /* altclass is a register class that we should use for allocating + pseudo if no register in the preferred class is available. + If no register in this class is available, memory is preferred. + + It might appear to be more general to have a bitmask of classes here, + but since it is recommended that there be a class corresponding to the + union of most major pair of classes, that generality is not required. */ + char altclass; +}; + /* Record the cost of each class for each pseudo. */ static struct costs *costs; @@ -655,52 +863,32 @@ static struct costs *costs; static struct costs init_cost; -/* Record the same data by operand number, accumulated for each alternative - in an insn. The contribution to a pseudo is that of the minimum-cost - alternative. */ - -static struct costs op_costs[MAX_RECOG_OPERANDS]; - -/* (enum reg_class) prefclass[R] is the preferred class for pseudo number R. +/* Record preferrences of each pseudo. This is available after `regclass' is run. */ -static char *prefclass; - -/* altclass[R] is a register class that we should use for allocating - pseudo number R if no register in the preferred class is available. - If no register in this class is available, memory is preferred. - - It might appear to be more general to have a bitmask of classes here, - but since it is recommended that there be a class corresponding to the - union of most major pair of classes, that generality is not required. - - This is available after `regclass' is run. */ +static struct reg_pref *reg_pref; -static char *altclass; +/* Allocated buffers for reg_pref. */ -/* Allocated buffers for prefclass and altclass. */ -static char *prefclass_buffer; -static char *altclass_buffer; +static struct reg_pref *reg_pref_buffer; -/* Record the depth of loops that we are in. */ +/* Frequency of executions of current insn. */ -static int loop_depth; +static int frequency; -/* Account for the fact that insns within a loop are executed very commonly, - but don't keep doing this as loops go too deep. */ - -static int loop_cost; - -static rtx scan_one_insn PROTO((rtx, int)); -static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *, - char *, const char **, rtx)); -static int copy_cost PROTO((rtx, enum machine_mode, +static rtx scan_one_insn PARAMS ((rtx, int)); +static void record_operand_costs PARAMS ((rtx, struct costs *, struct reg_pref *)); +static void dump_regclass PARAMS ((FILE *)); +static void record_reg_classes PARAMS ((int, int, rtx *, enum machine_mode *, + const char **, rtx, + struct costs *, struct reg_pref *)); +static int copy_cost PARAMS ((rtx, enum machine_mode, enum reg_class, int)); -static void record_address_regs PROTO((rtx, enum reg_class, int)); +static void record_address_regs PARAMS ((rtx, enum reg_class, int)); #ifdef FORBIDDEN_INC_DEC_CLASSES -static int auto_inc_dec_reg_p PROTO((rtx, enum machine_mode)); +static int auto_inc_dec_reg_p PARAMS ((rtx, enum machine_mode)); #endif -static void reg_scan_mark_refs PROTO((rtx, rtx, int, int)); +static void reg_scan_mark_refs PARAMS ((rtx, rtx, int, unsigned int)); /* Return the reg_class in which pseudo reg number REGNO is best allocated. This function is sometimes called before the info has been computed. @@ -710,19 +898,19 @@ enum reg_class reg_preferred_class (regno) int regno; { - if (prefclass == 0) + if (reg_pref == 0) return GENERAL_REGS; - return (enum reg_class) prefclass[regno]; + return (enum reg_class) reg_pref[regno].prefclass; } enum reg_class reg_alternate_class (regno) int regno; { - if (prefclass == 0) + if (reg_pref == 0) return ALL_REGS; - return (enum reg_class) altclass[regno]; + return (enum reg_class) reg_pref[regno].altclass; } /* Initialize some global data for this pass. */ @@ -738,7 +926,117 @@ regclass_init () /* This prevents dump_flow_info from losing if called before regclass is run. */ - prefclass = 0; + reg_pref = NULL; + + /* No more global register variables may be declared. */ + no_global_reg_vars = 1; +} + +/* Dump register costs. */ +static void +dump_regclass (dump) + FILE *dump; +{ + static const char *const reg_class_names[] = REG_CLASS_NAMES; + int i; + for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) + { + int /* enum reg_class */ class; + if (REG_N_REFS (i)) + { + fprintf (dump, " Register %i costs:", i); + for (class = 0; class < (int) N_REG_CLASSES; class++) + if (contains_reg_of_mode [(enum reg_class) class][PSEUDO_REGNO_MODE (i)] +#ifdef FORBIDDEN_INC_DEC_CLASSES + && (!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]) +#endif + ) + fprintf (dump, " %s:%i", reg_class_names[class], + costs[i].cost[(enum reg_class) class]); + fprintf (dump, " MEM:%i\n", costs[i].mem_cost); + } + } +} + + +/* Calculate the costs of insn operands. */ + +static void +record_operand_costs (insn, op_costs, reg_pref) + rtx insn; + struct costs *op_costs; + struct reg_pref *reg_pref; +{ + const char *constraints[MAX_RECOG_OPERANDS]; + enum machine_mode modes[MAX_RECOG_OPERANDS]; + int i; + + for (i = 0; i < recog_data.n_operands; i++) + { + constraints[i] = recog_data.constraints[i]; + modes[i] = recog_data.operand_mode[i]; + } + + /* If we get here, we are set up to record the costs of all the + operands for this insn. Start by initializing the costs. + Then handle any address registers. Finally record the desired + classes for any pseudos, doing it twice if some pair of + operands are commutative. */ + + for (i = 0; i < recog_data.n_operands; i++) + { + 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; + } + + 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') + record_address_regs (recog_data.operand[i], + MODE_BASE_REG_CLASS (modes[i]), frequency * 2); + } + + /* Check for commutative in a separate loop so everything will + have been initialized. We must do this even if one operand + is a constant--see addsi3 in m68k.md. */ + + for (i = 0; i < (int) recog_data.n_operands - 1; i++) + if (constraints[i][0] == '%') + { + const char *xconstraints[MAX_RECOG_OPERANDS]; + int j; + + /* Handle commutative operands by swapping the constraints. + We assume the modes are the same. */ + + for (j = 0; j < recog_data.n_operands; j++) + xconstraints[j] = constraints[j]; + + xconstraints[i] = constraints[i+1]; + xconstraints[i+1] = constraints[i]; + record_reg_classes (recog_data.n_alternatives, recog_data.n_operands, + recog_data.operand, modes, + xconstraints, insn, op_costs, reg_pref); + } + + record_reg_classes (recog_data.n_alternatives, recog_data.n_operands, + recog_data.operand, modes, + constraints, insn, op_costs, reg_pref); } /* Subroutine of regclass, processes one insn INSN. Scan it and record each @@ -755,26 +1053,9 @@ scan_one_insn (insn, pass) { enum rtx_code code = GET_CODE (insn); enum rtx_code pat_code; - const char *constraints[MAX_RECOG_OPERANDS]; - enum machine_mode modes[MAX_RECOG_OPERANDS]; - char subreg_changes_size[MAX_RECOG_OPERANDS]; rtx set, note; int i, j; - - /* Show that an insn inside a loop is likely to be executed three - times more than insns outside a loop. This is much more aggressive - than the assumptions made elsewhere and is being tried as an - experiment. */ - - if (code == NOTE) - { - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) - loop_depth++, loop_cost = 1 << (2 * MIN (loop_depth, 5)); - else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) - loop_depth--, loop_cost = 1 << (2 * MIN (loop_depth, 5)); - - return insn; - } + struct costs op_costs[MAX_RECOG_OPERANDS]; if (GET_RTX_CLASS (code) != 'i') return insn; @@ -790,13 +1071,6 @@ scan_one_insn (insn, pass) set = single_set (insn); extract_insn (insn); - for (i = 0; i < recog_n_operands; i++) - { - constraints[i] = recog_constraints[i]; - modes[i] = recog_operand_mode[i]; - } - memset (subreg_changes_size, 0, sizeof (subreg_changes_size)); - /* If this insn loads a parameter from its stack slot, then it represents a savings, rather than a cost, if the parameter is stored in memory. Record this fact. */ @@ -810,9 +1084,9 @@ scan_one_insn (insn, pass) costs[REGNO (SET_DEST (set))].mem_cost -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)), GENERAL_REGS, 1) - * loop_cost); + * frequency); record_address_regs (XEXP (SET_SRC (set), 0), - BASE_REG_CLASS, loop_cost * 2); + MODE_BASE_REG_CLASS (VOIDmode), frequency * 2); return insn; } @@ -829,24 +1103,22 @@ scan_one_insn (insn, pass) do this during our first pass. */ if (pass == 0 && optimize - && recog_n_operands >= 3 - && recog_constraints[1][0] == '0' - && recog_constraints[1][1] == 0 - && CONSTANT_P (recog_operand[1]) - && ! rtx_equal_p (recog_operand[0], recog_operand[1]) - && ! rtx_equal_p (recog_operand[0], recog_operand[2]) - && GET_CODE (recog_operand[0]) == REG - && MODES_TIEABLE_P (GET_MODE (recog_operand[0]), - recog_operand_mode[1])) + && recog_data.n_operands >= 3 + && recog_data.constraints[1][0] == '0' + && recog_data.constraints[1][1] == 0 + && CONSTANT_P (recog_data.operand[1]) + && ! rtx_equal_p (recog_data.operand[0], recog_data.operand[1]) + && ! rtx_equal_p (recog_data.operand[0], recog_data.operand[2]) + && GET_CODE (recog_data.operand[0]) == REG + && MODES_TIEABLE_P (GET_MODE (recog_data.operand[0]), + recog_data.operand_mode[1])) { rtx previnsn = prev_real_insn (insn); rtx dest - = gen_lowpart (recog_operand_mode[1], - recog_operand[0]); + = gen_lowpart (recog_data.operand_mode[1], + recog_data.operand[0]); rtx newinsn - = emit_insn_before (gen_move_insn (dest, - recog_operand[1]), - insn); + = emit_insn_before (gen_move_insn (dest, recog_data.operand[1]), insn); /* If this insn was the start of a basic block, include the new insn in that block. @@ -862,81 +1134,39 @@ scan_one_insn (insn, pass) } /* This makes one more setting of new insns's dest. */ - REG_N_SETS (REGNO (recog_operand[0]))++; - - *recog_operand_loc[1] = recog_operand[0]; - for (i = recog_n_dups - 1; i >= 0; i--) - if (recog_dup_num[i] == 1) - *recog_dup_loc[i] = recog_operand[0]; + REG_N_SETS (REGNO (recog_data.operand[0]))++; + REG_N_REFS (REGNO (recog_data.operand[0]))++; + REG_FREQ (REGNO (recog_data.operand[0])) += frequency; + + *recog_data.operand_loc[1] = recog_data.operand[0]; + REG_N_REFS (REGNO (recog_data.operand[0]))++; + REG_FREQ (REGNO (recog_data.operand[0])) += frequency; + for (i = recog_data.n_dups - 1; i >= 0; i--) + if (recog_data.dup_num[i] == 1) + { + *recog_data.dup_loc[i] = recog_data.operand[0]; + REG_N_REFS (REGNO (recog_data.operand[0]))++; + REG_FREQ (REGNO (recog_data.operand[0])) += frequency; + } return PREV_INSN (newinsn); } - /* If we get here, we are set up to record the costs of all the - operands for this insn. Start by initializing the costs. - Then handle any address registers. Finally record the desired - classes for any pseudos, doing it twice if some pair of - operands are commutative. */ - - for (i = 0; i < recog_n_operands; i++) - { - op_costs[i] = init_cost; - - if (GET_CODE (recog_operand[i]) == SUBREG) - { - rtx inner = SUBREG_REG (recog_operand[i]); - if (GET_MODE_SIZE (modes[i]) != GET_MODE_SIZE (GET_MODE (inner))) - subreg_changes_size[i] = 1; - recog_operand[i] = inner; - } - - if (GET_CODE (recog_operand[i]) == MEM) - record_address_regs (XEXP (recog_operand[i], 0), - BASE_REG_CLASS, loop_cost * 2); - else if (constraints[i][0] == 'p') - record_address_regs (recog_operand[i], - BASE_REG_CLASS, loop_cost * 2); - } - - /* Check for commutative in a separate loop so everything will - have been initialized. We must do this even if one operand - is a constant--see addsi3 in m68k.md. */ - - for (i = 0; i < recog_n_operands - 1; i++) - if (constraints[i][0] == '%') - { - const char *xconstraints[MAX_RECOG_OPERANDS]; - int j; - - /* Handle commutative operands by swapping the constraints. - We assume the modes are the same. */ - - for (j = 0; j < recog_n_operands; j++) - xconstraints[j] = constraints[j]; - - xconstraints[i] = constraints[i+1]; - xconstraints[i+1] = constraints[i]; - record_reg_classes (recog_n_alternatives, recog_n_operands, - recog_operand, modes, subreg_changes_size, - xconstraints, insn); - } - - record_reg_classes (recog_n_alternatives, recog_n_operands, recog_operand, - modes, subreg_changes_size, constraints, insn); + record_operand_costs (insn, op_costs, reg_pref); /* Now add the cost for each operand to the total costs for its register. */ - for (i = 0; i < recog_n_operands; i++) - if (GET_CODE (recog_operand[i]) == REG - && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER) + for (i = 0; i < recog_data.n_operands; i++) + if (GET_CODE (recog_data.operand[i]) == REG + && REGNO (recog_data.operand[i]) >= FIRST_PSEUDO_REGISTER) { - int regno = REGNO (recog_operand[i]); + int regno = REGNO (recog_data.operand[i]); struct costs *p = &costs[regno], *q = &op_costs[i]; - p->mem_cost += q->mem_cost * loop_cost; + p->mem_cost += q->mem_cost * frequency; for (j = 0; j < N_REG_CLASSES; j++) - p->cost[j] += q->cost[j] * loop_cost; + p->cost[j] += q->cost[j] * frequency; } return insn; @@ -948,22 +1178,26 @@ scan_one_insn (insn, pass) This pass comes just before local register allocation. */ void -regclass (f, nregs) +regclass (f, nregs, dump) rtx f; int nregs; + FILE *dump; { -#ifdef REGISTER_CONSTRAINTS - register rtx insn; - register int i; + rtx insn; + int i; int pass; init_recog (); 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 *) alloca (nregs); + in_inc_dec = (char *) xmalloc (nregs); /* Initialize information about which register classes can be used for pseudos that are auto-incremented or auto-decremented. It would @@ -974,7 +1208,7 @@ regclass (f, nregs) { rtx r = gen_rtx_REG (VOIDmode, 0); enum machine_mode m; - register int j; + int j; for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) if (TEST_HARD_REG_BIT (reg_class_contents[i], j)) @@ -994,15 +1228,15 @@ regclass (f, nregs) if ((0 #ifdef SECONDARY_RELOAD_CLASS - || (SECONDARY_RELOAD_CLASS (BASE_REG_CLASS, m, r) + || (SECONDARY_RELOAD_CLASS (MODE_BASE_REG_CLASS (VOIDmode), m, r) != NO_REGS) #else #ifdef SECONDARY_INPUT_RELOAD_CLASS - || (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r) + || (SECONDARY_INPUT_RELOAD_CLASS (MODE_BASE_REG_CLASS (VOIDmode), m, r) != NO_REGS) #endif #ifdef SECONDARY_OUTPUT_RELOAD_CLASS - || (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r) + || (SECONDARY_OUTPUT_RELOAD_CLASS (MODE_BASE_REG_CLASS (VOIDmode), m, r) != NO_REGS) #endif #endif @@ -1021,53 +1255,84 @@ regclass (f, nregs) for (pass = 0; pass <= flag_expensive_optimizations; pass++) { + int index; + + if (dump) + fprintf (dump, "\n\nPass %i\n\n",pass); /* Zero out our accumulation of the cost of each class for each reg. */ - bzero ((char *) costs, nregs * sizeof (struct costs)); + memset ((char *) costs, 0, nregs * sizeof (struct costs)); #ifdef FORBIDDEN_INC_DEC_CLASSES - bzero (in_inc_dec, nregs); + memset (in_inc_dec, 0, nregs); #endif - loop_depth = 0, loop_cost = 1; - /* Scan the instructions and record each time it would save code to put a certain register in a certain class. */ - for (insn = f; insn; insn = NEXT_INSN (insn)) + if (!optimize) { - insn = scan_one_insn (insn, pass); + frequency = REG_FREQ_MAX; + for (insn = f; insn; insn = NEXT_INSN (insn)) + insn = scan_one_insn (insn, pass); } + else + for (index = 0; index < n_basic_blocks; index++) + { + basic_block bb = BASIC_BLOCK (index); + + /* Show that an insn inside a loop is likely to be executed three + times more than insns outside a loop. This is much more + aggressive than the assumptions made elsewhere and is being + tried as an experiment. */ + frequency = REG_FREQ_FROM_BB (bb); + for (insn = bb->head; ; insn = NEXT_INSN (insn)) + { + insn = scan_one_insn (insn, pass); + if (insn == bb->end) + break; + } + } /* Now for each register look at how desirable each class is and find which class is preferred. Store that in - `prefclass[REGNO]'. Record in `altclass[REGNO]' the largest register + `prefclass'. Record in `altclass' the largest register class any of whose registers is better than memory. */ if (pass == 0) - { - prefclass = prefclass_buffer; - altclass = altclass_buffer; - } + reg_pref = reg_pref_buffer; + if (dump) + { + dump_regclass (dump); + fprintf (dump,"\n"); + } for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++) { - register int best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1; + int best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1; enum reg_class best = ALL_REGS, alt = NO_REGS; /* This is an enum reg_class, but we call it an int to save lots of casts. */ - register int class; - register struct costs *p = &costs[i]; + int class; + struct costs *p = &costs[i]; + + /* In non-optimizing compilation REG_N_REFS is not initialized + yet. */ + if (optimize && !REG_N_REFS (i)) + continue; for (class = (int) ALL_REGS - 1; class > 0; class--) { /* Ignore classes that are too small for this operand or - invalid for a operand that was auto-incremented. */ - if (CLASS_MAX_NREGS (class, PSEUDO_REGNO_MODE (i)) - > reg_class_size[class] + invalid for an operand that was auto-incremented. */ + if (!contains_reg_of_mode [class][PSEUDO_REGNO_MODE (i)] #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]) +#endif ) ; else if (p->cost[class] < best_cost) @@ -1076,7 +1341,7 @@ regclass (f, nregs) best = (enum reg_class) class; } else if (p->cost[class] == best_cost) - best = reg_class_subunion[(int)best][class]; + best = reg_class_subunion[(int) best][class]; } /* Record the alternate register class; i.e., a class for which @@ -1086,7 +1351,7 @@ regclass (f, nregs) should be provided as a register class. Don't do this if we will be doing it again later. */ - if (pass == 1 || ! flag_expensive_optimizations) + if ((pass == 1 || dump) || ! flag_expensive_optimizations) for (class = 0; class < N_REG_CLASSES; class++) if (p->cost[class] < p->mem_cost && (reg_class_size[(int) reg_class_subunion[(int) alt][class]] @@ -1094,6 +1359,10 @@ regclass (f, 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]) +#endif ) alt = reg_class_subunion[(int) alt][class]; @@ -1101,18 +1370,37 @@ regclass (f, nregs) if (alt == best) alt = NO_REGS; + if (dump + && (reg_pref[i].prefclass != (int) best + || reg_pref[i].altclass != (int) alt)) + { + static const char *const reg_class_names[] = REG_CLASS_NAMES; + fprintf (dump, " Register %i", i); + if (alt == ALL_REGS || best == ALL_REGS) + fprintf (dump, " pref %s\n", reg_class_names[(int) best]); + else if (alt == NO_REGS) + fprintf (dump, " pref %s or none\n", reg_class_names[(int) best]); + else + fprintf (dump, " pref %s, else %s\n", + reg_class_names[(int) best], + reg_class_names[(int) alt]); + } + /* We cast to (int) because (char) hits bugs in some compilers. */ - prefclass[i] = (int) best; - altclass[i] = (int) alt; + reg_pref[i].prefclass = (int) best; + reg_pref[i].altclass = (int) alt; } } -#endif /* REGISTER_CONSTRAINTS */ +#ifdef FORBIDDEN_INC_DEC_CLASSES + free (in_inc_dec); +#endif +#ifdef CLASS_CANNOT_CHANGE_MODE + BITMAP_XFREE (reg_changes_mode); +#endif free (costs); } -#ifdef REGISTER_CONSTRAINTS - /* Record the cost of using memory or registers of various classes for the operands in INSN. @@ -1138,15 +1426,16 @@ regclass (f, nregs) alternatives. */ static void -record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, - constraints, insn) +record_reg_classes (n_alts, n_ops, ops, modes, + constraints, insn, op_costs, reg_pref) int n_alts; int n_ops; rtx *ops; enum machine_mode *modes; - char *subreg_changes_size; const char **constraints; rtx insn; + struct costs *op_costs; + struct reg_pref *reg_pref; { int alt; int i, j; @@ -1161,6 +1450,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, int alt_fail = 0; int alt_cost = 0; enum reg_class classes[MAX_RECOG_OPERANDS]; + int allows_mem[MAX_RECOG_OPERANDS]; int class; for (i = 0; i < n_ops; i++) @@ -1169,12 +1459,12 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, rtx op = ops[i]; enum machine_mode mode = modes[i]; int allows_addr = 0; - int allows_mem = 0; int win = 0; unsigned char c; /* Initially show we know nothing about the register class. */ classes[i] = NO_REGS; + allows_mem[i] = 0; /* If this operand has no constraints at all, we can conclude nothing about it since anything is valid. */ @@ -1182,7 +1472,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, if (*p == 0) { if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) - bzero ((char *) &this_op_costs[i], sizeof this_op_costs[i]); + memset ((char *) &this_op_costs[i], 0, sizeof this_op_costs[i]); continue; } @@ -1197,8 +1487,12 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, if (p[0] >= '0' && p[0] <= '0' + i && (p[1] == ',' || p[1] == 0)) { + /* Copy class and whether memory is allowed from the matching + alternative. Then perform any needed cost computations + and/or adjustments. */ j = p[0] - '0'; classes[i] = classes[j]; + allows_mem[i] = allows_mem[j]; if (GET_CODE (op) != REG || REGNO (op) < FIRST_PSEUDO_REGISTER) { @@ -1234,12 +1528,45 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, } else { - /* The costs of this operand are the same as that of the - other operand. However, if we cannot tie them, this - alternative needs to do a copy, which is one - instruction. */ + /* The costs of this operand are not the same as the other + operand since move costs are not symmetric. Moreover, + if we cannot tie them, this alternative needs to do a + copy, which is one instruction. */ + + struct costs *pp = &this_op_costs[i]; + + for (class = 0; class < N_REG_CLASSES; class++) + pp->cost[class] + = ((recog_data.operand_type[i] != OP_OUT + ? may_move_in_cost[mode][class][(int) classes[i]] + : 0) + + (recog_data.operand_type[i] != OP_IN + ? may_move_out_cost[mode][(int) classes[i]][class] + : 0)); + + /* If the alternative actually allows memory, make things + a bit cheaper since we won't need an extra insn to + load it. */ + + pp->mem_cost + = ((recog_data.operand_type[i] != OP_IN + ? MEMORY_MOVE_COST (mode, classes[i], 0) + : 0) + + (recog_data.operand_type[i] != OP_OUT + ? MEMORY_MOVE_COST (mode, classes[i], 1) + : 0) - allows_mem[i]); + + /* If we have assigned a class to this register in our + first pass, add a cost to this alternative corresponding + to what we would add if this register were not in the + appropriate class. */ + + if (reg_pref) + alt_cost + += (may_move_in_cost[mode] + [(unsigned char) reg_pref[REGNO (op)].prefclass] + [(int) classes[i]]); - this_op_costs[i] = this_op_costs[j]; if (REGNO (ops[i]) != REGNO (ops[j]) && ! find_reg_note (insn, REG_DEAD, op)) alt_cost += 2; @@ -1282,13 +1609,13 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, address, ie BASE_REG_CLASS. */ classes[i] = reg_class_subunion[(int) classes[i]] - [(int) BASE_REG_CLASS]; + [(int) MODE_BASE_REG_CLASS (VOIDmode)]; break; case 'm': case 'o': case 'V': /* It doesn't seem worth distinguishing between offsettable and non-offsettable addresses here. */ - allows_mem = 1; + allows_mem[i] = 1; if (GET_CODE (op) == MEM) win = 1; break; @@ -1370,17 +1697,6 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, win = 1; break; -#ifdef EXTRA_CONSTRAINT - case 'Q': - case 'R': - case 'S': - case 'T': - case 'U': - if (EXTRA_CONSTRAINT (op, c)) - win = 1; - break; -#endif - case 'g': if (GET_CODE (op) == MEM || (CONSTANT_P (op) @@ -1389,30 +1705,26 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, #endif )) win = 1; - allows_mem = 1; + allows_mem[i] = 1; case 'r': classes[i] = reg_class_subunion[(int) classes[i]][(int) GENERAL_REGS]; break; default: - classes[i] - = reg_class_subunion[(int) classes[i]] - [(int) REG_CLASS_FROM_LETTER (c)]; + if (REG_CLASS_FROM_LETTER (c) != NO_REGS) + 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; +#endif + break; } constraints[i] = p; -#ifdef CLASS_CANNOT_CHANGE_SIZE - /* If we noted a subreg earlier, and the selected class is a - subclass of CLASS_CANNOT_CHANGE_SIZE, zap it. */ - if (subreg_changes_size[i] - && (reg_class_subunion[(int) CLASS_CANNOT_CHANGE_SIZE] - [(int) classes[i]] - == CLASS_CANNOT_CHANGE_SIZE)) - classes[i] = NO_REGS; -#endif - /* How we account for this operand now depends on whether it is a pseudo register or not. If it is, we first check if any register classes are valid. If not, we ignore this alternative, @@ -1424,36 +1736,49 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, { if (classes[i] == NO_REGS) { - /* We must always fail if the operand is a REG, but - we did not find a suitable class. - - Otherwise we may perform an uninitialized read - from this_op_costs after the `continue' statement - below. */ - alt_fail = 1; + /* We must always fail if the operand is a REG, but + we did not find a suitable class. + + Otherwise we may perform an uninitialized read + from this_op_costs after the `continue' statement + below. */ + alt_fail = 1; } else { struct costs *pp = &this_op_costs[i]; for (class = 0; class < N_REG_CLASSES; class++) - pp->cost[class] = may_move_cost[class][(int) classes[i]]; + pp->cost[class] + = ((recog_data.operand_type[i] != OP_OUT + ? may_move_in_cost[mode][class][(int) classes[i]] + : 0) + + (recog_data.operand_type[i] != OP_IN + ? may_move_out_cost[mode][(int) classes[i]][class] + : 0)); /* If the alternative actually allows memory, make things a bit cheaper since we won't need an extra insn to load it. */ - pp->mem_cost = (MEMORY_MOVE_COST (mode, classes[i], 1) - - allows_mem); + pp->mem_cost + = ((recog_data.operand_type[i] != OP_IN + ? MEMORY_MOVE_COST (mode, classes[i], 0) + : 0) + + (recog_data.operand_type[i] != OP_OUT + ? MEMORY_MOVE_COST (mode, classes[i], 1) + : 0) - allows_mem[i]); /* If we have assigned a class to this register in our first pass, add a cost to this alternative corresponding to what we would add if this register were not in the appropriate class. */ - if (prefclass) + if (reg_pref) alt_cost - += may_move_cost[(unsigned char)prefclass[REGNO (op)]][(int) classes[i]]; + += (may_move_in_cost[mode] + [(unsigned char) reg_pref[REGNO (op)].prefclass] + [(int) classes[i]]); } } @@ -1471,17 +1796,17 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, else if (classes[i] != NO_REGS) { - if (recog_op_type[i] != OP_OUT) + if (recog_data.operand_type[i] != OP_OUT) alt_cost += copy_cost (op, mode, classes[i], 1); - if (recog_op_type[i] != OP_IN) + if (recog_data.operand_type[i] != OP_IN) alt_cost += copy_cost (op, mode, classes[i], 0); } /* The only other way this alternative can be used is if this is a constant that could be placed into memory. */ - else if (CONSTANT_P (op) && (allows_addr || allows_mem)) + else if (CONSTANT_P (op) && (allows_addr || allows_mem[i])) alt_cost += MEMORY_MOVE_COST (mode, classes[i], 1); else alt_fail = 1; @@ -1498,7 +1823,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, && REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER) { struct costs *pp = &op_costs[i], *qq = &this_op_costs[i]; - int scale = 1 + (recog_op_type[i] == OP_INOUT); + int scale = 1 + (recog_data.operand_type[i] == OP_INOUT); pp->mem_cost = MIN (pp->mem_cost, (qq->mem_cost + alt_cost) * scale); @@ -1510,24 +1835,40 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, } /* If this insn is a single set copying operand 1 to operand 0 - and one is a pseudo with the other a hard reg that is in its - own register class, set the cost of that register class to -1. */ + and one operand is a pseudo with the other a hard reg or a pseudo + that prefers a register that is in its own register class then + we may want to adjust the cost of that register class to -1. + + Avoid the adjustment if the source does not die to avoid stressing of + register allocator by preferrencing two coliding registers into single + class. + + Also avoid the adjustment if a copy between registers of the class + is expensive (ten times the cost of a default copy is considered + arbitrarily expensive). This avoids losing when the preferred class + is very expensive as the source of a copy instruction. */ if ((set = single_set (insn)) != 0 && ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set) - && GET_CODE (ops[0]) == REG && GET_CODE (ops[1]) == REG) + && GET_CODE (ops[0]) == REG && GET_CODE (ops[1]) == REG + && find_regno_note (insn, REG_DEAD, REGNO (ops[1]))) for (i = 0; i <= 1; i++) if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER) { - int regno = REGNO (ops[!i]); + unsigned int regno = REGNO (ops[!i]); enum machine_mode mode = GET_MODE (ops[!i]); int class; - int nr; + unsigned int nr; + + if (regno >= FIRST_PSEUDO_REGISTER && reg_pref != 0) + { + enum reg_class pref = reg_pref[regno].prefclass; - if (regno >= FIRST_PSEUDO_REGISTER && prefclass != 0 - && (reg_class_size[(unsigned char)prefclass[regno]] - == CLASS_MAX_NREGS (prefclass[regno], mode))) - op_costs[i].cost[(unsigned char)prefclass[regno]] = -1; + if ((reg_class_size[(unsigned char) pref] + == CLASS_MAX_NREGS (pref, mode)) + && REGISTER_MOVE_COST (mode, pref, pref) < 10 * 2) + op_costs[i].cost[(unsigned char) pref] = -1; + } else if (regno < FIRST_PSEUDO_REGISTER) for (class = 0; class < N_REG_CLASSES; class++) if (TEST_HARD_REG_BIT (reg_class_contents[class], regno) @@ -1537,13 +1878,14 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, op_costs[i].cost[class] = -1; else { - for (nr = 0; nr < HARD_REGNO_NREGS(regno, mode); nr++) + for (nr = 0; nr < HARD_REGNO_NREGS (regno, mode); nr++) { - if (!TEST_HARD_REG_BIT (reg_class_contents[class], regno + nr)) + if (! TEST_HARD_REG_BIT (reg_class_contents[class], + regno + nr)) break; } - if (nr == HARD_REGNO_NREGS(regno,mode)) + if (nr == HARD_REGNO_NREGS (regno,mode)) op_costs[i].cost[class] = -1; } } @@ -1558,9 +1900,9 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size, static int copy_cost (x, mode, class, to_p) rtx x; - enum machine_mode mode; + enum machine_mode mode ATTRIBUTE_UNUSED; enum reg_class class; - int to_p; + int to_p ATTRIBUTE_UNUSED; { #ifdef HAVE_SECONDARY_RELOADS enum reg_class secondary_class = NO_REGS; @@ -1592,7 +1934,7 @@ copy_cost (x, mode, class, to_p) #endif if (secondary_class != NO_REGS) - return (move_cost[(int) secondary_class][(int) class] + return (move_cost[mode][(int) secondary_class][(int) class] + copy_cost (x, mode, secondary_class, 2)); #endif /* HAVE_SECONDARY_RELOADS */ @@ -1604,11 +1946,11 @@ copy_cost (x, mode, class, to_p) return MEMORY_MOVE_COST (mode, class, to_p); else if (GET_CODE (x) == REG) - return move_cost[(int) REGNO_REG_CLASS (REGNO (x))][(int) class]; + return move_cost[mode][(int) REGNO_REG_CLASS (REGNO (x))][(int) class]; else /* If this is a constant, we may eventually want to call rtx_cost here. */ - return 2; + return COSTS_N_INSNS (1); } /* Record the pseudo registers we must reload into hard registers @@ -1626,7 +1968,7 @@ record_address_regs (x, class, scale) enum reg_class class; int scale; { - register enum rtx_code code = GET_CODE (x); + enum rtx_code code = GET_CODE (x); switch (code) { @@ -1642,10 +1984,10 @@ record_address_regs (x, class, scale) /* When we have an address that is a sum, we must determine whether registers are "base" or "index" regs. If there is a sum of two registers, we must choose one to be - the "base". Luckily, we can use the REGNO_POINTER_FLAG - to make a good choice most of the time. We only need to do this - on machines that can have two registers in an address and where - the base and index register classes are different. + the "base". Luckily, we can use the REG_POINTER to make a good + choice most of the time. We only need to do this on machines + that can have two registers in an address and where the base + and index register classes are different. ??? This code used to set REGNO_POINTER_FLAG in some cases, but that seems bogus since it should only be set when we are sure @@ -1654,8 +1996,8 @@ record_address_regs (x, class, scale) { rtx arg0 = XEXP (x, 0); rtx arg1 = XEXP (x, 1); - register enum rtx_code code0 = GET_CODE (arg0); - register enum rtx_code code1 = GET_CODE (arg1); + enum rtx_code code0 = GET_CODE (arg0); + enum rtx_code code1 = GET_CODE (arg1); /* Look inside subregs. */ if (code0 == SUBREG) @@ -1674,7 +2016,7 @@ record_address_regs (x, class, scale) as well as in the tests below, that all addresses are in canonical form. */ - else if (INDEX_REG_CLASS == BASE_REG_CLASS) + else if (INDEX_REG_CLASS == MODE_BASE_REG_CLASS (VOIDmode)) { record_address_regs (arg0, class, scale); if (! CONSTANT_P (arg1)) @@ -1703,14 +2045,14 @@ record_address_regs (x, class, scale) && (REG_OK_FOR_BASE_P (arg0) || REG_OK_FOR_INDEX_P (arg0))) record_address_regs (arg1, REG_OK_FOR_BASE_P (arg0) - ? INDEX_REG_CLASS : BASE_REG_CLASS, + ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (VOIDmode), scale); else if (code0 == REG && code1 == REG && REGNO (arg1) < FIRST_PSEUDO_REGISTER && (REG_OK_FOR_BASE_P (arg1) || REG_OK_FOR_INDEX_P (arg1))) record_address_regs (arg0, REG_OK_FOR_BASE_P (arg1) - ? INDEX_REG_CLASS : BASE_REG_CLASS, + ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (VOIDmode), scale); #endif @@ -1718,17 +2060,17 @@ record_address_regs (x, class, scale) with the other operand the index. Likewise if the other operand is a MULT. */ - else if ((code0 == REG && REGNO_POINTER_FLAG (REGNO (arg0))) + else if ((code0 == REG && REG_POINTER (arg0)) || code1 == MULT) { - record_address_regs (arg0, BASE_REG_CLASS, scale); + record_address_regs (arg0, MODE_BASE_REG_CLASS (VOIDmode), scale); record_address_regs (arg1, INDEX_REG_CLASS, scale); } - else if ((code1 == REG && REGNO_POINTER_FLAG (REGNO (arg1))) + else if ((code1 == REG && REG_POINTER (arg1)) || code0 == MULT) { record_address_regs (arg0, INDEX_REG_CLASS, scale); - record_address_regs (arg1, BASE_REG_CLASS, scale); + record_address_regs (arg1, MODE_BASE_REG_CLASS (VOIDmode), scale); } /* Otherwise, count equal chances that each might be a base @@ -1736,14 +2078,28 @@ record_address_regs (x, class, scale) else { - record_address_regs (arg0, BASE_REG_CLASS, scale / 2); + record_address_regs (arg0, MODE_BASE_REG_CLASS (VOIDmode), + scale / 2); record_address_regs (arg0, INDEX_REG_CLASS, scale / 2); - record_address_regs (arg1, BASE_REG_CLASS, scale / 2); + record_address_regs (arg1, MODE_BASE_REG_CLASS (VOIDmode), + scale / 2); record_address_regs (arg1, INDEX_REG_CLASS, scale / 2); } } break; + /* Double the importance of a pseudo register that is incremented + or decremented, since it would take two extra insns + if it ends up in the wrong place. */ + case POST_MODIFY: + case PRE_MODIFY: + record_address_regs (XEXP (x, 0), MODE_BASE_REG_CLASS (VOIDmode), + 2 * scale); + if (REG_P (XEXP (XEXP (x, 1), 1))) + record_address_regs (XEXP (XEXP (x, 1), 1), + INDEX_REG_CLASS, 2 * scale); + break; + case POST_INC: case PRE_INC: case POST_DEC: @@ -1764,20 +2120,20 @@ record_address_regs (x, class, scale) case REG: { - register struct costs *pp = &costs[REGNO (x)]; - register int i; + struct costs *pp = &costs[REGNO (x)]; + int i; pp->mem_cost += (MEMORY_MOVE_COST (Pmode, class, 1) * scale) / 2; for (i = 0; i < N_REG_CLASSES; i++) - pp->cost[i] += (may_move_cost[i][(int) class] * scale) / 2; + pp->cost[i] += (may_move_in_cost[Pmode][i][(int) class] * scale) / 2; } break; default: { - register char *fmt = GET_RTX_FORMAT (code); - register int i; + const char *fmt = GET_RTX_FORMAT (code); + int i; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') record_address_regs (XEXP (x, i), class, scale); @@ -1814,11 +2170,10 @@ auto_inc_dec_reg_p (reg, mode) return 0; } #endif - -#endif /* REGISTER_CONSTRAINTS */ -static short *renumber = (short *)0; -static size_t regno_allocated = 0; +static short *renumber; +static size_t regno_allocated; +static unsigned int reg_n_max; /* Allocate enough space to hold NUM_REGS registers for the tables used for reg_scan and flow_analysis that are indexed by the register number. If @@ -1837,7 +2192,6 @@ allocate_reg_info (num_regs, new_p, renumber_p) size_t size_renumber; size_t min = (new_p) ? 0 : reg_n_max; struct reg_info_data *reg_data; - struct reg_info_data *reg_next; if (num_regs > regno_allocated) { @@ -1850,8 +2204,8 @@ allocate_reg_info (num_regs, new_p, renumber_p) { VARRAY_REG_INIT (reg_n_info, regno_allocated, "reg_n_info"); renumber = (short *) xmalloc (size_renumber); - prefclass_buffer = (char *) xmalloc (regno_allocated); - altclass_buffer = (char *) xmalloc (regno_allocated); + reg_pref_buffer = (struct reg_pref *) xmalloc (regno_allocated + * sizeof (struct reg_pref)); } else @@ -1860,22 +2214,19 @@ allocate_reg_info (num_regs, new_p, renumber_p) if (new_p) /* if we're zapping everything, no need to realloc */ { - free ((char *)renumber); - free ((char *)prefclass_buffer); - free ((char *)altclass_buffer); + free ((char *) renumber); + free ((char *) reg_pref); renumber = (short *) xmalloc (size_renumber); - prefclass_buffer = (char *) xmalloc (regno_allocated); - altclass_buffer = (char *) xmalloc (regno_allocated); + reg_pref_buffer = (struct reg_pref *) xmalloc (regno_allocated + * sizeof (struct reg_pref)); } else { - renumber = (short *) xrealloc ((char *)renumber, size_renumber); - prefclass_buffer = (char *) xrealloc ((char *)prefclass_buffer, - regno_allocated); - - altclass_buffer = (char *) xrealloc ((char *)altclass_buffer, - regno_allocated); + renumber = (short *) xrealloc ((char *) renumber, size_renumber); + reg_pref_buffer = (struct reg_pref *) xrealloc ((char *) reg_pref_buffer, + regno_allocated + * sizeof (struct reg_pref)); } } @@ -1893,45 +2244,42 @@ allocate_reg_info (num_regs, new_p, renumber_p) { /* Loop through each of the segments allocated for the actual reg_info pages, and set up the pointers, zero the pages, etc. */ - for (reg_data = reg_info_head; reg_data; reg_data = reg_next) + for (reg_data = reg_info_head; + reg_data && reg_data->max_index >= min; + reg_data = reg_data->next) { size_t min_index = reg_data->min_index; size_t max_index = reg_data->max_index; + size_t max = MIN (max_index, num_regs); + size_t local_min = min - min_index; + size_t i; - reg_next = reg_data->next; - if (min <= max_index) - { - size_t max = max_index; - size_t local_min = min - min_index; - size_t i; - - if (min < min_index) - local_min = 0; - if (!reg_data->used_p) /* page just allocated with calloc */ - reg_data->used_p = 1; /* no need to zero */ - else - bzero ((char *) ®_data->data[local_min], - sizeof (reg_info) * (max - min_index - local_min + 1)); + if (reg_data->min_index > num_regs) + continue; - for (i = min_index+local_min; i <= max; i++) - { - VARRAY_REG (reg_n_info, i) = ®_data->data[i-min_index]; - REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN; - renumber[i] = -1; - prefclass_buffer[i] = (char) NO_REGS; - altclass_buffer[i] = (char) NO_REGS; - } + if (min < min_index) + local_min = 0; + if (!reg_data->used_p) /* page just allocated with calloc */ + reg_data->used_p = 1; /* no need to zero */ + else + memset ((char *) ®_data->data[local_min], 0, + sizeof (reg_info) * (max - min_index - local_min + 1)); + + for (i = min_index+local_min; i <= max; i++) + { + VARRAY_REG (reg_n_info, i) = ®_data->data[i-min_index]; + REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN; + renumber[i] = -1; + reg_pref_buffer[i].prefclass = (char) NO_REGS; + reg_pref_buffer[i].altclass = (char) NO_REGS; } } } /* If {pref,alt}class have already been allocated, update the pointers to the newly realloced ones. */ - if (prefclass) - { - prefclass = prefclass_buffer; - altclass = altclass_buffer; - } + if (reg_pref) + reg_pref = reg_pref_buffer; if (renumber_p) reg_renumber = renumber; @@ -1953,15 +2301,13 @@ free_reg_info () for (reg_data = reg_info_head; reg_data; reg_data = reg_next) { reg_next = reg_data->next; - free ((char *)reg_data); + free ((char *) reg_data); } - free (prefclass_buffer); - free (altclass_buffer); - prefclass_buffer = (char *)0; - altclass_buffer = (char *)0; - reg_info_head = (struct reg_info_data *)0; - renumber = (short *)0; + free (reg_pref_buffer); + reg_pref_buffer = (struct reg_pref *) 0; + reg_info_head = (struct reg_info_data *) 0; + renumber = (short *) 0; } regno_allocated = 0; reg_n_max = 0; @@ -1978,20 +2324,28 @@ free_reg_info () /* Maximum number of parallel sets and clobbers in any insn in this fn. Always at least 3, since the combiner could put that many together - and we want this to remain correct for all the remaining passes. */ + and we want this to remain correct for all the remaining passes. + This corresponds to the maximum number of times note_stores will call + a function for any insn. */ int max_parallel; +/* Used as a temporary to record the largest number of registers in + PARALLEL in a SET_DEST. This is added to max_parallel. */ + +static int max_set_parallel; + void reg_scan (f, nregs, repeat) rtx f; - int nregs; - int repeat; + unsigned int nregs; + int repeat ATTRIBUTE_UNUSED; { - register rtx insn; + rtx insn; allocate_reg_info (nregs, TRUE, FALSE); max_parallel = 3; + max_set_parallel = 0; for (insn = f; insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == INSN @@ -2006,6 +2360,8 @@ reg_scan (f, nregs, repeat) if (REG_NOTES (insn)) reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0); } + + max_parallel += max_set_parallel; } /* Update 'regscan' information by looking at the insns @@ -2014,12 +2370,12 @@ reg_scan (f, nregs, repeat) such a REG. We only update information for those. */ void -reg_scan_update(first, last, old_max_regno) +reg_scan_update (first, last, old_max_regno) rtx first; rtx last; - int old_max_regno; + unsigned int old_max_regno; { - register rtx insn; + rtx insn; allocate_reg_info (max_reg_num (), FALSE, FALSE); @@ -2048,11 +2404,11 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno) rtx x; rtx insn; int note_flag; - int min_regno; + unsigned int min_regno; { - register enum rtx_code code; - register rtx dest; - register rtx note; + enum rtx_code code; + rtx dest; + rtx note; code = GET_CODE (x); switch (code) @@ -2070,7 +2426,7 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno) case REG: { - register int regno = REGNO (x); + unsigned int regno = REGNO (x); if (regno >= min_regno) { @@ -2103,9 +2459,17 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno) dest = XEXP (dest, 0)) ; + /* For a PARALLEL, record the number of things (less the usual one for a + SET) that are set. */ + if (GET_CODE (dest) == PARALLEL) + max_set_parallel = MAX (max_set_parallel, XVECLEN (dest, 0) - 1); + if (GET_CODE (dest) == REG && REGNO (dest) >= min_regno) - REG_N_SETS (REGNO (dest))++; + { + REG_N_SETS (REGNO (dest))++; + REG_N_REFS (REGNO (dest))++; + } /* If this is setting a pseudo from another pseudo or the sum of a pseudo and a constant integer and the other pseudo is known to be @@ -2125,18 +2489,18 @@ reg_scan_mark_refs (x, insn, note_flag, 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 - optimizations). So only set REGNO_POINTER_FLAG on the destination + 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 && ! REG_USERVAR_P (SET_DEST (x)) - && ! REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) + && ! REG_POINTER (SET_DEST (x)) && ((GET_CODE (SET_SRC (x)) == REG - && REGNO_POINTER_FLAG (REGNO (SET_SRC (x)))) + && REG_POINTER (SET_SRC (x))) || ((GET_CODE (SET_SRC (x)) == PLUS || GET_CODE (SET_SRC (x)) == LO_SUM) && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT && GET_CODE (XEXP (SET_SRC (x), 0)) == REG - && REGNO_POINTER_FLAG (REGNO (XEXP (SET_SRC (x), 0)))) + && REG_POINTER (XEXP (SET_SRC (x), 0))) || GET_CODE (SET_SRC (x)) == CONST || GET_CODE (SET_SRC (x)) == SYMBOL_REF || GET_CODE (SET_SRC (x)) == LABEL_REF @@ -2153,21 +2517,39 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno) && (GET_CODE (XEXP (note, 0)) == CONST || GET_CODE (XEXP (note, 0)) == SYMBOL_REF || GET_CODE (XEXP (note, 0)) == LABEL_REF)))) - REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1; + REG_POINTER (SET_DEST (x)) = 1; + + /* If this is setting a register from a register or from a simple + conversion of a register, propagate REG_DECL. */ + if (GET_CODE (dest) == REG) + { + rtx src = SET_SRC (x); + + while (GET_CODE (src) == SIGN_EXTEND + || GET_CODE (src) == ZERO_EXTEND + || GET_CODE (src) == TRUNCATE + || (GET_CODE (src) == SUBREG && subreg_lowpart_p (src))) + src = XEXP (src, 0); + + if (GET_CODE (src) == REG && REGNO_DECL (REGNO (src)) == 0) + REGNO_DECL (REGNO (src)) = REGNO_DECL (REGNO (dest)); + else if (GET_CODE (src) == REG && REGNO_DECL (REGNO (dest)) == 0) + REGNO_DECL (REGNO (dest)) = REGNO_DECL (REGNO (src)); + } /* ... fall through ... */ default: { - register char *fmt = GET_RTX_FORMAT (code); - register int i; + const char *fmt = GET_RTX_FORMAT (code); + int i; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') reg_scan_mark_refs (XEXP (x, i), insn, note_flag, min_regno); else if (fmt[i] == 'E' && XVEC (x, i) != 0) { - register int j; + int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag, min_regno); } @@ -2181,16 +2563,16 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno) int reg_class_subset_p (c1, c2) - register enum reg_class c1; - register enum reg_class c2; + enum reg_class c1; + enum reg_class c2; { if (c1 == c2) return 1; if (c2 == ALL_REGS) win: return 1; - GO_IF_HARD_REG_SUBSET (reg_class_contents[(int)c1], - reg_class_contents[(int)c2], + GO_IF_HARD_REG_SUBSET (reg_class_contents[(int) c1], + reg_class_contents[(int) c2], win); return 0; } @@ -2199,8 +2581,8 @@ reg_class_subset_p (c1, c2) int reg_classes_intersect_p (c1, c2) - register enum reg_class c1; - register enum reg_class c2; + enum reg_class c1; + enum reg_class c2; { #ifdef HARD_REG_SET register |