This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Fix the one entry mem{{,p}cpy,move,set} optimization aliasing issues (PR middle-end/29272)


On Mon, Oct 09, 2006 at 01:01:28PM +0200, Eric Botcazou wrote:
> > but I don't see what e.g. prevents the optimization 
> > to be done when we have
> >   p = &q->t;
> >   ...
> >   p0 = (ref_all) p; /* These two stmts come from __builtin_memcpy folding. 
> >   p0->s = x;
> > and later on some other pass notices that p is &q->t and optimizes
> > that into q->t.s = x;
> 
> Where's the problem here?  You need a latent aliasing violation in the code.

I was afraid that for something like:
extern void abort (void);

struct S { struct S *s; } s;
struct T;
struct TI { struct T *t; };
struct T { struct TI ti; } t;

static inline void
foo (void *s)
{
  struct T *p = s;
  struct TI *q = &p->ti;
  __builtin_memcpy (&q->t, &t.ti.t, sizeof (t.ti.t));
}

void *
__attribute__((noinline))
bar (void *p, struct S *q)
{
  q->s = &s;
  foo (p);
  return q->s;
}

int
main (void)
{
  t.ti.t = &t;
  if (bar (&s, &s) != (void *) &t)
    abort ();
  return 0;
}
where fold_builtin_memory_op only sees &q->t and not &p->ti.t
the ref_all cast would be removed in some folding, but I haven't
been able to reproduce something like that, apparently on
((struct TI * {ref-all}) &((struct T *) p)->ti)->t = t.ti.t;
the ref-all cast wasn't folded out.  So, if you think this is
100% safe, then something like the following (as fold_builtin
is called even before gimplification, I think we can't modify
the INDIRECT_REF's operand in-place) should work (certainly
works on the testcase):

2006-10-09  Jakub Jelinek  <jakub@redhat.com>
	    Eric Botcazou  <ebotcazou@adacore.com>

	PR middle-end/29272
	* builtins.c (adjust_memop_var_decl): New function.
	(fold_builtin_memset, fold_builtin_memory_op): Use it.

	* gcc.c-torture/execute/20060930-2.c: New test.

--- gcc/builtins.c.jj	2006-10-09 15:45:53.000000000 +0200
+++ gcc/builtins.c	2006-10-09 17:04:55.000000000 +0200
@@ -7893,6 +7893,43 @@ fold_builtin_exponent (tree fndecl, tree
   return 0;
 }
 
+/* If VAR is a VAR_DECL or component thereof, just return VAR.
+   If VAR is an INDIRECT_REF, return a copy of VAR's tree in which
+   the INDIRECT_REF is through a TYPE_REF_CAN_ALIAS_ALL pointer.
+   Otherwise return 0.  */
+
+static tree
+adjust_memop_var_decl (tree var)
+{
+  tree inner = var;
+  while (handled_component_p (inner))
+    inner = TREE_OPERAND (inner, 0);
+  if (TREE_CODE (inner) == INDIRECT_REF)
+    {
+      tree ref_all, *ptr;
+
+      if (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (inner, 0))))
+	return var;
+
+      ref_all
+	= build_pointer_type_for_mode (TREE_TYPE (inner), ptr_mode, true);
+      ptr = &var;
+      while (handled_component_p (*ptr))
+	{
+	  *ptr = copy_node (*ptr);
+	  ptr = &TREE_OPERAND (*ptr, 0);
+	}
+      *ptr = copy_node (*ptr);
+      TREE_OPERAND (*ptr, 0)
+	= fold_convert (ref_all, TREE_OPERAND (inner, 0));
+      return var;
+    }
+
+  if (SSA_VAR_P (inner))
+    return var;
+  return 0;
+}
+
 /* Fold function call to builtin memset.  Return
    NULL_TREE if no simplification can be made.  */
 
@@ -7933,6 +7970,10 @@ fold_builtin_memset (tree arglist, tree 
       && !POINTER_TYPE_P (TREE_TYPE (var)))
     return 0;
 
+  var = adjust_memop_var_decl (var);
+  if (! var)
+    return 0;
+
   length = tree_low_cst (len, 1);
   if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (var))) != length
       || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
@@ -8044,6 +8085,10 @@ fold_builtin_memory_op (tree arglist, tr
 	  && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (destvar)))
 	return 0;
 
+      destvar = adjust_memop_var_decl (destvar);
+      if (! destvar)
+	return 0;
+
       srcvar = src;
       STRIP_NOPS (srcvar);
       if (TREE_CODE (srcvar) != ADDR_EXPR)
@@ -8058,6 +8103,10 @@ fold_builtin_memory_op (tree arglist, tr
 	  && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (srcvar)))
 	return 0;
 
+      srcvar = adjust_memop_var_decl (srcvar);
+      if (! srcvar)
+	return 0;
+
       length = tree_low_cst (len, 1);
       if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (destvar))) != length
 	  || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
--- gcc/testsuite/gcc.c-torture/execute/20060930-2.c.jj	2006-10-09 15:54:31.000000000 +0200
+++ gcc/testsuite/gcc.c-torture/execute/20060930-2.c	2006-10-09 15:54:40.000000000 +0200
@@ -0,0 +1,31 @@
+/* PR middle-end/29272 */
+
+extern void abort (void);
+
+struct S { struct S *s; } s;
+struct T { struct T *t; } t;
+
+static inline void
+foo (void *s)
+{
+  struct T *p = s;
+  __builtin_memcpy (&p->t, &t.t, sizeof (t.t));
+}
+
+void *
+__attribute__((noinline))
+bar (void *p, struct S *q)
+{
+  q->s = &s;
+  foo (p);
+  return q->s;
+}
+
+int
+main (void)
+{
+  t.t = &t;
+  if (bar (&s, &s) != (void *) &t)
+    abort ();
+  return 0;
+}


	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]