------- Additional Comments From aoliva at gcc dot gnu dot org 2005-03-10 11:44 ------- Subject: Re: [PR target/20126, RFC] loop DEST_ADDR biv replacement may fail
On Mar 9, 2005, Jakub Jelinek <[EMAIL PROTECTED]> wrote: > On Wed, Mar 09, 2005 at 01:02:08AM -0300, Alexandre Oliva wrote: >> On Mar 8, 2005, Jakub Jelinek <[EMAIL PROTECTED]> wrote: >> >> > Unfortunately, it seems to break ada bootstrap on at least x86-64 and i386: >> >> Odd... It surely completed bootstrap for me with default build flags. > Your code hits just once on ali.adb Rats, I didn't realize I needed --enable-languages=all,ada to pick that up. Fixed now. > Note that recog_memoized (v->insn) is -1 even without the change, > not sure what would fix that up. Problem is that the insn has a volatile memory access, and loop runs with volatile_ok = 0. I'm not entirely sure why that is; presumably to avoid introducing or removing volatile memory accesses. I can see how this prevents introducing them, but it appears to me that it still can remove them. Anyhow, I've come up with a solution for this. This patch introduces a new function that is like validate_change, but if validate_change fails and the original insn fails to be recognized with !volatile_ok but passes with volatile_ok, then try the change and recog with volatile_ok. > But it certainly shows that *v->location doesn't have to be > a simple pseudo, so gen_move_insn might not work. Indeed. I've introduced a new pseudo to hold the computed value now, for the case in which *v->location isn't a reg. Passed bootstrap and regtest on x86_64-linux-gnu on mainline, as well as bootstrap on gcc-4_0-rhl-branch, both with Ada enabled. Ok to install? Index: gcc/ChangeLog from Alexandre Oliva <[EMAIL PROTECTED]> PR target/20126 * loop.c (loop_givs_rescan): If replacement of DEST_ADDR failed, set the original address pseudo to the correct value before the original insn, if possible, and leave the insn alone, otherwise create a new pseudo, set it and replace it in the insn. * recog.c (validate_change_maybe_volatile): New. * recog.h (validate_change_maybe_volatile): Declare. Index: gcc/loop.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/loop.c,v retrieving revision 1.522 diff -u -p -r1.522 loop.c --- gcc/loop.c 17 Jan 2005 08:46:15 -0000 1.522 +++ gcc/loop.c 10 Mar 2005 11:23:59 -0000 @@ -5470,9 +5470,31 @@ loop_givs_rescan (struct loop *loop, str mark_reg_pointer (v->new_reg, 0); if (v->giv_type == DEST_ADDR) - /* Store reduced reg as the address in the memref where we found - this giv. */ - validate_change (v->insn, v->location, v->new_reg, 0); + { + /* Store reduced reg as the address in the memref where we found + this giv. */ + if (validate_change_maybe_volatile (v->insn, v->location, + v->new_reg)) + /* Yay, it worked! */; + /* Not replaceable; emit an insn to set the original + giv reg from the reduced giv. */ + else if (REG_P (*v->location)) + loop_insn_emit_before (loop, 0, v->insn, + gen_move_insn (*v->location, + v->new_reg)); + else + { + /* If it wasn't a reg, create a pseudo and use that. */ + rtx reg, seq; + start_sequence (); + reg = force_reg (v->mode, *v->location); + seq = get_insns (); + end_sequence (); + loop_insn_emit_before (loop, 0, v->insn, seq); + gcc_assert (validate_change_maybe_volatile (v->insn, v->location, + reg)); + } + } else if (v->replaceable) { reg_map[REGNO (v->dest_reg)] = v->new_reg; Index: gcc/recog.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/recog.c,v retrieving revision 1.221 diff -u -p -r1.221 recog.c --- gcc/recog.c 7 Mar 2005 13:52:08 -0000 1.221 +++ gcc/recog.c 10 Mar 2005 11:24:01 -0000 @@ -235,6 +235,34 @@ validate_change (rtx object, rtx *loc, r return apply_change_group (); } +/* Same as validate_change, but doesn't support groups, and it accepts + volatile mems if they're already present in the original insn. + + ??? Should this should search new for new volatile MEMs and reject + them? */ + +int +validate_change_maybe_volatile (rtx object, rtx *loc, rtx new) +{ + int result; + + if (validate_change (object, loc, new, 0)) + return 1; + + if (volatile_ok || ! insn_invalid_p (object)) + return 0; + + volatile_ok = 1; + + gcc_assert (! insn_invalid_p (object)); + + result = validate_change (object, loc, new, 0); + + volatile_ok = 0; + + return result; +} + /* This subroutine of apply_change_group verifies whether the changes to INSN were valid; i.e. whether INSN can still be recognized. */ Index: gcc/recog.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/recog.h,v retrieving revision 1.55 diff -u -p -r1.55 recog.h --- gcc/recog.h 7 Mar 2005 13:52:09 -0000 1.55 +++ gcc/recog.h 10 Mar 2005 11:24:01 -0000 @@ -74,6 +74,7 @@ extern void init_recog_no_volatile (void extern int check_asm_operands (rtx); extern int asm_operand_ok (rtx, const char *); extern int validate_change (rtx, rtx *, rtx, int); +extern int validate_change_maybe_volatile (rtx, rtx *, rtx); extern int insn_invalid_p (rtx); extern void confirm_change_group (void); extern int apply_change_group (void); Index: gcc/testsuite/ChangeLog from Alexandre Oliva <[EMAIL PROTECTED]> * gcc.dg/pr20126.c: New. Index: gcc/testsuite/gcc.dg/pr20126.c =================================================================== RCS file: gcc/testsuite/gcc.dg/pr20126.c diff -N gcc/testsuite/gcc.dg/pr20126.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gcc/testsuite/gcc.dg/pr20126.c 10 Mar 2005 11:24:16 -0000 @@ -0,0 +1,50 @@ +/* dg-do run */ +/* dg-options "-O2" */ + +/* PR target/20126 was not really target-specific, but rather a loop's + failure to take into account the possibility that a DEST_ADDR giv + replacement might fail, such as when you attempt to replace a REG + with a PLUS in one of the register_operands of cmpstrqi_rex_1. */ + +extern void abort (void); + +typedef struct { int a; char b[3]; } S; +S c = { 2, "aa" }, d = { 2, "aa" }; + +void * +bar (const void *x, int y, int z) +{ + return (void *) 0; +} + +int +foo (S *x, S *y) +{ + const char *e, *f, *g; + int h; + + h = y->a; + f = y->b; + e = x->b; + + if (h == 1) + return bar (e, *f, x->a) != 0; + + g = e + x->a - h; + while (e <= g) + { + const char *t = e + 1; + if (__builtin_memcmp (e, f, h) == 0) + return 1; + e = t; + } + return 0; +} + +int +main (void) +{ + if (foo (&c, &d) != 1) + abort (); + return 0; +} -- Alexandre Oliva http://www.ic.unicamp.br/~oliva/ Red Hat Compiler Engineer [EMAIL PROTECTED], gcc.gnu.org} Free Software Evangelist [EMAIL PROTECTED], gnu.org} -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20126