diff options
Diffstat (limited to 'contrib/gcc/regclass.c')
-rw-r--r-- | contrib/gcc/regclass.c | 588 |
1 files changed, 436 insertions, 152 deletions
diff --git a/contrib/gcc/regclass.c b/contrib/gcc/regclass.c index 9b9a4d5..25cac8f 100644 --- a/contrib/gcc/regclass.c +++ b/contrib/gcc/regclass.c @@ -1,5 +1,5 @@ /* Compute register class preferences for pseudo-registers. - Copyright (C) 1987, 88, 91, 92, 93, 1994 Free Software Foundation, Inc. + Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc. This file is part of GNU CC. @@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA. */ and a function init_reg_sets to initialize the tables. */ #include "config.h" +#include "system.h" #include "rtl.h" #include "hard-reg-set.h" #include "flags.h" @@ -33,16 +34,13 @@ Boston, MA 02111-1307, USA. */ #include "recog.h" #include "reload.h" #include "real.h" -#include "bytecode.h" +#include "toplev.h" +#include "output.h" #ifndef REGISTER_MOVE_COST #define REGISTER_MOVE_COST(x, y) 2 #endif -#ifndef MEMORY_MOVE_COST -#define MEMORY_MOVE_COST(x) 4 -#endif - /* If we have auto-increment or auto-decrement and we can have secondary reloads, we are not allowed to use classes requiring secondary reloads for pseudos auto-incremented since reload can't handle it. */ @@ -81,6 +79,9 @@ char call_used_regs[FIRST_PSEUDO_REGISTER]; HARD_REG_SET call_used_reg_set; +/* HARD_REG_SET of registers we want to avoid caller saving. */ +HARD_REG_SET losing_caller_save_reg_set; + /* Data for initializing the above. */ static char initial_call_used_regs[] = CALL_USED_REGISTERS; @@ -160,15 +161,6 @@ char *reg_names[] = REGISTER_NAMES; enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER]; -/* Indexed by n, gives number of times (REG n) is set or clobbered. - This information remains valid for the rest of the compilation - of the current function; it is used to control register allocation. - - This information applies to both hard registers and pseudo registers, - unlike much of the information above. */ - -short *reg_n_sets; - /* Maximum cost of moving from a register in one class to a register in another class. Based on REGISTER_MOVE_COST. */ @@ -193,6 +185,29 @@ static char *in_inc_dec; #endif /* FORBIDDEN_INC_DEC_CLASSES */ +#ifdef HAVE_SECONDARY_RELOADS + +/* Sample MEM values for use by memory_move_secondary_cost. */ + +static rtx top_of_stack[MAX_MACHINE_MODE]; + +#endif /* HAVE_SECONDARY_RELOADS */ + +/* 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; /* non-zero if this has been used previously */ + reg_info data[1]; /* beginning of the reg_info data */ +}; + +static struct reg_info_data *reg_info_head; + + /* Function called only once to initialize the above data on reg usage. Once this is done, various switches may override. */ @@ -321,37 +336,8 @@ init_reg_sets () } } - /* 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++) - { - 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; - - may_move_cost[i][j] = cost; - } + /* Do any additional initialization regsets may need */ + INIT_ONCE_REG_SET (); } /* After switches have been processed, which perhaps alter @@ -360,7 +346,7 @@ init_reg_sets () static void init_reg_sets_1 () { - register int i; + register unsigned int i, j; /* This macro allows the fixed or call-used registers to depend on target flags. */ @@ -390,7 +376,41 @@ init_reg_sets_1 () SET_HARD_REG_BIT (call_used_reg_set, i); if (call_fixed_regs[i]) 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); } + + /* 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++) + { + 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; + + may_move_cost[i][j] = cost; + } } /* Compute the table of register modes. @@ -406,14 +426,13 @@ init_reg_modes () { reg_raw_mode[i] = choose_hard_reg_mode (i, 1); - /* If we couldn't find a valid mode, fall back to `word_mode'. - ??? We assume `word_mode' has already been initialized. + /* If we couldn't find a valid mode, just use the previous mode. ??? One situation in which we need to do this is on the mips where HARD_REGNO_NREGS (fpreg, [SD]Fmode) returns 2. Ideally we'd like to use DF mode for the even registers and VOIDmode for the odd (for the cpu models where the odd ones are inaccessible). */ if (reg_raw_mode[i] == VOIDmode) - reg_raw_mode[i] = word_mode; + reg_raw_mode[i] = i == 0 ? word_mode : reg_raw_mode[i-1]; } } @@ -425,12 +444,78 @@ init_regs () { /* This finishes what was started by init_reg_sets, but couldn't be done until after register usage was specified. */ - if (!output_bytecode) - init_reg_sets_1 (); + init_reg_sets_1 (); init_reg_modes (); + +#ifdef HAVE_SECONDARY_RELOADS + { + /* 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); + } +#endif } +#ifdef HAVE_SECONDARY_RELOADS + +/* Compute extra cost of moving registers to/from memory due to reloads. + Only needed if secondary reloads are required for memory moves. */ + +int +memory_move_secondary_cost (mode, class, in) + enum machine_mode mode; + enum reg_class class; + int 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]; + + if (in) + { +#ifdef SECONDARY_INPUT_RELOAD_CLASS + altclass = SECONDARY_INPUT_RELOAD_CLASS (class, mode, mem); +#else + altclass = NO_REGS; +#endif + } + else + { +#ifdef SECONDARY_OUTPUT_RELOAD_CLASS + altclass = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, mem); +#else + altclass = NO_REGS; +#endif + } + + if (altclass == NO_REGS) + return 0; + + if (in) + partial_cost = REGISTER_MOVE_COST (altclass, class); + else + partial_cost = REGISTER_MOVE_COST (class, altclass); + + if (class == altclass) + /* This isn't simply a copy-to-temporary situation. Can't guess + what it is, so MEMORY_MOVE_COST really ought not to be calling + here in that case. + + I'm tempted to put in an abort here, but returning this will + probably only give poor estimates, which is what we would've + had before this code anyways. */ + return partial_cost; + + /* Check if the secondary reload register will also need a + secondary reload. */ + return memory_move_secondary_cost (mode, altclass, in) + partial_cost; +} +#endif + /* Return a machine mode that is legitimate for hard reg REGNO and large enough to save nregs. If we can't find one, return VOIDmode. */ @@ -484,13 +569,6 @@ fix_register (name, fixed, call_used) { int i; - if (output_bytecode) - { - warning ("request to mark `%s' as %s ignored by bytecode compiler", - name, call_used ? "call-used" : "fixed"); - return; - } - /* Decode the name and update the primary form of the register info. */ @@ -574,6 +652,10 @@ static char *prefclass; static char *altclass; +/* Allocated buffers for prefclass and altclass. */ +static char *prefclass_buffer; +static char *altclass_buffer; + /* Record the depth of loops that we are in. */ static int loop_depth; @@ -588,8 +670,10 @@ static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *, static int copy_cost PROTO((rtx, enum machine_mode, enum reg_class, int)); static void record_address_regs PROTO((rtx, enum reg_class, int)); -static auto_inc_dec_reg_p PROTO((rtx, enum machine_mode)); -static void reg_scan_mark_refs PROTO((rtx, rtx, int)); +#ifdef FORBIDDEN_INC_DEC_CLASSES +static int auto_inc_dec_reg_p PROTO((rtx, enum machine_mode)); +#endif +static void reg_scan_mark_refs PROTO((rtx, rtx, int, 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. @@ -606,6 +690,7 @@ reg_preferred_class (regno) enum reg_class reg_alternate_class (regno) + int regno; { if (prefclass == 0) return ALL_REGS; @@ -654,7 +739,7 @@ regclass (f, nregs) for (i = 0; i < N_REG_CLASSES; i++) { - rtx r = gen_rtx (REG, VOIDmode, 0); + rtx r = gen_rtx_REG (VOIDmode, 0); enum machine_mode m; for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) @@ -674,6 +759,10 @@ regclass (f, nregs) being used in such addresses. */ if ((0 +#ifdef SECONDARY_RELOAD_CLASS + || (SECONDARY_RELOAD_CLASS (BASE_REG_CLASS, m, r) + != NO_REGS) +#else #ifdef SECONDARY_INPUT_RELOAD_CLASS || (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r) != NO_REGS) @@ -682,6 +771,7 @@ regclass (f, nregs) || (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r) != NO_REGS) #endif +#endif ) && ! auto_inc_dec_reg_p (r, m)) forbidden_inc_dec_class[i] = 1; @@ -772,7 +862,8 @@ regclass (f, nregs) && GET_CODE (XEXP (note, 0)) == MEM) { costs[REGNO (SET_DEST (set))].mem_cost - -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set))) + -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)), + GENERAL_REGS, 1) * loop_cost); record_address_regs (XEXP (SET_SRC (set), 0), BASE_REG_CLASS, loop_cost * 2); @@ -824,8 +915,8 @@ regclass (f, nregs) basic_block_head[b] = newinsn; } - /* This makes one more setting of new insns's dest. */ - reg_n_sets[REGNO (recog_operand[0])]++; + /* 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 = insn_n_dups[insn_code_number] - 1; i >= 0; i--) @@ -915,8 +1006,8 @@ regclass (f, nregs) if (pass == 0) { - prefclass = (char *) oballoc (nregs); - altclass = (char *) oballoc (nregs); + prefclass = prefclass_buffer; + altclass = altclass_buffer; } for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++) @@ -968,7 +1059,7 @@ regclass (f, nregs) /* If we don't add any classes, nothing to try. */ if (alt == best) - alt = (int) NO_REGS; + alt = NO_REGS; /* We cast to (int) because (char) hits bugs in some compilers. */ prefclass[i] = (int) best; @@ -1142,8 +1233,10 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn) p++; break; + case '?': + alt_cost += 2; case '%': - case '?': case '!': case '#': + case '!': case '#': case '&': case '0': case '1': case '2': case '3': case '4': case 'p': @@ -1289,7 +1382,8 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn) a bit cheaper since we won't need an extra insn to load it. */ - pp->mem_cost = MEMORY_MOVE_COST (mode) - allows_mem; + pp->mem_cost = (MEMORY_MOVE_COST (mode, classes[i], 1) + - allows_mem); /* If we have assigned a class to this register in our first pass, add a cost to this alternative corresponding @@ -1327,7 +1421,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn) constant that could be placed into memory. */ else if (CONSTANT_P (op) && allows_mem) - alt_cost += MEMORY_MOVE_COST (mode); + alt_cost += MEMORY_MOVE_COST (mode, classes[i], 1); else alt_fail = 1; } @@ -1407,7 +1501,9 @@ copy_cost (x, mode, class, to_p) enum reg_class class; int to_p; { +#ifdef HAVE_SECONDARY_RELOADS enum reg_class secondary_class = NO_REGS; +#endif /* If X is a SCRATCH, there is actually nothing to move since we are assuming optimal allocation. */ @@ -1444,7 +1540,7 @@ copy_cost (x, mode, class, to_p) else (constants). */ if (GET_CODE (x) == MEM || class == NO_REGS) - return MEMORY_MOVE_COST (mode); + 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]; @@ -1536,38 +1632,54 @@ record_address_regs (x, class, scale) else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF) record_address_regs (arg0, INDEX_REG_CLASS, scale); - /* If this the sum of two registers where the first is known to be a - pointer, it must be a base register with the second an index. */ + /* If both operands are registers but one is already a hard register + of index or base class, give the other the class that the hard + register is not. */ +#ifdef REG_OK_FOR_BASE_P else if (code0 == REG && code1 == REG - && REGNO_POINTER_FLAG (REGNO (arg0))) + && REGNO (arg0) < FIRST_PSEUDO_REGISTER + && (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, + 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, + scale); +#endif + + /* If one operand is known to be a pointer, it must be the base + with the other operand the index. Likewise if the other operand + is a MULT. */ + + else if ((code0 == REG && REGNO_POINTER_FLAG (REGNO (arg0))) + || code1 == MULT) { record_address_regs (arg0, BASE_REG_CLASS, scale); record_address_regs (arg1, INDEX_REG_CLASS, scale); } + else if ((code1 == REG && REGNO_POINTER_FLAG (REGNO (arg1))) + || code0 == MULT) + { + record_address_regs (arg0, INDEX_REG_CLASS, scale); + record_address_regs (arg1, BASE_REG_CLASS, scale); + } - /* If this is the sum of two registers and neither is known to - be a pointer, count equal chances that each might be a base + /* Otherwise, count equal chances that each might be a base or index register. This case should be rare. */ - else if (code0 == REG && code1 == REG - && ! REGNO_POINTER_FLAG (REGNO (arg0)) - && ! REGNO_POINTER_FLAG (REGNO (arg1))) + else { record_address_regs (arg0, BASE_REG_CLASS, scale / 2); record_address_regs (arg0, INDEX_REG_CLASS, scale / 2); record_address_regs (arg1, BASE_REG_CLASS, scale / 2); record_address_regs (arg1, INDEX_REG_CLASS, scale / 2); } - - /* In all other cases, the first operand is an index and the - second is the base. */ - - else - { - record_address_regs (arg0, INDEX_REG_CLASS, scale); - record_address_regs (arg1, BASE_REG_CLASS, scale); - } } break; @@ -1594,7 +1706,7 @@ record_address_regs (x, class, scale) register struct costs *pp = &costs[REGNO (x)]; register int i; - pp->mem_cost += (MEMORY_MOVE_COST (Pmode) * scale) / 2; + 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; @@ -1617,28 +1729,28 @@ record_address_regs (x, class, scale) /* Return 1 if REG is valid as an auto-increment memory reference to an object of MODE. */ -static +static int auto_inc_dec_reg_p (reg, mode) rtx reg; enum machine_mode mode; { #ifdef HAVE_POST_INCREMENT - if (memory_address_p (mode, gen_rtx (POST_INC, Pmode, reg))) + if (memory_address_p (mode, gen_rtx_POST_INC (Pmode, reg))) return 1; #endif #ifdef HAVE_POST_DECREMENT - if (memory_address_p (mode, gen_rtx (POST_DEC, Pmode, reg))) + if (memory_address_p (mode, gen_rtx_POST_DEC (Pmode, reg))) return 1; #endif #ifdef HAVE_PRE_INCREMENT - if (memory_address_p (mode, gen_rtx (PRE_INC, Pmode, reg))) + if (memory_address_p (mode, gen_rtx_PRE_INC (Pmode, reg))) return 1; #endif #ifdef HAVE_PRE_DECREMENT - if (memory_address_p (mode, gen_rtx (PRE_DEC, Pmode, reg))) + if (memory_address_p (mode, gen_rtx_PRE_DEC (Pmode, reg))) return 1; #endif @@ -1648,35 +1760,160 @@ auto_inc_dec_reg_p (reg, mode) #endif /* REGISTER_CONSTRAINTS */ -/* This is the `regscan' pass of the compiler, run just before cse - and again just before loop. +/* 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 non zero, 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 non zero, allocate the reg_renumber array also. */ - 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. +void +allocate_reg_info (num_regs, new_p, renumber_p) + size_t num_regs; + int new_p; + int renumber_p; +{ + static size_t regno_allocated = 0; + static short *renumber = (short *)0; + int i; + size_t size_info; + 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; + + /* Free up all storage allocated */ + if (num_regs < 0) + { + if (reg_n_info) + { + 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); + } - REPEAT is nonzero the second time this is called. */ + 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; + } + regno_allocated = 0; + reg_n_max = 0; + return; + } -/* Indexed by pseudo register number, gives uid of first insn using the reg - (as of the time reg_scan is called). */ + if (num_regs > regno_allocated) + { + size_t old_allocated = regno_allocated; -int *regno_first_uid; + regno_allocated = num_regs + (num_regs / 20); /* add some slop space */ + size_renumber = regno_allocated * sizeof (short); -/* Indexed by pseudo register number, gives uid of last insn using the reg - (as of the time reg_scan is called). */ + if (!reg_n_info) + { + 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); + } -int *regno_last_uid; + 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 *)prefclass_buffer); + free ((char *)altclass_buffer); + renumber = (short *) xmalloc (size_renumber); + prefclass_buffer = (char *) xmalloc (regno_allocated); + altclass_buffer = (char *) xmalloc (regno_allocated); + } + + else + { + renumber = (short *) xrealloc ((char *)renumber, size_renumber); + prefclass_buffer = (char *) xrealloc ((char *)prefclass_buffer, + regno_allocated); -/* Indexed by pseudo register number, gives uid of last insn using the reg - or mentioning it in a note (as of the time reg_scan is called). */ + altclass_buffer = (char *) xrealloc ((char *)altclass_buffer, + regno_allocated); + } + } -int *regno_last_note_uid; + size_info = (regno_allocated - old_allocated) * sizeof (reg_info) + + sizeof (struct reg_info_data) - sizeof (reg_info); + reg_data = (struct reg_info_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; + } -/* Record the number of registers we used when we allocated the above two - tables. If we are called again with more than this, we must re-allocate - the tables. */ + reg_n_max = num_regs; + if (min < num_regs) + { + /* 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) + { + size_t min_index = reg_data->min_index; + size_t max_index = reg_data->max_index; -static int highest_regno_in_uid_map; + reg_next = reg_data->next; + if (min <= max_index) + { + size_t max = max_index; + size_t local_min = min - min_index; + 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)); + + 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 {pref,alt}class have already been allocated, update the pointers to + the newly realloced ones. */ + if (prefclass) + { + prefclass = prefclass_buffer; + altclass = altclass_buffer; + } + + if (renumber_p) + reg_renumber = renumber; + + /* Tell the regset code about the new number of registers */ + MAX_REGNO_REG_SET (num_regs, new_p, renumber_p); +} + + +/* 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 @@ -1692,26 +1929,7 @@ reg_scan (f, nregs, repeat) { register rtx insn; - if (!repeat || nregs > highest_regno_in_uid_map) - { - /* Leave some spare space in case more regs are allocated. */ - highest_regno_in_uid_map = nregs + nregs / 20; - regno_first_uid - = (int *) oballoc (highest_regno_in_uid_map * sizeof (int)); - regno_last_uid - = (int *) oballoc (highest_regno_in_uid_map * sizeof (int)); - regno_last_note_uid - = (int *) oballoc (highest_regno_in_uid_map * sizeof (int)); - reg_n_sets - = (short *) oballoc (highest_regno_in_uid_map * sizeof (short)); - } - - bzero ((char *) regno_first_uid, highest_regno_in_uid_map * sizeof (int)); - bzero ((char *) regno_last_uid, highest_regno_in_uid_map * sizeof (int)); - bzero ((char *) regno_last_note_uid, - highest_regno_in_uid_map * sizeof (int)); - bzero ((char *) reg_n_sets, highest_regno_in_uid_map * sizeof (short)); - + allocate_reg_info (nregs, TRUE, FALSE); max_parallel = 3; for (insn = f; insn; insn = NEXT_INSN (insn)) @@ -1722,26 +1940,67 @@ reg_scan (f, nregs, repeat) if (GET_CODE (PATTERN (insn)) == PARALLEL && XVECLEN (PATTERN (insn), 0) > max_parallel) max_parallel = XVECLEN (PATTERN (insn), 0); - reg_scan_mark_refs (PATTERN (insn), insn, 0); + reg_scan_mark_refs (PATTERN (insn), insn, 0, 0); if (REG_NOTES (insn)) - reg_scan_mark_refs (REG_NOTES (insn), insn, 1); + reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0); + } +} + +/* Update 'regscan' information by looking at the insns + from FIRST to LAST. Some new REGs have been created, + and any REG with number greater than OLD_MAX_REGNO is + such a REG. We only update information for those. */ + +void +reg_scan_update(first, last, old_max_regno) + rtx first; + rtx last; + int old_max_regno; +{ + register rtx insn; + + allocate_reg_info (max_reg_num (), FALSE, FALSE); + + for (insn = first; insn != last; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN + || GET_CODE (insn) == CALL_INSN + || GET_CODE (insn) == JUMP_INSN) + { + if (GET_CODE (PATTERN (insn)) == PARALLEL + && XVECLEN (PATTERN (insn), 0) > max_parallel) + max_parallel = XVECLEN (PATTERN (insn), 0); + reg_scan_mark_refs (PATTERN (insn), insn, 0, old_max_regno); + + if (REG_NOTES (insn)) + reg_scan_mark_refs (REG_NOTES (insn), insn, 1, old_max_regno); } } /* 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. */ static void -reg_scan_mark_refs (x, insn, note_flag) +reg_scan_mark_refs (x, insn, note_flag, min_regno) rtx x; rtx insn; int note_flag; + int min_regno; { - register enum rtx_code code = GET_CODE (x); + register enum rtx_code code; register rtx dest; register rtx note; + /* This can happen when scanning insns referenced by certain notes. + + It is unclear if we should be scanning such insns; until someone can + say for sure this seems like the safest fix. */ + if (x == NULL_RTX) + return; + + code = GET_CODE (x); switch (code) { case CONST_INT: @@ -1759,24 +2018,27 @@ reg_scan_mark_refs (x, insn, note_flag) { register int regno = REGNO (x); - regno_last_note_uid[regno] = INSN_UID (insn); - if (!note_flag) - regno_last_uid[regno] = INSN_UID (insn); - if (regno_first_uid[regno] == 0) - regno_first_uid[regno] = INSN_UID (insn); + if (regno >= min_regno) + { + REGNO_LAST_NOTE_UID (regno) = INSN_UID (insn); + if (!note_flag) + REGNO_LAST_UID (regno) = INSN_UID (insn); + if (REGNO_FIRST_UID (regno) == 0) + REGNO_FIRST_UID (regno) = INSN_UID (insn); + } } break; 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, note_flag, min_regno); if (XEXP (x, 1)) - reg_scan_mark_refs (XEXP (x, 1), insn, note_flag); + reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno); 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, note_flag, min_regno); break; case SET: @@ -1787,8 +2049,9 @@ reg_scan_mark_refs (x, insn, note_flag) dest = XEXP (dest, 0)) ; - if (GET_CODE (dest) == REG) - reg_n_sets[REGNO (dest)]++; + if (GET_CODE (dest) == REG + && REGNO (dest) >= min_regno) + REG_N_SETS (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 @@ -1804,6 +2067,13 @@ reg_scan_mark_refs (x, insn, note_flag) if (GET_CODE (SET_DEST (x)) == REG && REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER + && REGNO (SET_DEST (x)) >= min_regno + /* If the destination pseudo is set more than once, then other + sets might not be to a pointer value (consider access to a + union in two threads of control in the presense of global + optimizations). So only set REGNO_POINTER_FLAG 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))) && ((GET_CODE (SET_SRC (x)) == REG @@ -1831,7 +2101,7 @@ reg_scan_mark_refs (x, insn, note_flag) || GET_CODE (XEXP (note, 0)) == LABEL_REF)))) REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1; - /* ... fall through ... */ + /* ... fall through ... */ default: { @@ -1840,12 +2110,12 @@ reg_scan_mark_refs (x, insn, 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, note_flag, min_regno); else if (fmt[i] == 'E' && XVEC (x, i) != 0) { register 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, note_flag, min_regno); } } } @@ -1898,3 +2168,17 @@ reg_classes_intersect_p (c1, c2) return 0; } +/* Release any memory allocated by register sets. */ + +void +regset_release_memory () +{ + if (basic_block_live_at_start) + { + free_regset_vector (basic_block_live_at_start, n_basic_blocks); + basic_block_live_at_start = 0; + } + + FREE_REG_SET (regs_live_at_setjmp); + bitmap_release_memory (); +} |