X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fregclass.c;h=1baccf68979640798ba253a409136350272640a8;hb=f38e9908a187124e506ee74ec2e4dc9dd7669d65;hp=f76fdcd77cfa6942bfbb1b51ce364d44834d0d87;hpb=00cb30dc08e9b6d5988e14797f58c2bfc298cfa1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/regclass.c b/gcc/regclass.c index f76fdcd77cf..1baccf68979 100644 --- a/gcc/regclass.c +++ b/gcc/regclass.c @@ -1,6 +1,6 @@ /* Compute register class preferences for pseudo-registers. Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996 - 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GCC. @@ -48,6 +48,12 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "timevar.h" #include "hashtab.h" #include "target.h" +#include "tree-pass.h" +#include "df.h" + +/* Maximum register number used in this function, plus one. */ + +int max_regno; static void init_reg_sets_1 (void); static void init_reg_autoinc (void); @@ -241,20 +247,6 @@ static char *in_inc_dec; static GTY(()) rtx top_of_stack[MAX_MACHINE_MODE]; -/* Linked list of reg_info structures allocated for reg_n_info array. - Grouping all of the allocated structures together in one lump - means only one call to bzero to clear them, rather than n smaller - calls. */ -struct reg_info_data { - struct reg_info_data *next; /* next set of reg_info structures */ - size_t min_index; /* minimum index # */ - size_t max_index; /* maximum index # */ - char used_p; /* nonzero if this has been used previously */ - reg_info data[1]; /* beginning of the 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. */ @@ -263,6 +255,26 @@ static int no_global_reg_vars = 0; /* Specify number of hard registers given machine mode occupy. */ unsigned char hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE]; +/* Given a register bitmap, turn on the bits in a HARD_REG_SET that + correspond to the hard registers, if any, set in that map. This + could be done far more efficiently by having all sorts of special-cases + with moving single words, but probably isn't worth the trouble. */ + +void +reg_set_to_hard_reg_set (HARD_REG_SET *to, bitmap from) +{ + unsigned i; + bitmap_iterator bi; + + EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi) + { + if (i >= FIRST_PSEUDO_REGISTER) + return; + SET_HARD_REG_BIT (*to, i); + } +} + + /* Function called only once to initialize the above data on reg usage. Once this is done, various switches may override. */ @@ -338,20 +350,11 @@ init_reg_sets_1 (void) COPY_HARD_REG_SET (c, reg_class_contents[i]); IOR_HARD_REG_SET (c, reg_class_contents[j]); for (k = 0; k < N_REG_CLASSES; k++) - { - GO_IF_HARD_REG_SUBSET (reg_class_contents[k], c, - subclass1); - continue; - - subclass1: - /* Keep the largest subclass. */ /* SPEE 900308 */ - GO_IF_HARD_REG_SUBSET (reg_class_contents[k], - reg_class_contents[(int) reg_class_subunion[i][j]], - subclass2); + if (hard_reg_set_subset_p (reg_class_contents[k], c) + && !hard_reg_set_subset_p (reg_class_contents[k], + reg_class_contents + [(int) reg_class_subunion[i][j]])) reg_class_subunion[i][j] = (enum reg_class) k; - subclass2: - ; - } } } @@ -369,9 +372,9 @@ init_reg_sets_1 (void) COPY_HARD_REG_SET (c, reg_class_contents[i]); IOR_HARD_REG_SET (c, reg_class_contents[j]); for (k = 0; k < N_REG_CLASSES; k++) - GO_IF_HARD_REG_SUBSET (c, reg_class_contents[k], superclass); + if (hard_reg_set_subset_p (c, reg_class_contents[k])) + break; - superclass: reg_class_superunion[i][j] = (enum reg_class) k; } } @@ -394,23 +397,21 @@ init_reg_sets_1 (void) continue; for (j = i + 1; j < N_REG_CLASSES; j++) - { - enum reg_class *p; - - GO_IF_HARD_REG_SUBSET (reg_class_contents[i], reg_class_contents[j], - subclass); - continue; - subclass: - /* Reg class I is a subclass of J. - Add J to the table of superclasses of I. */ - p = ®_class_superclasses[i][0]; - while (*p != LIM_REG_CLASSES) p++; - *p = (enum reg_class) j; - /* Add I to the table of superclasses of J. */ - p = ®_class_subclasses[j][0]; - while (*p != LIM_REG_CLASSES) p++; - *p = (enum reg_class) i; - } + if (hard_reg_set_subset_p (reg_class_contents[i], + reg_class_contents[j])) + { + /* Reg class I is a subclass of J. + Add J to the table of superclasses of I. */ + enum reg_class *p; + + p = ®_class_superclasses[i][0]; + while (*p != LIM_REG_CLASSES) p++; + *p = (enum reg_class) j; + /* Add I to the table of superclasses of J. */ + p = ®_class_subclasses[j][0]; + while (*p != LIM_REG_CLASSES) p++; + *p = (enum reg_class) i; + } } /* Initialize "constant" tables. */ @@ -811,7 +812,8 @@ struct costs /* Structure used to record preferences of given pseudo. */ struct reg_pref { - /* (enum reg_class) prefclass is the preferred class. */ + /* (enum reg_class) prefclass is the preferred class. May be + NO_REGS if no class is better than memory. */ char prefclass; /* altclass is a register class that we should use for allocating @@ -837,10 +839,6 @@ static struct costs init_cost; static struct reg_pref *reg_pref; -/* Allocated buffers for reg_pref. */ - -static struct reg_pref *reg_pref_buffer; - /* Frequency of executions of current insn. */ static int frequency; @@ -858,7 +856,7 @@ static void record_address_regs (enum machine_mode, rtx, int, enum rtx_code, #ifdef FORBIDDEN_INC_DEC_CLASSES static int auto_inc_dec_reg_p (rtx, enum machine_mode); #endif -static void reg_scan_mark_refs (rtx, rtx, int); +static void reg_scan_mark_refs (rtx, rtx); /* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudo registers. */ @@ -906,11 +904,14 @@ reg_alternate_class (int regno) /* Initialize some global data for this pass. */ -void +static unsigned int regclass_init (void) { int i; + if (df) + df_compute_regs_ever_live (true); + init_cost.mem_cost = 10000; for (i = 0; i < N_REG_CLASSES; i++) init_cost.cost[i] = 10000; @@ -921,7 +922,27 @@ regclass_init (void) /* No more global register variables may be declared. */ no_global_reg_vars = 1; + return 1; } + +struct tree_opt_pass pass_regclass_init = +{ + "regclass", /* name */ + NULL, /* gate */ + regclass_init, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 'k' /* letter */ +}; + + /* Dump register costs. */ static void @@ -1028,7 +1049,7 @@ record_operand_costs (rtx insn, struct costs *op_costs, there. */ static rtx -scan_one_insn (rtx insn, int pass) +scan_one_insn (rtx insn, int pass ATTRIBUTE_UNUSED) { enum rtx_code pat_code; rtx set, note; @@ -1068,68 +1089,6 @@ scan_one_insn (rtx insn, int pass) return insn; } - /* Improve handling of two-address insns such as - (set X (ashift CONST Y)) where CONST must be made to - match X. Change it into two insns: (set X CONST) - (set X (ashift X Y)). If we left this for reloading, it - would probably get three insns because X and Y might go - in the same place. This prevents X and Y from receiving - the same hard reg. - - We can only do this if the modes of operands 0 and 1 - (which might not be the same) are tieable and we only need - do this during our first pass. */ - - if (pass == 0 && optimize - && 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]) - && REG_P (recog_data.operand[0]) - && 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_data.operand_mode[1], - recog_data.operand[0]); - rtx newinsn - = 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. - We need not check for code_label here; - while a basic block can start with a code_label, - INSN could not be at the beginning of that block. */ - if (previnsn == 0 || JUMP_P (previnsn)) - { - basic_block b; - FOR_EACH_BB (b) - if (insn == BB_HEAD (b)) - BB_HEAD (b) = newinsn; - } - - /* This makes one more setting of new insns's dest. */ - 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); - } - record_operand_costs (insn, op_costs, reg_pref); /* Now add the cost for each operand to the total costs for @@ -1168,7 +1127,7 @@ init_reg_autoinc (void) for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) if (TEST_HARD_REG_BIT (reg_class_contents[i], j)) { - REGNO (r) = j; + SET_REGNO (r, j); for (m = VOIDmode; (int) m < (int) MAX_MACHINE_MODE; m = (enum machine_mode) ((int) m + 1)) @@ -1209,9 +1168,14 @@ regclass (rtx f, int nregs) rtx insn; int i; int pass; + max_regno = max_reg_num (); init_recog (); + reg_renumber = xmalloc (max_regno * sizeof (short)); + reg_pref = XCNEWVEC (struct reg_pref, max_regno); + memset (reg_renumber, -1, max_regno * sizeof (short)); + costs = XNEWVEC (struct costs, nregs); #ifdef FORBIDDEN_INC_DEC_CLASSES @@ -1269,9 +1233,6 @@ regclass (rtx f, int nregs) `prefclass'. Record in `altclass' the largest register class any of whose registers is better than memory. */ - if (pass == 0) - reg_pref = reg_pref_buffer; - if (dump_file) { dump_regclass (dump_file); @@ -1286,6 +1247,9 @@ regclass (rtx f, int nregs) int class; struct costs *p = &costs[i]; + if (regno_reg_rtx[i] == NULL) + continue; + /* In non-optimizing compilation REG_N_REFS is not initialized yet. */ if (optimize && !REG_N_REFS (i) && !REG_N_SETS (i)) @@ -1314,6 +1278,10 @@ regclass (rtx f, int nregs) best = reg_class_subunion[(int) best][class]; } + /* If no register class is better than memory, use memory. */ + if (p->mem_cost < best_cost) + best = NO_REGS; + /* Record the alternate register class; i.e., a class for which every register in it is better than using memory. If adding a class would make a smaller class (i.e., no union of just those @@ -1524,7 +1492,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, to what we would add if this register were not in the appropriate class. */ - if (reg_pref) + if (reg_pref && reg_pref[REGNO (op)].prefclass != NO_REGS) alt_cost += (may_move_in_cost[mode] [(unsigned char) reg_pref[REGNO (op)].prefclass] @@ -1750,7 +1718,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, to what we would add if this register were not in the appropriate class. */ - if (reg_pref) + if (reg_pref && reg_pref[REGNO (op)].prefclass != NO_REGS) alt_cost += (may_move_in_cost[mode] [(unsigned char) reg_pref[REGNO (op)].prefclass] @@ -1834,9 +1802,9 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, unsigned int regno = REGNO (ops[!i]); enum machine_mode mode = GET_MODE (ops[!i]); int class; - unsigned int nr; - if (regno >= FIRST_PSEUDO_REGISTER && reg_pref != 0) + if (regno >= FIRST_PSEUDO_REGISTER && reg_pref != 0 + && reg_pref[regno].prefclass != NO_REGS) { enum reg_class pref = reg_pref[regno].prefclass; @@ -1852,18 +1820,9 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, { if (reg_class_size[class] == 1) op_costs[i].cost[class] = -1; - else - { - for (nr = 0; nr < (unsigned) hard_regno_nregs[regno][mode]; nr++) - { - if (! TEST_HARD_REG_BIT (reg_class_contents[class], - regno + nr)) - break; - } - - if (nr == (unsigned) hard_regno_nregs[regno][mode]) - op_costs[i].cost[class] = -1; - } + else if (in_hard_reg_set_p (reg_class_contents[class], + mode, regno)) + op_costs[i].cost[class] = -1; } } } @@ -2142,195 +2101,56 @@ auto_inc_dec_reg_p (rtx reg, enum machine_mode mode) } #endif -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 - NEW_P is nonzero, initialize all of the registers, otherwise only - initialize the new registers allocated. The same table is kept from - function to function, only reallocating it when we need more room. If - RENUMBER_P is nonzero, allocate the reg_renumber array also. */ - +/* Free up the space allocated by allocate_reg_info. */ void -allocate_reg_info (size_t num_regs, int new_p, int renumber_p) +free_reg_info (void) { - size_t size_info; - size_t size_renumber; - size_t min = (new_p) ? 0 : reg_n_max; - struct reg_info_data *reg_data; - - if (num_regs > regno_allocated) + if (reg_pref) { - size_t old_allocated = regno_allocated; - - regno_allocated = num_regs + (num_regs / 20); /* Add some slop space. */ - size_renumber = regno_allocated * sizeof (short); - - if (!reg_n_info) - { - VARRAY_REG_INIT (reg_n_info, regno_allocated, "reg_n_info"); - renumber = xmalloc (size_renumber); - reg_pref_buffer = XNEWVEC (struct reg_pref, regno_allocated); - } - else - { - VARRAY_GROW (reg_n_info, regno_allocated); - - if (new_p) /* If we're zapping everything, no need to realloc. */ - { - free ((char *) renumber); - free ((char *) reg_pref); - renumber = xmalloc (size_renumber); - reg_pref_buffer = XNEWVEC (struct reg_pref, regno_allocated); - } - - else - { - renumber = xrealloc (renumber, size_renumber); - reg_pref_buffer = (struct reg_pref *) xrealloc (reg_pref_buffer, - regno_allocated - * sizeof (struct reg_pref)); - } - } - - size_info = (regno_allocated - old_allocated) * sizeof (reg_info) - + sizeof (struct reg_info_data) - sizeof (reg_info); - reg_data = xcalloc (size_info, 1); - reg_data->min_index = old_allocated; - reg_data->max_index = regno_allocated - 1; - reg_data->next = reg_info_head; - reg_info_head = reg_data; + free (reg_pref); + reg_pref = NULL; } - reg_n_max = num_regs; - if (min < num_regs) + if (reg_renumber) { - /* 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->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; - - if (reg_data->min_index > num_regs) - continue; - - 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 (®_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; - } - } + free (reg_renumber); + reg_renumber = NULL; } - - /* If {pref,alt}class have already been allocated, update the pointers to - the newly realloced ones. */ - if (reg_pref) - reg_pref = reg_pref_buffer; - - if (renumber_p) - reg_renumber = renumber; } -/* Free up the space allocated by allocate_reg_info. */ -void -free_reg_info (void) -{ - if (reg_n_info) - { - struct reg_info_data *reg_data; - struct reg_info_data *reg_next; - - VARRAY_FREE (reg_n_info); - for (reg_data = reg_info_head; reg_data; reg_data = reg_next) - { - reg_next = reg_data->next; - free ((char *) reg_data); - } - - 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; -} -/* This is the `regscan' pass of the compiler, run just before cse - and again just before loop. - - It finds the first and last use of each pseudo-register - and records them in the vectors regno_first_uid, regno_last_uid - and counts the number of sets in the vector reg_n_sets. - - REPEAT is nonzero the second time this is called. */ - -/* 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. - 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; +/* This is the `regscan' pass of the compiler, run just before cse and + again just before loop. It finds the first and last use of each + pseudo-register. */ void -reg_scan (rtx f, unsigned int nregs) +reg_scan (rtx f, unsigned int nregs ATTRIBUTE_UNUSED) { rtx insn; timevar_push (TV_REG_SCAN); - allocate_reg_info (nregs, TRUE, FALSE); - max_parallel = 3; - max_set_parallel = 0; - for (insn = f; insn; insn = NEXT_INSN (insn)) if (INSN_P (insn)) { - rtx pat = PATTERN (insn); - if (GET_CODE (pat) == PARALLEL - && XVECLEN (pat, 0) > max_parallel) - max_parallel = XVECLEN (pat, 0); - reg_scan_mark_refs (pat, insn, 0); - + reg_scan_mark_refs (PATTERN (insn), insn); if (REG_NOTES (insn)) - reg_scan_mark_refs (REG_NOTES (insn), insn, 1); + reg_scan_mark_refs (REG_NOTES (insn), insn); } - max_parallel += max_set_parallel; - timevar_pop (TV_REG_SCAN); } + /* X is the expression to scan. INSN is the insn it appears in. - NOTE_FLAG is nonzero if X is from INSN's notes rather than its body. */ + NOTE_FLAG is nonzero if X is from INSN's notes rather than its body. + We should only record information for REGs with numbers + greater than or equal to MIN_REGNO. */ + +extern struct tree_opt_pass *current_pass; static void -reg_scan_mark_refs (rtx x, rtx insn, int note_flag) +reg_scan_mark_refs (rtx x, rtx insn) { enum rtx_code code; rtx dest; @@ -2351,42 +2171,24 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag) case LABEL_REF: case ADDR_VEC: case ADDR_DIFF_VEC: - return; - case REG: - { - unsigned int regno = REGNO (x); - - if (!note_flag) - REGNO_LAST_UID (regno) = INSN_UID (insn); - if (REGNO_FIRST_UID (regno) == 0) - REGNO_FIRST_UID (regno) = INSN_UID (insn); - } - break; + return; case EXPR_LIST: if (XEXP (x, 0)) - reg_scan_mark_refs (XEXP (x, 0), insn, note_flag); + reg_scan_mark_refs (XEXP (x, 0), insn); if (XEXP (x, 1)) - reg_scan_mark_refs (XEXP (x, 1), insn, note_flag); + reg_scan_mark_refs (XEXP (x, 1), insn); break; case INSN_LIST: if (XEXP (x, 1)) - reg_scan_mark_refs (XEXP (x, 1), insn, note_flag); + reg_scan_mark_refs (XEXP (x, 1), insn); break; case CLOBBER: - { - rtx reg = XEXP (x, 0); - if (REG_P (reg)) - { - REG_N_SETS (REGNO (reg))++; - REG_N_REFS (REGNO (reg))++; - } - else if (MEM_P (reg)) - reg_scan_mark_refs (XEXP (reg, 0), insn, note_flag); - } + if (MEM_P (XEXP (x, 0))) + reg_scan_mark_refs (XEXP (XEXP (x, 0), 0), insn); break; case SET: @@ -2397,17 +2199,6 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag) 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 (REG_P (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 a pointer, set the destination to be a pointer as well. @@ -2427,7 +2218,7 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag) 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 + && DF_REG_DEF_COUNT (REGNO (SET_DEST (x))) == 1 && ! REG_USERVAR_P (SET_DEST (x)) && ! REG_POINTER (SET_DEST (x)) && ((REG_P (SET_SRC (x)) @@ -2457,7 +2248,7 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag) /* If this is setting a register from a register or from a simple conversion of a register, propagate REG_EXPR. */ - if (REG_P (dest)) + if (REG_P (dest) && !REG_ATTRS (dest)) { rtx src = SET_SRC (x); @@ -2467,9 +2258,9 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag) || (GET_CODE (src) == SUBREG && subreg_lowpart_p (src))) src = XEXP (src, 0); - if (!REG_ATTRS (dest) && REG_P (src)) + if (REG_P (src)) REG_ATTRS (dest) = REG_ATTRS (src); - if (!REG_ATTRS (dest) && MEM_P (src)) + if (MEM_P (src)) set_reg_attrs_from_mem (dest, src); } @@ -2482,12 +2273,12 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag) for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') - reg_scan_mark_refs (XEXP (x, i), insn, note_flag); + reg_scan_mark_refs (XEXP (x, i), insn); else if (fmt[i] == 'E' && XVEC (x, i) != 0) { int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) - reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag); + reg_scan_mark_refs (XVECEXP (x, i, j), insn); } } } @@ -2500,15 +2291,10 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag) int reg_class_subset_p (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], - win); - return 0; + return (c1 == c2 + || c2 == ALL_REGS + || hard_reg_set_subset_p (reg_class_contents[(int) c1], + reg_class_contents[(int) c2])); } /* Return nonzero if there is a register that is in both C1 and C2. */ @@ -2516,21 +2302,11 @@ reg_class_subset_p (enum reg_class c1, enum reg_class c2) int reg_classes_intersect_p (enum reg_class c1, enum reg_class c2) { - HARD_REG_SET c; - - if (c1 == c2) return 1; - - if (c1 == ALL_REGS || c2 == ALL_REGS) - return 1; - - COPY_HARD_REG_SET (c, reg_class_contents[(int) c1]); - AND_HARD_REG_SET (c, reg_class_contents[(int) c2]); - - GO_IF_HARD_REG_SUBSET (c, reg_class_contents[(int) NO_REGS], lose); - return 1; - - lose: - return 0; + return (c1 == c2 + || c1 == ALL_REGS + || c2 == ALL_REGS + || hard_reg_set_intersect_p (reg_class_contents[(int) c1], + reg_class_contents[(int) c2])); } #ifdef CANNOT_CHANGE_MODE_CLASS @@ -2558,16 +2334,8 @@ som_eq (const void *x, const void *y) return a->block == b->block; } -void -init_subregs_of_mode (void) -{ - if (subregs_of_mode) - htab_empty (subregs_of_mode); - else - subregs_of_mode = htab_create (100, som_hash, som_eq, free); -} -void +static void record_subregs_of_mode (rtx subreg) { struct subregs_of_mode_node dummy, *node; @@ -2598,6 +2366,53 @@ record_subregs_of_mode (rtx subreg) 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) +{ + 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); + + /* 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)); + else if (fmt[i] == 'E') + { + int j; + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + find_subregs_of_mode (XVECEXP (x, i, j)); + } + } +} + +static unsigned int +init_subregs_of_mode (void) +{ + basic_block bb; + rtx insn; + + if (subregs_of_mode) + htab_empty (subregs_of_mode); + else + subregs_of_mode = htab_create (100, som_hash, som_eq, free); + + FOR_EACH_BB (bb) + FOR_BB_INSNS (bb, insn) + if (INSN_P (insn)) + find_subregs_of_mode (PATTERN (insn)); + + return 0; +} + + /* Set bits in *USED which correspond to registers which can't change their mode from FROM to any mode in which REGNO was encountered. */ @@ -2610,6 +2425,7 @@ cannot_change_mode_set_regs (HARD_REG_SET *used, enum machine_mode from, unsigned char mask; unsigned int i; + gcc_assert (subregs_of_mode); dummy.block = regno & -8; node = htab_find_with_hash (subregs_of_mode, &dummy, dummy.block); if (node == NULL) @@ -2628,13 +2444,15 @@ cannot_change_mode_set_regs (HARD_REG_SET *used, enum machine_mode from, mode. */ bool -invalid_mode_change_p (unsigned int regno, enum reg_class class, +invalid_mode_change_p (unsigned int regno, + enum reg_class class ATTRIBUTE_UNUSED, enum machine_mode from) { struct subregs_of_mode_node dummy, *node; enum machine_mode to; unsigned char mask; + gcc_assert (subregs_of_mode); dummy.block = regno & -8; node = htab_find_with_hash (subregs_of_mode, &dummy, dummy.block); if (node == NULL) @@ -2648,6 +2466,72 @@ invalid_mode_change_p (unsigned int regno, enum reg_class class, return false; } + +static unsigned int +finish_subregs_of_mode (void) +{ + htab_delete (subregs_of_mode); + subregs_of_mode = 0; + return 0; +} +#else +static unsigned int +init_subregs_of_mode (void) +{ + return 0; +} +static unsigned int +finish_subregs_of_mode (void) +{ + return 0; +} + #endif /* CANNOT_CHANGE_MODE_CLASS */ +static bool +gate_subregs_of_mode_init (void) +{ +#ifdef CANNOT_CHANGE_MODE_CLASS + return true; +#else + return false; +#endif +} + +struct tree_opt_pass pass_subregs_of_mode_init = +{ + "subregs_of_mode_init", /* name */ + gate_subregs_of_mode_init, /* gate */ + init_subregs_of_mode, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 0 /* letter */ +}; + +struct tree_opt_pass pass_subregs_of_mode_finish = +{ + "subregs_of_mode_finish", /* name */ + gate_subregs_of_mode_init, /* gate */ + finish_subregs_of_mode, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ + 0 /* letter */ +}; + + + #include "gt-regclass.h"