From 46382283d57b72ccb117f1b2f3735c7e0c252870 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Sun, 10 Apr 2005 04:00:53 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 10 +++++++ gcc/loop.c | 28 +++++++++++++++++-- gcc/recog.c | 40 +++++++++++++++++++++++++++ gcc/recog.h | 1 + gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gcc.dg/pr20126.c | 50 ++++++++++++++++++++++++++++++++++ 6 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr20126.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 228d76eb14df..872e432d37a9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2005-04-09 Alexandre Oliva + + 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 * bb-reorder.c (find_rarely_executed_basic_blocks_and_crossing_edges): diff --git a/gcc/loop.c b/gcc/loop.c index e2e6074ccc47..f432e68e5927 100644 --- a/gcc/loop.c +++ b/gcc/loop.c @@ -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 d81ae5b3adc2..836ebb3eabd0 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 e6222a50cd3c..e8b25e65ce1f 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 c8508e84d188..fea25c4a5ada 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2005-04-09 Alexandre Oliva + + * gcc.dg/pr20126.c: New. + 2005-04-09 Bud Davis Steven G. Kargl diff --git a/gcc/testsuite/gcc.dg/pr20126.c b/gcc/testsuite/gcc.dg/pr20126.c new file mode 100644 index 000000000000..257832ab18a5 --- /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; +}