diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2005-04-10 04:00:53 +0000 |
---|---|---|
committer | Alexandre Oliva <aoliva@gcc.gnu.org> | 2005-04-10 04:00:53 +0000 |
commit | 46382283d57b72ccb117f1b2f3735c7e0c252870 (patch) | |
tree | 24485e56e8b36a8e92b4e868e76b61bc02192114 | |
parent | f7d7d3b779b8ade7cef279492981705ee9b5a577 (diff) | |
download | gcc-46382283d57b72ccb117f1b2f3735c7e0c252870.zip gcc-46382283d57b72ccb117f1b2f3735c7e0c252870.tar.gz gcc-46382283d57b72ccb117f1b2f3735c7e0c252870.tar.bz2 |
re PR target/20126 (Inlined memcmp makes one argument null on entry)
gcc/ChangeLog:
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.
gcc/testsuite/ChangeLog:
* gcc.dg/pr20126.c: New.
From-SVN: r97939
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/loop.c | 28 | ||||
-rw-r--r-- | gcc/recog.c | 40 | ||||
-rw-r--r-- | gcc/recog.h | 1 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr20126.c | 50 |
6 files changed, 130 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 228d76e..872e432 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2005-04-09 Alexandre Oliva <aoliva@redhat.com> + + 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. + 2005-04-09 Caroline Tice <ctice@apple.com> * bb-reorder.c (find_rarely_executed_basic_blocks_and_crossing_edges): @@ -5476,9 +5476,31 @@ loop_givs_rescan (struct loop *loop, struct iv_class *bl, rtx *reg_map) 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); + if (!validate_change_maybe_volatile (v->insn, v->location, reg)) + gcc_unreachable (); + } + } else if (v->replaceable) { reg_map[REGNO (v->dest_reg)] = v->new_reg; diff --git a/gcc/recog.c b/gcc/recog.c index d81ae5b..836ebb3 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -235,6 +235,46 @@ validate_change (rtx object, rtx *loc, rtx new, int in_group) return apply_change_group (); } + +/* Function to be passed to for_each_rtx to test whether a piece of + RTL contains any mem/v. */ +static int +volatile_mem_p (rtx *x, void *data ATTRIBUTE_UNUSED) +{ + return (MEM_P (*x) && MEM_VOLATILE_P (*x)); +} + +/* Same as validate_change, but doesn't support groups, and it accepts + volatile mems if they're already present in the original insn. */ + +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 + /* If there isn't a volatile MEM, there's nothing we can do. */ + || !for_each_rtx (&PATTERN (object), volatile_mem_p, 0) + /* Make sure we're not adding or removing volatile MEMs. */ + || for_each_rtx (loc, volatile_mem_p, 0) + || for_each_rtx (&new, volatile_mem_p, 0) + || !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. */ diff --git a/gcc/recog.h b/gcc/recog.h index e6222a5..e8b25e6 100644 --- a/gcc/recog.h +++ b/gcc/recog.h @@ -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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c8508e8..fea25c4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2005-04-09 Alexandre Oliva <aoliva@redhat.com> + + * gcc.dg/pr20126.c: New. + 2005-04-09 Bud Davis <bdavis@gfortran.org> Steven G. Kargl <kargls@comcast.net> diff --git a/gcc/testsuite/gcc.dg/pr20126.c b/gcc/testsuite/gcc.dg/pr20126.c new file mode 100644 index 0000000..257832a --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr20126.c @@ -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; +} |