+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):
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;
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. */
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);
+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>
--- /dev/null
+/* 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;
+}