summaryrefslogtreecommitdiff
path: root/gcc/cselib.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cselib.c')
-rw-r--r--gcc/cselib.c407
1 files changed, 336 insertions, 71 deletions
diff --git a/gcc/cselib.c b/gcc/cselib.c
index 456f1359b6f..8d52c519ff3 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "output.h"
#include "ggc.h"
#include "hashtab.h"
+#include "tree-pass.h"
#include "cselib.h"
#include "params.h"
#include "alloc-pool.h"
@@ -54,9 +55,8 @@ static void unchain_one_elt_loc_list (struct elt_loc_list **);
static int discard_useless_locs (void **, void *);
static int discard_useless_values (void **, void *);
static void remove_useless_values (void);
-static rtx wrap_constant (enum machine_mode, rtx);
static unsigned int cselib_hash_rtx (rtx, int);
-static cselib_val *new_cselib_val (unsigned int, enum machine_mode);
+static cselib_val *new_cselib_val (unsigned int, enum machine_mode, rtx);
static void add_mem_for_addr (cselib_val *, cselib_val *, rtx);
static cselib_val *cselib_lookup_mem (rtx, int);
static void cselib_invalidate_regno (unsigned int, enum machine_mode);
@@ -64,6 +64,15 @@ static void cselib_invalidate_mem (rtx);
static void cselib_record_set (rtx, cselib_val *, cselib_val *);
static void cselib_record_sets (rtx);
+struct expand_value_data
+{
+ bitmap regs_active;
+ cselib_expand_callback callback;
+ void *callback_arg;
+};
+
+static rtx cselib_expand_value_rtx_1 (rtx, struct expand_value_data *, int);
+
/* 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
@@ -134,6 +143,20 @@ static alloc_pool elt_loc_list_pool, elt_list_pool, cselib_val_pool, value_pool;
/* If nonnull, cselib will call this function before freeing useless
VALUEs. A VALUE is deemed useless if its "locs" field is null. */
void (*cselib_discard_hook) (cselib_val *);
+
+/* If nonnull, cselib will call this function before recording sets or
+ even clobbering outputs of INSN. All the recorded sets will be
+ represented in the array sets[n_sets]. new_val_min can be used to
+ tell whether values present in sets are introduced by this
+ instruction. */
+void (*cselib_record_sets_hook) (rtx insn, struct cselib_set *sets,
+ int n_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)
+
/* Allocate a struct elt_list and fill in its two elements with the
@@ -199,12 +222,20 @@ unchain_one_value (cselib_val *v)
}
/* Remove all entries from the hash table. Also used during
- initialization. If CLEAR_ALL isn't set, then only clear the entries
- which are known to have been used. */
+ initialization. */
void
cselib_clear_table (void)
{
+ cselib_reset_table_with_next_value (0);
+}
+
+/* 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)
+{
unsigned int i;
for (i = 0; i < n_used_regs; i++)
@@ -214,15 +245,24 @@ cselib_clear_table (void)
n_used_regs = 0;
+ /* ??? Preserve constants? */
htab_empty (cselib_hash_table);
n_useless_values = 0;
- next_unknown_value = 0;
+ next_unknown_value = num;
first_containing_mem = &dummy_val;
}
+/* Return the number of the next value that will be generated. */
+
+unsigned int
+cselib_get_next_unknown_value (void)
+{
+ return next_unknown_value;
+}
+
/* 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. We know
that all callers of htab_find_slot_with_hash will wrap CONST_INTs into a
@@ -317,7 +357,7 @@ discard_useless_locs (void **x, void *info ATTRIBUTE_UNUSED)
p = &(*p)->next;
}
- if (had_locs && v->locs == 0)
+ if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
{
n_useless_values++;
values_became_useless = 1;
@@ -332,7 +372,7 @@ discard_useless_values (void **x, void *info ATTRIBUTE_UNUSED)
{
cselib_val *v = (cselib_val *)*x;
- if (v->locs == 0)
+ if (v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
{
if (cselib_discard_hook)
cselib_discard_hook (v);
@@ -378,6 +418,78 @@ remove_useless_values (void)
gcc_assert (!n_useless_values);
}
+/* Arrange for a value to not be removed from the hash table even if
+ it becomes useless. */
+
+void
+cselib_preserve_value (cselib_val *v)
+{
+ PRESERVED_VALUE_P (v->val_rtx) = 1;
+}
+
+/* Test whether a value is preserved. */
+
+bool
+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. */
+
+static int
+cselib_clear_preserve (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))
+ {
+ PRESERVED_VALUE_P (v->val_rtx) = false;
+ if (!v->locs)
+ n_useless_values++;
+ }
+
+ return 1;
+}
+
+/* Clean all non-constant expressions in the hash table, but retain
+ their values. */
+
+void
+cselib_preserve_only_values (bool retain)
+{
+ 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]);
+
+ cselib_invalidate_mem (callmem);
+
+ remove_useless_values ();
+
+ gcc_assert (first_containing_mem == &dummy_val);
+}
+
/* Return the mode in which a register was last set. If X is not a
register, return its mode. If the mode in which the register was
set is not known, or the value was already clobbered, return
@@ -549,19 +661,6 @@ rtx_equal_for_cselib_p (rtx x, rtx y)
return 1;
}
-/* We need to pass down the mode of constants through the hash table
- functions. For that purpose, wrap them in a CONST of the appropriate
- mode. */
-static rtx
-wrap_constant (enum machine_mode mode, rtx x)
-{
- if (!CONST_INT_P (x) && GET_CODE (x) != CONST_FIXED
- && (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != VOIDmode))
- return x;
- gcc_assert (mode != VOIDmode);
- return gen_rtx_CONST (mode, x);
-}
-
/* Hash an rtx. Return 0 if we couldn't hash the rtx.
For registers and memory locations, we look up their cselib_val structure
and return its VALUE element.
@@ -748,7 +847,7 @@ cselib_hash_rtx (rtx x, int create)
value is MODE. */
static inline cselib_val *
-new_cselib_val (unsigned int value, enum machine_mode mode)
+new_cselib_val (unsigned int value, enum machine_mode mode, rtx x)
{
cselib_val *e = (cselib_val *) pool_alloc (cselib_val_pool);
@@ -768,6 +867,18 @@ new_cselib_val (unsigned int value, enum machine_mode mode)
e->addr_list = 0;
e->locs = 0;
e->next_containing_mem = 0;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "cselib value %u ", value);
+ if (flag_dump_noaddr || flag_dump_unnumbered)
+ fputs ("# ", dump_file);
+ else
+ fprintf (dump_file, "%p ", (void*)e);
+ print_rtl_single (dump_file, x);
+ fputc ('\n', dump_file);
+ }
+
return e;
}
@@ -827,7 +938,7 @@ cselib_lookup_mem (rtx x, int create)
if (! create)
return 0;
- mem_elt = new_cselib_val (++next_unknown_value, mode);
+ mem_elt = new_cselib_val (++next_unknown_value, 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);
@@ -842,7 +953,8 @@ cselib_lookup_mem (rtx x, int create)
expand to the same place. */
static rtx
-expand_loc (struct elt_loc_list *p, bitmap regs_active, int max_depth)
+expand_loc (struct elt_loc_list *p, struct expand_value_data *evd,
+ int max_depth)
{
rtx reg_result = NULL;
unsigned int regno = UINT_MAX;
@@ -854,7 +966,7 @@ expand_loc (struct elt_loc_list *p, bitmap regs_active, int max_depth)
the same reg. */
if ((REG_P (p->loc))
&& (REGNO (p->loc) < regno)
- && !bitmap_bit_p (regs_active, REGNO (p->loc)))
+ && !bitmap_bit_p (evd->regs_active, REGNO (p->loc)))
{
reg_result = p->loc;
regno = REGNO (p->loc);
@@ -867,7 +979,7 @@ expand_loc (struct elt_loc_list *p, bitmap regs_active, int max_depth)
else if (!REG_P (p->loc))
{
rtx result, note;
- if (dump_file)
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
print_inline_rtx (dump_file, p->loc, 0);
fprintf (dump_file, "\n");
@@ -878,7 +990,7 @@ expand_loc (struct elt_loc_list *p, bitmap regs_active, int max_depth)
&& (note = find_reg_note (p->setting_insn, REG_EQUAL, NULL_RTX))
&& XEXP (note, 0) == XEXP (p->loc, 1))
return XEXP (p->loc, 1);
- result = cselib_expand_value_rtx (p->loc, regs_active, max_depth - 1);
+ result = cselib_expand_value_rtx_1 (p->loc, evd, max_depth - 1);
if (result)
return result;
}
@@ -888,15 +1000,15 @@ expand_loc (struct elt_loc_list *p, bitmap regs_active, int max_depth)
if (regno != UINT_MAX)
{
rtx result;
- if (dump_file)
+ if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "r%d\n", regno);
- result = cselib_expand_value_rtx (reg_result, regs_active, max_depth - 1);
+ result = cselib_expand_value_rtx_1 (reg_result, evd, max_depth - 1);
if (result)
return result;
}
- if (dump_file)
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
if (reg_result)
{
@@ -931,6 +1043,35 @@ expand_loc (struct elt_loc_list *p, bitmap regs_active, int max_depth)
rtx
cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
{
+ struct expand_value_data evd;
+
+ evd.regs_active = regs_active;
+ evd.callback = NULL;
+ evd.callback_arg = NULL;
+
+ return cselib_expand_value_rtx_1 (orig, &evd, max_depth);
+}
+
+/* Same as cselib_expand_value_rtx, but using a callback to try to
+ resolve VALUEs that expand to nothing. */
+
+rtx
+cselib_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;
+
+ return cselib_expand_value_rtx_1 (orig, &evd, max_depth);
+}
+
+static rtx
+cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
+ int max_depth)
+{
rtx copy, scopy;
int i, j;
RTX_CODE code;
@@ -980,13 +1121,13 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
|| regno == HARD_FRAME_POINTER_REGNUM)
return orig;
- bitmap_set_bit (regs_active, regno);
+ bitmap_set_bit (evd->regs_active, regno);
- if (dump_file)
+ if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "expanding: r%d into: ", regno);
- result = expand_loc (l->elt->locs, regs_active, max_depth);
- bitmap_clear_bit (regs_active, regno);
+ result = expand_loc (l->elt->locs, evd, max_depth);
+ bitmap_clear_bit (evd->regs_active, regno);
if (result)
return result;
@@ -1017,8 +1158,8 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
case SUBREG:
{
- rtx subreg = cselib_expand_value_rtx (SUBREG_REG (orig), regs_active,
- max_depth - 1);
+ rtx subreg = cselib_expand_value_rtx_1 (SUBREG_REG (orig), evd,
+ max_depth - 1);
if (!subreg)
return NULL;
scopy = simplify_gen_subreg (GET_MODE (orig), subreg,
@@ -1027,18 +1168,39 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
if (scopy == NULL
|| (GET_CODE (scopy) == SUBREG
&& !REG_P (SUBREG_REG (scopy))
- && !MEM_P (SUBREG_REG (scopy))))
+ && !MEM_P (SUBREG_REG (scopy))
+ && (REG_P (SUBREG_REG (orig))
+ || MEM_P (SUBREG_REG (orig)))))
return shallow_copy_rtx (orig);
return scopy;
}
case VALUE:
- if (dump_file)
- fprintf (dump_file, "expanding value %s into: ",
- GET_MODE_NAME (GET_MODE (orig)));
+ {
+ rtx result;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fputs ("\nexpanding ", dump_file);
+ print_rtl_single (dump_file, orig);
+ fputs (" into...", dump_file);
+ }
- return expand_loc (CSELIB_VAL_PTR (orig)->locs, regs_active, max_depth);
+ if (!evd->callback)
+ result = NULL;
+ else
+ {
+ result = evd->callback (orig, evd->regs_active, max_depth,
+ evd->callback_arg);
+ if (result == orig)
+ result = NULL;
+ else if (result)
+ result = cselib_expand_value_rtx_1 (result, evd, max_depth);
+ }
+ if (!result)
+ result = expand_loc (CSELIB_VAL_PTR (orig)->locs, evd, max_depth);
+ return result;
+ }
default:
break;
}
@@ -1057,7 +1219,8 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
case 'e':
if (XEXP (orig, i) != NULL)
{
- rtx result = cselib_expand_value_rtx (XEXP (orig, i), regs_active, max_depth - 1);
+ rtx result = cselib_expand_value_rtx_1 (XEXP (orig, i), evd,
+ max_depth - 1);
if (!result)
return NULL;
XEXP (copy, i) = result;
@@ -1071,7 +1234,8 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
{
- rtx result = cselib_expand_value_rtx (XVECEXP (orig, i, j), regs_active, max_depth - 1);
+ rtx result = cselib_expand_value_rtx_1 (XVECEXP (orig, i, j),
+ evd, max_depth - 1);
if (!result)
return NULL;
XVECEXP (copy, i, j) = result;
@@ -1155,13 +1319,17 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
{
XEXP (copy, 0)
= gen_rtx_CONST (GET_MODE (XEXP (orig, 0)), XEXP (copy, 0));
- if (dump_file)
+ if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " wrapping const_int result in const to preserve mode %s\n",
GET_MODE_NAME (GET_MODE (XEXP (copy, 0))));
}
scopy = simplify_rtx (copy);
if (scopy)
- return scopy;
+ {
+ if (GET_MODE (copy) != GET_MODE (scopy))
+ scopy = wrap_constant (GET_MODE (copy), scopy);
+ return scopy;
+ }
return copy;
}
@@ -1199,7 +1367,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));
+ e = new_cselib_val (++next_unknown_value, GET_MODE (x), x);
}
return e->val_rtx;
@@ -1215,7 +1383,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));
+ e = new_cselib_val (++next_unknown_value, GET_MODE (x), x);
return e->val_rtx;
default:
@@ -1259,6 +1427,21 @@ 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
@@ -1287,10 +1470,10 @@ 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 l->elt;
+ return cselib_log_lookup (x, l->elt);
if (! create)
- return 0;
+ return cselib_log_lookup (x, 0);
if (i < FIRST_PSEUDO_REGISTER)
{
@@ -1300,7 +1483,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));
+ e = new_cselib_val (++next_unknown_value, GET_MODE (x), x);
e->locs = new_elt_loc_list (e->locs, x);
if (REG_VALUES (i) == 0)
{
@@ -1313,34 +1496,34 @@ cselib_lookup (rtx x, enum machine_mode mode, int create)
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 = e;
- return e;
+ return cselib_log_lookup (x, e);
}
if (MEM_P (x))
- return cselib_lookup_mem (x, create);
+ return cselib_log_lookup (x, cselib_lookup_mem (x, create));
hashval = cselib_hash_rtx (x, create);
/* Can't even create if hashing is not possible. */
if (! hashval)
- return 0;
+ return cselib_log_lookup (x, 0);
slot = htab_find_slot_with_hash (cselib_hash_table, wrap_constant (mode, x),
hashval, create ? INSERT : NO_INSERT);
if (slot == 0)
- return 0;
+ return cselib_log_lookup (x, 0);
e = (cselib_val *) *slot;
if (e)
- return e;
+ return cselib_log_lookup (x, e);
- e = new_cselib_val (hashval, mode);
+ e = new_cselib_val (hashval, mode, x);
/* 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. */
*slot = (void *) e;
e->locs = new_elt_loc_list (e->locs, cselib_subst_to_values (x));
- return e;
+ return cselib_log_lookup (x, e);
}
/* Invalidate any entries in reg_values that overlap REGNO. This is called
@@ -1427,7 +1610,7 @@ cselib_invalidate_regno (unsigned int regno, enum machine_mode mode)
break;
}
}
- if (v->locs == 0)
+ if (v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
n_useless_values++;
}
}
@@ -1510,7 +1693,7 @@ cselib_invalidate_mem (rtx mem_rtx)
unchain_one_elt_loc_list (p);
}
- if (had_locs && v->locs == 0)
+ if (had_locs && v->locs == 0 && !PRESERVED_VALUE_P (v->val_rtx))
n_useless_values++;
next = v->next_containing_mem;
@@ -1591,28 +1774,19 @@ cselib_record_set (rtx dest, cselib_val *src_elt, cselib_val *dest_addr_elt)
REG_VALUES (dreg)->elt = src_elt;
}
- if (src_elt->locs == 0)
+ if (src_elt->locs == 0 && !PRESERVED_VALUE_P (src_elt->val_rtx))
n_useless_values--;
src_elt->locs = new_elt_loc_list (src_elt->locs, dest);
}
else if (MEM_P (dest) && dest_addr_elt != 0
&& cselib_record_memory)
{
- if (src_elt->locs == 0)
+ if (src_elt->locs == 0 && !PRESERVED_VALUE_P (src_elt->val_rtx))
n_useless_values--;
add_mem_for_addr (dest_addr_elt, src_elt, dest);
}
}
-/* Describe a single set that is part of an insn. */
-struct set
-{
- rtx src;
- rtx dest;
- cselib_val *src_elt;
- cselib_val *dest_addr_elt;
-};
-
/* There is no good way to determine how many elements there can be
in a PARALLEL. Since it's fairly cheap, use a really large number. */
#define MAX_SETS (FIRST_PSEUDO_REGISTER * 2)
@@ -1623,7 +1797,7 @@ cselib_record_sets (rtx insn)
{
int n_sets = 0;
int i;
- struct set sets[MAX_SETS];
+ struct cselib_set sets[MAX_SETS];
rtx body = PATTERN (insn);
rtx cond = 0;
@@ -1695,6 +1869,9 @@ cselib_record_sets (rtx insn)
}
}
+ if (cselib_record_sets_hook)
+ cselib_record_sets_hook (insn, sets, n_sets);
+
/* Invalidate all locations written by this insn. Note that the elts we
looked up in the previous loop aren't affected, just some of their
locations may go away. */
@@ -1751,7 +1928,7 @@ cselib_process_insn (rtx insn)
&& GET_CODE (PATTERN (insn)) == ASM_OPERANDS
&& MEM_VOLATILE_P (PATTERN (insn))))
{
- cselib_clear_table ();
+ cselib_reset_table_with_next_value (next_unknown_value);
return;
}
@@ -1868,4 +2045,92 @@ cselib_finish (void)
next_unknown_value = 0;
}
+/* Dump the cselib_val *X to FILE *info. */
+
+static int
+dump_cselib_val (void **x, void *info)
+{
+ cselib_val *v = (cselib_val *)*x;
+ FILE *out = (FILE *)info;
+ bool need_lf = true;
+
+ print_inline_rtx (out, v->val_rtx, 0);
+
+ if (v->locs)
+ {
+ struct elt_loc_list *l = v->locs;
+ if (need_lf)
+ {
+ fputc ('\n', out);
+ need_lf = false;
+ }
+ fputs (" locs:", out);
+ do
+ {
+ fprintf (out, "\n from insn %i ",
+ INSN_UID (l->setting_insn));
+ print_inline_rtx (out, l->loc, 4);
+ }
+ while ((l = l->next));
+ fputc ('\n', out);
+ }
+ else
+ {
+ fputs (" no locs", out);
+ need_lf = true;
+ }
+
+ if (v->addr_list)
+ {
+ struct elt_list *e = v->addr_list;
+ if (need_lf)
+ {
+ fputc ('\n', out);
+ need_lf = false;
+ }
+ fputs (" addr list:", out);
+ do
+ {
+ fputs ("\n ", out);
+ print_inline_rtx (out, e->elt->val_rtx, 2);
+ }
+ while ((e = e->next));
+ fputc ('\n', out);
+ }
+ else
+ {
+ fputs (" no addrs", out);
+ need_lf = true;
+ }
+
+ if (v->next_containing_mem == &dummy_val)
+ fputs (" last mem\n", out);
+ else if (v->next_containing_mem)
+ {
+ fputs (" next mem ", out);
+ print_inline_rtx (out, v->next_containing_mem->val_rtx, 2);
+ fputc ('\n', out);
+ }
+ else if (need_lf)
+ fputc ('\n', out);
+
+ return 1;
+}
+
+/* Dump to OUT everything in the CSELIB table. */
+
+void
+dump_cselib_table (FILE *out)
+{
+ fprintf (out, "cselib hash table:\n");
+ htab_traverse (cselib_hash_table, dump_cselib_val, out);
+ if (first_containing_mem != &dummy_val)
+ {
+ fputs ("first mem ", out);
+ print_inline_rtx (out, first_containing_mem->val_rtx, 2);
+ fputc ('\n', out);
+ }
+ fprintf (out, "last unknown value %i\n", next_unknown_value);
+}
+
#include "gt-cselib.h"