This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [testcase] CSE bug
On Jul 23, 2001, Richard Henderson <rth@redhat.com> wrote:
> On Mon, Jul 23, 2001 at 04:35:59PM +0200, Jakub Jelinek wrote:
>> But remove_invalid_subreg_refs(60,0,SImode) invalidates only
>> (subreg:SI (reg:DI 60) 0),
>> (which in fact was not needed if invalidate_skipped_block recorded somewhere
>> that only part of the register needs to be invalidated and which one) and
>> from this point on, (subreg:SI (reg:DI 60) 4) is handled like if nobody
>> would ever touch it.
>> Any ideas what's the right way to fix this?
> Alex, didn't you have a patch that touched on this sort
> of thing? Did it ever get reviewed?
Yeah, the description sounds somewhat similar, but there a number of
function names that don't ring any bells right now. The problem
originally showed up on mn10300-elf, with a C++ test case, IIRC.
I got some feedback, but never an official approval or rejection.
Here's the patch file, created on Nov 18, 2000:
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* cse.c (invalidate) [REG]: Invalidate all SUBREGs of the REG.
(lookup_for_remove): Handle SUBREGs.
Index: gcc/cse.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cse.c,v
retrieving revision 1.164
diff -u -p -r1.164 cse.c
--- gcc/cse.c 2000/11/07 22:49:51 1.164
+++ gcc/cse.c 2000/11/18 22:27:04
@@ -1481,6 +1481,17 @@ lookup_for_remove (x, hash, mode)
&& REGNO (p->exp) == regno)
return p;
}
+ else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG)
+ {
+ unsigned int regno = REGNO (SUBREG_REG (x));
+
+ /* Don't check the machine mode when comparing SUBREGs. */
+ for (p = table[hash]; p; p = p->next_same_hash)
+ if (GET_CODE (p->exp) == SUBREG
+ && GET_CODE (SUBREG_REG (p->exp)) == REG
+ && REGNO (SUBREG_REG (p->exp)) == regno)
+ return p;
+ }
else
{
for (p = table[hash]; p; p = p->next_same_hash)
@@ -1880,9 +1891,21 @@ invalidate (x, full_mode)
/* Because a register can be referenced in more than one mode,
we might have to remove more than one table entry. */
struct table_elt *elt;
+ int i;
while ((elt = lookup_for_remove (x, hash, GET_MODE (x))))
remove_from_table (elt, hash);
+
+ /* Since multi-word PSEUDOS may also be referenced through
+ SUBREGs, we attempt to remove such subregs too. */
+ for (i = 0; i * UNITS_PER_WORD < GET_MODE_SIZE (GET_MODE (x)); i++)
+ {
+ rtx subreg = gen_rtx_SUBREG (VOIDmode, x, i);
+ unsigned hash = HASH (subreg, VOIDmode);
+
+ while ((elt = lookup_for_remove (subreg, hash, VOIDmode)))
+ remove_from_table (elt, hash);
+ }
}
else
{
Index: gcc/testsuite/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* gcc.c-torture/execute/20001118-1.c: New test.
Index: gcc/testsuite/gcc.c-torture/execute/20001118-1.c
===================================================================
RCS file: 20001118-1.c
diff -N 20001118-1.c
--- /dev/null Tue May 5 13:32:27 1998
+++ gcc/testsuite/gcc.c-torture/execute/20001118-1.c Sat Nov 18 14:27:06 2000
@@ -0,0 +1,32 @@
+/* Copyright 2000 Free Software Foundation
+ Origin: Jason Merrill <jason@redhat.com>. */
+
+union foo {
+ void (*pfn)();
+ short delta2;
+};
+
+struct pmf {
+ short delta;
+ short index;
+ union foo u;
+};
+
+void f () { }
+
+int main ()
+{
+ struct pmf pf = { 0, -1, { &f } };
+
+ struct pmf pg = (pf.index > 0
+ ? (struct pmf){ pf.delta, pf.index,{ delta2: pf.u.delta2 }}
+ : (struct pmf){ pf.delta, pf.index,{ pfn: pf.u.pfn }});
+
+ pf = (pg.index > 0
+ ? (struct pmf){ pg.delta, pg.index,{ delta2: pg.u.delta2 }}
+ : (struct pmf){ pg.delta, pg.index,{ pfn: pg.u.pfn }});
+
+ if (pf.u.pfn != &f)
+ abort ();
+ exit (0);
+}
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist *Please* write to mailing lists, not to me