[Bug target/20126] [3.3/3.4/4.0/4.1 Regression] Inlined memcmp makes one argument null on entry

aoliva at redhat dot com gcc-bugzilla@gcc.gnu.org
Thu Mar 10 11:45:00 GMT 2005


------- 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 <jakub@redhat.com> wrote:

> On Wed, Mar 09, 2005 at 01:02:08AM -0300, Alexandre Oliva wrote:
>> On Mar  8, 2005, Jakub Jelinek <jakub@redhat.com> 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  <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.

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  <aoliva@redhat.com>

	* 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   aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist  oliva@{lsd.ic.unicamp.br, gnu.org}


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20126



More information about the Gcc-bugs mailing list