This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: reload cse may delete loads it shouldn't
On Apr 16, 2003, Alexandre Oliva <aoliva at redhat dot com> wrote:
> On Apr 15, 2003, Alexandre Oliva <aoliva at redhat dot com> wrote:
>> Ok to install if it bootstrap on athlon-pc-linux-gnu?
> It bootstrapped ok on athlon-pc-linux-gnu, and passed tests without
> regressions on mn10300-elf, but RTH asked for some additional comments
> in the code. How's this? Ok to install?
Err... Of course I'd notice one second after hitting the send button
that I still hadn't updated the patch file after fixing an error I had
introduced in the last revision. Here's the correct version, that I'm
bootstrapping again just because I'm paranoid :-)
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva at redhat dot com>
* reload1.c (reload_cse_noop_set_p): Return false if mode of
SET_DEST is not the same as that returned by...
* cselib.h (cselib_reg_set_mode): ... new function.
* cselib.c (cselib_reg_set_mode): Define it.
(REG_VALUES): Document semantics of first element as set mode.
(cselib_subst_to_values): Skip first element if ELT is NULL.
(cselib_lookup): Likewise. Insert past the first element.
(cselib_invalidate_regno): NULLify first element.
(cselib_record_set): Set first element.
Index: gcc/reload1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload1.c,v
retrieving revision 1.387
diff -u -p -r1.387 reload1.c
--- gcc/reload1.c 9 Apr 2003 17:50:08 -0000 1.387
+++ gcc/reload1.c 16 Apr 2003 22:58:37 -0000
@@ -8025,6 +8025,9 @@ static int
reload_cse_noop_set_p (set)
rtx set;
{
+ if (cselib_reg_set_mode (SET_DEST (set)) != GET_MODE (SET_DEST (set)))
+ return 0;
+
return rtx_equal_for_cselib_p (SET_DEST (set), SET_SRC (set));
}
Index: gcc/cselib.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cselib.h,v
retrieving revision 1.7
diff -u -p -r1.7 cselib.h
--- gcc/cselib.h 11 Mar 2003 21:52:41 -0000 1.7
+++ gcc/cselib.h 16 Apr 2003 22:58:37 -0000
@@ -1,6 +1,6 @@
/* Common subexpression elimination for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999 Free Software Foundation, Inc.
+ 1999, 2003 Free Software Foundation, Inc.
This file is part of GCC.
@@ -67,6 +67,7 @@ extern void cselib_update_varray_sizes P
extern void cselib_init PARAMS ((void));
extern void cselib_finish PARAMS ((void));
extern void cselib_process_insn PARAMS ((rtx));
+extern enum machine_mode cselib_reg_set_mode PARAMS ((rtx));
extern int rtx_equal_for_cselib_p PARAMS ((rtx, rtx));
extern int references_value_p PARAMS ((rtx, int));
extern rtx cselib_subst_to_values PARAMS ((rtx));
Index: gcc/cselib.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cselib.c,v
retrieving revision 1.26
diff -u -p -r1.26 cselib.c
--- gcc/cselib.c 14 Mar 2003 20:15:11 -0000 1.26
+++ gcc/cselib.c 16 Apr 2003 22:58:38 -0000
@@ -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 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
This file is part of GCC.
@@ -99,9 +99,13 @@ 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. */
+/* 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. The first element of the list defines the mode in
+ which the register was set; if the mode is unknown or the value is
+ no longer valid in that mode, ELT will be NULL for the first
+ element. */
static GTY(()) varray_type reg_values;
static GTY((deletable (""))) varray_type reg_values_old;
#define REG_VALUES(I) VARRAY_ELT_LIST (reg_values, (I))
@@ -402,6 +406,25 @@ remove_useless_values ()
abort ();
}
+/* 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
+ VOIDmode. */
+
+enum machine_mode
+cselib_reg_set_mode (x)
+ rtx x;
+{
+ if (GET_CODE (x) != REG)
+ return GET_MODE (x);
+
+ if (REG_VALUES (REGNO (x)) == NULL
+ || REG_VALUES (REGNO (x))->elt == NULL)
+ return VOIDmode;
+
+ return GET_MODE (REG_VALUES (REGNO (x))->elt->u.val_rtx);
+}
+
/* Return nonzero if we can prove that X and Y contain the same value, taking
our gathered information into account. */
@@ -812,7 +835,10 @@ cselib_subst_to_values (x)
switch (code)
{
case REG:
- for (l = REG_VALUES (REGNO (x)); l; l = l->next)
+ l = REG_VALUES (REGNO (x));
+ if (l && l->elt == NULL)
+ l = l->next;
+ for (; l; l = l->next)
if (GET_MODE (l->elt->u.val_rtx) == GET_MODE (x))
return l->elt->u.val_rtx;
@@ -909,7 +935,10 @@ cselib_lookup (x, mode, create)
struct elt_list *l;
unsigned int i = REGNO (x);
- for (l = REG_VALUES (i); l; l = l->next)
+ l = REG_VALUES (i);
+ if (l && l->elt == NULL)
+ l = l->next;
+ for (; l; l = l->next)
if (mode == GET_MODE (l->elt->u.val_rtx))
return l->elt;
@@ -927,8 +956,14 @@ cselib_lookup (x, mode, create)
e = new_cselib_val (++next_unknown_value, GET_MODE (x));
e->locs = new_elt_loc_list (e->locs, x);
if (REG_VALUES (i) == 0)
- VARRAY_PUSH_UINT (used_regs, i);
- REG_VALUES (i) = new_elt_list (REG_VALUES (i), e);
+ {
+ /* Maintain the invariant that the first entry of
+ REG_VALUES, if present, must be the value used to set the
+ register, or NULL. */
+ VARRAY_PUSH_UINT (used_regs, i);
+ 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 (hash_table, x, e->value, INSERT);
*slot = e;
return e;
@@ -1011,17 +1046,28 @@ cselib_invalidate_regno (regno, mode)
struct elt_loc_list **p;
unsigned int this_last = i;
- if (i < FIRST_PSEUDO_REGISTER)
+ if (i < FIRST_PSEUDO_REGISTER && v != NULL)
this_last += HARD_REGNO_NREGS (i, GET_MODE (v->u.val_rtx)) - 1;
- if (this_last < regno)
+ if (this_last < regno || v == NULL)
{
l = &(*l)->next;
continue;
}
/* We have an overlap. */
- unchain_one_elt_list (l);
+ if (*l == REG_VALUES (i))
+ {
+ /* Maintain the invariant that the first entry of
+ REG_VALUES, if present, must be the value used to set
+ the register, or NULL. This is also nice because
+ then we won't push the same regno onto user_regs
+ multiple times. */
+ (*l)->elt = NULL;
+ l = &(*l)->next;
+ }
+ else
+ unchain_one_elt_list (l);
/* Now, we clear the mapping from value to reg. It must exist, so
this code will crash intentionally if it doesn't. */
@@ -1213,9 +1259,6 @@ cselib_record_set (dest, src_elt, dest_a
if (dreg >= 0)
{
- if (REG_VALUES (dreg) == 0)
- VARRAY_PUSH_UINT (used_regs, dreg);
-
if (dreg < FIRST_PSEUDO_REGISTER)
{
unsigned int n = HARD_REGNO_NREGS (dreg, GET_MODE (dest));
@@ -1224,7 +1267,20 @@ cselib_record_set (dest, src_elt, dest_a
max_value_regs = n;
}
- REG_VALUES (dreg) = new_elt_list (REG_VALUES (dreg), src_elt);
+ if (REG_VALUES (dreg) == 0)
+ {
+ VARRAY_PUSH_UINT (used_regs, dreg);
+ REG_VALUES (dreg) = new_elt_list (REG_VALUES (dreg), src_elt);
+ }
+ else
+ {
+ if (REG_VALUES (dreg)->elt == 0)
+ REG_VALUES (dreg)->elt = src_elt;
+ else
+ /* The register should have been invalidated. */
+ abort ();
+ }
+
if (src_elt->locs == 0)
n_useless_values--;
src_elt->locs = new_elt_loc_list (src_elt->locs, dest);
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva at {redhat dot com, gcc.gnu.org}
CS PhD student at IC-Unicamp oliva at {lsd dot ic dot unicamp dot br, gnu.org}
Free Software Evangelist Professional serial bug killer