X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcselib.c;h=f46c5ecb29b23295225c979ebabc275fd40512e0;hb=e93bcd03af477f080698c0ef08ad3f048e984dba;hp=aa5f7b022bc005c76d5e3d6b328feed5976e294e;hpb=bf4652ac2b3d27b528c7cf95a205f2be548c52c1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cselib.c b/gcc/cselib.c index aa5f7b022bc..f46c5ecb29b 100644 --- a/gcc/cselib.c +++ b/gcc/cselib.c @@ -1,6 +1,6 @@ /* Common subexpression elimination library for GNU compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" static bool cselib_record_memory; +static bool cselib_preserve_constants; static int entry_and_rtx_equal_p (const void *, const void *); static hashval_t get_value_hash (const void *); static struct elt_list *new_elt_list (struct elt_list *, cselib_val *); @@ -69,6 +70,7 @@ struct expand_value_data bitmap regs_active; cselib_expand_callback callback; void *callback_arg; + bool dummy; }; static rtx cselib_expand_value_rtx_1 (rtx, struct expand_value_data *, int); @@ -89,15 +91,53 @@ static htab_t cselib_hash_table; 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 unique id that the next create value will take. */ +static unsigned int next_uid; /* 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. */ +/* Count values without known locations, or with only locations that + wouldn't have been known except for debug insns. Whenever this + grows too big, we remove these useless values from the table. + + Counting values with only debug values is a bit tricky. We don't + want to increment n_useless_values when we create a value for a + debug insn, for this would get n_useless_values out of sync, but we + want increment it if all locs in the list that were ever referenced + in nondebug insns are removed from the list. + + In the general case, once we do that, we'd have to stop accepting + nondebug expressions in the loc list, to avoid having two values + equivalent that, without debug insns, would have been made into + separate values. However, because debug insns never introduce + equivalences themselves (no assignments), the only means for + growing loc lists is through nondebug assignments. If the locs + also happen to be referenced in debug insns, it will work just fine. + + A consequence of this is that there's at most one debug-only loc in + each loc list. If we keep it in the first entry, testing whether + we have a debug-only loc list takes O(1). + + Furthermore, since any additional entry in a loc list containing a + debug loc would have to come from an assignment (nondebug) that + references both the initial debug loc and the newly-equivalent loc, + the initial debug loc would be promoted to a nondebug loc, and the + loc list would not contain debug locs any more. + + So the only case we have to be careful with in order to keep + n_useless_values in sync between debug and nondebug compilations is + to avoid incrementing n_useless_values when removing the single loc + from a value that turns out to not appear outside debug values. We + increment n_useless_debug_values instead, and leave such values + alone until, for other reasons, we garbage-collect useless + values. */ static int n_useless_values; +static int n_useless_debug_values; + +/* Count values whose locs have been taken exclusively from debug + insns for the entire life of the value. */ +static int n_debug_values; /* Number of useless values before we remove them from the hash table. */ #define MAX_USELESS_VALUES 32 @@ -134,6 +174,11 @@ static int values_became_useless; presence in the list by checking the next pointer. */ static cselib_val dummy_val; +/* If non-NULL, value of the eliminated arg_pointer_rtx or frame_pointer_rtx + that is constant through the whole function and should never be + eliminated. */ +static cselib_val *cfa_base_preserved_val; + /* Used to list all values that contain memory reference. May or may not contain the useless values - the list is compacted each time memory is invalidated. */ @@ -154,8 +199,6 @@ void (*cselib_record_sets_hook) (rtx insn, struct cselib_set *sets, #define PRESERVED_VALUE_P(RTX) \ (RTL_FLAG_CHECK1("PRESERVED_VALUE_P", (RTX), VALUE)->unchanging) -#define LONG_TERM_PRESERVED_VALUE_P(RTX) \ - (RTL_FLAG_CHECK1("LONG_TERM_PRESERVED_VALUE_P", (RTX), VALUE)->in_struct) @@ -183,9 +226,33 @@ new_elt_loc_list (struct elt_loc_list *next, rtx loc) el->next = next; el->loc = loc; el->setting_insn = cselib_current_insn; + gcc_assert (!next || !next->setting_insn + || !DEBUG_INSN_P (next->setting_insn)); + + /* If we're creating the first loc in a debug insn context, we've + just created a debug value. Count it. */ + if (!next && cselib_current_insn && DEBUG_INSN_P (cselib_current_insn)) + n_debug_values++; + return el; } +/* Promote loc L to a nondebug cselib_current_insn if L is marked as + originating from a debug insn, maintaining the debug values + count. */ + +static inline void +promote_debug_loc (struct elt_loc_list *l) +{ + if (l->setting_insn && DEBUG_INSN_P (l->setting_insn) + && (!cselib_current_insn || !DEBUG_INSN_P (cselib_current_insn))) + { + n_debug_values--; + l->setting_insn = cselib_current_insn; + gcc_assert (!l->next); + } +} + /* The elt_list at *PL is no longer needed. Unchain it and free its storage. */ @@ -227,30 +294,83 @@ unchain_one_value (cselib_val *v) void cselib_clear_table (void) { - cselib_reset_table_with_next_value (0); + cselib_reset_table (1); +} + +/* Remove from hash table all VALUEs except constants. */ + +static int +preserve_only_constants (void **x, void *info ATTRIBUTE_UNUSED) +{ + cselib_val *v = (cselib_val *)*x; + + if (v->locs != NULL + && v->locs->next == NULL) + { + if (CONSTANT_P (v->locs->loc) + && (GET_CODE (v->locs->loc) != CONST + || !references_value_p (v->locs->loc, 0))) + return 1; + if (cfa_base_preserved_val) + { + if (v == cfa_base_preserved_val) + return 1; + if (GET_CODE (v->locs->loc) == PLUS + && CONST_INT_P (XEXP (v->locs->loc, 1)) + && XEXP (v->locs->loc, 0) == cfa_base_preserved_val->val_rtx) + return 1; + } + } + + htab_clear_slot (cselib_hash_table, x); + return 1; } /* Remove all entries from the hash table, arranging for the next value to be numbered NUM. */ void -cselib_reset_table_with_next_value (unsigned int num) +cselib_reset_table (unsigned int num) { unsigned int i; - for (i = 0; i < n_used_regs; i++) - REG_VALUES (used_regs[i]) = 0; - max_value_regs = 0; - n_used_regs = 0; + if (cfa_base_preserved_val) + { + unsigned int regno = REGNO (cfa_base_preserved_val->locs->loc); + unsigned int new_used_regs = 0; + for (i = 0; i < n_used_regs; i++) + if (used_regs[i] == regno) + { + new_used_regs = 1; + continue; + } + else + REG_VALUES (used_regs[i]) = 0; + gcc_assert (new_used_regs == 1); + n_used_regs = new_used_regs; + used_regs[0] = regno; + max_value_regs + = hard_regno_nregs[regno][GET_MODE (cfa_base_preserved_val->locs->loc)]; + } + else + { + for (i = 0; i < n_used_regs; i++) + REG_VALUES (used_regs[i]) = 0; + n_used_regs = 0; + } - /* ??? Preserve constants? */ - htab_empty (cselib_hash_table); + if (cselib_preserve_constants) + htab_traverse (cselib_hash_table, preserve_only_constants, NULL); + else + htab_empty (cselib_hash_table); n_useless_values = 0; + n_useless_debug_values = 0; + n_debug_values = 0; - next_unknown_value = num; + next_uid = num; first_containing_mem = &dummy_val; } @@ -258,9 +378,9 @@ cselib_reset_table_with_next_value (unsigned int num) /* Return the number of the next value that will be generated. */ unsigned int -cselib_get_next_unknown_value (void) +cselib_get_next_uid (void) { - return next_unknown_value; + return next_uid; } /* The equality test for our hash table. The first argument ENTRY is a table @@ -278,7 +398,7 @@ entry_and_rtx_equal_p (const void *entry, const void *x_arg) gcc_assert (!CONST_INT_P (x) && GET_CODE (x) != CONST_FIXED && (mode != VOIDmode || GET_CODE (x) != CONST_DOUBLE)); - + if (mode != GET_MODE (v->val_rtx)) return 0; @@ -293,7 +413,10 @@ entry_and_rtx_equal_p (const void *entry, const void *x_arg) 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; + { + promote_debug_loc (l); + return 1; + } return 0; } @@ -306,7 +429,7 @@ static hashval_t get_value_hash (const void *entry) { const cselib_val *const v = (const cselib_val *) entry; - return v->value; + return v->hash; } /* Return true if X contains a VALUE rtx. If ONLY_USELESS is set, we @@ -347,7 +470,8 @@ discard_useless_locs (void **x, void *info ATTRIBUTE_UNUSED) { cselib_val *v = (cselib_val *)*x; struct elt_loc_list **p = &v->locs; - int had_locs = v->locs != 0; + bool had_locs = v->locs != NULL; + rtx setting_insn = v->locs ? v->locs->setting_insn : NULL; while (*p) { @@ -359,7 +483,10 @@ discard_useless_locs (void **x, void *info ATTRIBUTE_UNUSED) if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx)) { - n_useless_values++; + if (setting_insn && DEBUG_INSN_P (setting_insn)) + n_useless_debug_values++; + else + n_useless_values++; values_became_useless = 1; } return 1; @@ -393,6 +520,7 @@ static void remove_useless_values (void) { cselib_val **p, *v; + /* First pass: eliminate locations that reference the value. That in turn can make more values useless. */ do @@ -413,6 +541,10 @@ remove_useless_values (void) } *p = &dummy_val; + n_useless_values += n_useless_debug_values; + n_debug_values -= n_useless_debug_values; + n_useless_debug_values = 0; + htab_traverse (cselib_hash_table, discard_useless_values, 0); gcc_assert (!n_useless_values); @@ -435,51 +567,26 @@ cselib_preserved_value_p (cselib_val *v) return PRESERVED_VALUE_P (v->val_rtx); } -/* Mark preserved values as preserved for the long term. */ - -static int -cselib_preserve_definitely (void **slot, void *info ATTRIBUTE_UNUSED) -{ - cselib_val *v = (cselib_val *)*slot; - - if (PRESERVED_VALUE_P (v->val_rtx) - && !LONG_TERM_PRESERVED_VALUE_P (v->val_rtx)) - LONG_TERM_PRESERVED_VALUE_P (v->val_rtx) = true; - - return 1; -} - -/* Clear the preserve marks for values not preserved for the long - term. */ +/* Arrange for a REG value to be assumed constant through the whole function, + never invalidated and preserved across cselib_reset_table calls. */ -static int -cselib_clear_preserve (void **slot, void *info ATTRIBUTE_UNUSED) +void +cselib_preserve_cfa_base_value (cselib_val *v) { - cselib_val *v = (cselib_val *)*slot; - - if (PRESERVED_VALUE_P (v->val_rtx) - && !LONG_TERM_PRESERVED_VALUE_P (v->val_rtx)) - { - PRESERVED_VALUE_P (v->val_rtx) = false; - if (!v->locs) - n_useless_values++; - } - - return 1; + if (cselib_preserve_constants + && v->locs + && REG_P (v->locs->loc)) + cfa_base_preserved_val = v; } /* Clean all non-constant expressions in the hash table, but retain their values. */ void -cselib_preserve_only_values (bool retain) +cselib_preserve_only_values (void) { int i; - htab_traverse (cselib_hash_table, - retain ? cselib_preserve_definitely : cselib_clear_preserve, - NULL); - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) cselib_invalidate_regno (i, reg_raw_mode[i]); @@ -715,7 +822,7 @@ cselib_hash_rtx (rtx x, int create) if (! e) return 0; - return e->value; + return e->hash; case DEBUG_EXPR: hash += ((unsigned) DEBUG_EXPR << 7) @@ -815,10 +922,10 @@ cselib_hash_rtx (rtx x, int create) { rtx tem = XEXP (x, i); unsigned int tem_hash = cselib_hash_rtx (tem, create); - + if (tem_hash == 0) return 0; - + hash += tem_hash; } break; @@ -827,10 +934,10 @@ cselib_hash_rtx (rtx x, int create) { unsigned int tem_hash = cselib_hash_rtx (XVECEXP (x, i, j), create); - + if (tem_hash == 0) return 0; - + hash += tem_hash; } break; @@ -838,13 +945,13 @@ cselib_hash_rtx (rtx x, int create) case 's': { const unsigned char *p = (const unsigned char *) XSTR (x, i); - + if (p) while (*p) hash += *p++; break; } - + case 'i': hash += XINT (x, i); break; @@ -853,7 +960,7 @@ cselib_hash_rtx (rtx x, int create) case 't': /* unused */ break; - + default: gcc_unreachable (); } @@ -866,13 +973,15 @@ cselib_hash_rtx (rtx x, int create) value is MODE. */ static inline cselib_val * -new_cselib_val (unsigned int value, enum machine_mode mode, rtx x) +new_cselib_val (unsigned int hash, enum machine_mode mode, rtx x) { cselib_val *e = (cselib_val *) pool_alloc (cselib_val_pool); - gcc_assert (value); + gcc_assert (hash); + gcc_assert (next_uid); - e->value = value; + e->hash = hash; + e->uid = next_uid++; /* We use an alloc pool to allocate this RTL construct because it accounts for about 8% of the overall memory usage. We know precisely when we can have VALUE RTXen (when cselib is active) @@ -889,7 +998,7 @@ new_cselib_val (unsigned int value, enum machine_mode mode, rtx x) if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "cselib value %u ", value); + fprintf (dump_file, "cselib value %u:%u ", e->uid, hash); if (flag_dump_noaddr || flag_dump_unnumbered) fputs ("# ", dump_file); else @@ -914,7 +1023,10 @@ add_mem_for_addr (cselib_val *addr_elt, cselib_val *mem_elt, rtx x) for (l = mem_elt->locs; l; l = l->next) if (MEM_P (l->loc) && CSELIB_VAL_PTR (XEXP (l->loc, 0)) == addr_elt) - return; + { + promote_debug_loc (l); + return; + } addr_elt->addr_list = new_elt_list (addr_elt->addr_list, mem_elt); mem_elt->locs @@ -952,15 +1064,18 @@ cselib_lookup_mem (rtx x, int create) /* Find a value that describes a value of our mode at that address. */ for (l = addr->addr_list; l; l = l->next) if (GET_MODE (l->elt->val_rtx) == mode) - return l->elt; + { + promote_debug_loc (l->elt->locs); + return l->elt; + } if (! create) return 0; - mem_elt = new_cselib_val (++next_unknown_value, mode, x); + mem_elt = new_cselib_val (next_uid, mode, x); add_mem_for_addr (addr, mem_elt, x); slot = htab_find_slot_with_hash (cselib_hash_table, wrap_constant (mode, x), - mem_elt->value, INSERT); + mem_elt->hash, INSERT); *slot = mem_elt; return mem_elt; } @@ -971,7 +1086,7 @@ cselib_lookup_mem (rtx x, int create) non-reg results, we just take the first one because they will all expand to the same place. */ -static rtx +static rtx expand_loc (struct elt_loc_list *p, struct expand_value_data *evd, int max_depth) { @@ -983,8 +1098,8 @@ expand_loc (struct elt_loc_list *p, struct expand_value_data *evd, { /* Avoid infinite recursion trying to expand a reg into a the same reg. */ - if ((REG_P (p->loc)) - && (REGNO (p->loc) < regno) + if ((REG_P (p->loc)) + && (REGNO (p->loc) < regno) && !bitmap_bit_p (evd->regs_active, REGNO (p->loc))) { reg_result = p->loc; @@ -992,7 +1107,7 @@ expand_loc (struct elt_loc_list *p, struct expand_value_data *evd, } /* Avoid infinite recursion and do not try to expand the value. */ - else if (GET_CODE (p->loc) == VALUE + else if (GET_CODE (p->loc) == VALUE && CSELIB_VAL_PTR (p->loc)->locs == p_in) continue; else if (!REG_P (p->loc)) @@ -1013,9 +1128,9 @@ expand_loc (struct elt_loc_list *p, struct expand_value_data *evd, if (result) return result; } - + } - + if (regno != UINT_MAX) { rtx result; @@ -1034,7 +1149,7 @@ expand_loc (struct elt_loc_list *p, struct expand_value_data *evd, print_inline_rtx (dump_file, reg_result, 0); fprintf (dump_file, "\n"); } - else + else fprintf (dump_file, "NULL\n"); } return reg_result; @@ -1045,7 +1160,7 @@ expand_loc (struct elt_loc_list *p, struct expand_value_data *evd, This is the opposite of common subexpression. Because local value numbering is such a weak optimization, the expanded expression is pretty much unique (not from a pointer equals point of view but - from a tree shape point of view. + from a tree shape point of view. This function returns NULL if the expansion fails. The expansion will fail if there is no value number for one of the operands or if @@ -1067,6 +1182,7 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth) evd.regs_active = regs_active; evd.callback = NULL; evd.callback_arg = NULL; + evd.dummy = false; return cselib_expand_value_rtx_1 (orig, &evd, max_depth); } @@ -1086,10 +1202,29 @@ cselib_expand_value_rtx_cb (rtx orig, bitmap regs_active, int max_depth, evd.regs_active = regs_active; evd.callback = cb; evd.callback_arg = data; + evd.dummy = false; return cselib_expand_value_rtx_1 (orig, &evd, max_depth); } +/* Similar to cselib_expand_value_rtx_cb, but no rtxs are actually copied + or simplified. Useful to find out whether cselib_expand_value_rtx_cb + would return NULL or non-NULL, without allocating new rtx. */ + +bool +cselib_dummy_expand_value_rtx_cb (rtx orig, bitmap regs_active, int max_depth, + cselib_expand_callback cb, void *data) +{ + struct expand_value_data evd; + + evd.regs_active = regs_active; + evd.callback = cb; + evd.callback_arg = data; + evd.dummy = true; + + return cselib_expand_value_rtx_1 (orig, &evd, max_depth) != NULL; +} + /* Internal implementation of cselib_expand_value_rtx and cselib_expand_value_rtx_cb. */ @@ -1124,7 +1259,7 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd, { rtx result; int regno = REGNO (orig); - + /* The only thing that we are not willing to do (this is requirement of dse and if others potential uses need this function we should add a parm to control @@ -1156,11 +1291,11 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd, if (result) return result; - else + else return orig; } } - + case CONST_INT: case CONST_DOUBLE: case CONST_VECTOR: @@ -1247,7 +1382,10 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd, that all fields need copying, and then clear the fields that should not be copied. That is the sensible default behavior, and forces us to explicitly document why we are *not* copying a flag. */ - copy = shallow_copy_rtx (orig); + if (evd->dummy) + copy = NULL; + else + copy = shallow_copy_rtx (orig); format_ptr = GET_RTX_FORMAT (code); @@ -1261,7 +1399,8 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd, max_depth - 1); if (!result) return NULL; - XEXP (copy, i) = result; + if (copy) + XEXP (copy, i) = result; } break; @@ -1269,14 +1408,16 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd, case 'V': if (XVEC (orig, i) != NULL) { - XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); - for (j = 0; j < XVECLEN (copy, i); j++) + if (copy) + XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i)); + for (j = 0; j < XVECLEN (orig, i); j++) { rtx result = cselib_expand_value_rtx_1 (XVECEXP (orig, i, j), evd, max_depth - 1); if (!result) return NULL; - XVECEXP (copy, i, j) = result; + if (copy) + XVECEXP (copy, i, j) = result; } } break; @@ -1297,6 +1438,9 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd, gcc_unreachable (); } + if (evd->dummy) + return orig; + mode = GET_MODE (copy); /* If an operand has been simplified into CONST_INT, which doesn't have a mode and the mode isn't derivable from whole rtx's mode, @@ -1393,7 +1537,7 @@ cselib_subst_to_values (rtx x) { /* This happens for autoincrements. Assign a value that doesn't match any other. */ - e = new_cselib_val (++next_unknown_value, GET_MODE (x), x); + e = new_cselib_val (next_uid, GET_MODE (x), x); } return e->val_rtx; @@ -1409,7 +1553,7 @@ cselib_subst_to_values (rtx x) case PRE_DEC: case POST_MODIFY: case PRE_MODIFY: - e = new_cselib_val (++next_unknown_value, GET_MODE (x), x); + e = new_cselib_val (next_uid, GET_MODE (x), x); return e->val_rtx; default: @@ -1422,30 +1566,31 @@ cselib_subst_to_values (rtx x) { 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; + if (t != XEXP (x, i)) + { + if (x == copy) + copy = shallow_copy_rtx (x); + XEXP (copy, i) = t; + } } else if (fmt[i] == 'E') { - int j, k; + int j; 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 (t != XVECEXP (x, i, j)) { - 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); + if (XVEC (x, i) == XVEC (copy, i)) + { + if (x == copy) + copy = shallow_copy_rtx (x); + XVEC (copy, i) = shallow_copy_rtvec (XVEC (x, i)); + } + XVECEXP (copy, i, j) = t; } - - XVECEXP (copy, i, j) = t; } } } @@ -1453,28 +1598,13 @@ cselib_subst_to_values (rtx x) return copy; } -/* Log a lookup of X to the cselib table along with the result RET. */ - -static cselib_val * -cselib_log_lookup (rtx x, cselib_val *ret) -{ - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fputs ("cselib lookup ", dump_file); - print_inline_rtx (dump_file, x, 2); - fprintf (dump_file, " => %u\n", ret ? ret->value : 0); - } - - return ret; -} - /* Look up the rtl expression X in our tables and return the value it has. 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 (rtx x, enum machine_mode mode, int create) +static cselib_val * +cselib_lookup_1 (rtx x, enum machine_mode mode, int create) { void **slot; cselib_val *e; @@ -1496,10 +1626,13 @@ cselib_lookup (rtx x, enum machine_mode mode, int create) l = l->next; for (; l; l = l->next) if (mode == GET_MODE (l->elt->val_rtx)) - return cselib_log_lookup (x, l->elt); + { + promote_debug_loc (l->elt->locs); + return l->elt; + } if (! create) - return cselib_log_lookup (x, 0); + return 0; if (i < FIRST_PSEUDO_REGISTER) { @@ -1509,7 +1642,7 @@ cselib_lookup (rtx x, enum machine_mode mode, int create) max_value_regs = n; } - e = new_cselib_val (++next_unknown_value, GET_MODE (x), x); + e = new_cselib_val (next_uid, GET_MODE (x), x); e->locs = new_elt_loc_list (e->locs, x); if (REG_VALUES (i) == 0) { @@ -1520,27 +1653,27 @@ cselib_lookup (rtx x, enum machine_mode mode, int create) REG_VALUES (i) = new_elt_list (REG_VALUES (i), NULL); } REG_VALUES (i)->next = new_elt_list (REG_VALUES (i)->next, e); - slot = htab_find_slot_with_hash (cselib_hash_table, x, e->value, INSERT); + slot = htab_find_slot_with_hash (cselib_hash_table, x, e->hash, INSERT); *slot = e; - return cselib_log_lookup (x, e); + return e; } if (MEM_P (x)) - return cselib_log_lookup (x, cselib_lookup_mem (x, create)); + return cselib_lookup_mem (x, create); hashval = cselib_hash_rtx (x, create); /* Can't even create if hashing is not possible. */ if (! hashval) - return cselib_log_lookup (x, 0); + return 0; slot = htab_find_slot_with_hash (cselib_hash_table, wrap_constant (mode, x), hashval, create ? INSERT : NO_INSERT); if (slot == 0) - return cselib_log_lookup (x, 0); + return 0; e = (cselib_val *) *slot; if (e) - return cselib_log_lookup (x, e); + return e; e = new_cselib_val (hashval, mode, x); @@ -1549,7 +1682,51 @@ cselib_lookup (rtx x, enum machine_mode mode, int create) cselib_subst_to_values will need to do lookups. */ *slot = (void *) e; e->locs = new_elt_loc_list (e->locs, cselib_subst_to_values (x)); - return cselib_log_lookup (x, e); + return e; +} + +/* Wrapper for cselib_lookup, that indicates X is in INSN. */ + +cselib_val * +cselib_lookup_from_insn (rtx x, enum machine_mode mode, + int create, rtx insn) +{ + cselib_val *ret; + + gcc_assert (!cselib_current_insn); + cselib_current_insn = insn; + + ret = cselib_lookup (x, mode, create); + + cselib_current_insn = NULL; + + return ret; +} + +/* Wrapper for cselib_lookup_1, that logs the lookup result and + maintains invariants related with debug insns. */ + +cselib_val * +cselib_lookup (rtx x, enum machine_mode mode, int create) +{ + cselib_val *ret = cselib_lookup_1 (x, mode, create); + + /* ??? Should we return NULL if we're not to create an entry, the + found loc is a debug loc and cselib_current_insn is not DEBUG? + If so, we should also avoid converting val to non-DEBUG; probably + easiest setting cselib_current_insn to NULL before the call + above. */ + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fputs ("cselib lookup ", dump_file); + print_inline_rtx (dump_file, x, 2); + fprintf (dump_file, " => %u:%u\n", + ret ? ret->uid : 0, + ret ? ret->hash : 0); + } + + return ret; } /* Invalidate any entries in reg_values that overlap REGNO. This is called @@ -1598,13 +1775,15 @@ cselib_invalidate_regno (unsigned int regno, enum machine_mode mode) while (*l) { cselib_val *v = (*l)->elt; + bool had_locs; + rtx setting_insn; struct elt_loc_list **p; unsigned int this_last = i; if (i < FIRST_PSEUDO_REGISTER && v != NULL) this_last = end_hard_regno (GET_MODE (v->val_rtx), i) - 1; - if (this_last < regno || v == NULL) + if (this_last < regno || v == NULL || v == cfa_base_preserved_val) { l = &(*l)->next; continue; @@ -1624,6 +1803,9 @@ cselib_invalidate_regno (unsigned int regno, enum machine_mode mode) else unchain_one_elt_list (l); + had_locs = v->locs != NULL; + setting_insn = v->locs ? v->locs->setting_insn : NULL; + /* Now, we clear the mapping from value to reg. It must exist, so this code will crash intentionally if it doesn't. */ for (p = &v->locs; ; p = &(*p)->next) @@ -1636,8 +1818,14 @@ cselib_invalidate_regno (unsigned int regno, enum machine_mode mode) break; } } - if (v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx)) - n_useless_values++; + + if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx)) + { + if (setting_insn && DEBUG_INSN_P (setting_insn)) + n_useless_debug_values++; + else + n_useless_values++; + } } } } @@ -1675,7 +1863,8 @@ cselib_invalidate_mem (rtx mem_rtx) { bool has_mem = false; struct elt_loc_list **p = &v->locs; - int had_locs = v->locs != 0; + bool had_locs = v->locs != NULL; + rtx setting_insn = v->locs ? v->locs->setting_insn : NULL; while (*p) { @@ -1720,7 +1909,12 @@ cselib_invalidate_mem (rtx mem_rtx) } if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx)) - n_useless_values++; + { + if (setting_insn && DEBUG_INSN_P (setting_insn)) + n_useless_debug_values++; + else + n_useless_values++; + } next = v->next_containing_mem; if (has_mem) @@ -1889,7 +2083,13 @@ cselib_record_sets (rtx insn) src = gen_rtx_IF_THEN_ELSE (GET_MODE (dest), cond, src, dest); sets[i].src_elt = cselib_lookup (src, GET_MODE (dest), 1); if (MEM_P (dest)) - sets[i].dest_addr_elt = cselib_lookup (XEXP (dest, 0), Pmode, 1); + { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest)); + + sets[i].dest_addr_elt = cselib_lookup (XEXP (dest, 0), + address_mode, 1); + } else sets[i].dest_addr_elt = 0; } @@ -1954,13 +2154,14 @@ cselib_process_insn (rtx insn) && GET_CODE (PATTERN (insn)) == ASM_OPERANDS && MEM_VOLATILE_P (PATTERN (insn)))) { - cselib_reset_table_with_next_value (next_unknown_value); + cselib_reset_table (next_uid); + cselib_current_insn = NULL_RTX; return; } if (! INSN_P (insn)) { - cselib_current_insn = 0; + cselib_current_insn = NULL_RTX; return; } @@ -1972,7 +2173,7 @@ cselib_process_insn (rtx insn) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (call_used_regs[i] || (REG_VALUES (i) && REG_VALUES (i)->elt - && HARD_REGNO_CALL_PART_CLOBBERED (i, + && HARD_REGNO_CALL_PART_CLOBBERED (i, GET_MODE (REG_VALUES (i)->elt->val_rtx)))) cselib_invalidate_regno (i, reg_raw_mode[i]); @@ -2002,13 +2203,16 @@ cselib_process_insn (rtx insn) if (GET_CODE (XEXP (x, 0)) == CLOBBER) cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0)); - cselib_current_insn = 0; + cselib_current_insn = NULL_RTX; if (n_useless_values > MAX_USELESS_VALUES /* remove_useless_values is linear in the hash table size. Avoid quadratic behavior for very large hashtables with very few useless elements. */ - && (unsigned int)n_useless_values > cselib_hash_table->n_elements / 4) + && ((unsigned int)n_useless_values + > (cselib_hash_table->n_elements + - cselib_hash_table->n_deleted + - n_debug_values) / 4)) remove_useless_values (); } @@ -2016,16 +2220,17 @@ cselib_process_insn (rtx insn) init_alias_analysis. */ void -cselib_init (bool record_memory) +cselib_init (int record_what) { - elt_list_pool = create_alloc_pool ("elt_list", + elt_list_pool = create_alloc_pool ("elt_list", sizeof (struct elt_list), 10); - elt_loc_list_pool = create_alloc_pool ("elt_loc_list", + elt_loc_list_pool = create_alloc_pool ("elt_loc_list", sizeof (struct elt_loc_list), 10); - cselib_val_pool = create_alloc_pool ("cselib_val_list", + cselib_val_pool = create_alloc_pool ("cselib_val_list", sizeof (cselib_val), 10); value_pool = create_alloc_pool ("value", RTX_CODE_SIZE (VALUE), 100); - cselib_record_memory = record_memory; + cselib_record_memory = record_what & CSELIB_RECORD_MEMORY; + cselib_preserve_constants = record_what & CSELIB_PRESERVE_CONSTANTS; /* (mem:BLK (scratch)) is a special mechanism to conflict with everything, see canon_true_dependence. This is only created once. */ @@ -2050,6 +2255,7 @@ cselib_init (bool record_memory) n_used_regs = 0; cselib_hash_table = htab_create (31, get_value_hash, entry_and_rtx_equal_p, NULL); + next_uid = 1; } /* Called when the current user is done with cselib. */ @@ -2058,6 +2264,8 @@ void cselib_finish (void) { cselib_discard_hook = NULL; + cselib_preserve_constants = false; + cfa_base_preserved_val = NULL; free_alloc_pool (elt_list_pool); free_alloc_pool (elt_loc_list_pool); free_alloc_pool (cselib_val_pool); @@ -2068,7 +2276,9 @@ cselib_finish (void) used_regs = 0; cselib_hash_table = 0; n_useless_values = 0; - next_unknown_value = 0; + n_useless_debug_values = 0; + n_debug_values = 0; + next_uid = 0; } /* Dump the cselib_val *X to FILE *info. */ @@ -2156,7 +2366,7 @@ dump_cselib_table (FILE *out) print_inline_rtx (out, first_containing_mem->val_rtx, 2); fputc ('\n', out); } - fprintf (out, "last unknown value %i\n", next_unknown_value); + fprintf (out, "next uid %i\n", next_uid); } #include "gt-cselib.h"