From 749a2da1bae8c0c91746d37b330626485566b308 Mon Sep 17 00:00:00 2001 From: Richard Kenner Date: Tue, 18 Apr 2000 18:14:10 +0000 Subject: [PATCH] c-decl.c (mark_binding_level): Use 'for' instead of `while'. * c-decl.c (mark_binding_level): Use 'for' instead of `while'. * conflict.c: Minor cleanups. * optabs.c: Add blank line * simplify-rtx.c: From-SVN: r33226 --- gcc/ChangeLog | 7 + gcc/c-decl.c | 4 +- gcc/conflict.c | 122 +++++++-------- gcc/optabs.c | 1 + gcc/simplify-rtx.c | 370 +++++++++++++++++++++++++-------------------- 5 files changed, 274 insertions(+), 230 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0f629e914b6..7c53d5b9fcb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +Tue Apr 18 14:16:47 2000 Richard Kenner + + * c-decl.c (mark_binding_level): Use 'for' instead of `while'. + * conflict.c: Minor cleanups. + * optabs.c: Add blank line + * simplify-rtx.c: + 2000-04-17 Zack Weinberg * cppexp.c (lex): Don't assume tokens are NUL terminated. diff --git a/gcc/c-decl.c b/gcc/c-decl.c index df1d707fa6c..4d175cb36de 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -2860,13 +2860,14 @@ lookup_name_current_level (name) } /* Mark ARG for GC. */ + static void mark_binding_level (arg) void *arg; { struct binding_level *level = *(struct binding_level **) arg; - while (level) + for (; level != 0; level = level->level_chain) { ggc_mark_tree (level->names); ggc_mark_tree (level->tags); @@ -2874,7 +2875,6 @@ mark_binding_level (arg) ggc_mark_tree (level->blocks); ggc_mark_tree (level->this_block); ggc_mark_tree (level->parm_order); - level = level->level_chain; } } diff --git a/gcc/conflict.c b/gcc/conflict.c index 667a18a672c..7ba50cc3c41 100644 --- a/gcc/conflict.c +++ b/gcc/conflict.c @@ -2,22 +2,22 @@ Copyright (C) 2000 Free Software Foundation, Inc. Contributed by CodeSourcery, LLC - This file is part of GNU CC. +This file is part of GNU CC. - 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. +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. - 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. +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. - 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. */ +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. */ /* References: @@ -27,7 +27,6 @@ #include "config.h" #include "system.h" - #include "obstack.h" #include "hashtab.h" #include "rtl.h" @@ -108,23 +107,18 @@ struct conflict_graph_def /* The initial capacity (number of conflict arcs) for newly-created conflict graphs. */ -#define INITIAL_ARC_CAPACITY (64) +#define INITIAL_ARC_CAPACITY 64 /* Computes the hash value of the conflict graph arc connecting regs - R1__ and R2__. R1__ is assumed to be smaller or equal to R2__. */ -#define CONFLICT_HASH_FN(r1__, r2__) ((r2__) * ((r2__) - 1) / 2 + (r1__)) - -static unsigned arc_hash - PARAMS ((const void *arcp)); -static int arc_eq - PARAMS ((const void *arcp1, const void *arcp2)); -static int print_conflict - PARAMS ((int reg1, int reg2, void *contextp)); -static void mark_reg - PARAMS ((rtx reg, rtx setter, void *data)); - - + R1 and R2. R1 is assumed to be smaller or equal to R2. */ +#define CONFLICT_HASH_FN(R1, R2) ((R2) * ((R2) - 1) / 2 + (R1)) + +static unsigned arc_hash PARAMS ((const void *)); +static int arc_eq PARAMS ((const void *, const void *)); +static int print_conflict PARAMS ((int, int, void *)); +static void mark_reg PARAMS ((rtx, rtx, void *)); + /* Callback function to compute the hash value of an arc. Uses current_graph to locate the graph to which the arc belongs. */ @@ -133,6 +127,7 @@ arc_hash (arcp) const void *arcp; { conflict_graph_arc arc = (conflict_graph_arc) arcp; + return CONFLICT_HASH_FN (arc->smaller, arc->larger); } @@ -146,6 +141,7 @@ arc_eq (arcp1, arcp2) { conflict_graph_arc arc1 = (conflict_graph_arc) arcp1; conflict_graph_arc arc2 = (conflict_graph_arc) arcp2; + return arc1->smaller == arc2->smaller && arc1->larger == arc2->larger; } @@ -156,24 +152,23 @@ conflict_graph conflict_graph_new (num_regs) int num_regs; { - conflict_graph graph = - (conflict_graph) xmalloc (sizeof (struct conflict_graph_def)); + conflict_graph graph + = (conflict_graph) xmalloc (sizeof (struct conflict_graph_def)); graph->num_regs = num_regs; /* Set up the hash table. No delete action is specified; memory management of arcs is through the obstack. */ - graph->arc_hash_table = - htab_create (INITIAL_ARC_CAPACITY, &arc_hash, &arc_eq, NULL); + graph->arc_hash_table + = htab_create (INITIAL_ARC_CAPACITY, &arc_hash, &arc_eq, NULL); /* Create an obstack for allocating arcs. */ - obstack_init (&(graph->arc_obstack)); + obstack_init (&graph->arc_obstack); /* Create and zero the lookup table by register number. */ - graph->neighbor_heads = (conflict_graph_arc *) - xmalloc (num_regs * sizeof (conflict_graph_arc)); - memset (graph->neighbor_heads, 0, - num_regs * sizeof (conflict_graph_arc)); + graph->neighbor_heads + = (conflict_graph_arc *) xmalloc (num_regs * sizeof (conflict_graph_arc)); + memset (graph->neighbor_heads, 0, num_regs * sizeof (conflict_graph_arc)); return graph; } @@ -183,7 +178,7 @@ void conflict_graph_delete (graph) conflict_graph graph; { - obstack_free (&(graph->arc_obstack), NULL); + obstack_free (&graph->arc_obstack, NULL); htab_delete (graph->arc_hash_table); free (graph->neighbor_heads); free (graph); @@ -218,10 +213,11 @@ conflict_graph_add (graph, reg1, reg2) return 0; /* Allocate an arc. */ - arc = (conflict_graph_arc) - obstack_alloc (&(graph->arc_obstack), - sizeof (struct conflict_graph_arc_def)); - + arc + = (conflict_graph_arc) + obstack_alloc (&graph->arc_obstack, + sizeof (struct conflict_graph_arc_def)); + /* Record the reg numbers. */ arc->smaller = smaller; arc->larger = larger; @@ -299,6 +295,7 @@ conflict_graph_merge_regs (graph, target, src) while (arc != NULL) { int other = arc->smaller; + if (other == src) other = arc->larger; @@ -372,19 +369,22 @@ conflict_graph_print (graph, fp) { int reg; struct print_context context; - context.fp = fp; + context.fp = fp; fprintf (fp, "Conflicts:\n"); + /* Loop over registers supported in this graph. */ for (reg = 0; reg < graph->num_regs; ++reg) { context.reg = reg; context.started = 0; + /* Scan the conflicts for reg, printing as we go. A label for this line will be printed the first time a conflict is printed for the reg; we won't start a new line if this reg has no conflicts. */ conflict_graph_enum (graph, reg, &print_conflict, &context); + /* If this reg does have conflicts, end the line. */ if (context.started) fputc ('\n', fp); @@ -469,9 +469,7 @@ conflict_graph_compute (regs, p) /* Walk the instruction stream backwards. */ head = bb->head; insn = bb->end; - for (insn = bb->end; - insn != head; - insn = PREV_INSN (insn)) + for (insn = bb->end; insn != head; insn = PREV_INSN (insn)) { int born_reg; int live_reg; @@ -497,20 +495,21 @@ conflict_graph_compute (regs, p) /* For every reg born here, add a conflict with every other reg live coming into this insn. */ - EXECUTE_IF_SET_IN_REG_SET (born, - FIRST_PSEUDO_REGISTER, - born_reg, { - EXECUTE_IF_SET_IN_REG_SET (live, - FIRST_PSEUDO_REGISTER, - live_reg, { - /* Build the conflict graph in terms of canonical - regnos. */ - int b = partition_find (p, born_reg); - int l = partition_find (p, live_reg); - if (b != l) - conflict_graph_add (graph, b, l); - }); - }); + EXECUTE_IF_SET_IN_REG_SET + (born, FIRST_PSEUDO_REGISTER, born_reg, + { + EXECUTE_IF_SET_IN_REG_SET + (live, FIRST_PSEUDO_REGISTER, live_reg, + { + /* Build the conflict graph in terms of canonical + regnos. */ + int b = partition_find (p, born_reg); + int l = partition_find (p, live_reg); + + if (b != l) + conflict_graph_add (graph, b, l); + }); + }); /* Morgan's algorithm checks the operands of the insn and adds them to the set of live regs. Instead, we @@ -519,7 +518,8 @@ conflict_graph_compute (regs, p) for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) if (REG_NOTE_KIND (link) == REG_DEAD) { - int regno = REGNO (XEXP (link, 0)); + unsigned int regno = REGNO (XEXP (link, 0)); + if (REGNO_REG_SET_P (regs, regno)) SET_REGNO_REG_SET (live, regno); } diff --git a/gcc/optabs.c b/gcc/optabs.c index 5f2a76ad9b9..304eb7400d2 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -3098,6 +3098,7 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align, to be used for operand OPNUM of the insn, is converted from mode MODE to WIDER_MODE (UNSIGNEDP determines whether it is a unsigned conversion), and that it is accepted by the operand predicate. Return the new value. */ + rtx prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp) int icode; diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 9e2674304ba..ffe7b240d1c 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -1,4 +1,4 @@ -/* Common subexpression elimination for GNU compiler. +/* RTL simplification functions for GNU compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. @@ -21,7 +21,6 @@ Boston, MA 02111-1307, USA. */ #include "config.h" -/* stdio.h must precede rtl.h for FFS. */ #include "system.h" #include @@ -94,10 +93,94 @@ Boston, MA 02111-1307, USA. */ || GET_CODE (X) == ADDRESSOF) -static rtx simplify_plus_minus PARAMS ((enum rtx_code, enum machine_mode, - rtx, rtx)); -static void check_fold_consts PARAMS ((PTR)); +static rtx simplify_plus_minus PARAMS ((enum rtx_code, + enum machine_mode, rtx, rtx)); +static void check_fold_consts PARAMS ((PTR)); +static int entry_and_rtx_equal_p PARAMS ((const void *, const void *)); +static unsigned int get_value_hash PARAMS ((const void *)); +static struct elt_list *new_elt_list PARAMS ((struct elt_list *, + cselib_val *)); +static struct elt_loc_list *new_elt_loc_list PARAMS ((struct elt_loc_list *, + rtx)); +static void unchain_one_value PARAMS ((cselib_val *)); +static void unchain_one_elt_list PARAMS ((struct elt_list **)); +static void unchain_one_elt_loc_list PARAMS ((struct elt_loc_list **)); +static void clear_table PARAMS ((void)); +static int check_value_useless PARAMS ((cselib_val *)); +static int discard_useless_locs PARAMS ((void **, void *)); +static int discard_useless_values PARAMS ((void **, void *)); +static void remove_useless_values PARAMS ((void)); +static unsigned int hash_rtx PARAMS ((rtx, enum machine_mode, int)); +static cselib_val *new_cselib_val PARAMS ((unsigned int, + enum machine_mode)); +static void add_mem_for_addr PARAMS ((cselib_val *, cselib_val *, + rtx)); +static cselib_val *cselib_lookup_mem PARAMS ((rtx, int)); +static rtx cselib_subst_to_values PARAMS ((rtx)); +static void cselib_invalidate_regno PARAMS ((unsigned int, + enum machine_mode)); +static int cselib_mem_conflict_p PARAMS ((rtx, rtx)); +static int cselib_invalidate_mem_1 PARAMS ((void **, void *)); +static void cselib_invalidate_mem PARAMS ((rtx)); +static void cselib_invalidate_rtx PARAMS ((rtx, rtx, void *)); +static void cselib_record_set PARAMS ((rtx, cselib_val *, + cselib_val *)); +static void cselib_record_sets PARAMS ((rtx)); + +/* There are three ways in which cselib can look up an rtx: + - for a REG, the reg_values table (which is indexed by regno) is used + - for a MEM, we recursively look up its address and then follow the + addr_list of that value + - for everything else, we compute a hash value and go through the hash + table. Since different rtx's can still have the same hash value, + this involves walking the table entries for a given value and comparing + the locations of the entries with the rtx we are looking up. */ + +/* A table that enables us to look up elts by their value. */ +static htab_t hash_table; + +/* This is a global so we don't have to pass this through every function. + It is used in new_elt_loc_list to set SETTING_INSN. */ +static rtx cselib_current_insn; + +/* Every new unknown value gets a unique number. */ +static unsigned int next_unknown_value; +/* The number of registers we had when the varrays were last resized. */ +static unsigned int cselib_nregs; + +/* Count values without known locations. Whenever this grows too big, we + remove these useless values from the table. */ +static int n_useless_values; + +/* Number of useless values before we remove them from the hash table. */ +#define MAX_USELESS_VALUES 32 + +/* This table maps from register number to values. It does not contain + pointers to cselib_val structures, but rather elt_lists. The purpose is + to be able to refer to the same register in different modes. */ +static varray_type reg_values; +#define REG_VALUES(I) VARRAY_ELT_LIST (reg_values, (I)) + +/* We pass this to cselib_invalidate_mem to invalidate all of + memory for a non-const call instruction. */ +static rtx callmem; + +/* Memory for our structures is allocated from this obstack. */ +static struct obstack cselib_obstack; + +/* Used to quickly free all memory. */ +static char *cselib_startobj; + +/* Caches for unused structures. */ +static cselib_val *empty_vals; +static struct elt_list *empty_elt_lists; +static struct elt_loc_list *empty_elt_loc_lists; + +/* Set by discard_useless_locs if it deleted the last location of any + value. */ +static int values_became_useless; + /* Make a binary operation by properly ordering the operands and seeing if the expression folds. */ @@ -1809,7 +1892,7 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2) enum machine_mode mode, op0_mode; rtx op0, op1, op2; { - int width = GET_MODE_BITSIZE (mode); + unsigned int width = GET_MODE_BITSIZE (mode); /* VOIDmode means "infinite" precision. */ if (width == 0) @@ -1872,9 +1955,10 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2) return op2; else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0)) { - rtx temp; - temp = simplify_relational_operation (GET_CODE (op0), op0_mode, - XEXP (op0, 0), XEXP (op0, 1)); + rtx temp + = simplify_relational_operation (GET_CODE (op0), op0_mode, + XEXP (op0, 0), XEXP (op0, 1)); + /* See if any simplifications were possible. */ if (temp == const0_rtx) return op2; @@ -1962,93 +2046,17 @@ simplify_rtx (x) } } -static int entry_and_rtx_equal_p PARAMS ((const void *, const void *)); -static unsigned int get_value_hash PARAMS ((const void *)); -static struct elt_list *new_elt_list PARAMS ((struct elt_list *, cselib_val *)); -static struct elt_loc_list *new_elt_loc_list PARAMS ((struct elt_loc_list *, rtx)); -static void unchain_one_value PARAMS ((cselib_val *)); -static void unchain_one_elt_list PARAMS ((struct elt_list **)); -static void unchain_one_elt_loc_list PARAMS ((struct elt_loc_list **)); -static void clear_table PARAMS ((void)); -static int check_value_useless PARAMS ((cselib_val *)); -static int discard_useless_locs PARAMS ((void **, void *)); -static int discard_useless_values PARAMS ((void **, void *)); -static void remove_useless_values PARAMS ((void)); -static unsigned int hash_rtx PARAMS ((rtx, enum machine_mode, int)); -static cselib_val *new_cselib_val PARAMS ((unsigned int, - enum machine_mode)); -static void add_mem_for_addr PARAMS ((cselib_val *, cselib_val *, - rtx)); -static cselib_val *cselib_lookup_mem PARAMS ((rtx, int)); -static rtx cselib_subst_to_values PARAMS ((rtx)); -static void cselib_invalidate_regno PARAMS ((unsigned int, - enum machine_mode)); -static int cselib_mem_conflict_p PARAMS ((rtx, rtx)); -static int cselib_invalidate_mem_1 PARAMS ((void **, void *)); -static void cselib_invalidate_mem PARAMS ((rtx)); -static void cselib_invalidate_rtx PARAMS ((rtx, rtx, void *)); -static void cselib_record_set PARAMS ((rtx, cselib_val *, - cselib_val *)); -static void cselib_record_sets PARAMS ((rtx)); - -/* There are three ways in which cselib can look up an rtx: - - for a REG, the reg_values table (which is indexed by regno) is used - - for a MEM, we recursively look up its address and then follow the - addr_list of that value - - for everything else, we compute a hash value and go through the hash - table. Since different rtx's can still have the same hash value, - this involves walking the table entries for a given value and comparing - the locations of the entries with the rtx we are looking up. */ - -/* A table that enables us to look up elts by their value. */ -static htab_t hash_table; - -/* This is a global so we don't have to pass this through every function. - It is used in new_elt_loc_list to set SETTING_INSN. */ -static rtx cselib_current_insn; - -/* Every new unknown value gets a unique number. */ -static unsigned int next_unknown_value; - -/* The number of registers we had when the varrays were last resized. */ -static int cselib_nregs; - -/* Count values without known locations. Whenever this grows too big, we - remove these useless values from the table. */ -static int n_useless_values; - -/* Number of useless values before we remove them from the hash table. */ -#define MAX_USELESS_VALUES 32 - -/* This table maps from register number to values. It does not contain - pointers to cselib_val structures, but rather elt_lists. The purpose is - to be able to refer to the same register in different modes. */ -static varray_type reg_values; -#define REG_VALUES(I) VARRAY_ELT_LIST (reg_values, (I)) - -/* We pass this to cselib_invalidate_mem to invalidate all of - memory for a non-const call instruction. */ -static rtx callmem; - -/* Memory for our structures is allocated from this obstack. */ -static struct obstack cselib_obstack; - -/* Used to quickly free all memory. */ -static char *cselib_startobj; - -/* Caches for unused structures. */ -static cselib_val *empty_vals; -static struct elt_list *empty_elt_lists; -static struct elt_loc_list *empty_elt_loc_lists; /* Allocate a struct elt_list and fill in its two elements with the arguments. */ + static struct elt_list * new_elt_list (next, elt) struct elt_list *next; cselib_val *elt; { struct elt_list *el = empty_elt_lists; + if (el) empty_elt_lists = el->next; else @@ -2061,12 +2069,14 @@ new_elt_list (next, elt) /* Allocate a struct elt_loc_list and fill in its two elements with the arguments. */ + static struct elt_loc_list * new_elt_loc_list (next, loc) struct elt_loc_list *next; rtx loc; { struct elt_loc_list *el = empty_elt_loc_lists; + if (el) empty_elt_loc_lists = el->next; else @@ -2080,22 +2090,26 @@ new_elt_loc_list (next, loc) /* The elt_list at *PL is no longer needed. Unchain it and free its storage. */ + static void unchain_one_elt_list (pl) struct elt_list **pl; { struct elt_list *l = *pl; + *pl = l->next; l->next = empty_elt_lists; empty_elt_lists = l; } /* Likewise for elt_loc_lists. */ + static void unchain_one_elt_loc_list (pl) struct elt_loc_list **pl; { struct elt_loc_list *l = *pl; + *pl = l->next; l->next = empty_elt_loc_lists; empty_elt_loc_lists = l; @@ -2103,6 +2117,7 @@ unchain_one_elt_loc_list (pl) /* Likewise for cselib_vals. This also frees the addr_list associated with V. */ + static void unchain_one_value (v) cselib_val *v; @@ -2116,10 +2131,12 @@ unchain_one_value (v) /* Remove all entries from the hash table. Also used during initialization. */ + static void clear_table () { - int i; + unsigned int i; + for (i = 0; i < cselib_nregs; i++) REG_VALUES (i) = 0; @@ -2136,25 +2153,28 @@ clear_table () /* The equality test for our hash table. The first argument ENTRY is a table element (i.e. a cselib_val), while the second arg X is an rtx. */ + static int entry_and_rtx_equal_p (entry, x_arg) const void *entry, *x_arg; { struct elt_loc_list *l; - const cselib_val *v = (const cselib_val *)entry; - rtx x = (rtx)x_arg; + const cselib_val *v = (const cselib_val *) entry; + rtx x = (rtx) x_arg; /* We don't guarantee that distinct rtx's have different hash values, so we need to do a comparison. */ for (l = v->locs; l; l = l->next) if (rtx_equal_for_cselib_p (l->loc, x)) return 1; + return 0; } /* The hash function for our hash table. The value is always computed with hash_rtx when adding an element; this function just extracts the hash value from a cselib_val structure. */ + static unsigned int get_value_hash (entry) const void *entry; @@ -2166,6 +2186,7 @@ get_value_hash (entry) /* If there are no more locations that hold a value, the value has become useless. See whether that is the case for V. Return 1 if this has just become useless. */ + static int check_value_useless (v) cselib_val *v; @@ -2186,6 +2207,7 @@ check_value_useless (v) only return true for values which point to a cselib_val whose value element has been set to zero, which implies the cselib_val will be removed. */ + int references_value_p (x, only_useless) rtx x; @@ -2193,7 +2215,7 @@ references_value_p (x, only_useless) { enum rtx_code code = GET_CODE (x); const char *fmt = GET_RTX_FORMAT (code); - int i; + int i, j; if (GET_CODE (x) == VALUE && (! only_useless || CSELIB_VAL_PTR (x)->value == 0)) @@ -2201,31 +2223,21 @@ references_value_p (x, only_useless) for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { - if (fmt[i] == 'e') - { - if (references_value_p (XEXP (x, i), only_useless)) - return 1; - } + if (fmt[i] == 'e' && references_value_p (XEXP (x, i), only_useless)) + return 1; else if (fmt[i] == 'E') - { - int j; - - for (j = 0; j < XVECLEN (x, i); j++) - if (references_value_p (XVECEXP (x, i, j), only_useless)) - return 1; - } + for (j = 0; j < XVECLEN (x, i); j++) + if (references_value_p (XVECEXP (x, i, j), only_useless)) + return 1; } return 0; } -/* Set by discard_useless_locs if it deleted the last location of any - value. */ -static int values_became_useless; - /* For all locations found in X, delete locations that reference useless values (i.e. values without any location). Called through htab_traverse. */ + static int discard_useless_locs (x, info) void **x; @@ -2241,6 +2253,7 @@ discard_useless_locs (x, info) else p = &(*p)->next; } + if (check_value_useless (v)) values_became_useless = 1; @@ -2262,11 +2275,13 @@ discard_useless_values (x, info) unchain_one_value (v); n_useless_values--; } + return 1; } /* Clean out useless values (i.e. those which no longer have locations associated with them) from the hash table. */ + static void remove_useless_values () { @@ -2288,6 +2303,7 @@ remove_useless_values () /* Return nonzero if we can prove that X and Y contain the same value, taking our gathered information into account. */ + int rtx_equal_for_cselib_p (x, y) rtx x, y; @@ -2299,12 +2315,15 @@ rtx_equal_for_cselib_p (x, y) if (GET_CODE (x) == REG || GET_CODE (x) == MEM) { cselib_val *e = cselib_lookup (x, VOIDmode, 0); + if (e) x = e->u.val_rtx; } + if (GET_CODE (y) == REG || GET_CODE (y) == MEM) { cselib_val *e = cselib_lookup (y, VOIDmode, 0); + if (e) y = e->u.val_rtx; } @@ -2327,8 +2346,7 @@ rtx_equal_for_cselib_p (x, y) /* Avoid infinite recursion. */ if (GET_CODE (t) == REG || GET_CODE (t) == MEM) continue; - - if (rtx_equal_for_cselib_p (t, y)) + else if (rtx_equal_for_cselib_p (t, y)) return 1; } @@ -2346,16 +2364,14 @@ rtx_equal_for_cselib_p (x, y) if (GET_CODE (t) == REG || GET_CODE (t) == MEM) continue; - - if (rtx_equal_for_cselib_p (x, t)) + else if (rtx_equal_for_cselib_p (x, t)) return 1; } return 0; } - if (GET_CODE (x) != GET_CODE (y) - || GET_MODE (x) != GET_MODE (y)) + if (GET_CODE (x) != GET_CODE (y) || GET_MODE (x) != GET_MODE (y)) return 0; /* This won't be handled correctly by the code below. */ @@ -2368,6 +2384,7 @@ rtx_equal_for_cselib_p (x, y) for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { int j; + switch (fmt[i]) { case 'w': @@ -2431,6 +2448,7 @@ rtx_equal_for_cselib_p (x, y) CREATE is nonzero, table elts are created for regs and mem. MODE is used in hashing for CONST_INTs only; otherwise the mode of X is used. */ + static unsigned int hash_rtx (x, mode, create) rtx x; @@ -2455,15 +2473,13 @@ hash_rtx (x, mode, create) e = cselib_lookup (x, GET_MODE (x), create); if (! e) return 0; + hash += e->value; return hash; case CONST_INT: - { - unsigned HOST_WIDE_INT tem = INTVAL (x); - hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + tem; - return hash ? hash : CONST_INT; - } + hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + INTVAL (x); + return hash ? hash : CONST_INT; case CONST_DOUBLE: /* This is like the general case, except that it only counts @@ -2471,10 +2487,7 @@ hash_rtx (x, mode, create) hash += (unsigned) code + (unsigned) GET_MODE (x); if (GET_MODE (x) != VOIDmode) for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++) - { - unsigned HOST_WIDE_INT tem = XWINT (x, i); - hash += tem; - } + hash += XWINT (x, i); else hash += ((unsigned) CONST_DOUBLE_LOW (x) + (unsigned) CONST_DOUBLE_HIGH (x)); @@ -2517,8 +2530,8 @@ hash_rtx (x, mode, create) { if (fmt[i] == 'e') { - unsigned int tem_hash; rtx tem = XEXP (x, i); + unsigned int tem_hash; /* If we are about to do the last recursive call needed at this level, change it into iteration. @@ -2528,57 +2541,63 @@ hash_rtx (x, mode, create) x = tem; goto repeat; } + tem_hash = hash_rtx (tem, 0, create); if (tem_hash == 0) return 0; + hash += tem_hash; } else if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x, i); j++) { unsigned int tem_hash = hash_rtx (XVECEXP (x, i, j), 0, create); + if (tem_hash == 0) return 0; + hash += tem_hash; } else if (fmt[i] == 's') { const unsigned char *p = (const unsigned char *) XSTR (x, i); + if (p) while (*p) hash += *p++; } else if (fmt[i] == 'i') - { - unsigned int tem = XINT (x, i); - hash += tem; - } + hash += XINT (x, i); else if (fmt[i] == '0' || fmt[i] == 't') /* unused */; else abort (); } + return hash ? hash : 1 + GET_CODE (x); } /* Create a new value structure for VALUE and initialize it. The mode of the value is MODE. */ + static cselib_val * new_cselib_val (value, mode) unsigned int value; enum machine_mode mode; { cselib_val *e = empty_vals; + if (e) empty_vals = e->u.next_free; else e = (cselib_val *) obstack_alloc (&cselib_obstack, sizeof (cselib_val)); + if (value == 0) abort (); + e->value = value; e->u.val_rtx = gen_rtx_VALUE (mode); CSELIB_VAL_PTR (e->u.val_rtx) = e; - e->addr_list = 0; e->locs = 0; return e; @@ -2587,6 +2606,7 @@ new_cselib_val (value, mode) /* ADDR_ELT is a value that is used as address. MEM_ELT is the value that contains the data at this address. X is a MEM that represents the value. Update the two value structures to represent this situation. */ + static void add_mem_for_addr (addr_elt, mem_elt, x) cselib_val *addr_elt, *mem_elt; @@ -2612,6 +2632,7 @@ add_mem_for_addr (addr_elt, mem_elt, x) /* Subroutine of cselib_lookup. Return a value for X, which is a MEM rtx. If CREATE, make a new one if we haven't seen it before. */ + static cselib_val * cselib_lookup_mem (x, create) rtx x; @@ -2622,9 +2643,8 @@ cselib_lookup_mem (x, create) cselib_val *mem_elt; struct elt_list *l; - if (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode) - return 0; - if (FLOAT_MODE_P (GET_MODE (x)) && flag_float_store) + if (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode + || (FLOAT_MODE_P (GET_MODE (x)) && flag_float_store)) return 0; /* Look up the value for the address. */ @@ -2636,8 +2656,10 @@ cselib_lookup_mem (x, create) for (l = addr->addr_list; l; l = l->next) if (GET_MODE (l->elt->u.val_rtx) == GET_MODE (x)) return l->elt; + if (! create) return 0; + mem_elt = new_cselib_val (++next_unknown_value, GET_MODE (x)); add_mem_for_addr (addr, mem_elt, x); slot = htab_find_slot_with_hash (hash_table, x, mem_elt->value, 1); @@ -2650,6 +2672,7 @@ cselib_lookup_mem (x, create) to registers and memory. X isn't actually modified; if modifications are needed, new rtl is allocated. However, the return value can share rtl with X. */ + static rtx cselib_subst_to_values (x) rtx x; @@ -2664,10 +2687,10 @@ cselib_subst_to_values (x) switch (code) { case REG: - i = REGNO (x); - for (l = REG_VALUES (i); l; l = l->next) + for (l = REG_VALUES (REGNO (x)); l; l = l->next) if (GET_MODE (l->elt->u.val_rtx) == GET_MODE (x)) return l->elt->u.val_rtx; + abort (); case MEM: @@ -2691,8 +2714,10 @@ cselib_subst_to_values (x) if (fmt[i] == 'e') { rtx t = cselib_subst_to_values (XEXP (x, i)); + if (t != XEXP (x, i) && x == copy) copy = shallow_copy_rtx (x); + XEXP (copy, i) = t; } else if (fmt[i] == 'E') @@ -2702,18 +2727,22 @@ cselib_subst_to_values (x) for (j = 0; j < XVECLEN (x, i); j++) { rtx t = cselib_subst_to_values (XVECEXP (x, i, j)); + if (t != XVECEXP (x, i, j) && XVEC (x, i) == XVEC (copy, i)) { if (x == copy) copy = shallow_copy_rtx (x); + XVEC (copy, i) = rtvec_alloc (XVECLEN (x, i)); for (k = 0; k < j; k++) XVECEXP (copy, i, k) = XVECEXP (x, i, k); } + XVECEXP (copy, i, j) = t; } } } + return copy; } @@ -2721,6 +2750,7 @@ cselib_subst_to_values (x) If CREATE is zero, we return NULL if we don't know the value. Otherwise, we create a new one if possible, using mode MODE if X doesn't have a mode (i.e. because it's a constant). */ + cselib_val * cselib_lookup (x, mode, create) rtx x; @@ -2740,12 +2770,15 @@ cselib_lookup (x, mode, create) if (GET_CODE (x) == REG) { struct elt_list *l; - int i = REGNO (x); + unsigned int i = REGNO (x); + for (l = REG_VALUES (i); l; l = l->next) if (mode == GET_MODE (l->elt->u.val_rtx)) return l->elt; + if (! create) return 0; + e = new_cselib_val (++next_unknown_value, GET_MODE (x)); e->locs = new_elt_loc_list (e->locs, x); REG_VALUES (i) = new_elt_list (REG_VALUES (i), e); @@ -2765,11 +2798,13 @@ cselib_lookup (x, mode, create) slot = htab_find_slot_with_hash (hash_table, x, hashval, create); if (slot == 0) return 0; + e = (cselib_val *) *slot; if (e) return e; e = new_cselib_val (hashval, mode); + /* We have to fill the slot before calling cselib_subst_to_values: the hash table is inconsistent until we do so, and cselib_subst_to_values will need to do lookups. */ @@ -2841,6 +2876,7 @@ cselib_invalidate_regno (regno, mode) break; } } + check_value_useless (v); } } @@ -2848,6 +2884,7 @@ cselib_invalidate_regno (regno, mode) /* The memory at address MEM_BASE is being changed. Return whether this change will invalidate VAL. */ + static int cselib_mem_conflict_p (mem_base, val) rtx mem_base; @@ -2855,7 +2892,7 @@ cselib_mem_conflict_p (mem_base, val) { enum rtx_code code; const char *fmt; - int i; + int i, j; code = GET_CODE (val); switch (code) @@ -2874,10 +2911,10 @@ cselib_mem_conflict_p (mem_base, val) case MEM: if (GET_MODE (mem_base) == BLKmode - || GET_MODE (val) == BLKmode) - return 1; - if (anti_dependence (val, mem_base)) + || GET_MODE (val) == BLKmode + || anti_dependence (val, mem_base)) return 1; + /* The address may contain nested MEMs. */ break; @@ -2886,7 +2923,6 @@ cselib_mem_conflict_p (mem_base, val) } fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') @@ -2895,13 +2931,9 @@ cselib_mem_conflict_p (mem_base, val) return 1; } else if (fmt[i] == 'E') - { - int j; - - for (j = 0; j < XVECLEN (val, i); j++) - if (cselib_mem_conflict_p (mem_base, XVECEXP (val, i, j))) - return 1; - } + for (j = 0; j < XVECLEN (val, i); j++) + if (cselib_mem_conflict_p (mem_base, XVECEXP (val, i, j))) + return 1; } return 0; @@ -2909,6 +2941,7 @@ cselib_mem_conflict_p (mem_base, val) /* For the value found in SLOT, walk its locations to determine if any overlap INFO (which is a MEM rtx). */ + static int cselib_invalidate_mem_1 (slot, info) void **slot; @@ -2920,9 +2953,9 @@ cselib_invalidate_mem_1 (slot, info) while (*p) { + rtx x = (*p)->loc; cselib_val *addr; struct elt_list **mem_chain; - rtx x = (*p)->loc; /* MEMs may occur in locations only at the top level; below that every MEM or REG is substituted by its VALUE. */ @@ -2945,10 +2978,13 @@ cselib_invalidate_mem_1 (slot, info) unchain_one_elt_list (mem_chain); break; } + mem_chain = &(*mem_chain)->next; } + unchain_one_elt_loc_list (p); } + check_value_useless (v); return 1; } @@ -2956,6 +2992,7 @@ cselib_invalidate_mem_1 (slot, info) /* Invalidate any locations in the table which are changed because of a store to MEM_RTX. If this is called because of a non-const call instruction, MEM_RTX is (mem:BLK const0_rtx). */ + static void cselib_invalidate_mem (mem_rtx) rtx mem_rtx; @@ -2966,16 +3003,15 @@ cselib_invalidate_mem (mem_rtx) /* Invalidate DEST, which is being assigned to or clobbered. The second and the third parameter exist so that this function can be passed to note_stores; they are ignored. */ + static void cselib_invalidate_rtx (dest, ignore, data) rtx dest; rtx ignore ATTRIBUTE_UNUSED; void *data ATTRIBUTE_UNUSED; { - while (GET_CODE (dest) == STRICT_LOW_PART - || GET_CODE (dest) == SIGN_EXTRACT - || GET_CODE (dest) == ZERO_EXTRACT - || GET_CODE (dest) == SUBREG) + while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SIGN_EXTRACT + || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG) dest = XEXP (dest, 0); if (GET_CODE (dest) == REG) @@ -3086,11 +3122,13 @@ cselib_record_sets (insn) } /* Record the effects of INSN. */ + void cselib_process_insn (insn) rtx insn; { int i; + rtx x; cselib_current_insn = insn; @@ -3111,6 +3149,7 @@ cselib_process_insn (insn) cselib_current_insn = 0; return; } + /* If this is a call instruction, forget anything stored in a call clobbered register, or, if this is not a const call, in memory. */ @@ -3130,26 +3169,17 @@ cselib_process_insn (insn) /* Clobber any registers which appear in REG_INC notes. We could keep track of the changes to their values, but it is unlikely to help. */ - { - rtx x; - - for (x = REG_NOTES (insn); x; x = XEXP (x, 1)) - if (REG_NOTE_KIND (x) == REG_INC) - cselib_invalidate_rtx (XEXP (x, 0), NULL_RTX, NULL); - } + for (x = REG_NOTES (insn); x; x = XEXP (x, 1)) + if (REG_NOTE_KIND (x) == REG_INC) + cselib_invalidate_rtx (XEXP (x, 0), NULL_RTX, NULL); #endif /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only after we have processed the insn. */ if (GET_CODE (insn) == CALL_INSN) - { - rtx x; - - for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1)) - if (GET_CODE (XEXP (x, 0)) == CLOBBER) - cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX, - NULL); - } + for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1)) + if (GET_CODE (XEXP (x, 0)) == CLOBBER) + cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX, NULL); cselib_current_insn = 0; @@ -3159,18 +3189,22 @@ cselib_process_insn (insn) /* Make sure our varrays are big enough. Not called from any cselib routines; it must be called by the user if it allocated new registers. */ + void cselib_update_varray_sizes () { - int nregs = max_reg_num (); + unsigned int nregs = max_reg_num (); + if (nregs == cselib_nregs) return; + cselib_nregs = nregs; VARRAY_GROW (reg_values, nregs); } /* Initialize cselib for one pass. The caller must also call init_alias_analysis. */ + void cselib_init () { @@ -3178,6 +3212,7 @@ cselib_init () if (! callmem) { extern struct obstack permanent_obstack; + gcc_obstack_init (&cselib_obstack); cselib_startobj = obstack_alloc (&cselib_obstack, 0); @@ -3194,6 +3229,7 @@ cselib_init () } /* Called when the current user is done with cselib. */ + void cselib_finish () { -- 2.30.2