re PR target/20126 (Inlined memcmp makes one argument null on entry)
authorAlexandre Oliva <aoliva@redhat.com>
Sun, 10 Apr 2005 04:00:53 +0000 (04:00 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Sun, 10 Apr 2005 04:00:53 +0000 (04:00 +0000)
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
gcc/loop.c
gcc/recog.c
gcc/recog.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr20126.c [new file with mode: 0644]

index 228d76e..872e432 100644 (file)
@@ -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):
index e2e6074..f432e68 100644 (file)
@@ -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;
index d81ae5b..836ebb3 100644 (file)
@@ -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.  */
 
index e6222a5..e8b25e6 100644 (file)
@@ -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 c8508e8..fea25c4 100644 (file)
@@ -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 (file)
index 0000000..257832a
--- /dev/null
@@ -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;
+}